// amigos.jsx — Sección Amigos de Serenia (v20): chats, solicitudes y grupos.
// Cargado en SerenIA.html: <script type="text/babel" src="./amigos.jsx"> (después de los helpers de Supabase,
// Turtle, POSES, MOOD_TONE_COLOR, msgTimeAgo, getNickname, etc., que viven en el HTML).
// El chat con un amigo (FriendChat) vive en amigos-chat.jsx y usa los helpers am* de este archivo.

// ── Helpers compartidos (prefijo am*) ────────────────────────────────────────
const AM_MOOD_POSE = { feliz: 'walk', calmo: 'meditate', neutral: 'sit', cansado: 'rest', ansioso: 'chat', triste: 'sad' };
const AM_MOOD_LABEL = { feliz: 'Feliz', calmo: 'Calmo', neutral: 'Neutral', cansado: 'Cansado', ansioso: 'Ansioso', triste: 'Triste' };
const AM_PERIOD_LABEL = { 'mañana': 'esta mañana', tarde: 'esta tarde', noche: 'esta noche' };
const AM_RED = '#C5524B', AM_STAR = '#C9A86A';

function amMoodPose(mood, fallback) { return AM_MOOD_POSE[mood] || fallback || 'sit'; }
function amMoodColor(mood, fallback) { return (typeof MOOD_TONE_COLOR !== 'undefined' && MOOD_TONE_COLOR[mood]) || fallback; }
// Privacidad del ánimo del amigo: 'all' | 'close' (solo cercanos) | '24h' | 'nobody'
function amCanSeeMood(privacy, isFavorite, fm) {
  if (!fm) return false;
  if (privacy === 'nobody') return false;
  if (privacy === 'close') return !!isFavorite;
  if (privacy === '24h') return (Date.now() - new Date(fm.created_at).getTime()) < 86400000;
  return true;
}
function amMoodText(fm) {
  if (!fm) return '';
  const when = fm.created_at ? msgTimeAgo(fm.created_at) : '';
  const sameDay = fm.created_at && new Date(fm.created_at).toDateString() === new Date().toDateString();
  const periodo = sameDay && fm.period ? AM_PERIOD_LABEL[fm.period] : null;
  return (AM_MOOD_LABEL[fm.mood] || fm.mood) + (periodo ? ' · ' + periodo : when && when !== 'ahora' ? ' · hace ' + when : '');
}
function amFirstName(name) { return (name || '').trim().split(/\s+/)[0] || 'tu amigo'; }
async function amCopy(text) {
  try { await navigator.clipboard.writeText(text); return true; } catch (_) {}
  try {
    const ta = document.createElement('textarea'); ta.value = text; ta.style.cssText = 'position:fixed;opacity:0';
    document.body.appendChild(ta); ta.select(); const ok = document.execCommand('copy'); ta.remove(); return ok;
  } catch (_) { return false; }
}
function amHaptic(kind) { try { if (window.haptic) window.haptic(kind); } catch (_) {} }

// Estilos base reutilizados en la sección
const amBtnPrimary = (p, disabled) => ({
  padding: '12px 16px', borderRadius: 14, border: 'none', cursor: disabled ? 'not-allowed' : 'pointer',
  background: disabled ? p.line : p.primaryDeep, color: '#fff', fontSize: 14, fontWeight: 600,
  fontFamily: 'inherit', transition: 'background .2s, transform .12s',
});
const amBtnGhost = (p) => ({
  padding: '12px 16px', borderRadius: 14, border: `1px solid ${p.line}`, cursor: 'pointer',
  background: 'transparent', color: p.inkSoft, fontSize: 14, fontWeight: 600, fontFamily: 'inherit',
});
const amInput = (p, error) => ({
  width: '100%', padding: '12px 14px', border: `1px solid ${error ? AM_RED : p.line}`, background: p.surface,
  borderRadius: 14, fontSize: 16, outline: 'none', color: p.ink, boxSizing: 'border-box', fontFamily: 'inherit',
});

// Hoja inferior (fixed: cubre la pantalla del teléfono o el marco en escritorio)
function AmSheet({ p, onClose, children, maxWidth = 520, zIndex = 5000 }) {
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose && onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);
  return (
    <div onClick={onClose} role="presentation" style={{
      position: 'fixed', inset: 0, zIndex, background: 'rgba(20,26,22,0.46)',
      display: 'flex', alignItems: 'flex-end', justifyContent: 'center', animation: 'amFade .18s ease',
    }}>
      <div onClick={e => e.stopPropagation()} role="dialog" aria-modal="true" style={{
        width: '100%', maxWidth, background: p.bg, borderRadius: '22px 22px 0 0',
        padding: '10px 18px calc(22px + env(safe-area-inset-bottom, 0px))', maxHeight: '86vh', overflowY: 'auto',
        boxShadow: '0 -8px 30px rgba(0,0,0,0.18)', animation: 'amSheetUp .26s cubic-bezier(.2,.8,.2,1)', color: p.ink,
      }}>
        <div style={{ width: 40, height: 4, background: p.line, borderRadius: 2, margin: '0 auto 14px' }} />
        {children}
      </div>
    </div>
  );
}

// Avatar con tortuga + punto de ánimo (o SOS)
function AmAvatar({ p, pose = 'sit', size = 52, dotColor, sos = false, ring = false, animate = false }) {
  const turtle = Math.round(size * 0.9);
  return (
    <div style={{ width: size, height: size, borderRadius: '50%', background: p.primarySoft, flexShrink: 0, position: 'relative',
      display: 'flex', alignItems: 'flex-end', justifyContent: 'center', overflow: 'visible',
      boxShadow: ring ? `0 0 0 2px ${p.bg}, 0 0 0 4px ${AM_STAR}` : 'none' }}>
      <div style={{ width: size, height: size, borderRadius: '50%', overflow: 'hidden', display: 'flex', alignItems: 'flex-end', justifyContent: 'center' }}>
        <Turtle pose={pose} size={turtle} animate={animate} />
      </div>
      {sos && <div style={{ position: 'absolute', inset: -3, borderRadius: '50%', border: `2px solid ${AM_RED}`, opacity: 0.6, animation: 'sosFriendPulse 1.8s ease-out infinite', pointerEvents: 'none' }} />}
      {dotColor && (
        <span style={{ position: 'absolute', bottom: 0, right: 0, width: Math.max(12, Math.round(size * 0.25)), height: Math.max(12, Math.round(size * 0.25)), borderRadius: '50%',
          background: dotColor, border: `2px solid ${p.bg}`, boxSizing: 'border-box', zIndex: 2,
          animation: sos ? 'sosFriendDot 1.4s ease-in-out infinite' : 'none' }} />
      )}
    </div>
  );
}

// Estado vacío con tortuga
function AmEmpty({ p, pose = 'rest', title, text, action, onAction, compact = false }) {
  return (
    <div style={{ textAlign: 'center', padding: compact ? '22px 16px 10px' : '34px 20px 16px', color: p.inkMute, gridColumn: '1 / -1' }}>
      <Turtle pose={pose} size={compact ? 64 : 84} animate style={{ margin: '0 auto', filter: 'drop-shadow(0 6px 12px rgba(0,0,0,0.10))' }} />
      <div style={{ fontSize: compact ? 14 : 16, fontWeight: 600, color: p.ink, marginTop: 12, fontFamily: 'Fraunces, serif' }}>{title}</div>
      {text && <div style={{ fontSize: 13, marginTop: 6, lineHeight: 1.55, maxWidth: 300, margin: '6px auto 0' }}>{text}</div>}
      {action && (
        <button onClick={onAction} style={{ ...amBtnPrimary(p, false), marginTop: 14, padding: '10px 18px', fontSize: 13, borderRadius: 999 }}>{action}</button>
      )}
    </div>
  );
}

// Código para compartir (propio o de un grupo) con botón copiar
function AmCodeChip({ p, code, label = 'Copiar', size = 'md' }) {
  const [copied, setCopied] = React.useState(false);
  if (!code) return null;
  return (
    <button onClick={async (e) => { e.stopPropagation(); const ok = await amCopy(code); if (ok) { amHaptic('light'); setCopied(true); setTimeout(() => setCopied(false), 1600); } }}
      title="Copiar código" style={{
        display: 'inline-flex', alignItems: 'center', gap: 6, padding: size === 'sm' ? '3px 8px' : '6px 10px', borderRadius: 999,
        border: `1px dashed ${copied ? p.primary : p.line}`, background: copied ? p.primarySoft : 'transparent', cursor: 'pointer',
        color: copied ? p.primaryDeep : p.inkSoft, fontSize: size === 'sm' ? 11 : 12, fontFamily: 'inherit', transition: 'all .2s',
      }}>
      <span style={{ fontFamily: 'ui-monospace, Menlo, monospace', letterSpacing: '0.08em', fontWeight: 600 }}>{code}</span>
      <span style={{ fontSize: size === 'sm' ? 10 : 11 }}>{copied ? '✓ Copiado' : label}</span>
    </button>
  );
}

// ── FriendsScreen ────────────────────────────────────────────────────────────
function FriendsScreen({ p, onOpenChat, onOpenClass, onOpenProfile, userId, user, onUnreadChange }) {
  const [tab, setTab] = React.useState('chats');
  const [showAdd, setShowAdd] = React.useState(false);
  const [menuOpen, setMenuOpen] = React.useState(null);        // id del amigo con hoja de opciones abierta
  const [confirmRemove, setConfirmRemove] = React.useState(false);
  const [friends, setFriends] = React.useState([]);
  const [requests, setRequests] = React.useState([]);
  const [sentRequests, setSentRequests] = React.useState([]);
  const [grupos, setGrupos] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [gruposLoading, setGruposLoading] = React.useState(true);
  const [addCode, setAddCode] = React.useState('');
  const [addError, setAddError] = React.useState('');
  const [addLoading, setAddLoading] = React.useState(false);
  const [addSuccess, setAddSuccess] = React.useState(false);
  const [myCodeCopied, setMyCodeCopied] = React.useState(false);
  const [sosFriends, setSosFriends] = React.useState({});
  const [friendMoods, setFriendMoods] = React.useState({});
  const [editingNick, setEditingNick] = React.useState(null);
  const [nickInput, setNickInput] = React.useState('');
  const [dataLoaded, setDataLoaded] = React.useState(false);
  const [reqBusy, setReqBusy] = React.useState({});             // id → 'accepting' | 'rejecting' | 'accepted'
  const [notice, setNotice] = React.useState('');

  // Grupos: modales existentes
  const [showCreateGroup, setShowCreateGroup] = React.useState(false);
  const [showClaseModal, setShowClaseModal] = React.useState(false);
  const [claseTab, setClaseTab] = React.useState('crear'); // 'crear' | 'unirse'
  const [groupName, setGroupName] = React.useState('');
  const [selectedFriends, setSelectedFriends] = React.useState([]);
  const [groupLoading, setGroupLoading] = React.useState(false);
  const [groupError, setGroupError] = React.useState('');
  const [className, setClassName] = React.useState('');
  const [classInstitution, setClassInstitution] = React.useState('');
  const [classType, setClassType] = React.useState('Educativa');
  const [joinCode, setJoinCode] = React.useState('');
  const [claseLoading, setClaseLoading] = React.useState(false);
  const [claseError, setClaseError] = React.useState('');
  const [claseSuccess, setClaseSuccess] = React.useState('');

  const flash = (t) => { setNotice(t); clearTimeout(flash._t); flash._t = setTimeout(() => setNotice(''), 2600); };

  const loadData = async () => {
    if (!userId || !window.SupaFriends) { setLoading(false); setGruposLoading(false); return; }
    setLoading(true);
    setGruposLoading(true);
    try {
      const [fr, rq] = await Promise.all([
        window.SupaFriends.getAccepted(userId),
        window.SupaFriends.getPending(userId),
      ]);
      const friendIds = (fr || []).map(f => f.friend.id);
      let lastMsgs = {};
      let unreadCounts = {};
      if (window.SupaMessages?.getLastMessages) {
        lastMsgs = await window.SupaMessages.getLastMessages(userId, friendIds).catch(() => ({}));
      }
      if (window.SupaMessages?.getUnreadCounts) {
        unreadCounts = await window.SupaMessages.getUnreadCounts(userId, friendIds).catch(() => ({}));
      }
      setFriends((fr || []).map((f, i) => {
        const last = lastMsgs[f.friend.id];
        return {
          id: f.friend.id,
          rowId: f.id,
          name: f.friend.name,
          nickname: userId ? getNickname(userId, f.friend.id) : null,
          muted: userId ? isMutedFriend(userId, f.friend.id) : false,
          userType: f.friend.user_type || 'Usuario',
          personalCode: f.friend.personal_code || '',
          tone: p.primary,
          last: last ? last.text.slice(0, 60) : 'Toca para chatear',
          lastAt: last ? last.created_at : null,
          time: last ? msgTimeAgo(last.created_at) : '',
          isSender: last ? last.sender_id === userId : false,
          unread: unreadCounts[f.friend.id] || 0,
          pose: POSES[i % POSES.length],
          isFavorite: f.is_favorite || false,
          moodPrivacy: f.friend.mood_privacy || 'all',
        };
      }));
      setDataLoaded(true);
      setRequests((rq || []).map(r => ({
        id: r.id,
        fromUserId: r.user.id,
        name: r.user.name,
        userType: r.user.user_type || 'Usuario',
      })));
      if (window.SupaSOS?.getForFriends) {
        const sosEvents = await window.SupaSOS.getForFriends(userId).catch(() => []);
        const sosMap = {};
        (sosEvents || []).forEach(e => { sosMap[e.friend_id] = e; });
        setSosFriends(sosMap);
      }
      // Ánimo real de cada amigo
      if (window.SupaMood?.getLastForUsers) {
        const moods = await window.SupaMood.getLastForUsers(friendIds).catch(() => ({}));
        setFriendMoods(moods || {});
      }
      // Solicitudes que yo envié y siguen sin respuesta
      if (window.__supa) {
        const { data } = await window.__supa.from('friends')
          .select('id, friend:profiles!friends_friend_id_fkey(id, name, user_type)')
          .eq('user_id', userId).eq('status', 'pending');
        setSentRequests((data || []).map(r => ({ id: r.id, toUserId: r.friend?.id, name: r.friend?.name || 'Alguien', userType: r.friend?.user_type || 'Usuario' })));
      }
    } catch (_) {}
    setLoading(false);

    if (window.SupaClasses) {
      try {
        const cls = await window.SupaClasses.getMine(userId);
        setGrupos(cls || []);
      } catch (_) {}
    }
    setGruposLoading(false);
  };

  React.useEffect(() => { loadData(); }, [userId]);

  React.useEffect(() => {
    if (!userId || !window.SupaMessages?.subscribeInbox) return;
    const sub = window.SupaMessages.subscribeInbox(userId, (msg) => {
      setFriends(fs => fs.map(f =>
        f.id === msg.sender_id ? { ...f, unread: (f.unread || 0) + 1, last: (msg.text || '').slice(0, 60), lastAt: msg.created_at, time: msgTimeAgo(msg.created_at), isSender: false } : f
      ));
    });
    return () => { try { sub?.unsubscribe?.(); } catch (_) {} };
  }, [userId]);

  React.useEffect(() => {
    if (onUnreadChange && dataLoaded) {
      const msgs = friends.reduce((s, f) => s + (f.unread || 0), 0);
      onUnreadChange(msgs + requests.length);
    }
  }, [friends, requests, dataLoaded]);

  // Realtime — actualizar ánimo de amigos cuando registren
  React.useEffect(() => {
    if (!friends.length || !window.__supa) return;
    const friendIds = new Set(friends.map(f => f.id));
    const channel = window.__supa
      .channel('friend-mood-updates')
      .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'mood_log' }, (payload) => {
        const { user_id, mood, tone, period, created_at } = payload.new || {};
        if (!friendIds.has(user_id)) return;
        setFriendMoods(prev => ({ ...prev, [user_id]: { user_id, mood, tone, period, created_at } }));
      })
      .subscribe();
    return () => { window.__supa.removeChannel(channel); };
  }, [friends.length]);

  // Realtime — solicitudes nuevas mientras la pantalla está abierta (canal propio: el de SupaFriends ya lo usa App)
  React.useEffect(() => {
    if (!userId || !window.__supa) return;
    const channel = window.__supa.channel("am-friend-reqs-" + userId)
      .on("postgres_changes", { event: "INSERT", schema: "public", table: "friends", filter: "friend_id=eq." + userId }, (payload) => {
        if (payload.new?.status === "pending") loadData();
      })
      .subscribe();
    return () => { try { window.__supa.removeChannel(channel); } catch (_) {} };
  }, [userId]);

  const handleSendRequest = async () => {
    if (!addCode.trim() || addLoading) return;
    setAddLoading(true);
    setAddError('');
    try {
      await window.SupaFriends.send(userId, addCode.trim().toUpperCase());
      amHaptic('success');
      setAddSuccess(true);
      setAddCode('');
      setTimeout(() => { setAddSuccess(false); setShowAdd(false); loadData(); }, 1500);
      if (window.SupaAchievements) {
        window.SupaAchievements.checkOneTime(userId, 'first_friend').then(a => {
          if (a) window.dispatchEvent(new CustomEvent('serenia-achievement', { detail: [a] }));
        });
      }
    } catch (err) {
      setAddError(err.message || 'No se pudo enviar la solicitud.');
    } finally {
      setAddLoading(false);
    }
  };

  const handleAccept = async (req) => {
    if (reqBusy[req.id]) return;
    setReqBusy(b => ({ ...b, [req.id]: 'accepting' }));
    try {
      await window.SupaFriends.accept(req.id, req.fromUserId, userId);
      amHaptic('success');
      setReqBusy(b => ({ ...b, [req.id]: 'accepted' }));
      flash(`${amFirstName(req.name)} y tú ya son amigos 🌿`);
      setTimeout(() => { setRequests(r => r.filter(x => x.id !== req.id)); loadData(); }, 900);
    } catch (_) {
      setReqBusy(b => { const n = { ...b }; delete n[req.id]; return n; });
      flash('No se pudo aceptar. Intenta de nuevo.');
    }
  };

  const handleReject = async (req) => {
    if (reqBusy[req.id]) return;
    setReqBusy(b => ({ ...b, [req.id]: 'rejecting' }));
    try {
      await window.SupaFriends.reject(req.id);
      amHaptic('light');
      setRequests(r => r.filter(x => x.id !== req.id));
    } catch (_) {
      setReqBusy(b => { const n = { ...b }; delete n[req.id]; return n; });
    }
  };

  const handleCancelSent = async (r) => {
    try { await window.SupaFriends.reject(r.id); setSentRequests(s => s.filter(x => x.id !== r.id)); } catch (_) {}
  };

  const handleRemove = async (friend) => {
    setMenuOpen(null); setConfirmRemove(false);
    setFriends(fs => fs.filter(f => f.id !== friend.id));
    if (userId && window.__supa) {
      try {
        await window.__supa.from('friends').delete()
          .or(`and(user_id.eq.${userId},friend_id.eq.${friend.id}),and(user_id.eq.${friend.id},friend_id.eq.${userId})`);
      } catch (_) {}
    }
    flash(`${amFirstName(friend.nickname || friend.name)} ya no está en tu red`);
  };

  const handleCreateGroup = async () => {
    if (!groupName.trim() || groupLoading) return;
    setGroupLoading(true);
    setGroupError('');
    try {
      const cls = await window.SupaClasses.create(userId, { name: groupName.trim(), institution: '', type: 'Grupo' });
      for (const fId of selectedFriends) {
        await window.SupaClasses.addMember(cls.id, fId).catch(() => {});
      }
      setGrupos(prev => [...prev, { ...cls, role: 'admin' }]);
      amHaptic('success');
      setShowCreateGroup(false);
      setGroupName('');
      setSelectedFriends([]);
      flash('Grupo creado. Comparte su código para invitar.');
    } catch (err) {
      setGroupError(err.message || 'No se pudo crear el grupo.');
    } finally {
      setGroupLoading(false);
    }
  };

  const handleCreateClass = async () => {
    if (!className.trim() || claseLoading) return;
    setClaseLoading(true);
    setClaseError('');
    try {
      const cls = await window.SupaClasses.create(userId, { name: className.trim(), institution: classInstitution.trim(), type: classType });
      setGrupos(prev => [...prev, { ...cls, role: 'admin' }]);
      amHaptic('success');
      setClaseSuccess('Clase creada');
      setTimeout(() => { setClaseSuccess(''); setShowClaseModal(false); setClassName(''); setClassInstitution(''); setClassType('Educativa'); }, 1400);
    } catch (err) {
      setClaseError(err.message || 'No se pudo crear la clase.');
    } finally {
      setClaseLoading(false);
    }
  };

  const handleJoinClass = async () => {
    if (!joinCode.trim() || claseLoading) return;
    setClaseLoading(true);
    setClaseError('');
    try {
      const cls = await window.SupaClasses.join(userId, joinCode.trim().toUpperCase());
      const full = await window.SupaClasses.getMine(userId).catch(() => null);
      if (full) setGrupos(full);
      else setGrupos(prev => [...prev, { ...cls, role: 'member' }]);
      amHaptic('success');
      setClaseSuccess('Te uniste a la clase');
      setTimeout(() => { setClaseSuccess(''); setShowClaseModal(false); setJoinCode(''); }, 1400);
    } catch (err) {
      setClaseError(err.message || 'No se pudo unir a la clase.');
    } finally {
      setClaseLoading(false);
    }
  };

  const toggleFriendSelect = (fId) => {
    setSelectedFriends(prev => prev.includes(fId) ? prev.filter(x => x !== fId) : [...prev, fId]);
  };

  const toggleFavorite = async (f) => {
    const newFav = !f.isFavorite;
    setFriends(fs => fs.map(x => x.id === f.id ? { ...x, isFavorite: newFav } : x));
    amHaptic('light');
    if (userId && window.SupaFriends?.setFavorite) {
      await window.SupaFriends.setFavorite(userId, f.id, newFav).catch(() => {});
    }
  };

  const openChat = (f) => {
    setMenuOpen(null);
    setFriends(fs => fs.map(x => x.id === f.id ? { ...x, unread: 0 } : x));
    const fm = friendMoods[f.id];
    const visible = amCanSeeMood(f.moodPrivacy, f.isFavorite, fm) ? fm : null;
    const sosEvt = sosFriends[f.id];
    onOpenChat({ ...f, pose: visible ? amMoodPose(visible.mood, f.pose) : f.pose, mood: visible, sosAt: sosEvt ? sosEvt.created_at : null });
  };

  const myCode = user?.personalCode || '···';
  const misGrupos = grupos.filter(g => g.type === 'Grupo');
  const misClases = grupos.filter(g => g.type !== 'Grupo');

  // Vista enriquecida y ordenada: SOS → no leídos → cercanos → último mensaje → nombre
  const enriched = friends.map(f => {
    const sosEvt = sosFriends[f.id];
    const fm = friendMoods[f.id];
    const visibleFm = amCanSeeMood(f.moodPrivacy, f.isFavorite, fm) ? fm : null;
    return {
      ...f, sosEvt, visibleFm,
      sosMinAgo: sosEvt ? Math.round((Date.now() - new Date(sosEvt.created_at).getTime()) / 60000) : null,
      dotColor: sosEvt ? AM_RED : visibleFm ? amMoodColor(visibleFm.mood, p.primary) : p.line,
      posePreview: visibleFm ? amMoodPose(visibleFm.mood, f.pose) : f.pose,
    };
  }).sort((a, b) =>
    (b.sosEvt ? 1 : 0) - (a.sosEvt ? 1 : 0) ||
    (b.unread > 0 ? 1 : 0) - (a.unread > 0 ? 1 : 0) ||
    (b.isFavorite ? 1 : 0) - (a.isFavorite ? 1 : 0) ||
    (new Date(b.lastAt || 0).getTime() - new Date(a.lastAt || 0).getTime()) ||
    (a.nickname || a.name).localeCompare(b.nickname || b.name, 'es')
  );
  const cercanos = enriched.filter(f => f.isFavorite);
  const menuFriend = menuOpen ? enriched.find(f => f.id === menuOpen) : null;

  const tabs = [
    { id: 'chats',  label: 'Chats',       count: friends.length,  badge: friends.reduce((s, f) => s + (f.unread || 0), 0) },
    { id: 'reqs',   label: 'Solicitudes', count: requests.length, badge: requests.length },
    { id: 'grupos', label: 'Grupos',      count: grupos.length,   badge: 0 },
  ];

  const sectionTitle = (t, extra) => (
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', margin: '4px 2px 10px' }}>
      <div style={{ fontSize: 11, fontWeight: 700, color: p.inkMute, letterSpacing: '0.08em', textTransform: 'uppercase' }}>{t}</div>
      {extra}
    </div>
  );

  return (
    <div className="am-root" style={{ padding: '8px 16px 28px', color: p.ink, minHeight: '100%', boxSizing: 'border-box', position: 'relative' }}>
      <style>{`
        @keyframes sosFriendPulse { 0% { transform: scale(0.95); opacity: 0.7; } 100% { transform: scale(1.25); opacity: 0; } }
        @keyframes sosFriendDot { 0%, 100% { transform: scale(1); } 40% { transform: scale(1.25); } }
        @keyframes amFade { from { opacity: 0; } to { opacity: 1; } }
        @keyframes amSheetUp { from { transform: translateY(24px); opacity: .6; } to { transform: translateY(0); opacity: 1; } }
        @keyframes amRise { from { transform: translateY(6px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
        @keyframes amSpin { to { transform: rotate(360deg); } }
        .am-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 10px; }
        .am-card { transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease; }
        .am-card:active { transform: scale(0.985); }
        .am-press { transition: transform .12s ease, opacity .12s ease; }
        .am-press:active { transform: scale(0.96); opacity: .85; }
        .am-scroll-x { display: flex; gap: 12px; overflow-x: auto; padding: 4px 2px 8px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
        .am-scroll-x::-webkit-scrollbar { display: none; }
        @media (prefers-reduced-motion: reduce) { .am-root * { animation-duration: .01ms !important; transition-duration: .01ms !important; } }
      `}</style>

      {/* Cabecera */}
      <div style={{ paddingTop: 8, display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 12 }}>
        <div>
          <div style={{ fontSize: 12, color: p.inkMute, letterSpacing: '0.06em', textTransform: 'uppercase', fontWeight: 600 }}>Tu red</div>
          <div style={{ fontSize: 30, fontFamily: 'Fraunces, serif', fontWeight: 400, marginTop: 2, lineHeight: 1.1 }}>Amigos</div>
        </div>
        <button onClick={() => { setShowAdd(true); setAddError(''); setAddCode(''); setAddSuccess(false); }} className="am-press" aria-label="Agregar amigo por código" style={{
          display: 'inline-flex', alignItems: 'center', gap: 6, padding: '10px 14px 10px 12px', borderRadius: 999, border: 'none',
          background: p.primaryDeep, color: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 600, fontFamily: 'inherit',
          boxShadow: `0 6px 16px ${p.primaryDeep}40`,
        }}>
          <span style={{ fontSize: 18, lineHeight: 1, marginTop: -2 }}>+</span> Agregar
        </button>
      </div>

      {/* Pestañas */}
      <div role="tablist" style={{ marginTop: 16, display: 'flex', gap: 4, padding: 4, background: p.surface, borderRadius: 14, border: `1px solid ${p.line}` }}>
        {tabs.map(t => {
          const active = tab === t.id;
          return (
            <button key={t.id} role="tab" aria-selected={active} onClick={() => { setTab(t.id); setMenuOpen(null); }} style={{
              flex: 1, padding: '9px 6px', borderRadius: 11, border: 'none', position: 'relative',
              background: active ? p.bg : 'transparent', color: active ? p.ink : p.inkMute,
              boxShadow: active ? '0 2px 8px rgba(0,0,0,0.08)' : 'none',
              fontWeight: active ? 700 : 500, fontSize: 13, cursor: 'pointer', fontFamily: 'inherit',
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6, transition: 'all .18s',
            }}>
              {t.label}
              {t.badge > 0 ? (
                <span style={{ minWidth: 18, height: 18, borderRadius: 9, padding: '0 5px', background: t.id === 'reqs' ? AM_RED : p.primaryDeep, color: '#fff',
                  fontSize: 10, fontWeight: 700, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>{t.badge > 99 ? '99+' : t.badge}</span>
              ) : t.count > 0 ? (
                <span style={{ fontSize: 11, color: active ? p.inkSoft : p.inkMute, fontWeight: 600 }}>{t.count}</span>
              ) : null}
            </button>
          );
        })}
      </div>

      {notice && (
        <div role="status" style={{ marginTop: 12, padding: '10px 14px', borderRadius: 12, background: p.primarySoft, color: p.primaryDeep, fontSize: 13, fontWeight: 500, animation: 'amRise .2s ease' }}>{notice}</div>
      )}

      {/* ── Chats ── */}
      {tab === 'chats' && (
        <div style={{ marginTop: 16 }}>
          {loading && (
            <div style={{ textAlign: 'center', padding: 32, color: p.inkMute, fontSize: 13 }}>
              <Turtle pose="sit" size={60} animate style={{ margin: '0 auto' }} /><div style={{ marginTop: 8 }}>Cargando amigos…</div>
            </div>
          )}
          {!loading && friends.length === 0 && (
            <AmEmpty p={p} pose="rest" title="Aún no tienes amigos aquí"
              text={<span>Comparte tu código <b style={{ color: p.primaryDeep, fontFamily: 'ui-monospace, Menlo, monospace' }}>{myCode}</b> o agrega a alguien con su código.</span>}
              action="Agregar por código" onAction={() => { setShowAdd(true); setAddError(''); setAddCode(''); setAddSuccess(false); }} />
          )}

          {!loading && cercanos.length > 0 && (
            <div style={{ marginBottom: 14 }}>
              {sectionTitle('Cercanos', <span style={{ fontSize: 11, color: p.inkMute }}>{cercanos.length === 1 ? '1 persona' : `${cercanos.length} personas`}</span>)}
              <div className="am-scroll-x">
                {cercanos.map(f => (
                  <button key={f.id} onClick={() => openChat(f)} className="am-press" style={{
                    flex: '0 0 auto', width: 72, background: 'transparent', border: 'none', cursor: 'pointer', padding: 0, color: p.ink, fontFamily: 'inherit',
                  }}>
                    <div style={{ display: 'flex', justifyContent: 'center', position: 'relative' }}>
                      <AmAvatar p={p} pose={f.posePreview} size={56} dotColor={f.dotColor} sos={!!f.sosEvt} ring />
                      {f.unread > 0 && !f.sosEvt && (
                        <span style={{ position: 'absolute', top: -4, right: 2, minWidth: 18, height: 18, borderRadius: 9, background: p.primaryDeep, color: '#fff', fontSize: 10, fontWeight: 700,
                          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', padding: '0 5px', border: `2px solid ${p.bg}` }}>{f.unread}</span>
                      )}
                    </div>
                    <div style={{ fontSize: 11, marginTop: 6, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{amFirstName(f.nickname || f.name)}</div>
                    <div style={{ fontSize: 10, color: f.sosEvt ? AM_RED : f.visibleFm ? amMoodColor(f.visibleFm.mood, p.inkMute) : p.inkMute, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {f.sosEvt ? 'SOS' : f.visibleFm ? AM_MOOD_LABEL[f.visibleFm.mood] || f.visibleFm.mood : '★ cercano'}
                    </div>
                  </button>
                ))}
              </div>
            </div>
          )}

          {!loading && friends.length > 0 && sectionTitle('Conversaciones', <span style={{ fontSize: 11, color: p.inkMute }}>{friends.length === 1 ? '1 amigo' : `${friends.length} amigos`}</span>)}
          <div className="am-grid">
            {enriched.map(f => (
              <div key={f.id} className="am-card" style={{
                position: 'relative', background: f.sosEvt ? 'rgba(197,82,75,0.06)' : p.surface,
                border: `1px solid ${f.sosEvt ? 'rgba(197,82,75,0.35)' : f.unread > 0 ? p.primary + '66' : p.line}`, borderRadius: 18,
                boxShadow: f.unread > 0 ? '0 4px 14px rgba(0,0,0,0.05)' : 'none',
              }}>
                <button onClick={() => openChat(f)} style={{
                  padding: '12px 46px 12px 12px', width: '100%', display: 'flex', alignItems: 'center', gap: 12, cursor: 'pointer',
                  color: p.ink, textAlign: 'left', background: 'transparent', border: 'none', borderRadius: 18, fontFamily: 'inherit',
                }}>
                  <AmAvatar p={p} pose={f.posePreview} size={52} dotColor={f.dotColor} sos={!!f.sosEvt} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
                      <span style={{ fontSize: 15, fontWeight: f.unread > 0 ? 700 : 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                        {f.nickname || f.name}
                      </span>
                      {f.nickname && <span style={{ fontSize: 11, color: p.inkMute, fontWeight: 400, flexShrink: 0 }}>{amFirstName(f.name)}</span>}
                      {f.isFavorite && <span title="Contacto cercano" style={{ fontSize: 12, color: AM_STAR, flexShrink: 0 }}>★</span>}
                      {f.muted && <span title="Silenciado" style={{ fontSize: 11, color: p.inkMute, flexShrink: 0 }}>🔕</span>}
                      <span style={{ marginLeft: 'auto', flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                        {f.time && !f.sosEvt && <span style={{ fontSize: 11, color: f.unread > 0 ? p.primaryDeep : p.inkMute, fontWeight: f.unread > 0 ? 600 : 400 }}>{f.time}</span>}
                      </span>
                    </div>
                    <div style={{ marginTop: 3, display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }}>
                      {f.sosEvt ? (
                        <span style={{ fontSize: 12.5, color: AM_RED, fontWeight: 600 }}>
                          Necesita apoyo · hace {f.sosMinAgo < 1 ? 'un momento' : `${f.sosMinAgo} min`} · Responder
                        </span>
                      ) : (
                        <>
                          {f.visibleFm && (
                            <span style={{ fontSize: 11, fontWeight: 600, color: amMoodColor(f.visibleFm.mood, p.inkSoft), flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                              <span style={{ width: 7, height: 7, borderRadius: 4, background: amMoodColor(f.visibleFm.mood, p.inkSoft), display: 'inline-block' }} />
                              {AM_MOOD_LABEL[f.visibleFm.mood] || f.visibleFm.mood}
                            </span>
                          )}
                          {f.visibleFm && <span style={{ color: p.line, fontSize: 11 }}>·</span>}
                          <span style={{ flex: 1, fontSize: 12.5, color: f.unread > 0 ? p.ink : p.inkSoft, fontWeight: f.unread > 0 ? 500 : 400,
                            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                            {f.last !== 'Toca para chatear' ? (f.isSender ? 'Tú: ' : '') + f.last : (f.visibleFm ? 'Toca para escribirle' : f.userType)}
                          </span>
                          {f.unread > 0 && (
                            <span style={{ minWidth: 20, height: 20, borderRadius: 10, background: p.primaryDeep, color: '#fff', fontSize: 11, fontWeight: 700,
                              display: 'inline-flex', alignItems: 'center', justifyContent: 'center', padding: '0 6px', flexShrink: 0 }}>{f.unread > 99 ? '99+' : f.unread}</span>
                          )}
                        </>
                      )}
                    </div>
                  </div>
                </button>
                <button onClick={() => { setMenuOpen(f.id); setConfirmRemove(false); setEditingNick(null); }} aria-label={`Opciones de ${f.nickname || f.name}`} className="am-press" style={{
                  position: 'absolute', top: '50%', right: 8, transform: 'translateY(-50%)', width: 34, height: 34,
                  background: 'transparent', border: 'none', cursor: 'pointer', color: p.inkMute,
                  fontSize: 18, display: 'grid', placeItems: 'center', borderRadius: 10, letterSpacing: '0.06em',
                }}>···</button>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* ── Solicitudes ── */}
      {tab === 'reqs' && (
        <div style={{ marginTop: 16 }}>
          {requests.length === 0 && sentRequests.length === 0 && (
            <AmEmpty p={p} pose="rest" title="Todo tranquilo por aquí"
              text={<span>Cuando alguien te mande una solicitud aparecerá aquí. Tu código es <b style={{ color: p.primaryDeep, fontFamily: 'ui-monospace, Menlo, monospace' }}>{myCode}</b>.</span>}
              action="Compartir mi código" onAction={() => { setShowAdd(true); setAddError(''); setAddCode(''); setAddSuccess(false); }} />
          )}
          {requests.length > 0 && sectionTitle('Quieren conectar contigo', <span style={{ fontSize: 11, color: p.inkMute }}>{requests.length}</span>)}
          <div className="am-grid">
            {requests.map((r, i) => {
              const st = reqBusy[r.id];
              return (
                <div key={r.id} style={{
                  padding: 14, background: st === 'accepted' ? p.primarySoft : p.surface, border: `1px solid ${st === 'accepted' ? p.primary : p.line}`, borderRadius: 18,
                  position: 'relative', overflow: 'hidden', transition: 'all .3s', animation: 'amRise .22s ease',
                }}>
                  <div style={{ position: 'absolute', left: -26, top: -26, width: 92, height: 92, borderRadius: '50%', background: p.primarySoft, opacity: 0.5, pointerEvents: 'none' }} />
                  <div style={{ display: 'flex', alignItems: 'center', gap: 12, position: 'relative' }}>
                    <AmAvatar p={p} pose={POSES[i % POSES.length]} size={52} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 15, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.name}</div>
                      <div style={{ fontSize: 12, color: p.inkMute, marginTop: 2 }}>
                        {r.userType} · <span style={{ color: p.primaryDeep, fontWeight: 600 }}>quiere conectar contigo</span>
                      </div>
                    </div>
                  </div>
                  <div style={{ display: 'flex', gap: 8, marginTop: 12, position: 'relative' }}>
                    {st === 'accepted' ? (
                      <div style={{ flex: 1, textAlign: 'center', padding: '10px', color: p.primaryDeep, fontWeight: 600, fontSize: 13 }}>✓ Ahora son amigos</div>
                    ) : (
                      <>
                        <button onClick={() => handleAccept(r)} disabled={!!st} className="am-press" style={{ ...amBtnPrimary(p, !!st), flex: 1.4, padding: '11px 12px', fontSize: 13, borderRadius: 12, opacity: st === 'rejecting' ? 0.5 : 1 }}>
                          {st === 'accepting' ? 'Aceptando…' : 'Aceptar'}
                        </button>
                        <button onClick={() => handleReject(r)} disabled={!!st} className="am-press" style={{ ...amBtnGhost(p), flex: 1, padding: '11px 12px', fontSize: 13, borderRadius: 12, opacity: st ? 0.5 : 1 }}>
                          {st === 'rejecting' ? 'Quitando…' : 'Rechazar'}
                        </button>
                      </>
                    )}
                  </div>
                </div>
              );
            })}
          </div>

          {sentRequests.length > 0 && (
            <div style={{ marginTop: requests.length ? 22 : 0 }}>
              {sectionTitle('Enviadas · esperando respuesta', <span style={{ fontSize: 11, color: p.inkMute }}>{sentRequests.length}</span>)}
              <div className="am-grid">
                {sentRequests.map(r => (
                  <div key={r.id} style={{ padding: '10px 12px', background: p.surface, border: `1px dashed ${p.line}`, borderRadius: 16, display: 'flex', alignItems: 'center', gap: 10 }}>
                    <AmAvatar p={p} pose="sit" size={40} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 14, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.name}</div>
                      <div style={{ fontSize: 11, color: p.inkMute }}>{r.userType} · aún no responde</div>
                    </div>
                    <button onClick={() => handleCancelSent(r)} style={{ ...amBtnGhost(p), padding: '7px 10px', fontSize: 12, borderRadius: 999 }}>Cancelar</button>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>
      )}

      {/* ── Grupos ── */}
      {tab === 'grupos' && (
        <div style={{ marginTop: 16 }}>
          {gruposLoading && (
            <div style={{ textAlign: 'center', padding: 32, color: p.inkMute, fontSize: 13 }}>
              <Turtle pose="sit" size={60} animate style={{ margin: '0 auto' }} /><div style={{ marginTop: 8 }}>Cargando grupos…</div>
            </div>
          )}
          {!gruposLoading && (
            <>
              <div style={{ display: 'flex', gap: 8, marginBottom: 18 }}>
                <button onClick={() => { setShowCreateGroup(true); setGroupName(''); setSelectedFriends([]); setGroupError(''); }} className="am-press" style={{ ...amBtnPrimary(p, false), flex: 1, padding: '12px 10px', fontSize: 13 }}>
                  + Crear grupo
                </button>
                <button onClick={() => { setShowClaseModal(true); setClaseTab('unirse'); setClaseError(''); setClaseSuccess(''); setJoinCode(''); }} className="am-press" style={{ ...amBtnGhost(p), flex: 1, padding: '12px 10px', fontSize: 13, color: p.primaryDeep, borderColor: p.primary + '88' }}>
                  Unirme con código
                </button>
              </div>

              {sectionTitle('Mis grupos', misGrupos.length > 0 && <span style={{ fontSize: 11, color: p.inkMute }}>{misGrupos.length}</span>)}
              {misGrupos.length === 0 ? (
                <AmEmpty p={p} pose="walk" compact title="Sin grupos todavía" text="Crea uno con tus amigos y compartan cómo van." />
              ) : (
                <div className="am-grid">
                  {misGrupos.map(g => <AmGroupCard key={g.id} p={p} g={g} icon="👥" onOpen={() => onOpenClass && onOpenClass(g)} />)}
                </div>
              )}

              <div style={{ marginTop: 22 }}>
                {sectionTitle('Clases e instituciones', (
                  <button onClick={() => { setShowClaseModal(true); setClaseTab('crear'); setClaseError(''); setClaseSuccess(''); setClassName(''); setClassInstitution(''); setClassType('Educativa'); setJoinCode(''); }}
                    style={{ background: 'transparent', border: 'none', color: p.primaryDeep, fontSize: 12, fontWeight: 600, cursor: 'pointer', fontFamily: 'inherit', padding: 0 }}>+ Crear clase</button>
                ))}
                {misClases.length === 0 ? (
                  <AmEmpty p={p} pose="meditate" compact title="Sin clases todavía" text="Únete con el código que te dé tu institución o crea la tuya." />
                ) : (
                  <div className="am-grid">
                    {misClases.map(g => <AmGroupCard key={g.id} p={p} g={g} icon={g.type === 'Laboral' ? '🏢' : '🎓'} onOpen={() => onOpenClass && onOpenClass(g)} />)}
                  </div>
                )}
              </div>
            </>
          )}
        </div>
      )}

      {/* Hoja: opciones de un amigo */}
      {menuFriend && (
        <AmSheet p={p} onClose={() => { setMenuOpen(null); setEditingNick(null); setConfirmRemove(false); }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14 }}>
            <AmAvatar p={p} pose={menuFriend.posePreview} size={48} dotColor={menuFriend.dotColor} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 17, fontFamily: 'Fraunces, serif', fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{menuFriend.nickname || menuFriend.name}</div>
              <div style={{ fontSize: 12, color: p.inkMute }}>{menuFriend.nickname ? menuFriend.name + ' · ' : ''}{menuFriend.userType}{menuFriend.visibleFm ? ' · ' + amMoodText(menuFriend.visibleFm) : ''}</div>
            </div>
            {menuFriend.personalCode && <AmCodeChip p={p} code={menuFriend.personalCode} size="sm" />}
          </div>

          {editingNick === menuFriend.id ? (
            <div style={{ marginBottom: 12 }}>
              <div style={{ fontSize: 11, color: p.inkSoft, marginBottom: 6, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.04em' }}>Apodo</div>
              <div style={{ display: 'flex', gap: 8 }}>
                <input autoFocus value={nickInput} onChange={e => setNickInput(e.target.value)} placeholder={menuFriend.name}
                  onKeyDown={e => {
                    if (e.key === 'Enter') {
                      const n = nickInput.trim(); setNickname(userId, menuFriend.id, n);
                      setFriends(fs => fs.map(x => x.id === menuFriend.id ? { ...x, nickname: n || null } : x)); setEditingNick(null);
                    }
                    if (e.key === 'Escape') setEditingNick(null);
                  }}
                  style={{ ...amInput(p, false), flex: 1, width: 'auto' }} />
                <button onClick={() => {
                  const n = nickInput.trim(); setNickname(userId, menuFriend.id, n);
                  setFriends(fs => fs.map(x => x.id === menuFriend.id ? { ...x, nickname: n || null } : x)); setEditingNick(null);
                }} style={{ ...amBtnPrimary(p, false), padding: '11px 16px' }}>OK</button>
              </div>
            </div>
          ) : (
            <div style={{ background: p.surface, border: `1px solid ${p.line}`, borderRadius: 16, overflow: 'hidden' }}>
              {[
                { icon: '💬', label: 'Abrir chat', on: () => openChat(menuFriend) },
                onOpenProfile && { icon: '✦', label: 'Ver muro', on: () => { setMenuOpen(null); onOpenProfile(menuFriend); } },
                { icon: menuFriend.isFavorite ? '☆' : '★', label: menuFriend.isFavorite ? 'Quitar de cercanos' : 'Agregar a cercanos', on: () => toggleFavorite(menuFriend), color: menuFriend.isFavorite ? p.inkMute : AM_STAR },
                { icon: '✎', label: menuFriend.nickname ? 'Cambiar apodo' : 'Poner apodo', on: () => { setEditingNick(menuFriend.id); setNickInput(menuFriend.nickname || ''); }, right: menuFriend.nickname },
                { icon: menuFriend.muted ? '🔔' : '🔕', label: menuFriend.muted ? 'Activar notificaciones' : 'Silenciar notificaciones', on: () => {
                  const newMuted = toggleMuteFriend(userId, menuFriend.id);
                  setFriends(fs => fs.map(x => x.id === menuFriend.id ? { ...x, muted: newMuted } : x));
                } },
              ].filter(Boolean).map((row, i, arr) => (
                <button key={row.label} onClick={row.on} style={{
                  width: '100%', padding: '14px 16px', background: 'transparent', border: 'none', textAlign: 'left', fontSize: 14, color: p.ink,
                  cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 12, fontFamily: 'inherit',
                  borderBottom: i < arr.length - 1 ? `1px solid ${p.line}` : 'none',
                }}>
                  <span style={{ fontSize: 17, width: 22, textAlign: 'center', color: row.color }}>{row.icon}</span>
                  <span>{row.label}</span>
                  {row.right && <span style={{ marginLeft: 'auto', color: p.inkMute, fontSize: 12 }}>{row.right}</span>}
                </button>
              ))}
            </div>
          )}

          {confirmRemove ? (
            <div style={{ marginTop: 12, padding: 14, borderRadius: 14, background: 'rgba(197,82,75,0.08)', border: '1px solid rgba(197,82,75,0.3)' }}>
              <div style={{ fontSize: 13, color: p.ink, lineHeight: 1.5 }}>¿Quitar a <b>{menuFriend.nickname || menuFriend.name}</b> de tu red? Dejarán de ver su ánimo y sus mensajes nuevos.</div>
              <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
                <button onClick={() => handleRemove(menuFriend)} style={{ ...amBtnPrimary(p, false), background: AM_RED, flex: 1, padding: '10px' }}>Sí, quitar</button>
                <button onClick={() => setConfirmRemove(false)} style={{ ...amBtnGhost(p), flex: 1, padding: '10px' }}>Cancelar</button>
              </div>
            </div>
          ) : (
            <button onClick={() => setConfirmRemove(true)} style={{ marginTop: 12, width: '100%', padding: 12, background: 'transparent', border: 'none', color: AM_RED, fontSize: 13, fontWeight: 600, cursor: 'pointer', fontFamily: 'inherit' }}>
              Quitar de mi red
            </button>
          )}
        </AmSheet>
      )}

      {/* Hoja: agregar por código */}
      {showAdd && (
        <AmSheet p={p} onClose={() => setShowAdd(false)}>
          <div style={{ fontSize: 18, fontWeight: 600, fontFamily: 'Fraunces, serif', marginBottom: 4 }}>Agregar amigo</div>
          <div style={{ fontSize: 13, color: p.inkMute, marginBottom: 16, lineHeight: 1.5 }}>Cada persona tiene un código. Comparte el tuyo o escribe el de alguien.</div>

          <div style={{ background: p.primarySoft, padding: '14px 16px', borderRadius: 16, display: 'flex', alignItems: 'center', gap: 12, marginBottom: 18 }}>
            <Turtle pose="chat" size={48} animate />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 10.5, color: p.primaryDeep, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Tu código</div>
              <div style={{ fontFamily: 'Fraunces, serif', fontSize: 28, fontWeight: 500, color: p.ink, letterSpacing: '0.12em', lineHeight: 1.15 }}>{myCode}</div>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              <button onClick={async () => { const ok = await amCopy(myCode); if (ok) { amHaptic('light'); setMyCodeCopied(true); setTimeout(() => setMyCodeCopied(false), 1600); } }}
                style={{ ...amBtnPrimary(p, false), padding: '8px 12px', fontSize: 12, borderRadius: 999, minWidth: 92 }}>{myCodeCopied ? '✓ Copiado' : 'Copiar'}</button>
              {typeof navigator !== 'undefined' && navigator.share && (
                <button onClick={() => navigator.share({ title: 'Mi código de Serenia', text: `Agrégame en Serenia con mi código ${myCode}` }).catch(() => {})}
                  style={{ ...amBtnGhost(p), padding: '8px 12px', fontSize: 12, borderRadius: 999, color: p.primaryDeep, borderColor: p.primary + '88' }}>Compartir</button>
              )}
            </div>
          </div>

          <div style={{ display: 'flex', alignItems: 'center', gap: 10, margin: '0 0 12px', color: p.inkMute, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600 }}>
            <span style={{ flex: 1, height: 1, background: p.line }} />o agrega a alguien<span style={{ flex: 1, height: 1, background: p.line }} />
          </div>
          <label style={{ fontSize: 12, color: p.inkSoft, display: 'block', marginBottom: 6 }}>Código de tu amigo (SR-XXXX)</label>
          <input
            value={addCode}
            onChange={e => { setAddCode(e.target.value.toUpperCase()); setAddError(''); }}
            onKeyDown={e => e.key === 'Enter' && handleSendRequest()}
            placeholder="SR-XXXX" maxLength={7} autoCapitalize="characters" autoCorrect="off" spellCheck={false}
            style={{ ...amInput(p, !!addError), fontFamily: 'Fraunces, serif', letterSpacing: '0.14em', textAlign: 'center', fontSize: 20 }} />
          {addError && <div role="alert" style={{ fontSize: 12, color: AM_RED, marginTop: 8, padding: '8px 12px', background: 'rgba(197,82,75,0.08)', borderRadius: 10 }}>{addError}</div>}
          {addSuccess && <div role="status" style={{ fontSize: 13, color: '#4E7C5C', marginTop: 8, padding: '8px 12px', background: 'rgba(107,155,122,0.14)', borderRadius: 10, fontWeight: 600 }}>¡Solicitud enviada! 🌿 Te avisaremos cuando acepte.</div>}
          <button onClick={handleSendRequest} disabled={!addCode.trim() || addLoading} className="am-press" style={{ ...amBtnPrimary(p, !addCode.trim() || addLoading), marginTop: 14, width: '100%', padding: 14 }}>
            {addLoading ? 'Enviando…' : 'Enviar solicitud'}
          </button>
        </AmSheet>
      )}

      {/* Hoja: crear grupo */}
      {showCreateGroup && (
        <AmSheet p={p} onClose={() => setShowCreateGroup(false)}>
          <div style={{ fontSize: 18, fontWeight: 600, fontFamily: 'Fraunces, serif', marginBottom: 4 }}>Crear grupo</div>
          <div style={{ fontSize: 13, color: p.inkMute, marginBottom: 16 }}>Grupo privado: agrega amigos directamente o comparte su código después.</div>
          <label style={{ fontSize: 12, color: p.inkSoft, display: 'block', marginBottom: 6 }}>Nombre del grupo</label>
          <input value={groupName} onChange={e => { setGroupName(e.target.value); setGroupError(''); }} placeholder="Ej. Familia, Equipo de trabajo…" style={{ ...amInput(p, false), marginBottom: 16 }} />
          {friends.length > 0 && (
            <>
              <div style={{ fontSize: 12, color: p.inkSoft, marginBottom: 8 }}>Agregar amigos al grupo</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginBottom: 16 }}>
                {friends.map(f => {
                  const sel = selectedFriends.includes(f.id);
                  return (
                    <button key={f.id} onClick={() => toggleFriendSelect(f.id)} style={{
                      padding: '9px 12px', borderRadius: 14, border: `1px solid ${sel ? p.primaryDeep : p.line}`, background: sel ? p.primarySoft : p.surface,
                      display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit', color: p.ink,
                    }}>
                      <AmAvatar p={p} pose={f.pose} size={34} />
                      <span style={{ flex: 1, fontSize: 14 }}>{f.nickname || f.name}</span>
                      <span style={{ fontSize: 16, color: sel ? p.primaryDeep : p.inkMute }}>{sel ? '✓' : '+'}</span>
                    </button>
                  );
                })}
              </div>
            </>
          )}
          {groupError && <div role="alert" style={{ fontSize: 12, color: AM_RED, marginBottom: 12, padding: '8px 12px', background: 'rgba(197,82,75,0.08)', borderRadius: 10 }}>{groupError}</div>}
          <button onClick={handleCreateGroup} disabled={!groupName.trim() || groupLoading} className="am-press" style={{ ...amBtnPrimary(p, !groupName.trim() || groupLoading), width: '100%', padding: 14 }}>
            {groupLoading ? 'Creando…' : 'Crear grupo'}
          </button>
        </AmSheet>
      )}

      {/* Hoja: crear clase / unirse con código */}
      {showClaseModal && (
        <AmSheet p={p} onClose={() => setShowClaseModal(false)}>
          <div style={{ fontSize: 18, fontWeight: 600, fontFamily: 'Fraunces, serif', marginBottom: 14 }}>Clases y grupos con código</div>
          <div role="tablist" style={{ display: 'flex', gap: 4, padding: 4, background: p.surface, borderRadius: 12, border: `1px solid ${p.line}`, marginBottom: 18 }}>
            {[{ id: 'unirse', label: 'Unirme con código' }, { id: 'crear', label: 'Crear clase' }].map(t => (
              <button key={t.id} role="tab" aria-selected={claseTab === t.id} onClick={() => { setClaseTab(t.id); setClaseError(''); setClaseSuccess(''); }} style={{
                flex: 1, padding: '8px 8px', borderRadius: 9, border: 'none', fontFamily: 'inherit',
                background: claseTab === t.id ? p.bg : 'transparent', color: claseTab === t.id ? p.ink : p.inkMute,
                boxShadow: claseTab === t.id ? '0 2px 8px rgba(0,0,0,0.08)' : 'none',
                fontWeight: claseTab === t.id ? 700 : 500, fontSize: 13, cursor: 'pointer',
              }}>{t.label}</button>
            ))}
          </div>

          {claseTab === 'crear' && (
            <>
              <label style={{ fontSize: 12, color: p.inkSoft, display: 'block', marginBottom: 6 }}>Nombre de la clase</label>
              <input value={className} onChange={e => { setClassName(e.target.value); setClaseError(''); }} placeholder="Ej. Biología 3A, Equipo Ventas…" style={{ ...amInput(p, false), marginBottom: 12 }} />
              <label style={{ fontSize: 12, color: p.inkSoft, display: 'block', marginBottom: 6 }}>Institución (opcional)</label>
              <input value={classInstitution} onChange={e => setClassInstitution(e.target.value)} placeholder="Ej. Tec de Ciudad Valles, Empresa…" style={{ ...amInput(p, false), marginBottom: 12 }} />
              <div style={{ fontSize: 12, color: p.inkSoft, marginBottom: 8 }}>Tipo</div>
              <div style={{ display: 'flex', gap: 6, marginBottom: 16 }}>
                {['Educativa', 'Laboral', 'Privada'].map(t => (
                  <button key={t} onClick={() => setClassType(t)} style={{
                    flex: 1, padding: '9px 4px', borderRadius: 12, fontFamily: 'inherit',
                    border: `1px solid ${classType === t ? p.primaryDeep : p.line}`, background: classType === t ? p.primarySoft : p.surface,
                    color: classType === t ? p.primaryDeep : p.inkSoft, fontSize: 13, fontWeight: classType === t ? 700 : 400, cursor: 'pointer',
                  }}>{t}</button>
                ))}
              </div>
              {claseError && <div role="alert" style={{ fontSize: 12, color: AM_RED, marginBottom: 12, padding: '8px 12px', background: 'rgba(197,82,75,0.08)', borderRadius: 10 }}>{claseError}</div>}
              {claseSuccess && <div role="status" style={{ fontSize: 13, color: '#4E7C5C', marginBottom: 12, padding: '8px 12px', background: 'rgba(107,155,122,0.14)', borderRadius: 10, fontWeight: 600 }}>✓ {claseSuccess}</div>}
              <button onClick={handleCreateClass} disabled={!className.trim() || claseLoading} className="am-press" style={{ ...amBtnPrimary(p, !className.trim() || claseLoading), width: '100%', padding: 14 }}>
                {claseLoading ? 'Creando…' : 'Crear clase'}
              </button>
            </>
          )}

          {claseTab === 'unirse' && (
            <>
              <label style={{ fontSize: 12, color: p.inkSoft, display: 'block', marginBottom: 8 }}>Código del grupo o clase (ej. CL-A1B2)</label>
              <input value={joinCode} onChange={e => { setJoinCode(e.target.value.toUpperCase()); setClaseError(''); }}
                onKeyDown={e => e.key === 'Enter' && handleJoinClass()} placeholder="CL-XXXX" maxLength={7} autoCapitalize="characters" autoCorrect="off" spellCheck={false}
                style={{ ...amInput(p, !!claseError), fontFamily: 'Fraunces, serif', letterSpacing: '0.14em', textAlign: 'center', fontSize: 20, marginBottom: 12 }} />
              {claseError && <div role="alert" style={{ fontSize: 12, color: AM_RED, marginBottom: 12, padding: '8px 12px', background: 'rgba(197,82,75,0.08)', borderRadius: 10 }}>{claseError}</div>}
              {claseSuccess && <div role="status" style={{ fontSize: 13, color: '#4E7C5C', marginBottom: 12, padding: '8px 12px', background: 'rgba(107,155,122,0.14)', borderRadius: 10, fontWeight: 600 }}>✓ {claseSuccess}</div>}
              <button onClick={handleJoinClass} disabled={!joinCode.trim() || claseLoading} className="am-press" style={{ ...amBtnPrimary(p, !joinCode.trim() || claseLoading), width: '100%', padding: 14 }}>
                {claseLoading ? 'Uniéndome…' : 'Unirme'}
              </button>
            </>
          )}
        </AmSheet>
      )}
    </div>
  );
}

// Tarjeta de grupo / clase
function AmGroupCard({ p, g, icon, onOpen }) {
  const inst = (g.institution || '').replace(/SerenIA/g, 'Serenia');
  return (
    <div className="am-card" style={{ background: p.surface, border: `1px solid ${p.line}`, borderRadius: 18, position: 'relative' }}>
      <button onClick={onOpen} style={{
        padding: '12px 14px', width: '100%', display: 'flex', alignItems: 'center', gap: 12, cursor: 'pointer', textAlign: 'left',
        background: 'transparent', border: 'none', color: p.ink, fontFamily: 'inherit', borderRadius: 18,
      }}>
        <div style={{ width: 46, height: 46, borderRadius: 14, background: p.primarySoft, display: 'grid', placeItems: 'center', fontSize: 22, flexShrink: 0 }}>{icon}</div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ fontSize: 15, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{g.name}</span>
            <span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase', padding: '2px 7px', borderRadius: 999, flexShrink: 0,
              background: g.role === 'admin' ? p.accentSoft : p.bg, color: g.role === 'admin' ? p.accent : p.inkMute, border: `1px solid ${g.role === 'admin' ? p.accent + '66' : p.line}` }}>
              {g.role === 'admin' ? 'Admin' : 'Miembro'}
            </span>
          </div>
          <div style={{ fontSize: 12, color: p.inkMute, marginTop: 3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
            {g.type === 'Grupo' ? 'Grupo privado' : g.type || 'Clase'}{inst ? ` · ${inst}` : ''}{g.members_count ? ` · ${g.members_count} personas` : ''}
          </div>
        </div>
        <span style={{ fontSize: 20, color: p.inkMute, flexShrink: 0 }}>›</span>
      </button>
      {g.code && (
        <div style={{ padding: '0 14px 12px', display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 11, color: p.inkMute }}>Invitar:</span>
          <AmCodeChip p={p} code={g.code} size="sm" />
        </div>
      )}
    </div>
  );
}

window.FriendsScreen = FriendsScreen;
