/* 表格，以及围着它转的筛选、分页、多选 */

/* ---- 筛选栏：一行，在它管的内容上面 ---- */

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  margin-bottom: 14px;
}

.filters-spacer {
  flex: 1;
}

/* 状态太多放不下时横向滑动，不换行 */
.filters-scroll {
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  white-space: nowrap;
}

/* 两组并排（Worker 页：池子 + 状态） */
.filters-scroll > .seg + .seg {
  margin-left: 10px;
}

.filters-scroll::-webkit-scrollbar {
  display: none;
}

.seg-count {
  margin-left: 6px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
}

.search {
  position: relative;
  flex: 1 1 220px;
  max-width: 320px;
}

.search-icon {
  position: absolute;
  top: 50%;
  left: 11px;
  color: var(--text-3);
  translate: 0 -50%;
  pointer-events: none;
}

.search-input {
  width: 100%;
  min-height: 34px;
  padding: 0 32px 0 34px;
  border: 0;
  border-radius: 10px;
  background: var(--fill);
  color: var(--text);
  font-size: 14px;
  box-shadow: 0 0 0 0 transparent;
  transition:
    background var(--dur-fast) ease,
    box-shadow var(--dur) var(--ease-out);
}

.search-input::placeholder {
  color: var(--text-3);
}

.search-input::-webkit-search-cancel-button {
  appearance: none;
}

.search-input:focus,
.search-input:focus-visible {
  outline: none;
  background: var(--surface);
  box-shadow:
    inset 0 0 0 1px var(--accent),
    0 0 0 4px var(--accent-ring);
}

.search-clear {
  position: absolute;
  top: 50%;
  right: 7px;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--text-3);
  color: var(--surface);
  translate: 0 -50%;
  transition:
    opacity var(--dur-fast) ease,
    scale var(--dur-spring) var(--spring);
}

.search-clear[hidden] {
  display: grid !important;
  opacity: 0;
  scale: 0.5;
  pointer-events: none;
}

.select {
  min-height: 34px;
  padding: 0 30px 0 12px;
  border: 0;
  border-radius: 10px;
  appearance: none;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' fill='none' stroke='%2386868b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E")
      no-repeat right 11px center,
    var(--fill);
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
  transition: background-color var(--dur-fast) ease;
}

@media (hover: hover) {
  .select:hover,
  .search-input:hover:not(:focus) {
    background-color: var(--fill-hover);
  }
}

/* ---- 复选框 ---- */

.check {
  display: block;
  flex: none;
  width: 18px;
  height: 18px;
  margin: 0;
  border: 1.5px solid var(--text-3);
  border-radius: 6px;
  appearance: none;
  background: transparent center / 0 no-repeat;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) ease,
    border-color var(--dur-fast) ease,
    background-size var(--dur-spring) var(--spring),
    scale var(--dur-spring) var(--spring);
}

.check:active {
  scale: 0.88;
}

.check:checked,
.check:indeterminate {
  border-color: var(--accent);
  background-color: var(--accent);
  background-size: 12px;
}

.check:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.3l2.4 2.4 4.6-5.2'/%3E%3C/svg%3E");
}

.check:indeterminate {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3 6h6'/%3E%3C/svg%3E");
}

/* 复选框本身只有 18px，把可点的范围撑到整个格子 */
.check-hit {
  display: grid;
  place-items: center;
  width: 44px;
  height: 100%;
  min-height: 44px;
  cursor: pointer;
}

/* ---- 表格 ---- */

.table-card {
  position: relative;
  border-radius: var(--r-card);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}

/* 重新取数时保持上一次的内容，只是淡一点，不闪骨架 */
.table-card.is-stale > .table {
  opacity: 0.55;
}

.table {
  width: 100%;
  border-spacing: 0;
  table-layout: fixed;
  font-size: 14px;
  transition: opacity var(--dur) ease;
}

.th {
  position: sticky;
  top: var(--topbar-h);
  z-index: 2;
  height: 40px;
  padding: 0 12px;
  border-bottom: 1px solid var(--hairline);
  background: var(--glass-strong);
  backdrop-filter: blur(20px) saturate(180%);
  color: var(--text-2);
  font-size: 12px;
  font-weight: 500;
  text-align: left;
  white-space: nowrap;
}

/* 卡片不能裁切溢出（否则表头粘不住），圆角交给四个角上的格子 */
.th:first-child {
  border-top-left-radius: var(--r-card);
}

.th:last-child {
  border-top-right-radius: var(--r-card);
}

.tr:last-child > .td:first-child {
  border-bottom-left-radius: var(--r-card);
}

.tr:last-child > .td:last-child {
  border-bottom-right-radius: var(--r-card);
}

@supports (corner-shape: squircle) {
  .th:first-child,
  .th:last-child,
  .tr:last-child > .td:first-child,
  .tr:last-child > .td:last-child,
  .tr:first-child,
  .tr:last-child {
    corner-shape: squircle;
  }
}

.th-sort {
  display: inline-flex;
  align-items: center;
  margin: 0 -6px;
  padding: 4px 6px;
  border-radius: 6px;
  color: inherit;
  font: inherit;
  transition:
    background var(--dur-fast) ease,
    color var(--dur-fast) ease;
}

/* 箭头不排序的时候**不占地方**（宽度收成 0）：原来只是看不见，照样占着 17px —— 数字
   列的表头因此和下面靠右的数对不齐，窄屏上表头也被它挤得省略。排这一列、鼠标停上去
   才展开。 */
.th-sort > svg {
  width: 0;
  margin-inline-start: 0;
  opacity: 0;
  transition:
    opacity var(--dur-fast) ease,
    width var(--dur-fast) ease,
    margin var(--dur-fast) ease,
    rotate var(--dur-spring) var(--spring);
}

/* 数字列靠右：箭头放在字的左边，字的右边和下面的数对齐 */
.th-num .th-sort {
  flex-direction: row-reverse;
}

.th[aria-sort="ascending"] .th-sort > svg,
.th[aria-sort="descending"] .th-sort > svg {
  width: 13px;
  margin-inline-start: 4px;
}

.th-num[aria-sort="ascending"] .th-sort > svg,
.th-num[aria-sort="descending"] .th-sort > svg {
  margin-inline: 0 4px;
}

.th[aria-sort="ascending"] .th-sort,
.th[aria-sort="descending"] .th-sort {
  color: var(--text);
}

.th[aria-sort="ascending"] .th-sort > svg,
.th[aria-sort="descending"] .th-sort > svg {
  opacity: 1;
}

.th[aria-sort="ascending"] .th-sort > svg {
  rotate: 180deg;
}

@media (hover: hover) {
  .th-sort:hover {
    background: var(--fill);
    color: var(--text);
  }

  .th-sort:hover > svg {
    width: 13px;
    margin-inline-start: 4px;
    opacity: 0.5;
  }

  .th-num .th-sort:hover > svg {
    margin-inline: 0 4px;
  }
}

.tr {
  position: relative;
  transition: background var(--dur-fast) ease;
}

.td {
  /* height 在表格里是"至少"：一行字的行就是 56；两行的（状态 + 原因、地址 + 认证）
     按内容长高，上下留出 8px，不贴着分隔线 */
  height: 56px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--hairline);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: background var(--dur-fast) ease;
}

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

.tr[aria-selected="true"] > .td {
  background: var(--accent-tint);
}

@media (hover: hover) {
  .tr:hover > .td {
    background: var(--fill-faint);
  }

  .tr[aria-selected="true"]:hover > .td {
    background: color-mix(in srgb, var(--accent) 14%, transparent);
  }
}

/* 表格是固定布局，列宽由表头决定；没写宽度的列（参数、说明）吃掉剩下的 */
.th-check,
.td-check {
  width: 44px;
  padding: 0;
}

/* 物料与代理的自增编号：只是个序号，几位数字就够，不跟账号 id 抢宽度 */
.th-rowid {
  width: 76px;
}

.td-rowid {
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.th-id {
  /* 要放得下 id 下面那行"11 位小红书号 + 新号/老号徽标"：116px 会把它裁掉
     （.td 是 overflow: hidden + table-layout: fixed，列宽说多少就是多少） */
  width: 148px;
}

/* 任务表的 ID 后面还跟着"优先""测试"两个小标记。版心 1200 放得下：进度、三列时间、
   操作（只有一个"⋯"）收一点，"参数"那列（自动宽）还剩一百六七十 */
.table-tasks .th-id {
  width: 196px;
}

.table-tasks .th-progress {
  width: 21%;
}

.table-tasks .th-time {
  width: 128px;
}

.table-tasks .th-actions {
  width: 60px;
}

/* 物料与代理的主列。openid 是定长的 32 位十六进制，给到刚好放下就行 ——
   原来是 28%，加上其余定宽列一共超出表宽，"说明"那列被挤得只剩一个字。 */
.th-openid {
  width: 300px;
}

.th-address {
  width: 28%;
}

/* token 只露末四位（••••98FF） */
.th-token {
  width: 112px;
}

.th-account {
  width: 150px;
}

/* 代理:绑定的账号、剩余有效期 */
.th-bound {
  width: 150px;
}

.th-expiry {
  width: 120px;
}

.th-progress {
  width: 27%;
}

.th-status {
  width: 104px;
}

/* 说明：异常 / 停用 / 冷却的原因，一句短话（全文在 title 里）。**这一页有要说明的
   行才出来**（表上的 data-notes，见 workers.js / proxies.js）：大多数时候一页全是正常
   的，常驻一整列空白只是把右边的数推远。出来的时候，没什么要说明的行写个淡的"—"
   （空着像是没取到数）。 */
.th-note {
  width: auto;
}

.table:not([data-notes]) .th-note,
.table:not([data-notes]) .td-note {
  display: none;
}

.td-note .cell-why {
  margin-top: 0;
}

/* 没有的值（"—"、还没绑定、还没用过）一律淡一档：一眼分得出"有数"和"没有" */
.cell-none,
.td-bound[data-none],
.cell-main[data-none] {
  color: var(--text-3);
}

/* Worker 表、代理表的列宽**按比例分**，只有勾选、序号、操作几列定宽：宽屏上多出来的
   宽度摊到每一列（原来全堆给"说明"和代理两列，正常的行那里空出一大块）。剩下的给
   **一列**自动宽的接着 —— 没有说明时是代理（Worker 表）/ 出口（代理表），有说明时是
   说明。必须总有一列自动宽：全是定宽、比例的时候，浏览器把多出来的塞给勾选、操作
   那几列定宽的。
 *
 * 比例按屏幕宽度分档，每一档都算过：这一档最窄的时候每列不比它的内容窄（账号 148、
 * 代理 187、成功率 108……），自动宽那一列也还剩一百七八十。放不下的档先收起次要的
 * 列。表格外面不滚动，加起来超了会伸出卡片。max(px, %) 不能用：表格的列宽遇到它
 * 当成自动宽。 */

/* ---- Worker 表 ----
   每列至少要（实测，含左右 12px 内边距）：账号 148、状态 82、代理 187（ip:端口）、
   手上未完成 96、已完成 72、调用失败 84、成功率 104、状态更新于 96，说明 180 起。 */

.table-workers .th-id {
  width: 14.5%;
}

.table-workers .th-status {
  width: 8%;
}

.table-workers .th-proxy {
  width: auto;
}

.table-workers .th-count {
  width: 9.5%;
}

.table-workers .col-done {
  width: 7.5%;
}

.table-workers .col-failed {
  width: 8.5%;
}

.table-workers .th-rate {
  width: 10.5%;
}

.table-workers .th-time {
  width: 9.5%;
}

/* 有说明：说明自动宽，代理按比例 */
.table-workers[data-notes] .th-id {
  width: 12.5%;
}

.table-workers[data-notes] .th-status {
  width: 7%;
}

.table-workers[data-notes] .th-proxy {
  width: 15.5%;
}

.table-workers[data-notes] .th-count {
  width: 8%;
}

.table-workers[data-notes] .col-done {
  width: 6%;
}

.table-workers[data-notes] .col-failed {
  width: 7%;
}

.table-workers[data-notes] .th-rate {
  width: 9%;
}

.table-workers[data-notes] .th-time {
  width: 8%;
}

/* 有说明、不到 1280：先收起成功率、状态更新于（没有说明时 1100 以下才收） */
@media (max-width: 1280px) {
  .table-workers[data-notes] .col-rate,
  .table-workers[data-notes] .col-updated {
    display: none;
  }

  .table-workers[data-notes] .th-id {
    width: 14.5%;
  }

  .table-workers[data-notes] .th-status {
    width: 8%;
  }

  .table-workers[data-notes] .th-proxy {
    width: 18.5%;
  }

  .table-workers[data-notes] .th-count {
    width: 9.5%;
  }

  .table-workers[data-notes] .col-done {
    width: 7.5%;
  }

  .table-workers[data-notes] .col-failed {
    width: 8.5%;
  }
}

@media (max-width: 1100px) {
  .table-workers .th-id {
    width: 18%;
  }

  .table-workers .th-status {
    width: 10%;
  }

  .table-workers .th-count {
    width: 11.5%;
  }

  .table-workers .col-done {
    width: 9%;
  }

  .table-workers .col-failed {
    width: 10%;
  }

  /* 有说明：再收起已完成、调用失败 */
  .table-workers[data-notes] .col-done,
  .table-workers[data-notes] .col-failed {
    display: none;
  }

  .table-workers[data-notes] .th-id {
    width: 18%;
  }

  .table-workers[data-notes] .th-status {
    width: 10%;
  }

  .table-workers[data-notes] .th-proxy {
    width: 22.5%;
  }

  .table-workers[data-notes] .th-count {
    width: 11.5%;
  }
}

/* 920 以下代理那一列收起来了（见下面的"窄一点的屏幕"），没有说明时由账号接着剩下的 */
@media (max-width: 920px) {
  .table-workers:not([data-notes]) .th-id {
    width: auto;
  }

  .table-workers .th-status,
  .table-workers[data-notes] .th-status {
    width: 13%;
  }

  .table-workers .th-count,
  .table-workers[data-notes] .th-count {
    width: 15%;
  }

  .table-workers .col-done {
    width: 11.5%;
  }

  .table-workers[data-notes] .th-id {
    width: 23.5%;
  }
}

/* ---- 代理表：认证、导入于不单独占列（各自是出口、最近使用下面那一行小字）。按屏幕
   宽度一层层收：先收最近使用，再收测速（手机上它们回到卡片里）。 ---- */

.table-proxies .th-rowid {
  width: 64px;
}

.table-proxies .th-address {
  width: auto;
}

.table-proxies .th-bound {
  width: 14%;
}

.table-proxies .th-expiry {
  width: 11%;
}

.table-proxies .th-pstatus {
  width: 10%;
}

.table-proxies .th-speed {
  width: 14%;
}

.table-proxies .th-time {
  width: 14%;
}

/* 有说明：说明自动宽，出口按比例 */
.table-proxies[data-notes] .th-address {
  width: 19%;
}

.table-proxies[data-notes] .th-bound {
  width: 12%;
}

.table-proxies[data-notes] .th-expiry,
.table-proxies[data-notes] .th-pstatus {
  width: 9%;
}

.table-proxies[data-notes] .th-speed,
.table-proxies[data-notes] .th-time {
  width: 10%;
}

/* 有说明、不到 1280：先收起最近使用（没有说明时 1200 以下才收） */
@media (max-width: 1280px) {
  .table-proxies[data-notes] .col-used {
    display: none;
  }
}

/* 不到 1200：有说明的再收起测速 */
@media (max-width: 1200px) {
  .table-proxies .th-pstatus {
    width: 11%;
  }

  .table-proxies[data-notes] .col-speed {
    display: none;
  }

  .table-proxies[data-notes] .th-address {
    width: 23%;
  }

  .table-proxies[data-notes] .th-bound {
    width: 14%;
  }

  .table-proxies[data-notes] .th-expiry {
    width: 10%;
  }

  .table-proxies[data-notes] .th-pstatus {
    width: 11%;
  }
}

@media (max-width: 1024px) {
  .table-proxies .th-bound {
    width: 16%;
  }

  .table-proxies .th-expiry,
  .table-proxies .th-pstatus {
    width: 12%;
  }

  .table-proxies[data-notes] .th-address {
    width: 25%;
  }

  .table-proxies[data-notes] .th-bound {
    width: 15%;
  }

  .table-proxies[data-notes] .th-pstatus {
    width: 12%;
  }
}

/* 有说明、不到 1024：再收起剩余有效期（手机上是卡片，照样写着） */
@media (min-width: 721px) and (max-width: 1024px) {
  .table-proxies[data-notes] .th-expiry,
  .table-proxies[data-notes] .td-expiry {
    display: none;
  }
}

@media (max-width: 920px) {
  .table-proxies .th-bound {
    width: 20%;
  }

  .table-proxies .th-expiry {
    width: 15%;
  }

  .table-proxies .th-pstatus {
    width: 16%;
  }

  .table-proxies[data-notes] .th-address {
    width: 28%;
  }

  .table-proxies[data-notes] .th-bound {
    width: 18%;
  }

  .table-proxies[data-notes] .th-pstatus {
    width: 15%;
  }
}

@media (max-width: 1200px) {
  .table-proxies .col-used {
    display: none;
  }
}

@media (max-width: 1024px) {
  .table-proxies .col-speed {
    display: none;
  }
}

/* 代理的测速：两行，握手在上、保活在下 */
.th-speed {
  width: 120px;
}

.td-speed {
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.speed-main,
.speed-sub {
  display: block;
}

.speed-sub {
  margin-top: 2px;
  color: var(--text-3);
  font-size: 12px;
}

.speed-sub[hidden] {
  display: none;
}

.td-speed[data-tone="muted"] .speed-main {
  color: var(--text-3);
}

.speed-main[data-tone="warn"],
.speed-sub[data-tone="warn"] {
  color: var(--warn);
}

.td-speed[data-tone="bad"] .speed-main,
.td-speed[data-tone="bad"] .speed-sub {
  color: var(--bad);
}

.td-speed[data-tone="bad"] .speed-main {
  font-weight: 600;
}

/* Worker 的代理（host:port）吃掉剩下的宽度：原来定宽 176，宽屏上多出来的地方被浏览器
   按比例摊给了每一列，数字列空着一大块、代理反倒被省略 */
.th-proxy {
  width: auto;
}

.th-rate {
  width: 132px;
}

.th-time {
  width: 132px;
}

.th-count {
  width: 88px;
}

.th-actions {
  width: 92px;
}

.th-num,
.td-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.td-muted {
  color: var(--text-2);
}

.td-actions {
  overflow: visible;
  text-align: right;
}

/* 剩余有效期：快到了橙色，过期了红色 */
.td-expiry[data-level="soon"] {
  color: var(--warn);
}

.td-expiry[data-level="expired"] {
  color: var(--bad);
}

.td-expiry[data-level="none"] {
  color: var(--text-3);
}

/* 每一行最右边的"⋯"：平时是一枚灰的，指到这一行才亮起来。触屏照常显示 */
.btn-more {
  width: 30px;
  min-height: 30px;
  background: none;
  color: var(--text-3);
}

.btn-more[aria-expanded="true"] {
  background: var(--fill);
  color: var(--text);
}

@media (hover: hover) {
  .tr:hover .btn-more,
  .tr:focus-within .btn-more {
    color: var(--text);
  }
}

/* 出口地址后面那个复制按钮：平时是一枚灰图标，指上去才亮 */
.copy-btn {
  flex: none;
  margin-left: 8px;
  padding: 2px;
  border: 0;
  background: none;
  color: var(--text-3);
  vertical-align: middle;
  cursor: pointer;
}

@media (hover: hover) {
  .copy-btn:hover {
    color: var(--accent);
  }
}

/* 每一行的"停止""置为异常"平时收着，指到这一行、或者用键盘移到这一行时才出现：
   一整列红字太吵，而且大多数时候用不上。触屏没有悬停，照常显示 */
@media (hover: hover) {
  .tr .btn-quiet-danger {
    opacity: 0;
    transition:
      opacity var(--dur-fast) ease,
      background var(--dur-fast) ease;
  }

  .tr:hover .btn-quiet-danger,
  .tr:focus-within .btn-quiet-danger {
    opacity: 1;
  }
}

/* 整行可点开详情：链接铺满整行，按钮和复选框浮在上面 */
.cell-link {
  border-radius: 6px;
  font-weight: 500;
}

.cell-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.cell-link:focus-visible {
  outline: none;
}

.cell-link:focus-visible::after {
  outline: 3px solid var(--accent-ring);
  outline-offset: -3px;
}

.cell-raised {
  position: relative;
  z-index: 1;
}

/* 参数那一格的「查看详情」：强调色加下划线，一看就知道能点 */
.detail-link {
  border-radius: 4px;
  color: var(--accent);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  white-space: nowrap;
  transition: text-decoration-color var(--dur-fast) ease;
}

.detail-link:focus-visible {
  outline: 2px solid var(--accent-ring);
  outline-offset: 2px;
}

@media (hover: hover) {
  .detail-link:hover {
    text-decoration-color: currentColor;
  }
}

.cell-progress {
  display: grid;
  grid-template-columns: minmax(60px, 1fr) auto;
  align-items: center;
  gap: 12px;
}

/* 给数字留够固定的宽度，这样每一行的进度条一样长，能上下比较 */
.cell-count {
  min-width: 13ch;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.cell-count > b {
  color: var(--text);
  font-weight: 500;
}

.cell-reason {
  color: var(--text-2);
}

/* ---- 表格下面：总数、每页条数、翻页 ---- */

.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 20px;
  margin-top: 16px;
  color: var(--text-2);
  font-size: 13px;
}

.pager-info {
  display: flex;
  align-items: center;
  gap: 12px;
  font-variant-numeric: tabular-nums;
}

.pager-nav {
  display: flex;
  align-items: center;
  gap: 2px;
}

.pager-btn {
  display: grid;
  place-items: center;
  min-width: 32px;
  height: 32px;
  padding: 0 8px;
  border-radius: 9px;
  color: var(--text-2);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  transition:
    background var(--dur-fast) ease,
    color var(--dur-fast) ease,
    scale var(--dur-spring) var(--spring);
}

.pager-btn:active {
  scale: 0.92;
}

.pager-btn:disabled {
  opacity: 0.3;
}

.pager-btn[aria-current="page"] {
  background: var(--text);
  color: var(--bg);
  font-weight: 600;
}

.pager-gap {
  min-width: 24px;
  color: var(--text-3);
  text-align: center;
}

@media (hover: hover) {
  .pager-btn:hover:not(:disabled, [aria-current="page"]) {
    background: var(--fill);
    color: var(--text);
  }
}

/* ---- 多选之后从底部浮上来的操作条 ---- */

.selbar {
  position: fixed;
  z-index: 35;
  bottom: calc(24px + env(safe-area-inset-bottom));
  left: 50%;
  display: flex;
  align-items: center;
  gap: 6px;
  max-width: calc(100vw - 24px);
  padding: 6px 6px 6px 18px;
  border-radius: var(--r-pill);
  background: var(--glass-strong);
  backdrop-filter: blur(28px) saturate(180%);
  box-shadow:
    inset 0 0.5px 0 var(--glass-rim),
    var(--shadow-float);
  font-size: 14px;
  white-space: nowrap;
  opacity: 1;
  translate: -50% 0;
  transition:
    opacity var(--dur) ease,
    translate var(--dur-spring-soft) var(--spring-soft),
    display var(--dur) ease allow-discrete;
}

@starting-style {
  .selbar {
    opacity: 0;
    translate: -50% 28px;
  }
}

.selbar[hidden] {
  display: none !important;
  opacity: 0;
  translate: -50% 28px;
}

.selbar-count {
  margin-right: 8px;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}

.selbar-more {
  margin-right: 4px;
}

.selbar-sep {
  flex: none;
  width: 1px;
  height: 20px;
  margin: 0 4px 0 2px;
  background: var(--hairline);
}

/* 按钮上那个小数：选中的里面这个操作能处理几条 */
.selbar-n {
  min-width: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--fill);
  color: var(--text-2);
  font-size: 11.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 18px;
  text-align: center;
}

.selbar-n:empty {
  display: none;
}

.btn-destructive .selbar-n {
  background: var(--bad-tint);
  color: var(--bad);
}

/* ---- Worker 表里的几格 ---- */

.worker-id {
  font-weight: 600;
}

/* 异常 / 停用的原因写在状态药丸下面：只占一行（行高整齐，不把一行撑成三层），
   写的是一句短话，全文和该怎么处理在 title 里 */
.cell-why {
  display: block;
  margin-top: 4px;
  overflow: hidden;
  color: var(--bad);
  font-size: 12px;
  line-height: 1.4;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cell-why[hidden] {
  display: none;
}

/* 原因前面的小标签：代理（线路问题，换一个就好）偏黄，账号（号坏了）红，手动和其他是灰的 */
.why-kind {
  display: inline-block;
  margin-right: 4px;
  padding: 0 5px;
  border-radius: 4px;
  background: var(--bad-tint);
  color: var(--bad);
  font-size: 11px;
  font-weight: 600;
  line-height: 16px;
  vertical-align: 1px;
}

.why-kind[data-kind="proxy"] {
  background: var(--warn-tint);
  color: var(--warn);
}

.why-kind[data-kind="manual"],
.why-kind[data-kind="other"] {
  background: var(--fill);
  color: var(--text-2);
}

/* 代理页的原因：停用的灰、冷却的黄，不是"坏了"的红 */
.cell-why[data-tone="disabled"] {
  color: var(--text-2);
}

.cell-why[data-tone="cooling"] {
  color: var(--warn);
}

.cell-proxy {
  color: var(--text-2);
  font-size: 12.5px;
}

.cell-proxy[data-tone="muted"] {
  color: var(--text-3);
}

.cell-proxy[data-tone="bad"] {
  color: var(--bad);
  font-family: var(--font-sans);
}

/* 0 退后一档：一屏都是 0 的时候，眼睛要能落在不是 0 的那几个上 */
[data-zero="1"] {
  color: var(--text-3);
}

.td-num[data-tone="bad"] {
  color: var(--bad);
  font-weight: 500;
}

/* 手上有正在调用的：数字前面一个会呼吸的小点 */
.cell-load[data-busy="1"]::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 6px;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: 2px;
  animation: pulse 1.6s var(--ease-in-out) infinite;
}

/* 成功率：一根细条 + 百分比；好的绿、一般的橙、差的红 */
.rate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 4.2em;
  align-items: center;
  gap: 8px;
}

.rate-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--fill);
  overflow: hidden;
}

.rate-fill {
  height: 100%;
  border-radius: inherit;
  background: var(--text-3);
  clip-path: inset(0 calc(100% - var(--p, 0%)) 0 0 round 2px);
  transition: clip-path var(--dur-spring-soft) var(--spring-soft);
}

.rate-fill[data-tone="ok"] {
  background: var(--ok);
}

.rate-fill[data-tone="warn"] {
  background: var(--warn);
}

.rate-fill[data-tone="bad"] {
  background: var(--bad);
}

.rate-text {
  color: var(--text-2);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* ---- 窄一点的屏幕：先收起次要的列 ---- */

@media (max-width: 1100px) {
  .col-updated,
  .col-issued,
  .col-used,
  .col-finished,
  .col-rate {
    display: none;
  }
}

@media (max-width: 920px) {
  /* 平板宽度：序号让位给主列，不然出口地址被挤得只剩"1(" */
  .th-rowid,
  .td-rowid {
    display: none;
  }

  .th-openid {
    width: 260px;
  }

  .th-bound {
    width: 128px;
  }

  .th-expiry {
    width: 96px;
  }

  .col-failed,
  .col-token,
  .col-account,
  .col-attempts,
  .col-started,
  .col-proxy {
    display: none;
  }
}

/* ---- 手机：每一行变成一张卡片 ----
 *
 * 卡片是三列网格：勾选（32px）| 内容（1fr）| 右边（auto）。
 * 除了勾选框和"状态/操作"这两块，**其余格子一律占满右边两列、一行一个** ——
 * 之前是让它们自动流，结果"完成于"这一类会掉进 32px 的勾选列里，标签还在、
 * 值被裁得看不见。宁可一行一个，也不要靠猜。
 */
@media (max-width: 720px) {
  .table,
  .tbody {
    display: block;
  }

  .thead {
    display: none;
  }

  .tr {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: 10px;
    row-gap: 6px;
    padding: 14px 16px 12px 10px;
    border-bottom: 1px solid var(--hairline);
  }

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

  .tr[aria-selected="true"] {
    background: var(--accent-tint);
  }

  .tr:first-child {
    border-radius: var(--r-card) var(--r-card) 0 0;
  }

  .tr:last-child {
    border-radius: 0 0 var(--r-card) var(--r-card);
  }

  .tr:only-child {
    border-radius: var(--r-card);
  }

  .td {
    display: block;
    grid-column: 2 / -1;
    min-width: 0;
    height: auto;
    padding: 0;
    border: 0;
    background: none !important;
  }

  .td-check {
    grid-column: 1;
    grid-row: 1;
    align-self: start;
    width: auto;
  }

  .check-hit {
    width: 32px;
    min-height: 24px;
  }

  .td-id {
    grid-column: 2;
    grid-row: 1;
    font-size: 14px;
  }

  .td-status {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
  }

  /* 说明（异常 / 停用 / 冷却的原因）是空的：卡片上不占一行 */
  .td.td-note[data-empty] {
    display: none; /* 要压过下面 .td[data-label] 的 flex */
  }

  .td-note .cell-why {
    white-space: normal;
  }

  .td-actions {
    grid-column: 3;
    justify-self: end;
    margin-top: 4px;
  }

  /* 标签 + 值：标签列固定宽度，值从同一条竖线开始。原来是 min-width:4.6em，
     五个字的标签（手上未完成、剩余有效期）会直接贴上值，读成"手上未完成0"。 */
  .td[data-label] {
    display: flex;
    align-items: baseline;
    gap: 12px;
    font-size: 13.5px;
  }

  .td[data-label]::before {
    content: attr(data-label);
    flex: none;
    width: 5.5em;
    color: var(--text-3);
    font-size: 12.5px;
  }

  /* 物料、代理的序号：卡片第一行已经是 openid / 出口地址，序号在手机上是噪音，
     而且两格都抢第一行会叠在一起 */
  .td-rowid {
    display: none;
  }

  /* 卡片里地方够，数字不必靠右对齐 */
  .td-num {
    text-align: left;
  }

  /* 表头藏了，这几列在手机上没意义 */
  .col-params,
  .col-updated,
  .col-failed,
  .col-done {
    display: none;
  }

  /* 浮在底部标签栏上面；四五个按钮在 390px 上要收紧一点才放得下，
     再窄就横向滑，别把"取消选择"切在屏幕外 */
  .selbar {
    bottom: calc(80px + env(safe-area-inset-bottom));
    gap: 4px;
    max-width: calc(100vw - 20px);
    padding: 5px 5px 5px 14px;
    overflow-x: auto;
    scrollbar-width: none;
    font-size: 13px;
  }

  .selbar::-webkit-scrollbar {
    display: none;
  }

  .selbar > .btn {
    flex: none;
    padding: 0 10px;
  }

  /* 手机上四个操作只留图标和数，字收起来（按钮上有 aria-label） */
  .selbar-label {
    display: none;
  }

  .selbar > .btn:has(.selbar-label) {
    gap: 4px;
    padding: 0 9px;
  }

  .selbar-count {
    margin-right: 4px;
  }

  .pager {
    justify-content: center;
  }

  /* 筛选：状态单独一行可以横着滑，右边渐隐提示后面还有；搜索和时间并排占满一行 */
  .filters-scroll {
    flex: 1 0 100%;
    margin-right: calc(-1 * var(--gutter));
    padding-right: 32px;
    mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
  }

  .filters-spacer {
    display: none;
  }

  /* 搜索框要有一个真实的 flex-basis：写成 0 的话它"永远塞得下"（0 ≤ 剩余空间），
     于是不会换行、被压成几个像素，里面那个 input 的最小宽度就把整页顶出去了。 */
  .search {
    flex: 1 1 200px;
    max-width: none;
  }
}
