*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; min-height: 100%; background: #000; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
  color: #fff;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
}
img { user-select: none; }

.landing {
  min-height: 100vh;
  background: #000;
}
.landing[data-layout="pending"] { visibility: hidden; }
/* PC 海报是 16:9，显示器普遍更宽，两侧会空出来（1280x628 上左右各 82px）。
   填色不能用一个纯色：海报左缘是纯白 #ffffff（占 95~99%），右缘是纯粉
   #f95db1（占 100%），统一填粉左边就会出现白海报边接粉背景的分界。
   左半白右半粉、分界压在 50% —— 海报居中且一定跨过中线，分界线永远被它盖住，
   两侧各自接上对应的边缘色。
   （屏幕比 16:9 还窄时变成上下留白，那两条会显出左白右粉的硬分界，
   但海报上下缘本身就是白粉混着的杂色，且 4:3 显示器现在基本绝迹，不为它让路。） */
.landing[data-layout="pc"] {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(to right, #ffffff 50%, #f95db1 50%);
}
/* 壳透出上面那层渐变：海报 460KB，加载期整屏就是左白右粉，不会先黑一下再跳色。 */
.landing[data-layout="pc"] .poster-shell { background: transparent; }

.poster-shell {
  position: relative;
  background: #000;
  overflow: hidden;
}
.poster-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  -webkit-user-drag: none;
}
.poster-hot {
  position: absolute;
  display: block;
  z-index: 3;
  background: transparent;
  border: 0;
  outline: 0;
  text-decoration: none;
  cursor: pointer;
}
.landing.debug-hotspots .poster-hot {
  outline: 2px solid rgba(255, 32, 32, .7);
  background: rgba(255, 32, 32, .12);
}

.poster-pc {
  width: min(100vw, calc(100vh * 16 / 9));
  height: min(100vh, calc(100vw * 9 / 16));
  display: none;
}
.landing[data-layout="pc"] .poster-pc { display: block; }
.landing[data-layout="pc"] .poster-mobile { display: none; }

/* 二维码浮层只作展示，pointer-events: none 让点击穿透下去。
   新稿 PC 的二维码框底下没有下载热区（扫码是给手机用的，点它没有语义），
   所以现在穿透下去就是海报本身，点了不会有反应 —— 这是预期。 */
.qr-overlay {
  position: absolute;
  background: #fff;
  overflow: hidden;
  z-index: 4;
  pointer-events: none;
}
.qr-overlay canvas,
.qr-overlay img,
.qr-overlay table,
.qr-overlay svg {
  width: 100% !important;
  height: 100% !important;
}

/* 海报是固定的 9:16，而真机屏幕比这更细长（多数是 19.5:9 ~ 20:9），
   所以宽度铺满之后下面总会空出 18~20% —— 见下面 .landing[data-layout="h5"]
   的背景色，那段空白填的是海报底色，不是黑边。

   calc(100vh * 9 / 16) 是另一头的约束：屏幕比 9:16 还方的时候（iPad 竖屏、
   折叠屏展开、手机横屏），按宽度铺满会让海报高过视口，下载按钮直接掉到首屏
   外面 —— iPad 竖屏要滚 298px 才看得到，横屏要滚 1062px。按高度反推宽度，
   海报整体缩小、左右留边，但按钮永远在屏幕里。
   dvh 那行是给 iOS Safari 的：100vh 取的是地址栏收起时的高度，会让海报底部
   被地址栏压住；不认 dvh 的浏览器忽略这行，回落到上一行的 vh。

   max-width 必须 >= landing.js detectDevice 的 isMobile 阈值（innerWidth <= 960），
   否则 751~960 这档窗口宽度会被判成 h5、却只画 750px 宽的海报。
   960 仍小于海报原图宽 1080，放大不会糊。

   老内核（UC 之类）不认 min() 时两条 width 一起失效，block 元素回落成
   100% 宽 —— 正好是加这个约束之前的行为，降级是安全的。 */
.poster-mobile {
  width: min(100%, calc(100vh * 9 / 16));
  width: min(100%, calc(100dvh * 9 / 16));
  max-width: 960px;
  margin: 0 auto;
  display: none;
}
/* 海报底部整行是纯色 #f962b3（a / b 两套一样，左中右都同色），页面背景取同一个
   值，视口比海报高时空出来的那段就成了海报的自然延伸，而不是一条黑带。
   换海报时如果底色变了，这里要跟着改 —— 取图最后几行的主色即可。
   body 也要设：iOS 下拉过头的回弹会露出 body 背景。 */
.landing[data-layout="h5"] {
  min-height: 100vh;
  background: #f962b3;
}
.landing[data-layout="h5"] .poster-mobile { display: block; }
/* 海报 430KB，慢网下有一段空窗期。壳的底色（基础规则里是 #000）在 H5 下也换成
   海报底色，这段时间看到的是一整块粉，而不是黑块突然跳成粉。

   overflow 放开是给手指让路：它贴着海报底边（93.49% + 6.51% = 100%），摆到
   最高那一帧袖口会探出去约 4.5px，被基础规则的 overflow: hidden 削成一条直边。
   H5 下壳外面就是上面那块同色填充，探出去反而看不出边界。
   PC 不放开 —— 那边壳外是黑的，而且手指底边在 96.3%，本来就转得开。 */
.landing[data-layout="h5"] .poster-shell {
  background: #f962b3;
  overflow: visible;
}
.landing[data-layout="h5"] .poster-img {
  width: 100%;
  height: auto;
  object-fit: contain;
}
body.landing-h5 {
  overflow-x: hidden;
  overflow-y: auto;
  background: #f962b3;
}

/* ========== 热区坐标 ==========
   2026-09-17 换成温迪的新稿：PC landing-pc-{a,b}.jpg 1920x1080，
   H5 landing-mobile-{a,b}.jpg 1080x1920。

   a / b 两套稿逐像素比对下来元素位置完全一致（顶部四个入口、两个下载按钮、
   二维码框、安装提示，坐标一个不差），所以这里不再按 .landing[data-style]
   分叉，只按 .poster-pc / .poster-mobile 分两份 —— 以后换同版式的图不用重标。
   真要上版式不同的第三套，再按 data-style 覆盖即可。

   坐标来自对 5760x3240 / 3240x5760 原稿做投影扫描，不是目测：
   顶部入口取图标与文字的并集，左右各留 0.4~0.6% 余量，保证相邻入口不重叠；
   下载按钮取按钮主体（含投影）的外接矩形，两个按钮之间的空隙保持不可点。

   第 4 个联络入口两块稿不同：PC 画的是官方邮箱，H5 画的是官方客服。 */
.poster-pc .hot-service  { display: none; }
.poster-mobile .hot-email { display: none; }

/* ---- PC：顶部四个入口（圆形图标在上、文字在下，热区取两者并集） ---- */
.poster-pc .hot-group    { left: 64.2%; top: .5%; width: 5.5%; height: 10.0%; }  /* TG 频道 */
.poster-pc .hot-business { left: 70.3%; top: .5%; width: 6.1%; height: 10.0%; }
.poster-pc .hot-channel  { left: 77.1%; top: .5%; width: 6.2%; height: 10.0%; }
.poster-pc .hot-email    { left: 83.9%; top: .5%; width: 6.2%; height: 10.0%; }

/* ---- PC：右下卡片。二维码白框给手机扫，旁边是安装提示，最右两个下载按钮 ---- */
.poster-pc .hot-qr         { left: 48.3%; top: 78.8%; width:  8.6%; height: 14.5%; }
/* risk 的左边界让开二维码白框（到 56.9%）和它右侧那行竖排「用手机扫一扫」，
   否则 .qr-overlay 是 pointer-events: none，点二维码会穿透下来开报毒弹层。 */
.poster-pc .hot-risk       { left: 59.0%; top: 79.3%; width: 23.2%; height: 13.0%; }
.poster-pc .hot-dl-ios     { left: 83.6%; top: 79.4%; width:  8.9%; height:  6.9%; }
.poster-pc .hot-dl-android { left: 83.6%; top: 87.3%; width:  8.9%; height:  7.0%; }

/* ---- H5：顶部是一条半透明长条，四个入口平铺在里面 ---- */
.poster-mobile .hot-business { left: 33.7%; top: 1.5%; width: 11.8%; height: 4.2%; }
.poster-mobile .hot-channel  { left: 49.3%; top: 1.5%; width: 11.9%; height: 4.2%; }
.poster-mobile .hot-service  { left: 64.9%; top: 1.5%; width: 13.1%; height: 4.2%; }
.poster-mobile .hot-group    { left: 81.7%; top: 1.5%; width: 11.9%; height: 4.2%; }

/* ---- H5：底部两个下载按钮，各占海报宽的三分之一 ---- */
.poster-mobile .hot-dl-ios     { left: 15.2%; top: 89.0%; width: 33.2%; height: 7.8%; }
.poster-mobile .hot-dl-android { left: 53.4%; top: 89.0%; width: 33.2%; height: 7.8%; }

/* H5 稿没画二维码卡片，也没画安装提示那段文字，两个热区都没有落点。
   元素仍然渲染（landing.js 对它们都做了空值判断，但保留结构更省事），
   这里直接隐藏。报毒弹层在 H5 上因此暂时没有入口 —— 要恢复得让 UI 在稿子上
   补一行提示文字，再把 hot-risk 的坐标标回来。 */
.poster-mobile .hot-qr,
.poster-mobile .hot-risk { display: none; }

/* ========== 引导点击的手指 ==========
   海报底图里的手指已经由 UI 擦掉，这里把它当成独立元素叠回原位置。
   位置就是手指图层在原稿上的外接矩形，所以和底图严丝合缝。

   为什么不做成 GIF：整张海报 5.1 秒的 GIF 是 18~21MB，而且只导到 640 宽
   （现在是 1080），又大又糊；拆出来用 CSS 动，两张 PNG 合计 8KB。

   pointer-events: none —— 手指压在安卓按钮右下角，必须让点击穿透到
   下面的 .hot-dl-android，否则手指盖住的那块点了没反应。 */
.tap-finger {
  position: absolute;
  display: block;
  z-index: 6;
  pointer-events: none;
  -webkit-user-drag: none;
  /* 绕手腕（袖口，在图的右下角）摆动，指尖在图的左上角 —— 这就是真实点击的
     动作：指尖抬起再落下。

     用 rotate 而不是 scale/translate，是被位置逼的：H5 那只手指正贴着海报底边
     （top 93.49% + height 6.51% = 100%），放大或下移会让袖口整片压到海报外。
     绕靠近底边的轴转，底边附近的点几乎不动，代价只有抬到最高那一帧探出约
     4.5px（390 宽屏上）——这点由 .landing[data-layout="h5"] .poster-shell 的
     overflow: visible 放行，探进的是同色填充区，看不出来。
     PC 那只手指底边在 96.3%，本来就转得开，壳仍保持 overflow: hidden。 */
  transform-origin: 88% 96%;
  animation: tap-finger 1.5s cubic-bezier(.4, 0, .5, 1) infinite;
  will-change: transform;
}
.poster-pc .tap-finger     { left: 90.99%; top: 84.26%; width:  7.81%; height: 12.04%; }
.poster-mobile .tap-finger { left: 81.39%; top: 93.49%; width: 15.93%; height:  6.51%; }

/* 抬起 -> 点下 -> 回位，后 40% 周期停住，避免一直抖看着烦躁。
   负角度是指尖抬离屏幕，正角度是点下去。 */
@keyframes tap-finger {
  0%, 60%, 100% { transform: rotate(0deg); }
  20%           { transform: rotate(-9deg); }
  40%           { transform: rotate(3.5deg); }
}
@media (prefers-reduced-motion: reduce) {
  .tap-finger { animation: none; }
}

.landing.debug-hotspots .tap-finger {
  outline: 2px solid rgba(32, 160, 255, .7);
}

/* ========== 安卓「安装包报毒解决方案」弹层 ========== */
.android-modal {
  position: fixed; inset: 0;
  background: #f5f5f5;
  color: #222;
  z-index: 100;
  overflow-y: auto;
}
.android-modal[hidden] { display: none; }
.android-modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px;
  background: #fff;
  border-bottom: 1px solid #eee;
  position: sticky; top: 0; z-index: 2;
}
.android-modal-back {
  width: 32px; height: 32px;
  background: none; border: 0; padding: 0;
  cursor: pointer;
}
.android-modal-back img { width: 100%; height: 100%; object-fit: contain; }
.android-modal-title { font-size: 16px; font-weight: 600; flex: 1; text-align: center; }
.android-modal-spacer { width: 32px; }

.android-modal-list { display: flex; flex-direction: column; gap: 8px; padding: 12px; }
.android-modal-cell {
  display: block;
  background: #fff;
  border-radius: 8px;
  overflow: hidden;
  text-decoration: none;
}
.android-modal-cell img { width: 100%; display: block; }

.android-modal-detail { padding: 12px; }
.android-modal-detail[hidden] { display: none; }
.android-modal-pic { background: #fff; border-radius: 8px; overflow: hidden; margin-bottom: 8px; }
.android-modal-pic img { width: 100%; display: block; }

.auto-download-fallback {
  position: fixed;
  left: 50%;
  bottom: max(18px, env(safe-area-inset-bottom));
  z-index: 90;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px 9px 14px;
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 999px;
  background: rgba(20, 20, 20, .88);
  box-shadow: 0 6px 24px rgba(0, 0, 0, .32);
  color: #fff;
  font-size: 13px;
  line-height: 1;
  transform: translateX(-50%);
  white-space: nowrap;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.auto-download-fallback[hidden] { display: none; }
.auto-download-fallback button {
  padding: 7px 13px;
  border: 0;
  border-radius: 999px;
  background: #08b857;
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.auto-download-fallback button:active { opacity: .78; }
