// Shared components for Fortune VPN ЛК — Sidebar, TopBar, Card, Hero, Modal, Icons.
// All built against the design tokens in tokens.css.

// ── Lucide-style stroke icons (1.75–2px, 22px box) ─────────────────────
const Icon = ({ d, size = 22, sw = 2, fill = "none", children }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">
    {children || <path d={d} />}
  </svg>
);

const Icons = {
  home:    () => <Icon><path d="M3 11l9-8 9 8" /><path d="M5 10v10h14V10" /></Icon>,
  phone:   () => <Icon><rect x="6" y="2" width="12" height="20" rx="2" /><path d="M11 18h2" /></Icon>,
  key:     () => <Icon><circle cx="8" cy="15" r="4" /><path d="M11 12l9-9" /><path d="M17 6l3 3" /><path d="M15 8l3 3" /></Icon>,
  gift:    () => <Icon><path d="M20 12v9H4v-9" /><rect x="2" y="7" width="20" height="5" rx="1" /><path d="M12 21V7" /><path d="M12 7c-1.5-3-5-3-5 0 0 2 2 2 5 2"/><path d="M12 7c1.5-3 5-3 5 0 0 2-2 2-5 2"/></Icon>,
  users:   () => <Icon><path d="M16 19v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 19v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13A4 4 0 0 1 16 11"/></Icon>,
  receipt: () => <Icon><path d="M5 3h14v18l-3-2-2 2-2-2-2 2-2-2-3 2z"/><path d="M9 8h6"/><path d="M9 12h6"/><path d="M9 16h4"/></Icon>,
  settings:() => <Icon><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 0 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 0 1 0-4h.1A1.7 1.7 0 0 0 4.6 9a1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1A1.7 1.7 0 0 0 9 4.6 1.7 1.7 0 0 0 10 3.1V3a2 2 0 0 1 4 0v.1A1.7 1.7 0 0 0 15 4.6a1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 0 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></Icon>,
  logout:  () => <Icon><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></Icon>,
  copy:    () => <Icon><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></Icon>,
  qr:      () => <Icon><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><path d="M14 14h3v3"/><path d="M21 14v3"/><path d="M14 21h7"/><path d="M17 17h0.01"/></Icon>,
  refresh: () => <Icon><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10"/><path d="M20.5 15a9 9 0 0 1-14.9 3.4L1 14"/></Icon>,
  check:   () => <Icon sw={2.5}><path d="M5 13l4 4L19 7"/></Icon>,
  alert:   () => <Icon><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.7 3h16.94a2 2 0 0 0 1.7-3L13.7 3.86a2 2 0 0 0-3.4 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></Icon>,
  info:    () => <Icon><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></Icon>,
  download:() => <Icon><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></Icon>,
  external:() => <Icon><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></Icon>,
  edit:    () => <Icon><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4z"/></Icon>,
  x:       () => <Icon sw={2.2}><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></Icon>,
  arrow:   () => <Icon><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></Icon>,
  back:    () => <Icon><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></Icon>,
  search:  () => <Icon><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></Icon>,
  trash:   () => <Icon><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></Icon>,
  shield:  () => <Icon><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></Icon>,
  send:    () => <Icon><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></Icon>,
  menu:    () => <Icon><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></Icon>,

  // ── Platform / client icons ──────────────────────────────────────────
  // Android — silhouette робота (плоская заливка, узнаваемая силуэтка).
  android: () => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
      <path d="M17.6 9.48l1.32-2.28a.5.5 0 0 0-.86-.5L16.7 9.04A8.5 8.5 0 0 0 12 8c-1.7 0-3.3.4-4.7 1.04L5.94 6.7a.5.5 0 1 0-.86.5L6.4 9.48A7.4 7.4 0 0 0 2 16h20a7.4 7.4 0 0 0-4.4-6.52zM7.5 14.2a.95.95 0 1 1 0-1.9.95.95 0 0 1 0 1.9zm9 0a.95.95 0 1 1 0-1.9.95.95 0 0 1 0 1.9z"/>
    </svg>
  ),
  // iOS / Apple — каноничный силуэт яблока (узнаваем мгновенно).
  apple:   () => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
      <path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.45 4.08zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/>
    </svg>
  ),
  // V2Ray — клиент-прокси. У бренда нет публичного icon-mark, делаем узнаваемую «V» в круге.
  v2ray:   () => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <circle cx="12" cy="12" r="9.5" />
      <path d="M7.5 8l4.5 9 4.5-9" fill="none" />
    </svg>
  ),
  // Incy — клиент-прокси. У бренда тоже нет icon-mark, делаем «I» в скруглённом квадрате.
  incy:    () => (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <rect x="3" y="3" width="18" height="18" rx="5" />
      <line x1="12" y1="7.5" x2="12" y2="16.5" strokeWidth="2.2" />
      <line x1="9.5" y1="7.5" x2="14.5" y2="7.5" strokeWidth="2.2" />
      <line x1="9.5" y1="16.5" x2="14.5" y2="16.5" strokeWidth="2.2" />
    </svg>
  ),
};

// ── Logo (matches landing) ────────────────────────────────────────────
const Logo = ({ size = 26 }) => (
  <div style={{ display: "inline-flex", alignItems: "center", gap: 10, fontWeight: 700, fontSize: 15.5, letterSpacing: "-0.01em", color: "var(--ink)", whiteSpace: "nowrap" }}>
    <img
      src="/assets/logo.png"
      alt="Fortune VPN"
      style={{ width: size, height: size, borderRadius: 8, display: "block", filter: "drop-shadow(0 4px 12px rgba(46,125,245,.35))" }}
    />
    <span>Fortune VPN</span>
  </div>
);

// Map route → page title for the top bar.
const ROUTE_TITLES = {
  home: "Главная",
  keys: "Подписка",
  "keys-empty": "Подписка",
  "keys-checkout": "Оформление подписки",
  "buy-start": "Оформление подписки",
  redeem: "Ваучер",
  referral: "Друзья",
  billing: "Платежи и чеки",
  settings: "Настройки",
  "setup-v2ray":   "Инструкция · V2Ray",
  "setup-incy":    "Инструкция · Incy",
  "setup-android": "Инструкция · Android",
  "setup-ios":     "Инструкция · iOS",
};

// Claude Code-style panel-left иконка. Состояние различается заливкой левой колонки:
//   Sidebar открыт   → левая колонка ЗАЛИТА (sidebar присутствует)
//   Sidebar свёрнут  → колонка-контур (sidebar отсутствует / спрятан)
// Никаких стрелок — направление не врёт.
const SidebarCollapseIcon = ({ size = 18 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
    <rect x="3" y="3" width="18" height="18" rx="2.5" />
    {/* Заливка левой колонки = «sidebar сейчас виден» */}
    <rect x="3" y="3" width="6.5" height="18" rx="2.5" fill="currentColor" fillOpacity="0.22" stroke="none" />
    <path d="M9.5 3v18" />
  </svg>
);
const SidebarExpandIcon = ({ size = 18 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
    <rect x="3" y="3" width="18" height="18" rx="2.5" />
    {/* Без заливки = «sidebar спрятан» */}
    <path d="M9.5 3v18" />
  </svg>
);

// Mac → ⌘B, Win/Linux → Ctrl+B (для tooltip)
const SHORTCUT_LABEL = (() => {
  if (typeof navigator === "undefined") return "(Ctrl+B)";
  const isMac = /Mac|iPhone|iPad|iPod/i.test(navigator.platform || navigator.userAgent);
  return isMac ? "(⌘B)" : "(Ctrl+B)";
})();

// Burger / close icons inline so we don't depend on extra Icon definitions.
const BurgerIcon = ({ open }) => (
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    {open ? (
      <React.Fragment><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></React.Fragment>
    ) : (
      <React.Fragment><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></React.Fragment>
    )}
  </svg>
);

// ── Top bar — page title + user. На мобиле слева бургер для drawer.
const TopBar = ({ email, active }) => {
  const ua = window.useAppState ? window.useAppState() : window.appState;
  const userEmail = email || ua?.user?.email;
  const title = ROUTE_TITLES[active] || "Личный кабинет";
  const drawerOpen = !!ua?.sidebar?.drawerOpen;
  return (
  <div data-role="topbar" style={{
    height: 64, padding: "10px 24px",
    display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16,
    borderBottom: "1px solid var(--border)",
    background: "rgba(13,17,26,.92)", backdropFilter: "saturate(180%) blur(16px)",
    flexShrink: 0,
  }}>
    <div style={{ display: "flex", alignItems: "center", gap: 12, flex: 1, minWidth: 0 }}>
      {/* Burger button — visible only on mobile via CSS class */}
      <button
        className="lk-burger"
        onClick={() => drawerOpen ? window.actions.closeDrawer() : window.actions.openDrawer()}
        aria-label={drawerOpen ? "Закрыть меню" : "Открыть меню"}
        style={{
          width: 36, height: 36, borderRadius: 8,
          background: "transparent", border: "1px solid var(--border)",
          color: "var(--ink)", cursor: "pointer",
          display: "none", placeItems: "center", flexShrink: 0,
        }}
      >
        <BurgerIcon open={drawerOpen} />
      </button>
      <h1 style={{
        margin: 0, fontSize: 18, fontWeight: 700, letterSpacing: "-0.015em",
        color: "var(--ink)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
      }}>{title}</h1>
    </div>
    {userEmail ? (
      <div style={{ display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }}>
        <span className="lk-email" style={{ fontSize: 13.5, color: "var(--muted)", maxWidth: 220, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{userEmail}</span>
        <div style={{
          width: 32, height: 32, borderRadius: 99, background: "var(--panel)",
          border: "1px solid var(--border)", display: "grid", placeItems: "center",
          fontSize: 13, fontWeight: 700, color: "var(--accent-soft)",
        }}>{userEmail[0].toUpperCase()}</div>
      </div>
    ) : (
      <a className="btn btn-primary btn-sm" href="#/login" style={{ textDecoration: "none", flexShrink: 0 }}>Войти</a>
    )}
  </div>
  );
};

// ── Footer (mirrors landing) ─────────────────────────────────────────
const Footer = () => (
  <footer style={{
    borderTop: "1px solid var(--border)", padding: "48px 24px 28px",
    background: "#0A0E14", marginTop: 48,
  }}>
    <div style={{ maxWidth: 1100, margin: "0 auto" }}>
      <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr", gap: 48, paddingBottom: 36, borderBottom: "1px solid var(--border)" }}>
        <div>
          <Logo />
          <p style={{ color: "var(--muted)", fontSize: 14, maxWidth: 300, marginTop: 14, lineHeight: 1.6 }}>
            Премиум VPN без блокировок, тормозов и лишних настроек. Работает в России прямо сейчас.
          </p>
        </div>
        <FooterCol title="Продукт">
          <FooterLink href="https://fortunetavern.com/buy" external>Тарифы</FooterLink>
          <FooterLink href="https://fortunetavern.com/setup" external>Как настроить</FooterLink>
          <FooterLink href="https://fortunetavern.com/faq" external>FAQ</FooterLink>
        </FooterCol>
        <FooterCol title="Документы">
          <FooterLink href="https://fortunetavern.com/offer" external>Публичная оферта</FooterLink>
          <FooterLink href="https://fortunetavern.com/privacy" external>Политика конфиденциальности</FooterLink>
          <FooterLink href="https://fortunetavern.com/offer#s11" external>Возврат денежных средств</FooterLink>
        </FooterCol>
        <FooterCol title="Контакты">
          <FooterLink href="https://fortunetavern.com/contacts" external>Поддержка</FooterLink>
          <FooterLink href="mailto:support@fortunetavern.com">support@fortunetavern.com</FooterLink>
          <FooterLink href="https://t.me/FortuneVPNsupportbot" external>Telegram: @FortuneVPNsupportbot</FooterLink>
          <FooterLink href="https://t.me/fortune_tavern_vpn" external>Telegram-канал</FooterLink>
        </FooterCol>
      </div>
      <div style={{ paddingTop: 24, color: "#6A6A82", fontSize: 13 }}>
        © 2026 Fortune Tavern Limited. Все права защищены.
      </div>
    </div>
  </footer>
);

const FooterCol = ({ title, children }) => (
  <div>
    <h4 style={{ fontSize: 12, textTransform: "uppercase", letterSpacing: ".1em", color: "var(--muted)", fontWeight: 600, margin: "0 0 14px" }}>{title}</h4>
    <div style={{ display: "flex", flexDirection: "column" }}>{children}</div>
  </div>
);

const FooterLink = ({ href, external, children }) => (
  <a href={href} target={external ? "_blank" : undefined} rel={external ? "noopener" : undefined}
     style={{ color: "#C9C9DC", padding: "6px 0", fontSize: 14, textDecoration: "none" }}>
    {children}
  </a>
);

// ── Sidebar ────────────────────────────────────────────────────────────
const SoonBadge = () => (
  <span style={{
    marginLeft: "auto", fontSize: 10, fontWeight: 700, letterSpacing: "0.03em",
    padding: "2px 7px", borderRadius: 999,
    background: "rgba(46,168,255,.15)", color: "var(--accent-soft)",
  }}>скоро</span>
);

const SidebarItem = ({ icon: I, label, active, danger, soon, onClick, collapsed }) => (
  <div onClick={onClick} title={collapsed ? label : undefined} style={{
    display: "flex", alignItems: "center", gap: 12,
    padding: collapsed ? "10px 0" : "10px 14px",
    justifyContent: collapsed ? "center" : "flex-start",
    borderRadius: 10,
    background: active ? "rgba(46,168,255,.12)" : "transparent",
    color: active ? "var(--accent-soft)" : danger ? "var(--muted)" : "var(--ink)",
    fontSize: 14, fontWeight: active ? 600 : 500, cursor: "pointer",
    border: active ? "1px solid rgba(46,168,255,.18)" : "1px solid transparent",
  }}>
    <span style={{ display: "flex", color: active ? "var(--accent-soft)" : "var(--muted)" }}>
      <I />
    </span>
    {!collapsed && <span>{label}</span>}
    {!collapsed && soon && <SoonBadge />}
  </div>
);

// Контекстный CTA «Активировать код» — отдельно от основной нав.
// Визуально выделен (dashed border + gift-иконка), на свёрнутом sidebar — только иконка.
// Прячется, если у юзера уже активная подписка и нет ваучера для активации
//   (юзер всё ещё может попасть на /redeem через прямой URL или через empty-state).
const RedeemCTA = ({ active, collapsed, onClick }) => {
  const ua = window.useAppState ? window.useAppState() : window.appState;
  const hasActiveSub = ua?.entitlement?.status === "active";
  // Если подписка уже активна — CTA становится менее заметным (приглушённый).
  // Но не прячем совсем — юзер может получить ещё один ваучер (подарок, докупка).
  const muted = hasActiveSub;
  const margin = collapsed ? "0 0 14px" : "0 0 16px";

  if (collapsed) {
    return (
      <div style={{ margin, display: "flex", justifyContent: "center" }}>
        <button
          onClick={onClick}
          title="Активировать код"
          aria-label="Активировать код"
          style={{
            width: 40, height: 40, borderRadius: 10,
            background: active
              ? "rgba(46,168,255,.18)"
              : muted ? "transparent" : "rgba(46,168,255,.10)",
            border: `1.5px ${muted ? "dashed" : "solid"} ${active ? "rgba(46,168,255,.55)" : "rgba(46,168,255,.32)"}`,
            color: active ? "var(--accent-soft)" : muted ? "var(--muted)" : "var(--accent-soft)",
            cursor: "pointer", display: "grid", placeItems: "center",
          }}
        >
          <Icons.gift />
        </button>
      </div>
    );
  }

  return (
    <button
      onClick={onClick}
      style={{
        margin,
        width: "100%", display: "flex", alignItems: "center", gap: 10,
        padding: "10px 14px", borderRadius: 12,
        background: active
          ? "linear-gradient(135deg, rgba(46,125,245,.18), rgba(46,168,255,.10))"
          : muted ? "transparent" : "linear-gradient(135deg, rgba(46,125,245,.10), rgba(46,168,255,.05))",
        border: `1.5px ${muted && !active ? "dashed" : "solid"} ${active ? "rgba(46,168,255,.55)" : "rgba(46,168,255,.30)"}`,
        color: active ? "#FFF" : muted ? "var(--muted)" : "var(--accent-soft)",
        fontSize: 14, fontWeight: active ? 600 : 500,
        cursor: "pointer", textAlign: "left",
        boxShadow: active ? "0 6px 18px -8px rgba(46,168,255,.5)" : "none",
        transition: "background .15s, border-color .15s",
      }}
    >
      <span style={{ display: "flex" }}><Icons.gift /></span>
      <span>Активировать код</span>
    </button>
  );
};

// Small logo-icon-only (используется в свёрнутом sidebar). Кликабельно → лендинг.
const LogoIconOnly = () => (
  <img
    src="/assets/logo.png"
    alt="Fortune VPN"
    style={{ width: 28, height: 28, borderRadius: 8, display: "block", filter: "drop-shadow(0 4px 12px rgba(46,125,245,.35))" }}
  />
);

const Sidebar = ({ active = "home" }) => {
  const ua = window.useAppState ? window.useAppState() : window.appState;
  const collapsed = !!ua?.sidebar?.collapsed;
  const go = (r) => () => {
    if (window.actions) window.actions.closeDrawer();  // на мобиле закрыть drawer после клика
    if (window.navigate) window.navigate(r);
  };
  const toggle = () => window.actions && window.actions.toggleSidebar();
  const logout = () => {
    if (window.actions) window.actions.logout();
  };
  const width = collapsed ? 68 : 240;
  return (
  <div data-role="sidebar" style={{
    width, flexShrink: 0, transition: "width .2s ease",
    background: "var(--bg-2)", borderRight: "1px solid var(--border)",
    padding: collapsed ? "16px 10px" : "20px 14px",
    display: "flex", flexDirection: "column",
  }}>
    {/* Header: logo + toggle */}
    <div style={{
      display: "flex", alignItems: "center",
      justifyContent: collapsed ? "center" : "space-between",
      gap: 8, padding: collapsed ? 0 : "0 6px",
      marginBottom: 18,
    }}>
      {collapsed ? (
        <a href="/" title="На главную сайта"
           style={{ display: "inline-flex", textDecoration: "none", color: "inherit" }}>
          <LogoIconOnly />
        </a>
      ) : (
        <a href="/" title="На главную сайта"
           style={{ textDecoration: "none", color: "inherit", display: "inline-flex" }}>
          <Logo />
        </a>
      )}
      {!collapsed && (
        <button
          onClick={toggle}
          title={`Свернуть боковую панель  ${SHORTCUT_LABEL}`}
          aria-label="Свернуть боковую панель"
          style={{
            width: 32, height: 32, borderRadius: 8,
            background: "transparent", border: "1px solid var(--border)",
            color: "var(--muted)", cursor: "pointer",
            display: "grid", placeItems: "center", flexShrink: 0,
          }}
        >
          <SidebarCollapseIcon />
        </button>
      )}
    </div>

    {/* Развернуть-кнопка в свёрнутом виде — отдельной строкой под лого. Стрелка наружу. */}
    {collapsed && (
      <button
        onClick={toggle}
        title={`Развернуть боковую панель  ${SHORTCUT_LABEL}`}
        aria-label="Развернуть боковую панель"
        style={{
          width: 32, height: 32, borderRadius: 8, margin: "0 auto 12px",
          background: "transparent", border: "1px solid var(--border)",
          color: "var(--muted)", cursor: "pointer",
          display: "grid", placeItems: "center", flexShrink: 0,
        }}
      >
        <SidebarExpandIcon />
      </button>
    )}

    <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
      <SidebarItem icon={Icons.home}    label="Главная"           active={active === "home"}     onClick={go("home")}    collapsed={collapsed} />
      <SidebarItem icon={Icons.key}     label="Подписка"          active={active === "keys"}     onClick={go("keys")}    collapsed={collapsed} />
      <SidebarItem icon={Icons.users}   label="Друзья"            active={active === "referral"} onClick={go("referral")} collapsed={collapsed} />
    </div>

    {/* Группа: инструкции по клиентам подключения */}
    {!collapsed && (
      <div style={{
        marginTop: 18, marginBottom: 6, padding: "0 14px",
        fontSize: 10.5, fontWeight: 700, letterSpacing: "0.12em", textTransform: "uppercase",
        color: "var(--dim)",
      }}>Инструкции</div>
    )}
    {collapsed && <div style={{ height: 1, background: "var(--border)", margin: "14px 6px 8px" }} />}
    <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
      <SidebarItem icon={Icons.v2ray}   label="V2Ray"   active={active === "setup-v2ray"}   onClick={go("setup-v2ray")}   collapsed={collapsed} />
      <SidebarItem icon={Icons.incy}    label="Incy"    active={active === "setup-incy"}    onClick={go("setup-incy")}    collapsed={collapsed} />
      <SidebarItem icon={Icons.android} label="Android" active={active === "setup-android"} onClick={go("setup-android")} soon collapsed={collapsed} />
      <SidebarItem icon={Icons.apple}   label="iOS"     active={active === "setup-ios"}     onClick={go("setup-ios")}     soon collapsed={collapsed} />
    </div>

    <div style={{ marginTop: "auto", display: "flex", flexDirection: "column", gap: 2 }}>
      <div style={{ height: 1, background: "var(--border)", margin: "8px 6px" }} />
      <SidebarItem icon={Icons.settings} label="Настройки" active={active === "settings"} onClick={go("settings")} collapsed={collapsed} />
      <SidebarItem icon={Icons.logout}   label="Выйти" danger onClick={logout} collapsed={collapsed} />
    </div>
  </div>
  );
};

// ── Page shell (sidebar + topbar + scroll content). Без большого футера —
// маркетинговые ссылки живут на лендинге, дашборд — рабочее пространство.
const Shell = ({ active, children, email, screenLabel }) => {
  const ua = window.useAppState ? window.useAppState() : window.appState;
  const drawerOpen = !!ua?.sidebar?.drawerOpen;
  return (
  <div className="screen" data-screen-label={screenLabel} data-drawer-open={drawerOpen ? "true" : "false"}>
    <Sidebar active={active} />
    {/* Mobile backdrop: на десктопе скрыт через CSS, на мобиле появляется только когда drawerOpen */}
    {drawerOpen && (
      <div
        onClick={() => window.actions.closeDrawer()}
        className="lk-drawer-backdrop"
        aria-hidden="true"
      />
    )}
    <div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <TopBar email={email} active={active} />
      <div style={{ flex: 1, overflow: "auto" }}>
        <div data-role="content" style={{ padding: "32px 40px 48px" }}>
          <div style={{ maxWidth: 1100, margin: "0 auto" }}>
            {children}
          </div>
        </div>
        <ShellFooter />
      </div>
    </div>
  </div>
  );
};

// Тонкая полоска внизу: copyright + ссылка на поддержку. Один ряд, приглушённо.
const ShellFooter = () => (
  <div style={{
    padding: "16px 40px",
    borderTop: "1px solid var(--border)",
    display: "flex", alignItems: "center", justifyContent: "space-between",
    gap: 16, flexWrap: "wrap",
    fontSize: 12.5, color: "var(--dim)",
  }}>
    <span>© Fortune Tavern Limited</span>
    <div style={{ display: "flex", gap: 18, alignItems: "center" }}>
      <a href="https://t.me/FortuneVPNsupportbot" target="_blank" rel="noopener"
         style={{ color: "var(--accent-soft)", textDecoration: "none" }}>
        Поддержка
      </a>
      <a href="https://t.me/fortune_tavern_vpn" target="_blank" rel="noopener"
         style={{ color: "var(--muted)", textDecoration: "none" }}>
        ТГ-канал
      </a>
      <a href="/" style={{ color: "var(--muted)", textDecoration: "none" }}>
        На сайт
      </a>
    </div>
  </div>
);

// ── Eyebrow pill (chip + text + dot) ──────────────────────────────────
const EyebrowPill = ({ chip, text, kind = "ok" }) => (
  <div className={`pill ${kind === "warn" ? "warn" : kind === "off" ? "off" : ""}`}>
    <span className="chip">{chip}</span>
    <span>{text}</span>
    <span className="dot" />
  </div>
);

// ── Hero (Доступ) ────────────────────────────────────────────────────
// dateTone: 'ok' (gradient), 'warn' (orange), 'danger' (red)
const HeroLine = ({ label, dateLabel, dateTone = "ok", primaryAction = "Продлить", ghostAction = "Управлять" }) => {
  const dateColor = dateTone === "warn" ? "var(--warning)" : dateTone === "danger" ? "var(--danger)" : null;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
      <div style={{
        fontSize: "clamp(28px, 3.2vw, 38px)", fontWeight: 800,
        letterSpacing: "-0.035em", lineHeight: 1.05, color: "#FFF",
      }}>
        {label} —{" "}
        {dateColor
          ? <span style={{ color: dateColor }}>{dateLabel}</span>
          : <span className="grad-text">{dateLabel}</span>}
      </div>
      <div style={{ display: "flex", gap: 10 }}>
        <button className={`btn btn-primary ${dateTone === "danger" ? "btn-lg" : ""}`}>{primaryAction}</button>
        <button className="btn btn-ghost">{ghostAction}</button>
      </div>
    </div>
  );
};

const Hero = ({ pill, title, lines = [], note, children }) => (
  <div className="bg-glows" style={{
    position: "relative", padding: "8px 0 36px", marginBottom: 20,
  }}>
    <div style={{ position: "relative", display: "flex", flexDirection: "column", gap: 18 }}>
      {pill}
      {title && (
        <div style={{
          fontSize: "clamp(34px, 4.4vw, 44px)", fontWeight: 800,
          letterSpacing: "-0.04em", lineHeight: 1, color: "#FFF",
        }}>{title}</div>
      )}
      {lines.length > 0 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 22, marginTop: 6 }}>
          {lines.map((l, i) => <HeroLine key={i} {...l} />)}
        </div>
      )}
      {children}
      {note && <div style={{ fontSize: 13, color: "var(--dim)", marginTop: 4 }}>{note}</div>}
    </div>
  </div>
);

// ── Card (.ps remix) with mouse glow ───────────────────────────────────
const PsCard = ({ children, style, onClick }) => {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const r = ref.current.getBoundingClientRect();
    ref.current.style.setProperty("--mx", `${e.clientX - r.left}px`);
    ref.current.style.setProperty("--my", `${e.clientY - r.top}px`);
  };
  return (
    <div ref={ref} className="ps" onMouseMove={onMove} onClick={onClick} style={style}>
      {children}
    </div>
  );
};

const PsIcon = ({ icon: I }) => (
  <div className="ps-icon"><I /></div>
);

// ── Badge ─────────────────────────────────────────────────────────────
const Badge = ({ kind = "active", children }) => {
  const cls = {
    active: "badge-active", warn: "badge-warn", danger: "badge-danger", pending: "badge-pending",
  }[kind] || "badge-pending";
  return (
    <span className={`badge ${cls}`}><span className="b-dot" />{children}</span>
  );
};

// ── Section header inside content ─────────────────────────────────────
const SectionHeader = ({ eyebrow, title, badge, action }) => (
  <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 16, marginBottom: 18 }}>
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      {eyebrow && <div className="eyebrow">{eyebrow}</div>}
      <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
        <h2 style={{
          margin: 0, fontSize: "clamp(28px, 3vw, 36px)", fontWeight: 800,
          letterSpacing: "-0.035em", lineHeight: 1.05, color: "#FFF",
        }}>{title}</h2>
        {badge}
      </div>
    </div>
    {action}
  </div>
);

// ── Assumption note ───────────────────────────────────────────────────
const Assumption = ({ kind = "ASSUMPTION", children }) => (
  <div className="asm">
    <span className="asm-tag">{kind}</span>
    <span>{children}</span>
  </div>
);

// ── Modal shell (used inside artboards to mock M1–M6) ─────────────────
const ModalShell = ({ title, children, primary, primaryKind = "primary", ghost = "Отмена", onClose }) => (
  <div style={{
    position: "absolute", inset: 0, background: "rgba(13,17,26,.7)",
    backdropFilter: "blur(8px)", display: "grid", placeItems: "center", zIndex: 50,
  }}>
    <div style={{
      width: 480, background: "var(--bg-2)", border: "1px solid var(--border-strong)",
      borderRadius: 20, padding: 24, position: "relative",
      boxShadow: "0 30px 80px -20px rgba(0,0,0,.6)",
    }}>
      <button style={{
        position: "absolute", top: 18, right: 18, width: 32, height: 32, borderRadius: 8,
        background: "transparent", border: "1px solid var(--border)", color: "var(--muted)",
        display: "grid", placeItems: "center", cursor: "pointer",
      }} onClick={onClose}><Icons.x /></button>
      <h3 style={{ margin: "0 0 12px", fontSize: 22, fontWeight: 700, letterSpacing: "-0.02em", color: "#FFF", paddingRight: 36 }}>{title}</h3>
      <div style={{ fontSize: 14.5, color: "var(--muted)", lineHeight: 1.55 }}>{children}</div>
      <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 22 }}>
        <button className="btn btn-ghost">{ghost}</button>
        {primary && <button className={`btn ${primaryKind === "danger" ? "btn-danger" : "btn-primary"}`}>{primary}</button>}
      </div>
    </div>
  </div>
);

// ── Auth-only narrow shell ────────────────────────────────────────────
const AuthShell = ({ children, screenLabel }) => (
  <div className="screen bg-glows auth-screen" data-screen-label={screenLabel}
       style={{ display: "block", padding: 32, position: "relative", overflowY: "auto" }}>
    <div className="auth-shell-inner" style={{ position: "relative", zIndex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", paddingTop: 60, minHeight: "100%" }}>
      <div style={{ marginBottom: 32 }}><Logo size={32} /></div>
      <div className="auth-card" style={{
        width: "100%", maxWidth: 460, background: "linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.01))",
        border: "1px solid var(--border)", borderRadius: 20, padding: 32,
      }}>
        {children}
      </div>
      <div style={{ marginTop: 20, fontSize: 12.5, color: "var(--dim)" }}>
        © Fortune Tavern Limited
      </div>
    </div>
  </div>
);

// expose to other Babel files
Object.assign(window, {
  Icons, Icon, Logo, TopBar, Sidebar, SidebarItem, Shell, AuthShell,
  Footer, FooterCol, FooterLink,
  EyebrowPill, Hero, HeroLine, PsCard, PsIcon, Badge,
  SectionHeader, Assumption, ModalShell,
});
