(function(){
// Shell: 左側導覽 + 頂部 bar + 主內容區
const T = window.STOCK_TOKENS;

function NavItem({ icon, label, active, onClick, badge }) {
  const [hover, setHover] = React.useState(false);
  return (
    <button onClick={onClick}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: 'flex', alignItems: 'center', gap: 10,
        width: '100%', padding: '8px 12px', borderRadius: 6,
        border: 'none', background: active ? T.surface : (hover ? T.hover : 'transparent'),
        color: active ? T.text : T.text2,
        fontSize: 13, fontWeight: active ? 600 : 500,
        cursor: 'pointer', textAlign: 'left',
        fontFamily: T.fontSans,
        boxShadow: active ? `0 1px 3px rgba(0,0,0,0.04), 0 0 0 1px ${T.border}` : 'none',
      }}>
      <span style={{ width: 16, height: 16, display: 'flex', alignItems: 'center', justifyContent: 'center', color: active ? T.primary : T.text3 }}>
        {icon}
      </span>
      <span style={{ flex: 1 }}>{label}</span>
      {badge && (
        <span style={{ fontSize: 9, fontWeight: 700, padding: '2px 5px', borderRadius: 3,
          background: T.aiSoft, color: T.ai, letterSpacing: 0.3 }}>{badge}</span>
      )}
    </button>
  );
}

const ICONS = {
  dashboard: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><rect x="2" y="2" width="5" height="5" rx="1"/><rect x="9" y="2" width="5" height="5" rx="1"/><rect x="2" y="9" width="5" height="5" rx="1"/><rect x="9" y="9" width="5" height="5" rx="1"/></svg>,
  portfolio: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M2 4h12v9a1 1 0 01-1 1H3a1 1 0 01-1-1V4z"/><path d="M5 4V3a1 1 0 011-1h4a1 1 0 011 1v1"/></svg>,
  stock: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M2 12l4-5 3 3 5-7"/><path d="M10 3h4v4"/></svg>,
  sector: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><circle cx="8" cy="8" r="6"/><path d="M8 2v6l4 2"/></svg>,
  flow: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M2 5h7M2 8h12M2 11h9"/><path d="M9 5l3-2v4z" fill="currentColor"/><path d="M11 11l3-2v4z" fill="currentColor"/></svg>,
  news: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><rect x="2" y="3" width="12" height="10" rx="1"/><path d="M5 6h6M5 9h6M5 11h4"/></svg>,
  watchlist: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M8 1.5l1.8 4.1 4.5.4-3.4 3 1 4.4L8 11.2l-3.9 2.2 1-4.4-3.4-3 4.5-.4z"/></svg>,
  picks: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M2 8l3 3 9-9"/><path d="M2 13h12"/></svg>,
  ai: <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M8 2v2M8 12v2M2 8h2M12 8h2M3.5 3.5l1.4 1.4M11.1 11.1l1.4 1.4M3.5 12.5l1.4-1.4M11.1 4.9l1.4-1.4"/><circle cx="8" cy="8" r="2.5"/></svg>,
};
window.ICONS = ICONS;

// ── Sidebar 內容（共用於 desktop aside 和 mobile drawer）───────────────────
function SidebarContent({ page, setPage, onClose }) {
  return (
    <>
      <div style={{ padding: '4px 12px 18px', display: 'flex', alignItems: 'center', gap: 8 }}>
        <div style={{ width: 24, height: 24, borderRadius: 5, background: T.text,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          color: 'white', fontWeight: 700, fontSize: 13, fontFamily: T.fontMono }}>S</div>
        <div>
          <div style={{ fontSize: 14, fontWeight: 600, color: T.text, letterSpacing: -0.2 }}>Stocksense</div>
          <div style={{ fontSize: 10, color: T.text3, fontFamily: T.fontMono }}>v2.4 · TW · US</div>
        </div>
        {onClose && (
          <button onClick={onClose} style={{
            marginLeft: 'auto', width: 28, height: 28, border: 'none', background: 'transparent',
            cursor: 'pointer', color: T.text3, display: 'flex', alignItems: 'center', justifyContent: 'center',
            borderRadius: 4,
          }}>
            <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.8">
              <path d="M3 3l10 10M13 3L3 13"/>
            </svg>
          </button>
        )}
      </div>

      <div style={{ fontSize: 10, fontWeight: 600, color: T.text4, letterSpacing: 0.5, padding: '8px 12px 4px' }}>總覽</div>
      <NavItem icon={ICONS.dashboard} label="Dashboard" active={page === 'dashboard'} onClick={() => setPage('dashboard')} />
      <NavItem icon={ICONS.picks} label="AI 推薦 / 每日整理" active={page === 'picks'} onClick={() => setPage('picks')} badge="AI" />
      <NavItem icon={ICONS.watchlist} label="我的觀察" active={page === 'watchlist'} onClick={() => setPage('watchlist')} />

      <div style={{ fontSize: 10, fontWeight: 600, color: T.text4, letterSpacing: 0.5, padding: '14px 12px 4px' }}>分析</div>
      <NavItem icon={ICONS.sector} label="產業 / 題材" active={page === 'sector'} onClick={() => setPage('sector')} badge="AI" />
      <NavItem icon={ICONS.news} label="新聞 + 情緒" active={page === 'news'} onClick={() => setPage('news')} badge="AI" />

      <div style={{ fontSize: 10, fontWeight: 600, color: T.text4, letterSpacing: 0.5, padding: '14px 12px 4px' }}>資金流向</div>
      <NavItem icon={ICONS.flow} label="台股資金流向" active={page === 'flow-tw'} onClick={() => setPage('flow-tw')} />
      <NavItem icon={ICONS.flow} label="美股資金流向" active={page === 'flow-us'} onClick={() => setPage('flow-us')} />

      <div style={{ flex: 1 }} />
    </>
  );
}

function Sidebar({ page, setPage, mobileOpen, setMobileOpen }) {
  const vp = window.useViewport();

  if (vp.isMobile) {
    return (
      <>
        {/* overlay */}
        {mobileOpen && (
          <div onClick={() => setMobileOpen(false)} style={{
            position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.4)',
            zIndex: 998,
          }} />
        )}
        {/* drawer */}
        <aside style={{
          position: 'fixed', top: 0, left: 0, bottom: 0,
          width: 240,
          transform: mobileOpen ? 'translateX(0)' : 'translateX(-100%)',
          transition: 'transform 0.25s cubic-bezier(0.4,0,0.2,1)',
          zIndex: 999,
          background: T.bg, borderRight: `1px solid ${T.border}`,
          padding: '18px 12px', display: 'flex', flexDirection: 'column', gap: 4,
          overflowY: 'auto',
        }}>
          <SidebarContent page={page} setPage={setPage} onClose={() => setMobileOpen(false)} />
        </aside>
      </>
    );
  }

  // desktop 原樣
  return (
    <aside style={{
      width: 220, background: T.bg, borderRight: `1px solid ${T.border}`,
      padding: '18px 12px', display: 'flex', flexDirection: 'column', gap: 4,
      flexShrink: 0,
    }}>
      <SidebarContent page={page} setPage={setPage} />
    </aside>
  );
}
window.Sidebar = Sidebar;

function TopBar({ page, onMenuClick }) {
  const vp = window.useViewport();
  const titles = {
    'dashboard': '今日總覽',
    'picks': 'AI 推薦 / 每日股票整理',
    'watchlist': '我的觀察',
    'sector': '產業 / 題材分析',
    'flow-tw': '台股資金流向',
    'flow-us': '美股資金流向',
    'news': '新聞 + 情緒分析',
  };
  return (
    <header style={{
      height: 56, padding: vp.isMobile ? '0 12px' : '0 24px', background: T.bg,
      borderBottom: `1px solid ${T.border}`,
      display: 'flex', alignItems: 'center', gap: vp.isMobile ? 10 : 16, flexShrink: 0,
    }}>
      {/* 漢堡選單按鈕（mobile only）*/}
      {vp.isMobile && (
        <button onClick={onMenuClick} style={{
          width: 36, height: 36, border: `1px solid ${T.border}`,
          borderRadius: 6, background: T.surface,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'pointer', color: T.text2, flexShrink: 0,
        }}>
          <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5">
            <path d="M2 4h12M2 8h12M2 12h12" strokeLinecap="round"/>
          </svg>
        </button>
      )}

      <div style={{
        fontSize: vp.isMobile ? 14 : 16,
        fontWeight: 600, color: T.text, letterSpacing: -0.3,
        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        flex: vp.isMobile ? 1 : 'none',
        maxWidth: vp.isMobile ? 'calc(100vw - 140px)' : 'none',
      }}>{titles[page]}</div>

      {!vp.isMobile && (
        <>
          <div style={{ width: 1, height: 18, background: T.border }} />
          <MarketTicker />
        </>
      )}
      {vp.isMobile && (
        <MobileIndexTicker />
      )}

      <div style={{ flex: 1 }} />

      {/* 通知鈴鐺 */}
      <button style={{
        width: vp.isMobile ? 32 : 32,
        height: vp.isMobile ? 32 : 32,
        borderRadius: 6, border: `1px solid ${T.border}`,
        background: T.surface, cursor: 'pointer', color: T.text2,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>
        <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M3 6a5 5 0 1110 0v3l1.5 2H1.5L3 9V6z"/><path d="M6 12a2 2 0 004 0"/></svg>
      </button>
      {/* User avatar */}
      <div style={{
        width: vp.isMobile ? 28 : 32,
        height: vp.isMobile ? 28 : 32,
        borderRadius: '50%', background: 'oklch(0.55 0.13 245)',
        color: 'white', fontSize: vp.isMobile ? 11 : 12, fontWeight: 600,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>YL</div>
    </header>
  );
}
window.TopBar = TopBar;

function MarketTicker() {
  const live = window.STOCK_DATA_LIVE;
  const indices = live?.market_indices?.indices || [];
  if (indices.length === 0) {
    return <div style={{ fontSize: 11, color: T.text3 }}>—</div>;
  }
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 18, fontFamily: T.fontMono }}>
      {indices.map(idx => (
        <div key={idx.symbol} style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
          <span style={{ fontSize: 11, color: T.text3 }}>{idx.name}</span>
          <span style={{ fontSize: 12, color: T.text, fontWeight: 500 }}>
            {idx.value != null ? window.fmt(idx.value, 2) : '—'}
          </span>
          {idx.change_pct != null && (
            <span style={{ fontSize: 11, color: window.dirColor(idx.change_pct), fontWeight: 500 }}>
              {window.sign(idx.change_pct)}{idx.change_pct.toFixed(2)}%
            </span>
          )}
        </div>
      ))}
    </div>
  );
}

function MobileIndexTicker() {
  const live = window.STOCK_DATA_LIVE;
  const indices = live?.market_indices?.indices || [];
  const first = indices[0];
  if (!first) {
    return (
      <div style={{ fontSize: 11, color: T.text3, fontFamily: T.fontMono, whiteSpace: 'nowrap' }}>
        —
      </div>
    );
  }
  return (
    <div style={{ fontSize: 11, color: T.text3, fontFamily: T.fontMono, whiteSpace: 'nowrap' }}>
      {first.name} {first.value != null ? window.fmt(first.value, 2) : '—'}
      {first.change_pct != null && (
        <span style={{ color: window.dirColor(first.change_pct) }}>
          {' '}{window.sign(first.change_pct)}{first.change_pct.toFixed(2)}%
        </span>
      )}
    </div>
  );
}

})();
