/* ============================================================
   飞行审批 · 批量受理
   —— 只在「待我受理」出现，尺度按这一列的实际尺寸写：
      面板 484 / 560 宽、卡 padding 11·13·11·15、底栏 46 高
   —— 操作条不住在列表顶上：它接的是列表面板自己那条底栏
     （#apvr-foot.is-batch）。进批量，只把左端那半格「共 N 条」让出来，
      翻页胶囊原样搬到这个位置上继续用（页码、每页条数都还是列表那一套），
      右端只留一个动作：「已选 N ｜ 开始批量检测」（不设「取消」——退出就是退路）；
      退出时整条原样还回去
   —— 结果卡不是新语言：它就是一张「待我受理」卡（同名、同编号行、
      同性质时间框），只在中间多一行检测结论、右上多一枚结论胶囊。
      同一条申请在两处必须是同一张脸
   —— 勾选圈挂在卡片 ::after 上（选中态画一枚对勾，空态只是一只空圈），
      卡片本身不插节点：翻页重绘、逐秒刷新都不会碰到它
   ============================================================ */

/* —— 结果态：整条筛选行收起 ——
   名单已经定了，再摆一排「换个时间看看」只是让人分心；
   收起来之后名单直接从页签下面长出来，顶上不留空场。
   回选择态时这条行连同开关一起回来（脚本 setQuiet(false)） */
#apvr-filter.is-quiet { display: none; }

/* —— ① 筛选条不动 ——
   批量是一种「选」，不是换了一页：日期、筛选、以及那颗开关本身都要在原地，
   人得看得见「我现在是在什么条件下选的」。改条件会换一批数据、勾选随之作废，
   那由脚本收尾（见 apvr:filter），不靠把这一行藏掉 */

/* ============================================================
   ② 底栏：批量操作条
   —— 它取代列表底栏的位置与外壳（#apvr-foot 自带顶部发丝线与面板底缘），
      这里只负责内部排布：左端读数、右端动作，两端拉开
   ============================================================ */
#apvr-panel .apvr-foot.is-batch { height: 46px; }

.apvb-bar {
  display: flex; align-items: center; gap: 7px;
  width: 100%; height: 100%;
  animation: apvb-bar-in 220ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes apvb-bar-in {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}

/* 选择 / 检测态的读数：数字是这一条里唯一会变的东西，给它暖色；
   上限常驻淡着，人不用去数还有几个名额 */
.apvb-n {
  flex-shrink: 0;
  font-size: calc(var(--fs-l3) - 0.5px); letter-spacing: 0.2px;
  color: rgba(198, 216, 234, 0.62);
  font-variant-numeric: tabular-nums;
}
.apvb-n b {
  display: inline-block; min-width: 1.15em; text-align: center;
  font-family: var(--font-mono);
  font-size: calc(var(--fs-l3) + 2.5px); font-weight: 500; color: #EFC08A;
  text-shadow: 0 0 12px rgba(232, 184, 121, 0.28);
  transition: color 160ms ease;
}
.apvb-n i { font-style: normal; color: rgba(198, 216, 234, 0.32); }

/* 中间那格：列表自己的翻页胶囊（.apva-pgt）原样住进来。
   它是列表现成的控件，批量只是把这半格让给它——
   「共 N 条」那半段不进来：左边那句「已选 N/15」已经报了规模，
   两条读数并排只会让人多算一次 */
.apvb-slot {
  display: inline-flex; align-items: center; flex-shrink: 0;
  height: 100%;
}
.apvb-slot .apva-ft-st { display: none; }
.apvb-slot .apva-ft { gap: 0; }

/* —— 结果态不报规模 ——
   名单本身就是答案：几条退回、几条通过，看分节一目了然。
   再在左端压一行「已检测 M · 1 退回 0 关注 3 通过」，
   等于把同一件事说第二遍，还把三个动作挤到右端去 */
/* 动作组：按动作轻重分三档——
   重新检测是重做、返回列表是退路（两枚有框无色），提交是往前走（唯一的实心）。
   选择态压在右端（左边有读数，动作该落在视野落点上）；
   结果态左端空了，这组就居中站——不偏不倚，三个动作一样近 */
.apvb-act {
  margin-left: auto; flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 7px;
}
.apvb-act.is-center { margin-left: 0; margin-right: 0; margin-inline: auto; gap: 10px; }

.apvb-btn {
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  height: 26px; padding: 0 8px;
  border: 1px solid transparent; border-radius: 7px;
  background: transparent;
  font-family: inherit; font-size: 11.5px; letter-spacing: 0.5px;
  color: rgba(206, 224, 240, 0.82);
  cursor: pointer; white-space: nowrap;
  transition: color 180ms ease, background 180ms ease,
              border-color 180ms ease, filter 160ms ease;
}
/* 图标：1.3 的发丝线，跟着字色走——它是动词的副词，不是插图 */
.apvb-btn > svg {
  width: 12.5px; height: 12.5px; flex-shrink: 0;
  fill: none; stroke: currentColor; stroke-width: 1.3;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: 0.82;
  transition: opacity 180ms ease;
}
.apvb-btn:hover > svg { opacity: 1; }
.apvb-btn > span + span, .apvb-btn > svg + span { margin-left: 6px; }

.apvb-btn:focus { outline: none; }
.apvb-btn:focus-visible {
  outline: none;
  border-color: rgba(240, 198, 143, 0.5);
  color: #F6E0BE;
}

/* 退路 / 重做：一枚薄框，hover 才亮 */
.apvb-btn.is-ghost {
  border-color: rgba(168, 196, 220, 0.14);
  background: rgba(255, 255, 255, 0.024);
  color: rgba(202, 222, 240, 0.8);
}
.apvb-btn.is-ghost:hover {
  border-color: rgba(168, 196, 220, 0.26);
  background: rgba(255, 255, 255, 0.055);
  color: #EDF4FB;
}
.apvb-btn.is-ghost:active { background: rgba(255, 255, 255, 0.075); }

/* 主按钮：选完就该按它，它是这条栏上唯一的实心，也是唯一的动作。
   按钮里装着「已选几条」——读数、一道发丝线、一句动词：左边是现状，右边是去处。

   配色是「半透石墨」：中性灰的底子里带一点透明度，
   让栏本身的暗色从底下透上来，它就不是一块贴上去的板，而是这层玻璃上的一块厚玻璃。
   不用蓝相：偏蓝的深灰在暗底上会发灰、发旧（那种「褪色的藏青」）；
   中性灰加一半通透反而干净——上沿一道高光压住边缘，外圈一道 0.18 的浅边，
   它靠「通透 + 厚度」立住，不靠颜色。 */
.apvb-btn.is-main {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 9px;
  height: 30px; padding: 0 16px 0 14px;
  border: 0; border-radius: 8px;
  background: linear-gradient(180deg, rgba(70, 80, 95, 0.58) 0%, rgba(28, 34, 44, 0.72) 100%);
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.5px; line-height: 1;
  color: #F0F5FC;
  box-shadow:
    inset 0 0 0 1px rgba(190, 212, 236, 0.20),
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    0 0 0 1px rgba(150, 180, 215, 0.07),
    0 4px 16px -11px rgba(0, 0, 0, 0.9);
}
.apvb-btn.is-main:hover {
  background: linear-gradient(180deg, rgba(80, 91, 107, 0.66) 0%, rgba(34, 40, 51, 0.78) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(206, 226, 246, 0.30),
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    0 0 0 1px rgba(160, 190, 225, 0.12),
    0 6px 20px -12px rgba(0, 0, 0, 1);
}
.apvb-btn.is-main:active { filter: brightness(0.94); }
/* 墨面上的字：三档都加粗，靠明度分层而不是靠字重——
   「已选」压到 56%（它是读数不是动作），数量纯白（它是唯一会变的字），
   动词压在 600 上；一道 26% 冷蓝竖线隔开「几条」与「做什么」 */
.apvb-btn.is-main .apvb-lab { color: rgba(206, 222, 240, 0.58); opacity: 1; }
.apvb-btn.is-main .apvb-cnt { color: #FFFFFF; }
.apvb-btn.is-main .apvb-cnt-s { height: 12px; background: rgba(255, 255, 255, 0.22); opacity: 1; }
/* 按钮里的读数：一句「已选」贴着数字，读起来是一个短语而不是两段字；
   数字用等宽，比动词再重一档——它是这枚按钮里唯一会变的字。
   两截都用 line-height:1 并交给 flex 居中：字身盒子等高铁定，上下才不会一边紧一边松 */
.apvb-pick {
  display: inline-flex; align-items: center; gap: 5px;
  line-height: 1;
}
.apvb-pick > * { line-height: 1; }
.apvb-lab {
  font-size: 12px; font-weight: 600; letter-spacing: 0.3px;
  opacity: 0.72;
}
.apvb-cnt {
  font-family: var(--font-mono); font-weight: 700;
  font-size: 12.5px; line-height: 1; letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  min-width: 1em; text-align: center;
}
.apvb-cnt-s {
  width: 1px; height: 11px; flex-shrink: 0;
  background: currentColor; opacity: 0.22;
}

/* 一条没选时它不该是一枚亮按钮：留形状、撤颜色。
   亮面收成一块暗玻璃、补一圈发丝——位置还在，只是不亮 */
.apvb-btn.is-main:disabled,
.apvb-btn.is-main:disabled:hover {
  background: rgba(255, 255, 255, 0.022);
  color: rgba(172, 190, 208, 0.30);
  box-shadow: inset 0 0 0 1px rgba(150, 178, 206, 0.09);
  filter: none; cursor: default;
}
.apvb-btn.is-main:disabled .apvb-lab { color: inherit; }
.apvb-btn.is-main:disabled .apvb-cnt { color: rgba(192, 210, 228, 0.44); }
.apvb-btn.is-main:disabled .apvb-cnt-s { background: currentColor; opacity: 0.18; }
/* 二次确认：按钮自己换一句话，不弹窗、不加解释条。
   红是「这一步不可逆」的通用信号，只在武装的那几秒出现；
   红面比蓝面浅，字必须跟着压深，否则白字压红只会发糊 */
.apvb-btn.is-main.is-armed {
  background: linear-gradient(180deg, #EDA294 0%, #CE7265 100%);
  color: #2A0F0C;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.36),
    0 0 0 1px rgba(232, 119, 107, 0.35),
    0 3px 14px -6px rgba(232, 119, 107, 0.9);
}

/* 红面上的字：同族深棕三档，竖线也压到深棕 26% */
.apvb-btn.is-main.is-armed .apvb-lab { color: rgba(42, 15, 12, 0.58); }
.apvb-btn.is-main.is-armed .apvb-cnt { color: #2A0F0C; }
.apvb-btn.is-main.is-armed .apvb-cnt-s { background: rgba(42, 15, 12, 0.26); }

/* 到顶那一刻，上限读数转暖：不用另起一行说「已达上限」，
   把「/ 15」从灰变金，就是那句话 */
.apvb-bar.is-full .apvb-n i { color: #C9A46A; }
.apvb-bar.is-full .apvb-n b { color: #F6D9B0; }

/* ============================================================
   ③ 选择态卡片：勾选圈
   —— 圈落在原 padding-left 的那块留白里（15 → 44），
      首行文字整体右移一格，卡片高度、行数、圆角都不动
   ============================================================ */
.apvr-content.is-batch .apva-card {
  padding-left: 44px;
  cursor: default;
}
/* 选择态下卡片不再「悬停即入口」：悬停仍给一层薄雾，但不加色脊、不浮起 */
.apvr-content.is-batch .apva-card:hover { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.apvr-content.is-batch .apva-card:focus-visible { outline: none; }

.apvr-content.is-batch .apva-card::after {
  content: "";
  position: absolute; left: 15px; top: 13px;
  width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid rgba(168, 196, 220, 0.33);
  background: rgba(255, 255, 255, 0.022);
  transition:
    background 160ms ease, border-color 160ms ease,
    box-shadow 200ms ease, transform 160ms cubic-bezier(0.22, 1, 0.36, 1);
  animation: apvb-cb-in 240ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes apvb-cb-in {
  from { opacity: 0; transform: scale(0.76); }
  to   { opacity: 1; transform: none; }
}

/* 选中：圈填暖色、画一枚对勾，卡片同时亮起一道同色描边。
   只有「选没选」这一件事——圈里不写序号：批量是先把人挑出来，
   第几个点的跟这一批要办的事没有关系；数目已经有底栏那颗按钮在报。
   对勾走内联 SVG 而不是字形：字形在等宽 / 系统字体里粗细不一，
   落在 17px 的圈里会被抗锯齿吃成一根灰线 */
.apvr-content.is-batch .apva-card.is-pick::after {
  border-color: rgba(242, 201, 148, 0.92);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='11' viewBox='0 0 11 11'%3E%3Cpath d='M2.2 5.7 L4.3 7.8 L8.8 3.1' fill='none' stroke='%2320160A' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"),
    linear-gradient(180deg, #F3CA95 0%, #D6A45E 100%);
  background-size: 11px 11px, 100% 100%;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  box-shadow: 0 0 10px -2px rgba(232, 184, 121, 0.8);
  transform: scale(1);
}
.apvr-content.is-batch .apva-card.is-pick {
  border-color: rgba(232, 184, 121, 0.42);
  background:
    radial-gradient(118% 100% at 0% 0%, rgba(232, 184, 121, 0.135) 0%, rgba(232, 184, 121, 0.018) 58%, rgba(232, 184, 121, 0) 100%),
    linear-gradient(180deg, rgba(92, 122, 152, 0.045) 0%, rgba(42, 56, 72, 0.012) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    inset 0 0 20px rgba(232, 184, 121, 0.035);
}
.apvr-content.is-batch .apva-card.is-pick:hover {
  border-color: rgba(232, 184, 121, 0.55);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.075),
    inset 0 0 22px rgba(232, 184, 121, 0.05);
}

/* 满额：未选的圈转淡，再点只抖一下。不弹提示条——
   十五这条线是人自己看着计数撞上的，再补一句解释是侮辱。
   圈淡到 0.3 就近乎消失了，会让人以为这些卡坏了；留 0.5，
   看得见、点不动，光标给 not-allowed 把话说清楚 */
.apvr-content.is-batch.is-full .apva-card:not(.is-pick)::after { opacity: 0.5; }
.apvr-content.is-batch.is-full .apva-card:not(.is-pick) { cursor: not-allowed; }
.apvr-content.is-batch.is-full .apva-card:not(.is-pick):hover {
  border-color: rgba(168, 196, 220, 0.085);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.045);
}

/* 已受理：不进这一批。圈收掉、左边距还原、整张卡退到背景里，
   让「还能选的那几张」在视觉上先站成一排 */
.apvr-content.is-batch .apva-card[data-urg="done"] {
  padding-left: 15px;
  opacity: 0.46;
  cursor: default;
}
.apvr-content.is-batch .apva-card[data-urg="done"]::after { display: none; }

/* 满额误触：抖一下，不换色、不出字 */
.apvb-shake { animation: apvb-shake 380ms cubic-bezier(0.36, 0.07, 0.19, 0.97); }
@keyframes apvb-shake {
  10%, 90% { transform: translateX(-1.5px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-3px); }
  40%, 60% { transform: translateX(3px); }
}

/* —— 未开智能检测时按批量：让开关自己说话 ——
   光从开关上闪两下，比任何一句「请先开启智能检测」都快 */
#apvr-sw.apvb-need { animation: apvb-need 1.15s ease; }
@keyframes apvb-need {
  0%, 100% { box-shadow: none; }
  12%, 44% {
    box-shadow:
      0 0 0 1.5px rgba(240, 198, 143, 0.62),
      0 0 16px rgba(232, 184, 121, 0.42);
  }
  28%, 60% { box-shadow: 0 0 0 1.5px rgba(240, 198, 143, 0.12); }
}

/* ============================================================
   ④ 检测与结果：同一族卡片
   —— 不另起一套「报告体」：结果卡沿用列卡片的长相（玻璃底、左缘色脊、
      渐变标题、编号行、性质时间框），只多两件批量的东西——
      右上那枚结论胶囊（几处冲突 / 几项提示）与一行结论（为什么被拎出来）。
      分组标题是这一屏唯一「不像卡」的部分：它读作目录，不作控件
   ============================================================ */

/* 结果态不再自己收右内距。
   原先这里写 padding-right: 6px 想把宽度让给名单，可右侧还有一条常驻的
   滚动指示（.apvr-scroll，right 6px / 宽 3px，2K 下 7px / 4px）——
   6px 的右内距正好让卡片压到那条指示上，看着像错位。
   现在回到容器自己的 12px（2K 14px），卡片右缘与左缘同口径，指示条也留出位置。
   再多让 2px：指示条在滚动时会亮起来，贴着走仍像没对齐，留一条缝才干净 */
#apvr-content.is-scan,
#apvr-content.is-result { padding-right: 14px; }
@media (min-width: 2048px) {
  #apvr-content.is-scan,
  #apvr-content.is-result { padding-right: 17px; }
}

.apvb-stage {
  display: flex; flex-direction: column;
  min-height: 100%;
  padding-bottom: 10px;
}

/* 扫描屏退场。
   这一下以前没有：光收、压暗带撤、下一帧 innerHTML 就被换掉，
   卡片重排和滚动归零全挤在同一瞬间，读起来是「页面被刷新了」。
   现在让这一屏自己沉下去、淡出去（380ms，退到七成才换内容），
   换掉的那一下正好落在它看不见的时候，结果那边再逐节浮起——
   两头叠着，中间那段「什么都没有」的空白就不存在了。
   位移只给 10px 并且往上走：往下沉会跟结果进来的方向撞在一起，像抖了一下 */
.apvb-stage.is-leaving {
  animation: apvb-leave 380ms cubic-bezier(0.42, 0, 0.28, 1) both;
  transform-origin: 50% 0;
  pointer-events: none;
  will-change: opacity, transform;
}
/* 退场用关键帧而不是 transition：transition 要有一个「前值」才动，
   而这一屏在加类的同一帧里还可能被别处重排（滚动、刷新），
   关键帧把起点写死成「现在这样」，加多少类都是同一条曲线 */
@keyframes apvb-leave {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-10px); }
}

/* 结果入场：不再整屏一次性淡进来。
   单条检测那边是「扫描走完 → 结果一块一块浮出来（三块错峰 520ms、每块 980ms）」，
   批量这里原来是 320ms 整屏 in，读起来是「页面刷新了」，不是「结论出来了」。
   现在按同一套语气拆开：节错峰 300ms 起、每节 620ms 浮到位，
   节内再逐条落 60ms 起——一屏六条要有个先来后到，眼睛才有地方落。
   首节不压延迟：换屏那一帧它就得开始起，否则中间会空出一小段全黑 */
.apvb-stage.is-fresh .apvb-g {
  animation: apvb-fresh 620ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--gi, 0) * 300ms);
}
@keyframes apvb-fresh {
  from { opacity: 0; transform: translateY(12px); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: none; }
}
.apvb-stage.is-fresh .apvb-gb > * {
  animation: apvb-rise 560ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--gi, 0) * 300ms + 90ms + var(--j, 0) * 60ms);
}
@keyframes apvb-rise {
  from { opacity: 0; transform: translateY(7px); }
  55%  { opacity: 1; }
  to   { opacity: 1; transform: none; }
}

/* —— 分节 —— */
.apvb-groups { display: flex; flex-direction: column; gap: 22px; padding: 8px 0 8px; }

.apvb-g { --gc: 168, 196, 220; }
.apvb-g.is-fail { --gc: 232, 119, 107; }
.apvb-g.is-warn { --gc: 224, 169, 104; }
.apvb-g.is-pass { --gc: 126, 201, 166; }
.apvb-g.is-cross { --gc: 224, 169, 104; }

/* 分节标题：一条通长的「章节带」。
   之前是一枚小标签加一条几乎看不见的发丝线，标签只占左端一小截，
   眼一扫过去分不出「这是一节的开始」还是「一行小标题」。
   现在让它横贯整行：左端一道 3px 实色脊贴边立住，底子从左往右
   由浓到无地淡出去，整条包一圈同色发丝——它是这一节的横幅，
   而不是标题旁边的一枚签。
   带里只写类名：条数下面一眼数得出，右端口径是同一句话说第二遍 */
.apvb-gh {
  position: relative;
  display: flex; align-items: center;
  height: 32px; padding: 0 13px 0 16px;
  border-radius: 7px;
  overflow: hidden;
  background: linear-gradient(90deg,
    rgba(var(--gc), 0.245) 0%,
    rgba(var(--gc), 0.120) 25%,
    rgba(var(--gc), 0.042) 56%,
    rgba(var(--gc), 0.012) 80%,
    rgba(255, 255, 255, 0.010) 100%);
  /* 四条内影各管一层：边（一圈发丝）、上（一道高光）、下（一道同色内影，
     让它有「厚度」，而不是一张纸贴在面板上）、外（一层同色落影） */
  box-shadow:
    inset 0 0 0 1px rgba(var(--gc), 0.27),
    inset 0 1px 0 rgba(255, 255, 255, 0.11),
    inset 0 -1px 0 rgba(var(--gc), 0.11),
    0 8px 22px -18px rgba(var(--gc), 0.95);
}
/* 左端色脊：不是把整条边染上色，而是一根「短脊」——
   上下各留 6px、两端 2px 圆角、贴住左缘。
   撑满全高时它读作「这条边是红的」，收短之后读作「这里插了一枚标记」，
   一个小动作的差别，但整条带子的气质就从上色变成标记 */
.apvb-gh::before {
  content: '';
  position: absolute; left: 0; top: 6px; bottom: 6px; width: 3.5px;
  border-radius: 2px;
  background: rgb(var(--gc));
  box-shadow: 2px 0 11px -1px rgba(var(--gc), 0.9);
}
.apvb-gn {
  flex-shrink: 0; position: relative;
  font-size: 13px; font-weight: 600; letter-spacing: 1.7px;
  color: rgb(var(--gc));
  text-shadow: 0 0 15px rgba(var(--gc), 0.55);
}

/* —— 每一条：一张与「待我受理」同族的卡 ——
   底子是列卡片那套玻璃（不整片染组色：十五张卡一起上色，
   分组就不再是分组，而是三块红黄绿的色板），组色只留给左缘那道 2px 色脊 */
.apvb-gb { display: flex; flex-direction: column; gap: 10px; padding: 7px 0 2px; }

.apvb-item {
  --gc: 168, 196, 220;   /* 扫描态还没有分组：给徽标一个中性组色，别让它落到未定义 */
  position: relative;
  padding: 11px 13px 11px 15px;
  border-radius: 10px;
  border: 1px solid rgba(168, 196, 220, 0.085);
  background:
    radial-gradient(120% 92% at 0% 0%, rgba(124, 158, 192, 0.05) 0%, rgba(124, 158, 192, 0) 62%),
    linear-gradient(180deg, rgba(92, 122, 152, 0.048) 0%, rgba(42, 56, 72, 0.014) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.045),
    inset 0 0 18px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: border-color 220ms ease, box-shadow 220ms ease;
}
/* 色脊与卡片同款：上亮下隐，hover 才点满 */
.apvb-item::before {
  content: '';
  position: absolute; left: 0; top: 11px; bottom: 11px; width: 2px;
  border-radius: 0 2px 2px 0;
  background: linear-gradient(180deg, rgba(var(--gc), 0.45) 0%, rgba(var(--gc), 0.05) 100%);
  box-shadow: 0 0 5px rgba(var(--gc), 0.12);
  transition: width 220ms ease, background 220ms ease, box-shadow 220ms ease;
}
.apvb-item:hover {
  border-color: rgba(178, 200, 222, 0.2);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.075),
    inset 0 0 22px rgba(0, 0, 0, 0.12),
    0 3px 16px -8px rgba(4, 12, 22, 0.7);
}
.apvb-item:hover::before {
  width: 3px;
  background: linear-gradient(180deg, rgba(var(--gc), 0.92) 0%, rgba(var(--gc), 0.1) 100%);
  box-shadow: 0 0 12px rgba(var(--gc), 0.38);
}
.apvb-item:active { filter: brightness(0.98); }
.apvb-item:focus-visible {
  outline: none;
  border-color: rgba(var(--gc), 0.55);
  box-shadow: inset 0 0 0 1px rgba(var(--gc), 0.35);
}

/* 首行：任务名称 + 结论胶囊 —— 与列卡片的首行同一副骨架 */
.apvb-top {
  position: relative;
  display: flex; align-items: flex-start; gap: 10px;
  padding-bottom: 8px; margin-bottom: 8px;
}
.apvb-top::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg,
    rgba(200, 216, 232, 0.105) 0%,
    rgba(200, 216, 232, 0.048) 58%,
    rgba(200, 216, 232, 0) 100%);
}
.apvb-nm {
  flex: 1; min-width: 0; margin: 0;
  font-size: 13.5px; font-weight: 600; line-height: 1.4; letter-spacing: 0.3px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  background: linear-gradient(180deg, #F1F8FE 0%, #CFE4F5 52%, #A6C6E2 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: #D5E4F0;
}
/* 结论胶囊：说的是「几处冲突 / 几项提示」，不是组名——
   组名已经写在这一节的标题上，胶囊再复述一遍就是同一句话说两遍 */
/* 结论胶囊：一枚「读数章」。之前是 1px 内距 + 0.09 底 + 0.22 边，
   压在深色卡上薄得像一行小字；现在给它实体：
   底子抬到 0.13、边 0.34、内距 2×9、外加一道顶部高光与一圈同色微晕，
   数字用等宽加粗、量词用正文字，两种字分工——先说几处，再说是什么 */
.apvb-pill {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 5px;
  margin-top: 0; padding: 2px 9px 2px 8px;
  border-radius: 6px; white-space: nowrap;
  color: rgb(var(--gc));
  background: linear-gradient(180deg, rgba(var(--gc), 0.17) 0%, rgba(var(--gc), 0.09) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(var(--gc), 0.34),
    inset 0 1px 0 rgba(255, 255, 255, 0.10),
    0 0 12px -6px rgba(var(--gc), 0.85);
}
.apvb-pill > i {
  width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0;
  background: currentColor; box-shadow: 0 0 7px currentColor;
}
.apvb-pill > b {
  font-family: var(--font-mono); font-weight: 700;
  font-size: 12px; line-height: 1.35; letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.apvb-pill > span {
  font-size: 11px; font-weight: 500; line-height: 1.35; letter-spacing: 0.4px;
}

/* 次行：申报编号 · 申请类型 · 申报方（.apva-no / .apva-dot / .apva-ty /
   .apva-by 直接沿用列卡片那套零件：字号、间距、圆点全不必再定义一遍） */
.apvb-sub {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  font-size: 13px; line-height: 1.6;
}

/* 结论：不再用一道竖线做引文（那道线在暗底上既空又硬，读起来像
   贴了一张错题本）。改成一枚「徽标 + 一句判断」：
   徽标是有语义的记号（三角警示 / 圆形感叹 / 勾），装在同色的
   圆底里，亮一档，扫读时眼睛先落在这里，再读右边那句结论。
   三档都有：通过档写的不是「建议通过」，而是「凭什么放行」 */
.apvb-vd {
  display: flex; align-items: flex-start; gap: 8px;
  margin-top: 10px;
  font-size: 12px; font-weight: 500; line-height: 1.55; letter-spacing: 0.2px;
  color: rgba(226, 238, 250, 0.9);
}
.apvb-vd > span { min-width: 0; }
.apvb-vdi {
  flex-shrink: 0;
  width: 16px; height: 16px; margin-top: 1.5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  color: rgb(var(--gc));
  background: radial-gradient(circle at 50% 28%, rgba(var(--gc), 0.26) 0%, rgba(var(--gc), 0.10) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(var(--gc), 0.34),
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 0 12px -4px rgba(var(--gc), 0.8);
}
.apvb-vdi > svg {
  width: 10px; height: 10px;
  fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
.apvb-item[data-mood="fail"] .apvb-vd { color: #F7C3B9; }
.apvb-item[data-mood="warn"] .apvb-vd { color: #F2D3A6; }
.apvb-item[data-mood="pass"] .apvb-vd { color: rgba(174, 218, 196, 0.9); }
/* 需协调：不放绿。这条自己六项都过了，可它现在要人动一下手，
   绿在这里的意思是「不用管」——那是这一屏最不该给它的暗示 */
.apvb-item[data-mood="cross"] .apvb-vd { color: #F2D3A6; }

/* 末行：性质 ｜ 起止时间 —— .apvx-meta 那枚修饰框原样搬来，
   框里是读数、框外是叙述，两种质地分开 */
.apvb-item .apvx-meta { margin-top: 8px; }

/* —— 批内交叉：一个框圈住两条完整的申请 ——
   冲突不是一条申请的一个属性，而是两条申请之间的一件事。
   框负责说「这两个撞上了」（重叠多久、撞在哪一段、为什么算撞），
   框里两条各自仍然是一张完整的结果卡——不是一行摘要。
   摘要行（名称 + 时段）看着省地方，但判断「怎么处置」要看的是
   申报方、性质、类型、时段这一整套；压成一行，人就得点进去再看一遍，
   而点进去一次只看得见一条，看完还得回来点第二条。
   所以这里宁可高一倍：两条的计划信息一次摆齐，框把它们绑成一对 */
.apvb-xg {
  position: relative;
  border-radius: 11px;
  border: 1px solid rgba(224, 169, 104, 0.17);
  /* 框体不上色：这张框的职责是「圈住这两个」，不是把这两条染成橙色。
     铺一层橙底，框里的卡就与上面各节那几张不是同一个质地了，
     读起来像「另一类数据」；透明底 + 一道橙边 + 一条橙头，
     层级反而更清楚——边是关系，卡是数据 */
  background: transparent;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.045);
  overflow: hidden;
}
.apvb-xg + .apvb-xg { margin-top: 10px; }

/* 框头：先说「撞了多久、撞在哪一段」，再说「为什么算撞」。
   字号与卡片里那枚修饰框（.apvx-meta：12px / 16px）一致——
   这一行和「性质 ｜ 起止时间」是同一档读数，不该比它小半号 */
.apvb-xh {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 12px;
  border-bottom: 1px solid rgba(224, 169, 104, 0.11);
  background: rgba(224, 169, 104, 0.05);
  font-size: 12px; line-height: 16px; letter-spacing: 0.2px;
  color: rgba(224, 178, 120, 0.88);
}
.apvb-xht { flex-shrink: 0; white-space: nowrap; }
/* 数字与时刻只换字体和字重，不换字号：同一行里的「180」和「分钟」
   要是差半号，读起来就是两个层级的东西，其实它们是一句话 */
.apvb-xht b {
  font-family: var(--font-mono); font-weight: 600;
  font-size: 12px; color: #F4CE9C;
  font-variant-numeric: tabular-nums;
}
.apvb-xht em {
  font-style: normal; margin-left: 7px;
  font-family: var(--font-mono); font-size: 12px;
  color: rgba(232, 196, 150, 0.72);
  font-variant-numeric: tabular-nums;
}
.apvb-xhw {
  margin-left: auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: 12px; line-height: 16px;
  color: rgba(212, 174, 130, 0.62);
}

/* 框里两张卡：与上面各节里那张脸完全一样，只把底边收窄一档，
   免得和外框自己那道描边叠成一条双线 */
.apvb-xb {
  display: flex; flex-direction: column; gap: 8px;
  padding: 9px;
}
.apvb-xb .apvb-item {
  border-color: rgba(168, 196, 220, 0.07);
}

/* —— 检测中：一道光缝自上而下读过去 ——
   下面这些零件与单条详情那套（flight-approval-smart.css ② 扫描舞台）同源：
   白芯 + 上下两撇色散 + 头顶竖纹读痕 + 身下前溢 + 两端光斑。
   同一件事，两处不该长两张脸；批量这边只做两处让步——
   舞台从「一整块正文」变成「一叠卡片」，光缝因此必须由脚本逐条推进，
   才能和「正在核验 7/15」的读数落在同一拍上 */
.apvb-scan {
  position: relative;
  padding-top: 6px;
}

.apvb-beam {
  position: absolute; left: 0; right: 0; top: 0; height: 0;
  z-index: 3; pointer-events: none;
  visibility: hidden;
  will-change: transform;
  /* 一个步长走完一段：匀线速度，不缓动——光和读数共一条时间轴，
     缓动会在每一段末尾先减速、再跳，节奏就跟读数错开了 */
  transition:
    transform var(--apvb-step, 520ms) linear,
    opacity 300ms ease;
}
/* 入场不走淡入：光芯自己会从中线抽出来，那已经是入场了。
   再叠一层 opacity 渐变，等于让光「先半亮着走两步」——
   实测首帧被渲染压住时，位置已经在动、亮度还停在 0，
   头两条会在看不见的光里被读完 */
.apvb-stage.is-sweep .apvb-beam { visibility: visible; }
.apvb-stage.is-swept .apvb-beam { opacity: 0; }

/* 白芯：两端收掉、中段提纯白。起手先从中间抽出来（scaleX 0.16 → 1），
   抽满才开始走——那是「上膛」，不是「出现」 */
.apvb-beam-core {
  position: absolute; left: 0; right: 0; top: -1px; height: 1.5px;
  mix-blend-mode: screen;
  transform: scaleX(0.16);
  transition: transform var(--apvb-lead, 420ms) cubic-bezier(0.2, 0.8, 0.3, 1);
  background: linear-gradient(90deg,
    rgba(150, 190, 230, 0) 0%,
    rgba(206, 228, 246, 0.72) 5%,
    #FFFFFF 18%,
    #FFFFFF 82%,
    rgba(214, 234, 250, 0.72) 95%,
    rgba(150, 190, 230, 0) 100%);
  box-shadow:
    0 0 2px rgba(255, 255, 255, 0.95),
    0 0 10px rgba(234, 245, 255, 0.95),
    0 0 28px rgba(140, 186, 230, 0.8),
    0 0 58px rgba(120, 168, 215, 0.32);
}
.apvb-stage.is-sweep .apvb-beam-core { transform: scaleX(1); }

/* 色散两撇：白线上下各一层雾，一条偏冷白、一条偏钢蓝。
   宽度只有 1px 的纯色线在这个尺寸上根本看不出来，色散要靠「雾」才成立 */
.apvb-beam-fr {
  position: absolute; left: 0; right: 0;
  mix-blend-mode: screen; pointer-events: none;
  filter: blur(3px);
}
.apvb-beam-fr.is-a {
  top: -19px; height: 18px;
  background: linear-gradient(180deg,
    rgba(150, 190, 230, 0) 0%,
    rgba(172, 206, 236, 0.34) 46%,
    rgba(214, 234, 250, 0.78) 100%);
}
.apvb-beam-fr.is-b {
  top: 2px; height: 11px;
  background: linear-gradient(180deg,
    rgba(198, 224, 244, 0.62) 0%,
    rgba(126, 170, 210, 0.24) 46%,
    rgba(90, 140, 190, 0) 100%);
}
/* 前溢：缝下方一小段被照亮，光才有推进的体积；再往下收干净，
   否则整叠卡片会被泡在一层白雾里 */
.apvb-beam-under {
  position: absolute; left: 0; right: 0; top: 1px; height: 26px;
  mix-blend-mode: screen;
  background: linear-gradient(180deg,
    rgba(214, 234, 250, 0.15) 0%,
    rgba(150, 190, 230, 0) 100%);
}
/* 竖纹读痕：缝上方一排 1px 短竖线横向流动。
   它把「正在解析」说得比任何一句文案都直接，也不占一行字的位置 */
.apvb-beam-ticks {
  position: absolute; left: 0; right: 0; top: -15px; height: 14px;
  mix-blend-mode: screen; opacity: 0.34;
  background-image: repeating-linear-gradient(90deg,
    rgba(228, 240, 250, 0.8) 0 1px, rgba(0, 0, 0, 0) 1px 7px);
  -webkit-mask-image: radial-gradient(112% 148% at 50% 100%, rgba(0, 0, 0, 0.95) 24%, rgba(0, 0, 0, 0) 84%);
  mask-image: radial-gradient(112% 148% at 50% 100%, rgba(0, 0, 0, 0.95) 24%, rgba(0, 0, 0, 0) 84%);
  animation: apvbTicks 0.9s linear infinite;
}
@keyframes apvbTicks {
  from { background-position: 0 0; }
  to   { background-position: 14px 0; }
}
/* 两端光斑：线走到卡片边不硬切，收成两个点光 */
.apvb-beam-glint {
  position: absolute; top: 0; width: 34px; height: 34px; margin-top: -17px;
  mix-blend-mode: screen;
  background: radial-gradient(closest-side,
    rgba(246, 252, 255, 0.88) 0%, rgba(156, 198, 234, 0.30) 44%, rgba(150, 190, 230, 0) 74%);
}
.apvb-beam-glint.is-l { left: -12px; }
.apvb-beam-glint.is-r { right: -12px; }

/* 压暗带：还没读到的那一半跟着光往下退。
   —— 这是「自上而下」的全部机关：整块压暗 + 一条亮线，读起来是
      「暗底上有条白杠在动」；压暗带跟着走，才是「光走过的地方读亮了、
      还没走到的地方还暗着」。分界就压在光缝脚下，留 54px 过渡给它的身体 */
.apvb-veil {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none; opacity: 0;
  background: linear-gradient(180deg,
    rgba(6, 10, 16, 0.02) 0%,
    rgba(6, 10, 16, 0.26) 62%,
    rgba(6, 10, 16, 0.40) 100%);
  -webkit-mask-image: linear-gradient(180deg,
    rgba(0, 0, 0, 0) calc(var(--sy, 0px) - 2px),
    rgba(0, 0, 0, 1) calc(var(--sy, 0px) + 54px),
    rgba(0, 0, 0, 1) 100%);
  mask-image: linear-gradient(180deg,
    rgba(0, 0, 0, 0) calc(var(--sy, 0px) - 2px),
    rgba(0, 0, 0, 1) calc(var(--sy, 0px) + 54px),
    rgba(0, 0, 0, 1) 100%);
  transition: opacity 320ms ease;
}
.apvb-stage.is-sweep .apvb-veil { opacity: 1; }
.apvb-stage.is-swept .apvb-veil { opacity: 0; transition-duration: 420ms; }

/* ============================================================
   检测中 · 面板边框光弧
   —— 与单条检测那圈同源（flight-approval-smart.css ① 边缘）：
      四角取景框 + 一圈内辉光 + 环上走的一束光。
      边框不是扫描的装饰，它和光缝是同一件事的两头：
      光缝在里头逐条读，边框在外头绕一圈，一头一尾同时起步、同时收。
   —— 周期由脚本写进 --apvb-orbit，值就是这一轮扫描的总长：
      绕完正好一圈，扫描结束的同一刻光回到起点收住。
      写死一个周期就成了「背景里自己在转的一圈边」，跟这场检测没关系了。
   ============================================================ */
@property --apvb-a {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.apvb-frame {
  position: absolute; inset: 0; z-index: 4;
  border-radius: inherit; overflow: hidden;
  pointer-events: none;
  visibility: hidden;
  transition: opacity 400ms ease;
}
/* 入场直接亮：边框是「通电」，它没有渐显这回事——光弧自己已经在转了，
   再叠一层 420ms 的淡入，只会让人先看见一圈灰边再亮起来。
   出场才淡：撤的时候要有收势，不能一刀切 */
.apvb-frame.is-on { visibility: visible; }
.apvb-frame.is-out { opacity: 0; }

/* 内侧通电辉光：光弧之外的第二层，让整块面板像被点亮了一圈。
   幅度压得很轻——它是「有余温」，不是「在闪」 */
.apvb-aura {
  position: absolute; inset: 0; border-radius: inherit;
  box-shadow:
    inset 0 0 38px rgba(120, 168, 208, 0.20),
    inset 0 0 1px rgba(214, 232, 246, 0.52);
  animation: apvbBreath 3.8s ease-in-out infinite;
}
@keyframes apvbBreath {
  0%, 100% { opacity: 0.68; }
  50%      { opacity: 1; }
}

/* 光弧本体：conic 铺满整块，双 mask 裁成 2.5px 的边框环。
   两层——.apvb-bloom 是同一支渐变的模糊版，负责溢出边框的光晕；
   .apvb-ring 保持锐利，负责那条看得清的亮线。
   只有锐线时，边光在深色玻璃上太薄；只有光晕时，又说不出是「光在走」。
   亮段接近纯白、暗段压到 0.04：光在边框上「走」不靠色相，靠明暗差在环上滑动 */
.apvb-ring, .apvb-bloom {
  position: absolute; inset: 0; border-radius: inherit; padding: 2.5px;
  background: conic-gradient(from var(--apvb-a, 0deg),
    rgba(255, 255, 255, 1) 0deg,
    rgba(234, 246, 255, 0.98) 7deg,
    rgba(198, 224, 244, 0.74) 18deg,
    rgba(162, 200, 232, 0.34) 34deg,
    rgba(150, 190, 230, 0.11) 56deg,
    rgba(150, 190, 230, 0.05) 88deg,
    rgba(150, 190, 230, 0.04) 176deg,
    rgba(178, 210, 238, 0.09) 196deg,
    rgba(200, 226, 244, 0.34) 208deg,
    rgba(172, 208, 236, 0.50) 216deg,
    rgba(160, 198, 232, 0.22) 230deg,
    rgba(150, 190, 230, 0.07) 252deg,
    rgba(150, 190, 230, 0.04) 310deg,
    rgba(150, 190, 230, 0.05) 360deg);
  -webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  -webkit-mask-clip: content-box, border-box;
  -webkit-mask-composite: xor;
  mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  mask-clip: content-box, border-box;
  mask-composite: exclude;
  animation: apvbOrbit var(--apvb-orbit, 4000ms) linear infinite;
}
.apvb-bloom { filter: blur(6px) saturate(0.92); opacity: 0.9; }
@keyframes apvbOrbit {
  from { --apvb-a: 0deg; }
  to   { --apvb-a: 360deg; }
}

/* 四角取景框：15px 的 L 形细线，向内 8px。
   比再加一圈边框轻，也不抢光弧——它只说「这块区域被系统框住了」 */
.apvb-corners { position: absolute; inset: 8px; }
.apvb-corners i {
  position: absolute; width: 15px; height: 15px;
  border: 1px solid rgba(206, 228, 246, 0.40);
  filter: drop-shadow(0 0 4px rgba(140, 182, 218, 0.6));
}
.apvb-corners i:nth-child(1) { left: 0; top: 0; border-right: 0; border-bottom: 0; border-radius: 2px 0 0 0; }
.apvb-corners i:nth-child(2) { right: 0; top: 0; border-left: 0; border-bottom: 0; border-radius: 0 2px 0 0; }
.apvb-corners i:nth-child(3) { right: 0; bottom: 0; border-left: 0; border-top: 0; border-radius: 0 0 2px 0; }
.apvb-corners i:nth-child(4) { left: 0; bottom: 0; border-right: 0; border-top: 0; border-radius: 0 0 0 2px; }

/* —— 检测中 —— */
.apvb-rows { display: flex; flex-direction: column; gap: 10px; --gc: 168, 196, 220; }
/* 排队不是「没加载出来」，是「数据都在、结论还没写」：
   所以卡片本身不调暗（调暗读作加载中），暗的是光还没走到的那半截，
   那件事归压暗带管 */
.apvb-item.is-wait { opacity: 0.94; cursor: default; }
.apvb-item.is-wait::before { background: rgba(255, 255, 255, 0.16); }
.apvb-item.is-wait:hover { border-color: rgba(168, 196, 220, 0.085); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.045); }
.apvb-item.is-wait:hover::before { width: 2px; background: rgba(255, 255, 255, 0.16); box-shadow: none; }
/* 排队时判断条的位置先放一条骨架：高度不塌，也说明「这里还没结论」 */
.apvb-item.is-wait .apvb-vdi {
  background: rgba(255, 255, 255, 0.03);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}
.apvb-item.is-wait .apvb-vd > span {
  display: block; height: 7px; width: 52%; margin-top: 5px;
  border-radius: 3px; background: rgba(255, 255, 255, 0.05);
}
/* 落定：光走到这一张的下缘、停住的那一拍，卡片才从内部亮一下——亮的是它自己的结论色。
   触发点由脚本给（readRow），不在光开始移动时；所以看见的顺序永远是
   「光走过去 → 停住 → 这一条亮起、写出结论 → 光再走」。
   400ms 收干净，正好在这条到位后的停顿里走完 */
.apvb-item.is-done { animation: apvb-lit 400ms cubic-bezier(0.28, 0.7, 0.34, 1) both; }
@keyframes apvb-lit {
  0% {
    border-color: rgba(168, 196, 220, 0.085);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.045),
      inset 0 0 18px rgba(0, 0, 0, 0.1);
  }
  22% {
    border-color: rgba(var(--gc), 0.52);
    box-shadow:
      inset 0 0 0 1px rgba(var(--gc), 0.22),
      inset 0 1px 0 rgba(255, 255, 255, 0.11),
      inset 0 0 34px rgba(var(--gc), 0.16),
      0 0 26px -8px rgba(var(--gc), 0.85);
  }
  100% {
    border-color: rgba(168, 196, 220, 0.085);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.045),
      inset 0 0 18px rgba(0, 0, 0, 0.1);
  }
}
/* 结论与胶囊别跟卡片同一帧一起冒出来：让光先到，字后落 */
.apvb-item.is-done .apvb-vd,
.apvb-item.is-done .apvb-pill { animation: apvb-fall 280ms 80ms cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes apvb-fall {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: none; }
}

/* 组色落到条目上：扫描态没有分组外壳，`--gc` 只能由结论自己带。
   顺带修掉一处旧偏差——结果态的胶囊一直是按组取色，扫描态却取到中性色，
   同一条结论在两屏里深浅不一样 */
.apvb-item[data-mood="fail"] { --gc: 232, 119, 107; }
.apvb-item[data-mood="warn"] { --gc: 224, 169, 104; }
.apvb-item[data-mood="pass"] { --gc: 126, 201, 166; }
/* 需协调沿用琥珀：它不是第五种结局，是「通过」与「关注」之间
   那一个必须要人动手的中间态 */
.apvb-item[data-mood="cross"] { --gc: 224, 169, 104; }

.apvb-none {
  padding: 40px 0; text-align: center;
  font-size: 11.5px; color: rgba(180, 200, 220, 0.4);
}

/* ============================================================
   ⑤ 2K 档：面板 560 宽，整族同步抬一档（与列卡片 2K 口径一致）
   ============================================================ */
@media (min-width: 2048px) {
  #apvr-panel .apvr-foot.is-batch { height: 50px; }
  .apvb-n { font-size: 12px; }
  .apvb-n b { font-size: 15px; }
  .apvb-btn > svg { width: 14px; height: 14px; }
  .apvb-btn { height: 28px; font-size: 12.5px; padding: 0 11px; }
  .apvb-btn.is-main { height: 32px; font-size: 13.5px; padding: 0 18px 0 16px; }
  .apvb-lab { font-size: 13.5px; }
  .apvb-pick { gap: 6px; }
  .apvb-cnt { font-size: 14.5px; }
  .apvb-cnt-s { height: 13px; }

  .apvb-nm { font-size: 15px; }
  .apvb-sub { font-size: 15px; }
  .apvb-sub .apva-no { font-size: 14px; }
  .apvb-vd { font-size: 12.5px; }
  .apvb-pill { font-size: 11.5px; }
  .apvb-gh { height: 36px; padding: 0 15px 0 18px; }
  .apvb-gn { font-size: 14px; letter-spacing: 1.9px; }
  .apvb-vd { font-size: 13px; margin-top: 11px; }
  .apvb-vdi { width: 18px; height: 18px; }
  .apvb-vdi > svg { width: 11px; height: 11px; }
  .apvb-xh { font-size: 14px; line-height: 20px; }
  .apvb-xht b, .apvb-xht em { font-size: 14px; }
  .apvb-xhw { font-size: 14px; line-height: 20px; }

  .apvb-beam-core { height: 2px; top: -1px; }
  .apvb-beam-glint { width: 40px; height: 40px; margin-top: -20px; }
  .apvb-beam-ticks { top: -17px; height: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .apvb-bar, .apvb-item.is-done,
  .apvb-stage.is-fresh .apvb-g, .apvb-stage.is-fresh .apvb-gb > * { animation: none; }
  .apvr-content.is-batch .apva-card::after { animation: none; }
  .apvb-shake { animation: none; }
  .apvb-beam, .apvb-beam-core, .apvb-beam-ticks { transition: none; animation: none; }
  .apvb-ring, .apvb-bloom, .apvb-aura { animation: none; }
  .apvb-beam { transition-duration: 0ms; }
  .apvb-item.is-done .apvb-vd, .apvb-item.is-done .apvb-pill { animation: none; }
  .apvb-veil { transition: none; }
  .apvb-stage.is-leaving { animation: none; }
  #apvr-sw.apvb-need { animation: none; box-shadow: 0 0 0 1.5px rgba(240, 198, 143, 0.6); }
}
