/* ==========================================================================
   文火工具箱 · 共用外壳样式

   设计取向：工具站，克制优先。用排版层级和留白建立秩序，
   不靠特效。所有类名保持不变，12 个页面依赖它们。

   三条硬约束：
   1. 字号只用下面 7 个档位，不再随手写 13px / 12px
   2. 圆角只用 3 个档位（--r-sm / --r-md / --r-lg），胶囊只给徽章
   3. 图标一律用 /assets/icons.svg 里的 Tabler 图标，不用 emoji
   ========================================================================== */

:root{
  /* 中性色。偏冷灰，比纯灰更沉稳 */
  --bg:#f5f6f8;
  --card:#fff;
  --card-2:#fafbfc;
  --line:#e2e5ea;
  --line-2:#eef0f3;
  --text:#161a1f;
  --text-2:#3f4750;
  --muted:#6b7480;

  /* 品牌蓝。比原来压深一档，正式感来自沉稳而非明亮 */
  --brand:#1f56d6;
  --brand-d:#173fa3;
  --brand-soft:#eef3ff;
  --brand-line:#d3e0fb;

  --ok:#15803d;   --ok-soft:#f0faf3;  --ok-line:#c3e6ce;
  --err:#c2261d;  --err-soft:#fdf1f0; --err-line:#f0c4c0;
  --warn:#8a6320; --warn-soft:#fdf8ec; --warn-line:#eddfba;

  /* 字号：7 档，够用且有层级 */
  --fs-xs:12px;    /* 元信息、脚注 */
  --fs-sm:13.5px;  /* 次要正文、表格 */
  --fs-base:15px;  /* 正文 */
  --fs-md:17px;    /* 小标题 */
  --fs-lg:20px;    /* 区块标题 */
  --fs-xl:27px;    /* 页面标题 */
  --fs-2xl:34px;   /* 首页主标题 */

  --r-sm:6px; --r-md:10px; --r-lg:14px;

  --sp-1:6px; --sp-2:10px; --sp-3:14px; --sp-4:20px; --sp-5:28px; --sp-6:40px;

  --shadow:0 1px 2px rgba(22,26,31,.04), 0 4px 12px rgba(22,26,31,.05);
  --ease:cubic-bezier(.16,1,.3,1);
}

@media (prefers-color-scheme: dark){
  :root{
    --bg:#0f1216; --card:#161a20; --card-2:#1b2028;
    --line:#2a313a; --line-2:#232a32;
    --text:#e8eaed; --text-2:#c2c8d0; --muted:#8b95a1;
    --brand:#6b95ff; --brand-d:#8aabff;
    --brand-soft:#18203040; --brand-line:#2f3f60;
    --ok:#5fc27e;  --ok-soft:#14231a;  --ok-line:#2c4a35;
    --err:#f08279; --err-soft:#251716; --err-line:#54302c;
    --warn:#d9b264;--warn-soft:#231d12;--warn-line:#4a3d23;
    --shadow:0 1px 2px rgba(0,0,0,.3), 0 4px 14px rgba(0,0,0,.28);
  }
}

*{box-sizing:border-box}

body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font:var(--fs-base)/1.75 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
a{color:var(--brand);text-underline-offset:2px}

/* 和 .nav-in 保持同宽同内边距，否则导航的品牌名和下面的内容左边缘对不齐。
   之前这里是 960px、导航是 1240px，差 280px，肉眼可见的错位。 */
.wrap{max-width:1120px;margin:0 auto;padding:var(--sp-5) var(--sp-5) 72px}

/* ===== 图标 =====
   用法：<svg class="i"><use href="/assets/icons.svg#lock"></use></svg>
   继承当前文字颜色和大小，所以放进任何文本里都自动协调。 */
.i{width:1em;height:1em;flex:none;vertical-align:-.14em;
   stroke:currentColor;fill:none;stroke-width:1.75;
   stroke-linecap:round;stroke-linejoin:round}
.i-lg{width:1.35em;height:1.35em}

/* ===== 顶部导航 =====
   全站统一，吸顶。品牌名兼作返回首页的入口，所以不再单独放返回条。 */
.nav{background:rgba(255,255,255,.86);backdrop-filter:saturate(180%) blur(10px);
  border-bottom:1px solid var(--line);position:sticky;top:0;z-index:20}
.nav-in{max-width:1120px;margin:0 auto;padding:0 var(--sp-5);min-height:62px;
  display:flex;align-items:center;gap:var(--sp-5)}
.nav .brand{display:inline-flex;align-items:center;gap:8px;text-decoration:none;
  color:var(--text);font-weight:600;font-size:var(--fs-md);letter-spacing:-.01em;flex:none}
.nav .brand .i{width:19px;height:19px;color:var(--brand)}
.nav .links{display:flex;gap:var(--sp-4);margin-left:auto;flex-wrap:wrap;align-items:center}
.nav .links a{color:var(--muted);text-decoration:none;font-size:var(--fs-sm);
  transition:color .15s var(--ease)}
.nav .links a:hover{color:var(--brand)}
/* 当前页高亮，让用户知道自己在哪一层 */
.nav .links a.on{color:var(--text);font-weight:600}

@media (prefers-color-scheme: dark){
  .nav{background:rgba(22,26,32,.86)}
}
@media(max-width:760px){
  .nav-in{padding:10px var(--sp-4);flex-wrap:wrap;gap:var(--sp-3)}
  .nav .links{margin-left:0;gap:var(--sp-3);width:100%}
}

/* PDF 操作切换器，挂在导航右侧 */
.pdfsw{display:inline-flex;align-items:center;gap:8px;
  font-size:var(--fs-xs);color:var(--muted);margin-left:var(--sp-4)}
.pdfsw select{font-size:var(--fs-sm);font-weight:600;color:var(--text);
  padding:6px 11px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--card);cursor:pointer;min-width:150px}
.pdfsw select:hover{border-color:var(--brand)}
@media(max-width:760px){ .pdfsw{margin-left:0} }

/* ===== 页头 =====
   工具页顶部做一条浅色渐层带，和首页的深色主视觉呼应，
   让内页不至于一上来就是白底文字。 */
header{position:relative;margin-bottom:var(--sp-5);padding:var(--sp-5) var(--sp-4) var(--sp-4);
  border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;
  background:
    radial-gradient(120% 140% at 0% 0%, var(--brand-soft), transparent 58%),
    linear-gradient(180deg, var(--card), var(--card-2));
}
header::after{content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--brand),transparent 72%)}
h1{font-size:var(--fs-xl);line-height:1.28;letter-spacing:-.018em;
  margin:0 0 var(--sp-2);font-weight:600}
.sub{color:var(--muted);font-size:var(--fs-base);margin:0;max-width:62ch}
.sub b{color:var(--text-2);font-weight:600}

.badges{margin-top:var(--sp-3);display:flex;gap:var(--sp-1);flex-wrap:wrap}
.badge{background:var(--card);border:1px solid var(--line);border-radius:999px;
  padding:4px 12px;font-size:var(--fs-xs);color:var(--muted);
  display:inline-flex;align-items:center;gap:5px}
.badge .i{opacity:.75;color:var(--brand)}

/* ===== 卡片 ===== */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:var(--sp-4);margin-bottom:var(--sp-3)}
.card h2{font-size:var(--fs-md);font-weight:600;margin:0 0 var(--sp-3);letter-spacing:-.005em}

/* ===== 拖放区 ===== */
.drop{border:1.5px dashed var(--line);border-radius:var(--r-md);padding:44px var(--sp-4);max-width:720px;
  text-align:center;cursor:pointer;background:var(--card-2);
  transition:border-color .18s var(--ease),background .18s var(--ease)}
.drop:hover,.drop.over{border-color:var(--brand);background:var(--brand-soft)}
.drop .ico{color:var(--muted);line-height:1}
.drop .ico .i{width:34px;height:34px;stroke-width:1.4}
.drop:hover .ico,.drop.over .ico{color:var(--brand)}
.drop .t{font-size:var(--fs-md);font-weight:600;margin:var(--sp-2) 0 4px}
.drop .h{font-size:var(--fs-sm);color:var(--muted)}
input[type=file]{display:none}

/* ===== 控件 ===== */
.row{display:flex;gap:var(--sp-2);flex-wrap:wrap;align-items:center;margin-top:var(--sp-3)}
button{font:inherit;font-size:var(--fs-sm);font-weight:550;border-radius:var(--r-sm);
  padding:9px 16px;cursor:pointer;border:1px solid transparent;
  display:inline-flex;align-items:center;gap:6px;
  transition:background .15s var(--ease),border-color .15s var(--ease),transform .1s var(--ease)}
button:active:not(:disabled){transform:translateY(1px)}
button:disabled{opacity:.45;cursor:not-allowed}
.btn-p{background:var(--brand);color:#fff}
.btn-p:hover:not(:disabled){background:var(--brand-d)}
.btn-s{background:var(--card);border-color:var(--line);color:var(--text-2)}
.btn-s:hover:not(:disabled){border-color:var(--muted);color:var(--text)}
.btn-mini{padding:3px 9px;font-size:var(--fs-xs);border-radius:var(--r-sm);
  background:var(--card);border:1px solid var(--line);color:var(--muted)}
.btn-mini:hover:not(:disabled){border-color:var(--muted);color:var(--text)}

.opts{display:flex;gap:var(--sp-4);flex-wrap:wrap;font-size:var(--fs-sm);color:var(--muted);
  margin-top:var(--sp-3);align-items:center}
.opts label{display:flex;gap:6px;align-items:center;cursor:pointer}
select,input[type=text],input[type=number],input[type=password]{
  font:inherit;font-size:var(--fs-sm);padding:7px 10px;
  border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--card);color:var(--text);transition:border-color .15s var(--ease)}
select:focus,input:focus{outline:none;border-color:var(--brand)}
/* 单行输入给个上限。之前 TRON 地址框用 flex:1 撑满整行，
   34 个字符占一千多像素，右边一大截空着，很别扭。 */
input[type=text],input[type=password]{min-width:220px;max-width:100%}
::placeholder{color:var(--muted);opacity:.75}

/* ===== 提示条 ===== */
.hint,.netwarn{margin-top:var(--sp-2);font-size:var(--fs-sm);border-radius:var(--r-md);
  padding:11px 15px;line-height:1.7}
.hint{color:var(--warn);background:var(--warn-soft);border:1px solid var(--warn-line)}
.hint b{color:var(--warn);font-weight:600}

/* 需要联网的工具专用警示。刻意比 .hint 更重——
   全站其余工具都承诺数据不上传，这类是例外，必须一眼看见。 */
.netwarn{color:var(--err);background:var(--err-soft);
  border:1px solid var(--err-line);border-left:3px solid var(--err)}
.netwarn b{color:var(--err);font-weight:600}
.netwarn a{color:var(--err)}

.status{margin-top:var(--sp-3);font-size:var(--fs-sm);min-height:22px;
  display:flex;align-items:center;gap:6px}
.s-ok{color:var(--ok)} .s-err{color:var(--err)} .s-run{color:var(--brand)}

/* ===== 文件列表 ===== */
.flist{list-style:none;margin:var(--sp-3) 0 0;padding:0}
.flist li{display:flex;align-items:center;gap:var(--sp-2);padding:9px 12px;
  border:1px solid var(--line);border-radius:var(--r-sm);margin-bottom:6px;
  background:var(--card);font-size:var(--fs-sm)}
.flist .idx{color:var(--muted);font-size:var(--fs-xs);min-width:22px;
  font-variant-numeric:tabular-nums}
.flist .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.flist .meta{color:var(--muted);font-size:var(--fs-xs);white-space:nowrap;
  font-variant-numeric:tabular-nums}

/* ===== 缩略图网格 ===== */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));
  gap:var(--sp-2);margin-top:var(--sp-3)}
.thumb{border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;
  background:var(--card);text-align:center}
.thumb canvas,.thumb img{display:block;width:100%;height:auto;background:#fff}
.thumb .cap{font-size:var(--fs-xs);color:var(--muted);padding:5px 4px;
  border-top:1px solid var(--line)}

/* ===== 批量查询：粘贴框 + 结果表格 ===== */
textarea.ta{width:100%;max-width:720px;min-height:150px;resize:vertical;
  font:var(--fs-sm)/1.75 ui-monospace,Consolas,"Courier New",monospace;
  padding:12px 14px;border:1px solid var(--line);border-radius:var(--r-md);
  background:var(--card);color:var(--text);transition:border-color .15s var(--ease)}
textarea.ta:focus{outline:none;border-color:var(--brand)}
.counter{font-size:var(--fs-xs);color:var(--muted);margin-top:6px;text-align:right;
  font-variant-numeric:tabular-nums}

.seg{display:inline-flex;border:1px solid var(--line);border-radius:var(--r-sm);
  overflow:hidden;background:var(--card)}
.seg button{border:0;border-radius:0;padding:8px 16px;background:transparent;color:var(--muted)}
.seg button.on{background:var(--brand);color:#fff}
.seg button+button{border-left:1px solid var(--line)}

.summary{display:flex;gap:var(--sp-5);flex-wrap:wrap;padding:var(--sp-3) var(--sp-4);
  background:var(--card-2);border:1px solid var(--line);border-radius:var(--r-md);
  margin-bottom:var(--sp-3);font-size:var(--fs-xs);color:var(--muted)}
.summary b{display:block;font-size:var(--fs-lg);font-weight:600;color:var(--text);
  margin-top:2px;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.summary .ok b{color:var(--ok)} .summary .bad b{color:var(--err)} .summary .all b{color:var(--brand)}

.tblwrap{max-height:60vh;overflow:auto;border:1px solid var(--line);
  border-radius:var(--r-md);background:var(--card)}
table.res{border-collapse:separate;border-spacing:0;width:100%;
  font-size:var(--fs-sm);white-space:nowrap}
table.res th,table.res td{padding:9px 14px;border-bottom:1px solid var(--line-2);text-align:left}
table.res thead th{position:sticky;top:0;z-index:1;background:var(--card-2);
  font-weight:600;font-size:var(--fs-xs);letter-spacing:.02em;
  border-bottom:1px solid var(--line);color:var(--muted)}
table.res tbody tr:hover td{background:var(--card-2)}
table.res tbody tr:last-child td{border-bottom:0}
table.res td.mono{font-family:ui-monospace,Consolas,monospace;font-size:var(--fs-xs)}
table.res td.fail{color:var(--err)}
table.res td.dim{color:var(--muted)}
.trunc{font-size:var(--fs-xs);color:var(--muted);padding:11px 14px;
  text-align:center;background:var(--card-2);border-top:1px solid var(--line)}

/* ===== 上传回执，替换掉拖放区 ===== */
.uploaded{display:none;border:1px solid var(--ok-line);background:var(--ok-soft);
  border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4)}
.uploaded.on{display:block}
.uploaded .hd{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.uploaded .tick{width:20px;height:20px;border-radius:50%;background:var(--ok);color:#fff;
  display:inline-flex;align-items:center;justify-content:center;flex:none}
.uploaded .tick .i{width:13px;height:13px;stroke-width:2.5}
.uploaded .fn{font-weight:600;word-break:break-all}
.uploaded .meta{font-size:var(--fs-sm);color:var(--muted);margin-top:8px;line-height:1.75}
.uploaded .meta b{color:var(--text);font-variant-numeric:tabular-nums}
.uploaded .warn{color:var(--err)}
.uploaded .acts{margin-top:var(--sp-3);display:flex;gap:8px;flex-wrap:wrap}

/* ===== 加载进度 ===== */
.prog{margin-top:var(--sp-2);display:none}
.prog.on{display:block}
.prog .bar{height:4px;background:var(--line);border-radius:99px;overflow:hidden}
.prog .bar i{display:block;height:100%;width:0;background:var(--brand);transition:width .25s var(--ease)}
.prog .txt{font-size:var(--fs-xs);color:var(--muted);margin-top:7px;font-variant-numeric:tabular-nums}

/* ===== 说明区 ===== */
/* 容器加宽到 1240px 后，纯文字段落一行能排到七八十个字，眼睛跟不上。
   给说明类内容单独限一个阅读宽度，表格和控件不受影响。 */
.tips{font-size:var(--fs-sm);color:var(--muted);line-height:1.8;max-width:78ch}
.hint,.netwarn{max-width:82ch}
.tips b{color:var(--text);font-weight:600}
.tips ul{padding-left:18px;margin:8px 0 0}
.tips li{margin-bottom:5px}
.tips li:last-child{margin-bottom:0}
.tips code{font-family:ui-monospace,Consolas,monospace;font-size:.92em;
  background:var(--card-2);border:1px solid var(--line);border-radius:4px;padding:1px 5px}

/* ===== 赞赏区 =====
   原来用 object-fit:cover 把竖长的收款码裁成正方形，上下各切掉约 30%，
   二维码本体缺角、可能扫不出来。改成 contain 完整显示。
   同时由居中竖排改为横排：原先整块高 360px，信息量却很少。 */
.tip-jar{display:flex;align-items:center;gap:var(--sp-5);flex-wrap:wrap;text-align:left}
.tip-jar .say{flex:1;min-width:220px}
.tip-jar h3{font-size:var(--fs-md);font-weight:600;margin:0 0 6px}
.tip-jar p{font-size:var(--fs-sm);color:var(--muted);margin:0;line-height:1.7}
.qr{display:flex;gap:var(--sp-3);flex-wrap:wrap}
.qr figure{margin:0;text-align:center}
.qr img{width:104px;height:142px;object-fit:contain;
  border:1px solid var(--line);border-radius:var(--r-sm);background:#fff;
  transition:transform .18s var(--ease),box-shadow .18s var(--ease)}
/* 收款码本来就小，悬停放大方便扫 */
.qr figure:hover img{transform:scale(1.06);box-shadow:0 8px 24px rgba(22,40,80,.14)}
.qr figcaption{font-size:var(--fs-xs);color:var(--muted);margin-top:6px}
/* 弹窗里的收款码是独立居中展示的，不走赞赏区那套横排 */
.modal .qr{justify-content:center}
@media(max-width:560px){
  .tip-jar{flex-direction:column;align-items:flex-start;gap:var(--sp-3)}
}

footer{text-align:center;color:var(--muted);font-size:var(--fs-xs);
  margin-top:var(--sp-5);padding-top:var(--sp-4);border-top:1px solid var(--line);line-height:2}

/* ===== 弹窗 ===== */
.mask{position:fixed;inset:0;background:rgba(10,13,17,.5);display:none;
  align-items:center;justify-content:center;padding:var(--sp-4);z-index:99;
  backdrop-filter:blur(2px)}
.mask.on{display:flex}
.modal{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:var(--sp-5);max-width:460px;width:100%;box-shadow:var(--shadow)}
.modal h3{margin:0 0 var(--sp-2);font-size:var(--fs-md);font-weight:600}
.modal p{margin:0 0 var(--sp-2);font-size:var(--fs-sm);color:var(--text-2)}
.modal ol{margin:0 0 var(--sp-3);padding-left:20px;font-size:var(--fs-sm);line-height:2}
.modal .note{font-size:var(--fs-sm);color:var(--muted);background:var(--card-2);
  border:1px solid var(--line);border-radius:var(--r-sm);padding:9px 12px;margin-bottom:var(--sp-4)}

@media(max-width:700px){
  :root{--fs-xl:23px; --fs-2xl:27px}
  .wrap{padding:var(--sp-4) var(--sp-4) 56px}
  .topbar{padding:var(--sp-3) var(--sp-3) 0}
  .drop{padding:32px var(--sp-3)}
  input[type=text],input[type=password]{min-width:150px}
  .summary{gap:var(--sp-4)}
  .qr{gap:var(--sp-4)}
}

/* ===== 滚动揭示 =====
   用 IntersectionObserver 加 .in（见 common.js），不监听 scroll 事件。
   动效只为建立阅读顺序，所以位移很小、只做一次。

   关键：隐藏态挂在 html.js-rv 下，而不是直接写 .rv。
   隐藏由 JS 开启、显示由 JS 完成——如果 JS 没跑（被拦截、加载失败、
   或 CSS 已更新但 JS 还是旧缓存），元素压根不会被隐藏，页面照常可读。
   直接写 .rv{opacity:0} 会让整页的可见性依赖 JS，一旦失败就是白屏。 */
.js-rv .rv{opacity:0;transform:translateY(14px);
  transition:opacity .7s var(--ease),transform .7s var(--ease)}
.js-rv .rv.in{opacity:1;transform:none}
.js-rv .rv-d1{transition-delay:.06s} .js-rv .rv-d2{transition-delay:.12s}
.js-rv .rv-d3{transition-delay:.18s} .js-rv .rv-d4{transition-delay:.24s}

@media (prefers-reduced-motion: reduce){
  *{transition:none !important;animation:none !important}
  .js-rv .rv{opacity:1;transform:none}
}
