/* ============================================================
   cloud-drive-go · 设计系统
   浅色 · 紧凑 · 极客
   ------------------------------------------------------------
   主应用样式表。
   不引用任何外部资源：字体用系统字体栈，图标用文字符号与
   扩展名徽标，不用图标库。
   ============================================================ */

/* ---------- 1. 设计 token ---------- */
:root{
  /* 表面 */
  --bg:            #ffffff;
  --bg-sub:        #f7f8fa;   /* 工具栏 / 表头 / 代码块 */
  --bg-inset:      #f0f2f5;   /* 输入框 / 凹陷区 */
  --bg-hover:      #eef1f5;
  --bg-active:     #e3e8ef;

  /* 线条 */
  --border:        #e4e7ec;
  --border-strong: #cfd6de;

  /* 文字 */
  --fg:            #1b1f24;
  --fg-2:          #57606a;
  --fg-3:          #8c959f;

  /* 强调（唯一的重色，其余一律灰阶） */
  --accent:        #2f6feb;
  --accent-hover:  #1f5fd8;
  --accent-bg:     #eaf1fe;
  --accent-border: #b6cffb;

  /* 语义 */
  --ok:            #1a7f37;
  --warn:          #9a6700;
  --danger:        #cf222e;
  --danger-hover:  #b31d28;
  --danger-bg:     #ffeef0;

  /* 字阶 —— 13px 是正文主力，紧凑 */
  --fs-xs: 11px;
  --fs-sm: 12px;
  --fs:    13px;
  --fs-md: 14px;
  --fs-lg: 16px;
  --fs-xl: 20px;

  /* 间距 */
  --s1: 4px;   --s2: 8px;   --s3: 12px;
  --s4: 16px;  --s5: 24px;  --s6: 32px;

  /* 圆角 —— 几乎方，极客感 */
  --r-sm: 2px;
  --r:    3px;
  --r-lg: 5px;

  /* 固定尺寸 */
  --row:    28px;   /* 表格行高 */
  --ctl:    26px;   /* 控件高度 */
  --topbar: 42px;

  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
             "Microsoft YaHei", "Hiragino Sans GB", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", "Courier New", monospace;

  --shadow-pop: 0 8px 24px rgba(27,31,36,.12), 0 1px 3px rgba(27,31,36,.08);
}

/* ---------- 2. reset & base ---------- */
*{ box-sizing: border-box; }

html,body{ height:100%; }

body{
  margin:0;
  font-family: var(--font-ui);
  font-size: var(--fs);
  line-height: 1.5;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* 数据一律等宽：文件名、大小、时间、路径、哈希、代码 */
.mono, code, kbd, pre, .num{
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.num{ font-variant-numeric: tabular-nums; }

a{ color: var(--accent); text-decoration: none; }
a:hover{ text-decoration: underline; }

h1,h2,h3,h4{ margin:0; font-weight:600; line-height:1.35; }
h1{ font-size: var(--fs-xl); }
h2{ font-size: var(--fs-lg); }
h3{ font-size: var(--fs-md); }
p{ margin:0 0 var(--s3); }

hr{ border:0; border-top:1px solid var(--border); margin: var(--s4) 0; }

::selection{ background: var(--accent-bg); }

/* 细滚动条，不抢视觉 */
*::-webkit-scrollbar{ width:10px; height:10px; }
*::-webkit-scrollbar-thumb{
  background:#d5dae1; border-radius:5px; border:2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover{ background:#c0c7d0; background-clip: padding-box; }
*::-webkit-scrollbar-track{ background: transparent; }

/* ---------- 3. 布局骨架 ---------- */
.app{ display:flex; flex-direction:column; height:100vh; }

/* 顶栏：品牌 + 搜索 + 用户区 */
.topbar{
  display:flex; align-items:center; gap: var(--s3);
  height: var(--topbar); flex:0 0 var(--topbar);
  padding: 0 var(--s3);
  background: var(--bg-sub);
  border-bottom: 1px solid var(--border);
}
.brand{
  display:flex; align-items:center; gap: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--fs-md); font-weight:600; letter-spacing:-.2px;
  color: var(--fg); white-space:nowrap;
}
.brand .dot{ width:7px; height:7px; border-radius:50%; background: var(--accent); }
/* 站点名可在设置页改（最长 64 字符）。给顶栏品牌一个上限，超出省略，
   否则长名字会把搜索框和导航挤走；手机端品牌名本来就被隐藏。 */
.brand .word{ max-width:240px; overflow:hidden; text-overflow:ellipsis; }
.topbar .spacer{ flex:1; }

/* 工具条：面包屑 + 操作按钮 */
.toolbar{
  display:flex; align-items:center; gap: var(--s2);
  height: 38px; flex:0 0 38px;
  padding: 0 var(--s3);
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}
.toolbar .spacer{ flex:1; }
/* 工具条右侧的统计，如「6 项 · 42.8 MB」。它在手机上被文末的媒体查询隐藏，
   各页要保留必须显式 display 放回 —— 它承载信息，不是布局占位。 */
.toolbar .stat{ font-size: var(--fs-xs); color: var(--fg-3); white-space: nowrap; }

/* 内容区 */
.content{ flex:1; overflow:auto; min-height:0; }
.content.pad{ padding: var(--s4); }

/* 窄容器：表单页用 */
.narrow{ width:100%; max-width: 340px; margin: 0 auto; }

/* ---------- 4. 按钮 ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  height: var(--ctl); padding: 0 10px;
  font-family: inherit; font-size: var(--fs-sm);
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  cursor: pointer; white-space: nowrap;
  transition: background .1s, border-color .1s;
}
.btn:hover{ background: var(--bg-hover); }
.btn:active{ background: var(--bg-active); }
.btn:disabled{ opacity:.45; cursor: default; }
.btn:focus-visible{ outline:2px solid var(--accent); outline-offset:1px; }

.btn-primary{
  color:#fff; background: var(--accent); border-color: var(--accent);
  font-weight:500;
}
.btn-primary:hover{ background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-primary:active{ background:#1a52c2; }

.btn-danger{ color: var(--danger); border-color:#f0b8bd; }
.btn-danger:hover{ background: var(--danger-bg); }

/* 无边框按钮，用于工具条与行内操作 */
.btn-ghost{ border-color: transparent; background: transparent; }
.btn-ghost:hover{ background: var(--bg-hover); border-color: transparent; }

.btn-sm{ height:22px; padding:0 7px; font-size: var(--fs-xs); }
.btn-block{ width:100%; }

/* 分段按钮组：视图切换、批量操作 */
.seg{ display:inline-flex; }
.seg .btn{ border-radius:0; margin-left:-1px; }
.seg .btn:first-child{ border-radius: var(--r) 0 0 var(--r); margin-left:0; }
.seg .btn:last-child{ border-radius:0 var(--r) var(--r) 0; }
.seg .btn.on{ background: var(--accent-bg); border-color: var(--accent-border); color: var(--accent); }

/* ---------- 5. 表单 ---------- */
.input, .select, textarea.input{
  width:100%; height: var(--ctl);
  padding: 0 8px;
  font-family: inherit; font-size: var(--fs-sm); color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
}
textarea.input{ height:auto; padding: 6px 8px; line-height:1.5; resize: vertical; }
.input:focus, .select:focus, textarea.input:focus{
  outline:none; border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-bg);
}
.input::placeholder{ color: var(--fg-3); }
.input[disabled]{ background: var(--bg-inset); color: var(--fg-3); }

.field{ margin-bottom: var(--s3); }
.field > label{
  display:block; margin-bottom: 5px;
  font-size: var(--fs-sm); font-weight:500; color: var(--fg-2);
}
.field .hint{ margin-top:5px; font-size: var(--fs-xs); color: var(--fg-3); }

/* 输入框 + 行内按钮（分享密码的「生成 / 复制」）：input 让出空间，按钮不收缩。
   .input 自带 width:100%，在 flex 里会把按钮挤出去，这里必须改回 auto。 */
.input-row{ display:flex; gap: var(--s2); }
.input-row .input{ flex:1; min-width:0; width:auto; }
.input-row .btn{ flex:none; }

/* TOTP 二维码：白底黑码固定，不跟主题走；padding 让白底连成一片静区 */
.qr{ display:inline-block; background:#fff; padding: var(--s2); border-radius: var(--r); line-height:0; }
.qr svg{ display:block; }

/* 搜索框：顶栏里用，带前缀符号 */
.search{
  position:relative; width: 260px;
}
.search .input{ padding-left: 26px; background: var(--bg); }
.search::before{
  content:"⌕"; position:absolute; left:8px; top:50%; transform:translateY(-50%);
  font-size:14px; color: var(--fg-3); pointer-events:none;
}
.search .kbd{
  position:absolute; right:6px; top:50%; transform:translateY(-50%);
}

kbd{
  display:inline-block; padding: 1px 5px;
  font-size: var(--fs-xs); color: var(--fg-2);
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-bottom-width:2px;
  border-radius: var(--r-sm);
}

/* 复选框：紧凑 */
input[type=checkbox]{
  width:13px; height:13px; margin:0; vertical-align:-2px;
  accent-color: var(--accent); cursor:pointer;
}

/* ---------- 6. 表格（主视图） ---------- */
.table{ width:100%; border-collapse: collapse; }

.table th{
  position:sticky; top:0; z-index:1;
  height: 26px; padding: 0 var(--s2);
  font-size: var(--fs-xs); font-weight:600; text-transform: uppercase;
  letter-spacing:.4px; color: var(--fg-3); text-align:left;
  background: var(--bg-sub);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.table th.sortable{ cursor:pointer; user-select:none; }
.table th.sortable:hover{ color: var(--fg-2); }
.table th .arrow{ color: var(--accent); }

.table td{
  height: var(--row); padding: 0 var(--s2);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.table tbody tr:hover{ background: var(--bg-hover); }
.table tbody tr.on{ background: var(--accent-bg); }
.table .col-check{ width:28px; text-align:center; padding-left: var(--s3); }
.table .col-badge{ width:44px; }
/* 尺寸按最长内容算：时间列要容得下带秒的 19 字符等宽时间，
   否则会被长文件名挤成两行。所有数据列一律 nowrap。 */
.table .col-size{ width:88px; text-align:right; color: var(--fg-2); white-space:nowrap; }
.table .col-time{ width:150px; color: var(--fg-2); white-space:nowrap; }
.table .col-act{ width:120px; text-align:right; white-space:nowrap; }
/* 分享列表的「密码」列：内容是「有密码」三个字，窄一点就会折成两行 */
.table .col-pwd{ width:64px; white-space:nowrap; }

/* 分享管理表的「目标」列是这张表的主键信息，宽度**由表宽决定**：
   桌面端吃掉其余列剩下的全部空间，窄屏下保底 220px。
   **超长路径折行，不用省略号** —— 截断的路径没法核对，多出的行高是值得的。
   （曾经定死 220px + 单行省略：桌面端右边空出一大片、手机上只剩路径前半段。） */
.table.share-admin-table th:first-child,
.table.share-admin-table td:first-child{ min-width:220px; }
.share-path{
  display:block; white-space:normal; overflow-wrap:anywhere;
}

/* 分享管理表的「链接」列 = 截断链接 + 审计标识，两段都是只读文本。
   截断链接只占 11 个字符（`s/` + token 前 8 位 + `…`）；完整地址用行内「复制」取回 ——
   不做点击复制，这一列就只是给人认的标识，逐行重复完整 URL 只会把表撑宽。 */
.table.share-admin-table .col-link{ width:180px; min-width:180px; white-space:nowrap; }
.share-link{ display:inline-flex; align-items:baseline; gap:var(--s2); white-space:nowrap; }
.share-hash{ color:var(--fg-3); font-size:var(--fs-xs); }
.table .name{ display:flex; align-items:center; gap: var(--s2); min-width:0; }
.table .name .txt{
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font-family: var(--font-mono); font-size: var(--fs-sm);
}
/* 长文件名不许把大小 / 时间 / 操作列挤出屏幕：
   ① 用固定布局 —— 自动布局下名称列的最小内容宽度会把整张表撑破；
      固定布局的列宽只认第一行（表头），所以表头也必须带 col-size / col-time；
   ② 名称单行省略 —— 换行会让桌面端行高不齐（行高是固定的 var(--row)）。
   完整名字看 title（桌面悬停）或打开预览。 */
.table.file-table{ table-layout: fixed; }
.table.file-table .col-act{ width:250px; } /* 文件行有 6 个按钮，比分享表的 3 个宽 */
.table .name .b{
  display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* 搜索结果：名称下面还有一行路径，两者各占一行；同样的长文本一律省略号 */
.table .name > div{ flex:1; min-width:0; }
.table .name .dim{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.table .col-act .btn{ opacity:0; }
.table tbody tr:hover .col-act .btn,
.table tbody tr.on .col-act .btn{ opacity:1; }

/* 一个单元格里放多个操作按钮（分享行的复制 / 编辑 / 撤销）。
   **不要改成 display:flex** —— td 一旦不再是 table-cell，`vertical-align:middle`
   就失效，同一行里别的单元格换行时按钮会顶到上沿 */
.td-actions{ text-align:right; white-space:nowrap; }
.td-actions .btn + .btn{ margin-left: var(--s2); }

/* 扩展名徽标 —— 取代图标，信息密度更高 */
.badge{
  display:inline-block; min-width:34px; padding: 1px 4px;
  font-family: var(--font-mono); font-size: 10px; font-weight:600;
  letter-spacing:.3px; text-align:center; text-transform:uppercase;
  color: var(--fg-2); background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.badge.dir{ color: var(--accent); background: var(--accent-bg); border-color: var(--accent-border); }
.badge.img{ color:#8250df; background:#f5f0ff; border-color:#ddd0fb; }
.badge.doc{ color: var(--danger); background: var(--danger-bg); border-color:#f5c2c7; }
.badge.ok{ color: var(--ok); background:#e7f5ea; border-color:#b9e0c3; }

/* ---------- 7. 标签 / 状态 ---------- */
.tag{
  display:inline-block; padding: 1px 6px;
  font-size: var(--fs-xs); color: var(--fg-2);
  background: var(--bg-inset); border-radius: 10px;
}
.tag.on{ color: var(--ok); background:#e7f5ea; }
.tag.warn{ color: var(--warn); background:#fff5d6; }
.tag.off{ color: var(--fg-3); }

.sep{ color: var(--border-strong); }
.dim{ color: var(--fg-3); }
.muted{ color: var(--fg-2); }

/* ---------- 8. 面包屑 ---------- */
/* .crumbs-row 是"上一级 + 面包屑"一行：滚动只发生在 .crumbs 里，↑ 永远可见 */
/* 基线上不设 flex:1 —— 预览页把 "/ 文件名" 接在它后面，撑开就会把这两段推走 */
.crumbs-row{ display:flex; align-items:center; gap:2px; min-width:0; }
.crumbs{
  display:flex; align-items:center; gap:2px;
  font-family: var(--font-mono); font-size: var(--fs-sm);
  min-width:0; overflow:hidden;
}
.crumbs a, .crumbs .cur{
  padding: 4px 8px; border-radius: var(--r-sm);
  white-space:nowrap;
}
/* ↑ 上一级。根目录下置灰而不是藏起来 —— 位置固定，才不用每次找 */
.crumbs-up{
  flex:0 0 auto; width:22px; height:22px; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  border:1px solid transparent; border-radius: var(--r-sm);
  background:transparent; color: var(--fg-2); font:inherit; line-height:1; cursor:pointer;
}
.crumbs-up:hover:not(:disabled){ background: var(--bg-hover); color: var(--fg); }
.crumbs-up:disabled{ opacity:.4; cursor:default; }
.crumbs a{ color: var(--fg-2); }
.crumbs a:hover{ background: var(--bg-hover); text-decoration:none; color: var(--fg); }
.crumbs .cur{ color: var(--fg); font-weight:600; }
.crumbs .sl{ color: var(--fg-3); }
/* 预览 / 编辑页把「/ 文件名」接在 .crumbs-row 后面：横向滚动时名字也始终可见。
   这两段包在同一个可收缩的容器里 —— 长文件名单独占一行时不会把斜杠甩在上一行，
   也不会把右侧按钮推出屏幕；名字用省略号，完整名字在 title 里。 */
.crumb-file{ display:flex; align-items:center; gap:2px; min-width:0; flex:0 1 auto; }
.crumb-file .sl{ flex:0 0 auto; color: var(--fg-3); }
.crumb-file .cur{
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  padding: 4px 8px; border-radius: var(--r-sm);
  color: var(--fg); font-weight:600;
}

/* ---------- 9. 模态 ---------- */
.overlay{
  position:fixed; inset:0; z-index:50;
  display:flex; align-items:center; justify-content:center;
  background: rgba(27,31,36,.32);
  padding: var(--s4);
}
.modal{
  width:100%; max-width: 420px;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  overflow:hidden;
}
.modal-head{
  display:flex; align-items:center; gap: var(--s2);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-md); font-weight:600;
}
/* 标题可能是完整路径（分享弹窗），不可断的长串会把 × 顶出 .modal 的裁剪框 ——
   min-width:0 让它能收缩，单行省略；× 不参与收缩，永远钉在右侧。 */
.modal-head .modal-title{
  flex:1 1 auto; min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.modal-head .x{
  flex:none; margin-left:auto; width:22px; height:22px;
  display:flex; align-items:center; justify-content:center;
  color: var(--fg-3); cursor:pointer; border-radius: var(--r);
  font-size:15px; line-height:1;
}
.modal-head .x:hover{ background: var(--bg-hover); color: var(--fg); }
.modal-body{ padding: var(--s4); }
.modal-foot{
  display:flex; gap: var(--s2); justify-content:flex-end;
  padding: var(--s3) var(--s4);
  background: var(--bg-sub);
  border-top: 1px solid var(--border);
}
.modal-foot .spacer{ flex:1; }

/* 选择列表（审计的事件筛选）：桌面与手机同一套，不交给原生 select */
/* max-height 60vh：15 个选项在矮屏手机上会顶出视口，列表自己滚，别撑破模态 */
.picker{ display:flex; flex-direction:column; gap:2px; max-height:60vh; overflow-y:auto; }
.picker-row{
  display:block; width:100%; text-align:left; padding:8px 10px;
  border:0; border-radius: var(--r-sm); background:transparent;
  color: var(--fg); font:inherit; cursor:pointer;
}
.picker-row:hover{ background: var(--bg-hover); }
.picker-row.on{ background: var(--bg-hover); font-weight:600; }

/* 目录选择器（移动 / 复制 / 移出回收站）。**不是 .picker** —— 那个是纵向单选列表。
   左边目录树懒加载，右边固定显示目标路径；手机上改为上下堆叠。 */
.modal.mv{ max-width:560px; }
.dirpick{ display:flex; gap:var(--s3); }
.dirpick-tree{
  flex:1 1 0; min-width:0;
  max-height:250px; overflow-y:auto; overflow-x:hidden;
  padding:var(--s1) 0;
  background:var(--bg-sub);
  border:1px solid var(--border); border-radius:var(--r);
}
/* 缩进靠嵌套容器逐层累加，不做 d1/d2/d3 那种只到三层的 class —— 目录深度没有上限 */
.dp-kids{ padding-left:14px; }
.dirpick .nav-item{
  display:flex; align-items:center; width:100%;
  min-height:28px; padding:2px var(--s3);
  border:0; border-left:2px solid transparent;
  background:transparent; color:var(--fg-2);
  font:inherit; font-size:var(--fs-sm); text-align:left;
  white-space:nowrap; overflow:hidden; cursor:pointer;
}
.dirpick .nav-item:hover{ background:var(--bg-hover); color:var(--fg); }
.dirpick .nav-item.on{
  color:var(--accent); background:var(--accent-bg);
  border-left-color:var(--accent); font-weight:500;
}
.dirpick .nav-item.off{ color:var(--fg-3); cursor:default; }
.dirpick .nav-item.off:hover{ background:transparent; color:var(--fg-3); }
.dirpick .nav-item .tw{ flex:0 0 14px; color:var(--fg-3); }
.dirpick .nav-item.on .tw{ color:var(--accent); }
.dirpick .nav-item .nm{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; }
.dp-empty{ padding:3px var(--s3) 3px 42px; color:var(--fg-3); font-size:var(--fs-xs); }
.dirpick-dest{
  flex:0 0 168px; min-width:0;
  padding:var(--s2) var(--s3);
  background:var(--bg-inset); border-radius:var(--r);
}
.dirpick-dest .p{
  font-family:var(--font-mono); font-size:var(--fs-sm);
  overflow-wrap:anywhere;
}
/* 未选中时是提示语，不是路径：用正文字体（中文在等宽字体下很丑，STYLE 2.4） */
.dirpick-dest .p.idle{ font-family:var(--font-ui); color:var(--fg-3); }
@media (max-width:720px){
  .dirpick{ flex-direction:column; }
  /* 竖排时 flex-basis:0 会把树压成 0 高（横排时它管的是宽度）—— 必须让内容撑开 */
  .dirpick-tree{ flex:1 1 auto; max-height:50vh; }
  .dirpick-dest{ flex:0 0 auto; }
  /* 触控行高（STYLE 5.1）：树里也要够得着 */
  .dirpick .nav-item{ min-height:var(--row); }
}

/* ---------- 10. Toast ---------- */
.toasts{
  position:fixed; right: var(--s4); bottom: var(--s4); z-index:60;
  display:flex; flex-direction:column; gap: var(--s2);
}
.toast{
  display:flex; align-items:center; gap: var(--s2);
  padding: 8px var(--s3);
  min-width: 240px; max-width: 380px;
  font-size: var(--fs-sm);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--fg-3);
  border-radius: var(--r);
  box-shadow: var(--shadow-pop);
}
.toast.ok{ border-left-color: var(--ok); }
.toast.err{ border-left-color: var(--danger); }
.toast.warn{ border-left-color: var(--warn); }

/* ---------- 11. 进度 ---------- */
.progress{
  height:6px; background: var(--bg-inset);
  border-radius: 3px; overflow:hidden;
}
.progress > i{
  display:block; height:100%;
  background: var(--accent);
  transition: width .15s linear;
}
.progress.thin{ height:3px; }

/* ---------- 12. 空状态 / 载入 ---------- */
.empty{
  padding: var(--s6) var(--s4);
  text-align:center; color: var(--fg-3);
  font-size: var(--fs-sm);
}
.empty .big{ font-size:22px; margin-bottom: var(--s2); opacity:.5; }

/* ---------- 13. 工具类 ---------- */
.row{ display:flex; align-items:center; gap: var(--s2); }
.col{ display:flex; flex-direction:column; gap: var(--s2); }
.wrap{ flex-wrap: wrap; }
.grow{ flex:1; min-width:0; }
.nowrap{ white-space:nowrap; }
.tr{ text-align:right; }
.tc{ text-align:center; }
.b{ font-weight:600; }
.sm{ font-size: var(--fs-sm); }
.xs{ font-size: var(--fs-xs); }
.lg{ font-size: var(--fs-lg); }
.mt1{margin-top:var(--s1)} .mt2{margin-top:var(--s2)}
.mt3{margin-top:var(--s3)} .mt4{margin-top:var(--s4)} .mt5{margin-top:var(--s5)}
.mb1{margin-bottom:var(--s1)} .mb2{margin-bottom:var(--s2)}
.mb3{margin-bottom:var(--s3)} .mb4{margin-bottom:var(--s4)} .mb5{margin-bottom:var(--s5)}
.hide{ display:none !important; }

/* 分栏：列表 + 详情（预览页用） */
.split{ display:flex; height:100%; min-height:0; }
.split .side{
  width: 240px; flex:0 0 240px; overflow:auto;
  border-right: 1px solid var(--border);
  background: var(--bg-sub);
}
.split .main{ flex:1; min-width:0; overflow:auto; }

/* 侧栏条目：PDF 目录用 */
.nav-item{
  display:block; padding: 5px var(--s3);
  font-size: var(--fs-sm); color: var(--fg-2);
  border-left: 2px solid transparent;
  cursor:pointer;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.nav-item:hover{ background: var(--bg-hover); color: var(--fg); }
.nav-item.on{
  color: var(--accent); background: var(--accent-bg);
  border-left-color: var(--accent); font-weight:500;
}
.nav-item .pg{ color: var(--fg-3); font-size: var(--fs-xs); }
.nav-item.d1{ padding-left: var(--s3); }
.nav-item.d2{ padding-left: var(--s4); }
.nav-item.d3{ padding-left: var(--s5); }

/* 提示条 */
.note{
  padding: var(--s2) var(--s3);
  font-size: var(--fs-sm);
  background: var(--bg-sub);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--r);
}
.note.warn{ border-left-color: var(--warn); background:#fffbf0; }
.note.danger{ border-left-color: var(--danger); background:#fff8f8; }

/* ---------- 14. 移动端导航菜单（由顶栏 ☰ 触发）---------- */
/* 桌面端不显示，手机上取代顶栏那一排导航按钮 */
.m-toggle{ display:none; }
.m-menu{
  display:none;
  position:absolute; right:var(--s2); top:calc(100% - 6px); z-index:45;
  min-width:170px; padding:var(--s1) 0;
  background:var(--bg);
  border:1px solid var(--border-strong);
  border-radius:var(--r);
  box-shadow:var(--shadow-pop);
}
.m-menu.on{ display:block; }
.m-menu a, .m-menu button{
  display:block; width:100%; text-align:left;
  padding:9px var(--s3);
  font-family:inherit; font-size:var(--fs-md); color:var(--fg);
  background:none; border:0; cursor:pointer;
}
.m-menu a:hover, .m-menu button:hover{
  background:var(--bg-hover); text-decoration:none; color:var(--fg);
}
.m-menu .hr{ height:1px; margin:var(--s1) 0; background:var(--border); }

/* ---------- 15. 浮动层（批量操作条 / 上传浮层）----------
   底部区域由 .bulk / .uploads / .toasts 三者共用，靠 z-index 分层，
   不各占一段垂直空间 —— 硬要错开会吃掉半屏。业务上它们本就不同时出现：
   Toast 是瞬时的、批量条要选中才出、上传浮层只在上传中。
   手机上三者一律贴底全宽，见下一节。
   ------------------------------------------ */

/* 批量操作条：选中时才出现，居中浮在内容区上，不占内容区高度 */
.bulk{
  position:fixed; left:50%; bottom:var(--s4); transform:translateX(-50%);
  z-index:40; display:flex; align-items:center; gap:var(--s2);
  padding:6px var(--s3) 6px 6px;
  background:var(--bg);
  border:1px solid var(--border-strong);
  border-radius:var(--r-lg);
  box-shadow:var(--shadow-pop);
}
.bulk .cnt{
  padding:4px var(--s3); font-size:var(--fs-sm); font-weight:600;
  color:var(--accent); background:var(--accent-bg); border-radius:var(--r);
  font-family:var(--font-mono);
}

/* 上传浮层：右下角，卡片内是逐个文件的上传进度 */
.uploads{
  position:fixed; right:var(--s4); bottom:var(--s4); z-index:45;
  width:320px;
  background:var(--bg); border:1px solid var(--border-strong);
  border-radius:var(--r-lg); box-shadow:var(--shadow-pop); overflow:hidden;
}
.uploads .hd{
  display:flex; align-items:center; gap:var(--s2);
  padding:6px var(--s3); background:var(--bg-sub);
  border-bottom:1px solid var(--border);
  font-size:var(--fs-sm); font-weight:600;
}
.uploads .hd .x{margin-left:auto;color:var(--fg-3);cursor:pointer;font-size:15px;line-height:1}
.uploads .bd{padding:var(--s2) var(--s3) var(--s3)}

/* 上传队列里的单条：文件名 / 大小 / 进度条 */
.up-item{padding:6px 0}
.up-item+.up-item{border-top:1px solid var(--border)}
.up-item .fn{display:flex;align-items:baseline;gap:var(--s2);font-size:var(--fs-sm)}
.up-item .fn .nm{font-family:var(--font-mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.up-item .fn .sz{margin-left:auto;font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--fg-3);white-space:nowrap}
.up-item .progress{margin-top:5px}

/* ---------- 16. 移动端（≤720px）----------
   原则：桌面端的一行工具条塞不进 390px，必须**折行**而不是压缩。
   行高放大到 44px 是为了触控 —— 这是移动端唯一允许放松紧凑性的地方。
   ------------------------------------------ */
@media (max-width: 720px){
  :root{ --row:44px; --ctl:32px; --topbar:46px; }

  /* 顶栏：品牌缩为圆点、搜索占满剩余、导航收进 ☰ */
  .topbar{ position:relative; gap:var(--s2); padding:0 var(--s2); }
  .topbar .brand .word{ display:none; }
  .search{ flex:1; width:auto; }
  .search .kbd{ display:none; }
  .topbar .nav{ display:none; }          /* 桌面导航按钮在手机上一律隐藏 */
  .m-toggle{ display:inline-flex; }

  /* 工具条折行：面包屑独占一行，其余落到第二行 */
  .toolbar{
    height:auto; flex:0 0 auto;
    flex-wrap:wrap; gap:var(--s2);
    padding:var(--s2);
  }
  .toolbar .spacer, .toolbar .stat{ display:none; }
  .crumbs-row{ flex:1 0 100%; }
  .crumbs{ flex:1; overflow-x:auto; }
  .toolbar .seg{ flex:1; }
  .toolbar .seg .btn{ flex:1; }

  /* 表格：只留 徽标 / 名称 / 大小；操作按钮改为常驻 */
  .table .col-time, .table .col-act{ display:none; }
  /* 分享管理表：字段多，手机上不卡片化，改为横向滚动（与审计表同一套做法）。
     全局规则在手机上藏了 .col-time，这里要把它放回来 —— 否则创建时间 / 最近访问
     会直接消失。目标列保持 220px 保底宽并折行，整条路径竖着读完即可，
     不必横向滚动去追；链接列是「截断链接 + 8 位 hash」的一行，两段都不换行 */
  .table-scroll .table.share-admin-table{ min-width:720px; }
  .table.share-admin-table .col-time{ display:table-cell; }
  .table .col-size{ width:64px; font-size:var(--fs-xs); }
  .table .col-act .btn{ opacity:1; }

  /* 表单卡片占满宽度 */
  .narrow{ max-width:none; }

  /* 浮动元素一律贴底全宽。
     注意：同一时刻只应出现一个 —— 批量操作条 / 上传浮层 / Toast 会互相覆盖 */
  .bulk, .uploads, .toasts{
    left:var(--s2); right:var(--s2); bottom:var(--s2);
    transform:none; width:auto;
  }
  .toast{ min-width:0; max-width:none; }

  /* 侧栏在手机上收起 */
  .split .side{ display:none; }
}
/* ---------- 17. 登录页 ---------- */
.login-wrap{
  display:flex; align-items:center; justify-content:center;
  min-height:100vh; padding: var(--s4);
}
/* 登录卡是全站唯一「无壳」的表单：品牌与标题居中，字段标签视觉隐藏 ——
   placeholder 已经说明每个框是什么，再顶一行标签只是重复。
   标签保留在 DOM 里（sr-only），读屏与自动填充仍靠 for/id 关联。
   **作用域必须限定在 .login-card**：.field / .btn-block 全站共用，
   全局改会把分享弹窗和设置页一起改掉。 */
.login-card{
  width:100%; max-width: 340px;
  padding: var(--s6);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.login-card .brand{ justify-content:center; }
.login-card h2{ text-align:center; margin-bottom: var(--s4); }
.login-card .field > label{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
.login-card .btn-block{ height:30px; }
a.btn{ text-decoration:none; }
a.btn:hover{ text-decoration:none; }

/* ---------- 18. 预览 ----------
   三态预览：图片 / Markdown / 代码。
   预览页是独立视图，内容区必须自己撑满，否则 iframe 高度塌成 150px。 */
.content.preview-page{ display:flex; flex-direction:column; overflow:hidden; }
.preview-body{ flex:1; min-height:0; display:flex; flex-direction:column; overflow:auto; }

/* A. 图片 */
.pane-img{ display:flex; flex:1; min-height:0; padding:var(--s5); background:var(--bg-inset); }
.img-stage{ margin:auto; display:flex; flex-direction:column; align-items:center; gap:var(--s3); }
.preview-img{
  max-width:100%; max-height:calc(100vh - 180px);
  border:1px solid var(--border-strong); border-radius:var(--r-lg); background:#fff;
}
.img-meta{ font-size:var(--fs-sm); color:var(--fg-2); overflow-wrap:anywhere; }

/* PDF / SVG */
.preview-frame{ flex:1; width:100%; min-height:0; border:0; background:var(--bg); }

/* B. Markdown */
.md{ max-width:720px; margin:0 auto; padding:var(--s5) var(--s4); width:100%; }
.md h1{ font-size:var(--fs-xl); padding-bottom:var(--s2); margin-bottom:var(--s4); border-bottom:1px solid var(--border); }
.md h2{ margin:var(--s5) 0 var(--s3); }
.md p{ line-height:1.7; }
.md ul, .md ol{ margin:0 0 var(--s3); padding-left:20px; }
.md li{ margin-bottom:3px; line-height:1.7; }
.md code{
  padding:1px 4px; font-size:var(--fs-sm);
  background:var(--bg-inset); border:1px solid var(--border); border-radius:var(--r-sm);
}
.md blockquote{
  margin:0 0 var(--s3); padding:var(--s2) var(--s3);
  color:var(--fg-2); background:var(--bg-sub); border-left:3px solid var(--border-strong);
}
.md blockquote p{ margin:0; }
.md pre{
  margin:0 0 var(--s3); padding:var(--s2) var(--s3);
  background:var(--bg-sub); border:1px solid var(--border);
  font-size:var(--fs-sm); line-height:1.6; overflow-x:auto; tab-size:4;
}
.md pre code{ padding:0; border:0; background:none; font-size:inherit; }
.md table{ border-collapse:collapse; margin:0 0 var(--s3); }
.md th, .md td{ padding:4px var(--s2); border:1px solid var(--border); text-align:left; }
.md img{ max-width:100%; }

/* C. 代码 */
.pane-code{ padding:var(--s4); }
.code-meta{ margin-bottom:var(--s2); font-size:var(--fs-xs); color:var(--fg-2); overflow-wrap:anywhere; }
.code-body{
  display:flex; background:var(--bg-sub); border:1px solid var(--border);
  font-family:var(--font-mono); font-size:var(--fs-sm); line-height:20px;
}
.code-body .ln{
  flex:0 0 auto; margin:0; padding:var(--s3) var(--s2) var(--s3) var(--s3);
  text-align:right; color:var(--fg-3); border-right:1px solid var(--border);
  user-select:none; -webkit-user-select:none;
}
.code-body .src{
  flex:1; min-width:0; margin:0; padding:var(--s3);
  overflow-x:auto; white-space:pre; tab-size:4;
}

/* 纯文本与提示 */
.preview-text{
  margin:0; padding:var(--s4);
  font-family:var(--font-mono); font-size:var(--fs-sm); line-height:1.6;
  white-space:pre-wrap; overflow-wrap:anywhere;
}
.preview-note{
  margin:auto; padding:var(--s5); display:flex; flex-direction:column;
  align-items:center; gap:var(--s4); color:var(--fg-2); text-align:center;
}

@media (max-width:720px){
  .toolbar #views{ flex:1 0 100%; }
  .toolbar > .btn{ flex:1; }
  .toolbar .sep{ display:none; }
  .pane-img, .pane-code{ padding:var(--s3); }
  .md{ width:100%; padding:var(--s4) 16px; }
  .code-body .ln{ padding:var(--s3) var(--s1) var(--s3) var(--s2); }
  .code-body .src{ padding:var(--s3) var(--s2); overflow-x:auto; }
}

/* ---------- 19. PDF 阅读器（M5.5）----------
   虚拟滚动：只保留当前页 ±1 的 canvas，其余是等高占位。 */
.reader{ display:flex; flex-direction:column; flex:1; min-height:0; }
.reader-split{ display:flex; flex:1; min-height:0; position:relative; }
.reader-side{
  width:240px; flex:0 0 240px; overflow:auto;
  border-right:1px solid var(--border); background:var(--bg-sub);
}
.reader .side-head{
  position:sticky; top:0; z-index:1;
  padding:var(--s2) var(--s3);
  font-size:var(--fs-xs); font-weight:600; letter-spacing:.4px;
  color:var(--fg-3); background:var(--bg-sub);
  border-bottom:1px solid var(--border);
}
.reader-side .outline{ padding:var(--s1) 0 var(--s4); }
.reader-side .nav-item{ display:flex; align-items:center; gap:var(--s2); }
.reader-side .nav-item .ttl{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; }
.reader-side .nav-item .pg{ flex:0 0 auto; }

.reader-main{ display:flex; flex-direction:column; flex:1; min-width:0; min-height:0; }
.pages{
  flex:1; min-height:0; overflow:auto;
  background:var(--bg-inset);
  padding:var(--s4) 0 var(--s5);
}
.pages-inner{ position:relative; }
.slot{ display:flex; flex-direction:column; align-items:center; margin:0 auto var(--s4); }
.slot-no{ margin-bottom:var(--s1); color:var(--fg-3); font-size:var(--fs-xs); }
.page-sheet{
  position:relative; overflow:hidden; background:#fff;
  border:1px solid var(--border);
  box-shadow:0 1px 2px rgba(27,31,36,.05), 0 6px 18px rgba(27,31,36,.05);
}
.page-sheet.ph{ background:transparent; border:1px dashed var(--border-strong); box-shadow:none; }
.page-sheet canvas{ display:block; }
.page-loading{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  font-size:var(--fs-sm); color:var(--fg-3);
  background:rgba(255,255,255,.65);
}

.reader-foot{
  flex:0 0 30px; display:flex; align-items:center; gap:var(--s3);
  padding:0 var(--s3); background:var(--bg); border-top:1px solid var(--border);
}
.reader-foot .progress{ flex:1; }
.reader .zoom-val{ min-width:42px; text-align:center; }
.reader .pageno-input{
  width:56px; padding:0 var(--s1); text-align:center;
  font-family:var(--font-mono); font-variant-numeric:tabular-nums;
}
/* 没有内嵌 outline 的扫描件：目录入口整个不存在，不留空面板 */
.reader.no-outline .reader-side,
.reader.no-outline .dir-btn{ display:none; }

@media (max-width:900px){
  /* 目录改成覆盖面板，由工具条 ☰ 唤出 */
  .reader-side{
    position:absolute; left:0; top:0; bottom:0; z-index:5;
    display:none; box-shadow:var(--shadow-pop);
  }
  .reader-side.open{ display:block; }
}

/* ---------- 20. 文本编辑器（M6）---------- */
.editor-body{ overflow:hidden; }
.editor-wrap{
  flex:1; min-height:0; position:relative;
  display:flex; flex-direction:column;
}
/* 冲突提示条独立成行，不遮挡代码 */
.conflict-bar{
  flex:0 0 auto;
  padding:var(--s2) var(--s3);
  background:var(--bg);
  border-bottom:1px solid var(--border);
}
.conflict-bar .note{ display:flex; align-items:center; gap:var(--s2); }
.conflict-bar .note .grow{ flex:1; }

.editor-statusbar{
  flex:0 0 auto;
  padding:4px var(--s3);
  background:var(--bg-sub);
  border-bottom:1px solid var(--border);
}
.editor-status-text{ font-size:var(--fs-xs); color:var(--fg-3); }
.editor-status-text.ok{ color:var(--ok); }
.editor-status-text.warn{ color:var(--warn); }
.editor-status-text.danger{ color:var(--danger); }

.editor-host{ flex:1; min-height:0; overflow:hidden; }
.editor-host .cm-editor{ height:100%; }

/* ---------- 21. 分享页（M7）---------- */
.share-app{ min-height:100vh; display:flex; flex-direction:column; }
.share-top{
  height:var(--topbar); flex:0 0 var(--topbar);
  display:flex; align-items:center; gap:var(--s2);
  padding:0 var(--s4);
  border-bottom:1px solid var(--border);
}
.share-main{
  flex:1; display:flex; flex-direction:column;
  align-items:center; justify-content:center;
  padding:var(--s5) var(--s4);
}
.share-main .stage{
  width:100%; display:flex; flex-direction:column;
  align-items:center; gap:var(--s3);
}
.share-card{ max-width:420px; width:100%; }
.share-card.wide{ max-width:860px; }
.share-card .modal-body{ padding:var(--s5) var(--s5) var(--s4); }
/* 密码框与登录页同一套：placeholder 已经说明，再顶一行标签只是重复。
   标签留在 DOM 里（sr-only），读屏与自动填充仍靠关联。
   **作用域必须限定 .share-card** —— 理由同 17 节登录页那条：.field 全站共用，
   全局改会把设置页、编辑弹窗一起改掉。 */
.share-card .field > label{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
.share-head{ text-align:center; }
.share-head .fname{
  margin-top:var(--s2); font-size:var(--fs-lg); font-weight:600;
  overflow-wrap:anywhere;
}
/* 没有徽标的头部（分享密码卡）：标题不再需要与徽标之间的那段间距 */
.share-head.plain .fname{ margin-top:0; }
/* 纯提示卡（分享失效 / 加载失败）：只有一行字，没有徽标可间距。
   margin-top 归零、上下内边距对称，文字才真正居中；默认的 24/16 是给带按钮的卡留的。 */
.share-card.msg .modal-body{ padding:var(--s5); }
.share-card.msg .fname{ margin-top:0; }
.badge-lg{ font-size:var(--fs-sm); padding:3px 8px; }
.share-actions{ display:flex; justify-content:center; margin-top:var(--s4); }
.btn-lg{ height:34px; padding:0 var(--s5); font-size:var(--fs-md); }
.btn-block{ width:100%; }
.share-main .tip{ margin:0; }

/* 分享页的内嵌预览：PDF 阅读器与图片都要有高度 */
.share-preview{
  margin-top:var(--s4); padding-top:var(--s3);
  border-top:1px solid var(--border);
  min-height:320px; display:flex; flex-direction:column;
}
.share-preview .preview-frame{ min-height:65vh; }
.share-preview .pane-img{ padding:var(--s3); }
/* PDF 阅读器的 .reader / .pages 用 flex:1 拿高度，父容器必须有**确定高度**。
   只给 min-height 时 flex:1 退化成内容高度，.pages 的 overflow:auto 无处可滚，
   整页被撑成页数倍高、页脚被顶到几万像素之外。图片与文本不需要这一条。 */
.share-preview.pdf{ height:70vh; min-height:420px; }

.dir-head{ display:flex; align-items:center; gap:var(--s2); margin-bottom:var(--s3); }
.dir-head .dir-name{ font-weight:600; overflow-wrap:anywhere; }
.dir-head .grow{ flex:1; }
.share-table td{ padding-top:4px; padding-bottom:4px; }
.share-name{ display:flex; align-items:center; gap:var(--s2); color:var(--fg); }
.share-name:hover{ text-decoration:none; color:var(--accent); }
.share-name .txt{ overflow-wrap:anywhere; }

/* ---------- 22. 移动端修正（M9）----------
   原则：信息不减少，只换排布（STYLE 5）。 */
.only-mobile{ display:none; }

@media (max-width:720px){
  .only-mobile{ display:inline-flex; align-items:center; }

  /* 文件表格 → 卡片式：名称 + 大小一行，时间与操作各占下一行 */
  .table.file-table thead{ display:none; }
  .table.file-table tbody tr{
    display:flex; flex-wrap:wrap; align-items:center;
    padding:var(--s2) var(--s3); border-bottom:1px solid var(--border);
  }
  .table.file-table td{ display:block; height:auto; padding:0; border:0; }
  /* flex-basis:0：名称列吃剩余空间 —— 用 auto 时，长名字会把大小列挤到下一行。
     padding-right：省略号和右侧的大小之间留一点缝，否则会连成一体 */
  .table.file-table td:not([class]){ flex:1 1 0; min-width:0; padding-right:var(--s2); }
  .table.file-table .col-check{ flex:0 0 auto; padding-right:var(--s2); }
  .table.file-table .col-size{
    flex:0 0 auto; width:auto; margin-left:auto; text-align:right;
  }
  .table.file-table .col-time{
    flex:1 0 100%; display:block;
    margin-top:2px; font-size:var(--fs-xs); color:var(--fg-3);
  }
  .table.file-table .col-act{
    flex:1 0 100%; display:flex; flex-wrap:wrap;
    gap:var(--s1); margin-top:var(--s1);
  }
  .table.file-table .col-act .btn{ opacity:1; }

  /* 分享页表格同样卡片化 */
  .table.share-table thead{ display:none; }
  .table.share-table tbody tr{
    display:flex; flex-wrap:wrap; align-items:center;
    padding:var(--s2) var(--s3); border-bottom:1px solid var(--border);
  }
  .table.share-table td{ display:block; height:auto; padding:0; border:0; }
  .table.share-table td:first-child{ flex:1 1 auto; min-width:0; }
  .table.share-table .col-size{ flex:0 0 auto; width:auto; margin-left:auto; }
  .table.share-table .col-time{
    flex:1 0 100%; display:block;
    margin-top:2px; font-size:var(--fs-xs); color:var(--fg-3);
  }

  /* 设置页的设备 / 分享表列多，横向滚动而不是把页面撑宽 */
  .table-scroll{ overflow-x:auto; }
  .table-scroll .table{ min-width:560px; }

  /* 预览 / 编辑工具条：按钮均分，避免单个悬空 */
  .preview-page > .toolbar > .btn,
  .preview-page > .toolbar > a.btn{ flex:1 1 auto; }
  .reader-toolbar .pageno-input{ width:48px; }
  .reader-toolbar .zoom-val{ min-width:34px; }
}

/* 顶栏导航组（桌面横排；手机上由 base 的 .topbar .nav{display:none} 收起） */
@media (min-width:721px){
  .topbar .nav{ display:flex; align-items:center; gap:var(--s2); }
}

/* ---------- 23. 手动重建索引（M10）---------- */
.reindex-stats{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(120px, 1fr));
  gap:var(--s3);
}
.reindex-stat{
  padding:var(--s3); background:var(--bg-sub);
  border:1px solid var(--border); border-radius:var(--r);
}
.clean-list{
  margin:var(--s1) 0 0; padding-left:var(--s4);
  max-height:220px; overflow:auto;
}
.clean-list li{ overflow-wrap:anywhere; }
.dup-group{
  padding:var(--s3); margin-bottom:var(--s3);
  background:var(--bg-sub); border:1px solid var(--border); border-radius:var(--r);
}
.dup-item{
  display:flex; align-items:center; gap:var(--s2);
  padding:var(--s1) 0; cursor:pointer;
}
.dup-item .mono{ flex:1; min-width:0; overflow-wrap:anywhere; }
@media (max-width:720px){
  .reindex-stats{ grid-template-columns:repeat(2, 1fr); }
}

/* 维护页的清理清单只有三列，手机上不许横向滚动把"条数"挤出屏幕 */
@media (max-width:720px){
  .table-scroll .table.reindex-table{ min-width:0; }
}

/* ---------- 24. 审计日志（M11）---------- */
.audit-toolbar{
  display:flex; align-items:center; gap:var(--s2); flex-wrap:wrap;
}
.audit-toolbar .input{ width:auto; max-width:100%; }
/* 四列在手机上无论如何挤不下，横向滚动由 .table-scroll 负责 */
.table-scroll .table.audit-table{ min-width:680px; }
/* 全局移动端规则把 .col-time 藏了（卡片布局不需要时间）；
   审计表是横向滚动的普通表格，时间必须保留 */
.table.audit-table .col-time{ display:table-cell; }
.audit-table .col-time,
.audit-table .col-ev,
.audit-table .col-ip{ white-space:nowrap; }
.audit-table .col-detail{ overflow-wrap:anywhere; }
/* 表头 sticky 相对 .content 定位，两处必须一起处理：
   ① .content.pad 的 16px 顶部 padding 会让 sticky 留一条缝 —— 审计页去掉它，
      间距移到内层 .audit-box（滚动时内层 padding 会离开，表头才贴住顶部）；
   ② 手机端 .table-scroll 的 overflow-x:auto 会把它变成 sticky 的滚动上下文
      （另一个轴被浏览器计算成 auto），表头就不再跟页面滚 —— 还原成 visible，
      横向滚动交给 .content（表格的 min-width 仍然生效）。 */
.content.audit-page{ padding-top:0; }
.content.audit-page .audit-box{ padding-top: var(--s4); }
.content.audit-page .table-scroll{ overflow:visible; }

/* 手机端：详情只占一行，超出省略；点这一行展开全文（放不下就多行），再点收回。
   详情列 240px（约 18 个汉字），多余的靠点击；四列横滚不变。
   行内字号比正文小一号（--fs-sm）：等宽字体同字号看起来比正文大。
   来源 IP 只保证 IPv4 完整（列宽 120px），IPv6 截断，展开后换行看全。
   ★ 截断必须挂在内层 .clamp 上，不能直接写 td：Chrome 不接受把表格单元格的
   display 改成 -webkit-box，-webkit-line-clamp 随之失效（文字会折成两行、
   正好塞进 44px 的格子里，看起来像"没截断"）。
   ★ 也不用 text-overflow:ellipsis —— 这张表是 table-layout:auto，省略号要求
   nowrap + 固定列宽，长路径会把整张表撑到几千像素。 */
@media (max-width:720px){
  /* 680 会把多出来的宽度分给详情列，min-width 归零后表格才缩到各列之和 */
  .table-scroll .table.audit-table{ min-width:0; }
  .table.audit-table{ font-size: var(--fs-sm); }
  .table.audit-table .tag{ font-size: var(--fs-sm); }
  .table.audit-table .col-ev .xs{ font-size: var(--fs-sm); }
  .table.audit-table .col-detail{ min-width: 240px; font-size: var(--fs-sm); }
  /* 120px 含左右各 8px 内边距，够 255.255.255.255（15 字符）一行放下。
     ★ 必须用 min-width：table-layout:auto 下 td 的 width 只是建议值，
     IPv6 会把列压到几十像素。white-space 放回 normal，否则 anywhere 不生效。 */
  .table.audit-table .col-ip{
    min-width: 120px; white-space:normal; overflow-wrap:anywhere;
  }
  .table.audit-table .col-ip .clamp,
  .table.audit-table .col-detail .clamp{
    display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:1;
    overflow:hidden;
  }
  .table.audit-table tr.open .col-ip .clamp,
  .table.audit-table tr.open .col-detail .clamp{ display:block; overflow:visible; }
}

/* ---------- 25. 拖拽上传（桌面端）----------
   触屏不触发 HTML5 drag，所以没有移动端样式。
   遮罩 z-index 48：压在 .uploads(45) / .bulk(40) 之上、.overlay(50) 之下 ——
   模态打开时本来就不显示遮罩，这个顺序只是保证万一同时出现也不会盖住模态。
   pointer-events:none 让遮罩自己不成为拖拽目标，否则子元素间穿梭时
   dragenter / dragleave 更难配平。
   ------------------------------------------ */
.drop-veil{
  position:fixed; inset:0; z-index:48;
  display:flex; align-items:center; justify-content:center;
  background: rgba(247,248,250,.70);
  opacity:0; pointer-events:none;
  transition: opacity .12s ease;
}
.drop-veil.on{ opacity:1; }
.drop-box{
  padding: var(--s5) var(--s6);
  text-align:center;
  background: var(--bg);
  border: 2px dashed var(--accent);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
}
.drop-arrow{ font-size:26px; line-height:1; color: var(--accent); }
.drop-title{ margin-top: var(--s1); font-size: var(--fs-lg); font-weight:600; }
.drop-path{
  margin-top: var(--s2); max-width: 46ch;
  font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--fg-3);
  word-break: break-all;
}

/* 确认框里的拖入清单：只列名字与类型（▸ 目录 / · 文件），不给大小和数量 */
.drop-list{
  padding: var(--s1) var(--s2);
  background: var(--bg-sub);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.drop-row{
  display:flex; align-items:baseline; gap: var(--s2);
  padding: 3px 0; font-size: var(--fs-sm);
}
.drop-mark{ flex:0 0 10px; text-align:center; color: var(--fg-3); }
.drop-name{ font-family: var(--font-mono); word-break: break-all; }
.drop-more{ padding-left: 18px; color: var(--fg-3); }

/* ---------- 26. 设置页 ---------- */

/* 底部的版本行。左侧竖线 + 浅底把它标成“附注”而不是又一块正文：
   排障时才需要读，平时不该抢注意力。等宽是为了 sha 与时间戳对齐。 */
.settings-version{
  margin-top: var(--s5);
  padding: var(--s2) var(--s3);
  border-left: 3px solid var(--border);
  background: var(--bg-sub);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-3);
}
