    /* ═══ 悬停提示气泡: 全站唯一一枚, 由 [data-tip] 驱动(见 JS 的 initTip) ═══
       不用原生 title 的原因: 那枚气泡由浏览器画, CSS 碰不到它 —— 系统是深色主题时
       浅色页面上会跳出一块深色气泡, 且固定约 1 秒延迟。这里自己画一枚, 颜色/圆角/
       延迟全归我们, 也才谈得上"全站统一样式"。
       底色取 --ink(与全站主文本同色, 不是纯黑): 白字压上去够沉, 又不会在浅色页面里
       砸出一个洞。pointer-events:none 是必须的 —— 气泡就贴在按钮边上, 若能接事件就会
       把鼠标从按钮上"偷"走, 于是气泡自己把自己关掉, 来回闪。 */
    .tip {
      position: fixed;
      left: 0;
      top: 0;
      z-index: 90;
      /* 压过所有弹层: 图表抽屉 50 / 预览 60 / 账号·授权 62 */
      max-width: 300px;
      padding: 6px 10px;
      border-radius: 8px;
      background: var(--tip-bg);
      color: #fff;
      font-size: 12px;
      line-height: 1.55;
      white-space: pre-line;
      /* 文案里写了 \n 就换行; 长编号 / 文件名没有空格也能断 */
      overflow-wrap: anywhere;
      pointer-events: none;
      opacity: 0;
      transform: translateY(2px);
      transition: opacity .12s ease, transform .12s ease;
    }

    .tip.on {
      opacity: 1;
      transform: none;
    }

    /* ── 轻提示: 非阻塞的短句回执(见 JS 的 toast) ──
       与上面那枚 #tip 是两回事: 那枚由 pointerover 驱动, 鼠标一动就收 —— 拿它报
       "这次操作没成", 用户手一抬就闪没了。这枚不接指针事件, 说完自己走。
       观感照抄 #tip(同 --ink 底 + 白字), 全站两种气泡才像一家人。
       压顶居中: 顶部中间是空的(顶栏控件都靠右), 不挡输入框也不挡对话正文。 */
    .toast {
      position: fixed;
      left: 50%;
      top: 14px;
      z-index: 70;
      max-width: min(420px, calc(100vw - 32px));
      padding: 8px 14px;
      border-radius: 9px;
      background: var(--tip-bg);
      color: #fff;
      font-size: 12.5px;
      line-height: 1.6;
      text-align: center;
      box-shadow: var(--shadow-sm);
      pointer-events: none;
      opacity: 0;
      transform: translate(-50%, -6px);
      transition: opacity .18s ease, transform .18s ease;
    }

    .toast.on {
      opacity: 1;
      transform: translate(-50%, 0);
    }

    /* 撤销键: .toast 整体 pointer-events: none(不挡下面的界面), 只有这颗按钮要能点。
       亮蓝 + 下划线, 与深底白字区分开又不抢镜(见 JS 的 toast 第三个参数)。 */
    .toast-act {
      pointer-events: auto;
      margin-left: 10px;
      padding: 0;
      border: none;
      background: none;
      color: #9ED4FF;
      font: inherit;
      font-size: 12.5px;
      text-decoration: underline;
      cursor: pointer;
    }

    /* ── 确认弹窗(全站唯一一枚, 替代原生 confirm; 见 JS 的 appConfirm) ──
       壳子直接复用 .mdl(购买/授权/预览同一个模子, 见 data-panel.css), 这里只补三处:
       1) 层级 —— 它可能盖在预览/授权之上再弹出来(删数据集时身后常常开着预览), .mdl 是 62;
       2) 正文换行 —— 确认文案里的 \n\n 是本意(先问一句, 再单独一行说后果), 默认会被
          当空白折叠掉, pre-line 才留得住;
       3) 两颗按钮 —— 「取消」是白底描边的次要动作, danger 那颗给不可逆的动作(删除)用红底,
          与全站的错误色同一个 --red。 */
    .mdl.mdl-confirm {
      z-index: 64;
    }

    .mdl-confirm .mdl-lead {
      white-space: pre-line;
    }

    .mdl-btn.ghost {
      background: var(--card);
      color: var(--muted);
      border: 1px solid var(--line);
    }

    .mdl-btn.ghost:hover {
      color: var(--brand);
      border-color: var(--brand);
      background: var(--brand-soft);
    }

    .mdl-btn.danger {
      background: var(--red);
    }

    /* ── 购买 AI 点弹窗(见 index.html 的 #pts) ──
       壳照抄 #auth 那一枚, 这里只补一处层级。.mdl 是 62、确认框是 64, 它取 63 —— 它可能
       盖在设置弹窗上弹出来(402 那条路: 用户正开着设置弹窗, 后端回"点不够" → 直接弹买点),
       所以要在 #acct 之上; 而确认框还能盖在它上面(买点弹窗里再问一句什么的话), 所以要在
       64 之下。DOM 里它也排在 #acct 之后, 两条一起保证同层时压得住。 */
    .mdl.mdl-pts {
      z-index: 63;
    }

    /* 页脚那枚「购买会员，到账 AI 点」: 铺满整宽、标签靠左。
       它上头那段说明(会员有效期至…)与下头的商品行都是从正文左缘起排的, 而这枚药丸原先
       贴着字宽、字在药丸里居中 —— 那行字看着就比上面缩进一格(393 上是 19px), 像没对齐。
       铺满整宽之后盒子左缘就是正文那条左缘; 字从居中改靠左, 左边留 10px 不啃到 1px 边框上
       (给 0 字就贴上去了, 渲染出来像坏了)。右边不留: 那是"靠左"该有的样子。
       只管 #pts 这一枚(带 .mdl-pts 前缀), 别的弹窗页脚那几颗不动。 */
    .mdl-pts .mdl-foot .mdl-btn {
      flex: 1;
      text-align: left;
      padding-left: 10px;
    }
