// Spiele (Games) screen + Crew screen

// How many games a user may shortlist as their "picks".
const MAX_PICKS = 33;

function ScreenSpiele({ wide, activeGroupId, groupGames, onToggleGroupGame, steamBusy, steamStatus, onDismissSteamStatus }) {
  const t = window.t;
  const de = (window.__LANG || 'de') !== 'en';
  // Multiplayer is the default view — it's a group-gaming app, so co-op/multi
  // games are what people usually want to pick for a session.
  const [filter, setFilter] = React.useState('multi');
  const [myPicks, setMyPicks] = React.useState(window.PICKS.me);
  // "Hide single-player games" profile preference (default on). When active the
  // multiplayer/single filter chips are pointless, so they're removed.
  const [hideSingle, setHideSingle] = React.useState(window.__MY_HIDE_SINGLE !== false);
  React.useEffect(() => {
    const onPrefs = () => setHideSingle(window.__MY_HIDE_SINGLE !== false);
    window.addEventListener('zocker-prefs-changed', onPrefs);
    return () => window.removeEventListener('zocker-prefs-changed', onPrefs);
  }, []);

  const steamConnected = !!window.__MY_STEAM?.connected;
  const steamCount = (window.MY_LIBRARY || []).filter(g => g.source === 'steam').length;
  const startSteamLogin = () => {
    window.location.href = `${window.API_BASE || ''}/api/steam/login`;
  };
  // Link straight to the user's Steam privacy settings (game details).
  const steamPrivacyUrl = steamStatus?.steamId
    ? `https://steamcommunity.com/profiles/${steamStatus.steamId}/edit/settings`
    : 'https://steamcommunity.com/my/edit/settings';

  // Manual add (search) state
  const [searchOpen, setSearchOpen] = React.useState(false);
  const [query, setQuery] = React.useState('');
  const [results, setResults] = React.useState([]);
  const [searching, setSearching] = React.useState(false);
  const [searchErr, setSearchErr] = React.useState(null);
  const [, forceRerender] = React.useReducer(x => x + 1, 0);
  const searchPanelRef = React.useRef(null);
  const searchBtnRef = React.useRef(null);

  // Has the initial DB load settled? While it hasn't (or a Steam import is
  // running) and we have no games yet, show a spinner instead of an empty list.
  const dataReady = window.useDataReady ? window.useDataReady() : true;
  // Re-render when games arrive after this screen mounted (Steam import, late
  // crew-member loads) so they show up without needing a tab switch.
  React.useEffect(() => {
    const onGames = () => forceRerender();
    window.addEventListener('zocker-games-updated', onGames);
    return () => window.removeEventListener('zocker-games-updated', onGames);
  }, []);

  // Close the manual-add panel when clicking anywhere outside it
  React.useEffect(() => {
    if (!searchOpen) return;
    const onDown = (e) => {
      if (searchPanelRef.current?.contains(e.target)) return;
      if (searchBtnRef.current?.contains(e.target)) return;
      setSearchOpen(false);
    };
    document.addEventListener('mousedown', onDown);
    document.addEventListener('touchstart', onDown);
    return () => {
      document.removeEventListener('mousedown', onDown);
      document.removeEventListener('touchstart', onDown);
    };
  }, [searchOpen]);

  const runSearch = async (e) => {
    e?.preventDefault();
    if (!query.trim()) return;
    setSearching(true); setSearchErr(null);
    const res = await window.fbSearchGames(query.trim());
    setSearching(false);
    if (!res.ok) setSearchErr(de ? 'Suche fehlgeschlagen. Backend/API-Key konfiguriert?' : 'Search failed. Is the backend/API key set up?');
    setResults(res.games || []);
  };
  const addManualGame = async (g) => {
    await window.fbAddGame({
      id: g.id, title: g.title, img: g.img, tag: g.tag || 'game',
      genre: g.genre || '', modes: g.modes || [],
      plat: ['manual'], source: 'manual',
    });
    forceRerender();
  };

  // Groups the user is in (so we can show toggle chips for them)
  const myGroups = window.GROUPS.filter(g => g.memberIds.includes('me'));

  // Group scope for vote counting
  const scopeMemberIds = activeGroupId === 'all'
    ? Object.keys(window.PICKS)
    : window.GROUPS_BY_ID[activeGroupId].memberIds;

  // The library shown here is the user's OWN games only — never games shared via
  // crew members' libraries. (window.GAMES is the merged catalog of everyone's
  // games; window.MY_LIBRARY is just mine.)
  const myLibrary = window.MY_LIBRARY || [];

  // Distinct genres present in my own library → one filter badge each (sorted).
  const genreList = React.useMemo(() => {
    const set = new Set();
    for (const g of myLibrary) {
      const label = window.gameGenreLabel(g);
      if (label) set.add(label);
    }
    return [...set].sort((a, b) => a.localeCompare(b));
  }, [myLibrary.length, filter]);

  // With the preference on, the multi/single chips are hidden — fall back to
  // "all" if one of them was the active filter.
  const effFilter = hideSingle && (filter === 'multi' || filter === 'single') ? 'all' : filter;

  const filtered = myLibrary.filter(g => {
    // Global preference: hide every non-multiplayer game.
    if (hideSingle && !window.gameIsMultiplayer(g)) return false;
    if (effFilter === 'all') return true;
    if (effFilter === 'steam') return g.plat.includes('steam');
    if (effFilter === 'multi') return window.gameIsMultiplayer(g);
    if (effFilter === 'single') return (g.modes || []).includes('single') && !window.gameIsMultiplayer(g);
    if (effFilter.startsWith('genre:')) return window.gameGenreLabel(g) === effFilter.slice(6);
    return true;
  });

  // Sort order:
  //  1. the user's own library always bubbles to the top, then
  //  2. when a specific crew is active, games excluded from it sink to the bottom.
  // groupGames[groupId] holds the ids EXCLUDED from that group; by default every
  // game is available for every group.
  const mineIds = new Set((window.MY_LIBRARY || []).map(g => g.id));
  const excludedFromGroup = (gid) =>
    activeGroupId !== 'all' && (groupGames[activeGroupId] || []).includes(gid);
  const sorted = [...filtered].sort((a, b) => {
    const am = mineIds.has(a.id) ? 0 : 1;
    const bm = mineIds.has(b.id) ? 0 : 1;
    if (am !== bm) return am - bm;
    const ax = excludedFromGroup(a.id) ? 1 : 0;
    const bx = excludedFromGroup(b.id) ? 1 : 0;
    return ax - bx;
  });

  // Show the loading spinner while the DB load (or a Steam import) is still in
  // flight and we don't yet have anything to display.
  const gamesLoading = (!dataReady || steamBusy) && sorted.length === 0;

  const togglePick = (gid) => {
    setMyPicks(prev => {
      const next = prev.includes(gid)
        ? prev.filter(x => x !== gid)
        : prev.length >= MAX_PICKS ? prev : [...prev, gid];
      window.fbSavePicks?.(next);
      return next;
    });
  };

  const voteCount = (gid) => {
    let n = 0;
    for (const fid of scopeMemberIds) {
      if (fid === 'me') {
        if (myPicks.includes(gid)) n++;
      } else if (window.PICKS[fid]?.includes(gid)) n++;
    }
    return n;
  };
  const scopeSize = scopeMemberIds.length;

  return (
    <div style={{ padding: '16px 0 100px' }}>
      <div style={{ padding: '0 16px' }}>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 500,
          color: 'var(--muted)', letterSpacing: 0.5, textTransform: 'uppercase',
        }}>{activeGroupId === 'all'
          ? t('deine_bibliothek')
          : t('games_in', window.groupName(window.GROUPS_BY_ID[activeGroupId]))
        }</div>
        <h1 style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 30, fontWeight: 700,
          color: 'var(--text)', letterSpacing: -0.8, margin: '2px 0 16px',
        }}>{t('spiele')}</h1>

        <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
          <ConnectionChip
            label="Steam"
            connected={steamConnected}
            count={
              steamBusy ? (de ? 'lädt…' : 'loading…')
              : steamConnected ? t('spiele_n', steamCount)
              : (de ? 'verbinden' : 'connect')
            }
            onClick={startSteamLogin}
          />
          <button ref={searchBtnRef} onClick={() => setSearchOpen(o => !o)} style={{
            appearance: 'none', cursor: 'pointer',
            flex: 1, padding: '10px 12px', borderRadius: 12,
            background: 'var(--surface)',
            border: `1px solid ${searchOpen ? 'color-mix(in oklab, var(--accent) 40%, var(--border))' : 'var(--border)'}`,
            display: 'flex', alignItems: 'center', gap: 10, textAlign: 'left',
          }}>
            <div style={{
              width: 26, height: 26, borderRadius: 8, flexShrink: 0,
              background: 'color-mix(in oklab, var(--accent) 14%, transparent)',
              color: 'var(--accent)', fontSize: 18, fontWeight: 300,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>+</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>
                {de ? 'Spiel hinzufügen' : 'Add game'}
              </div>
              <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: 'var(--muted)', marginTop: 1 }}>
                {de ? 'manuell suchen' : 'search manually'}
              </div>
            </div>
          </button>
        </div>

        {/* Steam private-profile / error banner */}
        {steamStatus && (
          <div style={{
            position: 'relative',
            background: steamStatus.kind === 'private'
              ? 'color-mix(in oklab, var(--violet) 12%, var(--surface))'
              : 'color-mix(in oklab, var(--pink) 12%, var(--surface))',
            border: `1px solid ${steamStatus.kind === 'private'
              ? 'color-mix(in oklab, var(--violet) 35%, var(--border))'
              : 'color-mix(in oklab, var(--pink) 35%, var(--border))'}`,
            borderRadius: 14, padding: 14, marginBottom: 14,
          }}>
            <button onClick={onDismissSteamStatus} aria-label="dismiss" style={{
              position: 'absolute', top: 8, right: 8,
              appearance: 'none', cursor: 'pointer',
              width: 24, height: 24, borderRadius: 999,
              background: 'transparent', border: 0, color: 'var(--muted)', fontSize: 16,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>×</button>

            {steamStatus.kind === 'private' ? (
              <>
                <div style={{
                  fontFamily: 'Space Grotesk, system-ui', fontSize: 14, fontWeight: 700,
                  color: 'var(--text)', marginBottom: 6, paddingRight: 24,
                }}>
                  {de ? 'Dein Steam-Profil ist privat' : 'Your Steam profile is private'}
                </div>
                <div style={{ fontSize: 12, color: 'var(--muted)', lineHeight: 1.6, marginBottom: 12 }}>
                  {de
                    ? 'Wir konnten deine Bibliothek nicht laden. Stelle in den Steam-Datenschutzeinstellungen „Spieldetails" auf Öffentlich – danach erneut verbinden.'
                    : 'We couldn\'t load your library. In your Steam privacy settings, set "Game details" to Public, then connect again.'}
                </div>
                <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                  <a href={steamPrivacyUrl} target="_blank" rel="noopener noreferrer" style={{
                    textDecoration: 'none',
                    background: 'var(--violet)', color: 'var(--bg-deep)',
                    borderRadius: 10, padding: '9px 14px',
                    fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 700,
                  }}>
                    {de ? 'Datenschutz öffnen' : 'Open privacy settings'}
                  </a>
                  <button onClick={startSteamLogin} style={{
                    appearance: 'none', cursor: 'pointer',
                    background: 'transparent', border: '1px solid var(--border)',
                    color: 'var(--text)', borderRadius: 10, padding: '9px 14px',
                    fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 600,
                  }}>
                    {de ? 'Erneut verbinden' : 'Connect again'}
                  </button>
                </div>
              </>
            ) : (
              <>
                <div style={{
                  fontFamily: 'Space Grotesk, system-ui', fontSize: 14, fontWeight: 700,
                  color: 'var(--text)', marginBottom: 6, paddingRight: 24,
                }}>
                  {de ? 'Steam-Verbindung fehlgeschlagen' : 'Steam connection failed'}
                </div>
                <div style={{ fontSize: 12, color: 'var(--muted)', lineHeight: 1.6, marginBottom: 12 }}>
                  {de
                    ? 'Beim Import ist etwas schiefgelaufen. Bitte versuche es erneut.'
                    : 'Something went wrong during import. Please try again.'}
                  {steamStatus.message ? ` (${steamStatus.message})` : ''}
                </div>
                <button onClick={startSteamLogin} style={{
                  appearance: 'none', cursor: 'pointer',
                  background: 'var(--accent)', border: 0,
                  color: 'var(--bg-deep)', borderRadius: 10, padding: '9px 14px',
                  fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 700,
                }}>
                  {de ? 'Erneut verbinden' : 'Try again'}
                </button>
              </>
            )}
          </div>
        )}

        {!steamConnected && !steamStatus && (
          <div style={{ fontSize: 11, color: 'var(--muted)', marginBottom: 12, lineHeight: 1.5 }}>
            {de
              ? 'Verbinde Steam, um deine echte Bibliothek zu importieren. Dein Steam-Profil muss „Spieldetails" öffentlich haben.'
              : 'Connect Steam to import your real library. Your Steam profile\'s game details must be public.'}
          </div>
        )}

        {/* Manual add search panel */}
        {searchOpen && (
          <div ref={searchPanelRef} style={{
            background: 'var(--surface)', border: '1px solid var(--border)',
            borderRadius: 16, padding: 12, marginBottom: 16,
          }}>
            <form onSubmit={runSearch} style={{ display: 'flex', gap: 8 }}>
              <input
                value={query} onChange={e => setQuery(e.target.value)}
                placeholder={de ? 'Spiel suchen…' : 'Search a game…'}
                autoFocus
                style={{
                  flex: 1, padding: '10px 12px', boxSizing: 'border-box',
                  background: 'var(--bg-deep)', border: '1px solid var(--border)',
                  borderRadius: 10, color: 'var(--text)',
                  fontFamily: 'Space Grotesk, system-ui', fontSize: 14, outline: 'none',
                }}
              />
              <button type="submit" disabled={searching || !query.trim()} style={{
                padding: '0 16px', borderRadius: 10, border: 0,
                background: (searching || !query.trim()) ? 'var(--surface-2)' : 'var(--accent)',
                color: (searching || !query.trim()) ? 'var(--muted)' : 'var(--bg-deep)',
                fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 700,
                cursor: (searching || !query.trim()) ? 'not-allowed' : 'pointer',
              }}>{searching ? '…' : (de ? 'Suchen' : 'Search')}</button>
            </form>

            {searchErr && (
              <div style={{ marginTop: 10, fontSize: 12, color: 'var(--pink)', lineHeight: 1.4 }}>{searchErr}</div>
            )}

            {results.length > 0 && (
              <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 6, maxHeight: 280, overflowY: 'auto' }}>
                {results.map(g => {
                  const added = (window.MY_LIBRARY || []).some(x => x.id === g.id);
                  return (
                    <div key={g.id} style={{
                      display: 'flex', alignItems: 'center', gap: 10,
                      padding: 8, borderRadius: 10, background: 'var(--bg-deep)',
                      border: '1px solid var(--border)',
                    }}>
                      <GameCover game={g} size={40} rounded={8} />
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 600, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{g.title}</div>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 3 }}>
                          <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: 'var(--muted)' }}>{window.gameGenreLabel(g) || g.tag}{g.released ? ' · ' + g.released.slice(0, 4) : ''}</span>
                          <ModeBadge modes={g.modes} />
                        </div>
                      </div>
                      <button onClick={() => addManualGame(g)} disabled={added} style={{
                        padding: '6px 12px', borderRadius: 999, border: 0,
                        background: added ? 'var(--surface-2)' : 'var(--accent)',
                        color: added ? 'var(--muted)' : 'var(--bg-deep)',
                        fontFamily: 'Space Grotesk, system-ui', fontSize: 12, fontWeight: 700,
                        cursor: added ? 'default' : 'pointer', whiteSpace: 'nowrap',
                      }}>{added ? '✓' : (de ? 'Add' : 'Add')}</button>
                    </div>
                  );
                })}
              </div>
            )}
          </div>
        )}
      </div>

      <div style={{ padding: '0 16px 22px' }}>
        <SectionHead title={`${t('meine_picks')} · ${myPicks.length}/${MAX_PICKS}`} />
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 12, color: 'var(--muted)',
          marginBottom: 12,
        }}>{t('bock_worauf')}</div>
        <div style={{ display: 'flex', gap: 10, overflowX: 'auto', margin: '0 -16px', padding: '0 16px', scrollbarWidth: 'none' }}>
          {myPicks.map(gid => {
            const g = window.GAMES_BY_ID[gid];
            if (!g) return null;
            const votes = voteCount(gid);
            return (
              <div key={gid} style={{
                position: 'relative', flexShrink: 0,
                display: 'flex', flexDirection: 'column', gap: 8,
              }}>
                <GameCover game={g} size={108} rounded={16} />
                <button onClick={() => togglePick(gid)} style={{
                  position: 'absolute', top: 6, right: 6,
                  width: 24, height: 24, borderRadius: '50%',
                  background: 'rgba(0,0,0,0.6)', border: 0, color: '#fff',
                  cursor: 'pointer',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  fontSize: 14,
                }}>×</button>
                <div style={{ width: 108 }}>
                  <div style={{
                    fontFamily: 'Space Grotesk, system-ui', fontSize: 12, fontWeight: 600,
                    color: 'var(--text)',
                    overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                  }}>{g.title}</div>
                  <div style={{
                    display: 'flex', alignItems: 'center', gap: 4, marginTop: 4,
                  }}>
                    <div style={{
                      flex: 1, height: 3, borderRadius: 999,
                      background: 'var(--surface-2)', overflow: 'hidden',
                    }}>
                      <div style={{
                        height: '100%',
                        width: `${(votes / scopeSize) * 100}%`,
                        background: 'var(--accent)',
                      }} />
                    </div>
                    <Mono size={10} color="var(--muted)">{votes}/{scopeSize}</Mono>
                  </div>
                </div>
              </div>
            );
          })}
          {myPicks.length < MAX_PICKS && (
            <div style={{
              width: 108, height: 108, borderRadius: 16,
              border: '1px dashed var(--border)', flexShrink: 0,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              color: 'var(--muted)',
              fontFamily: 'Space Grotesk, system-ui', fontSize: 28, fontWeight: 300,
            }}>+</div>
          )}
        </div>
      </div>

      <div style={{
        display: 'flex', gap: 6, padding: '0 16px',
        overflowX: 'auto', scrollbarWidth: 'none', marginBottom: 14,
      }}>
        {[
          ['all',    t('filter_all')],
          ...(hideSingle ? [] : [['multi', t('filter_multi')], ['single', t('filter_single')]]),
          ['steam',  t('filter_steam')],
        ].map(([id, label]) => (
          <Chip key={id} color="mint" active={effFilter === id} onClick={() => setFilter(id)}>
            {label}
          </Chip>
        ))}
        {/* One badge per genre present in the library */}
        {genreList.map(genre => {
          const id = 'genre:' + genre;
          return (
            <Chip key={id} color="violet" active={filter === id} onClick={() => setFilter(id)}>
              {genre}
            </Chip>
          );
        })}
      </div>

      {gamesLoading ? (
        <window.Spinner label={de ? 'Spiele werden geladen…' : 'Loading games…'} />
      ) : (
      <>
      <div style={{
        padding: '0 16px 10px',
        fontFamily: 'Space Grotesk, system-ui', fontSize: 11,
        color: 'var(--muted)', letterSpacing: 0.2,
      }}>
        💡 {t('tap_to_exclude')}
      </div>
      <div style={wide
        ? { padding: '0 16px', display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(330px, 1fr))', gap: 10, alignItems: 'start' }
        : { padding: '0 16px', display: 'flex', flexDirection: 'column', gap: 8 }}>
        {sorted.map(g => {
          const votes = voteCount(g.id);
          const picked = myPicks.includes(g.id);
          return (
            <div key={g.id} style={{
              background: picked ? 'color-mix(in oklab, var(--accent) 8%, var(--surface))' : 'var(--surface)',
              border: `1px solid ${picked ? 'color-mix(in oklab, var(--accent) 35%, var(--border))' : 'var(--border)'}`,
              borderRadius: 14, padding: 10,
              display: 'flex', flexDirection: 'column', gap: 10,
            }}>
              <button onClick={() => togglePick(g.id)} style={{
                appearance: 'none', cursor: 'pointer', textAlign: 'left',
                background: 'transparent', border: 0, padding: 0,
                display: 'flex', alignItems: 'center', gap: 12,
              }}>
                <GameCover game={g} size={56} rounded={10} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{
                    display: 'flex', alignItems: 'center', gap: 6,
                    fontFamily: 'Space Grotesk, system-ui', fontSize: 15, fontWeight: 600,
                    color: 'var(--text)', marginBottom: 4,
                  }}>
                    <span style={{
                      overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                      flex: 1,
                    }}>{g.title}</span>
                  </div>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
                    {g.plat.map(p => <PlatformPill key={p} platform={p} />)}
                    {window.gameGenreLabel(g) && (
                      <span style={{
                        fontFamily: 'Space Grotesk, system-ui', fontSize: 11, color: 'var(--muted)',
                      }}>{window.gameGenreLabel(g)}</span>
                    )}
                    <ModeBadge modes={g.modes} />
                  </div>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6 }}>
                  {votes > 0 && (
                    <div style={{
                      fontFamily: 'JetBrains Mono, monospace', fontSize: 11,
                      color: votes >= Math.ceil(scopeSize / 2) ? 'var(--accent)' : 'var(--muted)',
                      fontWeight: 600,
                    }}>{votes}/{scopeSize}</div>
                  )}
                  <div style={{
                    width: 24, height: 24, borderRadius: 7,
                    border: `1.5px solid ${picked ? 'var(--accent)' : 'var(--border)'}`,
                    background: picked ? 'var(--accent)' : 'transparent',
                    color: picked ? 'var(--bg-deep)' : 'transparent',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                  }}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M5 12l5 5L20 7" />
                    </svg>
                  </div>
                </div>
              </button>

              {/* Group assignment row */}
              <div style={{
                display: 'flex', alignItems: 'center', gap: 6,
                paddingTop: 8, borderTop: '1px dashed var(--border)',
              }}>
                <span style={{
                  fontFamily: 'Space Grotesk, system-ui', fontSize: 10, fontWeight: 600,
                  letterSpacing: 0.6, textTransform: 'uppercase',
                  color: 'var(--muted)',
                }}>{t('game_groups_exclude')}</span>
                <div style={{ display: 'flex', gap: 5, flexWrap: 'wrap', flex: 1 }}>
                  {myGroups.map(grp => {
                    // Available for the group by default; "excluded" when listed.
                    const excluded = (groupGames[grp.id] || []).includes(g.id);
                    return (
                      <button key={grp.id} onClick={() => onToggleGroupGame(grp.id, g.id)} style={{
                        appearance: 'none', cursor: 'pointer',
                        display: 'inline-flex', alignItems: 'center', gap: 4,
                        padding: '4px 8px', borderRadius: 999,
                        background: excluded
                          ? 'var(--bg-deep)'
                          : `oklch(0.85 0.16 ${grp.hue} / 0.14)`,
                        border: excluded
                          ? '1px solid var(--border)'
                          : `1px solid oklch(0.85 0.16 ${grp.hue} / 0.4)`,
                        color: excluded ? 'var(--muted)' : `oklch(0.85 0.16 ${grp.hue})`,
                        fontFamily: 'Space Grotesk, system-ui', fontSize: 10, fontWeight: 600,
                        letterSpacing: 0.3, textTransform: 'uppercase',
                        textDecoration: excluded ? 'line-through' : 'none',
                        opacity: excluded ? 0.7 : 1,
                      }}>
                        <span style={{ fontSize: 10 }}>{grp.glyph}</span>
                        <span style={{ whiteSpace: 'nowrap' }}>{window.groupName(grp)}</span>
                        {excluded && <span style={{ fontSize: 9, opacity: 0.8, marginLeft: 1 }}>✕</span>}
                      </button>
                    );
                  })}
                </div>
              </div>
            </div>
          );
        })}
      </div>
      </>
      )}
    </div>
  );
}

function ConnectionChip({ label, connected, count, onClick }) {
  return (
    <button onClick={onClick} style={{
      appearance: 'none', cursor: 'pointer',
      flex: 1, padding: '10px 12px', borderRadius: 12,
      background: 'var(--surface)',
      border: `1px solid ${connected ? 'color-mix(in oklab, var(--accent) 40%, var(--border))' : 'var(--border)'}`,
      display: 'flex', alignItems: 'center', gap: 10, textAlign: 'left',
    }}>
      <div style={{
        width: 6, height: 6, borderRadius: '50%',
        background: connected ? 'var(--accent)' : 'var(--muted)',
        boxShadow: connected ? '0 0 6px var(--accent)' : 'none',
      }} />
      <div style={{ flex: 1 }}>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 600,
          color: 'var(--text)',
        }}>{label}</div>
        <div style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: 'var(--muted)',
          marginTop: 1,
        }}>{count}</div>
      </div>
    </button>
  );
}

// Crew screen — groups + members
function ScreenCrew({ wide, activeGroupId, onChangeGroup, onOpenWeekly, onOpenNewGroup, onOpenAddFriend }) {
  const t = window.t;
  const [openGroupId, setOpenGroupId] = React.useState(null);
  const [openPersonId, setOpenPersonId] = React.useState(null);
  const [priorityMode, setPriorityMode] = React.useState(false);
  // Listed in crew-priority order so the most important crew is always on top.
  const myGroups = window.groupsByPriority(window.GROUPS.filter(g => g.memberIds.includes('me')));
  const canPrioritize = myGroups.length > 1;

  // Person detail — clicking a member opens a page with all their games.
  // Takes priority so it can be opened from the group view too.
  if (openPersonId && window.FRIENDS_BY_ID[openPersonId]) {
    return <PersonDetail wide={wide} personId={openPersonId} onBack={() => setOpenPersonId(null)} />;
  }

  // Group detail — open one group to see all its members
  const openGroup = openGroupId ? window.GROUPS_BY_ID[openGroupId] : null;
  if (openGroup) {
    return <GroupDetail wide={wide} group={openGroup} onBack={() => setOpenGroupId(null)}
      onOpenAddFriend={onOpenAddFriend} onOpenPerson={setOpenPersonId} />;
  }

  // Members in scope
  const memberIds = activeGroupId === 'all'
    ? [...new Set(window.GROUPS.flatMap(g => g.memberIds))]
    : window.GROUPS_BY_ID[activeGroupId].memberIds;
  const members = memberIds.map(id => window.FRIENDS_BY_ID[id]).filter(Boolean);
  const onlineCount = members.filter(m => m.online).length;

  return (
    <div style={{ padding: '16px 0 100px' }}>
      <div style={{ padding: '0 16px 16px' }}>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 500,
          color: 'var(--muted)', letterSpacing: 0.5, textTransform: 'uppercase',
        }}>
          {myGroups.length} {t('gruppen')} · {[...new Set(window.GROUPS.flatMap(g => g.memberIds))].length} {t('mitglieder').toLowerCase()}
        </div>
        <h1 style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 30, fontWeight: 700,
          color: 'var(--text)', letterSpacing: -0.8, margin: '2px 0 16px',
        }}>{t('meine_gruppen')}</h1>

        {/* Group cards — or the drag-to-reorder priority list when unlocked */}
        {priorityMode ? (
          <PriorityGroupList groups={myGroups} onDone={() => setPriorityMode(false)} />
        ) : (
          <div style={wide
            ? { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 10, marginBottom: 20 }
            : { display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 20 }}>
            {myGroups.map(g => (
              <GroupCard key={g.id} group={g} active={activeGroupId === g.id}
                onSelect={() => setOpenGroupId(g.id)} />
            ))}
            {canPrioritize && (
              <button onClick={() => setPriorityMode(true)} style={{
                appearance: 'none', cursor: 'pointer',
                padding: '12px 14px', borderRadius: 16,
                background: 'var(--surface)', border: '1px solid var(--border)',
                color: 'var(--muted)',
                display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
                fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 600,
              }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M3 6h13M3 12h9M3 18h5" /><path d="M18 9l3 3-3 3" />
                </svg>
                {t('prioritize_groups')}
              </button>
            )}
            <button onClick={onOpenNewGroup} style={{
              appearance: 'none', cursor: 'pointer',
              padding: 14, borderRadius: 16,
              background: 'transparent',
              border: '1px dashed var(--border)',
              color: 'var(--muted)',
              fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 500,
            }}>{t('neue_gruppe')}</button>
          </div>
        )}

        {/* Stats strip */}
        <div style={{
          display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 8,
          marginBottom: 18,
        }}>
          <Stat label={t('online')} value={onlineCount} />
          <Stat label={t('frei_heute')} value="4" />
          <Stat label={t('sessions_mo')} value="12" accent />
        </div>
      </div>

      <div style={{ padding: '0 16px' }}>
        <SectionHead title={t('mitglieder')} />
        <button type="button" onClick={() => onOpenAddFriend(activeGroupId)} style={{
          appearance: 'none', cursor: 'pointer', width: '100%',
          marginBottom: 12, padding: '12px 14px', borderRadius: 14,
          background: 'color-mix(in oklab, var(--accent) 12%, var(--surface))',
          border: '1px solid color-mix(in oklab, var(--accent) 35%, var(--border))',
          color: 'var(--accent)',
          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
          fontFamily: 'Space Grotesk, system-ui', fontSize: 14, fontWeight: 700,
        }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
            <circle cx="9" cy="7" r="4" />
            <path d="M19 8v6M22 11h-6" />
          </svg>
          {t('freund_einladen')}
        </button>
        <div style={wide
          ? { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 8 }
          : { display: 'flex', flexDirection: 'column', gap: 8 }}>
          {members.map(f => <FriendRow key={f.id} friend={f} onOpen={() => setOpenPersonId(f.id)} />)}
        </div>
      </div>

      <div style={{ padding: '20px 16px' }}>
        <Button variant="ghost" full onClick={onOpenWeekly}>
          {t('wochenplan_btn')}
        </Button>
      </div>
    </div>
  );
}

// Number of games for a member (library if we have it, else their picks)
function memberGameCount(id) {
  if (id === 'me') return (window.MY_LIBRARY?.length) || (window.PICKS.me?.length) || 0;
  return (window.PICKS[id]?.length) || 0;
}

// Group detail — header + full member list (name, gamertag, number of games)
function GroupDetail({ wide, group, onBack, onOpenAddFriend, onOpenPerson }) {
  const t = window.t;
  const members = group.memberIds.map(id => window.FRIENDS_BY_ID[id]).filter(Boolean);

  return (
    <div style={{ padding: '16px 0 100px' }}>
      <div style={{ padding: '0 16px' }}>
        <button type="button" onClick={onBack} style={{
          appearance: 'none', cursor: 'pointer', background: 'transparent', border: 0,
          color: 'var(--muted)', fontFamily: 'Space Grotesk, system-ui', fontSize: 13,
          fontWeight: 600, padding: '0 0 14px', display: 'flex', alignItems: 'center', gap: 6,
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><path d="M15 6l-6 6 6 6" strokeLinecap="round" strokeLinejoin="round"/></svg>
          {t('back')}
        </button>

        {/* Group header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 18 }}>
          <div style={{
            width: 56, height: 56, borderRadius: 16, flexShrink: 0,
            background: `oklch(0.3 0.06 ${group.hue})`,
            color: `oklch(0.88 0.16 ${group.hue})`,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontSize: 28, border: `1px solid oklch(0.85 0.16 ${group.hue} / 0.4)`,
          }}>{group.glyph}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <h1 style={{
              fontFamily: 'Space Grotesk, system-ui', fontSize: 26, fontWeight: 700,
              color: 'var(--text)', letterSpacing: -0.6, margin: 0,
            }}>{window.groupName(group)}</h1>
            <div style={{
              fontFamily: 'JetBrains Mono, monospace', fontSize: 12, color: 'var(--muted)',
              marginTop: 4,
            }}>{t('members_count', members.length)}</div>
          </div>
        </div>

        <button type="button" onClick={() => onOpenAddFriend(group.id)} style={{
          appearance: 'none', cursor: 'pointer', width: '100%',
          marginBottom: 14, padding: '12px 14px', borderRadius: 14,
          background: 'color-mix(in oklab, var(--accent) 12%, var(--surface))',
          border: '1px solid color-mix(in oklab, var(--accent) 35%, var(--border))',
          color: 'var(--accent)',
          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
          fontFamily: 'Space Grotesk, system-ui', fontSize: 14, fontWeight: 700,
        }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
            <circle cx="9" cy="7" r="4" />
            <path d="M19 8v6M22 11h-6" />
          </svg>
          {t('freund_einladen')}
        </button>

        <SectionHead title={t('mitglieder')} />
        <div style={wide
          ? { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 8 }
          : { display: 'flex', flexDirection: 'column', gap: 8 }}>
          {members.map(f => <GroupMemberRow key={f.id} friend={f} onOpen={() => onOpenPerson?.(f.id)} />)}
        </div>
      </div>
    </div>
  );
}

function GroupMemberRow({ friend, onOpen }) {
  const t = window.t;
  const isMe = friend.id === 'me';
  const gamerTag = friend.gamertag && friend.gamertag.trim();
  const games = memberGameCount(friend.id);
  return (
    <Card padded={false} onClick={onOpen} style={{
      padding: 12, display: 'flex', alignItems: 'center', gap: 12,
    }}>
      <Avatar id={friend.id} size={44} showStatus />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 15, fontWeight: 600,
          color: 'var(--text)',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>
          {friend.name}{isMe && <span style={{ color: 'var(--muted)', fontWeight: 400 }}> · {t('du')}</span>}
        </div>
        <div style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 11,
          color: gamerTag ? 'var(--muted)' : 'color-mix(in oklab, var(--muted) 60%, transparent)',
          marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>
          {gamerTag ? `@${gamerTag}` : t('no_gamertag')}
        </div>
      </div>
      <div style={{
        textAlign: 'right', flexShrink: 0,
      }}>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 18, fontWeight: 700,
          color: 'var(--accent)', letterSpacing: -0.5,
        }}>{games}</div>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 10, fontWeight: 600,
          color: 'var(--muted)', letterSpacing: 0.4, textTransform: 'uppercase',
        }}>{t('spiele')}</div>
      </div>
    </Card>
  );
}

function GroupCard({ group, active, onSelect }) {
  const t = window.t;
  const members = group.memberIds.map(id => window.FRIENDS_BY_ID[id]).filter(Boolean);
  const onlineN = members.filter(m => m.online).length;
  return (
    <button onClick={onSelect} style={{
      appearance: 'none', cursor: 'pointer', textAlign: 'left',
      padding: 14, borderRadius: 16,
      background: active
        ? `oklch(0.85 0.16 ${group.hue} / 0.10)`
        : 'var(--surface)',
      border: `1px solid ${active
        ? `oklch(0.85 0.16 ${group.hue} / 0.45)`
        : 'var(--border)'}`,
      display: 'flex', alignItems: 'center', gap: 14,
    }}>
      <div style={{
        width: 44, height: 44, borderRadius: 12, flexShrink: 0,
        background: `oklch(0.3 0.06 ${group.hue})`,
        color: `oklch(0.88 0.16 ${group.hue})`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontSize: 22,
        border: `1px solid oklch(0.85 0.16 ${group.hue} / 0.4)`,
      }}>{group.glyph}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 6,
          fontFamily: 'Space Grotesk, system-ui', fontSize: 16, fontWeight: 600,
          color: 'var(--text)', marginBottom: 3,
        }}>
          {window.groupName(group)}
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <AvatarStack ids={group.memberIds} size={18} max={5} />
          <span style={{
            fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: 'var(--muted)',
          }}>
            {group.memberIds.length} · {onlineN} {t('online').toLowerCase()}
          </span>
        </div>
      </div>
      {active && (
        <div style={{
          width: 8, height: 8, borderRadius: '50%',
          background: `oklch(0.85 0.16 ${group.hue})`,
          boxShadow: `0 0 8px oklch(0.85 0.16 ${group.hue})`,
        }} />
      )}
    </button>
  );
}

// One row in the priority list — looks like a GroupCard but carries a rank
// badge + drag handle and acts as the drag grip (pointer events live on it).
function PriorityRow({ group: g, rank, dragging, style, onGrab }) {
  const t = window.t;
  const rowRef = React.useRef(null);
  return (
    <div ref={rowRef}
      onPointerDown={(e) => onGrab(e, rowRef.current, g.id)}
      style={{
        display: 'flex', alignItems: 'center', gap: 12,
        padding: 12, borderRadius: 16,
        background: 'var(--surface)',
        border: `1px solid ${dragging ? `oklch(0.85 0.16 ${g.hue} / 0.5)` : 'var(--border)'}`,
        boxShadow: dragging ? '0 14px 34px rgba(0,0,0,0.5)' : 'none',
        cursor: 'grab', touchAction: 'none', userSelect: 'none',
        ...style,
      }}>
      <div style={{
        width: 22, height: 22, borderRadius: 999, flexShrink: 0,
        background: 'var(--bg-deep)', border: '1px solid var(--border)',
        color: 'var(--muted)',
        fontFamily: 'JetBrains Mono, monospace', fontSize: 11, fontWeight: 700,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>{rank}</div>
      <div style={{
        width: 40, height: 40, borderRadius: 11, flexShrink: 0,
        background: `oklch(0.3 0.06 ${g.hue})`,
        color: `oklch(0.88 0.16 ${g.hue})`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontSize: 20, border: `1px solid oklch(0.85 0.16 ${g.hue} / 0.4)`,
      }}>{g.glyph}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 15, fontWeight: 600,
          color: 'var(--text)',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{window.groupName(g)}</div>
        <div style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--muted)', marginTop: 2,
        }}>{g.memberIds.length} · {t('mitglieder').toLowerCase()}</div>
      </div>
      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--muted)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}>
        <path d="M5 9h14M5 15h14" />
      </svg>
    </div>
  );
}

// Drag-to-reorder crew priority list. Pointer-based (not HTML5 drag-and-drop)
// so it works on touch: the grabbed row floats under the finger while the rest
// reflow to make room. Each reorder is persisted via fbSaveCrewPriority.
function PriorityGroupList({ groups, onDone }) {
  const t = window.t;
  const [order, setOrder] = React.useState(() => groups.map(g => g.id));
  // drag = { id, y, grabDy, left, w, wrapTop } while a row is held, else null
  const [drag, setDrag] = React.useState(null);
  const wrapRef = React.useRef(null);
  const stepRef = React.useRef(0);

  const ordered = order.map(id => window.GROUPS_BY_ID[id]).filter(Boolean);

  const onGrab = (e, rowEl, id) => {
    if (!rowEl || !wrapRef.current) return;
    e.preventDefault();
    const rect = rowEl.getBoundingClientRect();
    const wrapRect = wrapRef.current.getBoundingClientRect();
    stepRef.current = rect.height + 10; // card height + column gap
    rowEl.setPointerCapture?.(e.pointerId);
    setDrag({
      id,
      y: e.clientY,
      grabDy: e.clientY - rect.top,
      wrapTop: wrapRect.top,
    });
  };

  const onMove = (e) => {
    if (!drag) return;
    const step = stepRef.current || 1;
    const rel = (e.clientY - drag.grabDy) - drag.wrapTop;
    let target = Math.round(rel / step);
    target = Math.max(0, Math.min(order.length - 1, target));
    const curIdx = order.indexOf(drag.id);
    if (target !== curIdx) {
      const next = order.filter(x => x !== drag.id);
      next.splice(target, 0, drag.id);
      setOrder(next);
    }
    setDrag(d => ({ ...d, y: e.clientY }));
  };

  const onDrop = () => {
    if (!drag) return;
    window.fbSaveCrewPriority?.(order);
    setDrag(null);
  };

  return (
    <div style={{ marginBottom: 20 }}>
      <div style={{
        fontFamily: 'Space Grotesk, system-ui', fontSize: 12, color: 'var(--muted)',
        lineHeight: 1.45, margin: '0 2px 10px', padding: '0 2px',
      }}>{t('crew_priority_desc')}</div>
      <div ref={wrapRef}
        onPointerMove={onMove} onPointerUp={onDrop} onPointerCancel={onDrop}
        style={{ display: 'flex', flexDirection: 'column', gap: 10, position: 'relative' }}>
        {ordered.map((g, idx) => {
          const isDragging = drag && drag.id === g.id;
          const style = isDragging ? {
            zIndex: 5, position: 'relative',
            transform: `translateY(${(drag.y - drag.grabDy - drag.wrapTop) - idx * stepRef.current}px)`,
          } : null;
          return (
            <PriorityRow key={g.id} group={g} rank={idx + 1}
              dragging={!!isDragging} style={style} onGrab={onGrab} />
          );
        })}
      </div>
      <button onClick={onDone} style={{
        appearance: 'none', cursor: 'pointer', width: '100%',
        marginTop: 12, padding: '12px 14px', borderRadius: 14,
        background: 'var(--accent)', border: '1px solid var(--accent)',
        color: 'var(--bg-deep)',
        fontFamily: 'Space Grotesk, system-ui', fontSize: 14, fontWeight: 700,
      }}>{t('prioritize_done')}</button>
    </div>
  );
}

function Stat({ label, value, accent }) {
  return (
    <div style={{
      background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 14, padding: 12,
    }}>
      <div style={{
        fontFamily: 'Space Grotesk, system-ui', fontSize: 24, fontWeight: 700,
        color: accent ? 'var(--accent)' : 'var(--text)',
        letterSpacing: -0.5,
      }}>{value}</div>
      <div style={{
        fontFamily: 'Space Grotesk, system-ui', fontSize: 11,
        color: 'var(--muted)', letterSpacing: 0.4, textTransform: 'uppercase',
        marginTop: 2, fontWeight: 600,
      }}>{label}</div>
    </div>
  );
}

function FriendRow({ friend, onOpen }) {
  const t = window.t;
  const isMe = friend.id === 'me';
  const picks = window.PICKS[friend.id] || [];
  return (
    <Card padded={false} onClick={onOpen} style={{
      padding: 12, display: 'flex', alignItems: 'center', gap: 12,
    }}>
      <Avatar id={friend.id} size={44} showStatus />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 6,
          fontFamily: 'Space Grotesk, system-ui', fontSize: 15, fontWeight: 600,
          color: 'var(--text)',
        }}>
          <span>{friend.name}{isMe && <span style={{ color: 'var(--muted)', fontWeight: 400 }}> · {t('du')}</span>}</span>
        </div>
        <div style={{
          fontFamily: 'Space Grotesk, system-ui', fontSize: 12, color: 'var(--muted)',
          marginTop: 2,
        }}>
          {friend.online ? t('online') : t('offline')} · {picks.length} {t('picks')}
        </div>
      </div>
      <div style={{ display: 'flex' }}>
        {picks.slice(0, 3).map((gid, i) => (
          <div key={gid} style={{ marginLeft: i === 0 ? 0 : -10 }}>
            <GameCover game={window.GAMES_BY_ID[gid]} size={28} rounded={6} />
          </div>
        ))}
      </div>
    </Card>
  );
}

// All games a person has shared — their full library if we have it,
// otherwise their current picks resolved from the catalog.
function personGames(id) {
  const lib = id === 'me' ? (window.MY_LIBRARY || []) : ((window.FRIEND_LIBRARY || {})[id] || []);
  if (lib && lib.length) return lib;
  return (window.PICKS[id] || []).map(gid => window.GAMES_BY_ID[gid]).filter(Boolean);
}

// Person detail — header + the full list of games this person has.
function PersonDetail({ wide, personId, onBack }) {
  const t = window.t;
  const friend = window.FRIENDS_BY_ID[personId];
  if (!friend) return null;
  const isMe = personId === 'me';
  const gamerTag = friend.gamertag && friend.gamertag.trim();
  const games = personGames(personId);
  const pickIds = new Set(window.PICKS[personId] || []);
  const picksCount = (window.PICKS[personId] || []).length;

  return (
    <div style={{ padding: '16px 0 100px' }}>
      <div style={{ padding: '0 16px' }}>
        <button type="button" onClick={onBack} style={{
          appearance: 'none', cursor: 'pointer', background: 'transparent', border: 0,
          color: 'var(--muted)', fontFamily: 'Space Grotesk, system-ui', fontSize: 13,
          fontWeight: 600, padding: '0 0 14px', display: 'flex', alignItems: 'center', gap: 6,
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><path d="M15 6l-6 6 6 6" strokeLinecap="round" strokeLinejoin="round"/></svg>
          {t('back')}
        </button>

        {/* Person header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 18 }}>
          <Avatar id={personId} size={56} ring showStatus />
          <div style={{ flex: 1, minWidth: 0 }}>
            <h1 style={{
              fontFamily: 'Space Grotesk, system-ui', fontSize: 26, fontWeight: 700,
              color: 'var(--text)', letterSpacing: -0.6, margin: 0,
              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            }}>{friend.name}{isMe && <span style={{ color: 'var(--muted)', fontWeight: 400, fontSize: 18 }}> · {t('du')}</span>}</h1>
            <div style={{
              fontFamily: 'JetBrains Mono, monospace', fontSize: 12,
              color: gamerTag ? 'var(--muted)' : 'color-mix(in oklab, var(--muted) 60%, transparent)',
              marginTop: 4,
            }}>
              {gamerTag ? `@${gamerTag}` : t('no_gamertag')} · {friend.online ? t('person_online') : t('person_offline')}
            </div>
          </div>
        </div>

        {/* Stats */}
        <div style={{
          display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 18,
        }}>
          <Stat label={t('person_games')} value={games.length} accent />
          <Stat label={t('picks')} value={picksCount} />
        </div>

        <SectionHead title={t('person_games')} />
        {games.length === 0 ? (
          <div style={{
            fontFamily: 'Space Grotesk, system-ui', fontSize: 13, color: 'var(--muted)',
            padding: '8px 4px',
          }}>{t('person_no_games')}</div>
        ) : (
          <div style={{
            display: 'grid',
            gridTemplateColumns: wide
              ? 'repeat(auto-fill, minmax(150px, 1fr))'
              : 'repeat(2, 1fr)',
            gap: 8,
          }}>
            {games.map(g => {
              const picked = pickIds.has(g.id);
              return (
                <div key={g.id} style={{
                  background: 'var(--surface)', border: `1px solid ${picked ? 'color-mix(in oklab, var(--accent) 35%, var(--border))' : 'var(--border)'}`,
                  borderRadius: 14, padding: 10,
                  display: 'flex', alignItems: 'center', gap: 10,
                }}>
                  <GameCover game={g} size={40} rounded={9} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{
                      fontFamily: 'Space Grotesk, system-ui', fontSize: 13, fontWeight: 600,
                      color: 'var(--text)',
                      overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                    }}>{g.title}</div>
                    {picked && (
                      <div style={{
                        fontFamily: 'Space Grotesk, system-ui', fontSize: 9, fontWeight: 700,
                        letterSpacing: 0.6, textTransform: 'uppercase', color: 'var(--accent)',
                        marginTop: 2,
                      }}>★ {t('person_picks_label')}</div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { ScreenSpiele, ScreenCrew, GroupCard, GroupDetail, GroupMemberRow, PersonDetail, personGames });
