// Mobile screens — NTP, Tabs, Chat list, Chat thread, Mesh peers
// Used by all 3 navigation variants.

// ───── NTP (no quick-action tiles, single search, recent + news) ─────
// Brand-glyph favicon — a rounded tile with the site's real wordmark letter,
// styled to feel like the actual app icon rather than a generic monogram.
function MFav({ site, size = 30, radius = 8 }) {
  return (
    <div style={{
      width: size, height: size, borderRadius: radius, flexShrink: 0,
      background: site.bg, color: site.c || '#fff',
      display: 'grid', placeItems: 'center', overflow: 'hidden',
      fontFamily: site.font || 'Geist, Inter, sans-serif', fontWeight: 700,
      fontSize: size * (site.glyph && site.glyph.length > 1 ? 0.34 : 0.5),
      letterSpacing: '-0.03em', border: (site.c === '#000' || site.bg === '#FFF') ? '1px solid ' + M_BORDER_SOFT : 0,
      boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.12)',
    }}>{site.glyph || site.t[0]}</div>
  );
}

function MScreenNTP({ onOpenSearch, onOpenSite, topOffset = 0, bottomOffset = 80 }) {
  const recents = [
    { t: 'suiii (Official Video)', u: 'm.youtube.c…', bg: '#FF0000', glyph: 'yt' },
    { t: 'Ram (Official Audio)', u: 'm.youtube.c…', bg: '#FF0000', glyph: 'yt' },
    { t: 'MF GABHRU! (Official Video)',  u: 'm.youtube.c…', bg: '#FF0000', glyph: 'yt' },
    { t: 'Morni (Official Video)',       u: 'm.youtube.c…', bg: '#FF0000', glyph: 'yt' },
    { t: 'Linear — Inbox',               u: 'linear.app',   bg: '#5E6AD2', glyph: 'L' },
    { t: 'Figma — Ajna UI',              u: 'figma.com',    bg: '#1E1E1E', glyph: 'F' },
  ];
  const cats = ['Top Stories', 'Crypto', 'Tech', 'Science', 'World', 'Finance', 'Sports', 'Entertainment'];
  const news = [
    { tag: 'BBC',       time: '9m',  title: 'UK millionaires ask Andy Burnham to tax them more', img: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400' },
    { tag: 'Firstpost', time: '16m', title: 'CJP Jantar Mantar Protest Live Updates: Delhi Police clarifies NSA order, says renewal not linked to CJP…', img: 'https://images.unsplash.com/photo-1591189863430-ab87e120f312?w=400' },
    { tag: 'DECRYPT',   time: '2h',  title: 'OpenAI poaches Coinbase marketing leadership in AI-crypto crossover', img: 'https://images.unsplash.com/photo-1639322537228-f710d846310a?w=400' },
    { tag: 'THE VERGE', time: '5h',  title: 'Apple opens on-device foundation models to third-party apps', img: 'https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=400' },
    { tag: 'ARS',       time: '8h',  title: 'The quiet return of peer-to-peer: why local-first is winning again', img: 'https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=400' },
    { tag: 'WIRED',     time: '11h', title: 'Inside the mesh networks keeping cities online during outages', img: 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=400' },
    { tag: 'HN',        time: '1d',  title: 'Show HN: I built an offline-first browser with a built-in AI', img: 'https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=400' },
  ];
  const [cat, setCat] = React.useState('Top Stories');
  const now = new Date();
  const dayName = now.toLocaleDateString('en-US', { weekday: 'long' }).toUpperCase();
  const monName = now.toLocaleDateString('en-US', { month: 'long' }).toUpperCase();
  const hr = now.getHours();
  const greeting = hr < 12 ? 'Good morning' : hr < 18 ? 'Good afternoon' : 'Good evening';
  const ytIcon = (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff"><path d="m10 15 5.19-3L10 9v6Z"/><path d="M21.6 7.2a2.5 2.5 0 0 0-1.77-1.77C18.25 5 12 5 12 5s-6.25 0-7.83.43A2.5 2.5 0 0 0 2.4 7.2 26 26 0 0 0 2 12a26 26 0 0 0 .4 4.8 2.5 2.5 0 0 0 1.77 1.77C5.75 19 12 19 12 19s6.25 0 7.83-.43a2.5 2.5 0 0 0 1.77-1.77A26 26 0 0 0 22 12a26 26 0 0 0-.4-4.8Z" fill="#FF0000"/><path d="m10 15 5.19-3L10 9v6Z" fill="#fff"/></svg>
  );
  return (
    <div className="mntp-scroll" style={{ padding: `${20 + topOffset}px 0 ${bottomOffset + 20}px`, height: '100%', overflowY: 'auto', boxSizing: 'border-box' }}>
      <style>{`.mntp-scroll::-webkit-scrollbar{width:0;height:0;display:none}.mntp-scroll{scrollbar-width:none;-ms-overflow-style:none}.mntp-hrow::-webkit-scrollbar{display:none}.mntp-hrow{scrollbar-width:none}`}</style>
      <div style={{ textAlign: 'center', marginTop: 36, marginBottom: 26, padding: '0 20px' }}>
        <div style={{ fontSize: 12, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.15em', textTransform: 'uppercase' }}>{dayName} · {monName} {now.getDate()}</div>
        <div style={{ fontSize: 38, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.03em', marginTop: 6, color: M_FG }}>{greeting}</div>
      </div>
      <div onClick={onOpenSearch} className="glass" style={{
        display: 'flex', alignItems: 'center', gap: 10,
        padding: '14px 18px', margin: '0 20px 26px',
        borderRadius: 16, cursor: 'pointer',
      }}>
        <span style={{ color: M_FG_DIM }}>{MIc.search({ s: 18 })}</span>
        <span style={{ flex: 1, fontSize: 15, color: M_FG_MUTED }}>Search or type URL</span>
        <span style={{ color: M_FG_DIM }}>{MIc.mic({ s: 18 })}</span>
      </div>

      {/* Recent — horizontal scrolling cards */}
      <div style={{ fontSize: 10, fontWeight: 600, color: M_FG_DIM, letterSpacing: '0.12em', textTransform: 'uppercase', margin: '0 20px 12px' }}>Recent</div>
      <div className="mntp-hrow" style={{ display: 'flex', gap: 12, overflowX: 'auto', padding: '0 20px 4px', marginBottom: 30 }}>
        {recents.map((r, i) => (
          <div key={i} onClick={() => onOpenSite ? onOpenSite(r) : onOpenSearch()} style={{ flexShrink: 0, width: 132, background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 16, padding: 14, cursor: 'pointer' }}>
            <div style={{ width: 34, height: 34, borderRadius: 10, background: r.glyph === 'yt' ? '#fff' : r.bg, display: 'grid', placeItems: 'center', marginBottom: 12 }}>
              {r.glyph === 'yt' ? ytIcon : <span style={{ fontSize: 16, fontWeight: 700, color: r.c || '#fff', fontFamily: 'Geist' }}>{r.glyph}</span>}
            </div>
            <div style={{ fontSize: 13, fontWeight: 600, color: M_FG, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em', lineHeight: 1.25, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden', minHeight: 32 }}>{r.t}</div>
            <div style={{ fontSize: 11, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', marginTop: 8, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{r.u}</div>
          </div>
        ))}
      </div>

      {/* Briefing — category chips + news list */}
      <div style={{ fontSize: 10, fontWeight: 600, color: M_FG_DIM, letterSpacing: '0.12em', textTransform: 'uppercase', margin: '0 20px 12px' }}>Briefing</div>
      <div className="mntp-hrow" style={{ display: 'flex', gap: 9, overflowX: 'auto', padding: '0 20px 4px', marginBottom: 8 }}>
        {cats.map(c => {
          const active = c === cat;
          return (
            <button key={c} onClick={() => setCat(c)} style={{
              flexShrink: 0, padding: '9px 18px', borderRadius: 999, border: 0, cursor: 'pointer', fontFamily: 'Geist, Inter, sans-serif',
              fontSize: 13, fontWeight: active ? 600 : 500,
              background: active ? M_FG : M_SURFACE,
              color: active ? '#0B0C0F' : M_FG_MUTED,
              border: active ? 0 : '1px solid ' + M_BORDER_SOFT,
            }}>{c}</button>
          );
        })}
      </div>

      <div style={{ padding: '0 20px' }}>
        {news.map((n, i, arr) => (
          <div key={i} onClick={onOpenSearch} style={{ display: 'flex', gap: 14, padding: '16px 0', borderBottom: i < arr.length - 1 ? '1px solid ' + M_BORDER_SOFT : 'none', cursor: 'pointer' }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 11, fontFamily: 'JetBrains Mono, monospace', color: M_FG_DIM, letterSpacing: '0.04em' }}>{n.tag} · {n.time}</div>
              <div style={{ fontSize: 15, fontWeight: 500, marginTop: 6, lineHeight: 1.35, color: M_FG, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em' }}>{n.title}</div>
            </div>
            <div style={{ width: 72, height: 72, borderRadius: 12, background: `center/cover url(${n.img}), ${M_SURFACE_2}`, flexShrink: 0 }}/>
          </div>
        ))}
      </div>
    </div>
  );
}

// ───── Tab switcher ─────
function MScreenTabs() {
  const tabs = [
    { title: 'Linear — Inbox', fav: 'L', bg: '#5E6AD2', url: 'linear.app' },
    { title: 'Figma — Ajna UI', fav: 'F', bg: '#000', url: 'figma.com' },
    { title: 'GitHub · ajna-inc', fav: 'G', bg: '#24292F', url: 'github.com' },
    { title: 'Notion · P2P Sync RFC', fav: 'N', bg: '#FFF', c: '#000', url: 'notion.so' },
    { title: 'HN — News', fav: 'Y', bg: '#FF6600', url: 'news.yc' },
  ];
  return (
    <div style={{ padding: '20px 16px 100px', height: '100%', overflowY: 'auto', boxSizing: 'border-box' }}>
      <div style={{ fontSize: 22, fontWeight: 600, fontFamily: 'Geist', letterSpacing: '-0.02em', marginBottom: 18 }}>Tabs <span style={{ color: M_FG_DIM, fontWeight: 400 }}>· 5</span></div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        {tabs.map((t, i) => (
          <div key={i} style={{ aspectRatio: '3/4', background: M_SURFACE, border: '1px solid ' + M_BORDER, borderRadius: 14, overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: 8, borderBottom: '1px solid ' + M_BORDER_SOFT }}>
              <MTile size={16} bg={t.bg} color={t.c||'#fff'} label={t.fav} radius={3}/>
              <div style={{ fontSize: 9, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', flex: 1 }}>{t.url}</div>
            </div>
            <div style={{ flex: 1, padding: 10, fontSize: 11, color: M_FG_MUTED, lineHeight: 1.3 }}>{t.title}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ───── Chat list — EMPTY STATE ─────
// First-launch / cleared / no peers added yet.
// Reassures user about E2E + offers 3 concrete next actions.
function MScreenChatListEmpty({ onAdd }) {
  const actions = [
    { id: 'scan',    icon: MIc.scan,      label: 'Scan a QR code', sub: 'Connect in person',           accent: M_ACCENT },
    { id: 'share',   icon: MIc.bolt,      label: 'Share my code',  sub: 'Let someone scan you',        accent: M_ACCENT_B },
    { id: 'handle',  icon: MIc.globe,     label: 'Add by handle',  sub: 'alex.ajna or did:key:…',      accent: '#A78BFA' },
  ];
  const open = (mode) => { if (onAdd) onAdd(mode); };
  return (
    <div style={{ padding: '20px 20px 100px', height: '100%', overflowY: 'auto', boxSizing: 'border-box', display: 'flex', flexDirection: 'column' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 32 }}>
        <div style={{ fontSize: 26, fontWeight: 600, fontFamily: 'Geist', letterSpacing: '-0.02em' }}>Chat</div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button style={{ width: 36, height: 36, borderRadius: 10, background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, color: M_FG_DIM, display: 'grid', placeItems: 'center', opacity: 0.5 }}>{MIc.search({ s: 16 })}</button>
          <button onClick={() => open('handle')} style={{ width: 36, height: 36, borderRadius: 10, background: 'linear-gradient(135deg, ' + M_ACCENT + ', ' + M_ACCENT_B + ')', border: 0, color: '#0B0C0F', display: 'grid', placeItems: 'center' }}>{MIc.plus({ s: 16 })}</button>
        </div>
      </div>

      {/* Concentric-rings illustration — signal / mesh metaphor */}
      <div style={{ display: 'grid', placeItems: 'center', margin: '20px 0 28px' }}>
        <div style={{ position: 'relative', width: 180, height: 180 }}>
          {[180, 140, 100, 64].map((d, i) => (
            <div key={i} style={{
              position: 'absolute', inset: '50% 0 0 50%',
              width: d, height: d, marginLeft: -d/2, marginTop: -d/2,
              borderRadius: '50%',
              border: '1px solid rgba(110,231,183,' + (0.05 + i * 0.06) + ')',
              background: i === 3 ? 'radial-gradient(circle, rgba(110,231,183,0.18) 0%, rgba(96,165,250,0.06) 70%, transparent 100%)' : 'transparent',
            }}/>
          ))}
          <div style={{
            position: 'absolute', inset: '50% 0 0 50%',
            width: 44, height: 44, marginLeft: -22, marginTop: -22,
            borderRadius: '50%',
            background: 'linear-gradient(135deg, ' + M_ACCENT + ', ' + M_ACCENT_B + ')',
            display: 'grid', placeItems: 'center', color: '#0B0C0F',
            boxShadow: '0 8px 24px rgba(110,231,183,0.25)',
          }}>{MIc.chat({ s: 22 })}</div>
          {/* small peer dots floating on rings */}
          {[
            { t: 18, l: 142, c: '#A78BFA' },
            { t: 142, l: 22, c: '#22D3EE' },
            { t: 156, l: 130, c: '#F472B6' },
          ].map((p, i) => (
            <div key={i} style={{
              position: 'absolute', top: p.t, left: p.l,
              width: 10, height: 10, borderRadius: '50%',
              background: p.c, boxShadow: '0 0 12px ' + p.c,
              opacity: 0.85,
            }}/>
          ))}
        </div>
      </div>

      <div style={{ textAlign: 'center', marginBottom: 8 }}>
        <div style={{ fontSize: 19, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.02em', color: M_FG }}>No conversations yet</div>
        <div style={{ fontSize: 13, color: M_FG_MUTED, marginTop: 6, lineHeight: 1.45, maxWidth: 280, margin: '6px auto 0' }}>
          Ajna chat is end-to-end encrypted over DIDComm. Add a peer to start your first conversation.
        </div>
      </div>

      <div style={{ marginTop: 24, display: 'flex', flexDirection: 'column', gap: 8 }}>
        {actions.map((a, i) => (
          <button key={a.id} onClick={() => open(a.id)} style={{
            display: 'flex', alignItems: 'center', gap: 14,
            padding: '14px 16px', background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT,
            borderRadius: 14, color: M_FG, textAlign: 'left', cursor: 'pointer', fontFamily: 'inherit',
          }}>
            <div style={{
              width: 36, height: 36, borderRadius: 10,
              background: a.accent + '1F', color: a.accent,
              display: 'grid', placeItems: 'center', flexShrink: 0,
            }}>{a.icon({ s: 18 })}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>{a.label}</div>
              <div style={{ fontSize: 11.5, color: M_FG_MUTED, marginTop: 2 }}>{a.sub}</div>
            </div>
            <span style={{ color: M_FG_DIM }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m9 5 7 7-7 7"/></svg>
            </span>
          </button>
        ))}
      </div>

      <div style={{
        marginTop: 24, padding: '10px 14px',
        background: 'rgba(110,231,183,0.06)', border: '1px solid rgba(110,231,183,0.12)',
        borderRadius: 10, display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <span style={{ color: M_ACCENT }}>{MIc.shield({ s: 14 })}</span>
        <div style={{ flex: 1, fontSize: 11, color: M_FG_MUTED, lineHeight: 1.4 }}>
          Your identity <span style={{ color: M_FG, fontFamily: 'JetBrains Mono, monospace' }}>did:key:…9kTp</span> is ready. Messages never touch Ajna servers.
        </div>
      </div>
    </div>
  );
}

// ───── Chat list ─────
// Animated typing dots for list previews
function MTypingDots() {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3, marginRight: 6 }}>
      <style>{`@keyframes mTypDot{0%,60%,100%{opacity:0.25;transform:translateY(0)}30%{opacity:1;transform:translateY(-2px)}}`}</style>
      {[0,1,2].map(i => <span key={i} style={{ width: 4, height: 4, borderRadius: '50%', background: M_ACCENT_B, animation: `mTypDot 1.2s ${i*0.15}s infinite` }}/>)}
    </span>
  );
}

// Swipe-left row — reveals Pin / Mute / Archive. Locks horizontal intent and
// stops propagation so the Chat⇆Calls pager doesn't also swipe.
function MSwipeRow({ children, onTap, last }) {
  const actions = [
    { id: 'pin',     bg: 'rgba(96,165,250,0.18)',  color: M_ACCENT_B, icon: <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="m12 17 .01 4"/><path d="M9.85 13H3l3-5h12l3 5h-6.85"/><path d="M6 8 9 3h6l3 5"/></svg> },
    { id: 'mute',    bg: 'rgba(255,255,255,0.07)', color: M_FG_MUTED, icon: <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M13.73 21a2 2 0 0 1-3.46 0"/><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="m2 2 20 20"/></svg> },
    { id: 'archive', bg: 'rgba(248,113,113,0.16)', color: '#F87171',  icon: <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="2" y="3" width="20" height="5" rx="1"/><path d="M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8"/><path d="M10 12h4"/></svg> },
  ];
  const W = actions.length * 52;
  const [dx, setDx] = React.useState(0);
  const [dragging, setDragging] = React.useState(false);
  const openRef = React.useRef(false);
  const start = React.useRef(null);
  const lock = React.useRef(null);
  const moved = React.useRef(false);
  const down = (e) => { start.current = { x: e.clientX, y: e.clientY, base: openRef.current ? -W : 0 }; lock.current = null; moved.current = false; };
  const move = (e) => {
    if (!start.current) return;
    const mx = e.clientX - start.current.x, my = e.clientY - start.current.y;
    if (lock.current === null) {
      if (Math.abs(mx) < 8 && Math.abs(my) < 8) return;
      lock.current = Math.abs(mx) > Math.abs(my) ? 'h' : 'v';
      if (lock.current === 'h') { setDragging(true); try { e.currentTarget.setPointerCapture(e.pointerId); } catch {} }
    }
    if (lock.current !== 'h') return;
    e.stopPropagation(); moved.current = true;
    let v = start.current.base + mx;
    if (v > 0) v *= 0.25;
    if (v < -W - 24) v = -W - 24 + (v + W + 24) * 0.25;
    setDx(v);
  };
  const up = (e) => {
    if (!start.current) return;
    if (lock.current === 'h') {
      e.stopPropagation();
      const shouldOpen = dx < -W / 2;
      openRef.current = shouldOpen;
      setDx(shouldOpen ? -W : 0);
    }
    start.current = null; lock.current = null; setDragging(false);
  };
  const tap = () => {
    if (moved.current) { moved.current = false; return; }
    if (openRef.current) { openRef.current = false; setDx(0); return; }
    onTap && onTap();
  };
  return (
    <div style={{ position: 'relative', overflow: 'hidden', borderBottom: last ? 'none' : '1px solid ' + M_BORDER_SOFT }}>
      <div style={{ position: 'absolute', top: 0, bottom: 0, right: 0, width: W, display: 'flex', alignItems: 'stretch' }}>
        {actions.map(a => (
          <button key={a.id} onClick={() => { openRef.current = false; setDx(0); }} aria-label={a.id} style={{ width: 52, background: a.bg, border: 0, color: a.color, display: 'grid', placeItems: 'center', cursor: 'pointer' }}>{a.icon}</button>
        ))}
      </div>
      <div
        onPointerDown={down} onPointerMove={move} onPointerUp={up} onPointerCancel={up}
        onClick={tap}
        style={{ transform: `translateX(${dx}px)`, transition: dragging ? 'none' : 'transform 240ms cubic-bezier(0.2,0.85,0.3,1)', background: M_BG, touchAction: 'pan-y', cursor: 'pointer' }}>
        {children}
      </div>
    </div>
  );
}

// Message-state glyph for previews (✓✓ read/delivered, mic, camera)
function MMsgState({ state }) {
  const dbl = (c) => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><path d="m1.5 12.5 4.5 4.5L14.5 8.5"/><path d="m9.5 15.5 2 1.5L22 6.5"/></svg>;
  if (state === 'read') return dbl(M_ACCENT_B);
  if (state === 'delivered') return dbl(M_FG_DIM);
  if (state === 'voice') return <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke={M_ACCENT} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M5 10a7 7 0 0 0 14 0"/><path d="M12 19v3"/></svg>;
  if (state === 'photo') return <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke={M_FG_MUTED} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}><rect x="3" y="3" width="18" height="18" rx="3"/><circle cx="9" cy="9" r="2"/><path d="m21 15-5-5L5 21"/></svg>;
  return null;
}

function MScreenChatList({ onOpen, onAdd, headerless }) {
  const chats = [
    { name: 'Rohan Sharma',    initials: 'RS', bg: '#F472B6', avatar: 'https://i.pravatar.cc/120?img=12', typing: true, preview: 'typing…', time: '10:42', conn: 'internet', online: true, unread: 3, fav: true },
    { name: 'Design · Ajna',   initials: 'DA', bg: 'linear-gradient(135deg,#6EE7B7,#60A5FA)', group: true, sender: 'Priya', preview: 'pushed the new NTP mocks', time: '10:31', conn: 'internet', unread: 12 },
    { name: 'Aishwarya Iyer',  initials: 'AI', bg: '#EF4444', avatar: 'https://i.pravatar.cc/120?img=49', state: 'read', preview: 'see you at 6', time: '10:02', conn: 'internet', online: true, fav: true },
    { name: 'Priya Nair',      initials: 'PN', bg: '#22D3EE', avatar: 'https://i.pravatar.cc/120?img=47', state: 'voice', preview: 'Voice message · 0:42', time: '09:47', conn: 'ble', online: true, unread: 2, fav: true },
    { name: 'Arjun Mehta',     initials: 'AM', bg: '#6EE7B7', avatar: 'https://i.pravatar.cc/120?img=14', state: 'delivered', preview: 'on it 👍', time: 'Yesterday', conn: 'internet', online: true, fav: true },
    { name: 'Family',          initials: 'F',  bg: '#FB923C', group: true, sender: 'Amma', state: 'photo', preview: 'Photo', time: 'Yesterday', conn: 'internet', muted: true },
    { name: 'Dimitri Volkov',  initials: 'DV', bg: '#FBBF24', avatar: 'https://i.pravatar.cc/120?img=33', draft: true, preview: 'let me check the PR and get back', time: 'Mon', conn: 'internet' },
    { name: 'Team · Mesh',     initials: 'TM', bg: '#A78BFA', group: true, sender: 'Bob', preview: 'joined the mesh', time: 'Mon', conn: 'mesh' },
    { name: 'Maya Chen',       initials: 'MC', bg: '#A78BFA', state: 'read', preview: 'thanks!', time: 'Sat', conn: 'mediator' },
  ];
  const [query, setQuery] = React.useState('');
  const [filter, setFilter] = React.useState('all'); // all | unread | groups
  const unreadTotal = chats.filter(c => c.unread).length;
  const favs = chats.filter(c => c.fav);
  const visible = chats.filter(c =>
    (query === '' || c.name.toLowerCase().includes(query.toLowerCase())) &&
    (filter === 'all' || (filter === 'unread' && c.unread) || (filter === 'groups' && c.group))
  );
  const chip = (id, label, badge) => {
    const active = filter === id;
    return (
      <button key={id} onClick={() => setFilter(id)} style={{
        display: 'inline-flex', alignItems: 'center', gap: 6, padding: '6px 13px', borderRadius: 999,
        background: active ? 'rgba(96,165,250,0.16)' : M_SURFACE,
        border: '1px solid ' + (active ? 'rgba(96,165,250,0.4)' : M_BORDER_SOFT),
        color: active ? M_ACCENT_B : M_FG_MUTED, fontSize: 12, fontWeight: active ? 600 : 500,
        fontFamily: 'inherit', cursor: 'pointer', flexShrink: 0,
      }}>
        {label}
        {badge > 0 && <span style={{ fontSize: 9.5, fontWeight: 700, fontFamily: 'JetBrains Mono, monospace', padding: '0 5px', borderRadius: 4, background: active ? 'rgba(96,165,250,0.25)' : 'rgba(255,255,255,0.08)' }}>{badge}</span>}
      </button>
    );
  };
  return (
    <div style={{ padding: headerless ? '2px 0 100px' : '20px 0 100px', height: '100%', overflowY: 'auto', boxSizing: 'border-box' }}>
      {!headerless && (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', margin: '0 20px 14px' }}>
        <div style={{ fontSize: 26, fontWeight: 600, fontFamily: 'Geist', letterSpacing: '-0.02em' }}>Chat</div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button onClick={onAdd} style={{ width: 36, height: 36, borderRadius: 10, background: 'linear-gradient(135deg, ' + M_ACCENT + ', ' + M_ACCENT_B + ')', border: 0, color: '#0B0C0F', display: 'grid', placeItems: 'center' }}>{MIc.plus({ s: 16 })}</button>
        </div>
      </div>
      )}
      {/* Inline search — filters as you type */}
      <div style={{ margin: '0 20px 10px', display: 'flex', alignItems: 'center', gap: 9, padding: '9px 13px', background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 12 }}>
        <span style={{ color: M_FG_DIM, display: 'grid', placeItems: 'center' }}>{MIc.search({ s: 14 })}</span>
        <input value={query} onChange={e => setQuery(e.target.value)} placeholder="Search chats" style={{ flex: 1, background: 'transparent', border: 0, outline: 'none', color: M_FG, fontSize: 13.5, fontFamily: 'inherit', minWidth: 0 }}/>
        {query && <button onClick={() => setQuery('')} style={{ background: 'transparent', border: 0, color: M_FG_DIM, cursor: 'pointer', padding: 0, fontSize: 13 }}>✕</button>}
      </div>
      {/* Filter chips */}
      <div style={{ display: 'flex', gap: 7, margin: '0 20px 12px', overflowX: 'auto', scrollbarWidth: 'none' }}>
        {chip('all', 'All')}
        {chip('unread', 'Unread', unreadTotal)}
        {chip('groups', 'Groups')}
      </div>
      {/* Pinned favorites — one-tap open */}
      {query === '' && filter === 'all' && (
        <div style={{ display: 'flex', gap: 16, margin: '2px 20px 6px', overflowX: 'auto', scrollbarWidth: 'none', paddingBottom: 8 }}>
          {favs.map(f => (
            <button key={f.name} onClick={() => onOpen && onOpen(f)} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6, background: 'transparent', border: 0, cursor: 'pointer', padding: 0, flexShrink: 0, fontFamily: 'inherit' }}>
              <div style={{ position: 'relative' }}>
                <MTile size={52} bg={f.bg} color="#fff" label={f.initials} img={f.avatar} radius={26}/>
                {f.online && <div style={{ position: 'absolute', bottom: 1, right: 1, width: 12, height: 12, borderRadius: '50%', background: '#22D27A', border: '2px solid ' + M_BG }}/>}
                {f.unread > 0 && <div style={{ position: 'absolute', top: -2, right: -2, minWidth: 16, height: 16, padding: '0 4px', borderRadius: 8, background: M_ACCENT_B, color: '#0B0C0F', fontSize: 9, fontWeight: 700, display: 'grid', placeItems: 'center' }}>{f.unread}</div>}
              </div>
              <span style={{ fontSize: 10.5, color: M_FG_MUTED, fontFamily: 'Geist', maxWidth: 56, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{f.name.split(' ')[0]}</span>
            </button>
          ))}
        </div>
      )}
      {/* Chat rows — swipe left for Pin / Mute / Archive */}
      {visible.map((c, i) => (
        <MSwipeRow key={c.name} last={i === visible.length - 1} onTap={() => onOpen && onOpen(c)}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '13px 20px' }}>
            <div style={{ position: 'relative', flexShrink: 0 }}>
              <MTile size={48} bg={c.bg} color={c.group ? '#0B0C0F' : '#fff'} label={c.initials} img={c.avatar} radius={24}/>
              {c.online && <div style={{ position: 'absolute', bottom: 0, right: 0, width: 12, height: 12, borderRadius: '50%', background: '#22D27A', border: '2px solid ' + M_BG }}/>}
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontSize: 15, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', flex: 1, color: M_FG }}>{c.name}</span>
                <MConnChip type={c.conn}/>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 13, color: c.unread ? M_FG : M_FG_MUTED, marginTop: 4, fontWeight: c.unread ? 500 : 400, minWidth: 0 }}>
                {c.typing ? (
                  <><MTypingDots/><span style={{ color: M_ACCENT_B, fontSize: 12.5, fontStyle: 'italic' }}>typing…</span></>
                ) : (
                  <>
                    {c.draft && <span style={{ color: '#F87171', fontWeight: 600, fontSize: 12.5, flexShrink: 0 }}>Draft:</span>}
                    {!c.draft && <MMsgState state={c.state}/>}
                    {!c.draft && c.group && c.sender && <span style={{ color: M_FG, fontWeight: 500, flexShrink: 0 }}>{c.sender}:</span>}
                    <span style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.preview}</span>
                  </>
                )}
              </div>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 5, flexShrink: 0 }}>
              <span style={{ fontSize: 11, color: c.unread ? M_ACCENT_B : M_FG_DIM, fontFamily: 'JetBrains Mono, monospace' }}>{c.time}</span>
              <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
                {c.muted && <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke={M_FG_DIM} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M13.73 21a2 2 0 0 1-3.46 0"/><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="m2 2 20 20"/></svg>}
                {c.unread > 0 && <span style={{ minWidth: 18, height: 18, padding: '0 5px', borderRadius: 9, background: c.muted ? 'rgba(255,255,255,0.14)' : M_ACCENT_B, color: c.muted ? M_FG_MUTED : '#0B0C0F', fontSize: 10, fontWeight: 700, display: 'grid', placeItems: 'center' }}>{c.unread}</span>}
              </div>
            </div>
          </div>
        </MSwipeRow>
      ))}
      {visible.length === 0 && (
        <div style={{ padding: '40px 20px', textAlign: 'center', color: M_FG_DIM, fontSize: 12.5 }}>No chats match “{query}”</div>
      )}
      <div style={{ margin: '14px 20px 0', fontSize: 10.5, color: M_FG_DIM, textAlign: 'center', fontFamily: 'JetBrains Mono, monospace' }}>swipe a chat left to pin · mute · archive</div>
    </div>
  );
}

// ───── Chat thread ─────
// When `empty` is true (or peer.empty), shows the no-messages-yet state:
// peer identity card, verification status, encryption notice, and starter chips.
function MScreenChat({ onBack, peer, empty, onCall }) {
  const p = peer || { name: 'Aishwarya Iyer', initials: 'AI', bg: '#EF4444', avatar: 'https://i.pravatar.cc/120?img=49', conn: 'internet', online: true };
  const isEmpty = empty || p.empty;
  const [menuOpen, setMenuOpen] = React.useState(false);
  const [profileOpen, setProfileOpen] = React.useState(false);
  const [muted, setMuted] = React.useState(false);
  const [disappearing, setDisappearing] = React.useState(false);
  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: M_BG, position: 'relative' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', borderBottom: '1px solid ' + M_BORDER_SOFT }}>
        <button onClick={onBack} aria-label="Back to chats" style={{
          display: 'inline-flex', alignItems: 'center', gap: 4,
          background: 'transparent', border: 0, color: M_ACCENT_B,
          padding: '6px 6px 6px 2px', cursor: 'pointer',
          fontFamily: 'inherit', fontSize: 14, fontWeight: 500,
        }}>
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m15 18-6-6 6-6"/></svg>
          <span>Chats</span>
        </button>
        <MTile size={34} bg={p.bg} color="#fff" label={p.initials} img={p.avatar} radius={17}/>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 15, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.name}</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 5, marginTop: 2 }}>
            <span style={{ width: 5, height: 5, borderRadius: '50%', background: p.online ? '#22D27A' : M_FG_DIM }}/>
            <span style={{ fontSize: 10.5, color: M_FG_MUTED }}>{p.online ? 'Online' : 'Offline'}</span>
            <MConnChip type={p.conn}/>
          </div>
        </div>
        <button style={{ background: 'transparent', border: 0, color: M_FG, padding: 4, display: 'grid', placeItems: 'center', cursor: 'pointer' }}
          onClick={() => onCall && onCall(p, 'audio')} aria-label="Audio call">{MIc.calls({ s: 19 })}</button>
        <button style={{ background: 'transparent', border: 0, color: M_FG, padding: 4, display: 'grid', placeItems: 'center', cursor: 'pointer' }}
          onClick={() => onCall && onCall(p, 'video')} aria-label="Video call">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="m23 7-7 5 7 5z"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>
        </button>
        <button onClick={() => setMenuOpen(true)} aria-label="Chat options" style={{ background: 'transparent', border: 0, color: M_FG, padding: 4, display: 'grid', placeItems: 'center', cursor: 'pointer' }}>{MIc.more({ s: 20 })}</button>
      </div>

      {isEmpty ? (
        <div style={{ flex: 1, overflowY: 'auto', padding: '24px 20px 16px', display: 'flex', flexDirection: 'column' }}>
          {/* Peer identity card */}
          <div style={{
            margin: '12px auto 0', padding: '22px 20px',
            background: 'linear-gradient(180deg, rgba(110,231,183,0.06), rgba(96,165,250,0.04))',
            border: '1px solid ' + M_BORDER,
            borderRadius: 18, width: '100%', maxWidth: 320, textAlign: 'center', boxSizing: 'border-box',
          }}>
            <div style={{ display: 'grid', placeItems: 'center', marginBottom: 12 }}>
              <div style={{ position: 'relative' }}>
                <MTile size={72} bg={p.bg} color="#fff" label={p.initials} img={p.avatar} radius={36}/>
                <div style={{
                  position: 'absolute', bottom: -2, right: -2,
                  width: 24, height: 24, borderRadius: '50%',
                  background: M_BG, display: 'grid', placeItems: 'center',
                  border: '2px solid ' + M_BG,
                }}>
                  <div style={{ width: 18, height: 18, borderRadius: '50%', background: M_ACCENT, display: 'grid', placeItems: 'center', color: '#0B0C0F' }}>
                    <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
                  </div>
                </div>
              </div>
            </div>
            <div style={{ fontSize: 17, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.02em' }}>{p.name}</div>
            <div style={{ fontSize: 11, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', marginTop: 4 }}>
              did:peer:2.{(p.initials || 'XX').toLowerCase()}…7Mq
            </div>
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: 5, marginTop: 12, padding: '4px 10px', borderRadius: 999, background: 'rgba(110,231,183,0.12)', color: M_ACCENT, fontSize: 10.5, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.06em', textTransform: 'uppercase', fontWeight: 600 }}>
              {MIc.shield({ s: 11 })} Verified · {p.conn === 'ble' ? 'BLE mesh' : p.conn === 'mesh' ? 'Mesh' : 'DIDComm 2'}
            </div>
            <div style={{ fontSize: 12, color: M_FG_MUTED, marginTop: 14, lineHeight: 1.45 }}>
              Connected {p.connectedWhen || 'just now'} · no messages yet
            </div>
          </div>

          {/* Encryption / privacy notice */}
          <div style={{
            marginTop: 18, padding: '12px 14px',
            background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT,
            borderRadius: 12, display: 'flex', alignItems: 'flex-start', gap: 10,
          }}>
            <span style={{ color: M_ACCENT_B, marginTop: 1 }}>{MIc.shield({ s: 16 })}</span>
            <div style={{ flex: 1, fontSize: 11.5, color: M_FG_MUTED, lineHeight: 1.45 }}>
              Messages are end-to-end encrypted. Only you and <span style={{ color: M_FG }}>{p.name.split(' ')[0]}</span> can read them — not even Ajna.
            </div>
          </div>

          {/* Conversation starters */}
          <div style={{ marginTop: 20 }}>
            <div style={{ fontSize: 10, fontWeight: 600, color: M_FG_DIM, letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 10 }}>Break the ice</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {[
                { e: '👋', t: 'Say hi' },
                { e: '✨', t: 'Nice to connect' },
                { e: '📎', t: 'Send a file' },
                { e: '📞', t: 'Start a call' },
              ].map(s => (
                <button key={s.t} style={{
                  display: 'inline-flex', alignItems: 'center', gap: 6,
                  padding: '8px 12px', background: M_SURFACE,
                  border: '1px solid ' + M_BORDER_SOFT, borderRadius: 999,
                  color: M_FG, fontSize: 12.5, fontFamily: 'inherit', cursor: 'pointer',
                }}>
                  <span style={{ fontSize: 13 }}>{s.e}</span>{s.t}
                </button>
              ))}
            </div>
          </div>

          {/* Empty "scroll up to load" placeholder feels honest about the state */}
          <div style={{ flex: 1, minHeight: 20 }}/>
          <div style={{ textAlign: 'center', fontSize: 10, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.1em', marginTop: 12 }}>
            ── BEGINNING OF CONVERSATION ──
          </div>
        </div>
      ) : (
        <div style={{ flex: 1, padding: '16px', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ textAlign: 'center', fontSize: 10, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.1em', margin: '4px 0 12px' }}>9:39 AM · DIDCOMM END-TO-END ENCRYPTED</div>
          <div style={{ alignSelf: 'flex-start', maxWidth: '72%', background: M_SURFACE, color: M_FG, padding: '9px 13px', borderRadius: '16px 16px 16px 4px', fontSize: 14 }}>hi</div>
          <div style={{ alignSelf: 'flex-end', maxWidth: '72%', background: 'linear-gradient(135deg, ' + M_ACCENT + ', ' + M_ACCENT_B + ')', color: '#0B0C0F', padding: '9px 13px', borderRadius: '16px 16px 4px 16px', fontSize: 14, fontWeight: 500 }}>Hi</div>
          <div style={{ alignSelf: 'flex-end', fontSize: 10, color: M_FG_DIM, marginRight: 4 }}>Delivered · 9:39</div>
          <div style={{ alignSelf: 'flex-start', fontSize: 11, color: M_FG_MUTED, fontStyle: 'italic', marginTop: 4 }}>typing…</div>
        </div>
      )}

      <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 14px 14px', borderTop: '1px solid ' + M_BORDER_SOFT }}>
        <button style={{ width: 36, height: 36, borderRadius: 18, background: M_SURFACE, border: 0, color: M_FG, display: 'grid', placeItems: 'center', flexShrink: 0 }}>{MIc.plus({ s: 18 })}</button>
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 8, padding: '8px 14px', background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 20 }}>
          <span style={{ flex: 1, fontSize: 13.5, color: M_FG_MUTED }}>{isEmpty ? `Message ${p.name.split(' ')[0]}…` : 'Message…'}</span>
          <span style={{ color: M_FG_DIM }}>{MIc.mic({ s: 16 })}</span>
        </div>
      </div>

      {menuOpen && (
        <MChatOptionsSheet
          peer={p}
          muted={muted} setMuted={setMuted}
          disappearing={disappearing} setDisappearing={setDisappearing}
          onClose={() => setMenuOpen(false)}
          onViewProfile={() => { setMenuOpen(false); setProfileOpen(true); }}
          onCall={onCall}
        />
      )}
      {profileOpen && (
        <MContactProfile
          peer={p}
          muted={muted} setMuted={setMuted}
          disappearing={disappearing} setDisappearing={setDisappearing}
          onClose={() => setProfileOpen(false)}
          onCall={onCall}
        />
      )}
    </div>
  );
}

// ───── Chat options bottom sheet (the ⋯ menu in a chat) ─────
function MChatOptionsSheet({ peer, muted, setMuted, disappearing, setDisappearing, onClose, onViewProfile, onCall }) {
  const p = peer;
  const quick = [
    { id: 'profile', label: 'Profile', icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></svg>, onClick: onViewProfile },
    { id: 'audio',   label: 'Audio',   icon: MIc.calls({ s: 18 }), onClick: () => { onClose(); onCall && onCall(p, 'audio'); } },
    { id: 'video',   label: 'Video',   icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="m23 7-7 5 7 5z"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>, onClick: () => { onClose(); onCall && onCall(p, 'video'); } },
    { id: 'search',  label: 'Search',  icon: MIc.search({ s: 18 }), onClick: onClose },
  ];
  const Row = ({ icon, color, label, sub, right, onClick, danger, last }) => (
    <button onClick={onClick} style={{
      width: '100%', display: 'flex', alignItems: 'center', gap: 13,
      padding: '13px 16px', background: 'transparent', border: 0,
      borderBottom: last ? 0 : '1px solid ' + M_BORDER_SOFT,
      color: danger ? '#F87171' : M_FG, textAlign: 'left', cursor: 'pointer', fontFamily: 'inherit',
    }}>
      <span style={{ width: 22, display: 'grid', placeItems: 'center', color: danger ? '#F87171' : (color || M_FG_MUTED), flexShrink: 0 }}>{icon}</span>
      <span style={{ flex: 1 }}>
        <span style={{ display: 'block', fontSize: 14, fontWeight: 500, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em' }}>{label}</span>
        {sub && <span style={{ display: 'block', fontSize: 11, color: M_FG_DIM, marginTop: 2 }}>{sub}</span>}
      </span>
      {right}
    </button>
  );
  const sw = (d, s = 18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">{d}</svg>;
  return (
    <>
      <div onClick={onClose} style={{ position: 'absolute', inset: 0, zIndex: 60, background: M_SCRIM, backdropFilter: 'blur(5px)', animation: 'mFade 180ms ease-out' }}/>
      <div style={{
        position: 'absolute', left: 0, right: 0, bottom: 0, zIndex: 61,
        background: 'var(--glass-strong)', backdropFilter: 'blur(var(--glass-blur)) saturate(1.5)', WebkitBackdropFilter: 'blur(var(--glass-blur)) saturate(1.5)', borderTop: '1px solid var(--glass-border)',
        borderRadius: '22px 22px 0 0', padding: '10px 0 22px', boxShadow: 'inset 0 1px 0 var(--glass-highlight)',
        animation: 'mSheetUp 260ms cubic-bezier(0.2,0.85,0.3,1)', maxHeight: '88%', overflowY: 'auto',
      }}>
        <style>{`@keyframes mSheetUp{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes mFade{from{opacity:0}to{opacity:1}}`}</style>
        <div style={{ width: 40, height: 4, borderRadius: 2, background: M_FG_DIM, margin: '4px auto 14px', opacity: 0.5 }}/>

        {/* Peer header — tap to open profile */}
        <button onClick={onViewProfile} style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 12, padding: '4px 16px 16px', background: 'transparent', border: 0, cursor: 'pointer', textAlign: 'left' }}>
          <MTile size={46} bg={p.bg} color="#fff" label={p.initials} img={p.avatar} radius={23}/>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 16, fontWeight: 600, color: M_FG, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.02em' }}>{p.name}</div>
            <div style={{ fontSize: 11, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', marginTop: 2 }}>did:peer:2.{(p.initials || 'XX').toLowerCase()}…7Mq</div>
          </div>
          <span style={{ color: M_FG_DIM }}>›</span>
        </button>

        {/* Quick action grid */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8, padding: '0 12px 14px' }}>
          {quick.map(q => (
            <button key={q.id} onClick={q.onClick} style={{
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7,
              padding: '12px 4px', background: M_TINT, border: '1px solid ' + M_BORDER_SOFT,
              borderRadius: 12, color: M_FG, cursor: 'pointer', fontFamily: 'inherit',
            }}>
              <span style={{ color: M_ACCENT_B }}>{q.icon}</span>
              <span style={{ fontSize: 11, fontWeight: 500 }}>{q.label}</span>
            </button>
          ))}
        </div>

        {/* Verification banner */}
        <div style={{ margin: '0 12px 14px', padding: '11px 13px', background: 'rgba(110,231,183,0.07)', border: '1px solid rgba(110,231,183,0.18)', borderRadius: 12, display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{ color: M_ACCENT }}>{MIc.shield({ s: 16 })}</span>
          <div style={{ flex: 1, fontSize: 11.5, color: M_FG_MUTED, lineHeight: 1.4 }}>
            Identity verified · <span style={{ color: M_FG }}>safety number matches</span>
          </div>
          <span style={{ fontSize: 9.5, color: M_ACCENT, fontFamily: 'JetBrains Mono, monospace', fontWeight: 700, letterSpacing: '0.06em' }}>✓ SAFE</span>
        </div>

        {/* Settings list */}
        <div style={{ margin: '0 12px 12px', background: M_BG, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, overflow: 'hidden' }}>
          <Row icon={sw(<><path d="M6 8a6 6 0 1 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10 21a2 2 0 0 0 4 0"/></>)} label="Mute notifications" sub={muted ? 'Muted' : 'Notifications on'}
            right={<MToggleSm on={muted} onChange={() => setMuted(m => !m)}/>}/>
          <Row icon={sw(<><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>)} label="Disappearing messages" sub={disappearing ? 'After 24 hours' : 'Off'}
            right={<MToggleSm on={disappearing} onChange={() => setDisappearing(d => !d)}/>}/>
          <Row icon={sw(<><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></>)} label="Media, links & files" sub="48 photos · 12 files" right={<span style={{ color: M_FG_DIM }}>›</span>} onClick={onClose} last/>
        </div>

        <div style={{ margin: '0 12px 12px', background: M_BG, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, overflow: 'hidden' }}>
          <Row icon={sw(<><path d="M12 2 4 5v7c0 5 3.5 8.5 8 10 4.5-1.5 8-5 8-10V5z"/><path d="m9 12 2 2 4-4"/></>)} color={M_ACCENT} label="Verify security code" sub="Compare safety numbers" right={<span style={{ color: M_FG_DIM }}>›</span>} onClick={onViewProfile}/>
          <Row icon={sw(<><circle cx="12" cy="12" r="9"/><path d="M9 12h6"/></>)} label="Block contact" danger onClick={onClose}/>
          <Row icon={sw(<><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></>)} label="Clear chat" danger onClick={onClose} last/>
        </div>

        <button onClick={onClose} style={{ width: 'calc(100% - 24px)', margin: '0 12px', padding: '13px 0', background: M_TINT, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, color: M_FG, fontSize: 14, fontWeight: 500, fontFamily: 'inherit', cursor: 'pointer' }}>Cancel</button>
      </div>
    </>
  );
}

// Small toggle for the sheet
function MToggleSm({ on, onChange }) {
  return (
    <button onClick={(e) => { e.stopPropagation(); onChange && onChange(); }} style={{
      width: 38, height: 22, borderRadius: 11, padding: 0, flexShrink: 0, position: 'relative',
      background: on ? 'linear-gradient(135deg,#6EE7B7,#60A5FA)' : M_TINT,
      border: '1px solid ' + (on ? 'transparent' : M_BORDER), cursor: 'pointer',
    }}>
      <span style={{ position: 'absolute', top: 2, left: on ? 18 : 2, width: 16, height: 16, borderRadius: 8, background: '#fff', boxShadow: '0 1px 3px rgba(0,0,0,0.3)', transition: 'left 180ms' }}/>
    </button>
  );
}

// ───── Contact profile (full screen, slides up) ─────
function MContactProfile({ peer, muted, setMuted, disappearing, setDisappearing, onClose, onCall }) {
  const p = peer;
  const connLabel = p.conn === 'ble' ? 'Bluetooth mesh' : p.conn === 'mesh' ? 'Ajna mesh' : 'DIDComm · Internet';
  const sw = (d, s = 18) => <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">{d}</svg>;
  // Deterministic safety-number block from initials
  const safety = (p.initials || 'XX').toUpperCase();
  const codeGroups = ['48201', '93517', '20846', '11759', '63092', '88410', '5723' + safety.charCodeAt(0) % 10, '40198', '27514', '63820', '99471', '50' + (safety.charCodeAt(1) % 100)];

  const Row = ({ icon, color, label, sub, right, onClick, danger, last }) => (
    <button onClick={onClick} style={{
      width: '100%', display: 'flex', alignItems: 'center', gap: 13,
      padding: '13px 16px', background: 'transparent', border: 0,
      borderBottom: last ? 0 : '1px solid ' + M_BORDER_SOFT,
      color: danger ? '#F87171' : M_FG, textAlign: 'left', cursor: 'pointer', fontFamily: 'inherit',
    }}>
      <span style={{ width: 22, display: 'grid', placeItems: 'center', color: danger ? '#F87171' : (color || M_FG_MUTED), flexShrink: 0 }}>{icon}</span>
      <span style={{ flex: 1 }}>
        <span style={{ display: 'block', fontSize: 14, fontWeight: 500, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em' }}>{label}</span>
        {sub && <span style={{ display: 'block', fontSize: 11, color: M_FG_DIM, marginTop: 2 }}>{sub}</span>}
      </span>
      {right}
    </button>
  );

  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 70, background: M_BG, display: 'flex', flexDirection: 'column', animation: 'mProfileIn 260ms cubic-bezier(0.2,0.85,0.3,1)' }}>
      <style>{`@keyframes mProfileIn{from{transform:translateY(100%)}to{transform:translateY(0)}}`}</style>
      {/* Top bar */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 14px' }}>
        <button onClick={onClose} aria-label="Close" style={{ display: 'inline-flex', alignItems: 'center', gap: 4, background: 'transparent', border: 0, color: M_ACCENT_B, fontSize: 14, fontWeight: 500, fontFamily: 'inherit', cursor: 'pointer', padding: 4 }}>
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6"/></svg>
          <span>Close</span>
        </button>
        <button style={{ background: 'transparent', border: 0, color: M_ACCENT_B, fontSize: 14, fontFamily: 'inherit', cursor: 'pointer', padding: 4 }}>Edit</button>
      </div>

      <div style={{ flex: 1, overflowY: 'auto', padding: '4px 16px 40px' }}>
        {/* Identity hero */}
        <div style={{ textAlign: 'center', padding: '8px 0 22px' }}>
          <div style={{ display: 'inline-grid', placeItems: 'center', position: 'relative' }}>
            <MTile size={88} bg={p.bg} color="#fff" label={p.initials} img={p.avatar} radius={44}/>
            {p.online && <div style={{ position: 'absolute', bottom: 4, right: 4, width: 18, height: 18, borderRadius: 9, background: '#22D27A', border: '3px solid ' + M_BG }}/>}
          </div>
          <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.025em', marginTop: 12 }}>{p.name}</div>
          <div style={{ fontSize: 11.5, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', marginTop: 4 }}>did:peer:2.{(p.initials || 'XX').toLowerCase()}…7Mq</div>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, marginTop: 12, padding: '5px 12px', borderRadius: 999, background: 'rgba(110,231,183,0.12)', color: M_ACCENT, fontSize: 10.5, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.06em', textTransform: 'uppercase', fontWeight: 600 }}>
            {MIc.shield({ s: 12 })} Verified · {connLabel}
          </div>
        </div>

        {/* Action row */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8, marginBottom: 22 }}>
          {[
            { id: 'msg',   label: 'Message', icon: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-5l-5 4v-4H6a3 3 0 0 1-3-3z"/></svg>, onClick: onClose },
            { id: 'audio', label: 'Call',    icon: MIc.calls({ s: 20 }), onClick: () => { onClose(); onCall && onCall(p, 'audio'); } },
            { id: 'video', label: 'Video',   icon: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="m23 7-7 5 7 5z"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>, onClick: () => { onClose(); onCall && onCall(p, 'video'); } },
            { id: 'mute',  label: muted ? 'Unmute' : 'Mute', icon: <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M6 8a6 6 0 1 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10 21a2 2 0 0 0 4 0"/></svg>, onClick: () => setMuted(m => !m) },
          ].map(a => (
            <button key={a.id} onClick={a.onClick} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7, padding: '14px 4px', background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, color: M_FG, cursor: 'pointer', fontFamily: 'inherit' }}>
              <span style={{ color: M_ACCENT_B }}>{a.icon}</span>
              <span style={{ fontSize: 11, fontWeight: 500 }}>{a.label}</span>
            </button>
          ))}
        </div>

        {/* Connection card */}
        <div style={{ fontSize: 10, fontWeight: 700, color: M_FG_DIM, letterSpacing: '0.12em', textTransform: 'uppercase', fontFamily: 'JetBrains Mono, monospace', padding: '0 4px 8px' }}>Connection</div>
        <div style={{ background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, overflow: 'hidden', marginBottom: 20 }}>
          <Row icon={sw(<><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></>)} label="Transport" sub={connLabel} right={<MConnChip type={p.conn}/>}/>
          <Row icon={sw(<><circle cx="12" cy="5" r="2"/><circle cx="5" cy="18" r="2"/><circle cx="19" cy="18" r="2"/><path d="M12 7v4M12 11 6 16M12 11l6 5"/></>)} label="Mesh hops" sub={p.conn === 'ble' ? '1 hop · direct BLE' : 'Via mediator'} right={<span style={{ color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace', fontSize: 12 }}>{p.conn === 'ble' ? '1' : '2'}</span>} last/>
        </div>

        {/* Safety number */}
        <div style={{ fontSize: 10, fontWeight: 700, color: M_FG_DIM, letterSpacing: '0.12em', textTransform: 'uppercase', fontFamily: 'JetBrains Mono, monospace', padding: '0 4px 8px', display: 'flex', justifyContent: 'space-between' }}>
          <span>Safety number</span>
          <span style={{ color: M_ACCENT }}>✓ Matches</span>
        </div>
        <div style={{ background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, padding: 16, marginBottom: 20 }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '8px 6px', marginBottom: 14 }}>
            {codeGroups.map((g, i) => (
              <div key={i} style={{ fontSize: 12.5, color: M_FG, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.04em', textAlign: 'center' }}>{g}</div>
            ))}
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <button style={{ flex: 1, padding: '10px 0', borderRadius: 10, background: M_TINT, border: '1px solid ' + M_BORDER_SOFT, color: M_FG, fontSize: 12.5, fontWeight: 500, fontFamily: 'inherit', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}>
              {sw(<><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M8 12h8M12 8v8"/></>, 14)} Scan QR
            </button>
            <button style={{ flex: 1, padding: '10px 0', borderRadius: 10, background: 'rgba(110,231,183,0.12)', border: '1px solid rgba(110,231,183,0.28)', color: M_ACCENT, fontSize: 12.5, fontWeight: 600, fontFamily: 'inherit', cursor: 'pointer' }}>Mark verified</button>
          </div>
        </div>

        {/* Preferences */}
        <div style={{ fontSize: 10, fontWeight: 700, color: M_FG_DIM, letterSpacing: '0.12em', textTransform: 'uppercase', fontFamily: 'JetBrains Mono, monospace', padding: '0 4px 8px' }}>Preferences</div>
        <div style={{ background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, overflow: 'hidden', marginBottom: 20 }}>
          <Row icon={sw(<><path d="M6 8a6 6 0 1 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10 21a2 2 0 0 0 4 0"/></>)} label="Mute notifications" right={<MToggleSm on={muted} onChange={() => setMuted(m => !m)}/>}/>
          <Row icon={sw(<><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>)} label="Disappearing messages" sub={disappearing ? 'After 24 hours' : 'Off'} right={<MToggleSm on={disappearing} onChange={() => setDisappearing(d => !d)}/>}/>
          <Row icon={sw(<><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></>)} label="Media, links & files" sub="48 photos · 12 files" right={<span style={{ color: M_FG_DIM }}>›</span>} last/>
        </div>

        {/* Danger */}
        <div style={{ background: M_SURFACE, border: '1px solid ' + M_BORDER_SOFT, borderRadius: 14, overflow: 'hidden' }}>
          <Row icon={sw(<><circle cx="12" cy="12" r="9"/><path d="M9 12h6"/></>)} label="Block contact" danger/>
          <Row icon={sw(<><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></>)} label="Delete contact" danger last/>
        </div>
      </div>
    </div>
  );
}

// ───── Ajna Network ─────
function MScreenNetwork() {
  return (
    <div style={{ padding: '20px 20px 100px', height: '100%', overflowY: 'auto', boxSizing: 'border-box' }}>
      <div style={{ fontSize: 26, fontWeight: 600, fontFamily: 'Geist', letterSpacing: '-0.02em', marginBottom: 20 }}>Network</div>
      <div style={{ padding: 20, borderRadius: 18, background: 'linear-gradient(135deg, rgba(110,231,183,0.12), rgba(96,165,250,0.12))', border: '1px solid ' + M_BORDER, marginBottom: 24 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 8, height: 8, borderRadius: '50%', background: '#22D27A', boxShadow: '0 0 10px #22D27A' }}/>
            <span style={{ fontSize: 11, color: M_FG_MUTED, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.1em', textTransform: 'uppercase' }}>All systems connected</span>
          </div>
          <span style={{ fontSize: 10, color: M_FG_DIM, fontFamily: 'JetBrains Mono, monospace' }}>did:key:…9kTp</span>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          {[{l: 'Mesh peers', v: '3', hint: 'BLE'}, {l: 'Mediators', v: '1', hint: 'online'}].map((s, i) => (
            <div key={i} style={{ padding: 12, background: 'rgba(0,0,0,0.25)', borderRadius: 10 }}>
              <div style={{ fontSize: 9.5, color: M_FG_DIM, letterSpacing: '0.08em', textTransform: 'uppercase', fontWeight: 600 }}>{s.l}</div>
              <div style={{ fontSize: 22, fontFamily: 'Geist', fontWeight: 600, marginTop: 4, letterSpacing: '-0.02em' }}>{s.v}</div>
              <div style={{ fontSize: 10, color: M_FG_MUTED, marginTop: 1 }}>{s.hint}</div>
            </div>
          ))}
        </div>
      </div>
      <div style={{ fontSize: 10, fontWeight: 600, color: M_FG_DIM, letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 8, paddingLeft: 2 }}>Mesh Network</div>
      <div style={{ background: M_SURFACE, borderRadius: 14, border: '1px solid ' + M_BORDER_SOFT }}>
        {[{t:'Bluetooth LE mesh', s: 'Connect with nearby Ajna devices', on: true}, {t:'Auto-reconnect', s: 'Re-join known mesh networks on range', on: true}, {t:'Discoverable', s: 'Let other devices find this phone', on: false}].map((r, i, a) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', borderBottom: i < a.length - 1 ? '1px solid ' + M_BORDER_SOFT : 'none' }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>{r.t}</div>
              <div style={{ fontSize: 12, color: M_FG_MUTED, marginTop: 2 }}>{r.s}</div>
            </div>
            <div style={{ width: 36, height: 20, borderRadius: 20, background: r.on ? 'linear-gradient(135deg, ' + M_ACCENT + ', ' + M_ACCENT_B + ')' : M_SURFACE_2, position: 'relative' }}>
              <div style={{ position: 'absolute', top: 2, left: r.on ? 18 : 2, width: 16, height: 16, borderRadius: '50%', background: '#fff', transition: 'left 180ms' }}/>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { MTypingDots, MSwipeRow, MMsgState,
  MScreenNTP, MScreenTabs, MScreenChatList, MScreenChatListEmpty, MScreenChat, MScreenNetwork,
  MChatOptionsSheet, MContactProfile, MToggleSm, MFav,
});
