/* ============================================================================
   指针跟随聚光边框 —— GlowCard / spotlight-card 的 vanilla 移植
   ----------------------------------------------------------------------------
   来源：用户提供的 React 组件 spotlight-card.tsx（shadcn + Tailwind + TS 写法）。
   本项目是纯 vanilla JS + 手写 CSS，没有 React / Tailwind / 构建步骤，
   那段 .tsx 无法直接粘贴使用 → 只移植它的**效果内核**：
     ① 指针跟随的柔光斑（卡片内）
     ② 指针跟随的发光描边环（1px）
   刻意**去掉**原版的「色相随指针 X 位置循环」（--hue = base + xp * spread）——
   那会得到彩虹色，违反本项目「一个语义一个颜色」与 .impeccable.md 的反例清单。
   色相改为跟随卡片**自身的语义色**（--glow-h），默认品牌玫红。

   用在哪（只给「本身就是卡片」的元素用）：
     .package-card  完整套餐 / 补差 / 联单 面板的套餐选择卡（最高频交互）
     .benefit-card  同上三面板的限时福利卡
     .rk-pod-card   排行榜领奖台（焦点卡，聚光跟随金 / 银 / 铜名次色）
     .mall-card     积分商城的商品卡（只读目录卡，但它本身已有 hover 位移 + 玫红描边/阴影
                    → 项目已按「交互外观」处理，聚光只是延续既有语言）

   ⚠️ 选型判据（加新目标前先过这两条）：
     ① **聚光色必须在该元素上已有既定语义** —— 上面这些的 hover/选中态本来就是品牌玫红
        （或领奖台的名次色），聚光只是延续。
        反例：主页入口卡 .home-card 的 hover 是**按 tone 上色**（蓝/橙/绿/紫，data-tone），
        加玫红聚光会打架；且它是降级 UI（数据总览无数据时才出现）→ 不加。
     ② **hover 已完整上色的元素不要再加聚光** —— 聚光是在元素本来没有交互色时补一层光；
        已有完整 hover 上色时，聚光只会变成污渍。
        反例：排行榜顾问行 .rk-row（2026-09-27 实测后有意不加）。它**通过判据 ①**：
        14px 圆角卡片 + cursor:pointer + hover 本就是玫红 #f9a8b8，加聚光也确实生效；
        但它 1080×54 的宽扁比例下圆形光斑糊成一块粉色污渍，因为它 hover 已经是
        **整圈玫红边框 + 玫红底**，聚光是冗余叠加。试过改横向椭圆仍不如不加 → 撤销。
        A/B 对比见 verify-output/glow-row-ab-noglow.png / glow-row-ab-withglow.png。
     ③ **不得抢占已有的 ::before / ::after** —— 本组件靠这两个伪元素发光，
        目标元素若已用它们做别的效果，加进来会**直接打掉那个效果**（不是叠加，是覆盖）。
        反例：话术结果卡 .seg-card（2026-09-27 实测后有意不加）。
        - **判据 ① 就不过**：#up-result .seg-card:hover 是玻璃白（bg rgba(255,255,255,.72)
          / border rgba(255,255,255,.95)），#panel-upgrade .seg-card:hover 只有位移+阴影、
          **完全没有颜色变化** —— 都不是玫红。
        - **且有硬冲突**：#up-result .seg-card **已经占用 ::before**（玻璃拟态
          `filter:url(#glass-distortion)`）+ **::after**（内高光 inset box-shadow）。
          实测把 .seg-card 加进本文件的 :is() 列表后，这两个伪元素的 opacity 由 **1 → 0**
          → 玻璃层整层消失，画面 **1.66% 像素改变**（明显差异 0.80%）。
          证据：verify-output/seg-ab-noglow.png / seg-ab-withglow.png。
        - 注意 .seg-card 是**内容卡**（34 处渲染，交互在卡内的「复制」按钮），卡本身不点选。
   ⚠️ 新增目标要**同时**改两处：下面的 :is() 列表 + glow-card.js 里的 SEL 常量。

   触摸设备 / prefers-reduced-motion 下整体关闭 —— 本效果是桌面指针反馈，触屏无意义。
   设计与 token 约定见 .impeccable.md 与 docs/11-ranking-ui-system.md。
   ============================================================================ */

:is(.package-card, .benefit-card, .rk-pod-card, .mall-card){
  position: relative;
  --glow-h: 350; --glow-s: 74%; --glow-l: 56%;   /* 默认 = 品牌玫红 #e11d48 */
  --glow-r: 170;                                 /* 光斑半径（px）；卡片越小要越小，否则整个盖住看不出「聚光」 */
}

/* 按卡片实际尺寸给半径：套餐卡扁而小，福利卡/领奖台/商品卡大一些 */
.package-card{ --glow-r: 96; }
.benefit-card{ --glow-r: 190; }
.rk-pod-card { --glow-r: 230; }
.mall-card   { --glow-r: 150; }

/* 领奖台：聚光跟随名次色（金 / 银 / 铜是面板内已认可的语义色，见 .impeccable.md 受控例外） */
.rk-pod.gold   .rk-pod-card{ --glow-h: 38;  --glow-s: 92%; --glow-l: 54%; }
.rk-pod.silver .rk-pod-card{ --glow-h: 214; --glow-s: 18%; --glow-l: 78%; }
.rk-pod.bronze .rk-pod-card{ --glow-h: 22;  --glow-s: 62%; --glow-l: 56%; }

:is(.package-card, .benefit-card, .rk-pod-card, .mall-card)::before,
:is(.package-card, .benefit-card, .rk-pod-card, .mall-card)::after{
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; opacity: 0; transition: opacity .16s ease;
}

/* ① 柔光斑（alpha 与原版 --bg-spot-opacity 0.1 同量级） */
:is(.package-card, .benefit-card, .rk-pod-card, .mall-card):hover::before{
  opacity: 1;
  background-image: radial-gradient(
    calc(var(--glow-r) * 1px) calc(var(--glow-r) * 1px)
      at calc(var(--gx, 0) * 1px) calc(var(--gy, 0) * 1px),
    hsl(var(--glow-h) var(--glow-s) var(--glow-l) / .18), transparent 72%);
}

/* ② 发光描边环：1px，用 mask 把中间挖空只留边。
   半径收紧到 0.55×、首段不透明 → 指针附近那一段边是亮的，远处迅速淡出，
   才是「一束光扫过边框」的观感（原版就是这个味道）。 */
:is(.package-card, .benefit-card, .rk-pod-card, .mall-card):hover::after{
  opacity: 1;
  padding: 1px;
  background-image: radial-gradient(
    calc(var(--glow-r) * 0.55px) calc(var(--glow-r) * 0.55px)
      at calc(var(--gx, 0) * 1px) calc(var(--gy, 0) * 1px),
    hsl(var(--glow-h) 96% 60%), hsl(var(--glow-h) 96% 60% / .45) 50%, transparent 78%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
}

@media (hover: none), (pointer: coarse){
  :is(.package-card, .benefit-card, .rk-pod-card, .mall-card)::before,
  :is(.package-card, .benefit-card, .rk-pod-card, .mall-card)::after{ display: none; }
}
@media (prefers-reduced-motion: reduce){
  :is(.package-card, .benefit-card, .rk-pod-card, .mall-card)::before,
  :is(.package-card, .benefit-card, .rk-pod-card, .mall-card)::after{ transition: none; }
}
