import {
  AlertCircle,
  ArrowRight,
  BookOpen,
  Camera,
  CheckCircle2,
  ChevronDown,
  ChevronRight,
  Clock3,
  Coins,
  Compass,
  Copy,
  Crown,
  Gamepad2,
  GitFork,
  Heart,
  Loader2,
  LogIn,
  MessageCircle,
  Palette,
  Pencil,
  Plus,
  ScanLine,
  Search,
  Settings,
  Share2,
  SlidersHorizontal,
  Sparkles,
  Star,
  ThumbsUp,
  Ticket,
  UserRound,
  XCircle,
} from 'lucide-react';
import QRCode from 'qrcode';
import {
  type ComponentType,
  type CSSProperties,
  type PointerEvent,
  type ReactNode,
  Suspense,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import profileClockImage from '../../../media/profile/_Image (1).png';
import profileGamepadImage from '../../../media/profile/_Image (2).png';
import profileStillLifeImage from '../../../media/profile/_Image (3).png';
import profileCoinsImage from '../../../media/profile/_Image (4).png';
import profileGiftImage from '../../../media/profile/_Image (6).png';
import profileCommunityImage from '../../../media/profile/_Image (7).png';
import profileFeedbackImage from '../../../media/profile/_Image (8).png';
import profileMascotImage from '../../../media/profile/_Image (9).png';
import profilePointImage from '../../../media/profile/_Image.png';
import communityQqQrImage from '../../../media/social-media-group/qq.png';
import communityWechatQrImage from '../../../media/social-media-group/wechat.png';
import type { PublicUserSummary } from '../../../packages/shared/src/contracts/auth';
import type {
  ConfirmWechatProfileRechargeOrderResponse,
  CustomWorldLibraryEntry,
  PlatformBrowseHistoryEntry,
  ProfileDashboardCardKey,
  ProfileDashboardSummary,
  ProfilePlayedWorkSummary,
  ProfilePlayStatsResponse,
  ProfileRechargeCenterResponse,
  ProfileRechargeProduct,
  ProfileReferralInviteCenterResponse,
  ProfileSaveArchiveSummary,
  ProfileTaskCenterResponse,
  ProfileTaskItem,
  ProfileWalletLedgerResponse,
  RedeemProfileRewardCodeResponse,
  WechatMiniProgramPayParams,
  WechatMiniProgramVirtualPayParams,
  WechatNativePayment,
} from '../../../packages/shared/src/contracts/runtime';
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
import { buildPublicWorkDetailUrl } from '../../routing/appPageRoutes';
import { refreshStoredAccessToken } from '../../services/apiClient';
import type { AuthUser } from '../../services/authService';
import {
  getPublicAuthUserByCode,
  getPublicAuthUserById,
  updateAuthProfile,
} from '../../services/authService';
import { copyTextToClipboard } from '../../services/clipboard';
import {
  resolveProfileRechargeProductPaymentChannel,
  shouldShowRechargeEntry,
  WECHAT_H5_PAYMENT_CHANNEL,
  WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL,
  WECHAT_NATIVE_PAYMENT_CHANNEL,
} from '../../services/payment/paymentPlatform';
import { redirectToPaymentUrl } from '../../services/payment/paymentRedirect';
import {
  claimRpgProfileTaskReward,
  confirmWechatRpgProfileRechargeOrder,
  createRpgProfileRechargeOrder,
  getRpgProfileRechargeCenter,
  getRpgProfileReferralInviteCenter,
  getRpgProfileTasks,
  getRpgProfileWalletLedger,
  redeemRpgProfileReferralInviteCode,
  redeemRpgProfileRewardCode,
  watchWechatRpgProfileRechargeOrder,
} from '../../services/rpg-entry/rpgProfileClient';
import type { CustomWorldProfile } from '../../types';
import { useAuthUi } from '../auth/AuthUiContext';
import { LegalDocumentModal } from '../common/LegalDocumentModal';
import {
  getLegalDocument,
  ICP_RECORD_NUMBER,
  ICP_RECORD_URL,
  LEGAL_DOCUMENTS,
  type LegalDocumentId,
} from '../common/legalDocuments';
import {
  buildCenteredSquareImageCropRect,
  clampSquareImageCropRect,
  SquareImageCropModal,
  type SquareImageCropRect,
} from '../common/SquareImageCropModal';
import { CustomWorldCoverArtwork } from '../CustomWorldCoverArtwork';
import {
  canExposePublicWork,
  EDUTAINMENT_WORK_TAG,
  filterEdutainmentPublicWorks,
  filterGeneralPublicWorks,
  findPublicWorkForHistoryEntry,
  isEdutainmentEntryEnabled,
} from '../platform-entry/platformEdutainmentVisibility';
import { getInitialPlatformDesktopLayout } from '../platform-entry/platformEntryResponsive';
import { ResolvedAssetImage } from '../ResolvedAssetImage';
import { RpgEntryBrandLogo } from './RpgEntryBrandLogo';
import {
  buildPlatformPublicGalleryCardKey,
  buildPlatformWorldDisplayTags,
  describePlatformThemeLabel,
  formatPlatformWorkDisplayName,
  formatPlatformWorkDisplayTag,
  formatPlatformWorldTime,
  isBarkBattleGalleryEntry,
  isBigFishGalleryEntry,
  isEdutainmentGalleryEntry,
  isJumpHopGalleryEntry,
  isMatch3DGalleryEntry,
  isPuzzleGalleryEntry,
  isSquareHoleGalleryEntry,
  isVisualNovelGalleryEntry,
  isWoodenFishGalleryEntry,
  type PlatformPublicGalleryCard,
  type PlatformWorldCardLike,
  resolvePlatformPublicWorkCode,
  resolvePlatformWorkAuthorDisplayName,
  resolvePlatformWorldCoverImage,
  resolvePlatformWorldCoverSlides,
  resolvePlatformWorldFallbackCoverImage,
  resolvePlatformWorldLeadPortrait,
} from './rpgEntryWorldPresentation';

export type PlatformHomeTab =
  | 'home'
  | 'category'
  | 'create'
  | 'saves'
  | 'profile';
export interface RpgEntryHomeViewProps {
  activeTab: PlatformHomeTab;
  isDesktopLayout?: boolean;
  onTabChange: (tab: PlatformHomeTab) => void;
  hasSavedGame: boolean;
  savedSnapshot: HydratedSavedGameSnapshot | null;
  saveEntries: ProfileSaveArchiveSummary[];
  saveError: string | null;
  featuredEntries: PlatformPublicGalleryCard[];
  latestEntries: PlatformPublicGalleryCard[];
  myEntries: CustomWorldLibraryEntry<CustomWorldProfile>[];
  historyEntries: PlatformBrowseHistoryEntry[];
  profileDashboard: ProfileDashboardSummary | null;
  isLoadingPlatform: boolean;
  isLoadingDashboard: boolean;
  isResumingSaveWorldKey: string | null;
  platformError: string | null;
  dashboardError: string | null;
  onContinueGame: (snapshot?: HydratedSavedGameSnapshot | null) => void;
  onResumeSave: (entry: ProfileSaveArchiveSummary) => void;
  onOpenCreateWorld: () => void;
  onOpenCreateTypePicker: () => void;
  onOpenGalleryDetail: (entry: PlatformPublicGalleryCard) => void;
  onOpenChildMotionDemo?: () => void;
  onOpenBabyLoveDrawing?: () => void;
  onOpenRecommendGalleryDetail?: (entry: PlatformPublicGalleryCard) => void;
  recommendRuntimeContent?: ReactNode;
  activeRecommendEntryKey?: string | null;
  isStartingRecommendEntry?: boolean;
  isRecommendRuntimeReady?: boolean;
  recommendRuntimeError?: string | null;
  onSelectNextRecommendEntry?: (activeEntryKey?: string | null) => void;
  onSelectPreviousRecommendEntry?: (activeEntryKey?: string | null) => void;
  onLikeRecommendEntry?: (entry: PlatformPublicGalleryCard) => void;
  onRemixRecommendEntry?: (entry: PlatformPublicGalleryCard) => void;
  onOpenLibraryDetail: (
    entry: CustomWorldLibraryEntry<CustomWorldProfile>,
  ) => void;
  onDeleteLibraryEntry?: (
    entry: CustomWorldLibraryEntry<CustomWorldProfile>,
  ) => void;
  deletingLibraryEntryId?: string | null;
  onSearchPublicCode?: (keyword: string) => void | Promise<boolean | void>;
  isSearchingPublicCode?: boolean;
  onOpenProfileDashboardCard?: (cardKey: ProfileDashboardCardKey) => void;
  profilePlayStats?: ProfilePlayStatsResponse | null;
  isProfilePlayStatsOpen?: boolean;
  isProfilePlayStatsLoading?: boolean;
  profilePlayStatsError?: string | null;
  onCloseProfilePlayStats?: () => void;
  onOpenPlayedWork?: (work: ProfilePlayedWorkSummary) => void;
  onOpenFeedback?: () => void;
  onRechargeSuccess?: () => void | Promise<void>;
  profileTaskRefreshKey?: number;
  createTabContent?: ReactNode;
  draftTabContent?: ReactNode;
  hasUnreadDraftUpdate?: boolean;
}

const PANEL_SURFACE_CLASS = 'platform-surface platform-surface--soft';
const HERO_SURFACE_CLASS =
  'platform-surface platform-surface--hero platform-interactive-card min-w-0';
const MOBILE_PAGE_STAGE_CLASS =
  'platform-page-stage platform-remap-surface min-w-0 space-y-4 overflow-hidden pb-2';
const MOBILE_PROFILE_PAGE_STAGE_CLASS =
  'platform-remap-surface min-w-0 space-y-4 pb-2';
const MOBILE_RECOMMEND_PAGE_STAGE_CLASS =
  'platform-page-stage min-w-0 space-y-4 overflow-hidden pb-2';
const MOBILE_DISCOVER_PAGE_STAGE_CLASS =
  'platform-remap-surface min-w-0 space-y-4 overflow-hidden pb-2';
const DESKTOP_PAGE_STAGE_CLASS =
  'platform-page-stage platform-remap-surface min-w-0 space-y-5 pb-4';
const DESKTOP_DISCOVER_PAGE_STAGE_CLASS =
  'platform-remap-surface min-w-0 space-y-5 pb-4';
const PLATFORM_HOME_TABS: PlatformHomeTab[] = [
  'home',
  'category',
  'create',
  'saves',
  'profile',
];
const PROFILE_TASK_DAY_MS = 24 * 60 * 60 * 1000;
const PROFILE_TASK_BEIJING_OFFSET_MS = 8 * 60 * 60 * 1000;
const PROFILE_TASK_MIN_RESET_DELAY_MS = 1000;
const AVATAR_MAX_FILE_SIZE = 5 * 1024 * 1024;
const AVATAR_OUTPUT_SIZE = 256;
const AVATAR_ALLOWED_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp']);
const PLATFORM_WORK_COVER_CAROUSEL_INTERVAL_MS = 4200;
const PROFILE_INVITE_QUERY_KEYS = ['inviteCode', 'invite_code'] as const;
const RECOMMEND_ENTRY_SWIPE_THRESHOLD_PX = 36;
const RECOMMEND_ENTRY_COMMIT_ANIMATION_MS = 180;
const RECOMMEND_ENTRY_DRAG_LIMIT_PX = 160;
const WECHAT_JS_SDK_URL = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js';
const WECHAT_PAY_CONFIRM_RETRY_DELAYS_MS = [800, 1600, 3000] as const;
const WECHAT_NATIVE_PAY_QR_IMAGE_SIZE = 180;
const PROFILE_TASK_STATUS_PRIORITY_RANK: Record<
  ProfileTaskItem['status'],
  number
> = {
  claimable: 2,
  incomplete: 1,
  disabled: 0,
  claimed: -1,
};
const PROFILE_TASK_CARD_FALLBACK_REWARD_POINTS = 10;
const PROFILE_QR_SCAN_INTERVAL_MS = 360;

function selectProfileTaskCenterTasks(tasks: ProfileTaskItem[]) {
  return tasks
    .map((task, index) => ({ task, index }))
    .filter(
      ({ task }) =>
        task.status === 'claimable' || task.status === 'incomplete',
    )
    .sort(
      (left, right) =>
        PROFILE_TASK_STATUS_PRIORITY_RANK[right.task.status] -
          PROFILE_TASK_STATUS_PRIORITY_RANK[left.task.status] ||
        left.index - right.index,
    )
    .slice(0, 1)
    .map(({ task }) => task);
}

function selectProfileTaskCardTask(tasks: ProfileTaskItem[]) {
  return (
    selectProfileTaskCenterTasks(tasks)[0] ??
    tasks.find((task) => task.status === 'claimed') ??
    tasks.find((task) => task.status !== 'disabled') ??
    null
  );
}

function buildProfileTaskCardSummary(center: ProfileTaskCenterResponse | null) {
  const task = selectProfileTaskCardTask(center?.tasks ?? []);
  const threshold = Math.max(1, task?.threshold ?? 1);
  const progressCount = Math.min(task?.progressCount ?? 0, threshold);
  const rewardPoints =
    task?.rewardPoints ?? PROFILE_TASK_CARD_FALLBACK_REWARD_POINTS;

  return {
    progressCount,
    progressPercent: Math.round((progressCount / threshold) * 100),
    rewardPoints,
    threshold,
  };
}

function getDelayUntilNextProfileTaskReset(nowMs = Date.now()) {
  const shiftedNow = nowMs + PROFILE_TASK_BEIJING_OFFSET_MS;
  const nextDayStart =
    Math.floor(shiftedNow / PROFILE_TASK_DAY_MS) * PROFILE_TASK_DAY_MS +
    PROFILE_TASK_DAY_MS;
  const nextResetAt = nextDayStart - PROFILE_TASK_BEIJING_OFFSET_MS;
  return Math.max(PROFILE_TASK_MIN_RESET_DELAY_MS, nextResetAt - nowMs);
}

type ProfileReferralPanel = 'invite' | 'redeem' | 'community';
type ProfilePopupPanel = ProfileReferralPanel | 'saveArchives';
type BarcodeDetectorLike = {
  detect: (source: CanvasImageSource) => Promise<Array<{ rawValue?: string }>>;
};
type BarcodeDetectorConstructorLike = new (options?: {
  formats?: string[];
}) => BarcodeDetectorLike;
type RechargeTab = 'points' | 'membership';
type WechatMiniProgramPaymentStatus = 'success' | 'fail' | 'cancel';
type WechatPayResult = {
  requestId: string;
  orderId: string | null;
  status: WechatMiniProgramPaymentStatus;
  errorMessage: string | null;
};
type RechargePaymentResultKind = 'success' | 'pending' | 'cancel' | 'failed';
type RechargePaymentResult = {
  kind: RechargePaymentResultKind;
  title: string;
  message: string;
};
type WechatRechargeOrderConfirmationState = {
  orderId: string;
};
const WECHAT_PAY_RESULT_RECHECK_INTERVAL_MS = 250;
const WECHAT_PAY_RESULT_RECHECK_TIMEOUT_MS = 10000;

function getBarcodeDetectorConstructor(): BarcodeDetectorConstructorLike | null {
  const maybeDetector = (globalThis as unknown as {
    BarcodeDetector?: BarcodeDetectorConstructorLike;
  }).BarcodeDetector;
  return typeof maybeDetector === 'function' ? maybeDetector : null;
}
type NativeWechatPaymentState = WechatNativePayment & {
  orderId: string;
  isConfirming: boolean;
};
type DiscoverChannel =
  | 'recommend'
  | 'today'
  | 'category'
  | 'ranking'
  | 'edutainment';
type PlatformRankingTab = 'hot' | 'remix' | 'new' | 'like';
type PlatformCategoryKindFilter =
  | 'all'
  | 'puzzle'
  | 'match3d'
  | 'square-hole'
  | 'visual-novel'
  | 'bark-battle'
  | 'big-fish'
  | 'custom-world';
type PlatformCategorySortMode = 'composite' | 'latest' | 'play' | 'like';

const COMMUNITY_QR_CODES = [
  {
    label: '微信群',
    src: communityWechatQrImage,
    alt: '玩家社区微信群二维码',
  },
  {
    label: 'QQ群',
    src: communityQqQrImage,
    alt: '玩家社区 QQ 群二维码',
  },
] as const;

const DISCOVER_CHANNELS: Array<{
  id: DiscoverChannel;
  label: string;
}> = [
  { id: 'recommend', label: '推荐' },
  { id: 'today', label: '今日' },
  { id: 'category', label: '分类' },
  { id: 'ranking', label: '排行' },
];
const EDUTAINMENT_DISCOVER_CHANNEL = {
  id: 'edutainment',
  label: EDUTAINMENT_WORK_TAG,
} as const;
const PLATFORM_CATEGORY_KIND_FILTERS: Array<{
  id: PlatformCategoryKindFilter;
  label: string;
}> = [
  { id: 'all', label: '全部' },
  { id: 'puzzle', label: '拼图' },
  { id: 'match3d', label: '抓鹅' },
  { id: 'square-hole', label: '方洞' },
  { id: 'visual-novel', label: '视觉' },
  { id: 'bark-battle', label: '汪汪' },
  { id: 'big-fish', label: '大鱼' },
  { id: 'custom-world', label: 'RPG' },
];
const PLATFORM_CATEGORY_SORT_OPTIONS: Array<{
  id: PlatformCategorySortMode;
  label: string;
}> = [
  { id: 'composite', label: '综合' },
  { id: 'latest', label: '最新' },
  { id: 'play', label: '游玩' },
  { id: 'like', label: '点赞' },
];
const BABY_LOVE_DRAWING_DEFAULT_CARD = {
  title: '宝贝爱画',
  subtitle: '空白画板',
  summary: '挥动小手画一张画。',
};
const CHILD_MOTION_DEMO_DEFAULT_CARD = {
  title: '热身关卡',
  subtitle: '动作识别热身',
  summary: '站位、招手和左右手活动。',
};

const PLATFORM_RANKING_TABS: Array<{
  id: PlatformRankingTab;
  label: string;
  metricLabel: string;
  emptyText: string;
}> = [
  {
    id: 'hot',
    label: '热门榜',
    metricLabel: '游玩',
    emptyText: '公开广场暂时还没有热门作品。',
  },
  {
    id: 'remix',
    label: '改造榜',
    metricLabel: '改造',
    emptyText: '公开广场暂时还没有改造作品。',
  },
  {
    id: 'new',
    label: '新品榜',
    metricLabel: '近7日',
    emptyText: '近 7 日暂时还没有新品。',
  },
  {
    id: 'like',
    label: '点赞榜',
    metricLabel: '点赞',
    emptyText: '公开广场暂时还没有点赞作品。',
  },
];
function ResolvedAssetBackdrop({
  src,
  fallbackSrc,
  alt,
  className,
  ariaHidden = false,
}: {
  src?: string | null;
  fallbackSrc?: string | null;
  alt: string;
  className: string;
  ariaHidden?: boolean;
}) {
  return (
    <ResolvedAssetImage
      src={src}
      fallbackSrc={fallbackSrc}
      alt={alt}
      aria-hidden={ariaHidden}
      className={className}
    />
  );
}

function PlatformWorkCoverArtwork({
  entry,
  imageSrc,
  fallbackSrc,
  alt,
  className,
}: {
  entry: PlatformPublicGalleryCard;
  imageSrc?: string | null;
  fallbackSrc?: string | null;
  alt: string;
  className: string;
}) {
  if (isBarkBattleGalleryEntry(entry)) {
    return (
      <CustomWorldCoverArtwork
        imageSrc={imageSrc}
        fallbackImageSrc={fallbackSrc}
        title={entry.worldName}
        fallbackLabel="封面"
        renderMode={entry.coverRenderMode}
        characterImageSrcs={entry.coverCharacterImageSrcs}
        className={className}
      />
    );
  }

  return (
    <ResolvedAssetBackdrop
      src={imageSrc}
      fallbackSrc={fallbackSrc}
      alt={alt}
      className={className}
    />
  );
}

function SectionHeader({ title, detail }: { title: string; detail: string }) {
  return (
    <div className="mb-3">
      <div className="text-[10px] font-semibold tracking-[0.26em] text-[var(--platform-text-soft)]">
        {detail}
      </div>
      <div className="mt-1 text-base font-semibold text-[var(--platform-text-strong)]">
        {title}
      </div>
    </div>
  );
}

function PublicCodeSearchBar({
  value,
  onChange,
  onSubmit,
  isSearching,
  className,
}: {
  value: string;
  onChange: (value: string) => void;
  onSubmit: () => void;
  isSearching: boolean;
  className?: string;
}) {
  return (
    <div
      className={`platform-desktop-search flex min-w-0 items-center gap-3 px-4 py-3 text-[var(--platform-text-soft)] ${className ?? ''}`}
    >
      <Search className="h-4 w-4 shrink-0" />
      <input
        value={value}
        onChange={(event) => onChange(event.target.value)}
        onKeyDown={(event) => {
          if (event.key === 'Enter') {
            event.preventDefault();
            onSubmit();
          }
        }}
        placeholder="搜索作品号、名称、作者、描述"
        className="w-full min-w-0 bg-transparent text-sm text-[var(--platform-text-strong)] outline-none placeholder:text-[var(--platform-text-soft)]"
      />
      <button
        type="button"
        onClick={onSubmit}
        disabled={!value.trim() || isSearching}
        className="shrink-0 text-xs font-semibold text-[var(--platform-text-soft)] disabled:opacity-50"
      >
        {isSearching ? '搜索中' : '搜索'}
      </button>
    </div>
  );
}

function EmptyShelf({ text }: { text: string }) {
  return (
    <div
      className={`${PANEL_SURFACE_CLASS} min-w-0 rounded-[1.35rem] px-4 py-3 text-sm leading-6 text-[var(--platform-text-base)]`}
    >
      {text}
    </div>
  );
}

function SaveArchivePreview({
  entry,
  className,
}: {
  entry: ProfileSaveArchiveSummary;
  className: string;
}) {
  return (
    <div
      aria-hidden="true"
      className={`platform-remap-surface relative shrink-0 overflow-hidden rounded-[1.35rem] border border-white/12 bg-black/18 shadow-[var(--platform-desktop-hover-shadow)] ${className}`}
    >
      {entry.coverImageSrc ? (
        <ResolvedAssetBackdrop
          src={entry.coverImageSrc}
          alt=""
          className="absolute inset-0 h-full w-full object-cover"
        />
      ) : (
        <div className="absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(255,255,255,0.18),transparent_34%),linear-gradient(145deg,rgba(255,94,125,0.92),rgba(255,150,116,0.88))]" />
      )}
      <div className="absolute inset-0 bg-[var(--platform-card-overlay-soft)]" />
    </div>
  );
}

function WorldCard({
  entry,
  onClick,
  className,
  authorAvatarUrl,
  authorSummary,
  feedCardKey,
  enableCoverCarousel = false,
  isCoverCarouselActive = false,
  variant = 'standard',
}: {
  entry: PlatformPublicGalleryCard;
  onClick: () => void;
  className?: string;
  authorAvatarUrl?: string | null;
  authorSummary?: PublicUserSummary | null;
  feedCardKey?: string;
  enableCoverCarousel?: boolean;
  isCoverCarouselActive?: boolean;
  variant?: 'standard' | 'immersive';
}) {
  const fallbackCoverImage = resolvePlatformWorldCoverImage(entry);
  const fallbackAssetCoverImage = resolvePlatformWorldFallbackCoverImage(entry);
  const coverSlides = useMemo(() => {
    if (!enableCoverCarousel) {
      return fallbackCoverImage
        ? [
            {
              id: 'cover',
              imageSrc: fallbackCoverImage,
              label: entry.worldName,
            },
          ]
        : [];
    }

    return resolvePlatformWorldCoverSlides(entry);
  }, [enableCoverCarousel, entry, fallbackCoverImage]);
  const [activeCoverIndex, setActiveCoverIndex] = useState(0);
  const visibleCoverIndex = isCoverCarouselActive ? activeCoverIndex : 0;
  const activeCoverSlide =
    coverSlides[visibleCoverIndex] ?? coverSlides[0] ?? null;
  const coverImage = activeCoverSlide?.imageSrc ?? '';
  const displayName = formatPlatformWorkDisplayName(entry.worldName);
  const tags = buildPlatformWorldDisplayTags(entry, 3);
  const playCount = getPlatformWorldPlayCount(entry);
  const remixCount = getPlatformWorldRemixCount(entry);
  const likeCount = getPlatformWorldLikeCount(entry);
  const typeLabel = describePublicGalleryCardKind(entry);
  const authorName = resolvePlatformWorkAuthorDisplayName(
    entry,
    authorSummary,
  );
  const authorAvatarLabel = getPublicAuthorAvatarLabel(authorName);
  const normalizedAuthorAvatarUrl = authorAvatarUrl?.trim() ?? '';
  const cardLabel = `${entry.worldName}，${typeLabel}，${formatCompactCount(playCount)}游玩，${formatCompactCount(remixCount)}改造，${formatCompactCount(likeCount)}点赞`;
  const coverStats = [
    {
      label: '游玩',
      value: playCount,
      icon: Gamepad2,
    },
    {
      label: '改造',
      value: remixCount,
      icon: Pencil,
    },
    {
      label: '点赞',
      value: likeCount,
      icon: Heart,
    },
  ];

  useEffect(() => {
    setActiveCoverIndex(0);
  }, [entry.ownerUserId, entry.profileId, coverSlides.length]);

  useEffect(() => {
    if (!isCoverCarouselActive) {
      setActiveCoverIndex(0);
    }
  }, [isCoverCarouselActive]);

  useEffect(() => {
    if (!isCoverCarouselActive || coverSlides.length <= 1) {
      return undefined;
    }

    const timerId = window.setInterval(() => {
      setActiveCoverIndex((current) => (current + 1) % coverSlides.length);
    }, PLATFORM_WORK_COVER_CAROUSEL_INTERVAL_MS);

    return () => {
      window.clearInterval(timerId);
    };
  }, [coverSlides.length, isCoverCarouselActive]);

  return (
    <button
      type="button"
      onClick={onClick}
      aria-label={cardLabel}
      data-mobile-feed-card-key={feedCardKey}
      className={`platform-public-work-card ${variant === 'immersive' ? 'platform-public-work-card--immersive' : ''} platform-surface platform-interactive-card relative flex w-[min(21rem,88vw)] shrink-0 flex-col overflow-hidden p-0 text-left ${className ?? ''}`}
    >
      <div className="platform-public-work-card__cover relative aspect-video overflow-hidden">
        {coverImage ? (
          <PlatformWorkCoverArtwork
            entry={entry}
            imageSrc={coverImage}
            fallbackSrc={fallbackAssetCoverImage}
            alt={entry.worldName}
            className="absolute inset-0 h-full w-full object-cover"
          />
        ) : (
          <div className="absolute inset-0 bg-[radial-gradient(circle_at_18%_16%,rgba(255,255,255,0.28),transparent_30%),linear-gradient(135deg,rgba(255,118,117,0.42),rgba(89,164,255,0.34))]" />
        )}
        <div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(0,0,0,0.02),rgba(0,0,0,0.18))]" />
        <div className="platform-public-work-card__cover-stats">
          {coverStats.map(({ label, value, icon: Icon }) => (
            <span key={label} className="platform-public-work-card__cover-stat">
              <Icon
                className={`h-3.5 w-3.5 ${label === '点赞' ? 'fill-current' : ''}`}
                aria-hidden="true"
              />
              <span>{formatCompactCount(value)}</span>
            </span>
          ))}
        </div>
      </div>

      <div className="platform-public-work-card__body flex min-h-[7.25rem] flex-col gap-2 px-3.5 py-3">
        <div className="flex min-w-0 items-start justify-between gap-3">
          <div className="min-w-0 flex-1">
            <div className="line-clamp-1 break-words text-base font-black leading-tight text-[var(--platform-text-strong)]">
              {displayName}
            </div>
            <div className="mt-1 flex min-w-0 items-center gap-1.5">
              <span
                aria-hidden="true"
                className="platform-public-work-card__author-avatar"
              >
                {normalizedAuthorAvatarUrl ? (
                  <img
                    src={normalizedAuthorAvatarUrl}
                    alt=""
                    className="platform-public-work-card__author-avatar-image"
                  />
                ) : (
                  authorAvatarLabel
                )}
              </span>
              <span className="line-clamp-1 break-words text-[11px] font-semibold text-[var(--platform-text-soft)]">
                {authorName}
              </span>
            </div>
          </div>
          <span className="platform-public-work-card__kind shrink-0">
            {typeLabel}
          </span>
        </div>

        <div className="line-clamp-2 break-words text-xs leading-5 text-[color:color-mix(in_srgb,var(--platform-text-base)_88%,transparent)]">
          {entry.summaryText || entry.subtitle || '等待补充世界摘要。'}
        </div>

        <div className="mt-auto flex min-w-0 flex-wrap gap-1.5">
          {tags.length > 0 ? (
            tags.map((tag, index) => (
              <span
                key={`world-tag-${index}-${tag || 'empty'}`}
                className="platform-pill platform-pill--neutral max-w-full px-2.5"
              >
                <span className="truncate">{tag}</span>
              </span>
            ))
          ) : (
            <span className="platform-pill platform-pill--neutral px-2.5">
              {describePublicGalleryCardKind(entry)}
            </span>
          )}
        </div>
      </div>
    </button>
  );
}

function CreationLibraryCard({
  entry,
  onClick,
  onDelete,
  isDeleting = false,
}: {
  entry: CustomWorldLibraryEntry<CustomWorldProfile>;
  onClick: () => void;
  onDelete?: () => void;
  isDeleting?: boolean;
}) {
  const coverImage = resolvePlatformWorldCoverImage(entry);
  const leadPortrait = resolvePlatformWorldLeadPortrait(entry);
  const statusLabel = entry.visibility === 'published' ? '已发布' : '草稿';
  const metaLabel =
    entry.visibility === 'published'
      ? formatPlatformWorldTime(entry.publishedAt)
      : '仅自己可见';
  const primaryTag =
    buildPlatformWorldDisplayTags(entry, 1)[0] ??
    formatPlatformWorkDisplayTag(describePlatformThemeLabel(entry.themeMode));
  const displayName = formatPlatformWorkDisplayName(entry.worldName);
  const summaryText =
    entry.summaryText || entry.subtitle || '继续补完这个世界的设定与游玩入口。';

  return (
    <button
      type="button"
      onClick={onClick}
      className="platform-surface platform-interactive-card relative flex min-h-[13rem] w-full min-w-0 flex-col overflow-hidden px-3 py-3 text-left sm:min-h-[14rem] sm:px-3.5 sm:py-3.5"
    >
      {coverImage ? (
        <ResolvedAssetBackdrop
          src={coverImage}
          alt={entry.worldName}
          className="absolute inset-0 h-full w-full object-cover opacity-38"
        />
      ) : null}
      {leadPortrait ? (
        <ResolvedAssetImage
          src={leadPortrait}
          alt=""
          aria-hidden="true"
          className="absolute bottom-1.5 right-1.5 h-16 w-16 object-contain opacity-24 sm:h-20 sm:w-20"
        />
      ) : null}
      <div className="absolute inset-0 bg-[var(--platform-card-overlay-strong)]" />
      {onDelete ? (
        <button
          type="button"
          onClick={(event) => {
            event.stopPropagation();
            onDelete();
          }}
          disabled={isDeleting}
          className="platform-button platform-button--danger absolute right-2 top-2 z-20 min-h-0 rounded-full px-2.5 py-1 text-[10px] disabled:cursor-not-allowed disabled:opacity-60"
        >
          {isDeleting ? '删除中' : '删除'}
        </button>
      ) : null}
      <div className="relative z-10 flex h-full min-w-0 flex-col">
        <div className="flex min-w-0 flex-wrap items-center gap-1.5">
          <span
            className={`inline-flex items-center rounded-full border px-2 py-1 text-[10px] font-semibold tracking-[0.12em] ${
              entry.visibility === 'published'
                ? 'border-emerald-300/25 bg-emerald-500/12 text-emerald-50'
                : 'border-amber-300/25 bg-amber-500/12 text-amber-50'
            }`}
          >
            {statusLabel}
          </span>
          <span className="inline-flex min-w-0 max-w-full items-center rounded-full border border-white/12 bg-black/18 px-2 py-1 text-[10px] font-medium text-[var(--platform-text-base)]">
            <span className="truncate">{metaLabel}</span>
          </span>
        </div>

        <div className="mt-auto min-w-0">
          <div className="line-clamp-2 break-words text-base font-black leading-[1.15] text-[var(--platform-text-strong)] sm:text-[1.12rem]">
            {displayName}
          </div>
          {entry.subtitle ? (
            <div className="mt-1 line-clamp-1 break-words text-[11px] tracking-[0.08em] text-[color:color-mix(in_srgb,var(--platform-text-base)_84%,transparent)]">
              {entry.subtitle}
            </div>
          ) : null}
          <div className="mt-2 line-clamp-3 break-words text-[11px] leading-5 text-[color:color-mix(in_srgb,var(--platform-text-base)_88%,transparent)] sm:text-xs">
            {summaryText}
          </div>
          <div className="mt-3 flex flex-wrap items-center gap-1.5">
            <span className="inline-flex min-w-0 max-w-full items-center rounded-full border border-white/12 bg-black/18 px-2 py-1 text-[10px] font-semibold tracking-[0.1em] text-[color:color-mix(in_srgb,var(--platform-text-strong)_90%,transparent)]">
              <span className="truncate">{primaryTag}</span>
            </span>
            <span className="inline-flex items-center gap-1 text-[11px] font-semibold text-[var(--platform-text-base)]">
              <span>
                {entry.visibility === 'published' ? '进入世界' : '继续创作'}
              </span>
              <ArrowRight className="h-3.5 w-3.5 shrink-0" />
            </span>
          </div>
        </div>
      </div>
    </button>
  );
}

function RecommendRuntimePreviewCard({
  entry,
  position,
}: {
  entry: PlatformPublicGalleryCard;
  position: 'previous' | 'next';
}) {
  const coverImage = resolvePlatformWorldCoverImage(entry);
  const displayName = formatPlatformWorkDisplayName(entry.worldName);
  const typeLabel = describePublicGalleryCardKind(entry);

  return (
    <div
      className="platform-recommend-runtime-preview"
      aria-hidden="true"
      data-preview-position={position}
    >
      {coverImage ? (
        <PlatformWorkCoverArtwork
          entry={entry}
          imageSrc={coverImage}
          alt=""
          className="absolute inset-0 h-full w-full object-cover"
        />
      ) : (
        <div className="absolute inset-0 bg-[radial-gradient(circle_at_18%_16%,rgba(255,255,255,0.28),transparent_30%),linear-gradient(135deg,rgba(255,118,117,0.42),rgba(89,164,255,0.34))]" />
      )}
      <div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(0,0,0,0.08),rgba(0,0,0,0.42))]" />
      <div className="platform-recommend-runtime-preview__body">
        <span className="platform-public-work-card__kind">{typeLabel}</span>
        <span className="platform-recommend-runtime-preview__title">
          {displayName}
        </span>
      </div>
    </div>
  );
}

function RecommendRuntimeCover({
  entry,
  className = '',
}: {
  entry: PlatformPublicGalleryCard;
  className?: string;
}) {
  const coverImage = resolvePlatformWorldCoverImage(entry);
  const fallbackCoverImage = resolvePlatformWorldFallbackCoverImage(entry);

  return (
    <div
      className={`platform-recommend-runtime-cover ${className}`}
      aria-hidden="true"
    >
      {coverImage || fallbackCoverImage ? (
        <PlatformWorkCoverArtwork
          entry={entry}
          imageSrc={coverImage}
          fallbackSrc={fallbackCoverImage}
          alt=""
          className="absolute inset-0 h-full w-full object-cover"
        />
      ) : (
        <div className="absolute inset-0 bg-[radial-gradient(circle_at_22%_18%,rgba(255,255,255,0.28),transparent_30%),linear-gradient(135deg,rgba(255,118,117,0.42),rgba(89,164,255,0.34))]" />
      )}
      <div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(0,0,0,0.05),rgba(0,0,0,0.34))]" />
    </div>
  );
}

function RecommendRuntimeMountedProbe({
  onMounted,
}: {
  onMounted: () => void;
}) {
  useEffect(() => {
    const animationFrameId = window.requestAnimationFrame(onMounted);
    return () => window.cancelAnimationFrame(animationFrameId);
  }, [onMounted]);

  return null;
}

function RecommendRuntimeVisual({
  entry,
  runtimeContent,
  isStarting,
  isRuntimeReady,
}: {
  entry: PlatformPublicGalleryCard;
  runtimeContent?: ReactNode;
  isStarting: boolean;
  isRuntimeReady: boolean;
}) {
  const [isRuntimeMounted, setIsRuntimeMounted] = useState(false);
  const activeEntryKey = buildPublicGalleryCardKey(entry);
  const previousEntryKeyRef = useRef(activeEntryKey);

  useEffect(() => {
    if (previousEntryKeyRef.current === activeEntryKey) {
      return;
    }
    previousEntryKeyRef.current = activeEntryKey;
    setIsRuntimeMounted((currentValue) => {
      // 中文注释：拼图推荐流“下一关”会在同一个 run 内切到相似作品；
      // 此时只更新作品信息和分享基准，不应重显封面造成运行态闪跳。
      if (currentValue && !isStarting && isRuntimeReady) {
        return currentValue;
      }
      return false;
    });
  }, [activeEntryKey, isRuntimeReady, isStarting]);

  const handleRuntimeMounted = useCallback(() => {
    if (!isStarting && isRuntimeReady) {
      setIsRuntimeMounted(true);
    }
  }, [isRuntimeReady, isStarting]);

  const shouldShowCover =
    !runtimeContent || isStarting || !isRuntimeReady || !isRuntimeMounted;

  return (
    <div className="platform-recommend-runtime-visual">
      {runtimeContent ? (
        <Suspense fallback={null}>
          <div
            className="platform-recommend-runtime-viewport"
            aria-hidden={shouldShowCover}
          >
            {runtimeContent}
          </div>
          <RecommendRuntimeMountedProbe
            key={activeEntryKey}
            onMounted={handleRuntimeMounted}
          />
        </Suspense>
      ) : null}
      <RecommendRuntimeCover
        entry={entry}
        className={
          shouldShowCover ? '' : 'platform-recommend-runtime-cover--hidden'
        }
      />
    </div>
  );
}

function RecommendSwipeCard({
  entry,
  authorAvatarUrl,
  authorSummary,
  isActive,
  visual,
  shareState,
  onDragPointerDown,
  onDragPointerMove,
  onDragPointerUp,
  onDragPointerCancel,
  onLike,
  onShare,
  onRemix,
}: {
  entry: PlatformPublicGalleryCard;
  authorAvatarUrl?: string | null;
  authorSummary?: PublicUserSummary | null;
  isActive: boolean;
  visual: ReactNode;
  shareState?: 'idle' | 'copied' | 'failed';
  onDragPointerDown?: (event: PointerEvent<HTMLElement>) => void;
  onDragPointerMove?: (event: PointerEvent<HTMLElement>) => void;
  onDragPointerUp?: (event: PointerEvent<HTMLElement>) => void;
  onDragPointerCancel?: (event: PointerEvent<HTMLElement>) => void;
  onLike?: () => void;
  onShare?: () => void;
  onRemix?: () => void;
}) {
  return (
    <div
      className={`platform-recommend-swipe-card ${isActive ? 'platform-recommend-swipe-card--active' : 'platform-recommend-swipe-card--preview'}`}
      data-active={isActive ? 'true' : 'false'}
    >
      <div className="platform-recommend-swipe-card__visual">{visual}</div>
      <div
        className="platform-recommend-swipe-card__meta"
        data-recommend-swipe-zone={isActive ? 'true' : 'false'}
      >
        <RecommendRuntimeMeta
          entry={entry}
          authorAvatarUrl={authorAvatarUrl}
          authorSummary={authorSummary}
          isActive={isActive}
          shareState={shareState}
          onDragPointerDown={onDragPointerDown}
          onDragPointerMove={onDragPointerMove}
          onDragPointerUp={onDragPointerUp}
          onDragPointerCancel={onDragPointerCancel}
          onLike={onLike}
          onShare={onShare}
          onRemix={onRemix}
        />
      </div>
    </div>
  );
}

function RecommendRuntimeMeta({
  entry,
  authorAvatarUrl,
  authorSummary,
  onDragPointerDown,
  onDragPointerMove,
  onDragPointerUp,
  onDragPointerCancel,
  shareState = 'idle',
  onLike,
  onShare,
  onRemix,
  isActive = true,
}: {
  entry: PlatformPublicGalleryCard;
  authorAvatarUrl?: string | null;
  authorSummary?: PublicUserSummary | null;
  onDragPointerDown?: (event: PointerEvent<HTMLElement>) => void;
  onDragPointerMove?: (event: PointerEvent<HTMLElement>) => void;
  onDragPointerUp?: (event: PointerEvent<HTMLElement>) => void;
  onDragPointerCancel?: (event: PointerEvent<HTMLElement>) => void;
  shareState?: 'idle' | 'copied' | 'failed';
  onLike?: () => void;
  onShare?: () => void;
  onRemix?: () => void;
  isActive?: boolean;
}) {
  const likeCount = getPlatformWorldLikeCount(entry);
  const remixCount = getPlatformWorldRemixCount(entry);
  const authorName = resolvePlatformWorkAuthorDisplayName(
    entry,
    authorSummary,
  );
  const authorAvatarLabel = getPublicAuthorAvatarLabel(authorName);
  const normalizedAuthorAvatarUrl = authorAvatarUrl?.trim() ?? '';
  const displayName = formatPlatformWorkDisplayName(entry.worldName);
  const stopActionPointer = (event: PointerEvent<HTMLButtonElement>) => {
    event.stopPropagation();
  };

  return (
    <section
      className={`platform-recommend-work-meta ${
        isActive
          ? 'platform-recommend-work-meta--active'
          : 'platform-recommend-work-meta--preview'
      }`}
      aria-label={`${entry.worldName} 作品信息`}
      aria-hidden={!isActive}
      data-active={isActive ? 'true' : 'false'}
      onPointerDown={(event) => {
        onDragPointerDown?.(event);
      }}
      onPointerMove={onDragPointerMove}
      onPointerUp={onDragPointerUp}
      onPointerCancel={onDragPointerCancel}
    >
      <div className="platform-recommend-work-meta__row">
        <div className="platform-recommend-work-meta__identity">
          <span
            className="platform-recommend-work-meta__avatar"
            aria-hidden="true"
          >
            {normalizedAuthorAvatarUrl ? (
              <img
                src={normalizedAuthorAvatarUrl}
                alt=""
                className="h-full w-full rounded-full object-cover"
              />
            ) : (
              authorAvatarLabel
            )}
          </span>
          <span className="platform-recommend-work-meta__text">
            <span className="platform-recommend-work-meta__author">
              {authorName}
            </span>
            <span className="platform-recommend-work-meta__title">
              {displayName}
            </span>
          </span>
        </div>
        <div className="platform-recommend-work-meta__actions">
          <button
            type="button"
            className="platform-recommend-work-meta__action platform-recommend-work-meta__action--icon platform-recommend-work-meta__action--like"
            onPointerDown={stopActionPointer}
            onClick={(event) => {
              event.stopPropagation();
              onLike?.();
            }}
            disabled={!isActive || !onLike}
            aria-label={`点赞 ${formatCompactCount(likeCount)}`}
            title="点赞"
          >
            <ThumbsUp className="h-5 w-5" aria-hidden="true" />
          </button>
          <span
            className="platform-recommend-work-meta__like-count"
            aria-label={`${formatCompactCount(likeCount)} 个赞`}
          >
            {formatCompactCount(likeCount)}
          </span>
          <button
            type="button"
            className="platform-recommend-work-meta__action platform-recommend-work-meta__action--icon"
            onPointerDown={stopActionPointer}
            onClick={(event) => {
              event.stopPropagation();
              onShare?.();
            }}
            disabled={!isActive || !onShare}
            aria-label={
              shareState === 'copied'
                ? '分享内容已复制'
                : shareState === 'failed'
                  ? '分享内容复制失败'
                  : '分享'
            }
            title="分享"
          >
            <Share2 className="h-5 w-5" aria-hidden="true" />
          </button>
          <button
            type="button"
            className="platform-recommend-work-meta__action platform-recommend-work-meta__action--icon platform-recommend-work-meta__action--remix"
            onPointerDown={stopActionPointer}
            onClick={(event) => {
              event.stopPropagation();
              onRemix?.();
            }}
            disabled={!isActive || !onRemix}
            aria-label={`改造 ${formatCompactCount(remixCount)}`}
            title="改造"
          >
            <GitFork className="h-5 w-5" aria-hidden="true" />
          </button>
        </div>
      </div>
    </section>
  );
}

function SaveArchiveCard({
  entry,
  onClick,
  loading = false,
}: {
  entry: ProfileSaveArchiveSummary;
  onClick: () => void;
  loading?: boolean;
}) {
  const summaryText =
    entry.summaryText || entry.subtitle || '继续推进上一次保存的故事。';
  const displayName = formatPlatformWorkDisplayName(entry.worldName);

  return (
    <button
      type="button"
      onClick={onClick}
      disabled={loading}
      className={`platform-surface platform-surface--soft platform-interactive-card relative flex min-h-[13rem] w-full overflow-hidden p-3.5 text-left sm:min-h-[12.5rem] sm:p-4 ${loading ? 'opacity-80' : ''}`}
    >
      <div className="absolute inset-0 bg-[var(--platform-card-overlay-deep)]" />
      <div className="relative z-10 flex h-full w-full flex-col gap-3">
        <div className="flex flex-wrap justify-end gap-2">
          <span className="rounded-full border border-white/10 bg-black/18 px-2.5 py-1 text-[11px] font-medium text-[var(--platform-text-base)]">
            {loading ? '恢复中' : formatSnapshotTime(entry.lastPlayedAt)}
          </span>
        </div>
        <div className="flex min-w-0 flex-1 items-stretch gap-3 sm:gap-4">
          <div className="min-w-0 flex-1">
            <div className="line-clamp-2 break-words text-[1.35rem] font-black leading-tight text-[var(--platform-text-strong)] sm:text-2xl">
              {displayName}
            </div>
            {entry.subtitle ? (
              <div className="mt-1 line-clamp-2 break-words text-sm font-semibold text-[var(--platform-text-base)]">
                {entry.subtitle}
              </div>
            ) : null}
            <div className="mt-2 line-clamp-3 break-words text-xs leading-5 text-[var(--platform-text-soft)] sm:text-sm">
              {summaryText}
            </div>
            <div className="mt-4 inline-flex items-center gap-1.5 text-xs font-semibold text-zinc-200">
              <span>{loading ? '正在恢复' : '继续游玩'}</span>
              <ArrowRight className="h-3.5 w-3.5 shrink-0" />
            </div>
          </div>
          <SaveArchivePreview
            entry={entry}
            className="aspect-square w-[6.5rem] self-start sm:w-[7.5rem]"
          />
        </div>
      </div>
    </button>
  );
}

function PlatformTabButton({
  active,
  label,
  icon: Icon,
  onClick,
  emphasized = false,
  showDot = false,
  disabled = false,
}: {
  active: boolean;
  label: string;
  icon: ComponentType<{ className?: string }>;
  onClick: () => void;
  emphasized?: boolean;
  showDot?: boolean;
  disabled?: boolean;
}) {
  const ariaLabel = showDot ? `${label}，有新草稿` : label;

  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      aria-label={ariaLabel}
      className={`platform-bottom-nav__button ${emphasized ? 'platform-bottom-nav__button--primary' : ''} ${active ? 'platform-bottom-nav__button--active' : ''} disabled:cursor-not-allowed disabled:opacity-55`}
    >
      <span className="platform-bottom-nav__button-content">
        <span
          className={`platform-bottom-nav__icon-shell ${emphasized ? 'platform-bottom-nav__primary-action' : ''}`}
        >
          <Icon className="platform-bottom-nav__icon" />
          {showDot ? (
            <span aria-hidden="true" className="platform-nav-unread-dot" />
          ) : null}
        </span>
        <span className="platform-bottom-nav__label">{label}</span>
        {active ? (
          <span
            aria-hidden="true"
            className="platform-bottom-nav__active-mark"
          />
        ) : null}
      </span>
    </button>
  );
}

function DesktopTabButton({
  active,
  label,
  icon: Icon,
  onClick,
  emphasized = false,
  showDot = false,
  disabled = false,
}: {
  active: boolean;
  label: string;
  icon: ComponentType<{ className?: string }>;
  onClick: () => void;
  emphasized?: boolean;
  showDot?: boolean;
  disabled?: boolean;
}) {
  const ariaLabel = showDot ? `${label}，有新草稿` : label;

  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      aria-label={ariaLabel}
      className={`platform-desktop-rail__button ${emphasized ? 'platform-desktop-rail__button--primary' : ''} ${active ? 'platform-desktop-rail__button--active' : ''} disabled:cursor-not-allowed disabled:opacity-55`}
    >
      <span className="platform-desktop-rail__icon-shell">
        <Icon className="platform-desktop-rail__icon h-[1.1rem] w-[1.1rem]" />
        {showDot ? (
          <span aria-hidden="true" className="platform-nav-unread-dot" />
        ) : null}
      </span>
      <span className="platform-desktop-rail__label text-[11px] font-semibold tracking-[0.2em]">
        {label}
      </span>
    </button>
  );
}

function PlatformTabPanel({
  tab,
  activeTab,
  children,
}: {
  tab: PlatformHomeTab;
  activeTab: PlatformHomeTab;
  children: ReactNode;
}) {
  const active = activeTab === tab;

  // 主 Tab 保持挂载，只切换可见性，避免重页面卸载重建造成首帧闪烁。
  return (
    <section
      id={`platform-tab-panel-${tab}`}
      aria-hidden={!active}
      className={`platform-tab-panel ${active ? 'platform-tab-panel--active' : 'platform-tab-panel--hidden'}`}
    >
      {children}
    </section>
  );
}

function DesktopTrendingItem({
  entry,
  rank,
  onClick,
}: {
  entry: PlatformPublicGalleryCard;
  rank: number;
  onClick: () => void;
}) {
  const coverImage = resolvePlatformWorldCoverImage(entry);
  const displayName = formatPlatformWorkDisplayName(entry.worldName);
  const tags = buildPlatformWorldDisplayTags(entry, 2);

  return (
    <button
      type="button"
      onClick={onClick}
      className="platform-desktop-trending-item flex items-center gap-4 px-4 py-4 text-left"
    >
      <div className="relative h-[5.5rem] w-[4.3rem] shrink-0 overflow-hidden rounded-[1rem] border border-[var(--platform-subpanel-border)] bg-[rgba(255,255,255,0.66)]">
        {coverImage ? (
          <PlatformWorkCoverArtwork
            entry={entry}
            imageSrc={coverImage}
            alt={entry.worldName}
            className="h-full w-full object-cover"
          />
        ) : null}
        <div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(255,255,255,0.04),rgba(91,24,46,0.26))]" />
      </div>

      <div className="min-w-0 flex-1">
        <div className="flex items-center gap-2 text-[10px] tracking-[0.18em] text-[var(--platform-text-soft)]">
          <span>{`${rank}`.padStart(2, '0')}</span>
          <span className="truncate">
            {describePublicGalleryCardKind(entry)}
          </span>
        </div>
        <div className="mt-2 line-clamp-1 text-lg font-semibold text-[var(--platform-text-strong)]">
          {displayName}
        </div>
        <div className="mt-1 line-clamp-2 text-sm leading-6 text-[color:color-mix(in_srgb,var(--platform-text-base)_86%,transparent)]">
          {entry.summaryText || entry.subtitle || '等待补充世界摘要。'}
        </div>
        <div className="mt-3 flex flex-wrap gap-2">
          {tags.length > 0 ? (
            tags.map((tag, index) => (
              <span
                key={`${entry.profileId}-trend-tag-${index}-${tag}`}
                className="platform-pill platform-pill--neutral px-2.5"
              >
                {tag}
              </span>
            ))
          ) : (
            <span className="platform-pill platform-pill--neutral px-2.5">
              {isBigFishGalleryEntry(entry)
                ? '大鱼'
                : isPuzzleGalleryEntry(entry)
                  ? '拼图'
                  : isEdutainmentGalleryEntry(entry)
                    ? entry.templateName
                    : describePublicGalleryCardKind(entry)}
            </span>
          )}
        </div>
      </div>

      <ChevronRight className="h-4 w-4 shrink-0 text-[var(--platform-text-soft)]" />
    </button>
  );
}

function PlatformRankingItem({
  entry,
  rank,
  metricLabel,
  metricValue,
  onClick,
}: {
  entry: PlatformPublicGalleryCard;
  rank: number;
  metricLabel: string;
  metricValue: number;
  onClick: () => void;
}) {
  const coverImage = resolvePlatformWorldCoverImage(entry);
  const displayName = formatPlatformWorkDisplayName(entry.worldName);
  const tags = buildPlatformWorldDisplayTags(entry, 2);
  const actionLabel =
    isPuzzleGalleryEntry(entry) || isVisualNovelGalleryEntry(entry)
      ? '试玩'
      : '进入';

  return (
    <button
      type="button"
      onClick={onClick}
      className="platform-ranking-item w-full text-left"
    >
      <div className="platform-ranking-item__rank">{rank}</div>
      <div className="platform-ranking-item__cover">
        {coverImage ? (
          <PlatformWorkCoverArtwork
            entry={entry}
            imageSrc={coverImage}
            alt={entry.worldName}
            className="h-full w-full object-cover"
          />
        ) : (
          <div className="h-full w-full bg-[radial-gradient(circle_at_24%_18%,rgba(255,255,255,0.24),transparent_30%),linear-gradient(135deg,rgba(255,118,117,0.42),rgba(89,164,255,0.34))]" />
        )}
      </div>
      <div className="min-w-0 flex-1">
        <div className="line-clamp-1 break-words text-base font-black leading-tight text-[var(--platform-text-strong)]">
          {displayName}
        </div>
        <div className="mt-1 flex min-w-0 flex-wrap items-center gap-x-1.5 gap-y-1 text-xs font-semibold text-[var(--platform-text-soft)]">
          <span className="text-[var(--platform-warm-text)]">
            {formatCompactCount(metricValue)}
          </span>
          <span>{metricLabel}</span>
          <span>·</span>
          <span>{describePublicGalleryCardKind(entry)}</span>
        </div>
        <div className="platform-ranking-item__tags">
          {tags.map((tag, index) => (
            <span key={`${entry.profileId}-ranking-tag-${index}-${tag}`}>
              {tag}
            </span>
          ))}
        </div>
      </div>
      <span className="platform-ranking-item__action">{actionLabel}</span>
    </button>
  );
}

function PlatformCategoryGameItem({
  entry,
  categoryTag,
  onClick,
}: {
  entry: PlatformPublicGalleryCard;
  categoryTag: string;
  onClick: () => void;
}) {
  const coverImage = resolvePlatformWorldCoverImage(entry);
  const displayName = formatPlatformWorkDisplayName(entry.worldName);
  const tags = buildPlatformWorldDisplayTags(entry, 2);
  const metric = getPlatformCategoryPrimaryMetric(entry);
  const metaParts = [
    describePublicGalleryCardKind(entry),
    ...tags.filter((tag) => tag !== categoryTag),
  ].slice(0, 3);
  const actionLabel =
    isPuzzleGalleryEntry(entry) || isVisualNovelGalleryEntry(entry)
      ? '试玩'
      : '进入';
  const summaryText =
    entry.summaryText || entry.subtitle || `${displayName} 正在等待摘要。`;

  return (
    <button
      type="button"
      onClick={onClick}
      aria-label={`${entry.worldName}，${actionLabel}`}
      className="platform-category-game-item"
    >
      <div className="platform-category-game-item__cover">
        {coverImage ? (
          <PlatformWorkCoverArtwork
            entry={entry}
            imageSrc={coverImage}
            alt={entry.worldName}
            className="h-full w-full object-cover"
          />
        ) : (
          <div className="h-full w-full bg-[radial-gradient(circle_at_24%_18%,rgba(255,255,255,0.26),transparent_32%),linear-gradient(135deg,rgba(255,118,117,0.44),rgba(89,164,255,0.36))]" />
        )}
      </div>

      <div className="platform-category-game-item__body">
        <div className="platform-category-game-item__title-row">
          <span className="platform-category-game-item__title">
            {displayName}
          </span>
          <span className="platform-category-game-item__badge">公开</span>
        </div>

        <div className="platform-category-game-item__meta">
          <span className="platform-category-game-item__metric">
            <Star className="h-3.5 w-3.5 fill-current" />
            <span>{formatCompactCount(metric.value)}</span>
          </span>
          <span>{metric.label}</span>
          {metaParts.length > 0 ? <span>{metaParts.join(' · ')}</span> : null}
        </div>

        <div className="platform-category-game-item__summary">
          {summaryText}
        </div>
      </div>

      <span className="platform-category-game-item__action">{actionLabel}</span>
    </button>
  );
}

function PlatformCategoryFilterDialog({
  kindFilter,
  sortMode,
  resultCount,
  onKindFilterChange,
  onSortModeChange,
  onReset,
  onClose,
}: {
  kindFilter: PlatformCategoryKindFilter;
  sortMode: PlatformCategorySortMode;
  resultCount: number;
  onKindFilterChange: (filter: PlatformCategoryKindFilter) => void;
  onSortModeChange: (mode: PlatformCategorySortMode) => void;
  onReset: () => void;
  onClose: () => void;
}) {
  return (
    <div className="platform-modal-backdrop fixed inset-0 z-[90] flex items-end justify-center px-3 py-4 sm:items-center">
      <button
        type="button"
        aria-label="关闭分类筛选"
        className="absolute inset-0"
        onClick={onClose}
      />
      <div
        role="dialog"
        aria-modal="true"
        aria-label="分类筛选"
        className="platform-modal-shell platform-category-filter-dialog relative w-full max-w-md overflow-hidden rounded-[1.35rem]"
      >
        <div className="flex min-w-0 items-center justify-between gap-3 px-4 py-4">
          <div className="min-w-0">
            <div className="text-base font-black text-[var(--platform-text-strong)]">
              分类筛选
            </div>
            <div className="mt-0.5 text-xs font-semibold text-[var(--platform-text-soft)]">
              {resultCount} 个作品
            </div>
          </div>
          <button
            type="button"
            onClick={onClose}
            className="platform-modal-close flex h-9 w-9 items-center justify-center rounded-full"
            aria-label="关闭"
          >
            <XCircle className="h-5 w-5" />
          </button>
        </div>

        <div className="grid gap-4 px-4 pb-4">
          <div className="grid gap-2">
            <div className="text-xs font-black text-[var(--platform-text-soft)]">
              玩法
            </div>
            <div className="platform-category-filter-dialog__options">
              {PLATFORM_CATEGORY_KIND_FILTERS.map((option) => {
                const active = option.id === kindFilter;

                return (
                  <button
                    key={option.id}
                    type="button"
                    onClick={() => onKindFilterChange(option.id)}
                    className={`platform-category-filter-dialog__option ${active ? 'platform-category-filter-dialog__option--active' : ''}`}
                  >
                    {option.label}
                  </button>
                );
              })}
            </div>
          </div>

          <div className="grid gap-2">
            <div className="text-xs font-black text-[var(--platform-text-soft)]">
              排序
            </div>
            <div className="platform-category-filter-dialog__options">
              {PLATFORM_CATEGORY_SORT_OPTIONS.map((option) => {
                const active = option.id === sortMode;

                return (
                  <button
                    key={option.id}
                    type="button"
                    onClick={() => onSortModeChange(option.id)}
                    className={`platform-category-filter-dialog__option ${active ? 'platform-category-filter-dialog__option--active' : ''}`}
                  >
                    {option.label}
                  </button>
                );
              })}
            </div>
          </div>
        </div>

        <div className="platform-category-filter-dialog__actions">
          <button
            type="button"
            onClick={onReset}
            className="platform-category-filter-dialog__action platform-category-filter-dialog__action--secondary"
          >
            重置
          </button>
          <button
            type="button"
            onClick={onClose}
            className="platform-category-filter-dialog__action platform-category-filter-dialog__action--primary"
          >
            完成
          </button>
        </div>
      </div>
    </div>
  );
}

function buildPublicCategoryGroups(
  featuredEntries: PlatformPublicGalleryCard[],
  latestEntries: PlatformPublicGalleryCard[],
) {
  const publicEntryMap = new Map<string, PlatformPublicGalleryCard>();

  filterGeneralPublicWorks([...featuredEntries, ...latestEntries]).forEach(
    (entry) => {
      publicEntryMap.set(buildPublicGalleryCardKey(entry), entry);
    },
  );

  const categoryMap = new Map<string, PlatformPublicGalleryCard[]>();
  Array.from(publicEntryMap.values()).forEach((entry) => {
    const tags = buildPlatformWorldDisplayTags(entry, 3);
    const normalizedTags = tags.length > 0 ? tags : ['回响'];

    normalizedTags.forEach((tag) => {
      const entries = categoryMap.get(tag) ?? [];
      entries.push(entry);
      categoryMap.set(tag, entries);
    });
  });

  return Array.from(categoryMap.entries())
    .map(([tag, entries]) => ({ tag, entries }))
    .sort((left, right) => {
      if (right.entries.length !== left.entries.length) {
        return right.entries.length - left.entries.length;
      }

      return left.tag.localeCompare(right.tag, 'zh-CN');
    });
}

function getPlatformPublicEntries(
  featuredEntries: PlatformPublicGalleryCard[],
  latestEntries: PlatformPublicGalleryCard[],
) {
  const entryMap = new Map<string, PlatformPublicGalleryCard>();

  filterGeneralPublicWorks([...featuredEntries, ...latestEntries]).forEach(
    (entry) => {
      entryMap.set(buildPublicGalleryCardKey(entry), entry);
    },
  );

  return Array.from(entryMap.values());
}

function getAllPlatformPublicEntries(
  featuredEntries: PlatformPublicGalleryCard[],
  latestEntries: PlatformPublicGalleryCard[],
) {
  const entryMap = new Map<string, PlatformPublicGalleryCard>();

  [...featuredEntries, ...latestEntries].forEach((entry) => {
    entryMap.set(buildPublicGalleryCardKey(entry), entry);
  });

  return Array.from(entryMap.values());
}

function normalizePlatformSearchText(value: string | null | undefined) {
  return (value ?? '').trim().toLocaleLowerCase('zh-CN');
}

function normalizePlatformCompactSearchText(value: string | null | undefined) {
  return normalizePlatformSearchText(value).replace(/[\s_-]+/gu, '');
}

function getPlatformSearchableWorkIds(entry: PlatformPublicGalleryCard) {
  const ids = [entry.publicWorkCode, entry.profileId];
  if ('workId' in entry) {
    ids.push(entry.workId);
  }

  return ids.filter((value): value is string => Boolean(value?.trim()));
}

function buildPlatformWorkSearchText(entry: PlatformPublicGalleryCard) {
  return [
    ...getPlatformSearchableWorkIds(entry),
    entry.worldName,
    entry.authorDisplayName,
    entry.summaryText,
    entry.subtitle,
  ].join(' ');
}

function matchesPlatformWorkSearch(
  entry: PlatformPublicGalleryCard,
  keyword: string,
) {
  const normalizedKeyword = normalizePlatformSearchText(keyword);
  const compactKeyword = normalizePlatformCompactSearchText(keyword);
  if (!normalizedKeyword) {
    return false;
  }

  const normalizedSearchText = normalizePlatformSearchText(
    buildPlatformWorkSearchText(entry),
  );
  if (normalizedSearchText.includes(normalizedKeyword)) {
    return true;
  }

  return (
    Boolean(compactKeyword) &&
    normalizePlatformCompactSearchText(
      buildPlatformWorkSearchText(entry),
    ).includes(compactKeyword)
  );
}

function filterPlatformWorkSearchResults(
  entries: PlatformPublicGalleryCard[],
  keyword: string,
) {
  return entries
    .filter((entry) => matchesPlatformWorkSearch(entry, keyword))
    .sort((left, right) => {
      const leftCode = getPlatformSearchableWorkIds(left)[0] ?? '';
      const rightCode = getPlatformSearchableWorkIds(right)[0] ?? '';
      const normalizedKeyword = normalizePlatformSearchText(keyword);
      const leftNameStarts = normalizePlatformSearchText(
        left.worldName,
      ).startsWith(normalizedKeyword);
      const rightNameStarts = normalizePlatformSearchText(
        right.worldName,
      ).startsWith(normalizedKeyword);
      if (leftNameStarts !== rightNameStarts) {
        return leftNameStarts ? -1 : 1;
      }

      const leftCodeStarts = normalizePlatformCompactSearchText(
        leftCode,
      ).startsWith(normalizePlatformCompactSearchText(keyword));
      const rightCodeStarts = normalizePlatformCompactSearchText(
        rightCode,
      ).startsWith(normalizePlatformCompactSearchText(keyword));
      if (leftCodeStarts !== rightCodeStarts) {
        return leftCodeStarts ? -1 : 1;
      }

      return getPlatformWorldTimestamp(right) - getPlatformWorldTimestamp(left);
    });
}

function isExactPublicWorkCodeSearch(
  entries: PlatformPublicGalleryCard[],
  keyword: string,
) {
  const normalizedKeyword = normalizePlatformSearchText(keyword);
  return entries.some(
    (entry) =>
      Boolean(entry.publicWorkCode?.trim()) &&
      normalizePlatformSearchText(entry.publicWorkCode) === normalizedKeyword,
  );
}

function buildPublicGalleryCardKey(entry: PlatformPublicGalleryCard) {
  return buildPlatformPublicGalleryCardKey(entry);
}

function PlatformWorkSearchResults({
  keyword,
  entries,
  onOpen,
  onClear,
}: {
  keyword: string;
  entries: PlatformPublicGalleryCard[];
  onOpen: (entry: PlatformPublicGalleryCard) => void;
  onClear: () => void;
}) {
  const trimmedKeyword = keyword.trim();
  if (!trimmedKeyword) {
    return null;
  }

  return (
    <section className={`${PANEL_SURFACE_CLASS} px-4 py-3.5 sm:px-5 sm:py-4`}>
      <div className="flex items-center justify-between gap-3">
        <SectionHeader title="搜索结果" detail={`${entries.length} 个作品`} />
        <button
          type="button"
          onClick={onClear}
          className="platform-icon-button"
          aria-label="清空搜索"
          title="清空搜索"
        >
          ×
        </button>
      </div>
      {entries.length > 0 ? (
        <div className="grid min-w-0 gap-2.5">
          {entries.slice(0, 12).map((entry) => {
            const displayName = formatPlatformWorkDisplayName(entry.worldName);
            const workCode = getPlatformSearchableWorkIds(entry)[0] ?? '';
            const summaryText =
              entry.summaryText || entry.subtitle || '等待补充世界摘要。';

            return (
              <button
                key={`${buildPublicGalleryCardKey(entry)}:search-result`}
                type="button"
                onClick={() => onOpen(entry)}
                className="platform-desktop-trending-item flex w-full items-center justify-between gap-3 px-4 py-3 text-left"
              >
                <div className="min-w-0">
                  <div className="line-clamp-1 text-sm font-semibold text-[var(--platform-text-strong)]">
                    {displayName}
                  </div>
                  <div className="mt-1 line-clamp-1 text-xs text-[var(--platform-text-soft)]">
                    {entry.authorDisplayName}
                    {workCode ? ` · ${workCode}` : ''}
                  </div>
                  <div className="mt-1 line-clamp-2 text-xs leading-5 text-[var(--platform-text-base)]">
                    {summaryText}
                  </div>
                </div>
                <span className="platform-pill platform-pill--neutral shrink-0 px-3">
                  {describePublicGalleryCardKind(entry)}
                </span>
              </button>
            );
          })}
        </div>
      ) : (
        <EmptyShelf text="没有匹配的公开作品。" />
      )}
    </section>
  );
}

function buildPublicWorkAuthorLookupKey(entry: PlatformPublicGalleryCard) {
  if ('authorPublicUserCode' in entry) {
    const authorPublicUserCode = entry.authorPublicUserCode?.trim();
    if (authorPublicUserCode) {
      return `code:${authorPublicUserCode}`;
    }
  }

  const ownerUserId = entry.ownerUserId.trim();
  return ownerUserId ? `id:${ownerUserId}` : null;
}

async function getPublicWorkAuthorSummary(
  authorLookupKey: string,
): Promise<PublicUserSummary | null> {
  if (authorLookupKey.startsWith('code:')) {
    return getPublicAuthUserByCode(authorLookupKey.slice('code:'.length));
  }

  if (authorLookupKey.startsWith('id:')) {
    return getPublicAuthUserById(authorLookupKey.slice('id:'.length));
  }

  return null;
}

function describePublicGalleryCardKind(entry: PlatformPublicGalleryCard) {
  if (isBigFishGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('大鱼吃小鱼');
  }
  if (isPuzzleGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('拼图');
  }
  if (isMatch3DGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('抓大鹅');
  }
  if (isSquareHoleGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('方洞挑战');
  }
  if (isJumpHopGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('跳一跳');
  }
  if (isWoodenFishGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('敲木鱼');
  }
  if (isVisualNovelGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('视觉小说');
  }
  if (isBarkBattleGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag('汪汪声浪');
  }
  if (isEdutainmentGalleryEntry(entry)) {
    return formatPlatformWorkDisplayTag(entry.templateName);
  }
  return formatPlatformWorkDisplayTag(describePlatformThemeLabel(entry.themeMode));
}
function getPublicAuthorAvatarLabel(authorDisplayName: string) {
  return Array.from(authorDisplayName.trim() || '玩')[0] ?? '玩';
}

function getPlatformWorldLikeCount(entry: PlatformWorldCardLike) {
  return Math.max(0, Math.round(entry.likeCount ?? 0));
}

function getPlatformWorldPlayCount(entry: PlatformWorldCardLike) {
  return Math.max(
    0,
    Math.round(('playCount' in entry && entry.playCount) || 0),
  );
}

function getPlatformWorldRemixCount(entry: PlatformWorldCardLike) {
  return Math.max(
    0,
    Math.round(('remixCount' in entry && entry.remixCount) || 0),
  );
}

function getPlatformWorldRecentPlayCount(entry: PlatformWorldCardLike) {
  return Math.max(
    0,
    Math.round(('recentPlayCount7d' in entry && entry.recentPlayCount7d) || 0),
  );
}

function getPlatformWorldTimestamp(entry: PlatformWorldCardLike) {
  const rawTime = entry.publishedAt ?? entry.updatedAt;
  return parsePlatformEntryTimestamp(rawTime);
}

// 首页“今日游戏”只看作品首次发布时间，按玩家浏览器本地自然日判断。
function parsePlatformEntryTimestamp(value: string | null | undefined) {
  if (!value) {
    return 0;
  }

  const normalized = value.trim();
  const numericTimestamp = normalized.match(/^(-?\d+(?:\.\d+)?)(?:Z)?$/u);
  if (numericTimestamp?.[1]) {
    const rawTimestamp = Number(numericTimestamp[1]);
    if (Number.isFinite(rawTimestamp)) {
      const absoluteTimestamp = Math.abs(rawTimestamp);
      const timestampMs =
        absoluteTimestamp >= 1_000_000_000_000_000
          ? rawTimestamp / 1000
          : absoluteTimestamp >= 1_000_000_000_000
            ? rawTimestamp
            : absoluteTimestamp >= 1_000_000_000
              ? rawTimestamp * 1000
              : Number.NaN;
      return Number.isNaN(timestampMs) ? 0 : timestampMs;
    }
  }

  const timestamp = new Date(normalized).getTime();
  return Number.isNaN(timestamp) ? 0 : timestamp;
}

function isSameLocalCalendarDay(left: Date, right: Date) {
  return (
    left.getFullYear() === right.getFullYear() &&
    left.getMonth() === right.getMonth() &&
    left.getDate() === right.getDate()
  );
}

function isPublishedToday(entry: PlatformPublicGalleryCard, now = new Date()) {
  const publishedAtTimestamp = parsePlatformEntryTimestamp(entry.publishedAt);
  if (publishedAtTimestamp <= 0) {
    return false;
  }

  const publishedAt = new Date(publishedAtTimestamp);
  return isSameLocalCalendarDay(publishedAt, now);
}

function filterTodayPublishedEntries(entries: PlatformPublicGalleryCard[]) {
  const now = new Date();
  return entries.filter((entry) => isPublishedToday(entry, now));
}

function sortEntriesByMetric(
  entries: PlatformPublicGalleryCard[],
  getMetric: (entry: PlatformPublicGalleryCard) => number,
) {
  return [...entries].sort((left, right) => {
    const metricDiff = getMetric(right) - getMetric(left);
    if (metricDiff !== 0) {
      return metricDiff;
    }

    return getPlatformWorldTimestamp(right) - getPlatformWorldTimestamp(left);
  });
}

function buildPlatformRankingEntries(
  entries: PlatformPublicGalleryCard[],
  tab: PlatformRankingTab,
) {
  if (tab === 'hot') {
    return sortEntriesByMetric(entries, getPlatformWorldPlayCount);
  }

  if (tab === 'remix') {
    return sortEntriesByMetric(entries, getPlatformWorldRemixCount);
  }

  if (tab === 'like') {
    return sortEntriesByMetric(entries, getPlatformWorldLikeCount);
  }

  return sortEntriesByMetric(entries, getPlatformWorldRecentPlayCount);
}

function getPlatformRankingMetricValue(
  entry: PlatformPublicGalleryCard,
  tab: PlatformRankingTab,
) {
  if (tab === 'remix') {
    return getPlatformWorldRemixCount(entry);
  }

  if (tab === 'like') {
    return getPlatformWorldLikeCount(entry);
  }

  if (tab === 'new') {
    return getPlatformWorldRecentPlayCount(entry);
  }

  return getPlatformWorldPlayCount(entry);
}

function getPlatformCategoryCompositeScore(entry: PlatformPublicGalleryCard) {
  // 分类频道只使用公开读模型已经返回的指标做前端排序，不在 UI 层伪造评分数据。
  return (
    getPlatformWorldPlayCount(entry) +
    getPlatformWorldRemixCount(entry) +
    getPlatformWorldLikeCount(entry) +
    getPlatformWorldRecentPlayCount(entry)
  );
}

function getPlatformCategoryKindFilter(entry: PlatformPublicGalleryCard) {
  if (isPuzzleGalleryEntry(entry)) {
    return 'puzzle';
  }

  if (isMatch3DGalleryEntry(entry)) {
    return 'match3d';
  }

  if (isSquareHoleGalleryEntry(entry)) {
    return 'square-hole';
  }

  if (isVisualNovelGalleryEntry(entry)) {
    return 'visual-novel';
  }

  if (isBarkBattleGalleryEntry(entry)) {
    return 'bark-battle';
  }

  if (isBigFishGalleryEntry(entry)) {
    return 'big-fish';
  }

  return 'custom-world';
}

function matchesPlatformCategoryKindFilter(
  entry: PlatformPublicGalleryCard,
  kindFilter: PlatformCategoryKindFilter,
) {
  return (
    kindFilter === 'all' || getPlatformCategoryKindFilter(entry) === kindFilter
  );
}

function sortPlatformCategoryEntries(
  entries: PlatformPublicGalleryCard[],
  sortMode: PlatformCategorySortMode,
) {
  return [...entries].sort((left, right) => {
    if (sortMode === 'latest') {
      return getPlatformWorldTimestamp(right) - getPlatformWorldTimestamp(left);
    }

    const metricDiff =
      sortMode === 'play'
        ? getPlatformWorldPlayCount(right) - getPlatformWorldPlayCount(left)
        : sortMode === 'like'
          ? getPlatformWorldLikeCount(right) - getPlatformWorldLikeCount(left)
          : getPlatformCategoryCompositeScore(right) -
            getPlatformCategoryCompositeScore(left);

    if (metricDiff !== 0) {
      return metricDiff;
    }

    return getPlatformWorldTimestamp(right) - getPlatformWorldTimestamp(left);
  });
}

function getPlatformCategoryPrimaryMetric(entry: PlatformPublicGalleryCard) {
  const likeCount = getPlatformWorldLikeCount(entry);
  if (likeCount > 0) {
    return { label: '点赞', value: likeCount };
  }

  const recentPlayCount = getPlatformWorldRecentPlayCount(entry);
  if (recentPlayCount > 0) {
    return { label: '近7日', value: recentPlayCount };
  }

  return { label: '游玩', value: getPlatformWorldPlayCount(entry) };
}

function formatCompactCount(value: number) {
  const normalizedValue = Math.max(0, Math.round(value));
  if (normalizedValue >= 100000000) {
    return `${(normalizedValue / 100000000).toFixed(1)}亿`;
  }
  if (normalizedValue >= 10000) {
    return `${(normalizedValue / 10000).toFixed(1)}万`;
  }
  return `${normalizedValue}`;
}

function formatSnapshotTime(value: string | null | undefined) {
  if (!value) {
    return '刚刚保存';
  }

  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return value;
  }

  return date.toLocaleString('zh-CN', {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function formatCompactPlayTime(playTimeMs: number) {
  const totalMinutes = Math.max(0, Math.floor(playTimeMs / 60000));
  const days = totalMinutes / 1440;

  if (days >= 10) {
    return `${Math.floor(days)}天`;
  }
  if (days >= 1) {
    return `${days.toFixed(days >= 3 ? 0 : 1)}天`;
  }

  const hours = totalMinutes / 60;
  if (hours >= 1) {
    return `${hours.toFixed(hours >= 10 ? 0 : 1)}小时`;
  }

  return `${Math.max(0, totalMinutes)}分`;
}

// “游戏时长”固定使用小时，避免短时长切到分钟或长时长切到天。
function formatTotalPlayTimeHours(playTimeMs: number) {
  const roundedHours = Math.max(0, Math.round(playTimeMs / 360000) / 10);

  return `${roundedHours.toLocaleString('zh-CN', {
    maximumFractionDigits: 1,
  })}小时`;
}

function formatDashboardCount(value: number) {
  const normalizedValue = Math.max(0, Math.round(value));
  if (normalizedValue >= 100000000) {
    return `${(normalizedValue / 100000000).toFixed(1)}亿`;
  }
  if (normalizedValue >= 10000) {
    return `${(normalizedValue / 10000).toFixed(1)}万`;
  }

  return normalizedValue.toLocaleString('zh-CN');
}

function normalizeProfileInviteQueryCode(value: string | null | undefined) {
  return (value ?? '')
    .trim()
    .replace(/[^0-9a-z]/giu, '')
    .toUpperCase();
}

function readProfileInviteCodeFromLocationSearch(search: string) {
  const params = new URLSearchParams(search);
  for (const key of PROFILE_INVITE_QUERY_KEYS) {
    const inviteCode = normalizeProfileInviteQueryCode(params.get(key));
    if (inviteCode) {
      return inviteCode;
    }
  }
  return '';
}

function formatPlayedWorkType(value: string | null | undefined) {
  const normalizedValue = (value ?? '').toLowerCase();
  if (normalizedValue === 'puzzle') {
    return '拼图';
  }
  if (normalizedValue === 'match3d' || normalizedValue === 'match_3d') {
    return '抓鹅';
  }
  if (normalizedValue === 'square-hole' || normalizedValue === 'square_hole') {
    return '方洞';
  }
  if (normalizedValue === 'big_fish' || normalizedValue === 'big-fish') {
    return '大鱼';
  }
  return 'RPG';
}

function formatPlayedWorkId(work: ProfilePlayedWorkSummary) {
  return work.profileId?.trim() || work.worldKey;
}

function buildPublicUserCode(user: AuthUser | null | undefined) {
  if (user?.publicUserCode?.trim()) {
    return user.publicUserCode.trim();
  }

  const raw = user?.id.replace(/[^a-zA-Z0-9]/gu, '').toUpperCase() || '00000000';

  return `SY-${raw.slice(-8).padStart(8, '0')}`;
}

function getUserAvatarLabel(user: AuthUser | null | undefined) {
  return (user?.displayName || '叙')
    .slice(0, 1)
    .toUpperCase();
}

function validateProfileDisplayName(value: string) {
  const normalized = value.trim();
  if (!normalized) {
    return '请输入昵称';
  }
  const length = Array.from(normalized).length;
  if (length < 2 || length > 20) {
    return '昵称需要 2 到 20 位';
  }
  if (!/^[\u4e00-\u9fffa-zA-Z0-9_]+$/u.test(normalized)) {
    return '昵称仅支持中文、英文、数字和下划线';
  }

  return null;
}

function readImageIntrinsicSize(src: string) {
  return new Promise<{ width: number; height: number }>((resolve, reject) => {
    const image = new Image();
    image.onload = () => {
      resolve({
        width: image.naturalWidth,
        height: image.naturalHeight,
      });
    };
    image.onerror = () => reject(new Error('图片读取失败'));
    image.src = src;
  });
}

function loadAvatarFile(file: File) {
  return new Promise<string>((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      if (typeof reader.result !== 'string') {
        reject(new Error('图片读取失败'));
        return;
      }
      resolve(reader.result);
    };
    reader.onerror = () => reject(new Error('图片读取失败'));
    reader.readAsDataURL(file);
  });
}

function cropAvatarImage(params: {
  source: string;
  cropX: number;
  cropY: number;
  cropSize: number;
}) {
  return new Promise<string>((resolve, reject) => {
    const image = new Image();
    image.onload = () => {
      const canvas = document.createElement('canvas');
      canvas.width = AVATAR_OUTPUT_SIZE;
      canvas.height = AVATAR_OUTPUT_SIZE;
      const context = canvas.getContext('2d');
      if (!context) {
        reject(new Error('头像裁剪失败'));
        return;
      }

      context.drawImage(
        image,
        params.cropX,
        params.cropY,
        params.cropSize,
        params.cropSize,
        0,
        0,
        AVATAR_OUTPUT_SIZE,
        AVATAR_OUTPUT_SIZE,
      );
      resolve(canvas.toDataURL('image/png'));
    };
    image.onerror = () => reject(new Error('头像裁剪失败'));
    image.src = params.source;
  });
}

function ProfileStatCard({
  cardKey,
  label,
  value,
  onClick,
  icon,
  imageSrc,
}: {
  cardKey: ProfileDashboardCardKey;
  label: string;
  value: string;
  onClick?: ((cardKey: ProfileDashboardCardKey) => void) | null;
  icon: ComponentType<{ className?: string }>;
  imageSrc?: string;
}) {
  const Icon = icon;

  return (
    <button
      type="button"
      onClick={onClick ? () => onClick(cardKey) : undefined}
      aria-label={`${label} ${value}`}
      className="platform-profile-stat-card flex min-h-[5.25rem] items-center justify-center gap-2 px-2.5 py-2.5 text-center transition"
    >
      <div className="platform-profile-stat-card__icon">
        {imageSrc ? (
          <img src={imageSrc} alt="" className="h-full w-full object-contain" />
        ) : (
          <Icon className="h-5 w-5" />
        )}
      </div>
      <div className="min-w-0 text-left">
        <div className="platform-profile-stat-card__value whitespace-nowrap text-[16px] font-black leading-none text-[var(--platform-text-strong)]">
          {value}
        </div>
        <div className="platform-profile-stat-card__label mt-1 whitespace-nowrap text-[11px] font-medium text-[var(--platform-text-soft)]">
          {label}
        </div>
      </div>
    </button>
  );
}

function ProfileStatCardSkeleton() {
  return (
    <div className="platform-subpanel flex min-h-[5.75rem] flex-col items-center justify-center rounded-[1.35rem] px-3 py-3 text-center">
      <div className="h-4 w-20 animate-pulse rounded-full bg-[var(--platform-subpanel-border)]" />
      <div className="mt-2 h-7 w-16 animate-pulse rounded-full bg-[var(--platform-line-soft)]" />
    </div>
  );
}

function ProfileShortcutButton({
  label,
  subLabel,
  icon,
  onClick,
  imageSrc,
}: {
  label: string;
  subLabel?: ReactNode;
  icon: ComponentType<{ className?: string }>;
  onClick?: (() => void) | null;
  imageSrc?: string;
}) {
  const Icon = icon;

  return (
    <button
      type="button"
      onClick={onClick ?? undefined}
      className="platform-profile-shortcut-button flex min-h-[4.75rem] w-full flex-col items-center justify-center gap-1.5 px-2 py-2.5 text-center transition"
    >
      <div className="platform-profile-shortcut-button__icon">
        {imageSrc ? (
          <img src={imageSrc} alt="" className="h-full w-full object-contain" />
        ) : (
          <Icon className="h-[1.125rem] w-[1.125rem]" />
        )}
      </div>
      <div className="platform-profile-shortcut-button__label whitespace-nowrap text-[12px] font-semibold text-[var(--platform-text-strong)]">
        {label}
      </div>
      {subLabel ? (
        <div className="platform-profile-shortcut-button__sub-label flex min-h-4 items-center justify-center gap-1 whitespace-nowrap text-[10px] font-medium text-[var(--platform-text-soft)]">
          {subLabel}
        </div>
      ) : null}
    </button>
  );
}

function ProfileSettingsRow({
  label,
  icon,
  onClick,
}: {
  label: string;
  icon: ComponentType<{ className?: string }>;
  onClick: () => void;
}) {
  const Icon = icon;

  return (
    <button
      type="button"
      onClick={onClick}
      className="platform-profile-settings-row flex w-full items-center justify-between gap-3 px-4 py-3 text-left transition"
    >
      <span className="flex min-w-0 items-center gap-3">
        <span className="platform-profile-settings-row__icon">
          <Icon className="h-4 w-4" />
        </span>
        <span className="truncate text-[14px] font-semibold text-[var(--platform-text-strong)]">
          {label}
        </span>
      </span>
      <ChevronRight className="h-4 w-4 shrink-0 text-[var(--platform-text-soft)]" />
    </button>
  );
}

function ProfileLegalSection({
  onOpenDocument,
}: {
  onOpenDocument: (documentId: LegalDocumentId) => void;
}) {
  return (
    <section
      className="platform-profile-legal-strip"
      aria-label="法律信息"
    >
      <div className="platform-profile-legal-strip__links">
        {LEGAL_DOCUMENTS.map((document, index) => (
          <button
            key={document.id}
            type="button"
            onClick={() => onOpenDocument(document.id)}
            className="platform-profile-legal-strip__link"
          >
            {document.title}
            {index < LEGAL_DOCUMENTS.length - 1 ? (
              <span aria-hidden="true" className="platform-profile-legal-strip__divider" />
            ) : null}
          </button>
        ))}
      </div>
      <a
        href={ICP_RECORD_URL}
        target="_blank"
        rel="noreferrer"
        className="platform-profile-legal-strip__record"
      >
        {ICP_RECORD_NUMBER}
      </a>
    </section>
  );
}

function ProfileReferralUserAvatar({
  name,
  avatarUrl,
}: {
  name: string;
  avatarUrl: string | null;
}) {
  const avatarLabel = (name.trim() || '玩').slice(0, 1).toUpperCase();

  return (
    <span className="flex h-9 w-9 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[#ff4056] text-xs font-black text-white">
      {avatarUrl ? (
        <img
          src={avatarUrl}
          alt=""
          className="h-full w-full object-cover"
          loading="lazy"
          decoding="async"
        />
      ) : (
        avatarLabel
      )}
    </span>
  );
}

function ProfileNicknameModal({
  value,
  error,
  isSaving,
  onChange,
  onClose,
  onSubmit,
}: {
  value: string;
  error: string | null;
  isSaving: boolean;
  onChange: (value: string) => void;
  onClose: () => void;
  onSubmit: () => void;
}) {
  return (
    <div className="platform-modal-backdrop fixed inset-0 z-[80] flex items-center justify-center px-4 py-6">
      <div
        role="dialog"
        aria-modal="true"
        aria-labelledby="profile-nickname-title"
        className="platform-modal-shell platform-remap-surface w-full max-w-sm overflow-hidden rounded-[1.4rem]"
      >
        <div className="flex items-center justify-between border-b border-white/10 px-5 py-4">
          <div id="profile-nickname-title" className="text-base font-black">
            修改昵称
          </div>
          <button
            type="button"
            aria-label="关闭昵称修改"
            onClick={onClose}
            className="platform-profile-icon-button flex h-8 w-8 items-center justify-center rounded-full"
          >
            ×
          </button>
        </div>
        <div className="px-5 py-5">
          <label className="block">
            <span className="sr-only">新昵称</span>
            <input
              autoFocus
              value={value}
              onChange={(event) => onChange(event.target.value)}
              onKeyDown={(event) => {
                if (event.key === 'Enter') {
                  event.preventDefault();
                  onSubmit();
                }
              }}
              maxLength={20}
              className="w-full rounded-2xl border border-white/12 bg-white/10 px-4 py-3 text-base font-semibold text-[var(--platform-text-strong)] outline-none transition focus:border-[var(--platform-surface-hover-border)]"
              placeholder="输入新昵称"
            />
          </label>
          {error ? (
            <div className="mt-3 rounded-2xl border border-rose-400/25 bg-rose-500/10 px-3 py-2 text-sm text-rose-600">
              {error}
            </div>
          ) : null}
          <div className="mt-5 grid grid-cols-2 gap-3">
            <button
              type="button"
              onClick={onClose}
              className="platform-button platform-button--secondary justify-center"
            >
              取消
            </button>
            <button
              type="button"
              onClick={onSubmit}
              disabled={isSaving}
              className="platform-button platform-button--primary justify-center disabled:cursor-not-allowed disabled:opacity-60"
            >
              {isSaving ? '保存中' : '保存'}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

const WALLET_LEDGER_SOURCE_LABELS: Record<string, string> = {
  new_user_registration_reward: '注册赠送',
  points_recharge: '泥点充值',
  invite_inviter_reward: '邀请奖励',
  invite_invitee_reward: '填写邀请码奖励',
  snapshot_sync: '账户同步',
  asset_operation_consume: '资产操作消耗',
  asset_operation_refund: '资产操作退回',
  redeem_code_reward: '兑换码奖励',
  daily_task_reward: '每日任务奖励',
};

function formatWalletLedgerAmount(amountDelta: number) {
  return amountDelta > 0 ? `+${amountDelta}` : `${amountDelta}`;
}

function formatRechargePrice(priceCents: number) {
  const yuan = priceCents / 100;
  return `¥${Number.isInteger(yuan) ? yuan.toFixed(0) : yuan.toFixed(2)}`;
}

function clearWechatPayResultHash() {
  if (typeof window === 'undefined') {
    return;
  }

  const rawHash = window.location.hash.replace(/^#/, '');
  if (!rawHash.includes('wx_pay_result=')) {
    return;
  }
  const params = new URLSearchParams(rawHash);
  params.delete('wx_pay_result');
  const nextHash = params.toString();
  const nextUrl = `${window.location.pathname}${window.location.search}${nextHash ? `#${nextHash}` : ''}`;
  window.history.replaceState(null, '', nextUrl);
}

function readWechatPayResultFromHash(): WechatPayResult | null {
  if (typeof window === 'undefined') {
    return null;
  }

  const result = new URLSearchParams(
    window.location.hash.replace(/^#/, ''),
  ).get('wx_pay_result');
  if (!result) {
    return null;
  }

  const [requestId = '', rawStatus = '', explicitOrderId = '', ...rawErrors] =
    result.split(':');
  const inferredOrderId = requestId
    .replace(/^wechat_pay_/, '')
    .replace(/_\d+$/, '')
    .trim();
  const orderId = explicitOrderId.trim() || inferredOrderId;
  const status =
    rawStatus === 'success'
      ? 'success'
      : rawStatus === 'cancel'
        ? 'cancel'
        : 'fail';
  let errorMessage: string | null = null;
  const rawError = rawErrors.join(':');
  if (rawError) {
    try {
      errorMessage = decodeURIComponent(rawError);
    } catch (_error) {
      errorMessage = rawError;
    }
  }

  return {
    requestId,
    orderId: orderId || null,
    status,
    errorMessage,
  };
}

function loadWechatJsSdk() {
  if (typeof window === 'undefined') {
    return Promise.reject(new Error('请在微信小程序内完成支付'));
  }
  if (window.wx?.miniProgram?.navigateTo) {
    return Promise.resolve(window.wx);
  }

  return new Promise<NonNullable<Window['wx']>>((resolve, reject) => {
    const existingScript = document.querySelector<HTMLScriptElement>(
      `script[src="${WECHAT_JS_SDK_URL}"]`,
    );
    const complete = () => {
      if (window.wx?.miniProgram?.navigateTo) {
        resolve(window.wx);
      } else {
        reject(new Error('请在微信小程序内完成支付'));
      }
    };

    if (existingScript) {
      existingScript.addEventListener('load', complete, { once: true });
      existingScript.addEventListener(
        'error',
        () => reject(new Error('请在微信小程序内完成支付')),
        { once: true },
      );
      complete();
      return;
    }

    const script = document.createElement('script');
    script.src = WECHAT_JS_SDK_URL;
    script.async = true;
    script.onload = complete;
    script.onerror = () => reject(new Error('请在微信小程序内完成支付'));
    document.head.appendChild(script);
  });
}

async function requestWechatMiniProgramPayment(
  payload:
    | WechatMiniProgramPayParams
    | WechatMiniProgramVirtualPayParams
    | null
    | undefined,
  orderId: string,
): Promise<void> {
  if (!payload) {
    return Promise.reject(new Error('请在微信小程序内完成支付'));
  }
  const wxBridge = await loadWechatJsSdk();
  const miniProgram = wxBridge.miniProgram;
  if (!miniProgram || typeof miniProgram.navigateTo !== 'function') {
    return Promise.reject(new Error('请在微信小程序内完成支付'));
  }
  const navigateTo = miniProgram.navigateTo;

  const requestId = `wechat_pay_${orderId}_${Date.now()}`;
  return new Promise<void>((resolve, reject) => {
    navigateTo({
      url: `/pages/wechat-pay/index?requestId=${encodeURIComponent(requestId)}&orderId=${encodeURIComponent(orderId)}&payParams=${encodeURIComponent(JSON.stringify(payload))}`,
      success() {
        resolve();
      },
      fail(error) {
        console.error('[wechat-pay] navigateTo failed', error);
        reject(
          error instanceof Error
            ? error
            : new Error('请在微信小程序内完成支付'),
        );
      },
    });
  });
}

function waitWechatPayConfirmDelay(delayMs: number) {
  return new Promise<void>((resolve) => {
    window.setTimeout(resolve, delayMs);
  });
}

async function confirmWechatRechargeOrderUntilSettled(
  orderId: string,
): Promise<ConfirmWechatProfileRechargeOrderResponse> {
  let latestResponse = await confirmWechatRpgProfileRechargeOrder(orderId);
  if (latestResponse.order.status !== 'pending') {
    return latestResponse;
  }

  for (const delayMs of WECHAT_PAY_CONFIRM_RETRY_DELAYS_MS) {
    await waitWechatPayConfirmDelay(delayMs);

    latestResponse = await confirmWechatRpgProfileRechargeOrder(orderId);
    if (latestResponse.order.status !== 'pending') {
      return latestResponse;
    }
  }

  try {
    const streamedResponse = await watchWechatRpgProfileRechargeOrder(orderId);
    return streamedResponse;
  } catch {
    return latestResponse;
  }
}

function useWechatNativeQrCode(codeUrl: string | null) {
  const [qrImageUrl, setQrImageUrl] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    setQrImageUrl(null);
    if (!codeUrl) {
      return () => {
        cancelled = true;
      };
    }

    void QRCode.toDataURL(codeUrl, {
      errorCorrectionLevel: 'M',
      margin: 1,
      width: WECHAT_NATIVE_PAY_QR_IMAGE_SIZE,
    }).then((dataUrl) => {
      if (!cancelled) {
        setQrImageUrl(dataUrl);
      }
    });

    return () => {
      cancelled = true;
    };
  }, [codeUrl]);

  return qrImageUrl;
}

function RechargeProductCard({
  product,
  submittingProductId,
  onBuy,
}: {
  product: ProfileRechargeProduct;
  submittingProductId: string | null;
  onBuy: (product: ProfileRechargeProduct) => void;
}) {
  const submitting = submittingProductId === product.productId;
  const effectiveBonusPoints = product.bonusPoints;
  const badgeLabel = product.badgeLabel;
  const value =
    product.kind === 'points'
      ? `${product.pointsAmount}${effectiveBonusPoints > 0 ? `+${effectiveBonusPoints}` : ''}泥点`
      : `${product.durationDays}天`;

  return (
    <button
      type="button"
      onClick={() => onBuy(product)}
      disabled={Boolean(submittingProductId)}
      className="platform-subpanel platform-interactive-card relative min-h-[7.25rem] rounded-[1.15rem] px-3.5 py-3.5 text-left disabled:cursor-not-allowed disabled:opacity-60"
    >
      {badgeLabel ? (
        <span className="platform-pill platform-pill--warm absolute right-3 top-3 max-w-[7rem] truncate px-2 py-0.5 text-[10px]">
          {badgeLabel}
        </span>
      ) : null}
      <div className="pr-20 text-sm font-black text-[var(--platform-text-strong)]">
        {product.title}
      </div>
      <div className="mt-3 text-2xl font-black text-[var(--platform-text-strong)]">
        {value}
      </div>
      <div className="mt-2 flex items-center justify-between gap-3">
        <span className="text-sm font-bold text-[var(--platform-text-soft)]">
          {formatRechargePrice(product.priceCents)}
        </span>
        <span className="platform-primary-button rounded-full px-3 py-1.5 text-xs font-black">
          {submitting ? '处理中' : '购买'}
        </span>
      </div>
    </button>
  );
}

function ProfileRechargeModal({
  center,
  isLoading,
  error,
  submittingProductId,
  nativePayment,
  activeTab,
  onTabChange,
  onClose,
  onRetry,
  onBuy,
  onConfirmNativePayment,
}: {
  center: ProfileRechargeCenterResponse | null;
  isLoading: boolean;
  error: string | null;
  submittingProductId: string | null;
  nativePayment: NativeWechatPaymentState | null;
  activeTab: RechargeTab;
  onTabChange: (tab: RechargeTab) => void;
  onClose: () => void;
  onRetry: () => void;
  onBuy: (product: ProfileRechargeProduct) => void;
  onConfirmNativePayment: () => void;
}) {
  const nativeQrImageUrl = useWechatNativeQrCode(
    nativePayment?.codeUrl ?? null,
  );
  const products =
    activeTab === 'points'
      ? (center?.pointProducts ?? [])
      : (center?.membershipProducts ?? []);
  const memberLabel =
    center?.membership.status === 'active'
      ? center.membership.expiresAt
        ? `会员至 ${formatSnapshotTime(center.membership.expiresAt)}`
        : '会员已生效'
      : '普通用户';

  return (
    <div className="platform-modal-backdrop fixed inset-0 z-[80] flex items-center justify-center px-4 py-6">
      <div className="platform-recharge-modal w-full max-w-[34rem] overflow-hidden rounded-[1.4rem]">
        <div className="flex items-center justify-between border-b border-white/10 px-5 py-4">
          <div>
            <div className="text-base font-black">账户充值</div>
            <div className="mt-1 text-xs font-semibold text-[var(--platform-text-soft)]">
              {center
                ? `${center.walletBalance}泥点 · ${memberLabel}`
                : '读取中'}
            </div>
          </div>
          <button
            type="button"
            aria-label="关闭账户充值"
            onClick={onClose}
            className="platform-modal-close flex h-9 w-9 items-center justify-center rounded-full"
          >
            ×
          </button>
        </div>
        <div className="max-h-[min(76vh,36rem)] overflow-y-auto px-5 py-5">
          <div className="grid grid-cols-2 gap-2">
            <button
              type="button"
              onClick={() => onTabChange('points')}
              className={`platform-category-chip justify-center ${activeTab === 'points' ? 'platform-category-chip--active' : ''}`}
            >
              泥点充值
            </button>
            <button
              type="button"
              onClick={() => onTabChange('membership')}
              className={`platform-category-chip justify-center ${activeTab === 'membership' ? 'platform-category-chip--active' : ''}`}
            >
              会员卡
            </button>
          </div>

          {error ? (
            <div className="platform-profile-error mt-4 rounded-2xl px-3 py-2 text-xs font-semibold">
              <div>{error}</div>
              <button
                type="button"
                onClick={onRetry}
                className="platform-primary-button mt-3 rounded-2xl px-4 py-2 text-xs font-black"
              >
                重新加载
              </button>
            </div>
          ) : null}

          {isLoading ? (
            <div className="mt-4 grid gap-3 sm:grid-cols-2">
              {Array.from({ length: 4 }).map((_, index) => (
                <div
                  key={index}
                  className="h-28 animate-pulse rounded-[1.15rem] bg-white/10"
                />
              ))}
            </div>
          ) : products.length > 0 ? (
            <div className="mt-4 grid gap-3 sm:grid-cols-2">
              {products.map((product) => (
                <RechargeProductCard
                  key={product.productId}
                  product={product}
                  submittingProductId={submittingProductId}
                  onBuy={onBuy}
                />
              ))}
            </div>
          ) : (
            <div className="platform-subpanel mt-4 rounded-2xl px-4 py-8 text-center text-sm font-semibold text-[var(--platform-text-soft)]">
              暂无可购买套餐
            </div>
          )}

          {nativePayment ? (
            <div className="platform-subpanel mt-4 rounded-2xl px-4 py-4 text-center">
              <div className="text-sm font-black">微信扫码支付</div>
              <div className="mx-auto mt-3 flex h-[180px] w-[180px] items-center justify-center rounded-xl bg-white p-2">
                {nativeQrImageUrl ? (
                  <img
                    src={nativeQrImageUrl}
                    alt="微信 Native 支付二维码"
                    className="h-full w-full"
                  />
                ) : (
                  <span className="text-xs font-semibold text-slate-500">
                    生成中
                  </span>
                )}
              </div>
              <button
                type="button"
                onClick={onConfirmNativePayment}
                disabled={nativePayment.isConfirming}
                className="platform-primary-button mt-4 rounded-2xl px-4 py-2 text-xs font-black disabled:cursor-wait disabled:opacity-60"
              >
                {nativePayment.isConfirming ? '确认中' : '我已支付'}
              </button>
            </div>
          ) : null}
        </div>
      </div>
    </div>
  );
}

function RechargePaymentResultModal({
  result,
  onClose,
}: {
  result: RechargePaymentResult;
  onClose: () => void;
}) {
  const Icon =
    result.kind === 'success'
      ? CheckCircle2
      : result.kind === 'cancel'
        ? XCircle
        : AlertCircle;
  const iconClass =
    result.kind === 'success'
      ? 'text-[var(--platform-success-text)]'
      : result.kind === 'cancel'
        ? 'text-[var(--platform-text-soft)]'
        : 'text-[var(--platform-button-danger-text)]';

  return (
    <div className="platform-modal-backdrop fixed inset-0 z-[90] flex items-center justify-center px-4 py-6">
      <div
        role="dialog"
        aria-modal="true"
        aria-labelledby="recharge-payment-result-title"
        className="platform-modal-shell platform-remap-surface w-full max-w-sm overflow-hidden rounded-[1.4rem]"
      >
        <div className="px-5 pb-5 pt-6 text-center">
          <div
            className={`mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-white/10 ${iconClass}`}
          >
            <Icon className="h-8 w-8" aria-hidden="true" />
          </div>
          <div
            id="recharge-payment-result-title"
            className="mt-4 text-xl font-black text-[var(--platform-text-strong)]"
          >
            {result.title}
          </div>
          <div className="mt-3 text-sm font-semibold leading-6 text-[var(--platform-text-soft)]">
            {result.message}
          </div>
          <button
            type="button"
            onClick={onClose}
            className="platform-primary-button mt-5 w-full rounded-2xl px-4 py-3 text-sm font-black"
          >
            知道了
          </button>
        </div>
      </div>
    </div>
  );
}

function RechargePaymentConfirmationMask({
  orderId,
}: {
  orderId: string;
}) {
  return (
    <div className="platform-modal-backdrop fixed inset-0 z-[95] flex items-center justify-center px-4 py-6">
      <div
        role="dialog"
        aria-modal="true"
        aria-label="正在确认支付"
        className="platform-modal-shell platform-remap-surface w-full max-w-sm overflow-hidden rounded-[1.4rem]"
      >
        <div className="px-5 pb-5 pt-6 text-center">
          <div className="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-white/10 text-[var(--platform-accent)]">
            <Loader2 className="h-8 w-8 animate-spin" aria-hidden="true" />
          </div>
          <div className="mt-4 text-xl font-black text-[var(--platform-text-strong)]">
            正在确认支付
          </div>
          <div className="mt-3 text-sm font-semibold leading-6 text-[var(--platform-text-soft)]">
            订单 {orderId} 正在同步到账状态，请先停留在当前页面。
          </div>
        </div>
      </div>
    </div>
  );
}

function WalletLedgerModal({
  ledger,
  fallbackBalance,
  isLoading,
  error,
  onClose,
  onRetry,
}: {
  ledger: ProfileWalletLedgerResponse | null;
  fallbackBalance: number;
  isLoading: boolean;
  error: string | null;
  onClose: () => void;
  onRetry: () => void;
}) {
  const entries = ledger?.entries ?? [];
  const balance = entries[0]?.balanceAfter ?? fallbackBalance;

  return (
    <div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/48 px-3 py-5">
      <div className="relative max-h-[min(92vh,42rem)] w-full max-w-[30rem] overflow-hidden rounded-[1.35rem] bg-[linear-gradient(180deg,#fff7f8_0%,#ffffff_38%,#f8fafc_100%)] text-zinc-950 shadow-2xl">
        <button
          type="button"
          onClick={onClose}
          className="absolute right-3 top-3 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white/78 text-[#ff4056] shadow-sm"
          aria-label="关闭泥点账单"
        >
          ×
        </button>
        <div className="max-h-[min(92vh,42rem)] overflow-y-auto px-4 pb-5 pt-4 sm:px-5">
          <div className="pr-10">
            <div className="text-[10px] font-black tracking-[0.22em] text-[#ff4056]">
              LEDGER
            </div>
            <div className="mt-1 text-2xl font-black">泥点账单</div>
            <div className="mt-3 inline-flex items-center gap-2 rounded-full border border-rose-100 bg-white/70 px-3 py-1.5 text-xs font-bold text-zinc-600">
              <Coins className="h-3.5 w-3.5 text-[#ff4056]" />
              <span>{balance}泥点</span>
            </div>
          </div>

          {error ? (
            <div className="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-3 py-3 text-sm text-rose-700">
              <div>{error}</div>
              <button
                type="button"
                onClick={onRetry}
                className="mt-3 rounded-full bg-[#ff4056] px-4 py-2 text-xs font-black text-white"
              >
                重新加载
              </button>
            </div>
          ) : isLoading ? (
            <div className="mt-5 space-y-3">
              {Array.from({ length: 5 }).map((_, index) => (
                <div
                  key={index}
                  className="h-16 animate-pulse rounded-xl bg-zinc-100"
                />
              ))}
            </div>
          ) : entries.length === 0 ? (
            <div className="mt-5 rounded-xl border border-zinc-200 bg-white px-4 py-8 text-center text-sm font-semibold text-zinc-500">
              暂无账单记录
            </div>
          ) : (
            <div className="mt-5 space-y-2.5">
              {entries.map((entry) => {
                const isIncome = entry.amountDelta > 0;
                const label =
                  WALLET_LEDGER_SOURCE_LABELS[entry.sourceType] ??
                  entry.sourceType;

                return (
                  <div
                    key={entry.id}
                    className="flex items-center justify-between gap-3 rounded-xl border border-zinc-200 bg-white px-3 py-3 shadow-sm"
                  >
                    <div className="min-w-0">
                      <div className="truncate text-sm font-black text-zinc-900">
                        {label}
                      </div>
                      <div className="mt-1 text-xs font-semibold text-zinc-500">
                        {formatPlatformWorldTime(entry.createdAt)}
                      </div>
                    </div>
                    <div className="shrink-0 text-right">
                      <div
                        className={`text-base font-black ${
                          isIncome ? 'text-emerald-600' : 'text-rose-500'
                        }`}
                      >
                        {formatWalletLedgerAmount(entry.amountDelta)}
                      </div>
                      <div className="mt-1 text-[11px] font-semibold text-zinc-400">
                        余额 {entry.balanceAfter}
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

const PROFILE_TASK_STATUS_LABELS: Record<ProfileTaskItem['status'], string> = {
  incomplete: '未完成',
  claimable: '可领取',
  claimed: '已领取',
  disabled: '已停用',
};

function ProfileTaskCenterModal({
  center,
  isLoading,
  error,
  success,
  claimingTaskId,
  fallbackBalance,
  onClose,
  onRetry,
  onClaim,
}: {
  center: ProfileTaskCenterResponse | null;
  isLoading: boolean;
  error: string | null;
  success: string | null;
  claimingTaskId: string | null;
  fallbackBalance: number;
  onClose: () => void;
  onRetry: () => void;
  onClaim: (taskId: string) => void;
}) {
  const tasks = selectProfileTaskCenterTasks(center?.tasks ?? []);
  const walletBalance = center?.walletBalance ?? fallbackBalance;

  return (
    <div className="platform-modal-backdrop fixed inset-0 z-[80] flex items-center justify-center px-4 py-6">
      <div className="platform-recharge-modal w-full max-w-md overflow-hidden rounded-[1.4rem]">
        <div className="flex items-center justify-between border-b border-white/10 px-5 py-4">
          <div>
            <div className="text-base font-black">每日任务</div>
            <div className="mt-1 text-xs font-semibold text-[var(--platform-text-soft)]">
              {walletBalance}泥点
            </div>
          </div>
          <button
            type="button"
            aria-label="关闭每日任务"
            onClick={onClose}
            className="platform-modal-close flex h-9 w-9 items-center justify-center rounded-full"
          >
            ×
          </button>
        </div>
        <div className="space-y-3 px-5 py-5">
          {error ? (
            <div className="platform-profile-error rounded-2xl px-3 py-2 text-xs font-semibold">
              <div>{error}</div>
              <button
                type="button"
                onClick={onRetry}
                className="platform-primary-button mt-3 rounded-2xl px-4 py-2 text-xs font-black"
              >
                重新加载
              </button>
            </div>
          ) : null}
          {success ? (
            <div className="platform-profile-success rounded-2xl px-3 py-2 text-xs font-semibold">
              {success}
            </div>
          ) : null}
          {isLoading ? (
            <div className="space-y-3">
              {Array.from({ length: 2 }).map((_, index) => (
                <div
                  key={index}
                  className="h-20 animate-pulse rounded-2xl bg-white/10"
                />
              ))}
            </div>
          ) : tasks.length === 0 ? (
            <div className="platform-subpanel rounded-2xl px-4 py-8 text-center text-sm font-semibold text-[var(--platform-text-soft)]">
              暂无任务
            </div>
          ) : (
            <div className="space-y-3">
              {tasks.map((task) => {
                const isClaimable = task.status === 'claimable';
                const isClaiming = claimingTaskId === task.taskId;
                const progressLabel = `${Math.min(task.progressCount, task.threshold)}/${task.threshold}`;

                return (
                  <div
                    key={task.taskId}
                    className="platform-subpanel rounded-2xl px-4 py-4"
                  >
                    <div className="flex min-w-0 items-start justify-between gap-3">
                      <div className="min-w-0">
                        <div className="text-base font-black text-[var(--platform-text-strong)]">
                          {task.title}
                        </div>
                        <div className="mt-1 text-xs font-semibold text-[var(--platform-text-soft)]">
                          {progressLabel}
                        </div>
                      </div>
                      <div className="shrink-0 text-right">
                        <div className="text-sm font-black text-[var(--platform-text-strong)]">
                          +{task.rewardPoints}
                        </div>
                        <div className="mt-1 text-[11px] font-semibold text-[var(--platform-text-soft)]">
                          {PROFILE_TASK_STATUS_LABELS[task.status]}
                        </div>
                      </div>
                    </div>
                    <button
                      type="button"
                      disabled={!isClaimable || Boolean(claimingTaskId)}
                      onClick={() => onClaim(task.taskId)}
                      className="platform-primary-button mt-3 w-full rounded-2xl px-4 py-2.5 text-sm font-black disabled:cursor-not-allowed disabled:opacity-50"
                    >
                      {isClaiming
                        ? '领取中'
                        : task.status === 'claimed'
                          ? '已领取'
                          : isClaimable
                            ? '领取'
                            : '未完成'}
                    </button>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function RewardCodeRedeemModal({
  value,
  isSubmitting,
  error,
  success,
  onChange,
  onSubmit,
  onClose,
}: {
  value: string;
  isSubmitting: boolean;
  error: string | null;
  success: string | null;
  onChange: (value: string) => void;
  onSubmit: () => void;
  onClose: () => void;
}) {
  return (
    <div className="platform-modal-backdrop fixed inset-0 z-[80] flex items-center justify-center px-4 py-6">
      <div className="platform-recharge-modal w-full max-w-sm overflow-hidden rounded-[1.4rem]">
        <div className="flex items-center justify-between border-b border-white/10 px-5 py-4">
          <div className="text-base font-black">兑换码</div>
          <button
            type="button"
            aria-label="关闭兑换码"
            onClick={onClose}
            className="platform-modal-close flex h-9 w-9 items-center justify-center rounded-full"
          >
            ×
          </button>
        </div>
        <div className="space-y-3 px-5 py-5">
          <input
            value={value}
            onChange={(event) => onChange(event.target.value)}
            onKeyDown={(event) => {
              if (event.key === 'Enter') {
                onSubmit();
              }
            }}
            className="platform-profile-input w-full rounded-2xl px-4 py-3 text-sm font-semibold uppercase tracking-normal"
            placeholder="输入兑换码"
            autoFocus
          />
          <button
            type="button"
            onClick={onSubmit}
            disabled={isSubmitting || !value.trim()}
            className="platform-primary-button w-full rounded-2xl px-4 py-3 text-sm font-black disabled:cursor-not-allowed disabled:opacity-50"
          >
            {isSubmitting ? '兑换中' : '兑换'}
          </button>
          {error ? (
            <div className="platform-profile-error rounded-2xl px-3 py-2 text-xs font-semibold">
              {error}
            </div>
          ) : null}
          {success ? (
            <div className="platform-profile-success rounded-2xl px-3 py-2 text-xs font-semibold">
              {success}
            </div>
          ) : null}
        </div>
      </div>
    </div>
  );
}

function ProfileQrScannerModal({
  error,
  result,
  onClose,
  onError,
  onResult,
}: {
  error: string | null;
  result: string | null;
  onClose: () => void;
  onError: (message: string) => void;
  onResult: (value: string) => void;
}) {
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const streamRef = useRef<MediaStream | null>(null);

  useEffect(() => {
    const videoElement = videoRef.current;
    if (!videoElement) {
      return;
    }

    let isMounted = true;
    let scanTimer: number | null = null;
    const detectorCtor = getBarcodeDetectorConstructor();
    const detector = detectorCtor
      ? new detectorCtor({ formats: ['qr_code'] })
      : null;

    const clearScanTimer = () => {
      if (scanTimer !== null) {
        window.clearTimeout(scanTimer);
        scanTimer = null;
      }
    };
    const stopCamera = () => {
      const stream = streamRef.current;
      streamRef.current = null;
      if (stream) {
        stream.getTracks().forEach((track) => track.stop());
      }
      videoElement.srcObject = null;
    };

    const scanVideo = async () => {
      if (!isMounted || !detector || videoElement.readyState < 2) {
        if (isMounted && detector) {
          scanTimer = window.setTimeout(scanVideo, PROFILE_QR_SCAN_INTERVAL_MS);
        }
        return;
      }

      try {
        const codes = await detector.detect(videoElement);
        const rawValue = codes[0]?.rawValue?.trim();
        if (rawValue) {
          clearScanTimer();
          stopCamera();
          onResult(rawValue);
          return;
        }
      } catch {
        onError('扫码识别失败，请调整二维码位置');
      }

      if (isMounted) {
        scanTimer = window.setTimeout(scanVideo, PROFILE_QR_SCAN_INTERVAL_MS);
      }
    };

    const startCamera = async () => {
      if (typeof navigator === 'undefined' || !navigator.mediaDevices?.getUserMedia) {
        onError('当前浏览器不支持摄像头扫码');
        return;
      }

      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: false,
          video: { facingMode: { ideal: 'environment' } },
        });

        if (!isMounted) {
          stream.getTracks().forEach((track) => track.stop());
          return;
        }

        streamRef.current?.getTracks().forEach((track) => track.stop());
        streamRef.current = stream;
        videoElement.srcObject = stream;
        await videoElement.play();
        if (!detector) {
          onError('当前浏览器暂不支持二维码识别');
          return;
        }
        scanTimer = window.setTimeout(scanVideo, PROFILE_QR_SCAN_INTERVAL_MS);
      } catch {
        onError('无法打开摄像头，请检查权限');
      }
    };

    void startCamera();

    return () => {
      isMounted = false;
      clearScanTimer();
      stopCamera();
    };
  }, [onError, onResult]);

  return (
    <div
      className="platform-modal-backdrop fixed inset-0 z-[80] flex items-center justify-center px-4 py-6"
      role="dialog"
      aria-modal="true"
      aria-label="扫码"
    >
      <div className="platform-qr-scanner-modal w-full max-w-sm overflow-hidden rounded-[1.4rem]">
        <div className="flex items-center justify-between border-b border-white/10 px-5 py-4">
          <div className="text-base font-black">扫码</div>
          <button
            type="button"
            aria-label="关闭扫码"
            onClick={onClose}
            className="platform-modal-close flex h-9 w-9 items-center justify-center rounded-full"
          >
            ×
          </button>
        </div>
        <div className="space-y-3 px-5 py-5">
          <div className="platform-qr-scanner-modal__viewport">
            <video
              ref={videoRef}
              className="h-full w-full object-cover"
              playsInline
              muted
            />
            <span className="platform-qr-scanner-modal__frame" />
          </div>
          {result ? (
            <div className="platform-profile-success rounded-2xl px-3 py-2 text-xs font-semibold">
              已识别：{result}
            </div>
          ) : error ? (
            <div className="platform-profile-error rounded-2xl px-3 py-2 text-xs font-semibold">
              {error}
            </div>
          ) : null}
        </div>
      </div>
    </div>
  );
}

function ProfileReferralModal({
  panel,
  center,
  isLoading,
  isSubmittingRedeem,
  redeemCode,
  error,
  success,
  onClose,
  onCopyInvite,
  onRedeemCodeChange,
  onSubmitRedeemCode,
}: {
  panel: ProfileReferralPanel;
  center: ProfileReferralInviteCenterResponse | null;
  isLoading: boolean;
  isSubmittingRedeem: boolean;
  redeemCode: string;
  error: string | null;
  success: string | null;
  onClose: () => void;
  onCopyInvite: () => void;
  onRedeemCodeChange: (value: string) => void;
  onSubmitRedeemCode: () => void;
}) {
  const title =
    panel === 'invite'
      ? '邀请好友'
      : panel === 'redeem'
        ? '填邀请码'
        : '玩家社区';
  const normalizedRedeemCode = redeemCode
    .trim()
    .replace(/[^0-9a-z]/gi, '')
    .toUpperCase();

  return (
    <div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/42 px-3 py-5">
      <div className="relative w-full max-w-[24rem] overflow-hidden rounded-[1.35rem] bg-white text-zinc-950 shadow-2xl">
        <button
          type="button"
          onClick={onClose}
          className="absolute right-3 top-2 z-10 flex h-8 w-8 items-center justify-center rounded-full text-[#ff4056]"
          aria-label={`关闭${title}`}
        >
          ×
        </button>
        <div className="px-5 pb-5 pt-4">
          <div className="text-center text-xl font-black">{title}</div>

          {panel === 'community' ? (
            <div className="mt-5 grid grid-cols-2 gap-3">
              {COMMUNITY_QR_CODES.map((qrCode) => (
                <div
                  key={qrCode.label}
                  className="rounded-xl border border-zinc-200 bg-zinc-50 p-2.5 text-center"
                >
                  <div className="aspect-square overflow-hidden rounded-lg border border-zinc-200 bg-white p-1.5">
                    <img
                      src={qrCode.src}
                      alt={qrCode.alt}
                      className="h-full w-full object-contain"
                      loading="lazy"
                      decoding="async"
                    />
                  </div>
                  <div className="mt-2 text-sm font-bold text-zinc-700">
                    {qrCode.label}
                  </div>
                </div>
              ))}
            </div>
          ) : panel === 'redeem' ? (
            isLoading ? (
              <div className="mt-5 space-y-3">
                <div className="h-12 animate-pulse rounded-xl bg-zinc-100" />
                <div className="h-11 animate-pulse rounded-xl bg-zinc-100" />
              </div>
            ) : center?.hasRedeemedCode ? (
              <div className="mt-5 rounded-xl bg-zinc-50 px-4 py-5 text-center text-sm font-semibold text-zinc-600">
                已填写邀请码
              </div>
            ) : (
              <form
                className="mt-5 space-y-3"
                onSubmit={(event) => {
                  event.preventDefault();
                  onSubmitRedeemCode();
                }}
              >
                <input
                  value={redeemCode}
                  onChange={(event) => onRedeemCodeChange(event.target.value)}
                  className="w-full rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-3 text-center text-base font-black uppercase tracking-[0.16em] text-zinc-950 outline-none focus:border-[#ff4056]"
                  placeholder="邀请码"
                  aria-label="邀请码"
                  autoComplete="off"
                  autoFocus
                />
                <button
                  type="submit"
                  disabled={isSubmittingRedeem || !normalizedRedeemCode}
                  className="flex w-full items-center justify-center rounded-xl bg-[#ff4056] px-4 py-3 text-sm font-black text-white disabled:cursor-not-allowed disabled:opacity-60"
                >
                  {isSubmittingRedeem ? '提交中' : '提交'}
                </button>
              </form>
            )
          ) : isLoading ? (
            <div className="mt-5 space-y-3">
              <div className="h-20 animate-pulse rounded-xl bg-zinc-100" />
              <div className="h-10 animate-pulse rounded-xl bg-zinc-100" />
            </div>
          ) : (
            <div className="mt-5 space-y-3">
              <div className="rounded-xl bg-zinc-50 px-4 py-4 text-center">
                <div className="text-[11px] font-bold text-zinc-500">
                  邀请码
                </div>
                <div className="mt-1 text-3xl font-black tracking-[0.16em] text-[#ff4056]">
                  {center?.inviteCode ?? '--------'}
                </div>
              </div>
              <div className="rounded-xl border border-amber-200 bg-amber-50 px-3.5 py-3 text-sm font-semibold leading-6 text-amber-900">
                <div>
                  {`邀请一个用户注册，双方都可以获得${center?.rewardPoints ?? 30}泥点。`}
                </div>
                <div>每日最多获得十次邀请奖励。</div>
              </div>
              <button
                type="button"
                onClick={onCopyInvite}
                disabled={!center?.inviteCode}
                className="flex w-full items-center justify-center gap-2 rounded-xl bg-[#ff4056] px-4 py-3 text-sm font-black text-white disabled:opacity-60"
              >
                <Copy className="h-4 w-4" />
                复制邀请
              </button>
              <div className="rounded-xl bg-zinc-50 px-3.5 py-3">
                <div className="text-xs font-black text-zinc-900">成功邀请</div>
                {center?.invitedUsers?.length ? (
                  <div className="mt-3 max-h-44 space-y-2 overflow-y-auto pr-1">
                    {center.invitedUsers.map((user) => (
                      <div
                        key={`${user.userId}-${user.boundAt}`}
                        className="flex items-center gap-3 rounded-lg bg-white px-2.5 py-2"
                      >
                        <ProfileReferralUserAvatar
                          name={user.displayName}
                          avatarUrl={user.avatarUrl}
                        />
                        <div className="min-w-0 flex-1">
                          <div className="truncate text-sm font-bold text-zinc-900">
                            {user.displayName || '玩家'}
                          </div>
                        </div>
                      </div>
                    ))}
                  </div>
                ) : (
                  <div className="mt-3 rounded-lg bg-white px-3 py-3 text-center text-xs font-semibold text-zinc-500">
                    暂无成功邀请
                  </div>
                )}
              </div>
            </div>
          )}

          {error ? (
            <div className="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">
              {error}
            </div>
          ) : null}
          {success ? (
            <div className="mt-4 rounded-xl border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-700">
              {success}
            </div>
          ) : null}
        </div>
      </div>
    </div>
  );
}

function ProfileSaveArchivesModal({
  saveEntries,
  saveError,
  isResumingSaveWorldKey,
  onClose,
  onResumeSave,
}: {
  saveEntries: ProfileSaveArchiveSummary[];
  saveError: string | null;
  isResumingSaveWorldKey: string | null;
  onClose: () => void;
  onResumeSave: (entry: ProfileSaveArchiveSummary) => void;
}) {
  return (
    <div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/48 px-3 py-5">
      <div className="relative max-h-[min(92vh,42rem)] w-full max-w-[38rem] overflow-hidden rounded-[1.35rem] bg-white text-zinc-950 shadow-2xl">
        <button
          type="button"
          onClick={onClose}
          className="absolute right-3 top-3 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white/80 text-[#ff4056] shadow-sm"
          aria-label="关闭存档"
        >
          ×
        </button>
        <div className="max-h-[min(92vh,42rem)] overflow-y-auto px-4 pb-5 pt-4 sm:px-5">
          <div className="pr-10">
            <div className="text-[10px] font-black tracking-[0.22em] text-[#ff4056]">
              SAVES
            </div>
            <div className="mt-1 text-2xl font-black">存档</div>
          </div>

          {saveError ? (
            <div className="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">
              {saveError}
            </div>
          ) : null}

          {saveEntries.length > 0 ? (
            <div className="mt-5 grid gap-3">
              {saveEntries.map((entry) => (
                <SaveArchiveCard
                  key={`${entry.worldKey}:profile-archive`}
                  entry={entry}
                  loading={isResumingSaveWorldKey === entry.worldKey}
                  onClick={() => onResumeSave(entry)}
                />
              ))}
            </div>
          ) : (
            <div className="mt-5 rounded-xl bg-zinc-50 px-4 py-5 text-center text-sm font-semibold text-zinc-500">
              暂无存档
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function ProfilePlayedWorksModal({
  stats,
  isLoading,
  error,
  saveEntries,
  saveError,
  isResumingSaveWorldKey,
  onClose,
  onOpenWork,
  onResumeSave,
}: {
  stats: ProfilePlayStatsResponse | null;
  isLoading: boolean;
  error: string | null;
  saveEntries: ProfileSaveArchiveSummary[];
  saveError: string | null;
  isResumingSaveWorldKey: string | null;
  onClose: () => void;
  onOpenWork?: (work: ProfilePlayedWorkSummary) => void;
  onResumeSave: (entry: ProfileSaveArchiveSummary) => void;
}) {
  const playedWorks = stats?.playedWorks ?? [];
  const hasArchiveEntries = saveEntries.length > 0;
  const hasPlayedWorks = playedWorks.length > 0;

  return (
    <div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/48 px-3 py-5">
      <div className="relative max-h-[min(92vh,42rem)] w-full max-w-[38rem] overflow-hidden rounded-[1.35rem] bg-white text-zinc-950 shadow-2xl">
        <button
          type="button"
          onClick={onClose}
          className="absolute right-3 top-3 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white/80 text-[#ff4056] shadow-sm"
          aria-label="关闭玩过"
        >
          ×
        </button>
        <div className="max-h-[min(92vh,42rem)] overflow-y-auto px-4 pb-5 pt-4 sm:px-5">
          <div className="pr-10">
            <div className="text-[10px] font-black tracking-[0.22em] text-[#ff4056]">
              PLAYED
            </div>
            <div className="mt-1 text-2xl font-black">玩过</div>
            <div className="mt-2 inline-flex items-center gap-2 rounded-full border border-rose-100 bg-rose-50 px-3 py-1.5 text-xs font-bold text-zinc-600">
              <Clock3 className="h-3.5 w-3.5 text-[#ff4056]" />
              <span>
                {formatTotalPlayTimeHours(stats?.totalPlayTimeMs ?? 0)}
              </span>
            </div>
          </div>

          {error ? (
            <div className="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">
              {error}
            </div>
          ) : null}
          {saveError ? (
            <div className="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">
              {saveError}
            </div>
          ) : null}

          {isLoading ? (
            <div className="mt-5 space-y-3">
              {Array.from({ length: 4 }).map((_, index) => (
                <div
                  key={index}
                  className="h-20 animate-pulse rounded-xl bg-zinc-100"
                />
              ))}
            </div>
          ) : hasArchiveEntries || hasPlayedWorks ? (
            <div className="mt-5 space-y-5">
              {hasArchiveEntries ? (
                <section>
                  <div className="mb-2 text-xs font-black text-zinc-500">
                    可继续
                  </div>
                  <div className="grid gap-3">
                    {saveEntries.map((entry) => (
                      <SaveArchiveCard
                        key={`${entry.worldKey}:played-archive`}
                        entry={entry}
                        loading={isResumingSaveWorldKey === entry.worldKey}
                        onClick={() => onResumeSave(entry)}
                      />
                    ))}
                  </div>
                </section>
              ) : null}

              {hasPlayedWorks ? (
                <section>
                  <div className="mb-2 text-xs font-black text-zinc-500">
                    玩过
                  </div>
                  <div className="space-y-3">
                    {playedWorks.map((work) => (
                      <button
                        type="button"
                        key={`${work.worldKey}:${work.lastPlayedAt}`}
                        onClick={() => onOpenWork?.(work)}
                        className="w-full rounded-2xl border border-zinc-200 bg-zinc-50 px-4 py-3 text-left transition hover:border-[#ff4056] hover:bg-white"
                      >
                        <div className="flex min-w-0 items-start justify-between gap-3">
                          <div className="min-w-0">
                            <div className="line-clamp-1 text-base font-black text-zinc-950">
                              {work.worldTitle}
                            </div>
                            {work.worldSubtitle ? (
                              <div className="mt-1 line-clamp-1 text-xs text-zinc-500">
                                {work.worldSubtitle}
                              </div>
                            ) : null}
                          </div>
                          <span className="shrink-0 rounded-full bg-rose-50 px-2.5 py-1 text-[11px] font-bold text-[#ff4056]">
                            {formatPlayedWorkType(work.worldType)}
                          </span>
                        </div>
                        <div className="mt-3 grid gap-2 text-xs text-zinc-500 sm:grid-cols-3">
                          <span className="truncate">
                            作品号 {formatPlayedWorkId(work)}
                          </span>
                          <span className="truncate">
                            最近 {formatSnapshotTime(work.lastPlayedAt)}
                          </span>
                          <span className="truncate">
                            时长{' '}
                            {formatCompactPlayTime(work.lastObservedPlayTimeMs)}
                          </span>
                        </div>
                      </button>
                    ))}
                  </div>
                </section>
              ) : null}
            </div>
          ) : (
            <div className="mt-5 rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-4 text-sm text-zinc-600">
              暂无玩过
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

export function RpgEntryHomeView({
  activeTab,
  isDesktopLayout: isDesktopLayoutProp,
  onTabChange,
  saveEntries,
  saveError,
  featuredEntries,
  latestEntries,
  myEntries,
  historyEntries,
  profileDashboard,
  isLoadingPlatform,
  isLoadingDashboard,
  isResumingSaveWorldKey,
  platformError,
  dashboardError,
  onResumeSave,
  onOpenCreateTypePicker,
  onOpenGalleryDetail,
  onOpenChildMotionDemo,
  onOpenBabyLoveDrawing,
  onOpenRecommendGalleryDetail,
  recommendRuntimeContent,
  activeRecommendEntryKey = null,
  isStartingRecommendEntry = false,
  isRecommendRuntimeReady = false,
  recommendRuntimeError = null,
  onSelectNextRecommendEntry,
  onSelectPreviousRecommendEntry,
  onLikeRecommendEntry,
  onRemixRecommendEntry,
  onOpenLibraryDetail,
  onDeleteLibraryEntry,
  deletingLibraryEntryId = null,
  onSearchPublicCode,
  isSearchingPublicCode = false,
  onOpenProfileDashboardCard,
  profilePlayStats = null,
  isProfilePlayStatsOpen = false,
  isProfilePlayStatsLoading = false,
  profilePlayStatsError = null,
  onCloseProfilePlayStats,
  onOpenPlayedWork,
  onOpenFeedback,
  onRechargeSuccess,
  profileTaskRefreshKey = 0,
  createTabContent,
  draftTabContent,
  hasUnreadDraftUpdate = false,
}: RpgEntryHomeViewProps) {
  const authUi = useAuthUi();
  const showRechargeEntry = shouldShowRechargeEntry();
  const [desktopSearchKeyword, setDesktopSearchKeyword] = useState('');
  const [mobileSearchKeyword, setMobileSearchKeyword] = useState('');
  const [activeWorkSearchKeyword, setActiveWorkSearchKeyword] = useState('');
  const [isRewardCodeOpen, setIsRewardCodeOpen] = useState(false);
  const [rewardCodeInput, setRewardCodeInput] = useState('');
  const [isSubmittingRewardCode, setIsSubmittingRewardCode] = useState(false);
  const [rewardCodeError, setRewardCodeError] = useState<string | null>(null);
  const [rewardCodeSuccess, setRewardCodeSuccess] = useState<string | null>(
    null,
  );
  const [isRechargeOpen, setIsRechargeOpen] = useState(false);
  const [rechargeCenter, setRechargeCenter] =
    useState<ProfileRechargeCenterResponse | null>(null);
  const [isLoadingRechargeCenter, setIsLoadingRechargeCenter] = useState(false);
  const [rechargeError, setRechargeError] = useState<string | null>(null);
  const [rechargePaymentResult, setRechargePaymentResult] =
    useState<RechargePaymentResult | null>(null);
  const [wechatRechargeOrderConfirmationState, setWechatRechargeOrderConfirmationState] =
    useState<WechatRechargeOrderConfirmationState | null>(null);
  const [nativeWechatPayment, setNativeWechatPayment] =
    useState<NativeWechatPaymentState | null>(null);
  const [activeRechargeTab, setActiveRechargeTab] =
    useState<RechargeTab>('points');
  const [submittingRechargeProductId, setSubmittingRechargeProductId] =
    useState<string | null>(null);
  const [isWalletLedgerOpen, setIsWalletLedgerOpen] = useState(false);
  const [walletLedger, setWalletLedger] =
    useState<ProfileWalletLedgerResponse | null>(null);
  const [walletLedgerError, setWalletLedgerError] = useState<string | null>(
    null,
  );
  const [isLoadingWalletLedger, setIsLoadingWalletLedger] = useState(false);
  const [isTaskCenterOpen, setIsTaskCenterOpen] = useState(false);
  const [taskCenter, setTaskCenter] =
    useState<ProfileTaskCenterResponse | null>(null);
  const [taskCenterError, setTaskCenterError] = useState<string | null>(null);
  const [isLoadingTaskCenter, setIsLoadingTaskCenter] = useState(false);
  const taskCenterRequestIdRef = useRef(0);
  const [claimingTaskId, setClaimingTaskId] = useState<string | null>(null);
  const [taskClaimSuccess, setTaskClaimSuccess] = useState<string | null>(null);
  const [isQrScannerOpen, setIsQrScannerOpen] = useState(false);
  const [qrScannerError, setQrScannerError] = useState<string | null>(null);
  const [qrScannerResult, setQrScannerResult] = useState<string | null>(null);
  const [profilePopupPanel, setProfilePopupPanel] =
    useState<ProfilePopupPanel | null>(null);
  const [referralCenter, setReferralCenter] =
    useState<ProfileReferralInviteCenterResponse | null>(null);
  const [isLoadingReferral, setIsLoadingReferral] = useState(false);
  const [isReferralCenterInitialized, setIsReferralCenterInitialized] =
    useState(false);
  const pendingProfileInviteCode = useMemo(
    () =>
      typeof window === 'undefined'
        ? ''
        : readProfileInviteCodeFromLocationSearch(window.location.search),
    [],
  );
  const promptedLoginForInviteQueryRef = useRef(false);
  const autoOpenedInviteQueryRef = useRef(false);
  const [referralRedeemCode, setReferralRedeemCode] = useState(
    pendingProfileInviteCode,
  );
  const [isSubmittingReferralRedeem, setIsSubmittingReferralRedeem] =
    useState(false);
  const [referralError, setReferralError] = useState<string | null>(null);
  const [referralSuccess, setReferralSuccess] = useState<string | null>(null);
  const [selectedCategoryTag, setSelectedCategoryTag] = useState<string | null>(
    null,
  );
  const [categoryKindFilter, setCategoryKindFilter] =
    useState<PlatformCategoryKindFilter>('all');
  const [categorySortMode, setCategorySortMode] =
    useState<PlatformCategorySortMode>('composite');
  const [isCategoryFilterPanelOpen, setIsCategoryFilterPanelOpen] =
    useState(false);
  const [discoverChannel, setDiscoverChannel] =
    useState<DiscoverChannel>('recommend');
  const mobileDiscoverFeedRef = useRef<HTMLElement | null>(null);
  const [mobileCenteredCardKey, setMobileCenteredCardKey] = useState<
    string | null
  >(null);
  const hasManualCategoryTagSelectionRef = useRef(false);
  const pendingPublicAuthorKeysRef = useRef<Set<string>>(new Set());
  const [publicAuthorSummariesByKey, setPublicAuthorSummariesByKey] = useState<
    Record<string, PublicUserSummary | null>
  >({});
  const [activeRankingTab, setActiveRankingTab] =
    useState<PlatformRankingTab>('hot');
  const [visitedTabs, setVisitedTabs] = useState<Set<PlatformHomeTab>>(
    () => new Set([activeTab]),
  );
  const [profileCopyState, setProfileCopyState] = useState<
    'idle' | 'copied' | 'failed'
  >('idle');
  const [activeLegalDocumentId, setActiveLegalDocumentId] =
    useState<LegalDocumentId | null>(null);
  const profileCopyResetTimerRef = useRef<number | null>(null);
  const avatarFileInputRef = useRef<HTMLInputElement | null>(null);
  const pendingWechatRechargeOrderIdRef = useRef<string | null>(null);
  const confirmingWechatRechargeOrderIdRef = useRef<string | null>(null);
  const [isNicknameModalOpen, setIsNicknameModalOpen] = useState(false);
  const [nicknameInput, setNicknameInput] = useState('');
  const [nicknameError, setNicknameError] = useState<string | null>(null);
  const [isSavingNickname, setIsSavingNickname] = useState(false);
  const [avatarSource, setAvatarSource] = useState<string | null>(null);
  const [avatarImageSize, setAvatarImageSize] = useState<{
    width: number;
    height: number;
  } | null>(null);
  const [avatarCrop, setAvatarCrop] = useState<SquareImageCropRect>({
    x: 0,
    y: 0,
    size: 1,
  });
  const [avatarError, setAvatarError] = useState<string | null>(null);
  const [isSavingAvatar, setIsSavingAvatar] = useState(false);
  const isAuthenticated = Boolean(authUi?.user);
  const edutainmentEntryEnabled = isEdutainmentEntryEnabled();
  const [fallbackDesktopLayout] = useState(getInitialPlatformDesktopLayout);
  const isDesktopLayout = isDesktopLayoutProp ?? fallbackDesktopLayout;
  const openRecommendGalleryDetail =
    onOpenRecommendGalleryDetail ?? onOpenGalleryDetail;
  const generalFeaturedEntries = useMemo(
    () => filterGeneralPublicWorks(featuredEntries),
    [featuredEntries],
  );
  const featuredShelf = useMemo(
    () => generalFeaturedEntries.slice(0, 6),
    [generalFeaturedEntries],
  );
  const generalLatestEntries = useMemo(
    () => filterGeneralPublicWorks(latestEntries),
    [latestEntries],
  );
  const allEdutainmentEntries = useMemo(
    () => filterEdutainmentPublicWorks([...featuredEntries, ...latestEntries]),
    [featuredEntries, latestEntries],
  );
  const edutainmentEntries = useMemo(
    () => (edutainmentEntryEnabled ? allEdutainmentEntries : []),
    [allEdutainmentEntries, edutainmentEntryEnabled],
  );
  const visibleDiscoverChannels = useMemo(
    () =>
      edutainmentEntryEnabled
        ? [...DISCOVER_CHANNELS, EDUTAINMENT_DISCOVER_CHANNEL]
        : DISCOVER_CHANNELS,
    [edutainmentEntryEnabled],
  );
  const categoryGroups = useMemo(
    () =>
      buildPublicCategoryGroups(generalFeaturedEntries, generalLatestEntries),
    [generalFeaturedEntries, generalLatestEntries],
  );
  const publicEntries = useMemo(
    () =>
      getPlatformPublicEntries(generalFeaturedEntries, generalLatestEntries),
    [generalFeaturedEntries, generalLatestEntries],
  );
  const allPublicEntries = useMemo(
    () => getAllPlatformPublicEntries(featuredEntries, latestEntries),
    [featuredEntries, latestEntries],
  );
  const visibleHistoryEntries = useMemo(
    () =>
      historyEntries.filter((entry) => {
        const matchedPublicWork = findPublicWorkForHistoryEntry(
          entry,
          allPublicEntries,
        );
        return !matchedPublicWork || canExposePublicWork(matchedPublicWork);
      }),
    [allPublicEntries, historyEntries],
  );
  const workSearchResults = useMemo(
    () =>
      filterPlatformWorkSearchResults(publicEntries, activeWorkSearchKeyword),
    [activeWorkSearchKeyword, publicEntries],
  );
  const getPublicEntryAuthorAvatarUrl = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      const authorLookupKey = buildPublicWorkAuthorLookupKey(entry);
      if (!authorLookupKey) {
        return null;
      }

      return (
        publicAuthorSummariesByKey[authorLookupKey]?.avatarUrl?.trim() || null
      );
    },
    [publicAuthorSummariesByKey],
  );
  const getPublicEntryAuthorSummary = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      const authorLookupKey = buildPublicWorkAuthorLookupKey(entry);
      if (!authorLookupKey) {
        return null;
      }

      return publicAuthorSummariesByKey[authorLookupKey] ?? null;
    },
    [publicAuthorSummariesByKey],
  );
  const activeCategoryGroup =
    categoryGroups.find((group) => group.tag === selectedCategoryTag) ??
    categoryGroups[0] ??
    null;
  const activeCategoryEntries = useMemo(() => {
    if (!activeCategoryGroup) {
      return [];
    }

    return sortPlatformCategoryEntries(
      activeCategoryGroup.entries.filter((entry) =>
        matchesPlatformCategoryKindFilter(entry, categoryKindFilter),
      ),
      categorySortMode,
    );
  }, [activeCategoryGroup, categoryKindFilter, categorySortMode]);
  const activeCategoryRawCount = activeCategoryGroup?.entries.length ?? 0;
  const activeCategoryFilterLabel =
    PLATFORM_CATEGORY_KIND_FILTERS.find(
      (option) => option.id === categoryKindFilter,
    )?.label ?? '全部';
  const activeCategorySortLabel =
    PLATFORM_CATEGORY_SORT_OPTIONS.find(
      (option) => option.id === categorySortMode,
    )?.label ?? '综合';
  const activeCategoryFilterCount = activeCategoryEntries.length;
  const categoryFilterApplied = categoryKindFilter !== 'all';
  const visibleTabs = useMemo<PlatformHomeTab[]>(
    () =>
      isAuthenticated
        ? ['home', 'category', 'create', 'saves', 'profile']
        : ['home', 'create', 'category'],
    [isAuthenticated],
  );
  const publicUserCode = buildPublicUserCode(authUi?.user);
  const avatarLabel = getUserAvatarLabel(authUi?.user);
  const avatarUrl = authUi?.user?.avatarUrl?.trim() || null;
  const activeLegalDocument = activeLegalDocumentId
    ? getLegalDocument(activeLegalDocumentId)
    : null;
  const remainingNarrativeCoins = profileDashboard?.walletBalance ?? 0;
  const totalPlayTime = formatTotalPlayTimeHours(
    profileDashboard?.totalPlayTimeMs ?? 0,
  );
  const playedWorkCount = profileDashboard?.playedWorldCount ?? 0;
  const profileTaskCardSummary = useMemo(
    () => buildProfileTaskCardSummary(taskCenter),
    [taskCenter],
  );
  const tabIcons: Record<
    PlatformHomeTab,
    ComponentType<{ className?: string }>
  > = isAuthenticated
    ? {
        home: Sparkles,
        category: Compass,
        create: Plus,
        saves: Pencil,
        profile: UserRound,
      }
    : {
        home: Gamepad2,
        category: Compass,
        create: Sparkles,
        saves: Pencil,
        profile: UserRound,
      };
  const tabLabels = {
    home: '推荐',
    category: '发现',
    create: '创作',
    saves: '草稿',
    profile: '我的',
  } as const;

  useEffect(() => {
    if (!visibleTabs.includes(activeTab)) {
      onTabChange(isAuthenticated ? 'home' : 'category');
    }
  }, [activeTab, isAuthenticated, onTabChange, visibleTabs]);

  useEffect(() => {
    if (
      !visibleDiscoverChannels.some((channel) => channel.id === discoverChannel)
    ) {
      setDiscoverChannel('recommend');
    }
  }, [discoverChannel, visibleDiscoverChannels]);

  useEffect(() => {
    setVisitedTabs((currentTabs) => {
      if (currentTabs.has(activeTab)) {
        return currentTabs;
      }

      const nextTabs = new Set(currentTabs);
      nextTabs.add(activeTab);
      return nextTabs;
    });
  }, [activeTab]);

  useEffect(
    () => () => {
      if (profileCopyResetTimerRef.current !== null) {
        window.clearTimeout(profileCopyResetTimerRef.current);
      }
    },
    [],
  );

  useEffect(() => {
    if (categoryGroups.length === 0) {
      setSelectedCategoryTag(null);
      hasManualCategoryTagSelectionRef.current = false;
      return;
    }

    const firstCategoryGroup = categoryGroups[0];
    const selectedCategoryGroup =
      categoryGroups.find((group) => group.tag === selectedCategoryTag) ?? null;
    if (
      firstCategoryGroup &&
      (!selectedCategoryGroup ||
        (!hasManualCategoryTagSelectionRef.current &&
          firstCategoryGroup.tag !== selectedCategoryGroup.tag))
    ) {
      setSelectedCategoryTag(firstCategoryGroup.tag);
    }
    if (
      selectedCategoryTag &&
      !categoryGroups.some((group) => group.tag === selectedCategoryTag)
    ) {
      hasManualCategoryTagSelectionRef.current = false;
    }
  }, [categoryGroups, selectedCategoryTag]);

  useEffect(() => {
    const missingAuthorKeys = [
      ...new Set(
        publicEntries
          .map(buildPublicWorkAuthorLookupKey)
          .filter((key): key is string => Boolean(key)),
      ),
    ].filter(
      (key) =>
        !(key in publicAuthorSummariesByKey) &&
        !pendingPublicAuthorKeysRef.current.has(key),
    );

    if (missingAuthorKeys.length === 0) {
      return undefined;
    }

    let cancelled = false;
    missingAuthorKeys.forEach((key) => {
      pendingPublicAuthorKeysRef.current.add(key);
    });

    // 中文注释：头像来自公开用户摘要，失败时缓存空值，避免首页滚动时反复打公开用户接口。
    void Promise.all(
      missingAuthorKeys.map(async (authorLookupKey) => {
        try {
          const author = await getPublicWorkAuthorSummary(authorLookupKey);
          return [authorLookupKey, author] as const;
        } catch {
          return [authorLookupKey, null] as const;
        } finally {
          pendingPublicAuthorKeysRef.current.delete(authorLookupKey);
        }
      }),
    ).then((results) => {
      if (cancelled) {
        return;
      }

      setPublicAuthorSummariesByKey((currentSummaries) => {
        let changed = false;
        const nextSummaries = { ...currentSummaries };

        results.forEach(([authorLookupKey, author]) => {
          if (authorLookupKey in nextSummaries) {
            return;
          }

          nextSummaries[authorLookupKey] = author;
          changed = true;
        });

        return changed ? nextSummaries : currentSummaries;
      });
    });

    return () => {
      cancelled = true;
    };
  }, [publicAuthorSummariesByKey, publicEntries]);
  const openUserSurface = () => {
    if (authUi?.user) {
      authUi.openAccountModal();
      return;
    }
    authUi?.openLoginModal();
  };

  useEffect(() => {
    if (!pendingProfileInviteCode || autoOpenedInviteQueryRef.current) {
      return;
    }

    if (!authUi?.user) {
      if (!promptedLoginForInviteQueryRef.current) {
        promptedLoginForInviteQueryRef.current = true;
        authUi?.openLoginModal();
      }
      return;
    }

    autoOpenedInviteQueryRef.current = true;
    setReferralRedeemCode(pendingProfileInviteCode);
    setReferralError(null);
    setReferralSuccess(null);
    setProfilePopupPanel('redeem');
  }, [authUi, pendingProfileInviteCode]);
  const scheduleProfileCopyStateReset = () => {
    if (profileCopyResetTimerRef.current !== null) {
      window.clearTimeout(profileCopyResetTimerRef.current);
    }
    profileCopyResetTimerRef.current = window.setTimeout(() => {
      profileCopyResetTimerRef.current = null;
      setProfileCopyState('idle');
    }, 1400);
  };
  const copyProfilePublicUserCode = () => {
    void copyTextToClipboard(publicUserCode).then((copied) => {
      setProfileCopyState(copied ? 'copied' : 'failed');
      scheduleProfileCopyStateReset();
    });
  };
  const openNicknameModal = () => {
    const user = authUi?.user;
    if (!user) {
      authUi?.openLoginModal();
      return;
    }

    setNicknameInput(user.displayName);
    setNicknameError(null);
    setIsNicknameModalOpen(true);
  };
  const submitNickname = () => {
    if (!authUi?.user || isSavingNickname) {
      return;
    }

    const validationError = validateProfileDisplayName(nicknameInput);
    if (validationError) {
      setNicknameError(validationError);
      return;
    }

    const nextName = nicknameInput.trim();
    setIsSavingNickname(true);
    setNicknameError(null);
    void updateAuthProfile({ displayName: nextName })
      .then((nextUser) => {
        authUi.setCurrentUser(nextUser);
        setIsNicknameModalOpen(false);
      })
      .catch((error: unknown) => {
        setNicknameError(
          error instanceof Error ? error.message : '昵称保存失败',
        );
      })
      .finally(() => setIsSavingNickname(false));
  };
  const openAvatarPicker = () => {
    if (!authUi?.user) {
      authUi?.openLoginModal();
      return;
    }

    setAvatarError(null);
    avatarFileInputRef.current?.click();
  };
  const handleAvatarFileChange = (file: File | null) => {
    if (avatarFileInputRef.current) {
      avatarFileInputRef.current.value = '';
    }
    if (!file) {
      return;
    }
    if (!AVATAR_ALLOWED_TYPES.has(file.type)) {
      setAvatarError('头像仅支持 jpg、png、webp');
      return;
    }
    if (file.size > AVATAR_MAX_FILE_SIZE) {
      setAvatarError('头像图片不能超过 5MB');
      return;
    }

    setAvatarError(null);
    void loadAvatarFile(file)
      .then(async (source) => {
        const imageSize = await readImageIntrinsicSize(source);
        setAvatarSource(source);
        setAvatarImageSize(imageSize);
        setAvatarCrop(buildCenteredSquareImageCropRect(imageSize));
      })
      .catch((error: unknown) => {
        setAvatarError(
          error instanceof Error ? error.message : '头像图片读取失败',
        );
      });
  };
  const updateAvatarCrop = useCallback(
    (nextCrop: SquareImageCropRect) => {
      if (!avatarImageSize) {
        return;
      }

      setAvatarCrop(clampSquareImageCropRect(avatarImageSize, nextCrop));
    },
    [avatarImageSize],
  );
  const submitAvatar = () => {
    if (
      !avatarSource ||
      !avatarImageSize ||
      avatarCrop.size <= 0 ||
      isSavingAvatar
    ) {
      return;
    }

    setIsSavingAvatar(true);
    setAvatarError(null);
    void cropAvatarImage({
      source: avatarSource,
      cropX: avatarCrop.x,
      cropY: avatarCrop.y,
      cropSize: avatarCrop.size,
    })
      .then((avatarDataUrl) => updateAuthProfile({ avatarDataUrl }))
      .then((nextUser) => {
        authUi?.setCurrentUser(nextUser);
        setAvatarSource(null);
        setAvatarImageSize(null);
      })
      .catch((error: unknown) => {
        setAvatarError(error instanceof Error ? error.message : '头像上传失败');
      })
      .finally(() => setIsSavingAvatar(false));
  };
  const loadWalletLedger = () => {
    setWalletLedgerError(null);
    setIsLoadingWalletLedger(true);
    void getRpgProfileWalletLedger()
      .then(setWalletLedger)
      .catch((error: unknown) => {
        setWalletLedger(null);
        setWalletLedgerError(
          error instanceof Error ? error.message : '读取泥点账单失败',
        );
      })
      .finally(() => setIsLoadingWalletLedger(false));
  };
  const openWalletLedgerPanel = () => {
    setIsWalletLedgerOpen(true);
    loadWalletLedger();
  };
  const loadRechargeCenter = useCallback(() => {
    setRechargeError(null);
    setIsLoadingRechargeCenter(true);
    void getRpgProfileRechargeCenter()
      .then(setRechargeCenter)
      .catch((error: unknown) => {
        setRechargeCenter(null);
        setRechargeError(
          error instanceof Error ? error.message : '读取账户充值失败',
        );
      })
      .finally(() => setIsLoadingRechargeCenter(false));
  }, []);
  const refreshRechargeState = useCallback(() => {
    loadRechargeCenter();
    setSubmittingRechargeProductId(null);
    pendingWechatRechargeOrderIdRef.current = null;
    confirmingWechatRechargeOrderIdRef.current = null;
    setWechatRechargeOrderConfirmationState(null);
    setNativeWechatPayment(null);
  }, [loadRechargeCenter]);
  const handleWechatPayResult = useCallback(() => {
    const payResult = readWechatPayResultFromHash();
    if (!payResult) {
      return false;
    }

    if (
      pendingWechatRechargeOrderIdRef.current &&
      payResult.orderId &&
      payResult.orderId !== pendingWechatRechargeOrderIdRef.current
    ) {
      return false;
    }

    if (payResult.status === 'success') {
      const orderId = payResult.orderId || pendingWechatRechargeOrderIdRef.current;
      if (!orderId) {
        clearWechatPayResultHash();
        return true;
      }
      if (confirmingWechatRechargeOrderIdRef.current === orderId) {
        clearWechatPayResultHash();
        return true;
      }
      confirmingWechatRechargeOrderIdRef.current = orderId;
      setWechatRechargeOrderConfirmationState({ orderId });
      setSubmittingRechargeProductId(null);
      setRechargePaymentResult(null);
      void confirmWechatRechargeOrderUntilSettled(orderId)
        .then((response) => {
          const isPaid = response.order.status === 'paid';
          setRechargeCenter(response.center);
          pendingWechatRechargeOrderIdRef.current = null;
          confirmingWechatRechargeOrderIdRef.current = null;
          setWechatRechargeOrderConfirmationState(null);
          setRechargePaymentResult(
            isPaid
              ? {
                  kind: 'success',
                  title: '支付成功',
                  message: '已到账，账户状态已刷新。',
                }
              : {
                  kind: 'pending',
                  title: '支付处理中',
                  message: '正在等待到账状态确认，请稍后查看余额或会员状态。',
                },
          );
          if (isPaid) {
            void onRechargeSuccess?.();
          }
          clearWechatPayResultHash();
        })
        .catch(() => {
          confirmingWechatRechargeOrderIdRef.current = null;
          setWechatRechargeOrderConfirmationState(null);
          setRechargePaymentResult({
            kind: 'pending',
            title: '支付处理中',
            message: '暂时没能确认到账状态，请稍后查看余额或会员状态。',
          });
          clearWechatPayResultHash();
        });
    } else if (payResult.status === 'cancel') {
      setRechargePaymentResult({
        kind: 'cancel',
        title: '支付已取消',
        message: '本次没有扣款，账户状态未发生变化。',
      });
      setWechatRechargeOrderConfirmationState(null);
      refreshRechargeState();
    } else {
      const detail = payResult.errorMessage
        ? `微信返回：${payResult.errorMessage}`
        : '微信支付没有完成，本次不会入账。';
      setRechargePaymentResult({
        kind: 'failed',
        title: '支付未完成',
        message: detail,
      });
      setWechatRechargeOrderConfirmationState(null);
      refreshRechargeState();
    }

    clearWechatPayResultHash();
    return true;
  }, [onRechargeSuccess, refreshRechargeState]);
  const pollWechatPayResultFromHash = useCallback(
    () => handleWechatPayResult(),
    [handleWechatPayResult],
  );
  const confirmPendingWechatRechargeOrder = useCallback(() => {
    const orderId = pendingWechatRechargeOrderIdRef.current;
    if (!orderId || confirmingWechatRechargeOrderIdRef.current === orderId) {
      return false;
    }

    confirmingWechatRechargeOrderIdRef.current = orderId;
    setWechatRechargeOrderConfirmationState({ orderId });
    setRechargePaymentResult(null);
    void confirmWechatRechargeOrderUntilSettled(orderId)
      .then((response) => {
        const isPaid = response.order.status === 'paid';
        setRechargeCenter(response.center);
        pendingWechatRechargeOrderIdRef.current = null;
        confirmingWechatRechargeOrderIdRef.current = null;
        setWechatRechargeOrderConfirmationState(null);
        setSubmittingRechargeProductId(null);
        setRechargePaymentResult(
          isPaid
            ? {
                kind: 'success',
                title: '支付成功',
                message: '已到账，账户状态已刷新。',
              }
            : {
                kind: 'pending',
                title: '支付处理中',
                message: '正在等待到账状态确认，请稍后查看余额或会员状态。',
              },
        );
        if (isPaid) {
          void onRechargeSuccess?.();
        }
      })
      .catch(() => {
        confirmingWechatRechargeOrderIdRef.current = null;
        setWechatRechargeOrderConfirmationState(null);
        setRechargePaymentResult({
          kind: 'pending',
          title: '支付处理中',
          message: '暂时没能确认到账状态，请稍后查看余额或会员状态。',
        });
      });
    return true;
  }, [onRechargeSuccess]);
  const openRechargeModal = () => {
    if (!authUi?.user) {
      authUi?.openLoginModal();
      return;
    }

    setIsRechargeOpen(true);
    loadRechargeCenter();
  };
  const openRechargeOrRewardCodeModal = () => {
    if (showRechargeEntry) {
      openRechargeModal();
      return;
    }

    openRewardCodeModal();
  };
  const buyRechargeProduct = (product: ProfileRechargeProduct) => {
    if (submittingRechargeProductId) {
      return;
    }

    const paymentChannel = resolveProfileRechargeProductPaymentChannel(
      { kind: product.kind },
      {},
    );
    setSubmittingRechargeProductId(product.productId);
    setRechargeError(null);
    setRechargePaymentResult(null);
    setWechatRechargeOrderConfirmationState(null);
    setNativeWechatPayment(null);
    void createRpgProfileRechargeOrder(product.productId, paymentChannel)
      .then(async (response) => {
        if (paymentChannel === WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_CHANNEL) {
          pendingWechatRechargeOrderIdRef.current = response.order.orderId;
          setRechargeCenter(response.center);
          await requestWechatMiniProgramPayment(
            response.wechatMiniProgramPayParams,
            response.order.orderId,
          );
          return;
        }
        if (paymentChannel === WECHAT_H5_PAYMENT_CHANNEL) {
          const h5Url = response.wechatH5Payment?.h5Url?.trim();
          if (!h5Url) {
            throw new Error('微信 H5 支付链接生成失败');
          }
          pendingWechatRechargeOrderIdRef.current = response.order.orderId;
          setRechargeCenter(response.center);
          setRechargePaymentResult({
            kind: 'pending',
            title: '正在打开微信支付',
            message: '完成支付后返回页面确认到账状态。',
          });
          redirectToPaymentUrl(h5Url);
          return;
        }
        if (paymentChannel === WECHAT_NATIVE_PAYMENT_CHANNEL) {
          const codeUrl = response.wechatNativePayment?.codeUrl?.trim();
          if (!codeUrl) {
            throw new Error('微信 Native 支付二维码生成失败');
          }
          pendingWechatRechargeOrderIdRef.current = response.order.orderId;
          setRechargeCenter(response.center);
          setNativeWechatPayment({
            orderId: response.order.orderId,
            codeUrl,
            isConfirming: false,
          });
          setSubmittingRechargeProductId(null);
          return;
        }

        throw new Error('充值支付渠道无效');
      })
      .catch((error: unknown) => {
        pendingWechatRechargeOrderIdRef.current = null;
        setNativeWechatPayment(null);
        setRechargeError(error instanceof Error ? error.message : '充值失败');
        setSubmittingRechargeProductId(null);
      });
  };
  const confirmNativeWechatPayment = useCallback(() => {
    if (!nativeWechatPayment || nativeWechatPayment.isConfirming) {
      return;
    }

    setNativeWechatPayment((current) =>
      current && current.orderId === nativeWechatPayment.orderId
        ? { ...current, isConfirming: true }
        : current,
    );
    setRechargePaymentResult({
      kind: 'pending',
      title: '正在确认支付',
      message: '正在查询微信支付到账状态。',
    });
    void confirmWechatRechargeOrderUntilSettled(nativeWechatPayment.orderId)
      .then((response) => {
        const isPaid = response.order.status === 'paid';
        setRechargeCenter(response.center);
        setRechargePaymentResult(
          isPaid
            ? {
                kind: 'success',
                title: '支付成功',
                message: '已到账，账户状态已刷新。',
              }
            : {
                kind: 'pending',
                title: '等待微信确认',
                message: '暂时没能确认到账状态，请稍后再试。',
              },
        );
        if (isPaid) {
          setNativeWechatPayment(null);
          pendingWechatRechargeOrderIdRef.current = null;
          void onRechargeSuccess?.();
        } else {
          setNativeWechatPayment((current) =>
            current && current.orderId === nativeWechatPayment.orderId
              ? { ...current, isConfirming: false }
              : current,
          );
        }
      })
      .catch(() => {
        setRechargePaymentResult({
          kind: 'pending',
          title: '等待微信确认',
          message: '暂时没能确认到账状态，请稍后再试。',
        });
        setNativeWechatPayment((current) =>
          current && current.orderId === nativeWechatPayment.orderId
            ? { ...current, isConfirming: false }
            : current,
        );
      })
      .finally(() => setSubmittingRechargeProductId(null));
  }, [nativeWechatPayment, onRechargeSuccess]);
  useEffect(() => {
    const handleHashChange = () => {
      handleWechatPayResult();
    };
    const handleResume = () => {
      if (
        typeof document !== 'undefined' &&
        document.visibilityState === 'hidden'
      ) {
        return;
      }
      if (!handleWechatPayResult()) {
        confirmPendingWechatRechargeOrder();
      }
    };

    window.addEventListener('hashchange', handleHashChange);
    window.addEventListener('focus', handleResume);
    window.addEventListener('pageshow', handleResume);
    document.addEventListener('visibilitychange', handleResume);
    handleWechatPayResult();
    return () => {
      window.removeEventListener('hashchange', handleHashChange);
      window.removeEventListener('focus', handleResume);
      window.removeEventListener('pageshow', handleResume);
      document.removeEventListener('visibilitychange', handleResume);
    };
  }, [confirmPendingWechatRechargeOrder, handleWechatPayResult]);
  useEffect(() => {
    if (!submittingRechargeProductId || wechatRechargeOrderConfirmationState) {
      return undefined;
    }

    const startedAt = Date.now();
    let timer: number | null = null;
    const pollPayResult = () => {
      if (pollWechatPayResultFromHash()) {
        return;
      }
      if (Date.now() - startedAt >= WECHAT_PAY_RESULT_RECHECK_TIMEOUT_MS) {
        return;
      }
      timer = window.setTimeout(
        pollPayResult,
        WECHAT_PAY_RESULT_RECHECK_INTERVAL_MS,
      );
    };

    timer = window.setTimeout(
      pollPayResult,
      WECHAT_PAY_RESULT_RECHECK_INTERVAL_MS,
    );
    return () => {
      if (timer !== null) {
        window.clearTimeout(timer);
      }
    };
  }, [
    pollWechatPayResultFromHash,
    submittingRechargeProductId,
    wechatRechargeOrderConfirmationState,
  ]);
  const loadTaskCenter = useCallback(() => {
    const requestId = ++taskCenterRequestIdRef.current;
    setTaskCenterError(null);
    setIsLoadingTaskCenter(true);
    void getRpgProfileTasks()
      .then((center) => {
        if (requestId === taskCenterRequestIdRef.current) {
          setTaskCenter(center);
        }
      })
      .catch((error: unknown) => {
        if (requestId !== taskCenterRequestIdRef.current) {
          return;
        }
        setTaskCenter(null);
        setTaskCenterError(
          error instanceof Error ? error.message : '读取每日任务失败',
        );
      })
      .finally(() => {
        if (requestId === taskCenterRequestIdRef.current) {
          setIsLoadingTaskCenter(false);
        }
      });
  }, []);

  useEffect(() => {
    if (activeTab !== 'profile' || !isAuthenticated) {
      taskCenterRequestIdRef.current += 1;
      setTaskCenter(null);
      setTaskCenterError(null);
      return;
    }

    loadTaskCenter();
  }, [activeTab, isAuthenticated, loadTaskCenter, profileTaskRefreshKey]);

  useEffect(() => {
    if (activeTab !== 'profile' || !isAuthenticated) {
      return undefined;
    }

    let cancelled = false;
    let timer: number | null = null;

    const scheduleNextReset = () => {
      if (cancelled) {
        return;
      }
      timer = window.setTimeout(() => {
        void refreshStoredAccessToken({ clearOnFailure: false })
          .catch(() => undefined)
          .finally(() => {
            if (cancelled) {
              return;
            }
            loadTaskCenter();
            scheduleNextReset();
          });
      }, getDelayUntilNextProfileTaskReset());
    };

    scheduleNextReset();
    return () => {
      cancelled = true;
      if (timer !== null) {
        window.clearTimeout(timer);
      }
    };
  }, [activeTab, isAuthenticated, loadTaskCenter]);

  const openTaskCenterPanel = () => {
    setIsTaskCenterOpen(true);
    setTaskClaimSuccess(null);
    if (!taskCenter) {
      loadTaskCenter();
    }
  };
  const openQrScannerPanel = () => {
    if (!authUi?.user) {
      authUi?.openLoginModal();
      return;
    }

    setQrScannerError(null);
    setQrScannerResult(null);
    setIsQrScannerOpen(true);
  };
  const loadReferralCenter = useCallback(() => {
    setIsLoadingReferral(true);
    setIsReferralCenterInitialized(false);
    void getRpgProfileReferralInviteCenter()
      .then(setReferralCenter)
      .catch((error: unknown) => {
        setReferralCenter(null);
        setReferralError(
          error instanceof Error ? error.message : '读取邀请码失败',
        );
      })
      .finally(() => {
        setIsReferralCenterInitialized(true);
        setIsLoadingReferral(false);
      });
  }, []);
  useEffect(() => {
    if (activeTab !== 'profile' || !isAuthenticated) {
      setIsReferralCenterInitialized(false);
      setReferralCenter(null);
      return;
    }

    loadReferralCenter();
  }, [activeTab, isAuthenticated, loadReferralCenter]);
  const openProfilePopupPanel = (panel: ProfileReferralPanel) => {
    setProfilePopupPanel(panel);
    setReferralError(null);
    setReferralSuccess(null);
    if (panel === 'redeem') {
      setReferralRedeemCode(pendingProfileInviteCode);
    }
    if (panel === 'community') {
      return;
    }

    if (!isReferralCenterInitialized && !isLoadingReferral) {
      loadReferralCenter();
    }
  };
  const copyInviteInfo = () => {
    if (!referralCenter?.inviteCode) {
      return;
    }

    const inviteUrl =
      typeof window === 'undefined'
        ? referralCenter.inviteLinkPath
        : new URL(referralCenter.inviteLinkPath, window.location.origin).href;
    void copyTextToClipboard(`${referralCenter.inviteCode} ${inviteUrl}`).then(
      (copied) => {
        setReferralSuccess(copied ? '已复制' : '复制失败');
      },
    );
  };
  const submitReferralRedeemCode = () => {
    const inviteCode = referralRedeemCode
      .trim()
      .replace(/[^0-9a-z]/gi, '')
      .toUpperCase();
    if (isSubmittingReferralRedeem || !inviteCode) {
      return;
    }

    setIsSubmittingReferralRedeem(true);
    setReferralError(null);
    setReferralSuccess(null);
    void redeemRpgProfileReferralInviteCode(inviteCode)
      .then((response) => {
        setReferralCenter(response.center);
        setReferralRedeemCode('');
        setReferralSuccess('已填写');
        void onRechargeSuccess?.();
      })
      .catch((error: unknown) => {
        setReferralError(
          error instanceof Error ? error.message : '填写邀请码失败',
        );
      })
      .finally(() => setIsSubmittingReferralRedeem(false));
  };
  const openRewardCodeModal = () => {
    setIsRewardCodeOpen(true);
    setRewardCodeError(null);
    setRewardCodeSuccess(null);
  };
  const submitRewardCode = () => {
    if (isSubmittingRewardCode || !rewardCodeInput.trim()) {
      return;
    }

    setIsSubmittingRewardCode(true);
    setRewardCodeError(null);
    setRewardCodeSuccess(null);
    void redeemRpgProfileRewardCode(rewardCodeInput)
      .then((response: RedeemProfileRewardCodeResponse) => {
        setRewardCodeInput('');
        setRewardCodeSuccess(`已到账 ${response.amountGranted} 泥点`);
        void onRechargeSuccess?.();
      })
      .catch((error: unknown) => {
        setRewardCodeError(error instanceof Error ? error.message : '兑换失败');
      })
      .finally(() => setIsSubmittingRewardCode(false));
  };
  const claimTaskReward = (taskId: string) => {
    if (claimingTaskId) {
      return;
    }

    setClaimingTaskId(taskId);
    setTaskCenterError(null);
    setTaskClaimSuccess(null);
    void claimRpgProfileTaskReward(taskId)
      .then((response) => {
        setTaskCenter(response.center);
        setTaskClaimSuccess(`已领取 ${response.rewardPoints} 泥点`);
        void onRechargeSuccess?.();
      })
      .catch((error: unknown) => {
        setTaskCenterError(
          error instanceof Error ? error.message : '领取任务奖励失败',
        );
      })
      .finally(() => setClaimingTaskId(null));
  };
  const clearWorkSearch = () => {
    setActiveWorkSearchKeyword('');
    setDesktopSearchKeyword('');
    setMobileSearchKeyword('');
  };
  const updateDesktopSearchKeyword = (value: string) => {
    setDesktopSearchKeyword(value);
    if (!value.trim()) {
      setActiveWorkSearchKeyword('');
    }
  };
  const updateMobileSearchKeyword = (value: string) => {
    setMobileSearchKeyword(value);
    if (!value.trim()) {
      setActiveWorkSearchKeyword('');
    }
  };
  const submitWorkSearch = (keyword: string) => {
    const trimmedKeyword = keyword.trim();
    if (!trimmedKeyword) {
      return;
    }

    // 中文注释：优先使用首页已经聚合好的公开作品读模型做模糊命中；
    // 无本地命中时继续走既有编号直达兜底，避免破坏深链搜索。
    const matchedEntries = filterPlatformWorkSearchResults(
      publicEntries,
      trimmedKeyword,
    );
    const hiddenEdutainmentMatches = filterPlatformWorkSearchResults(
      allEdutainmentEntries,
      trimmedKeyword,
    );
    if (
      matchedEntries.length > 0 &&
      isExactPublicWorkCodeSearch(matchedEntries, trimmedKeyword) &&
      onSearchPublicCode &&
      !isSearchingPublicCode
    ) {
      setActiveWorkSearchKeyword('');
      void onSearchPublicCode(trimmedKeyword);
      return;
    }

    if (matchedEntries.length > 0) {
      setActiveWorkSearchKeyword(trimmedKeyword);
      return;
    }

    if (hiddenEdutainmentMatches.length > 0) {
      setActiveWorkSearchKeyword(trimmedKeyword);
      return;
    }

    setActiveWorkSearchKeyword('');
    if (!onSearchPublicCode || isSearchingPublicCode) {
      return;
    }

    void onSearchPublicCode(trimmedKeyword);
  };
  const submitDesktopSearch = () => {
    submitWorkSearch(desktopSearchKeyword);
  };
  const submitMobileSearch = () => {
    submitWorkSearch(mobileSearchKeyword);
  };
  const cycleCategorySortMode = () => {
    const currentIndex = PLATFORM_CATEGORY_SORT_OPTIONS.findIndex(
      (option) => option.id === categorySortMode,
    );
    const nextIndex =
      currentIndex >= 0
        ? (currentIndex + 1) % PLATFORM_CATEGORY_SORT_OPTIONS.length
        : 0;
    setCategorySortMode(
      PLATFORM_CATEGORY_SORT_OPTIONS[nextIndex]?.id ?? 'composite',
    );
  };
  const desktopHeroEntry =
    featuredShelf[0] ?? generalLatestEntries[0] ?? myEntries[0] ?? null;
  const desktopHeroCover = desktopHeroEntry
    ? resolvePlatformWorldCoverImage(desktopHeroEntry)
    : null;
  const desktopHeroStripEntries = (
    featuredShelf.length > 0 ? featuredShelf : generalLatestEntries
  ).slice(0, 5);
  // 网页端保留原有宽屏布局，只把模块数据同步到移动端首页频道语义。
  const desktopRecommendEntries = useMemo(() => {
    const entryMap = new Map<string, PlatformPublicGalleryCard>();
    [...featuredShelf, ...generalLatestEntries].forEach((entry) => {
      entryMap.set(buildPublicGalleryCardKey(entry), entry);
    });

    return Array.from(entryMap.values());
  }, [featuredShelf, generalLatestEntries]);
  const desktopTodayEntries = useMemo(
    () => filterTodayPublishedEntries(generalLatestEntries),
    [generalLatestEntries],
  );
  const desktopFeaturedGrid = desktopRecommendEntries.slice(0, 4);
  const desktopCategoryGrid = activeCategoryEntries.slice(0, 6);
  const desktopLibraryPreview = myEntries.slice(0, 2);
  const recommendedFeedEntries = useMemo(() => {
    const entryMap = new Map<string, PlatformPublicGalleryCard>();
    [...featuredShelf, ...generalLatestEntries].forEach((entry) => {
      entryMap.set(buildPublicGalleryCardKey(entry), entry);
    });

    return Array.from(entryMap.values());
  }, [featuredShelf, generalLatestEntries]);
  const discoverFeedEntries = useMemo(() => {
    const entryMap = new Map<string, PlatformPublicGalleryCard>();
    const sourceEntries =
      discoverChannel === 'recommend'
        ? recommendedFeedEntries
        : filterTodayPublishedEntries(generalLatestEntries);

    sourceEntries.forEach((entry) => {
      entryMap.set(buildPublicGalleryCardKey(entry), entry);
    });

    return Array.from(entryMap.values());
  }, [discoverChannel, generalLatestEntries, recommendedFeedEntries]);
  const edutainmentFeedEntries = useMemo(() => {
    const entryMap = new Map<string, PlatformPublicGalleryCard>();
    edutainmentEntries.forEach((entry) => {
      entryMap.set(buildPublicGalleryCardKey(entry), entry);
    });

    return Array.from(entryMap.values());
  }, [edutainmentEntries]);
  const mobileFeedCarouselEnabled =
    !isDesktopLayout &&
    activeTab === 'category' &&
    (discoverChannel === 'recommend' || discoverChannel === 'today');
  useEffect(() => {
    if (!mobileFeedCarouselEnabled) {
      setMobileCenteredCardKey(null);
      return undefined;
    }

    const feedElement = mobileDiscoverFeedRef.current;
    const scrollElement = feedElement?.closest('.platform-tab-panel');
    if (!feedElement || !scrollElement) {
      setMobileCenteredCardKey(null);
      return undefined;
    }

    let frameId: number | null = null;
    const updateCenteredCard = () => {
      frameId = null;
      const cards = Array.from(
        feedElement.querySelectorAll<HTMLElement>(
          '[data-mobile-feed-card-key]',
        ),
      );
      const viewportRect = scrollElement.getBoundingClientRect();
      const viewportCenterY =
        viewportRect.top + Math.max(0, viewportRect.height) / 2;
      let closestKey: string | null = null;
      let closestDistance = Number.POSITIVE_INFINITY;

      cards.forEach((card) => {
        const cardKey = card.dataset.mobileFeedCardKey;
        if (!cardKey) {
          return;
        }

        const cardRect = card.getBoundingClientRect();
        if (
          cardRect.bottom <= viewportRect.top ||
          cardRect.top >= viewportRect.bottom
        ) {
          return;
        }

        const cardCenterY = cardRect.top + cardRect.height / 2;
        const distance = Math.abs(cardCenterY - viewportCenterY);
        if (distance < closestDistance) {
          closestDistance = distance;
          closestKey = cardKey;
        }
      });

      setMobileCenteredCardKey((current) =>
        current === closestKey ? current : closestKey,
      );
    };
    const scheduleUpdate = () => {
      if (frameId !== null) {
        return;
      }

      frameId =
        typeof window.requestAnimationFrame === 'function'
          ? window.requestAnimationFrame(updateCenteredCard)
          : window.setTimeout(updateCenteredCard, 0);
    };

    scheduleUpdate();
    scrollElement.addEventListener('scroll', scheduleUpdate, { passive: true });
    window.addEventListener('resize', scheduleUpdate);

    return () => {
      if (frameId !== null) {
        if (typeof window.cancelAnimationFrame === 'function') {
          window.cancelAnimationFrame(frameId);
        } else {
          window.clearTimeout(frameId);
        }
      }
      scrollElement.removeEventListener('scroll', scheduleUpdate);
      window.removeEventListener('resize', scheduleUpdate);
    };
  }, [
    discoverChannel,
    discoverFeedEntries,
    activeTab,
    mobileFeedCarouselEnabled,
  ]);
  const activeRankingConfig = PLATFORM_RANKING_TABS.find(
    (tab) => tab.id === activeRankingTab,
  ) as (typeof PLATFORM_RANKING_TABS)[number];
  const rankingEntries = useMemo(
    () =>
      buildPlatformRankingEntries(publicEntries, activeRankingTab).slice(0, 30),
    [activeRankingTab, publicEntries],
  );
  const activeRecommendEntry =
    recommendedFeedEntries.find(
      (entry) => buildPublicGalleryCardKey(entry) === activeRecommendEntryKey,
    ) ??
    recommendedFeedEntries[0] ??
    null;
  const activeRecommendIndex = activeRecommendEntry
    ? recommendedFeedEntries.findIndex(
        (entry) =>
          buildPublicGalleryCardKey(entry) ===
          buildPublicGalleryCardKey(activeRecommendEntry),
      )
    : -1;
  const previousRecommendEntry =
    activeRecommendIndex >= 0 && recommendedFeedEntries.length > 1
      ? recommendedFeedEntries[
          (activeRecommendIndex - 1 + recommendedFeedEntries.length) %
            recommendedFeedEntries.length
        ]
      : null;
  const nextRecommendEntry =
    activeRecommendIndex >= 0 && recommendedFeedEntries.length > 1
      ? recommendedFeedEntries[
          (activeRecommendIndex + 1) % recommendedFeedEntries.length
        ]
      : null;
  const [recommendDragOffsetY, setRecommendDragOffsetY] = useState(0);
  const [recommendDragCommitDirection, setRecommendDragCommitDirection] =
    useState<1 | -1 | null>(null);
  const [recommendShareState, setRecommendShareState] = useState<
    'idle' | 'copied' | 'failed'
  >('idle');
  const activeRecommendEntryKeyForSelection = activeRecommendEntry
    ? buildPublicGalleryCardKey(activeRecommendEntry)
    : null;
  const recommendShareResetTimerRef = useRef<number | null>(null);
  const recommendCardStageRef = useRef<HTMLDivElement | null>(null);
  const recommendDragStartRef = useRef<{
    pointerId: number;
    startY: number;
    dragging: boolean;
  } | null>(null);
  const commitRecommendDrag = useCallback(
    (direction: 1 | -1) => {
      if (recommendDragCommitDirection) {
        return;
      }

      setRecommendDragCommitDirection(direction);
      const panelHeight =
        recommendCardStageRef.current?.getBoundingClientRect().height ?? 0;
      const commitDistance = panelHeight > 0 ? panelHeight : window.innerHeight;
      setRecommendDragOffsetY(
        direction === 1 ? -commitDistance : commitDistance,
      );
      window.setTimeout(() => {
        if (direction === 1) {
          onSelectNextRecommendEntry?.(activeRecommendEntryKeyForSelection);
        } else {
          onSelectPreviousRecommendEntry?.(activeRecommendEntryKeyForSelection);
        }
        setRecommendDragOffsetY(0);
        setRecommendDragCommitDirection(null);
      }, RECOMMEND_ENTRY_COMMIT_ANIMATION_MS);
    },
    [
      activeRecommendEntryKeyForSelection,
      onSelectNextRecommendEntry,
      onSelectPreviousRecommendEntry,
      recommendDragCommitDirection,
    ],
  );
  const beginRecommendDrag = useCallback(
    (event: PointerEvent<HTMLElement>) => {
      if (
        recommendDragCommitDirection ||
        !activeRecommendEntry ||
        recommendedFeedEntries.length <= 1
      ) {
        return;
      }

      recommendDragStartRef.current = {
        pointerId: event.pointerId,
        startY: event.clientY,
        dragging: false,
      };
      event.currentTarget.setPointerCapture?.(event.pointerId);
    },
    [
      activeRecommendEntry,
      recommendDragCommitDirection,
      recommendedFeedEntries.length,
    ],
  );
  const moveRecommendDrag = useCallback((event: PointerEvent<HTMLElement>) => {
    const drag = recommendDragStartRef.current;
    if (!drag) {
      return;
    }

    const deltaY = event.clientY - drag.startY;
    drag.dragging =
      drag.dragging ||
      Math.abs(deltaY) >= RECOMMEND_ENTRY_SWIPE_THRESHOLD_PX / 2;
    if (!drag.dragging) {
      return;
    }

    event.preventDefault();
    const cardHeight =
      recommendCardStageRef.current?.getBoundingClientRect().height ?? 0;
    const dragLimit =
      cardHeight > 0 ? cardHeight : RECOMMEND_ENTRY_DRAG_LIMIT_PX;
    setRecommendDragOffsetY(Math.max(-dragLimit, Math.min(dragLimit, deltaY)));
  }, []);
  const endRecommendDrag = useCallback(
    (event: PointerEvent<HTMLElement>) => {
      const drag = recommendDragStartRef.current;
      if (!drag) {
        return;
      }

      event.currentTarget.releasePointerCapture?.(drag.pointerId);
      recommendDragStartRef.current = null;
      const deltaY = event.clientY - drag.startY;
      if (Math.abs(deltaY) < RECOMMEND_ENTRY_SWIPE_THRESHOLD_PX) {
        setRecommendDragOffsetY(0);
        return;
      }

      commitRecommendDrag(deltaY < 0 ? 1 : -1);
    },
    [commitRecommendDrag],
  );
  const cancelRecommendDrag = useCallback(
    (event: PointerEvent<HTMLElement>) => {
      const drag = recommendDragStartRef.current;
      if (drag) {
        event.currentTarget.releasePointerCapture?.(drag.pointerId);
      }
      recommendDragStartRef.current = null;
      setRecommendDragOffsetY(0);
    },
    [],
  );
  const recommendRailStyle = {
    transform: `translate3d(0, ${recommendDragOffsetY}px, 0)`,
  } satisfies CSSProperties;
  const recommendRailClassName = recommendDragCommitDirection
    ? 'platform-recommend-swipe-rail--committing'
    : recommendDragOffsetY === 0
      ? 'platform-recommend-swipe-rail--settled'
      : 'platform-recommend-swipe-rail--dragging';
  const selectNextRecommendEntry = useCallback(() => {
    if (
      isAuthenticated &&
      activeRecommendEntry &&
      recommendedFeedEntries.length > 1
    ) {
      commitRecommendDrag(1);
      return;
    }

    onSelectNextRecommendEntry?.(activeRecommendEntryKeyForSelection);
  }, [
    activeRecommendEntry,
    activeRecommendEntryKeyForSelection,
    commitRecommendDrag,
    isAuthenticated,
    onSelectNextRecommendEntry,
    recommendedFeedEntries.length,
  ]);
  useEffect(
    () => () => {
      if (recommendShareResetTimerRef.current !== null) {
        window.clearTimeout(recommendShareResetTimerRef.current);
      }
    },
    [],
  );
  useEffect(() => {
    setRecommendShareState('idle');
  }, [activeRecommendEntryKey]);
  const shareRecommendEntry = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      const publicWorkCode = resolvePlatformPublicWorkCode(entry)?.trim();
      if (!publicWorkCode) {
        setRecommendShareState('failed');
        return;
      }

      const shareText = `邀请你来玩《${entry.worldName}》\n作品号：${publicWorkCode}\n${buildPublicWorkDetailUrl(publicWorkCode)}`;
      void copyTextToClipboard(shareText).then((copied) => {
        setRecommendShareState(copied ? 'copied' : 'failed');
        if (recommendShareResetTimerRef.current !== null) {
          window.clearTimeout(recommendShareResetTimerRef.current);
        }
        recommendShareResetTimerRef.current = window.setTimeout(() => {
          recommendShareResetTimerRef.current = null;
          setRecommendShareState('idle');
        }, 1400);
      });
    },
    [],
  );
  const leadPublicEntry = featuredShelf[0] ?? generalLatestEntries[0] ?? null;
  const openLeadPublicEntry = () => {
    if (leadPublicEntry) {
      openRecommendGalleryDetail(leadPublicEntry);
      return;
    }

    onTabChange('category');
  };

  const mobileRankingPanel: ReactNode = (
    <section
      className={`${PANEL_SURFACE_CLASS} platform-ranking-panel px-4 py-3.5 sm:px-5 sm:py-4`}
    >
      <div
        className="platform-ranking-tabs flex min-w-0 gap-2 overflow-x-auto pb-1 scrollbar-hide"
        role="tablist"
        aria-label="作品排行"
      >
        {PLATFORM_RANKING_TABS.map((tab) => {
          const active = tab.id === activeRankingTab;

          return (
            <button
              key={tab.id}
              type="button"
              role="tab"
              aria-selected={active}
              onClick={() => setActiveRankingTab(tab.id)}
              className={`platform-ranking-tab shrink-0 ${active ? 'platform-ranking-tab--active' : ''}`}
            >
              {tab.label}
            </button>
          );
        })}
      </div>

      {isLoadingPlatform ? (
        <EmptyShelf text="正在读取公开作品..." />
      ) : rankingEntries.length > 0 ? (
        <div className="mt-3 grid min-w-0 gap-2.5">
          {rankingEntries.map((entry, index) => (
            <PlatformRankingItem
              key={`${buildPublicGalleryCardKey(entry)}:ranking:${activeRankingTab}`}
              entry={entry}
              rank={index + 1}
              metricLabel={activeRankingConfig.metricLabel}
              metricValue={getPlatformRankingMetricValue(
                entry,
                activeRankingTab,
              )}
              onClick={() => onOpenGalleryDetail(entry)}
            />
          ))}
        </div>
      ) : (
        <EmptyShelf text={activeRankingConfig.emptyText} />
      )}
    </section>
  );

  const mobileRecommendContent: ReactNode = (
    <div
      className={`${MOBILE_RECOMMEND_PAGE_STAGE_CLASS} platform-mobile-home-stage platform-mobile-recommend-stage`}
    >
      {platformError ? (
        <div className="rounded-2xl border border-rose-400/20 bg-rose-500/10 px-4 py-3 text-sm leading-6 text-rose-700">
          {platformError}
        </div>
      ) : null}

      {isLoadingPlatform ? (
        <section className="platform-recommend-runtime-panel">
          <div className="platform-recommend-runtime-state">
            正在读取公开作品...
          </div>
        </section>
      ) : recommendRuntimeError ? (
        <section className="platform-recommend-runtime-panel">
          <button
            type="button"
            onClick={() =>
              activeRecommendEntry
                ? openRecommendGalleryDetail(activeRecommendEntry)
                : undefined
            }
            className="platform-recommend-runtime-state platform-recommend-runtime-state--button"
          >
            {recommendRuntimeError}
          </button>
        </section>
      ) : activeRecommendEntry ? (
        <div
          ref={recommendCardStageRef}
          className="platform-recommend-swipe-stage"
        >
          <div
            className={`platform-recommend-swipe-rail ${recommendRailClassName}`}
            style={recommendRailStyle}
          >
            {previousRecommendEntry ? (
              <div className="platform-recommend-swipe-page platform-recommend-swipe-page--previous">
                <RecommendSwipeCard
                  entry={previousRecommendEntry}
                  authorAvatarUrl={getPublicEntryAuthorAvatarUrl(
                    previousRecommendEntry,
                  )}
                  authorSummary={getPublicEntryAuthorSummary(
                    previousRecommendEntry,
                  )}
                  isActive={false}
                  visual={
                    <RecommendRuntimePreviewCard
                      entry={previousRecommendEntry}
                      position="previous"
                    />
                  }
                />
              </div>
            ) : null}

            <div className="platform-recommend-swipe-page platform-recommend-swipe-page--current">
              <RecommendSwipeCard
                entry={activeRecommendEntry}
                authorAvatarUrl={getPublicEntryAuthorAvatarUrl(
                  activeRecommendEntry,
                )}
                authorSummary={getPublicEntryAuthorSummary(
                  activeRecommendEntry,
                )}
                isActive
                visual={
                  <RecommendRuntimeVisual
                    entry={activeRecommendEntry}
                    runtimeContent={recommendRuntimeContent}
                    isStarting={isStartingRecommendEntry}
                    isRuntimeReady={isRecommendRuntimeReady}
                  />
                }
                onDragPointerDown={beginRecommendDrag}
                onDragPointerMove={moveRecommendDrag}
                onDragPointerUp={endRecommendDrag}
                onDragPointerCancel={cancelRecommendDrag}
                shareState={recommendShareState}
                onLike={() => onLikeRecommendEntry?.(activeRecommendEntry)}
                onShare={() => shareRecommendEntry(activeRecommendEntry)}
                onRemix={() => onRemixRecommendEntry?.(activeRecommendEntry)}
              />
            </div>

            {nextRecommendEntry ? (
              <div className="platform-recommend-swipe-page platform-recommend-swipe-page--next">
                <RecommendSwipeCard
                  entry={nextRecommendEntry}
                  authorAvatarUrl={getPublicEntryAuthorAvatarUrl(
                    nextRecommendEntry,
                  )}
                  authorSummary={getPublicEntryAuthorSummary(
                    nextRecommendEntry,
                  )}
                  isActive={false}
                  visual={
                    <RecommendRuntimePreviewCard
                      entry={nextRecommendEntry}
                      position="next"
                    />
                  }
                />
              </div>
            ) : null}
          </div>
        </div>
      ) : (
        <section className="platform-recommend-runtime-panel">
          <EmptyShelf text="公开广场暂时还没有可展示的作品。" />
        </section>
      )}
    </div>
  );

  const mobileDiscoverContent: ReactNode = (
    <div className={`${MOBILE_DISCOVER_PAGE_STAGE_CLASS} platform-mobile-home-stage`}>
      <PublicCodeSearchBar
        value={mobileSearchKeyword}
        onChange={updateMobileSearchKeyword}
        onSubmit={submitMobileSearch}
        isSearching={isSearchingPublicCode}
      />

      {activeWorkSearchKeyword.trim() ? (
        <PlatformWorkSearchResults
          keyword={activeWorkSearchKeyword}
          entries={workSearchResults}
          onOpen={onOpenGalleryDetail}
          onClear={clearWorkSearch}
        />
      ) : (
        <>
          <div className="platform-mobile-home-channelbar flex min-w-0 gap-4 overflow-x-auto pb-1 scrollbar-hide">
            {visibleDiscoverChannels.map((channel) => {
              const active = discoverChannel === channel.id;
              return (
                <button
                  key={channel.id}
                  type="button"
                  onClick={() => setDiscoverChannel(channel.id)}
                  className={`platform-mobile-home-channel shrink-0 ${active ? 'platform-mobile-home-channel--active' : ''}`}
                >
                  {channel.label}
                </button>
              );
            })}
          </div>

          {platformError ? (
            <div className="rounded-2xl border border-rose-400/20 bg-rose-500/10 px-4 py-3 text-sm leading-6 text-rose-700">
              {platformError}
            </div>
          ) : null}

          {discoverChannel === 'ranking' ? (
            mobileRankingPanel
          ) : discoverChannel === 'category' ? (
            <section className="platform-category-list-panel">
              {isLoadingPlatform ? (
                <EmptyShelf text="正在读取公开作品..." />
              ) : categoryGroups.length > 0 && activeCategoryGroup ? (
                <>
                  <div className="platform-category-filter-row">
                    <button
                      type="button"
                      onClick={() => setIsCategoryFilterPanelOpen(true)}
                      aria-haspopup="dialog"
                      className="platform-category-filter-button"
                    >
                      <SlidersHorizontal className="h-4 w-4" />
                      <span>
                        {categoryFilterApplied
                          ? activeCategoryFilterLabel
                          : '筛选'}
                      </span>
                      <span className="platform-category-filter-button__count">
                        {activeCategoryFilterCount}
                      </span>
                    </button>
                    <span className="platform-category-filter-divider" />
                    <div className="platform-category-chip-scroll scrollbar-hide">
                      {categoryGroups.map((group) => {
                        const active = group.tag === activeCategoryGroup.tag;

                        return (
                          <button
                            key={group.tag}
                            type="button"
                            onClick={() => {
                              hasManualCategoryTagSelectionRef.current = true;
                              setSelectedCategoryTag(group.tag);
                            }}
                            className={`platform-category-chip ${active ? 'platform-category-chip--active' : ''}`}
                          >
                            {group.tag}
                          </button>
                        );
                      })}
                    </div>
                  </div>

                  <button
                    type="button"
                    onClick={cycleCategorySortMode}
                    className="platform-category-sort-button"
                  >
                    <span>按{activeCategorySortLabel}排序</span>
                    <ChevronDown className="h-3.5 w-3.5" />
                  </button>

                  {activeCategoryEntries.length > 0 ? (
                    <div className="platform-category-game-list">
                      {activeCategoryEntries.map((entry) => (
                        <PlatformCategoryGameItem
                          key={`${buildPublicGalleryCardKey(entry)}:mobile-category:${activeCategoryGroup.tag}:${categoryKindFilter}:${categorySortMode}`}
                          entry={entry}
                          categoryTag={activeCategoryGroup.tag}
                          onClick={() => onOpenGalleryDetail(entry)}
                        />
                      ))}
                    </div>
                  ) : (
                    <EmptyShelf text="当前筛选下没有作品。" />
                  )}
                </>
              ) : (
                <EmptyShelf text="公开广场暂时还没有可分类的作品。" />
              )}
            </section>
          ) : discoverChannel === 'edutainment' ? (
            <section className="platform-mobile-home-feed">
              {isLoadingPlatform ? (
                <EmptyShelf text="正在读取公开作品..." />
              ) : edutainmentFeedEntries.length > 0 ||
                onOpenChildMotionDemo ||
                onOpenBabyLoveDrawing ? (
                <div className="grid min-w-0 gap-3">
                  {edutainmentFeedEntries.map((entry) => {
                    const cardKey = buildPublicGalleryCardKey(entry);

                    return (
                      <WorldCard
                        key={`${cardKey}:mobile-edutainment`}
                        entry={entry}
                        onClick={() => onOpenGalleryDetail(entry)}
                        className="w-full"
                        authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
                        authorSummary={getPublicEntryAuthorSummary(entry)}
                        feedCardKey={cardKey}
                      />
                    );
                  })}
                  {onOpenChildMotionDemo ? (
                    <button
                      type="button"
                      className="platform-edutainment-level-card"
                      onClick={onOpenChildMotionDemo}
                    >
                      <span className="platform-edutainment-level-card__icon">
                        <Camera className="h-7 w-7" />
                      </span>
                      <span className="platform-edutainment-level-card__body">
                        <strong>{CHILD_MOTION_DEMO_DEFAULT_CARD.title}</strong>
                        <span>{CHILD_MOTION_DEMO_DEFAULT_CARD.subtitle}</span>
                      </span>
                      <span className="platform-edutainment-level-card__summary">
                        {CHILD_MOTION_DEMO_DEFAULT_CARD.summary}
                      </span>
                    </button>
                  ) : null}
                  {onOpenBabyLoveDrawing ? (
                    <button
                      type="button"
                      className="platform-edutainment-level-card"
                      onClick={onOpenBabyLoveDrawing}
                    >
                      <span className="platform-edutainment-level-card__icon">
                        <Palette className="h-7 w-7" />
                      </span>
                      <span className="platform-edutainment-level-card__body">
                        <strong>{BABY_LOVE_DRAWING_DEFAULT_CARD.title}</strong>
                        <span>{BABY_LOVE_DRAWING_DEFAULT_CARD.subtitle}</span>
                      </span>
                      <span className="platform-edutainment-level-card__summary">
                        {BABY_LOVE_DRAWING_DEFAULT_CARD.summary}
                      </span>
                    </button>
                  ) : null}
                </div>
              ) : (
                <EmptyShelf text="暂时还没有可展示的作品。" />
              )}
            </section>
          ) : (
            <section
              ref={mobileDiscoverFeedRef}
              className="platform-mobile-home-feed"
            >
              {isLoadingPlatform ? (
                <EmptyShelf text="正在读取公开作品..." />
              ) : discoverFeedEntries.length > 0 ? (
                <div className="grid min-w-0 gap-3">
                  {discoverFeedEntries.map(
                    (entry: PlatformPublicGalleryCard) => {
                      const cardKey = buildPublicGalleryCardKey(entry);

                      return (
                        <WorldCard
                          key={`${cardKey}:mobile-feed:${discoverChannel}`}
                        entry={entry}
                        onClick={() => onOpenGalleryDetail(entry)}
                        className="w-full"
                        authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
                        authorSummary={getPublicEntryAuthorSummary(entry)}
                        feedCardKey={cardKey}
                        enableCoverCarousel={mobileFeedCarouselEnabled}
                        isCoverCarouselActive={
                            mobileCenteredCardKey === cardKey
                          }
                        />
                      );
                    },
                  )}
                </div>
              ) : (
                <EmptyShelf text="公开广场暂时还没有可展示的作品。" />
              )}
            </section>
          )}
        </>
      )}
    </div>
  );

  const desktopDiscoverContent: ReactNode = (
    <div className={DESKTOP_DISCOVER_PAGE_STAGE_CLASS}>
      <div className="platform-mobile-home-channelbar flex min-w-0 gap-4 overflow-x-auto pb-1 scrollbar-hide">
        {visibleDiscoverChannels.map((channel) => {
          const active = discoverChannel === channel.id;

          return (
            <button
              key={`desktop-${channel.id}`}
              type="button"
              onClick={() => setDiscoverChannel(channel.id)}
              className={`platform-mobile-home-channel shrink-0 ${active ? 'platform-mobile-home-channel--active' : ''}`}
            >
              {channel.label}
            </button>
          );
        })}
      </div>

      {platformError ? (
        <div className="rounded-[1.5rem] border border-rose-400/20 bg-rose-500/10 px-4 py-3 text-sm leading-6 text-rose-700">
          {platformError}
        </div>
      ) : null}

      {discoverChannel === 'ranking' ? (
        mobileRankingPanel
      ) : discoverChannel === 'category' ? (
        <section className="platform-desktop-panel px-5 py-5">
          <SectionHeader title="作品分类" detail="GAME CATEGORY" />
          {isLoadingPlatform ? (
            <EmptyShelf text="正在读取作品分类..." />
          ) : activeCategoryGroup && activeCategoryRawCount > 0 ? (
            <>
              <div className="mb-4 flex min-w-0 items-center gap-2">
                <button
                  type="button"
                  onClick={() => setIsCategoryFilterPanelOpen(true)}
                  aria-haspopup="dialog"
                  className="platform-category-filter-button"
                >
                  <SlidersHorizontal className="h-4 w-4" />
                  <span>
                    {categoryFilterApplied ? activeCategoryFilterLabel : '筛选'}
                  </span>
                  <span className="platform-category-filter-button__count">
                    {activeCategoryFilterCount}
                  </span>
                </button>
                <div className="flex min-w-0 flex-1 items-center gap-2 overflow-x-auto pb-1 scrollbar-hide">
                  {categoryGroups.map((group) => {
                    const active = group.tag === activeCategoryGroup.tag;

                    return (
                      <button
                        key={`${group.tag}:desktop-discover-category`}
                        type="button"
                        onClick={() => {
                          hasManualCategoryTagSelectionRef.current = true;
                          setSelectedCategoryTag(group.tag);
                        }}
                        className={`platform-category-chip shrink-0 ${active ? 'platform-category-chip--active' : ''}`}
                      >
                        {group.tag}
                      </button>
                    );
                  })}
                </div>
                <button
                  type="button"
                  onClick={cycleCategorySortMode}
                  className="platform-category-sort-button shrink-0"
                >
                  <span>{activeCategorySortLabel}</span>
                  <ChevronDown className="h-3.5 w-3.5" />
                </button>
              </div>
              {desktopCategoryGrid.length > 0 ? (
                <div className="grid gap-4 xl:grid-cols-3">
                  {desktopCategoryGrid.map((entry) => (
                    <WorldCard
                      key={`${buildPublicGalleryCardKey(entry)}:desktop-discover-category:${activeCategoryGroup.tag}:${categoryKindFilter}:${categorySortMode}`}
                      entry={entry}
                      onClick={() => openRecommendGalleryDetail(entry)}
                      className="w-full min-w-0"
                      authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
                      authorSummary={getPublicEntryAuthorSummary(entry)}
                    />
                  ))}
                </div>
              ) : (
                <EmptyShelf text="当前筛选下没有作品。" />
              )}
            </>
          ) : (
            <EmptyShelf text="暂时还没有可分类的作品。" />
          )}
        </section>
      ) : discoverChannel === 'edutainment' ? (
        <section className="platform-desktop-panel px-5 py-5">
          <SectionHeader title={EDUTAINMENT_WORK_TAG} detail="EDUTAINMENT" />
          {isLoadingPlatform ? (
            <EmptyShelf text="正在读取公开作品..." />
          ) : edutainmentFeedEntries.length > 0 ||
            onOpenChildMotionDemo ||
            onOpenBabyLoveDrawing ? (
            <div className="grid gap-4 xl:grid-cols-3">
              {edutainmentFeedEntries.map((entry) => (
                <WorldCard
                  key={`${buildPublicGalleryCardKey(entry)}:desktop-edutainment`}
                  entry={entry}
                  onClick={() => openRecommendGalleryDetail(entry)}
                  className="w-full min-w-0"
                  authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
                  authorSummary={getPublicEntryAuthorSummary(entry)}
                />
              ))}
              {onOpenChildMotionDemo ? (
                <button
                  type="button"
                  className="platform-edutainment-level-card"
                  onClick={onOpenChildMotionDemo}
                >
                  <span className="platform-edutainment-level-card__icon">
                    <Camera className="h-7 w-7" />
                  </span>
                  <span className="platform-edutainment-level-card__body">
                    <strong>{CHILD_MOTION_DEMO_DEFAULT_CARD.title}</strong>
                    <span>{CHILD_MOTION_DEMO_DEFAULT_CARD.subtitle}</span>
                  </span>
                  <span className="platform-edutainment-level-card__summary">
                    {CHILD_MOTION_DEMO_DEFAULT_CARD.summary}
                  </span>
                </button>
              ) : null}
              {onOpenBabyLoveDrawing ? (
                <button
                  type="button"
                  className="platform-edutainment-level-card"
                  onClick={onOpenBabyLoveDrawing}
                >
                  <span className="platform-edutainment-level-card__icon">
                    <Palette className="h-7 w-7" />
                  </span>
                  <span className="platform-edutainment-level-card__body">
                    <strong>{BABY_LOVE_DRAWING_DEFAULT_CARD.title}</strong>
                    <span>{BABY_LOVE_DRAWING_DEFAULT_CARD.subtitle}</span>
                  </span>
                  <span className="platform-edutainment-level-card__summary">
                    {BABY_LOVE_DRAWING_DEFAULT_CARD.summary}
                  </span>
                </button>
              ) : null}
            </div>
          ) : (
            <EmptyShelf text="暂时还没有可展示的作品。" />
          )}
        </section>
      ) : (
        <section className="platform-desktop-panel px-5 py-5">
          <SectionHeader
            title={discoverChannel === 'today' ? '今日游戏' : '推荐'}
            detail={discoverChannel === 'today' ? 'TODAY GAMES' : 'RECOMMENDED'}
          />
          {isLoadingPlatform ? (
            <EmptyShelf text="正在读取公开作品..." />
          ) : discoverFeedEntries.length > 0 ? (
            <div className="grid gap-4 xl:grid-cols-3">
              {discoverFeedEntries.map((entry) => (
                <WorldCard
                  key={`${buildPublicGalleryCardKey(entry)}:desktop-discover-feed:${discoverChannel}`}
                  entry={entry}
                  onClick={() => openRecommendGalleryDetail(entry)}
                  className="w-full min-w-0"
                  authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
                  authorSummary={getPublicEntryAuthorSummary(entry)}
                />
              ))}
            </div>
          ) : (
            <EmptyShelf text="公开广场暂时还没有可展示的作品。" />
          )}
        </section>
      )}
    </div>
  );
  const categoryContent: ReactNode = isDesktopLayout
    ? desktopDiscoverContent
    : mobileDiscoverContent;

  const fallbackCreateStartContent: ReactNode = (
    <div className={MOBILE_PAGE_STAGE_CLASS}>
      <button
        type="button"
        onClick={onOpenCreateTypePicker}
        className={`${HERO_SURFACE_CLASS} relative block w-full overflow-hidden px-4 py-4 text-left`}
      >
        <div className="absolute inset-0 bg-[var(--platform-hero-overlay-strong)]" />
        <div className="relative z-10 flex min-h-[10rem] flex-col justify-between">
          <span className="platform-pill platform-pill--cool w-fit">
            CREATE
          </span>
          <div className="min-w-0">
            <div className="break-all text-[clamp(1.6rem,7.4vw,1.92rem)] font-black leading-tight text-white">
              开启新的创作
            </div>
            <div className="mt-2 max-w-[28rem] break-all text-sm leading-6 text-zinc-200/88">
              先选择游戏类型，再进入对应的创作工作台继续推进。
            </div>
            <div className="mt-4 flex items-center gap-2 text-sm font-semibold text-white/90">
              <span>选择类型并继续</span>
              <ArrowRight className="h-4 w-4" />
            </div>
          </div>
        </div>
      </button>
    </div>
  );

  const fallbackDraftContent: ReactNode = (
    <div className={MOBILE_PAGE_STAGE_CLASS}>
      <section>
        <SectionHeader title="我的创作" detail="草稿与已发布" />
        {platformError ? (
          <div className="rounded-2xl border border-rose-400/20 bg-rose-500/10 px-4 py-3 text-sm leading-6 text-rose-700">
            {platformError}
          </div>
        ) : null}
        {isLoadingPlatform ? (
          <EmptyShelf text="正在读取你的作品..." />
        ) : myEntries.length > 0 ? (
          <div className="grid grid-cols-2 gap-2.5 sm:gap-3 xl:grid-cols-3">
            {myEntries.map(
              (entry: CustomWorldLibraryEntry<CustomWorldProfile>) => (
                <CreationLibraryCard
                  key={`${entry.ownerUserId}:${entry.profileId}:mine`}
                  entry={entry}
                  onClick={() => onOpenLibraryDetail(entry)}
                  onDelete={
                    onDeleteLibraryEntry
                      ? () => onDeleteLibraryEntry(entry)
                      : undefined
                  }
                  isDeleting={deletingLibraryEntryId === entry.profileId}
                />
              ),
            )}
          </div>
        ) : (
          <EmptyShelf
            text={
              isAuthenticated
                ? '你还没有保存任何自定义世界，先创建一个草稿开始吧。'
                : '登录后查看你的作品。'
            }
          />
        )}
      </section>
    </div>
  );

  const createContent: ReactNode =
    createTabContent ?? fallbackCreateStartContent;

  const savesContent: ReactNode = (
    <>
      {platformError ? (
        <div className="rounded-2xl border border-rose-400/20 bg-rose-500/10 px-4 py-3 text-sm leading-6 text-rose-700">
          {platformError}
        </div>
      ) : null}
      {draftTabContent ?? fallbackDraftContent}
    </>
  );

  const profileContent: ReactNode = (
    <div className={`${MOBILE_PROFILE_PAGE_STAGE_CLASS} platform-profile-page`}>
      {authUi?.user ? (
        <>
          <section className="platform-profile-header">
            <img
              src={profileStillLifeImage}
              alt=""
              className="platform-profile-scene-decor"
            />
            <div className="platform-profile-header__identity">
              <div className="platform-profile-header__identity-row flex min-w-0 items-center gap-4">
                <button
                  type="button"
                  onClick={openAvatarPicker}
                  className="platform-profile-avatar relative h-[5.15rem] w-[5.15rem] shrink-0 rounded-full"
                  aria-label="上传头像"
                >
                  {avatarUrl ? (
                    <img
                      src={avatarUrl}
                      alt=""
                      className="h-full w-full rounded-full object-cover"
                    />
                  ) : (
                    <img
                      src={profileMascotImage}
                      alt=""
                      className="h-full w-full rounded-full object-cover"
                    />
                  )}
                  <span className="platform-profile-camera absolute bottom-0 right-0 flex h-7 w-7 items-center justify-center rounded-full">
                    <Camera className="h-3.5 w-3.5" />
                  </span>
                </button>
                <input
                  ref={avatarFileInputRef}
                  type="file"
                  aria-label="上传头像"
                  accept="image/jpeg,image/png,image/webp"
                  className="hidden"
                  onChange={(event) =>
                    handleAvatarFileChange(event.target.files?.[0] ?? null)
                  }
                />

                <div className="platform-profile-header__text min-w-0">
                  <div className="flex items-center gap-2">
                    <div className="platform-profile-header__name truncate text-[18px] font-black leading-tight text-[var(--platform-text-strong)]">
                      {authUi.user.displayName}
                    </div>
                    <button
                      type="button"
                      onClick={openNicknameModal}
                      className="platform-profile-edit-button"
                      aria-label="修改昵称"
                    >
                      <Pencil className="h-3.5 w-3.5" />
                    </button>
                  </div>
                  <div className="platform-profile-header__code mt-2 flex flex-wrap items-center gap-2 text-[12px] text-[var(--platform-text-base)]">
                    <span>陶泥号： {publicUserCode}</span>
                    <button
                      type="button"
                      onClick={copyProfilePublicUserCode}
                      className="platform-profile-copy-button"
                    >
                      {profileCopyState === 'copied'
                        ? '已复制'
                        : profileCopyState === 'failed'
                          ? '复制失败'
                          : '复制'}
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </section>

          <button
            type="button"
            onClick={openRechargeOrRewardCodeModal}
            className="platform-profile-membership-card"
            aria-label="查看权益"
          >
            <span className="platform-profile-membership-card__badge">
              <Crown className="platform-profile-membership-card__crown" />
            </span>
            <span className="min-w-0 flex-1">
              <span className="platform-profile-membership-card__title block text-[16px] font-black leading-tight text-white">
                普通用户
              </span>
              <span className="platform-profile-membership-card__subtitle mt-1.5 block text-[12px] font-medium text-white/92">
                升级会员，享专属特权与福利
              </span>
            </span>
            <span className="platform-profile-membership-card__action">
              查看权益
            </span>
          </button>

          <section className="platform-profile-stats-panel" aria-label="我的数据">
            <div className="platform-profile-stats-grid grid grid-cols-3 gap-3">
              {isLoadingDashboard ? (
                <>
                  <ProfileStatCardSkeleton />
                  <ProfileStatCardSkeleton />
                  <ProfileStatCardSkeleton />
                </>
              ) : dashboardError ? (
                <>
                  <ProfileStatCard
                    cardKey="wallet"
                    label="泥点余额"
                    value="暂不可用"
                    icon={Coins}
                    imageSrc={profilePointImage}
                    onClick={openWalletLedgerPanel}
                  />
                  <ProfileStatCard
                    cardKey="playTime"
                    label="累计游玩"
                    value="暂不可用"
                    icon={Clock3}
                    imageSrc={profileClockImage}
                    onClick={onOpenProfileDashboardCard}
                  />
                  <ProfileStatCard
                    cardKey="playedWorks"
                    label="已玩游戏"
                    value="暂不可用"
                    icon={BookOpen}
                    imageSrc={profileGamepadImage}
                    onClick={onOpenProfileDashboardCard}
                  />
                </>
              ) : (
                <>
                  <ProfileStatCard
                    cardKey="wallet"
                    label="泥点余额"
                    value={formatDashboardCount(remainingNarrativeCoins)}
                    icon={Coins}
                    imageSrc={profilePointImage}
                    onClick={openWalletLedgerPanel}
                  />
                  <ProfileStatCard
                    cardKey="playTime"
                    label="累计游玩"
                    value={totalPlayTime}
                    icon={Clock3}
                    imageSrc={profileClockImage}
                    onClick={onOpenProfileDashboardCard}
                  />
                  <ProfileStatCard
                    cardKey="playedWorks"
                    label="已玩游戏"
                    value={`${formatDashboardCount(playedWorkCount)}个`}
                    icon={BookOpen}
                    imageSrc={profileGamepadImage}
                    onClick={onOpenProfileDashboardCard}
                  />
                </>
              )}
            </div>
          </section>

          <button
            type="button"
            onClick={openTaskCenterPanel}
            className="platform-profile-daily-task-card"
          >
            <span className="min-w-0 flex-1">
              <span className="platform-profile-daily-task-card__title block text-[15px] font-black text-[var(--platform-text-strong)]">
                每日任务
              </span>
              <span className="platform-profile-daily-task-card__desc mt-2 block text-[12px] font-medium text-[var(--platform-text-base)]">
                完成任务可领取{' '}
                <span className="text-[#c45b2a]">
                  {profileTaskCardSummary.rewardPoints}
                </span>{' '}
                泥点
              </span>
              <span className="platform-profile-daily-task-card__progress mt-3 flex items-center gap-3">
                <span className="platform-profile-daily-task-card__progress-value text-[13px] font-semibold text-[#dc3f0e]">
                  {profileTaskCardSummary.progressCount} /{' '}
                  {profileTaskCardSummary.threshold}
                </span>
                <span className="platform-profile-daily-task-card__track">
                  <span
                    className="platform-profile-daily-task-card__bar"
                    style={{
                      width: `${profileTaskCardSummary.progressPercent}%`,
                    }}
                  />
                </span>
              </span>
            </span>
            <img
              src={profileMascotImage}
              alt=""
              className="platform-profile-daily-task-card__mascot"
            />
          </button>

          <section
            className="platform-profile-shortcut-panel"
            aria-label="常用功能"
          >
            <div className="platform-profile-shortcut-grid grid w-full !grid-cols-4">
              <ProfileShortcutButton
                label="泥点充值"
                subLabel="充值泥点"
                icon={Coins}
                imageSrc={profileCoinsImage}
                onClick={openRechargeOrRewardCodeModal}
              />
              <ProfileShortcutButton
                label="兑换码"
                subLabel="领取福利"
                icon={Ticket}
                imageSrc={profileGiftImage}
                onClick={openRewardCodeModal}
              />
              <ProfileShortcutButton
                label="玩家社区"
                subLabel="交流心得"
                icon={MessageCircle}
                imageSrc={profileCommunityImage}
                onClick={() => openProfilePopupPanel('community')}
              />
              <ProfileShortcutButton
                label="反馈与建议"
                subLabel="帮我们优化产品"
                icon={MessageCircle}
                imageSrc={profileFeedbackImage}
                onClick={onOpenFeedback}
              />
            </div>
          </section>

          <section className="platform-profile-settings-panel" aria-label="设置入口">
            <ProfileSettingsRow
              label="通用设置"
              icon={Settings}
              onClick={() => authUi.openSettingsModal()}
            />
          </section>

          <ProfileLegalSection onOpenDocument={setActiveLegalDocumentId} />
        </>
      ) : (
        <section className={`${PANEL_SURFACE_CLASS} px-4 py-3.5`}>
          <div className="platform-subpanel rounded-[1.35rem] px-4 py-4">
            <div className="text-base font-semibold text-[var(--platform-text-strong)]">
              尚未登录
            </div>
            <button
              type="button"
              onClick={() => authUi?.openLoginModal()}
              className="platform-button platform-button--primary mt-4"
            >
              登录
            </button>
          </div>
        </section>
      )}
    </div>
  );

  const desktopHomeContent: ReactNode = (
    <div className={DESKTOP_PAGE_STAGE_CLASS}>
      {platformError ? (
        <div className="rounded-[1.5rem] border border-rose-400/20 bg-rose-500/10 px-4 py-3 text-sm leading-6 text-rose-700">
          {platformError}
        </div>
      ) : null}

      {activeWorkSearchKeyword.trim() ? (
        <PlatformWorkSearchResults
          keyword={activeWorkSearchKeyword}
          entries={workSearchResults}
          onOpen={onOpenGalleryDetail}
          onClear={clearWorkSearch}
        />
      ) : (
        <>
          <div className="grid gap-5 xl:grid-cols-[minmax(0,1.55fr)_22rem]">
            <button
              type="button"
              onClick={openLeadPublicEntry}
              className={`${HERO_SURFACE_CLASS} relative block overflow-hidden px-7 py-6 text-left`}
            >
              {desktopHeroCover ? (
                desktopHeroEntry ? (
                  <PlatformWorkCoverArtwork
                    entry={desktopHeroEntry}
                    imageSrc={desktopHeroCover}
                    alt=""
                    className="absolute inset-0 h-full w-full object-cover opacity-34"
                  />
                ) : (
                  <ResolvedAssetBackdrop
                    src={desktopHeroCover}
                    alt=""
                    aria-hidden="true"
                    className="absolute inset-0 h-full w-full object-cover opacity-34"
                  />
                )
              ) : null}
              <div className="absolute inset-0 bg-[var(--platform-hero-overlay-strong)]" />
              <div className="relative z-10 flex min-h-[24rem] flex-col justify-between">
                <div className="flex items-start justify-between gap-4">
                  <span className="platform-pill platform-pill--warm">
                    作品
                  </span>
                  <span className="platform-pill platform-pill--neutral px-3">
                    {leadPublicEntry
                      ? describePublicGalleryCardKind(leadPublicEntry)
                      : '作品'}
                  </span>
                </div>

                <div className="max-w-[35rem]">
                  <div className="text-5xl font-semibold leading-[1.08] text-white">
                    {leadPublicEntry?.worldName ?? '浏览玩家作品'}
                  </div>
                  <div className="mt-4 text-base leading-8 text-zinc-200/86">
                    {leadPublicEntry?.summaryText ||
                      leadPublicEntry?.subtitle ||
                      '挑一个玩家作品，开始今天的游玩。'}
                  </div>
                  <div className="mt-5 inline-flex items-center gap-2 rounded-full border border-white/18 bg-white/18 px-4 py-2 text-sm font-semibold text-white/92">
                    <span>查看作品</span>
                    <ArrowRight className="h-4 w-4" />
                  </div>
                </div>

                {desktopHeroStripEntries.length > 0 ? (
                  <div className="grid gap-3 sm:grid-cols-5">
                    {desktopHeroStripEntries.map((entry, index) => {
                      const coverImage = resolvePlatformWorldCoverImage(entry);
                      const displayName = formatPlatformWorkDisplayName(
                        entry.worldName,
                      );
                      return (
                        <div
                          key={`${entry.ownerUserId}:${entry.profileId}:hero-strip`}
                          className="platform-subpanel overflow-hidden rounded-[1.15rem]"
                        >
                          <div className="relative aspect-[1.35/1] overflow-hidden">
                            {coverImage ? (
                              <PlatformWorkCoverArtwork
                                entry={entry}
                                imageSrc={coverImage}
                                alt=""
                                className="h-full w-full object-cover"
                              />
                            ) : null}
                            <div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(255,255,255,0.04),rgba(91,24,46,0.34))]" />
                          </div>
                          <div className="flex items-center gap-2 px-3 py-2 text-[11px] text-[color:color-mix(in_srgb,var(--platform-text-base)_82%,transparent)]">
                            <span className="text-[var(--platform-text-soft)]">
                              {`${index + 1}`.padStart(2, '0')}
                            </span>
                            <span className="line-clamp-1">{displayName}</span>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                ) : null}
              </div>
            </button>

            <section className="platform-desktop-panel px-5 py-5">
              <div className="mb-4 flex items-start justify-between gap-3">
                <SectionHeader title="今日游戏" detail="TODAY GAMES" />
                <span className="platform-pill platform-pill--neutral px-3">
                  TODAY
                </span>
              </div>
              {isLoadingPlatform ? (
                <EmptyShelf text="正在读取今日游戏..." />
              ) : desktopTodayEntries.length > 0 ? (
                <div className="space-y-3">
                  {desktopTodayEntries.slice(0, 3).map((entry, index) => (
                    <DesktopTrendingItem
                      key={`${buildPublicGalleryCardKey(entry)}:desktop-today`}
                      entry={entry}
                      rank={index + 1}
                      onClick={() => openRecommendGalleryDetail(entry)}
                    />
                  ))}
                </div>
              ) : (
                <EmptyShelf text="今天暂时还没有新游戏。" />
              )}
            </section>
          </div>

          <div
            className={`grid gap-5 ${desktopLibraryPreview.length > 0 || visibleHistoryEntries.length > 0 ? '2xl:grid-cols-[minmax(0,1.2fr)_minmax(22rem,0.8fr)]' : ''}`}
          >
            <section className="platform-desktop-panel px-5 py-5">
              <SectionHeader title="推荐" detail="RECOMMENDED" />
              {isLoadingPlatform ? (
                <EmptyShelf text="正在读取推荐作品..." />
              ) : desktopFeaturedGrid.length > 0 ? (
                <div className="grid gap-4 xl:grid-cols-2">
                  {desktopFeaturedGrid.map((entry) => (
                    <WorldCard
                      key={`${buildPublicGalleryCardKey(entry)}:desktop-featured`}
                      entry={entry}
                      onClick={() => openRecommendGalleryDetail(entry)}
                      className="w-full min-w-0"
                      authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
                      authorSummary={getPublicEntryAuthorSummary(entry)}
                    />
                  ))}
                </div>
              ) : (
                <EmptyShelf text="暂时还没有推荐作品。" />
              )}
            </section>

            {desktopLibraryPreview.length > 0 ||
            visibleHistoryEntries.length > 0 ? (
              <section className="platform-desktop-panel px-5 py-5">
                <SectionHeader
                  title={
                    desktopLibraryPreview.length > 0 ? '最近作品' : '最近浏览'
                  }
                  detail="QUICK ACCESS"
                />

                <div>
                  <div className="text-[10px] font-semibold tracking-[0.24em] text-[var(--platform-text-soft)]">
                    {desktopLibraryPreview.length > 0 ? '最近作品' : '最近浏览'}
                  </div>

                  {desktopLibraryPreview.length > 0 ? (
                    <div className="mt-3 space-y-3">
                      {desktopLibraryPreview.map((entry) => {
                        const displayName = formatPlatformWorkDisplayName(
                          entry.worldName,
                        );

                        return (
                          <button
                            key={`${entry.ownerUserId}:${entry.profileId}:desktop-mine`}
                            type="button"
                            onClick={() => onOpenLibraryDetail(entry)}
                            className="platform-desktop-trending-item flex w-full items-center justify-between gap-3 px-4 py-4 text-left"
                          >
                            <div className="min-w-0">
                              <div className="line-clamp-1 text-base font-semibold text-[var(--platform-text-strong)]">
                                {displayName}
                              </div>
                              <div className="mt-1 text-sm text-[var(--platform-text-soft)]">
                                {entry.visibility === 'published'
                                  ? `发布于 ${formatPlatformWorldTime(entry.publishedAt)}`
                                  : '草稿待完善'}
                              </div>
                            </div>
                            <span className="platform-pill platform-pill--neutral px-3">
                              {entry.visibility === 'published'
                                ? '已发布'
                                : '草稿'}
                            </span>
                          </button>
                        );
                      })}
                    </div>
                  ) : (
                    <div className="mt-3 space-y-3">
                      {visibleHistoryEntries.slice(0, 2).map((entry) => {
                        const displayName = formatPlatformWorkDisplayName(
                          entry.worldName,
                        );

                        return (
                          <button
                            key={`${entry.ownerUserId}:${entry.profileId}:desktop-history`}
                            type="button"
                            onClick={() =>
                              openRecommendGalleryDetail({
                                ownerUserId: entry.ownerUserId,
                                profileId: entry.profileId,
                                publicWorkCode: null,
                                authorPublicUserCode: null,
                                visibility: 'published',
                                publishedAt: entry.visitedAt,
                                updatedAt: entry.visitedAt,
                                worldName: entry.worldName,
                                subtitle: entry.subtitle,
                                summaryText: entry.summaryText,
                                coverImageSrc: entry.coverImageSrc,
                                themeMode: entry.themeMode,
                                authorDisplayName: entry.authorDisplayName,
                                playableNpcCount: 0,
                                landmarkCount: 0,
                                likeCount: 0,
                              })
                            }
                            className="platform-desktop-trending-item flex w-full items-center justify-between gap-3 px-4 py-4 text-left"
                          >
                            <div className="min-w-0">
                              <div className="line-clamp-1 text-base font-semibold text-[var(--platform-text-strong)]">
                                {displayName}
                              </div>
                              <div className="mt-1 text-sm text-[var(--platform-text-soft)]">
                                作者：{entry.authorDisplayName}
                              </div>
                            </div>
                            <span className="platform-pill platform-pill--neutral px-3">
                              浏览
                            </span>
                          </button>
                        );
                      })}
                    </div>
                  )}
                </div>
              </section>
            ) : null}
          </div>

          <section className="platform-desktop-panel px-5 py-5">
            <SectionHeader title="作品分类" detail="GAME CATEGORY" />
            {isLoadingPlatform ? (
              <EmptyShelf text="正在读取作品分类..." />
            ) : activeCategoryGroup && activeCategoryRawCount > 0 ? (
              <>
                <div className="mb-4 flex min-w-0 items-center gap-2">
                  <button
                    type="button"
                    onClick={() => setIsCategoryFilterPanelOpen(true)}
                    aria-haspopup="dialog"
                    className="platform-category-filter-button"
                  >
                    <SlidersHorizontal className="h-4 w-4" />
                    <span>
                      {categoryFilterApplied
                        ? activeCategoryFilterLabel
                        : '筛选'}
                    </span>
                    <span className="platform-category-filter-button__count">
                      {activeCategoryFilterCount}
                    </span>
                  </button>
                  <div className="flex min-w-0 flex-1 items-center gap-2 overflow-x-auto pb-1 scrollbar-hide">
                    {categoryGroups.map((group) => {
                      const active = group.tag === activeCategoryGroup.tag;

                      return (
                        <button
                          key={`${group.tag}:desktop-category`}
                          type="button"
                          onClick={() => {
                            hasManualCategoryTagSelectionRef.current = true;
                            setSelectedCategoryTag(group.tag);
                          }}
                          className={`platform-category-chip shrink-0 ${active ? 'platform-category-chip--active' : ''}`}
                        >
                          {group.tag}
                        </button>
                      );
                    })}
                  </div>
                  <button
                    type="button"
                    onClick={cycleCategorySortMode}
                    className="platform-category-sort-button shrink-0"
                  >
                    <span>{activeCategorySortLabel}</span>
                    <ChevronDown className="h-3.5 w-3.5" />
                  </button>
                </div>
                {desktopCategoryGrid.length > 0 ? (
                  <div className="grid gap-4 xl:grid-cols-3">
                    {desktopCategoryGrid.map((entry) => (
                      <WorldCard
                        key={`${buildPublicGalleryCardKey(entry)}:desktop-category:${activeCategoryGroup.tag}:${categoryKindFilter}:${categorySortMode}`}
                        entry={entry}
                        onClick={() => openRecommendGalleryDetail(entry)}
                        className="w-full min-w-0"
                        authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
                        authorSummary={getPublicEntryAuthorSummary(entry)}
                      />
                    ))}
                  </div>
                ) : (
                  <EmptyShelf text="当前筛选下没有作品。" />
                )}
              </>
            ) : (
              <EmptyShelf text="暂时还没有可分类的作品。" />
            )}
          </section>
        </>
      )}
    </div>
  );

  const tabContentById = {
    home: isDesktopLayout ? desktopHomeContent : mobileRecommendContent,
    category: categoryContent,
    create: createContent,
    saves: savesContent,
    profile: profileContent,
  } satisfies Record<PlatformHomeTab, ReactNode>;
  const tabPanels = PLATFORM_HOME_TABS.filter((tab) =>
    visibleTabs.includes(tab),
  ).map((tab) => {
    const shouldMountPanel = tab === activeTab || visitedTabs.has(tab);

    return (
      <PlatformTabPanel key={tab} tab={tab} activeTab={activeTab}>
        {shouldMountPanel ? tabContentById[tab] : null}
      </PlatformTabPanel>
    );
  });
  const profileEditModals: ReactNode = (
    <>
      {isNicknameModalOpen ? (
        <ProfileNicknameModal
          value={nicknameInput}
          error={nicknameError}
          isSaving={isSavingNickname}
          onChange={(value) => {
            setNicknameInput(value);
            setNicknameError(null);
          }}
          onClose={() => setIsNicknameModalOpen(false)}
          onSubmit={submitNickname}
        />
      ) : null}
      {avatarSource && avatarImageSize ? (
        <SquareImageCropModal
          source={avatarSource}
          imageSize={avatarImageSize}
          cropRect={avatarCrop}
          titleId="profile-avatar-crop-title"
          labels={{
            title: '裁剪头像',
            close: '关闭头像裁剪',
            editor: '头像裁剪操作区',
            previewAlt: '头像裁剪预览',
            cancel: '取消',
            submit: '上传',
            saving: '上传中',
          }}
          error={avatarError}
          isSaving={isSavingAvatar}
          onCropRectChange={updateAvatarCrop}
          onClose={() => {
            setAvatarSource(null);
            setAvatarImageSize(null);
            setAvatarError(null);
          }}
          onSubmit={submitAvatar}
        />
      ) : null}
      {avatarError && !avatarSource ? (
        <div className="pointer-events-none fixed left-1/2 top-5 z-[90] w-[min(92vw,22rem)] -translate-x-1/2 rounded-2xl border border-rose-400/25 bg-white px-4 py-3 text-center text-sm font-semibold text-rose-600 shadow-2xl">
          {avatarError}
        </div>
      ) : null}
    </>
  );
  const rewardCodeModal: ReactNode = isRewardCodeOpen ? (
    <RewardCodeRedeemModal
      value={rewardCodeInput}
      isSubmitting={isSubmittingRewardCode}
      error={rewardCodeError}
      success={rewardCodeSuccess}
      onChange={setRewardCodeInput}
      onSubmit={submitRewardCode}
      onClose={() => setIsRewardCodeOpen(false)}
    />
  ) : null;
  const rechargeModal: ReactNode = isRechargeOpen ? (
    <ProfileRechargeModal
      center={rechargeCenter}
      isLoading={isLoadingRechargeCenter}
      error={rechargeError}
      submittingProductId={submittingRechargeProductId}
      nativePayment={nativeWechatPayment}
      activeTab={activeRechargeTab}
      onTabChange={setActiveRechargeTab}
      onClose={() => setIsRechargeOpen(false)}
      onRetry={loadRechargeCenter}
      onBuy={buyRechargeProduct}
      onConfirmNativePayment={confirmNativeWechatPayment}
    />
  ) : null;
  const rechargePaymentResultModal: ReactNode = rechargePaymentResult ? (
    <RechargePaymentResultModal
      result={rechargePaymentResult}
      onClose={() => setRechargePaymentResult(null)}
    />
  ) : null;
  const rechargePaymentConfirmationMask: ReactNode =
    wechatRechargeOrderConfirmationState ? (
      <RechargePaymentConfirmationMask
        orderId={wechatRechargeOrderConfirmationState.orderId}
      />
    ) : null;
  const isRechargePaymentConfirmationPending = Boolean(
    wechatRechargeOrderConfirmationState,
  );
  const categoryFilterDialog: ReactNode = isCategoryFilterPanelOpen ? (
    <PlatformCategoryFilterDialog
      kindFilter={categoryKindFilter}
      sortMode={categorySortMode}
      resultCount={activeCategoryFilterCount}
      onKindFilterChange={setCategoryKindFilter}
      onSortModeChange={setCategorySortMode}
      onReset={() => {
        setCategoryKindFilter('all');
        setCategorySortMode('composite');
      }}
      onClose={() => setIsCategoryFilterPanelOpen(false)}
    />
  ) : null;
  const qrScannerModal: ReactNode = isQrScannerOpen ? (
    <ProfileQrScannerModal
      error={qrScannerError}
      result={qrScannerResult}
      onClose={() => {
        setIsQrScannerOpen(false);
        setQrScannerError(null);
        setQrScannerResult(null);
      }}
      onError={setQrScannerError}
      onResult={(value) => {
        setQrScannerError(null);
        setQrScannerResult(value);
      }}
    />
  ) : null;

  if (!isDesktopLayout) {
    const isMobileRecommendTab = activeTab === 'home';

    return (
      <>
        <div
          inert={isRechargePaymentConfirmationPending ? true : undefined}
          className={`platform-mobile-entry-shell ${isMobileRecommendTab ? 'platform-mobile-entry-shell--recommend' : ''} flex h-full min-h-0 min-w-0 flex-col overflow-hidden`}
        >
          {!isMobileRecommendTab ? (
            <div className="platform-mobile-topbar mb-3 flex shrink-0 items-center justify-between gap-3 px-0.5">
              <RpgEntryBrandLogo />
              {isAuthenticated && activeTab === 'profile' ? (
                <div className="flex items-center gap-2.5">
                  <button
                    type="button"
                    onClick={openQrScannerPanel}
                    className="platform-profile-header__icon-button"
                    aria-label="扫码"
                  >
                    <ScanLine className="h-5 w-5" />
                  </button>
                  <button
                    type="button"
                    onClick={() => authUi?.openSettingsModal()}
                    className="platform-profile-header__icon-button"
                    aria-label="打开设置"
                  >
                    <Settings className="h-5 w-5" />
                  </button>
                </div>
              ) : isAuthenticated &&
                (activeTab === 'create' || activeTab === 'saves') ? (
                <button
                  type="button"
                  onClick={openRechargeOrRewardCodeModal}
                  className="platform-mobile-create-wallet-chip inline-flex shrink-0 items-center gap-1.5 rounded-full border border-[#f0cfae] bg-[#fff5eb] px-2.5 py-1.5 text-xs font-black text-[#b65f2c] shadow-[0_10px_22px_rgba(174,111,73,0.12)]"
                  aria-label={`${formatDashboardCount(remainingNarrativeCoins)}泥点`}
                >
                  <span className="grid h-6 w-6 place-items-center rounded-full bg-[#ffe0ab] text-[#cf7b34]">
                    <Coins className="h-3.5 w-3.5" />
                  </span>
                  <span>{formatDashboardCount(remainingNarrativeCoins)}泥点</span>
                </button>
              ) : !isAuthenticated ? (
                <button
                  type="button"
                  onClick={openUserSurface}
                  className="platform-button platform-button--primary shrink-0 px-3 py-2 text-xs"
                >
                  <LogIn className="h-3.5 w-3.5" />
                  登录
                </button>
              ) : null}
            </div>
          ) : null}

          <div className="platform-tab-panel-stack min-w-0 flex-1">
            {tabPanels}
          </div>

          <div className="platform-mobile-bottom-dock min-w-0 shrink-0">
            <div
              className={`platform-bottom-nav grid ${visibleTabs.length === 5 ? 'grid-cols-5' : visibleTabs.length === 4 ? 'grid-cols-4' : visibleTabs.length === 3 ? 'grid-cols-3' : 'grid-cols-2'}`}
            >
              {visibleTabs.map((tab) => (
                <PlatformTabButton
                  key={tab}
                  active={activeTab === tab}
                  label={
                    activeTab === 'home' && tab === 'home'
                      ? '下一个'
                      : tabLabels[tab]
                  }
                  icon={
                    activeTab === 'home' && tab === 'home'
                      ? ChevronDown
                      : tabIcons[tab]
                  }
                  emphasized={tab === 'create'}
                  showDot={tab === 'saves' && hasUnreadDraftUpdate}
                  disabled={isRechargePaymentConfirmationPending}
                  onClick={() => {
                    if (isRechargePaymentConfirmationPending) {
                      return;
                    }
                    if (activeTab === 'home' && tab === 'home') {
                      selectNextRecommendEntry();
                      return;
                    }

                    onTabChange(tab);
                  }}
                />
              ))}
            </div>
          </div>
          {profilePopupPanel === 'saveArchives' ? (
          <ProfileSaveArchivesModal
            saveEntries={saveEntries}
            saveError={saveError}
            isResumingSaveWorldKey={isResumingSaveWorldKey}
            onClose={() => setProfilePopupPanel(null)}
            onResumeSave={onResumeSave}
          />
        ) : profilePopupPanel ? (
          <ProfileReferralModal
            panel={profilePopupPanel}
            center={referralCenter}
            isLoading={isLoadingReferral}
            isSubmittingRedeem={isSubmittingReferralRedeem}
            redeemCode={referralRedeemCode}
            error={referralError}
            success={referralSuccess}
            onClose={() => setProfilePopupPanel(null)}
            onCopyInvite={copyInviteInfo}
            onRedeemCodeChange={setReferralRedeemCode}
            onSubmitRedeemCode={submitReferralRedeemCode}
          />
        ) : null}
        {rewardCodeModal}
        {rechargeModal}
        {rechargePaymentResultModal}
        {qrScannerModal}
        {categoryFilterDialog}
        {isTaskCenterOpen ? (
          <ProfileTaskCenterModal
            center={taskCenter}
            isLoading={isLoadingTaskCenter}
            error={taskCenterError}
            success={taskClaimSuccess}
            claimingTaskId={claimingTaskId}
            fallbackBalance={remainingNarrativeCoins}
            onClose={() => setIsTaskCenterOpen(false)}
            onRetry={loadTaskCenter}
            onClaim={claimTaskReward}
          />
        ) : null}
        {isProfilePlayStatsOpen ? (
          <ProfilePlayedWorksModal
            stats={profilePlayStats}
            isLoading={isProfilePlayStatsLoading}
            error={profilePlayStatsError}
            saveEntries={saveEntries}
            saveError={saveError}
            isResumingSaveWorldKey={isResumingSaveWorldKey}
            onClose={onCloseProfilePlayStats ?? (() => undefined)}
            onOpenWork={onOpenPlayedWork}
            onResumeSave={onResumeSave}
          />
        ) : null}
        {isWalletLedgerOpen ? (
          <WalletLedgerModal
            ledger={walletLedger}
            fallbackBalance={remainingNarrativeCoins}
            isLoading={isLoadingWalletLedger}
            error={walletLedgerError}
            onClose={() => setIsWalletLedgerOpen(false)}
            onRetry={loadWalletLedger}
          />
        ) : null}
        <LegalDocumentModal
          document={activeLegalDocument}
          open={Boolean(activeLegalDocument)}
          platformTheme={authUi?.platformTheme}
          onClose={() => setActiveLegalDocumentId(null)}
        />
        {profileEditModals}
      </div>
      {rechargePaymentConfirmationMask}
      </>
    );
  }

  return (
    <>
      <div
        inert={isRechargePaymentConfirmationPending ? true : undefined}
        className="flex h-full min-h-0 flex-col"
      >
        <div className="flex h-full min-h-0 flex-col">
          <div className="platform-desktop-shell flex h-full min-h-0 flex-col p-5 xl:p-6">
            <div className="platform-desktop-topbar flex items-center gap-4 px-5 py-4">
              <div className="flex min-w-0 flex-1 items-center gap-5">
                <RpgEntryBrandLogo className="shrink-0" decorative />
                <PublicCodeSearchBar
                  value={desktopSearchKeyword}
                  onChange={updateDesktopSearchKeyword}
                  onSubmit={submitDesktopSearch}
                  isSearching={
                    !onSearchPublicCode || Boolean(isSearchingPublicCode)
                  }
                  className="max-w-[34rem] flex-1"
                />
              </div>

              <div className="flex items-center gap-3">
                {isAuthenticated &&
                (activeTab === 'create' || activeTab === 'saves') ? (
                  <button
                    type="button"
                    onClick={openRechargeOrRewardCodeModal}
                    className="platform-desktop-create-wallet-chip platform-desktop-search inline-flex items-center gap-2 px-3 py-2.5 text-xs font-black text-[#b65f2c]"
                    aria-label={`${formatDashboardCount(remainingNarrativeCoins)}泥点`}
                  >
                    <span className="grid h-7 w-7 place-items-center rounded-full bg-[#ffe0ab] text-[#cf7b34]">
                      <Coins className="h-3.5 w-3.5" />
                    </span>
                    <span>{formatDashboardCount(remainingNarrativeCoins)}泥点</span>
                  </button>
                ) : null}
                <button
                  type="button"
                  onClick={openUserSurface}
                  className="platform-desktop-search flex items-center gap-3 px-3 py-2.5 text-left"
                >
                  <span
                    className="flex h-11 w-11 items-center justify-center overflow-hidden rounded-full text-base font-black text-white"
                    style={{
                      background: 'var(--platform-profile-avatar-fill)',
                      boxShadow: 'var(--platform-profile-avatar-shadow)',
                    }}
                  >
                    {avatarUrl ? (
                      <img
                        src={avatarUrl}
                        alt=""
                        className="h-full w-full object-cover"
                      />
                    ) : (
                      avatarLabel
                    )}
                  </span>
                  <span className="min-w-0">
                    <span className="block truncate text-sm font-semibold text-[var(--platform-text-strong)]">
                      {authUi?.user?.displayName || '登录'}
                    </span>
                    <span className="block truncate text-xs text-[var(--platform-text-soft)]">
                      {authUi?.user ? publicUserCode : '账号入口'}
                    </span>
                  </span>
                </button>
              </div>
            </div>

            <div className="mt-5 flex min-h-0 gap-5">
              <aside className="platform-desktop-rail flex w-[5.8rem] shrink-0 flex-col gap-3 p-3">
                {visibleTabs.map((tab) => (
                  <DesktopTabButton
                    key={tab}
                    active={activeTab === tab}
                    label={tabLabels[tab]}
                    icon={tabIcons[tab]}
                    emphasized={tab === 'create'}
                    showDot={tab === 'saves' && hasUnreadDraftUpdate}
                    disabled={isRechargePaymentConfirmationPending}
                    onClick={() => {
                      if (isRechargePaymentConfirmationPending) {
                        return;
                      }
                      onTabChange(tab);
                    }}
                  />
                ))}
              </aside>

              <div className="platform-tab-panel-stack min-w-0 flex-1">
                {tabPanels}
              </div>
            </div>
          </div>
        </div>
      </div>
      {rewardCodeModal}
      {rechargeModal}
      {rechargePaymentResultModal}
      {categoryFilterDialog}
      {isTaskCenterOpen ? (
        <ProfileTaskCenterModal
          center={taskCenter}
          isLoading={isLoadingTaskCenter}
          error={taskCenterError}
          success={taskClaimSuccess}
          claimingTaskId={claimingTaskId}
          fallbackBalance={remainingNarrativeCoins}
          onClose={() => setIsTaskCenterOpen(false)}
          onRetry={loadTaskCenter}
          onClaim={claimTaskReward}
        />
      ) : null}
      {profilePopupPanel === 'saveArchives' ? (
        <ProfileSaveArchivesModal
          saveEntries={saveEntries}
          saveError={saveError}
          isResumingSaveWorldKey={isResumingSaveWorldKey}
          onClose={() => setProfilePopupPanel(null)}
          onResumeSave={onResumeSave}
        />
      ) : profilePopupPanel ? (
        <ProfileReferralModal
          panel={profilePopupPanel}
          center={referralCenter}
          isLoading={isLoadingReferral}
          isSubmittingRedeem={isSubmittingReferralRedeem}
          redeemCode={referralRedeemCode}
          error={referralError}
          success={referralSuccess}
          onClose={() => setProfilePopupPanel(null)}
          onCopyInvite={copyInviteInfo}
          onRedeemCodeChange={setReferralRedeemCode}
          onSubmitRedeemCode={submitReferralRedeemCode}
        />
      ) : null}
      {isProfilePlayStatsOpen ? (
        <ProfilePlayedWorksModal
          stats={profilePlayStats}
          isLoading={isProfilePlayStatsLoading}
          error={profilePlayStatsError}
          saveEntries={saveEntries}
          saveError={saveError}
          isResumingSaveWorldKey={isResumingSaveWorldKey}
          onClose={onCloseProfilePlayStats ?? (() => undefined)}
          onOpenWork={onOpenPlayedWork}
          onResumeSave={onResumeSave}
        />
      ) : null}
      {isWalletLedgerOpen ? (
        <WalletLedgerModal
          ledger={walletLedger}
          fallbackBalance={remainingNarrativeCoins}
          isLoading={isLoadingWalletLedger}
          error={walletLedgerError}
          onClose={() => setIsWalletLedgerOpen(false)}
          onRetry={loadWalletLedger}
        />
      ) : null}
      <LegalDocumentModal
        document={activeLegalDocument}
        open={Boolean(activeLegalDocument)}
        platformTheme={authUi?.platformTheme}
        onClose={() => setActiveLegalDocumentId(null)}
      />
      {profileEditModals}
      {rechargePaymentConfirmationMask}
    </>
  );
}

export const PlatformHomeView = RpgEntryHomeView;
