<template>
  <view class="fortune-wrap">
    <view class="bg">
      <view class="bg-base" />
      <view class="bg-texture" />
      <view class="bg-glow bg-glow-a" />
      <view class="bg-glow bg-glow-b" />
      <view v-for="star in stars" :key="star.id" class="bg-star" :style="{
        top: star.top,
        left: star.left,
        width: star.size + 'px',
        height: star.size + 'px',
        animationDuration: star.duration + 's',
        animationDelay: star.delay + 's'
      }" />
    </view>

    <view class="header">
      <view class="header-left" @click="emit('back')">
        <text class="header-back">‹</text>
      </view>
      <view class="header-mid">
        <text class="header-title">{{ props.data?.header?.title || '商业运势批复' }}</text>
        <text class="header-subtitle">{{ props.data?.header?.subtitle || 'Business Fortune Report' }}</text>
      </view>
      <view class="header-right">
        <view class="header-icon" @click="handleDownloadPdf">
          <text class="header-icon-text">↓</text>
        </view>
      </view>
    </view>

    <scroll-view scroll-x class="tabs" show-scrollbar="false">
      <view class="tabs-inner">
        <view v-for="t in tabList" :key="t.id" class="tab" :class="{ active: activeTab === t.id }"
          @click="activeTab = t.id">
          <view class="tab-icon-wrap">
            <text class="tab-icon">{{ t.icon }}</text>
            <view v-if="t.locked" class="tab-lock-dot"><text class="tab-lock-dot-text">锁</text></view>
          </view>
          <text class="tab-label">{{ t.label }}</text>
          <view v-if="activeTab === t.id" class="tab-indicator" />
        </view>
      </view>
    </scroll-view>

    <view class="content-area">
      <scroll-view scroll-y class="content">
        <view class="content-inner">
          <!-- 通用section/node渲染器 -->
          <view v-if="!shouldShowLockOverlay" class="stack">
            <!-- 有数据时显示内容 -->
            <view v-if="activeSections.length > 0">
              <view v-for="(section, sectionIndex) in activeSections" :key="sectionIndex" class="card">
                <view v-if="section.title" class="section-title">
                  <view class="bar" />
                  <view>
                    <text class="section-title-text">{{ section.title }}</text>
                    <text v-if="section.subtitle" class="section-subtitle">{{ section.subtitle }}</text>
                  </view>
                </view>

                <view v-for="(node, nodeIndex) in section.nodes" :key="nodeIndex" class="node-container">
                  <!-- KV节点 -->
                  <view v-if="node.type === 'kv'" class="kv">
                    <view v-for="(item, itemIndex) in node.items" :key="itemIndex" class="kv-row">
                      <text class="muted">{{ item.label }}</text>
                      <text class="serif">{{ item.value }}</text>
                    </view>
                  </view>

                  <!-- 文本节点 -->
                  <view v-else-if="node.type === 'text'" class="box-dark">
                    <text class="tiny muted lh">{{ node.text }}</text>
                  </view>

                  <!-- 列表节点 -->
                  <view v-else-if="node.type === 'list'" class="box-dark">
                    <view v-for="(item, itemIndex) in node.items" :key="itemIndex" class="list-item">
                      <text class="tiny muted">• {{ item }}</text>
                    </view>
                  </view>
                </view>
              </view>
            </view>

            <!-- 无数据时显示占位内容 -->
            <view v-else class="card">
              <view class="section-title">
                <view class="bar" />
                <view>
                  <text class="section-title-text">数据加载中</text>
                  <text class="section-subtitle">Loading...</text>
                </view>
              </view>
              <view class="box-dark">
                <text class="tiny muted">正在获取您的商业运势数据，请稍候...</text>
              </view>
            </view>
          </view>

          <view class="bottom-spacer" />
        </view>
      </scroll-view>

      <!-- 通用锁定浮层 -->
      <view v-if="shouldShowLockOverlay && activeLockInfo" class="lock-overlay">
        <view class="lock-card">
          <view class="lock-circle"><text class="lock-circle-text">锁</text></view>
          <text class="lock-h">{{ activeLockInfo.title }}</text>
          <view class="lock-p">
            <text class="lock-p-text">解锁后获取精准指导</text>
            <text class="lock-p-sub">助企业把握商机，规避风险</text>
          </view>
          <view class="lock-cta" @click="unlockActiveTab"><text class="lock-cta-text">立即解锁 ¥{{ activeLockInfo.price }}</text></view>
        </view>
      </view>
    </view>

    <!-- 详情弹窗 -->
    <view v-if="showDetailModal" class="detail-modal-overlay" @click.stop="closeDetailModal">
      <view class="detail-modal" @click.stop>
        <view class="detail-modal-head">
          <text class="detail-modal-title">{{ detailModalTitle }}</text>
          <view class="detail-modal-close" @click="closeDetailModal"><text class="detail-modal-close-text">×</text></view>
        </view>
        <scroll-view scroll-y class="detail-modal-body">
          <view class="detail-modal-content">
            <text v-for="(line, i) in detailModalLines" :key="i" class="detail-modal-text">{{ line }}</text>
          </view>
        </scroll-view>
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { checkAllWealthUnlockStatus } from '@/utils/wealth-payment';
import { paymentApi, userApi } from '@/api';
import { HIDE_RECHARGE_FEATURE } from '@/utils/feature-flags';
import pdfBgUrl from "../../utils/pdf/background.png";

const APPID = 'wx1ca1ac7ad12123ac';
const CBF_PENDING_KEY = 'wx_cbf_pending';

function getUrlCode(): string | null {
    let search = window.location.search;
    if (search === '' && window.location.hash.indexOf('?') > -1) {
        search = '?' + (window.location.hash.split('?')[1] || '');
    }
    if (!search) return null;
    const r = search.substr(1).match(/(^|&)code=([^&]*)(&|$)/);
    return r ? decodeURIComponent(r[2]) : null;
}
function cleanCodeFromUrl() {
    try { const url = new URL(window.location.href); if (url.searchParams.has('code')) { url.searchParams.delete('code'); url.searchParams.delete('state'); window.history.replaceState(null, '', url.toString()); } } catch {}
}
function isWechat(): boolean { return /MicroMessenger/i.test(navigator.userAgent); }

declare const uni: any;

const props = defineProps<{
  data?: any;
}>();

const emit = defineEmits<{
  back: [];
}>();

const activeTab = ref('destiny');
const isMonthUnlocked = ref(false);
const isDayUnlocked = ref(false);
const accountRemainQuota = ref<number | null>(null);

// 背景星星
const stars = Array.from({ length: 30 }, (_, i) => ({
  id: i,
  top: Math.random() * 100 + '%',
  left: Math.random() * 100 + '%',
  size: Math.random() * 2 + 1,
  duration: Math.random() * 3 + 2,
  delay: Math.random() * 2
}));

// Tab图标映射
const tabIconMap: Record<string, string> = {
  destiny: '商',
  year: '运',
  month: '月',
  day: '日',
  fengshui: '风'
};

// 从props.data解析的tabs数据
const dataTabs = computed(() => {
  const tabs = props.data?.tabs;
  if (!Array.isArray(tabs)) return [];
  return tabs;
});

// Tab列表（含icon和lock状态）
const tabList = computed(() => {
  return dataTabs.value.map((t: any) => ({
    id: t.id,
    label: t.label,
    icon: tabIconMap[t.id] || t.id.charAt(0),
    locked: t.id === 'month' ? (t.locked && !isMonthUnlocked.value) : t.id === 'day' ? (t.locked && !isDayUnlocked.value) : false
  }));
});

// 当前激活tab的数据
const activeTabData = computed(() => {
  return dataTabs.value.find((t: any) => t.id === activeTab.value) || null;
});

// 当前激活tab的sections
const activeSections = computed(() => {
  return activeTabData.value?.sections || [];
});

// 当前tab是否处于锁定状态
const isActiveTabLocked = computed(() => {
  if (activeTab.value === 'month' && !isMonthUnlocked.value && activeTabData.value?.locked) return true;
  if (activeTab.value === 'day' && !isDayUnlocked.value && activeTabData.value?.locked) return true;
  return false;
});
const isQuotaZero = computed(() => Number(accountRemainQuota.value) === 0);
const rechargeFeatureVisible = computed(() => HIDE_RECHARGE_FEATURE !== true);
const isRechargeTargetTab = computed(() => activeTab.value === 'month' || activeTab.value === 'day');
const shouldShowLockOverlay = computed(() =>
  rechargeFeatureVisible.value && isRechargeTargetTab.value && isQuotaZero.value && isActiveTabLocked.value
);

// 当前tab的锁定信息
const activeLockInfo = computed(() => {
  const lock = activeTabData.value?.lock || {};
  const fallbackPrice = Number((props.data as any)?.unlock_price);
  return {
    title: lock?.title || (activeTab.value === 'month' ? '企业商运-月度详批' : '企业商运-每日运程'),
    price: String(lock?.price ?? (Number.isFinite(fallbackPrice) && fallbackPrice > 0 ? fallbackPrice : 19.9)),
  };
});

// 支付解锁当前tab
const unlockActiveTab = async () => {
  if (!isQuotaZero.value) {
    uni.showToast({ title: '当前额度大于0，无需充值', icon: 'none' });
    return;
  }
  const tabData = activeTabData.value;
  const lockInfo = activeLockInfo.value;
  
  if (!tabData || !lockInfo) {
    uni.showToast({ title: '解锁信息不完整', icon: 'none' });
    return;
  }

  const reportId = props.data?.id;
  if (!reportId) {
    uni.showToast({ title: '报告ID不存在', icon: 'none' });
    return;
  }

  if (!isWechat()) {
    uni.showToast({ title: '请在微信中打开', icon: 'none' });
    return;
  }

  const price = parseFloat(lockInfo.price);
  const unlockType = activeTab.value === 'month' ? 'monthly' : 'daily';
  const desc = activeTab.value === 'month' ? '企业商运-月度详批' : '企业商运-每日运程';

  const code = getUrlCode();
  if (!code) {
    try { localStorage.setItem(CBF_PENDING_KEY, JSON.stringify({ tab: activeTab.value, reportId, unlockType, ts: Date.now() })); } catch {}
    const redirectUri = encodeURIComponent(window.location.href);
    window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${APPID}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`;
    return;
  }

  cleanCodeFromUrl();
  try { localStorage.removeItem(CBF_PENDING_KEY); } catch {}

  try {
    uni.showLoading({ title: '创建订单中...' });
    const orderRes = await paymentApi.createOrder({
      description: desc,
      total_amount: price,
      business_type: 'wealth_analysis',
      business_id: reportId,
      pay_type: 'jsapi',
      code,
    });
    uni.hideLoading();

    if (!orderRes?.appId || !orderRes?.paySign) {
      uni.showToast({ title: '获取支付参数失败', icon: 'none' });
      return;
    }

    const pp = orderRes;
    await new Promise<void>((resolve) => {
      const invoke = () => {
        (window as any).WeixinJSBridge.invoke('getBrandWCPayRequest', {
          appId: pp.appId, timeStamp: pp.timeStamp, nonceStr: pp.nonceStr,
          package: pp.package, signType: pp.signType || 'RSA', paySign: pp.paySign,
        }, (res: any) => {
          if (res.err_msg === 'get_brand_wcpay_request:ok') {
            uni.showToast({ title: '支付成功', icon: 'success' });
            if (activeTab.value === 'month') isMonthUnlocked.value = true;
            else if (activeTab.value === 'day') isDayUnlocked.value = true;
            uni.setStorageSync(`wealth_unlock_${unlockType}_${reportId}`, true);
          } else {
            uni.showToast({ title: res.err_msg === 'get_brand_wcpay_request:cancel' ? '已取消' : '支付失败', icon: 'none' });
          }
          resolve();
        });
      };
      if (typeof (window as any).WeixinJSBridge === 'undefined') {
        document.addEventListener('WeixinJSBridgeReady', invoke, false);
      } else {
        invoke();
      }
    });
  } catch (error: any) {
    uni.hideLoading();
    uni.showToast({ title: error.msg || '创建订单失败', icon: 'none' });
  }
};

// 刷新解锁后的内容
const refreshUnlockedContent = async () => {
  try {
    // 这里可以重新调用API获取解锁后的详细数据
    // 暂时只显示解锁成功的提示
    setTimeout(() => {
      uni.showToast({ 
        title: '解锁成功！请查看详细内容', 
        icon: 'success',
        duration: 2000
      });
    }, 500);
  } catch (error) {
    console.error('刷新解锁内容失败:', error);
  }
};

// 检查本地存储的解锁状态
const checkUnlockStatus = () => {
  const reportId = props.data?.id;
  if (reportId) {
    const unlockStatus = checkAllWealthUnlockStatus(reportId);
    
    if (unlockStatus.monthly) isMonthUnlocked.value = true;
    if (unlockStatus.daily) isDayUnlocked.value = true;
  }
};

const loadMyQuota = async () => {
  try {
    const quotaRes: any = await userApi.getMyMembershipQuota({ clearAuthOnError: false, showError: false });
    const freeRename = Number(quotaRes?.free_rename_quota);
    const remainRaw = quotaRes?.remaining_quota ?? quotaRes?.remain_quota ?? quotaRes?.left_quota;
    const remainFallback = Number(remainRaw);
    const remain = Number.isFinite(freeRename) ? freeRename : remainFallback;
    accountRemainQuota.value = Number.isFinite(remain) ? remain : 0;
  } catch {
    accountRemainQuota.value = null;
  }
};

// 组件挂载时检查解锁状态
onMounted(async () => {
  checkUnlockStatus();
  await loadMyQuota();
});

// 详情弹窗
const showDetailModal = ref(false);
const detailModalTitle = ref('');
const detailModalLines = ref<string[]>([]);

const closeDetailModal = () => {
  showDetailModal.value = false;
  detailModalTitle.value = '';
  detailModalLines.value = [];
};

const handleDownloadPdf = async () => {
  if (typeof window === "undefined" || typeof document === "undefined") return;
  uni.showLoading({ title: "正在生成PDF..." });

  const escapeHtml = (s: string) =>
    s
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#39;");
  const toStr = (v: any) => String(v ?? "").trim();
  const arr = (v: any) => (Array.isArray(v) ? v : []);
  const uniqueLines = (lines: string[]) => {
    const seen = new Set<string>();
    const out: string[] = [];
    lines.forEach((line) => {
      const v = toStr(line);
      if (!v || seen.has(v)) return;
      seen.add(v);
      out.push(v);
    });
    return out;
  };
  const flattenDetailNodes = (nodes: any[]): string[] => {
    const out: string[] = [];
    for (const n of nodes) {
      if (!n || typeof n !== "object") continue;
      if (n.type === "text" && toStr(n.text)) out.push(toStr(n.text));
      if (n.type === "list") {
        arr(n.items).forEach((it: any) => {
          const s = toStr(it);
          if (s) out.push(`· ${s}`);
        });
      }
      if (n.type === "kv") {
        arr(n.items).forEach((it: any) => {
          const k = toStr(it?.label);
          const v = toStr(it?.value);
          if (k || v) out.push(`${k}：${v}`);
        });
      }
    }
    return out;
  };
  const excludeKeys = new Set([
    "id", "report_id", "reportId", "created_at", "updated_at", "createdAt", "updatedAt",
    "ts", "timestamp",
    "is_unlocked", "unlock_price", "locked", "lock", "price",
  ]);
  const noisyKeys = new Set(["details", "nodes", "type", "meta", "status", "code", "raw"]);
  const keyLabelMap: Record<string, string> = {
    title: "标题",
    subtitle: "副标题",
    summary: "概述",
    advice: "建议",
    score: "评分",
    trend: "趋势",
    name: "名称",
    company_name: "企业名称",
    wealth_score: "财运评分",
    wealth_level: "财运等级",
    wealth_trend: "财运趋势",
    yuedo_xiangpi: "月度详批",
    yuedu_xiangpi: "月度详批",
    is_unlocked: "解锁状态",
    unlock_price: "解锁价格",
    price: "价格",
    section: "章节",
    sections: "内容",
    lock: "解锁",
    label: "标签",
    value: "内容",
    nodes: "内容",
    text: "说明",
    items: "条目",
  };
  const prettyKey = (k: string): string => {
    if (keyLabelMap[k]) return keyLabelMap[k];
    if (/^[a-z0-9_]+$/i.test(k)) return "";
    return k;
  };
  const flattenAnyToLines = (val: any, depth = 0): string[] => {
    if (depth > 6 || val === null || val === undefined) return [];
    if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
      const s = toStr(val);
      return s ? [s] : [];
    }
    if (Array.isArray(val)) return val.flatMap((it) => flattenAnyToLines(it, depth + 1));
    if (typeof val === "object") {
      const out: string[] = [];
      Object.keys(val).forEach((k) => {
        if (excludeKeys.has(k) || noisyKeys.has(k)) return;
        const label = prettyKey(k);
        const child = flattenAnyToLines((val as any)[k], depth + 1);
        child.forEach((line) => out.push(label ? `${label}：${line}` : line));
      });
      return out;
    }
    return [];
  };

  try {
    const raw = props.data || {};
    const tabs = Array.isArray(raw?.tabs) ? raw.tabs : [];
    const moduleList: Array<{ title: string; lines: string[] }> = [];
    const push = (title: string, lines: string[]) => {
      const l = uniqueLines(lines);
      if (!l.length) return;
      moduleList.push({ title, lines: l });
    };

    tabs.forEach((tab: any) => {
      const title = toStr(tab?.label || tab?.id || "章节");
      const sections = Array.isArray(tab?.sections) ? tab.sections : [];
      const lines: string[] = [];
      sections.forEach((sec: any) => {
        const secTitle = toStr(sec?.title);
        const secSub = toStr(sec?.subtitle);
        if (secTitle) lines.push(`【${secTitle}${secSub ? ` · ${secSub}` : ""}】`);
        const nodes = Array.isArray(sec?.nodes) ? sec.nodes : [];
        nodes.forEach((node: any) => {
          if (node?.type === "kv") {
            arr(node?.items).forEach((it: any) => {
              const k = toStr(it?.label);
              const v = toStr(it?.value);
              if (k || v) lines.push(`${k}：${v}`);
            });
          } else if (node?.type === "text") {
            const t = toStr(node?.text);
            if (t) lines.push(t);
          } else if (node?.type === "list") {
            arr(node?.items).forEach((it: any) => {
              const s = toStr(it);
              if (s) lines.push(`· ${s}`);
            });
          } else {
            lines.push(...flattenAnyToLines(node));
          }
        });
      });
      if (!lines.length) lines.push(...flattenAnyToLines(tab));
      push(title, lines);
    });

    // 兜底补充：接口根级其他字段
    Object.keys(raw || {}).forEach((k) => {
      if (excludeKeys.has(k) || k === "tabs") return;
      const v = (raw as any)[k];
      const lines = uniqueLines([
        ...(v && typeof v === "object" ? flattenDetailNodes(arr(v?.details?.nodes)) : []),
        ...flattenAnyToLines(v),
      ]);
      if (!lines.length) return;
      push(prettyKey(k) || "其他信息", lines);
    });

    if (!moduleList.length) {
      uni.showToast({ title: "暂无可导出的报告内容", icon: "none" });
      return;
    }

    const [{ jsPDF }, html2canvasMod] = await Promise.all([import("jspdf"), import("html2canvas")]);
    const html2canvas = (html2canvasMod as any).default || (html2canvasMod as any);
    const PAGE_W = 794;
    const PAGE_H = 1123;
    const MAX_LINES = 42;
    const wrappedLineCost = (line: string) => {
      const t = toStr(line);
      if (!t) return 1;
      return Math.max(1, Math.ceil(t.length / 30));
    };
    const splitByLines = (lines: string[], max: number) => {
      const res: string[][] = [];
      let bucket: string[] = [];
      let cost = 0;
      lines.forEach((line) => {
        const lc = wrappedLineCost(line);
        if (bucket.length && cost + lc > max) {
          res.push(bucket);
          bucket = [];
          cost = 0;
        }
        bucket.push(line);
        cost += lc;
      });
      if (bucket.length) res.push(bucket);
      return res.length ? res : [[]];
    };

    const styleId = "pdf-gen-company-fortune-style";
    let style = document.getElementById(styleId) as HTMLStyleElement | null;
    if (!style) {
      style = document.createElement("style");
      style.id = styleId;
      document.head.appendChild(style);
    }
    style.textContent = `
      .pdf-gen-page{position:absolute;width:${PAGE_W}px;height:${PAGE_H}px;background-size:cover;background-position:center;font-family:"Songti SC","SimSun","STSong","Noto Serif SC",serif;color:#f2e6d8;}
      .pdf-gen-panel{position:absolute;left:48px;right:48px;top:116px;bottom:92px;background:rgba(10,10,15,.62);border:1px solid rgba(212,175,55,.38);border-radius:16px;padding:30px 28px;box-sizing:border-box;overflow:hidden;}
      .pdf-cover-kicker{text-align:center;font-size:12px;letter-spacing:.28em;color:rgba(212,175,55,.72);margin-bottom:12px;}
      .pdf-cover-title{text-align:center;font-size:25px;letter-spacing:.16em;font-weight:700;color:rgba(212,175,55,.95);margin-bottom:22px;}
      .pdf-name{text-align:center;font-size:46px;font-weight:800;margin-bottom:14px;color:rgba(242,230,216,.98);}
      .pdf-cover-divider{width:210px;height:1px;margin:22px auto 18px;background:linear-gradient(90deg,rgba(212,175,55,0),rgba(212,175,55,.7),rgba(212,175,55,0));}
      .pdf-cover-seal{width:66px;height:66px;margin:26px auto 0;border-radius:50%;border:1px solid rgba(212,175,55,.34);display:flex;align-items:center;justify-content:center;color:rgba(212,175,55,.92);font-size:20px;}
      .pdf-dir-title{font-size:20px;font-weight:800;letter-spacing:.14em;color:rgba(212,175,55,.95);margin-bottom:12px;}
      .pdf-dir-kicker{font-size:11px;letter-spacing:.24em;color:rgba(212,175,55,.68);margin-bottom:8px;}
      .pdf-dir-list{margin-top:6px;border-top:1px solid rgba(212,175,55,.14);}
      .pdf-dir-item{display:flex;align-items:center;border-bottom:1px solid rgba(255,255,255,.08);min-height:42px;padding:0 4px;box-sizing:border-box;gap:8px;}
      .pdf-dir-idx{width:68px;flex:0 0 68px;font-size:15px;color:rgba(212,175,55,.96);font-weight:800;}
      .pdf-dir-name{flex:1;font-size:16px;color:rgba(232,232,232,.96);font-weight:700;}
      .pdf-dir-dots{flex:1;border-bottom:1px dashed rgba(212,175,55,.34);height:0;transform:translateY(2px);}
      .pdf-dir-page{width:62px;flex:0 0 62px;text-align:right;font-size:13px;color:rgba(226,214,188,.92);font-weight:700;border:1px solid rgba(212,175,55,.22);border-radius:999px;padding:2px 8px;box-sizing:border-box;background:rgba(212,175,55,.06);}
      .pdf-flow-section{margin-bottom:10px;border-radius:10px;border:1px solid rgba(212,175,55,.16);background:rgba(11,16,38,.55);overflow:hidden;}
      .pdf-flow-head{height:38px;display:flex;align-items:center;gap:10px;padding:0 14px;border-bottom:1px solid rgba(212,175,55,.16);background:linear-gradient(90deg,rgba(212,175,55,.12),rgba(212,175,55,.03));}
      .pdf-flow-bullet{color:rgba(212,175,55,.96);font-size:15px;}
      .pdf-flow-title{color:rgba(245,236,218,.98);font-size:16px;font-weight:800;letter-spacing:.05em;}
      .pdf-flow-body{padding:10px 14px 12px;}
      .pdf-flow-line{font-size:15px;line-height:1.72;color:rgba(228,230,238,.95);margin-bottom:2px;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;}
      .pdf-page-footer{position:absolute;left:48px;right:48px;bottom:42px;height:24px;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:rgba(210,210,210,.72);letter-spacing:.04em;}
      .pdf-footer-line{position:absolute;left:48px;right:48px;bottom:70px;height:1px;background:linear-gradient(90deg,rgba(212,175,55,0),rgba(212,175,55,.45),rgba(212,175,55,0));}
    `;

    const wrapper = document.createElement("div");
    wrapper.style.position = "fixed";
    wrapper.style.left = "-100000px";
    wrapper.style.top = "0";
    wrapper.style.zIndex = "-1";
    wrapper.style.width = "0";
    wrapper.style.height = "0";
    document.body.appendChild(wrapper);

    const pages: HTMLElement[] = [];
    const createPageEl = (idx: number) => {
      const el = document.createElement("div");
      el.className = "pdf-gen-page";
      el.style.left = `${idx * 2}px`;
      el.style.top = `${idx * 2}px`;
      (el.style as any).backgroundImage = `url(${pdfBgUrl})`;
      wrapper.appendChild(el);
      pages.push(el);
      return el;
    };
    const appendFooter = (el: HTMLElement, pageNo: number, label = "商业运势批复") => {
      const footer = document.createElement("div");
      footer.className = "pdf-page-footer";
      footer.innerHTML = `<div>${escapeHtml(label)}</div><div>第 ${pageNo} 页</div>`;
      const line = document.createElement("div");
      line.className = "pdf-footer-line";
      el.appendChild(line);
      el.appendChild(footer);
    };

    const coverEl = createPageEl(0);
    const companyName = toStr(raw?.header?.company_name || raw?.header?.name || "企业");
    coverEl.innerHTML = `
      <div class="pdf-gen-panel">
        <div class="pdf-cover-kicker">玄 · 商 · 运 · 势</div>
        <div class="pdf-cover-title">商业运势批复</div>
        <div class="pdf-name">${escapeHtml(companyName)}</div>
        <div style="text-align:center;color:rgba(226,226,226,0.92);font-size:14px;margin-bottom:18px;">命盘解读 · 年月日运 · 风水锦囊</div>
        <div class="pdf-cover-divider"></div>
        <div class="pdf-cover-seal">商</div>
      </div>
    `;
    appendFooter(coverEl, 1, "商业运势批复 · 封面");

    const dirEl = createPageEl(1);
    type ChapterPage = { chapterNo: number; title: string; lines: string[]; continued?: boolean };
    const contentPages: ChapterPage[] = [];
    const dirItems: Array<{ no: number; title: string; start: number; end: number }> = [];
    let currentPageNo = 3;
    moduleList.forEach((m, idx) => {
      const chapterNo = idx + 1;
      const chunks = splitByLines(m.lines, MAX_LINES);
      const start = currentPageNo;
      chunks.forEach((chunk, cIdx) => {
        contentPages.push({ chapterNo, title: m.title, lines: chunk, continued: cIdx > 0 });
        currentPageNo += 1;
      });
      const end = Math.max(start, currentPageNo - 1);
      dirItems.push({ no: chapterNo, title: m.title, start, end });
    });
    dirEl.innerHTML = `
      <div class="pdf-gen-panel">
        <div class="pdf-dir-kicker">卷 一 · 纲 目</div>
        <div class="pdf-dir-title">目录</div>
        <div class="pdf-dir-list">
          ${dirItems.map((it) => {
            const pageText = it.start === it.end ? `${it.start}` : `${it.start}-${it.end}`;
            return `<div class="pdf-dir-item">
              <div class="pdf-dir-idx">第${it.no}章</div>
              <div class="pdf-dir-name">${escapeHtml(it.title)}</div>
              <div class="pdf-dir-dots"></div>
              <div class="pdf-dir-page">${escapeHtml(pageText)}</div>
            </div>`;
          }).join("")}
        </div>
      </div>
    `;
    appendFooter(dirEl, 2, "商业运势批复 · 目录");

    contentPages.forEach((section, i) => {
      const el = createPageEl(2 + i);
      const titleText = `第${section.chapterNo}章 ${section.title}${section.continued ? "（续）" : ""}`;
      const linesHtml = section.lines.map((ln) => `<div class="pdf-flow-line">${escapeHtml(ln || " ")}</div>`).join("");
      el.innerHTML = `
        <div class="pdf-gen-panel">
          <div class="pdf-flow-section">
            <div class="pdf-flow-head">
              <div class="pdf-flow-bullet">✧</div>
              <div class="pdf-flow-title">${escapeHtml(titleText)}</div>
            </div>
            <div class="pdf-flow-body">${linesHtml}</div>
          </div>
        </div>
      `;
      appendFooter(el, 3 + i);
    });

    const doc = new jsPDF({ unit: "pt", format: "a4" });
    const pageW = doc.internal.pageSize.getWidth();
    const pageH = doc.internal.pageSize.getHeight();
    const renderScale = Math.min(1.45, Math.max(1.15, Number((window as any)?.devicePixelRatio || 1)));
    const jpegQuality = 0.86;
    for (let i = 0; i < pages.length; i++) {
      const canvas = await html2canvas(pages[i], {
        scale: renderScale,
        useCORS: true,
        allowTaint: true,
        backgroundColor: "#0a0a0f",
        logging: false,
      });
      const img = canvas.toDataURL("image/jpeg", jpegQuality);
      if (i > 0) doc.addPage();
      doc.addImage(img, "JPEG", 0, 0, pageW, pageH, undefined, "FAST");
    }
    wrapper.remove();
    doc.save(`${companyName || "商业运势"}-商业运势批复.pdf`);
    uni.showToast({ title: "PDF下载成功", icon: "success" });
  } catch (e) {
    console.error("生成PDF失败:", e);
    uni.showToast({ title: "PDF下载失败", icon: "none" });
  } finally {
    uni.hideLoading();
  }
};
</script>

<style scoped>
.fortune-wrap {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: #050508;
  color: #e2e2e2;
  overflow: hidden;
  z-index: 60;
  font-size: 26rpx;
  line-height: 1.6;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}

.bg-base {
  position: absolute;
  inset: 0;
  background: #050508;
}

.bg-texture {
  position: absolute;
  inset: 0;
  background-image: url('https://www.transparenttextures.com/patterns/stardust.png');
  background-size: auto;
  opacity: 0.2;
}

.bg-glow {
  position: absolute;
  width: 50%;
  height: 50%;
  border-radius: 999px;
  filter: blur(100px);
}

.bg-glow-a {
  top: -10%;
  left: -10%;
  background: #d4af37;
  opacity: 0.05;
}

.bg-glow-b {
  bottom: -10%;
  right: -10%;
  background: #8b2323;
  opacity: 0.05;
}

.bg-star {
  position: absolute;
  border-radius: 50%;
  background: #fff;
  opacity: 0.2;
  animation: twinkle 3s ease-in-out infinite;
}

@keyframes twinkle {
  0%,
  100% {
    opacity: 0.1;
    transform: scale(1);
  }
  50% {
    opacity: 0.55;
    transform: scale(1.2);
  }
}

.header {
  position: relative;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 28rpx 30rpx;
  padding-top: calc(28rpx + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  background: rgba(10, 10, 15, 0.8);
  backdrop-filter: blur(10px);
}

.header-left {
  width: 72rpx;
  height: 72rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.header-back {
  color: #a0a0a0;
  font-size: 44rpx;
  line-height: 44rpx;
}

.header-mid {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.header-title {
  font-size: 30rpx;
  font-weight: 700;
  color: #d4af37;
  letter-spacing: 0.2em;
}

.header-subtitle {
  margin-top: 6rpx;
  font-size: 18rpx;
  color: #5a5a5a;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.header-right {
  display: flex;
  align-items: center;
  gap: 16rpx;
}

.header-icon {
  width: 64rpx;
  height: 64rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.header-icon-text {
  font-size: 30rpx;
  color: #d4af37;
}

.tabs {
  position: relative;
  z-index: 10;
  background: rgba(10, 10, 15, 0.5);
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.tabs-inner {
  display: flex;
  align-items: center;
  min-width: max-content;
  padding: 0 12rpx;
}

.tab {
  position: relative;
  min-width: 140rpx;
  padding: 18rpx 18rpx 20rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
  color: #666;
}

.tab.active {
  color: #d4af37;
}

.tab-icon-wrap {
  position: relative;
  width: 56rpx;
  height: 56rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tab-icon {
  font-size: 28rpx;
  line-height: 1;
  display: block;
}

.tab-lock-dot {
  position: absolute;
  top: -6rpx;
  right: -10rpx;
  width: 32rpx;
  height: 32rpx;
  padding: 0;
  border-radius: 999rpx;
  border: 1px solid rgba(212, 175, 55, 0.35);
  background: rgba(212, 175, 55, 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}

.tab-lock-dot-text {
  font-size: 18rpx;
  line-height: 1;
  color: #d4af37;
}

.tab-label {
  font-size: 22rpx;
  font-weight: 700;
  letter-spacing: 0.18em;
}

.tab-indicator {
  position: absolute;
  bottom: 0;
  width: 64rpx;
  height: 4rpx;
  background: #d4af37;
}

.content {
  position: relative;
  z-index: 10;
  flex: 1;
}

.content-inner {
  padding: 38rpx 38rpx 160rpx;
}

.stack {
  display: flex;
  flex-direction: column;
  gap: 24rpx;
}

.card {
  position: relative;
  background: #1a1a2e;
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 18rpx;
  padding: 28rpx;
  overflow: hidden;
}

.card-grad {
  background: linear-gradient(135deg, #1a1a2e, #0a0a0f);
}

.border-gold {
  border-color: rgba(212, 175, 55, 0.3);
}

.card-watermark {
  position: absolute;
  top: 0;
  right: 0;
  padding: 14rpx;
  opacity: 0.08;
}

.wm {
  font-size: 80rpx;
  color: #d4af37;
}

.section-title {
  display: flex;
  align-items: center;
  gap: 14rpx;
  margin-bottom: 18rpx;
}

.bar {
  width: 8rpx;
  height: 44rpx;
  border-radius: 999rpx;
  background: #d4af37;
  box-shadow: 0 0 16rpx rgba(212, 175, 55, 0.5);
}

.st {
  display: block;
  font-size: 28rpx;
  font-weight: 800;
  letter-spacing: 0.18em;
  font-family: "Songti SC", "Noto Serif SC", SimSun, serif;
}

.sst {
  display: block;
  margin-top: 6rpx;
  font-size: 18rpx;
  color: #a0a0a0;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.muted {
  color: #a0a0a0;
}

.gold {
  color: #d4af37;
}

.red {
  color: #f87171;
}

.serif {
  font-family: "Songti SC", "Noto Serif SC", SimSun, serif;
}

.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}

.bold {
  font-weight: 800;
}

.tiny {
  font-size: 22rpx;
}

.micro {
  font-size: 20rpx;
}

.lh {
  line-height: 1.6;
}

.row {
  display: flex;
  align-items: flex-start;
}

.col {
  display: flex;
  flex-direction: column;
}

.flex-1 {
  flex: 1;
}

.gap-1 {
  gap: 8rpx;
}

.gap-2 {
  gap: 16rpx;
}

.gap-3 {
  gap: 24rpx;
}

.mt-1 {
  margin-top: 8rpx;
}

.mt-2 {
  margin-top: 16rpx;
}

.mb-3 {
  margin-bottom: 24rpx;
}

.divider {
  height: 1px;
  background: rgba(255, 255, 255, 0.05);
  margin: 20rpx 0;
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.grid-4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.center {
  text-align: center;
}

.row-wide {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: rgba(255, 255, 255, 0.05);
  padding: 14rpx 16rpx;
  border-radius: 14rpx;
}

.info-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12rpx 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.info-row:last-child {
  border-bottom: 0;
}

.box-dark {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 14rpx;
  padding: 18rpx;
  border: 1px solid rgba(255, 255, 255, 0.06);
}

.box {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 14rpx;
  padding: 18rpx;
}

.box-left {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 14rpx;
  padding: 18rpx;
  border-left-width: 6rpx;
  border-left-style: solid;
}

.gold-left {
  border-left-color: #d4af37;
}

.red-left {
  border-left-color: #ef4444;
}

.grade-badge {
  width: 140rpx;
  height: 140rpx;
  border-radius: 999rpx;
  background: rgba(212, 175, 55, 0.1);
  border: 1px solid #d4af37;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.grade-text {
  font-size: 40rpx;
  font-weight: 900;
  color: #d4af37;
}

.scorebar {
  margin-bottom: 16rpx;
}

.scorebar-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6rpx;
}

.scorebar-track {
  width: 100%;
  height: 12rpx;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 999rpx;
  overflow: hidden;
}

.scorebar-fill {
  height: 100%;
  border-radius: 999rpx;
}

.note {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 14rpx;
  padding: 18rpx;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 10rpx;
  margin-top: 10rpx;
}

.chip {
  font-size: 18rpx;
  padding: 6rpx 10rpx;
  border: 1px solid rgba(212, 175, 55, 0.3);
  border-radius: 12rpx;
  color: #d4af37;
}

.chip-bad {
  border-color: rgba(239, 68, 68, 0.3);
  color: #f87171;
}

.kv {
  display: flex;
  flex-direction: column;
  gap: 12rpx;
}

.kv-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14rpx 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.kv-row:last-child {
  border-bottom: 0;
}

.karma {
  display: flex;
  flex-direction: column;
  gap: 16rpx;
}

.karma-item {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 14rpx;
  padding: 18rpx;
  display: flex;
  gap: 16rpx;
  align-items: flex-start;
}

.karma-icon {
  width: 48rpx;
  height: 48rpx;
  border-radius: 12rpx;
  background: rgba(160, 160, 160, 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
}

.karma-icon-gold {
  background: rgba(212, 175, 55, 0.12);
}

.karma-icon-text {
  color: #a0a0a0;
  font-size: 18rpx;
  font-weight: 900;
}

.star-item {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 14rpx;
  padding: 14rpx 16rpx;
  border-left: 6rpx solid #d4af37;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.tag {
  font-size: 18rpx;
  padding: 4rpx 12rpx;
  border-radius: 12rpx;
}

.tag-good {
  background: rgba(127, 29, 29, 0.4);
  color: #fca5a5;
}

.tag-mid {
  background: rgba(55, 65, 81, 1);
  color: #9ca3af;
}

.tag-green {
  background: rgba(20, 83, 45, 0.3);
  color: #4ade80;
}

.tag-red {
  background: rgba(127, 29, 29, 0.3);
  color: #f87171;
}

.radar {
  align-items: center;
  gap: 24rpx;
}

.radar-left {
  position: relative;
  width: 260rpx;
  height: 260rpx;
}

.radar-svg {
  width: 100%;
  height: 100%;
  transform: rotate(180deg);
}

.radar-label {
  position: absolute;
  font-size: 14rpx;
  color: #e2e2e2;
}

.radar-top {
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  font-weight: 900;
}

.radar-right-pos {
  right: 0;
  top: 35%;
  transform: translateX(6rpx);
}

.radar-left-label {
  left: 0;
  top: 35%;
  transform: translateX(-6rpx);
}

.radar-br {
  bottom: 0;
  right: 5%;
}

.radar-bl {
  bottom: 0;
  left: 5%;
}

.radar-right {
  flex: 1;
  border-left: 1px solid rgba(255, 255, 255, 0.05);
  padding-left: 18rpx;
  display: flex;
  flex-direction: column;
  gap: 16rpx;
}

.bar-item {
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}

.bar-head {
  display: flex;
  justify-content: space-between;
}

.bar-track {
  width: 100%;
  height: 8rpx;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 999rpx;
  overflow: hidden;
}

.bar-fill {
  height: 100%;
}

.timeline {
  margin-top: 10rpx;
}

.timeline-item {
  position: relative;
  padding-left: 24rpx;
  padding-bottom: 24rpx;
  border-left: 1px solid rgba(255, 255, 255, 0.1);
}

.timeline-item.current {
  border-left-color: rgba(212, 175, 55, 0.8);
}

.dot {
  position: absolute;
  left: -10rpx;
  top: 6rpx;
  width: 18rpx;
  height: 18rpx;
  border-radius: 999rpx;
  background: #333;
  border: 4rpx solid #050508;
}

.dot.on {
  background: #d4af37;
  box-shadow: 0 0 12rpx rgba(212, 175, 55, 0.6);
}

.timeline-body {
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}

.timeline-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.tl-name {
  font-size: 24rpx;
  font-weight: 800;
}

.pill {
  font-size: 18rpx;
  color: #666;
  background: rgba(255, 255, 255, 0.05);
  padding: 6rpx 14rpx;
  border-radius: 999rpx;
}

.current-tag {
  align-self: flex-start;
  font-size: 18rpx;
  color: #d4af37;
  background: rgba(212, 175, 55, 0.1);
  padding: 6rpx 12rpx;
  border-radius: 12rpx;
}

.annual-head {
  align-items: flex-start;
}

.annual-tag {
  width: 96rpx;
  height: 96rpx;
  border-radius: 14rpx;
  background: #d4af37;
  color: #000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.annual-tag-text {
  font-size: 40rpx;
  font-weight: 900;
}

.annual-pill {
  margin-top: 10rpx;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12rpx;
  padding: 8rpx 12rpx;
  text-align: center;
}

.annual-chart {
  margin-top: 18rpx;
  background: rgba(26, 26, 46, 0.8);
  border-radius: 14rpx;
  padding: 16rpx;
  border: 1px solid rgba(255, 255, 255, 0.05);
}

.annual-chart-head {
  justify-content: space-between;
  align-items: center;
}

.annual-bars {
  height: 180rpx;
  display: flex;
  align-items: flex-end;
  gap: 8rpx;
  margin-top: 16rpx;
}

.annual-bar {
  flex: 1;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 10rpx 10rpx 0 0;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
}

.annual-bar-fill {
  width: 100%;
  background: rgba(212, 175, 55, 0.5);
}

.annual-bars-foot {
  justify-content: space-between;
  margin-top: 8rpx;
}

.table {
  border-radius: 14rpx;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.tr {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  padding: 12rpx 10rpx;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.tr:last-child {
  border-bottom: 0;
}

.th {
  background: rgba(255, 255, 255, 0.04);
}

.tc {
  font-size: 20rpx;
}

.compass {
  position: relative;
  width: 420rpx;
  height: 420rpx;
  border-radius: 999rpx;
  background: #0a0a0f;
  border: 2px solid rgba(255, 255, 255, 0.05);
  margin: 0 auto 20rpx;
}

.compass-center {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12rpx;
  height: 12rpx;
  border-radius: 999rpx;
  background: #d4af37;
  transform: translate(-50%, -50%);
}

.compass-t {
  position: absolute;
  top: 10rpx;
  left: 50%;
  transform: translateX(-50%);
  font-size: 14rpx;
  color: #f87171;
  font-weight: 900;
}

.compass-b {
  position: absolute;
  bottom: 10rpx;
  left: 50%;
  transform: translateX(-50%);
  font-size: 14rpx;
  color: #666;
}

.compass-l {
  position: absolute;
  left: 10rpx;
  top: 50%;
  transform: translateY(-50%);
  font-size: 14rpx;
  color: #666;
}

.compass-r {
  position: absolute;
  right: 10rpx;
  top: 50%;
  transform: translateY(-50%);
  font-size: 14rpx;
  color: #666;
}

.compass-tr {
  position: absolute;
  top: 15%;
  right: 15%;
  font-size: 12rpx;
  color: #a0a0a0;
}

.compass-tl {
  position: absolute;
  top: 15%;
  left: 15%;
  font-size: 12rpx;
}

.compass-br {
  position: absolute;
  bottom: 15%;
  right: 15%;
  font-size: 12rpx;
  color: #666;
}

.compass-bl {
  position: absolute;
  bottom: 15%;
  left: 15%;
  font-size: 12rpx;
}

.compass-s {
  color: #f87171;
}

.role-list {
  display: flex;
  flex-direction: column;
}

.role-item {
  display: flex;
  gap: 16rpx;
  padding: 18rpx 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.role-item.last {
  border-bottom: 0;
}

.role-icon {
  width: 44rpx;
  height: 44rpx;
  border-radius: 12rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.box-i {
  border-radius: 14rpx;
  padding: 18rpx;
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.box-i.good {
  background: rgba(20, 83, 45, 0.12);
  border-color: rgba(34, 197, 94, 0.2);
}

.box-i.bad {
  background: rgba(127, 29, 29, 0.12);
  border-color: rgba(239, 68, 68, 0.2);
}

.lock-root {
  position: relative;
  min-height: 800rpx;
}

.content-area {
  position: relative;
  flex: 1;
  height: 0;
  display: flex;
  flex-direction: column;
}

.lock-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(5, 5, 8, 0.6);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.lock-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: rgba(10, 10, 18, 0.75);
  border: 1px solid rgba(212, 175, 55, 0.3);
  border-radius: 24rpx;
  padding: 56rpx 48rpx;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 8rpx 48rpx rgba(0, 0, 0, 0.5);
  width: 85%;
  max-width: 600rpx;
}

.lock-circle {
  width: 96rpx;
  height: 96rpx;
  border-radius: 999rpx;
  background: #d4af37;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 24rpx;
  box-shadow: 0 0 24rpx rgba(212, 175, 55, 0.6);
}

.lock-circle-text {
  color: #000;
  font-weight: 900;
}

.lock-h {
  font-size: 30rpx;
  font-weight: 800;
  margin-bottom: 14rpx;
}

.lock-p {
  text-align: center;
  margin-bottom: 24rpx;
}

.lock-p-text {
  display: block;
  color: #a0a0a0;
}

.lock-p-sub {
  display: block;
  color: rgba(212, 175, 55, 0.8);
  margin-top: 6rpx;
}

.lock-cta {
  padding: 18rpx 44rpx;
  border-radius: 999rpx;
  background: linear-gradient(90deg, #d4af37, #b49120);
}

.lock-cta-text {
  color: #000;
  font-weight: 900;
  letter-spacing: 0.12em;
}

.blurred {
  filter: blur(8px);
  opacity: 0.4;
  pointer-events: none;
}

.clickable {
  transition: opacity 0.15s ease;
}

.clickable:active {
  opacity: 0.82;
}

.trend {
  margin-top: 14rpx;
  height: 220rpx;
  position: relative;
}

.trend-bars {
  position: absolute;
  left: 8rpx;
  right: 8rpx;
  top: 10rpx;
  bottom: 40rpx;
  display: flex;
  align-items: flex-end;
  gap: 8rpx;
}

.trend-bar {
  flex: 1;
  height: 100%;
  border-radius: 10rpx 10rpx 0 0;
  background: rgba(255, 255, 255, 0.04);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
}

.trend-bar-fill {
  width: 100%;
  background: linear-gradient(180deg, rgba(212, 175, 55, 0.7), rgba(212, 175, 55, 0.1));
}

.trend-months {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: space-between;
  padding: 0 8rpx;
}

.m-table {
  margin-top: 14rpx;
  border-radius: 14rpx;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.m-tr {
  display: flex;
  gap: 12rpx;
  padding: 12rpx;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.m-tr:last-child {
  border-bottom: 0;
}

.m-th {
  background: rgba(212, 175, 55, 0.1);
}

.m-td {
  width: 120rpx;
  font-size: 20rpx;
}

.badge {
  padding: 4rpx 10rpx;
  border-radius: 12rpx;
  font-size: 18rpx;
}

.badge-red {
  background: rgba(127, 29, 29, 0.3);
  color: #fca5a5;
}

.badge-gray {
  background: rgba(31, 41, 55, 1);
  color: #9ca3af;
}

.badge-blue {
  background: rgba(30, 58, 138, 0.3);
  color: #93c5fd;
}

.cal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 14rpx;
  padding: 0 12rpx;
}

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 12rpx;
}

.cal-cell {
  aspect-ratio: 1 / 1;
  border-radius: 12rpx;
  background: rgba(255, 255, 255, 0.05);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.cal-cell.hit {
  background: rgba(212, 175, 55, 0.2);
  border: 1px solid rgba(212, 175, 55, 0.5);
}

.hour {
  padding: 10rpx 8rpx;
  border-radius: 12rpx;
  text-align: center;
}

.hour-good {
  background: rgba(212, 175, 55, 0.1);
  color: #d4af37;
}

.hour-bad {
  background: rgba(127, 29, 29, 0.1);
  color: #f87171;
}

.hour-mid {
  background: rgba(255, 255, 255, 0.05);
  color: #666;
}

.action {
  margin-top: 18rpx;
  background: rgba(212, 175, 55, 0.06);
  border: 1px solid rgba(212, 175, 55, 0.2);
  border-radius: 14rpx;
  padding: 18rpx;
}

.noble {
  width: 120rpx;
  height: 160rpx;
  background: #0a0a0f;
  border: 1px solid rgba(212, 175, 55, 0.3);
  border-radius: 14rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.noble-avatar {
  width: 64rpx;
  height: 64rpx;
  border-radius: 999rpx;
  background: rgba(212, 175, 55, 0.2);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 10rpx;
}

.noble-avatar-text {
  font-size: 36rpx;
}

.noble-tag {
  font-size: 14rpx;
  color: #d4af37;
  border: 1px solid rgba(212, 175, 55, 0.3);
  padding: 4rpx 10rpx;
  border-radius: 10rpx;
}

.dotc {
  width: 44rpx;
  height: 44rpx;
  border-radius: 999rpx;
  box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.3);
}

.detail-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28rpx;
}

.detail-modal {
  width: 100%;
  max-width: 680rpx;
  background: rgba(10, 10, 15, 0.98);
  border: 1px solid rgba(212, 175, 55, 0.25);
  border-radius: 18rpx;
  overflow: hidden;
}

.detail-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18rpx 18rpx;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.detail-modal-title {
  flex: 1;
  color: #d4af37;
  font-weight: 900;
  font-size: 28rpx;
  padding-right: 16rpx;
}

.detail-modal-close {
  width: 56rpx;
  height: 56rpx;
  border-radius: 999rpx;
  background: rgba(255, 255, 255, 0.06);
  display: flex;
  align-items: center;
  justify-content: center;
}

.detail-modal-close-text {
  color: #a0a0a0;
  font-size: 34rpx;
  line-height: 1;
}

.detail-modal-body {
  max-height: 70vh;
}

.detail-modal-content {
  padding: 18rpx;
}

.detail-modal-text {
  display: block;
  color: #a0a0a0;
  font-size: 24rpx;
  line-height: 1.8;
  margin-bottom: 12rpx;
}

.bottom-spacer {
  height: 120rpx;
}
</style>

<style>
page {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  overflow: hidden;
}
</style>
