// extra-pages.jsx — Catalog, Studio landing, Download, Auth

// ────────────────────────────────────────────
// Catalog / Library — full grid with sidebar filters
// ────────────────────────────────────────────
function CatalogPage({ t, str, dark, lang, setLang, navigate }) {
  const [cat, setCat] = useState('all');
  const [sort, setSort] = useState('popular');
  const [view, setView] = useState('grid');
  const cats = ['all', 'obby', 'sim', 'rpg', 'racing', 'horror', 'tycoon'];
  const sortOptions = lang === 'ru'
    ? { popular: 'По популярности', rating: 'По рейтингу', new: 'Новинки', az: 'A → Z' }
    : { popular: 'Popular', rating: 'Top rated', new: 'New', az: 'A → Z' };

  let list = cat === 'all' ? GAMES : GAMES.filter(g => g.genre === cat);
  list = [...list];
  if (sort === 'rating') list.sort((a, b) => b.rating - a.rating);
  if (sort === 'new') list.reverse();
  if (sort === 'az') list.sort((a, b) => a.title.localeCompare(b.title));
  if (sort === 'popular') list.sort((a, b) => b.players - a.players);

  return (
    <div style={{ background: t.bg, color: t.text, fontFamily: '"Inter", system-ui, sans-serif', minHeight: '100vh' }}>
      <Nav t={t} str={str} dark={dark} lang={lang} setLang={setLang} active="library" setActive={(k) => navigate(k === 'discover' ? 'home' : k === 'library' ? 'catalog' : k === 'create' ? 'studio' : 'home')} />

      <div style={{ maxWidth: 1280, margin: '0 auto', padding: '32px 28px 60px' }}>
        <div style={{ marginBottom: 24 }}>
          <div style={{ fontSize: 11, color: t.faint, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 6 }}>
            {str.nav_library}
          </div>
          <h1 style={{ margin: 0, fontFamily: '"Inter Tight", sans-serif', fontSize: 48, fontWeight: 700, letterSpacing: '-0.03em' }}>
            {lang === 'ru' ? 'Все миры Craftix' : 'All Craftix worlds'}
          </h1>
          <div style={{ marginTop: 8, color: t.muted, fontSize: 14 }}>
            {lang === 'ru' ? 'Каталог откроется после первых публикаций.' : 'Catalog opens once the first places ship.'}
          </div>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '220px 1fr', gap: 32 }}>
          {/* Filter rail */}
          <aside style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
            <div>
              <div style={{ fontSize: 11, color: t.faint, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>
                {str.categories}
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                {cats.map(c => (
                  <button key={c} onClick={() => setCat(c)} style={{
                    background: cat === c ? t.surface2 : 'transparent', border: 'none', cursor: 'pointer',
                    padding: '8px 10px', borderRadius: 7, textAlign: 'left',
                    fontFamily: 'inherit', fontSize: 13, fontWeight: 500,
                    color: cat === c ? t.text : t.muted, display: 'flex', justifyContent: 'space-between',
                  }}>
                    <span>{str[c] || c}</span>
                    <span style={{ fontFamily: 'ui-monospace, monospace', fontSize: 11, color: t.faint }}>
                      {c === 'all' ? GAMES.length : GAMES.filter(g => g.genre === c).length}
                    </span>
                  </button>
                ))}
              </div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: t.faint, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>
                {lang === 'ru' ? 'Игроков сейчас' : 'Active players'}
              </div>
              <input type="range" defaultValue="50" style={{ width: '100%', accentColor: t.accent }} />
              <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', marginTop: 4 }}>
                <span>0</span><span>50k+</span>
              </div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: t.faint, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>
                {lang === 'ru' ? 'Платформа' : 'Platform'}
              </div>
              {['Desktop', 'Web', 'Mobile'].map(p => (
                <label key={p} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '6px 0', fontSize: 13, color: t.text, cursor: 'pointer' }}>
                  <input type="checkbox" defaultChecked style={{ accentColor: t.accent }} /> {p}
                </label>
              ))}
            </div>
          </aside>

          {/* Results */}
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 20, paddingBottom: 16, borderBottom: `1px solid ${t.border}` }}>
              <div style={{ fontSize: 14, color: t.muted }}>
                <span style={{ color: t.text, fontWeight: 600 }}>{list.length}</span> {str.worlds}
              </div>
              <div style={{ flex: 1 }} />
              <div style={{ display: 'flex', gap: 4, padding: 3, background: t.surface, borderRadius: 8, border: `1px solid ${t.border}` }}>
                {Object.entries(sortOptions).map(([k, v]) => (
                  <button key={k} onClick={() => setSort(k)} style={{
                    background: sort === k ? t.bg : 'transparent', border: 'none', cursor: 'pointer',
                    padding: '5px 10px', borderRadius: 6, fontSize: 12, fontWeight: 500,
                    color: sort === k ? t.text : t.muted, fontFamily: 'inherit',
                  }}>{v}</button>
                ))}
              </div>
              <div style={{ display: 'flex', gap: 2 }}>
                <button onClick={() => setView('grid')} style={{ width: 28, height: 28, border: `1px solid ${t.border}`, borderRadius: 6, background: view === 'grid' ? t.surface2 : 'transparent', cursor: 'pointer', color: t.text, fontFamily: 'ui-monospace, monospace' }}>▦</button>
                <button onClick={() => setView('list')} style={{ width: 28, height: 28, border: `1px solid ${t.border}`, borderRadius: 6, background: view === 'list' ? t.surface2 : 'transparent', cursor: 'pointer', color: t.text, fontFamily: 'ui-monospace, monospace' }}>≡</button>
              </div>
            </div>

            {list.length === 0 ? (
              <EmptyState
                t={t} height={360}
                title={lang === 'ru' ? 'Каталог пока пуст' : 'Catalog is empty'}
                sub={lang === 'ru' ? 'Скоро здесь появятся первые миры. Хочешь быть среди авторов — открой Studio.' : 'First worlds land here soon. Want to be one of the early creators — open Studio.'}
                action={lang === 'ru' ? 'Открыть Studio' : 'Open Studio'}
                onAction={() => navigate('studio')}
              />
            ) : view === 'grid' ? (
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
                {list.map(g => <GameCard key={g.id} g={g} t={t} str={str} dark={dark} onClick={() => navigate('game', { gameId: g.id })} />)}
              </div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {list.map((g, i) => (
                  <div key={g.id} onClick={() => navigate('game', { gameId: g.id })} style={{
                    display: 'grid', gridTemplateColumns: '60px 1fr auto auto auto auto', gap: 16, alignItems: 'center',
                    padding: '10px 14px', background: t.surface, border: `1px solid ${t.border}`, borderRadius: 10, cursor: 'pointer',
                  }}>
                    <div style={{ width: 60, height: 60 }}><Placeholder hue={g.hue} pattern={g.pattern} dark={dark} radius={8} /></div>
                    <div>
                      <div style={{ fontSize: 14, fontWeight: 600 }}>{g.title}</div>
                      <div style={{ fontSize: 11, color: t.muted }}>{str.by} {g.creator}</div>
                    </div>
                    <div style={{ fontSize: 11, fontFamily: 'ui-monospace, monospace', color: t.muted, textTransform: 'uppercase', minWidth: 60 }}>{g.genre}</div>
                    <div style={{ fontFamily: 'ui-monospace, monospace', fontSize: 12 }}>★ {g.rating}</div>
                    <div style={{ fontFamily: 'ui-monospace, monospace', fontSize: 12, color: t.muted, minWidth: 80, textAlign: 'right' }}>● {fmt(g.players)}</div>
                    <Btn t={t} kind="primary" size="sm">▶ {str.play}</Btn>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────
// Studio landing — for developers
// ────────────────────────────────────────────
function StudioPage({ t, str, dark, lang, setLang, navigate }) {
  return (
    <div style={{ background: t.bg, color: t.text, fontFamily: '"Inter", system-ui, sans-serif', minHeight: '100vh' }}>
      <Nav t={t} str={str} dark={dark} lang={lang} setLang={setLang} active="create" setActive={(k) => navigate(k === 'discover' ? 'home' : k === 'library' ? 'catalog' : k === 'create' ? 'studio' : 'home')} />

      {/* Hero */}
      <div style={{ maxWidth: 1280, margin: '0 auto', padding: '80px 28px 60px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 48, alignItems: 'center' }}>
        <div>
          <div style={{ fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 18 }}>
            ✦ Craftix Studio · {lang === 'ru' ? 'ранний доступ' : 'early access'}
          </div>
          <h1 style={{ margin: 0, fontFamily: '"Inter Tight", sans-serif', fontSize: 84, lineHeight: 0.95, fontWeight: 700, letterSpacing: '-0.045em' }}>
            {lang === 'ru' ? 'Делай миры. ' : 'Make worlds. '}<span style={{ background: t.accent, color: t.accentInk, padding: '0 12px', borderRadius: 12 }}>{lang === 'ru' ? 'Без кода' : 'No code'}</span> {lang === 'ru' ? 'или с кодом.' : 'or with code.'}
          </h1>
          <p style={{ marginTop: 24, fontSize: 17, color: t.muted, lineHeight: 1.55, maxWidth: 520 }}>
            {lang === 'ru'
              ? 'Мощный 3D-редактор, скриптинг на Lua, мгновенная публикация. Бесплатно для всех — монетизация только когда твоя игра приносит доход.'
              : 'A powerful 3D editor, Lua scripting, instant publish. Free for everyone — you only pay when your game makes money.'}
          </p>
          <div style={{ marginTop: 28, display: 'flex', gap: 10 }}>
            <Btn t={t} kind="primary" size="lg" onClick={() => navigate('download')}>↓ {lang === 'ru' ? 'Скачать Studio' : 'Download Studio'}</Btn>
            <Btn t={t} kind="outline" size="lg" onClick={() => navigate('editor')}>{lang === 'ru' ? 'Открыть демо' : 'Open live demo'} →</Btn>
          </div>
          <div style={{ marginTop: 22, display: 'flex', gap: 24, fontSize: 12, color: t.muted, fontFamily: 'ui-monospace, monospace' }}>
            <span>● Windows</span><span>● macOS</span><span>● Linux</span>
          </div>
        </div>
        <div style={{ position: 'relative', height: 460 }}>
          <StudioEditor t={t} str={str} dark={dark} lang={lang} setLang={setLang} navigate={navigate} embedded />
        </div>
      </div>

      {/* Pillars band — no fake numbers */}
      <div style={{ maxWidth: 1280, margin: '0 auto', padding: '0 28px' }}>
        <div style={{ borderTop: `1px solid ${t.border}`, borderBottom: `1px solid ${t.border}`, padding: '32px 0', display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 24 }}>
          {[
            { k: lang === 'ru' ? 'бесплатно' : 'free', v: lang === 'ru' ? 'для всех' : 'for everyone' },
            { k: lang === 'ru' ? 'без банковской карты' : 'no card', v: lang === 'ru' ? 'на старт' : 'to start' },
            { k: 'Lua', v: lang === 'ru' ? 'скриптинг' : 'scripting' },
            { k: 'Win · macOS · Linux', v: lang === 'ru' ? 'кросс-платформа' : 'cross-platform' },
          ].map(s => (
            <div key={s.k}>
              <div style={{ fontSize: 11, color: t.faint, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{s.v}</div>
              <div style={{ marginTop: 6, fontFamily: '"Inter Tight", sans-serif', fontSize: 28, fontWeight: 600, letterSpacing: '-0.02em' }}>{s.k}</div>
            </div>
          ))}
        </div>
      </div>

      {/* Feature grid */}
      <div style={{ maxWidth: 1280, margin: '0 auto', padding: '60px 28px' }}>
        <SectionHead t={t} kicker="features" title={lang === 'ru' ? 'Что внутри Studio' : 'Inside Studio'} />
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
          {[
            { i: '◆', h: lang === 'ru' ? '3D редактор' : '3D editor', d: lang === 'ru' ? 'Меш-инструменты, физика, лайтмаппинг.' : 'Mesh tools, physics, lightmapping.' },
            { i: '◇', h: lang === 'ru' ? 'Lua скриптинг' : 'Lua scripting', d: lang === 'ru' ? 'Полный API, hot-reload, отладчик.' : 'Full API, hot-reload, debugger.' },
            { i: '◉', h: lang === 'ru' ? 'Multiplayer из коробки' : 'Multiplayer baked in', d: lang === 'ru' ? 'Серверы, репликация, голос — настроены.' : 'Servers, replication, voice — preconfigured.' },
            { i: '✦', h: lang === 'ru' ? 'Asset Store' : 'Asset Store', d: lang === 'ru' ? 'Тысячи моделей и звуков от сообщества.' : 'Thousands of community models and sounds.' },
            { i: '◈', h: lang === 'ru' ? 'Аналитика' : 'Analytics', d: lang === 'ru' ? 'Удержание, ARPU, A/B тесты — встроены.' : 'Retention, ARPU, A/B tests — built-in.' },
            { i: '▣', h: lang === 'ru' ? 'Монетизация' : 'Monetization', d: lang === 'ru' ? 'Пропуска, предметы, подписки в 2 клика.' : 'Passes, items, subs in two clicks.' },
          ].map(f => (
            <div key={f.h} style={{ padding: 24, background: t.surface, border: `1px solid ${t.border}`, borderRadius: 14 }}>
              <div style={{ width: 36, height: 36, background: t.surface2, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'ui-monospace, monospace', fontSize: 18, color: t.accent, marginBottom: 16 }}>{f.i}</div>
              <div style={{ fontFamily: '"Inter Tight", sans-serif', fontSize: 18, fontWeight: 600, letterSpacing: '-0.01em' }}>{f.h}</div>
              <div style={{ marginTop: 6, fontSize: 13, color: t.muted, lineHeight: 1.55 }}>{f.d}</div>
            </div>
          ))}
        </div>
      </div>

      {/* Code preview */}
      <div style={{ maxWidth: 1280, margin: '0 auto', padding: '20px 28px 60px' }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 32, alignItems: 'center' }}>
          <div>
            <div style={{ fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>
              api · examples
            </div>
            <h2 style={{ margin: 0, fontFamily: '"Inter Tight", sans-serif', fontSize: 36, fontWeight: 700, letterSpacing: '-0.025em' }}>
              {lang === 'ru' ? 'Lua, который ты ожидаешь.' : 'The Lua you expect.'}
            </h2>
            <p style={{ marginTop: 14, fontSize: 15, color: t.muted, lineHeight: 1.6 }}>
              {lang === 'ru'
                ? 'Знакомый API, типизация через аннотации, импорт пакетов из npm-подобного реестра.'
                : 'Familiar API, optional typing via annotations, npm-style package imports.'}
            </p>
          </div>
          <pre style={{
            margin: 0, padding: 24, background: dark ? 'oklch(11% 0.005 250)' : 'oklch(15% 0.005 250)',
            color: 'oklch(92% 0.005 250)', borderRadius: 14,
            fontFamily: '"JetBrains Mono", ui-monospace, monospace', fontSize: 13, lineHeight: 1.6, overflow: 'hidden',
          }}>
{`-- player_jump.lua
local Players = craftix.Players
local Input   = craftix.Input

Input:OnAction("jump", function(player)
  local char = player.character
  if char.grounded then
    char:ApplyImpulse(Vector3.up * 32)
    craftix.Sound:Play("woosh", { pitch = 1.05 })
  end
end)`}
          </pre>
        </div>
      </div>

      {/* CTA */}
      <div style={{ maxWidth: 1280, margin: '0 auto 60px', padding: '0 28px' }}>
        <div style={{
          padding: 48, borderRadius: 18, textAlign: 'center',
          background: t.text, color: t.bg,
        }}>
          <h2 style={{ margin: 0, fontFamily: '"Inter Tight", sans-serif', fontSize: 56, fontWeight: 700, letterSpacing: '-0.03em' }}>
            {lang === 'ru' ? 'Начни сегодня.' : 'Start today.'}
          </h2>
          <p style={{ marginTop: 12, fontSize: 16, opacity: 0.7, maxWidth: 480, marginLeft: 'auto', marginRight: 'auto' }}>
            {lang === 'ru' ? 'Бесплатно. Без банковской карты. Опубликуй мир за час.' : 'Free. No card. Publish a world within an hour.'}
          </p>
          <div style={{ marginTop: 24, display: 'flex', gap: 10, justifyContent: 'center' }}>
            <button onClick={() => navigate('download')} style={{ padding: '14px 26px', background: t.accent, color: t.accentInk, border: 'none', borderRadius: 10, fontSize: 14, fontWeight: 600, cursor: 'pointer', fontFamily: 'inherit' }}>↓ {lang === 'ru' ? 'Скачать Studio' : 'Get Studio'}</button>
            <button style={{ padding: '14px 26px', background: 'transparent', color: t.bg, border: `1px solid ${t.bg}`, borderRadius: 10, fontSize: 14, fontWeight: 600, cursor: 'pointer', fontFamily: 'inherit' }}>{lang === 'ru' ? 'Открыть туториал' : 'Open tutorial'}</button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────
// Download page
// ────────────────────────────────────────────
function DownloadPage({ t, str, dark, lang, setLang, navigate }) {
  const [os, setOs] = useState('mac');
  const oses = [
    { key: 'mac',   label: 'macOS',   sub: '12.0+ · Apple Silicon / Intel' },
    { key: 'win',   label: 'Windows', sub: '10/11 · 64-bit' },
    { key: 'linux', label: 'Linux',   sub: 'AppImage · deb · rpm' },
  ];
  const cur = oses.find(o => o.key === os);

  return (
    <div style={{ background: t.bg, color: t.text, fontFamily: '"Inter", system-ui, sans-serif', minHeight: '100vh' }}>
      <Nav t={t} str={str} dark={dark} lang={lang} setLang={setLang} active="discover" setActive={(k) => navigate(k === 'discover' ? 'home' : k === 'library' ? 'catalog' : k === 'create' ? 'studio' : 'home')} />

      <div style={{ maxWidth: 1100, margin: '0 auto', padding: '60px 28px' }}>
        <div style={{ textAlign: 'center', marginBottom: 48 }}>
          <div style={{ fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 14 }}>
            ↓ {lang === 'ru' ? 'Скачать клиент' : 'Get the client'}
          </div>
          <h1 style={{ margin: 0, fontFamily: '"Inter Tight", sans-serif', fontSize: 64, fontWeight: 700, letterSpacing: '-0.035em' }}>
            {lang === 'ru' ? 'Craftix Player & Studio.' : 'Craftix Player & Studio.'}
          </h1>
          <p style={{ marginTop: 14, color: t.muted, fontSize: 16, maxWidth: 580, marginLeft: 'auto', marginRight: 'auto' }}>
            {lang === 'ru' ? 'Один клиент — играй и создавай. Бесплатно навсегда.' : 'One client — play and create. Free forever.'}
          </p>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 32 }}>
          {oses.map(o => (
            <button key={o.key} onClick={() => setOs(o.key)} style={{
              padding: 24, borderRadius: 14, cursor: 'pointer', textAlign: 'left',
              background: os === o.key ? t.text : t.surface,
              color: os === o.key ? t.bg : t.text,
              border: `1px solid ${os === o.key ? t.text : t.border}`,
              fontFamily: 'inherit',
            }}>
              <div style={{ fontSize: 22, fontWeight: 600, fontFamily: '"Inter Tight", sans-serif' }}>{o.label}</div>
              <div style={{ fontSize: 12, opacity: 0.7, marginTop: 4 }}>{o.sub}</div>
            </button>
          ))}
        </div>

        <div style={{ padding: 32, background: t.surface, border: `1px solid ${t.border}`, borderRadius: 16, display: 'grid', gridTemplateColumns: '1fr auto', gap: 20, alignItems: 'center' }}>
          <div>
            <div style={{ fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              {lang === 'ru' ? 'Скоро · ранний доступ' : 'Soon · early access'}
            </div>
            <div style={{ marginTop: 6, fontFamily: '"Inter Tight", sans-serif', fontSize: 24, fontWeight: 600 }}>
              Craftix-{cur.label}.{os === 'mac' ? 'dmg' : os === 'win' ? 'exe' : 'AppImage'}
            </div>
            <div style={{ marginTop: 4, fontSize: 12, color: t.muted, fontFamily: 'ui-monospace, monospace' }}>
              {lang === 'ru' ? 'Сборка появится здесь после публикации.' : 'Build lands here after launch.'}
            </div>
          </div>
          <Btn t={t} kind="primary" size="lg">{lang === 'ru' ? 'Уведомить меня' : 'Notify me'}</Btn>
        </div>

        {/* System reqs */}
        <div style={{ marginTop: 48, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
          {[
            { h: lang === 'ru' ? 'Минимальные требования' : 'Minimum', items: [['CPU', 'Dual-core 2.4 GHz'], ['RAM', '4 GB'], ['GPU', 'OpenGL 3.3 / Metal'], ['Disk', '2 GB']] },
            { h: lang === 'ru' ? 'Рекомендуемые' : 'Recommended',     items: [['CPU', 'Quad-core 3.0 GHz'], ['RAM', '8 GB'], ['GPU', 'Vulkan 1.1 / Metal 3'], ['Disk', '8 GB SSD']] },
          ].map(b => (
            <div key={b.h} style={{ padding: 24, background: t.surface, border: `1px solid ${t.border}`, borderRadius: 14 }}>
              <div style={{ fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 14 }}>{b.h}</div>
              {b.items.map(([k, v]) => (
                <div key={k} style={{ display: 'flex', justifyContent: 'space-between', padding: '8px 0', borderBottom: `1px solid ${t.border}`, fontSize: 13 }}>
                  <span style={{ color: t.muted }}>{k}</span>
                  <span style={{ color: t.text, fontFamily: 'ui-monospace, monospace' }}>{v}</span>
                </div>
              ))}
            </div>
          ))}
        </div>

        <div style={{ marginTop: 32, padding: 20, background: t.surface, border: `1px solid ${t.border}`, borderRadius: 12, textAlign: 'center', fontSize: 13, color: t.muted }}>
          {lang === 'ru' ? 'Web-плеер запустится прямо в браузере — ' : 'Or play instantly in your browser — '}
          <a onClick={() => navigate('catalog')} style={{ color: t.text, textDecoration: 'underline', cursor: 'pointer', fontWeight: 500 }}>{lang === 'ru' ? 'выбрать игру' : 'pick a game'}</a>.
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────
// Auth / Sign up
// ────────────────────────────────────────────
function AuthPage({ t, str, dark, lang, setLang, navigate }) {
  const [mode, setMode] = useState('signup'); // signup | signin
  const [email, setEmail] = useState('');
  const [user, setUser] = useState('');
  const [pass, setPass] = useState('');
  const [busy, setBusy] = useState(false);
  const [err,  setErr]  = useState('');
  const isSignup = mode === 'signup';

  // Real submit handler — talks to Supabase auth via the global client
  // installed by /craftix-config.js. The trigger handle_new_user() in the
  // SQL migration auto-creates a profiles row from the metadata.
  async function submit() {
    setErr('');
    if (!email || !pass) {
      setErr(lang === 'ru' ? 'Заполни email и пароль.' : 'Email and password required.');
      return;
    }
    if (isSignup && (!user || user.length < 3)) {
      setErr(lang === 'ru' ? 'Никнейм минимум 3 символа.' : 'Username must be 3+ characters.');
      return;
    }
    setBusy(true);
    try {
      const sb = window.getSupabase();
      let res;
      if (isSignup) {
        res = await sb.auth.signUp({
          email, password: pass,
          options: { data: { username: user, display_name: user } },
        });
      } else {
        res = await sb.auth.signInWithPassword({ email, password: pass });
      }
      if (res.error) { setErr(res.error.message); return; }
      // success — go home (or verify if email confirmation is on).
      navigate(isSignup && !res.data.session ? 'verify' : 'home');
    } catch (ex) {
      setErr(String(ex && ex.message || ex));
    } finally {
      setBusy(false);
    }
  }

  return (
    <div style={{ background: t.bg, color: t.text, fontFamily: '"Inter", system-ui, sans-serif', minHeight: '100vh', display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
      {/* Left form column */}
      <div style={{ padding: '40px 60px', display: 'flex', flexDirection: 'column' }}>
        <div onClick={() => navigate('home')} style={{ cursor: 'pointer' }}>
          <Logo dark={dark} />
        </div>
        <div style={{ flex: 1, display: 'flex', alignItems: 'center' }}>
          <div style={{ width: '100%', maxWidth: 380 }}>
            <div style={{ fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 14 }}>
              {isSignup ? (lang === 'ru' ? 'Новый аккаунт' : 'New account') : (lang === 'ru' ? 'Возвращение' : 'Welcome back')}
            </div>
            <h1 style={{ margin: 0, fontFamily: '"Inter Tight", sans-serif', fontSize: 44, fontWeight: 700, letterSpacing: '-0.03em', lineHeight: 1.05 }}>
              {isSignup
                ? (lang === 'ru' ? 'Запрыгивай.' : 'Jump in.')
                : (lang === 'ru' ? 'С возвращением.' : 'Glad you\u2019re back.')}
            </h1>
            <p style={{ marginTop: 10, fontSize: 14, color: t.muted, lineHeight: 1.55 }}>
              {isSignup
                ? (lang === 'ru' ? 'Ник навсегда. Email можно сменить.' : 'Username is forever. Email is editable.')
                : (lang === 'ru' ? 'Введи свои данные.' : 'Enter your details.')}
            </p>

            <div style={{ marginTop: 28, display: 'flex', flexDirection: 'column', gap: 12 }}>
              {isSignup && (
                <Field t={t} label={lang === 'ru' ? 'Никнейм' : 'Username'} value={user} onChange={setUser} placeholder="craftix_player" mono />
              )}
              <Field t={t} label="Email" value={email} onChange={setEmail} placeholder="you@craftix.dev" />
              <Field t={t} label={lang === 'ru' ? 'Пароль' : 'Password'} value={pass} onChange={setPass} placeholder="••••••••" type="password" />
            </div>

            {isSignup && (
              <label style={{ display: 'flex', gap: 10, alignItems: 'flex-start', marginTop: 16, fontSize: 12, color: t.muted, lineHeight: 1.5, cursor: 'pointer' }}>
                <input type="checkbox" defaultChecked style={{ marginTop: 2, accentColor: t.accent }} />
                <span>{lang === 'ru' ? 'Я согласен с условиями и мне 13+' : 'I agree to terms and I\u2019m 13+'}</span>
              </label>
            )}

            <Btn t={t} kind="primary" size="lg" fullWidth style={{ marginTop: 22, opacity: busy ? 0.6 : 1 }} onClick={busy ? undefined : submit}>
              {busy
                ? (lang === 'ru' ? 'Подождите…' : 'Working…')
                : (isSignup
                    ? (lang === 'ru' ? 'Создать аккаунт' : 'Create account')
                    : (lang === 'ru' ? 'Войти' : 'Sign in'))}
            </Btn>

            {err && (
              <div style={{
                marginTop: 12, padding: '10px 12px',
                borderRadius: 8, fontSize: 12,
                background: dark ? 'rgba(220,80,80,0.12)' : 'rgba(220,80,80,0.10)',
                color: dark ? '#ff8a8a' : '#a32020',
                border: `1px solid ${dark ? 'rgba(220,80,80,0.35)' : 'rgba(220,80,80,0.25)'}`,
              }}>{err}</div>
            )}

            {!isSignup && (
              <div style={{ marginTop: 10, textAlign: 'right' }}>
                <span onClick={() => navigate('forgot')} style={{ fontSize: 12, color: t.muted, textDecoration: 'underline', cursor: 'pointer' }}>
                  {lang === 'ru' ? 'Забыл пароль?' : 'Forgot password?'}
                </span>
              </div>
            )}

            <div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '20px 0', color: t.faint }}>
              <div style={{ flex: 1, height: 1, background: t.border }} />
              <div style={{ fontSize: 11, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.08em' }}>
                {lang === 'ru' ? 'или' : 'or'}
              </div>
              <div style={{ flex: 1, height: 1, background: t.border }} />
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
              <OAuthButton provider="google"  dark={dark} disabled={busy}
                           onError={setErr} />
              <OAuthButton provider="discord" dark={dark} disabled={busy}
                           onError={setErr} />
            </div>

            <div style={{ marginTop: 22, fontSize: 13, color: t.muted, textAlign: 'center' }}>
              {isSignup
                ? (lang === 'ru' ? 'Уже есть аккаунт? ' : 'Already have an account? ')
                : (lang === 'ru' ? 'Новый игрок? ' : 'New here? ')}
              <span onClick={() => setMode(isSignup ? 'signin' : 'signup')} style={{ color: t.text, textDecoration: 'underline', cursor: 'pointer', fontWeight: 500 }}>
                {isSignup ? (lang === 'ru' ? 'Войти' : 'Sign in') : (lang === 'ru' ? 'Создать' : 'Sign up')}
              </span>
            </div>
          </div>
        </div>
        <div style={{ fontSize: 11, color: t.faint, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
          © 2026 craftix dev
        </div>
      </div>

      {/* Right artwork column */}
      <div style={{ position: 'relative', overflow: 'hidden', borderLeft: `1px solid ${t.border}` }}>
        <Placeholder hue={130} pattern="grid" dark={dark} radius={0} label="auth illustration · 1080x1200" />
        <div style={{
          position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: 60,
        }}>
          <div style={{ maxWidth: 420 }}>
            <div style={{ fontFamily: '"Inter Tight", sans-serif', fontSize: 40, fontWeight: 700, letterSpacing: '-0.025em', lineHeight: 1.1, color: t.text }}>
              {lang === 'ru' ? 'Один аккаунт. Любой мир.' : 'One account. Any world.'}
            </div>
            <div style={{ marginTop: 16, fontSize: 14, color: t.muted, lineHeight: 1.6 }}>
              {lang === 'ru'
                ? 'Кросс-сохранения между Player и Studio. Друзья, инвентарь, бейджи — везде с тобой.'
                : 'Cross-save between Player and Studio. Friends, inventory, badges — with you everywhere.'}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// Branded OAuth button. Mimics the official "Sign in with X" widgets:
//   • Google — white, light shadow, 4-color "G" mark, "Continue with Google"
//   • Discord — blurple #5865F2, white text + clyde mark
// Click triggers a Supabase OAuth redirect; the provider must be enabled
// in Supabase dashboard → Authentication → Providers.
function OAuthButton({ provider, dark, disabled, onError }) {
  const isGoogle = provider === 'google';

  async function go() {
    onError && onError('');
    if (!window.getSupabase) return;
    try {
      const sb = window.getSupabase();
      const { error } = await sb.auth.signInWithOAuth({
        provider,
        options: { redirectTo: window.location.origin + '/Craftix.html' },
      });
      if (error && onError) onError(error.message);
    } catch (e) {
      if (onError) onError(String(e && e.message || e));
    }
  }

  const baseStyle = {
    height: 44, padding: '0 14px', borderRadius: 10,
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
    fontFamily: 'inherit', fontSize: 14, fontWeight: 500,
    cursor: disabled ? 'default' : 'pointer',
    border: '1px solid transparent', width: '100%', whiteSpace: 'nowrap',
    transition: 'all 0.12s', opacity: disabled ? 0.55 : 1,
  };

  if (isGoogle) {
    return (
      <button onClick={disabled ? undefined : go} style={{
        ...baseStyle,
        background: '#ffffff', color: '#1f1f1f',
        border: `1px solid ${dark ? '#dadce0aa' : '#dadce0'}`,
        boxShadow: dark ? 'none' : '0 1px 2px rgba(60,64,67,0.08)',
      }}
        onMouseEnter={(e) => { if (!disabled) e.currentTarget.style.background = '#f7f8f8'; }}
        onMouseLeave={(e) => { e.currentTarget.style.background = '#ffffff'; }}
      >
        <GoogleG />
        <span>Continue with Google</span>
      </button>
    );
  }

  // Discord
  return (
    <button onClick={disabled ? undefined : go} style={{
      ...baseStyle,
      background: '#5865F2', color: '#ffffff', border: '1px solid #5865F2',
    }}
      onMouseEnter={(e) => { if (!disabled) e.currentTarget.style.background = '#4752c4'; }}
      onMouseLeave={(e) => { e.currentTarget.style.background = '#5865F2'; }}
    >
      <DiscordMark />
      <span>Continue with Discord</span>
    </button>
  );
}

// Google "G" logo — 4-colour, official.
function GoogleG() {
  return (
    <svg width="18" height="18" viewBox="0 0 18 18" aria-hidden="true">
      <path fill="#4285F4" d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.258h2.908c1.702-1.567 2.684-3.875 2.684-6.615z"/>
      <path fill="#34A853" d="M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.583-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z"/>
      <path fill="#FBBC05" d="M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z"/>
      <path fill="#EA4335" d="M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z"/>
    </svg>
  );
}

// Discord clyde mark — official.
function DiscordMark() {
  return (
    <svg width="20" height="15" viewBox="0 0 71 55" aria-hidden="true" fill="none">
      <path fill="#fff" d="M60.105 4.898A58.55 58.55 0 0 0 45.653.415a.22.22 0 0 0-.232.11 40.784 40.784 0 0 0-1.8 3.697c-5.456-.817-10.886-.817-16.23 0a37.39 37.39 0 0 0-1.831-3.697.227.227 0 0 0-.233-.11 58.39 58.39 0 0 0-14.451 4.483.207.207 0 0 0-.095.082C1.578 18.73-.944 32.144.293 45.39a.243.243 0 0 0 .093.165 58.875 58.875 0 0 0 17.717 8.962.227.227 0 0 0 .246-.082 42.07 42.07 0 0 0 3.622-5.901.222.222 0 0 0-.122-.31 38.81 38.81 0 0 1-5.539-2.64.225.225 0 0 1-.022-.374 30.742 30.742 0 0 0 1.099-.86.218.218 0 0 1 .228-.031c11.622 5.305 24.205 5.305 35.69 0a.218.218 0 0 1 .232.029c.353.292.722.582 1.1.862a.225.225 0 0 1-.019.374 36.404 36.404 0 0 1-5.541 2.638.225.225 0 0 0-.12.312 47.249 47.249 0 0 0 3.62 5.898.224.224 0 0 0 .246.084 58.682 58.682 0 0 0 17.745-8.962.226.226 0 0 0 .093-.163c1.481-15.315-2.48-28.618-10.5-40.412a.18.18 0 0 0-.092-.083zm-36.38 32.427c-3.497 0-6.38-3.211-6.38-7.156 0-3.944 2.827-7.156 6.38-7.156 3.582 0 6.438 3.24 6.382 7.156 0 3.945-2.828 7.156-6.382 7.156zm23.593 0c-3.498 0-6.38-3.211-6.38-7.156 0-3.944 2.826-7.156 6.38-7.156 3.582 0 6.437 3.24 6.38 7.156 0 3.945-2.798 7.156-6.38 7.156z"/>
    </svg>
  );
}

function Field({ t, label, value, onChange, placeholder, type = 'text', mono }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      <span style={{ fontSize: 11, color: t.muted, fontFamily: 'ui-monospace, monospace', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{label}</span>
      <input
        type={type} value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder}
        style={{
          height: 42, padding: '0 14px',
          background: t.surface, border: `1px solid ${t.border}`, borderRadius: 10,
          color: t.text, fontSize: 14, outline: 'none',
          fontFamily: mono ? '"JetBrains Mono", ui-monospace, monospace' : 'inherit',
        }}
        onFocus={(e) => e.target.style.borderColor = t.text}
        onBlur={(e) => e.target.style.borderColor = t.border}
      />
    </label>
  );
}

Object.assign(window, { CatalogPage, StudioPage, DownloadPage, AuthPage });
