
*,*::before,*::after{box-sizing:border-box}
:root{
 --bg:#f7f8fa; --panel:#fff; --ink:#1a1d21; --ink2:#4a5158; --ink3:#7c858e;
 --line:#e4e7eb; --line2:#eef0f3; --brand:#2563eb; --brand-soft:#eff4ff;
 --brand-d:#1d4ed8; --accent:#b45309; --accent-soft:#fff7ed; --ok:#15803d; --radius:14px;
 --shadow:0 1px 2px rgba(16,24,40,.04),0 4px 16px rgba(16,24,40,.05);
 /* 交互动效统一用这三个记号：曲线带回弹，让反馈“灵动”但不浮夸 */
 --ease:cubic-bezier(.34,1.42,.5,1); --easeout:cubic-bezier(.22,.8,.3,1); --dur:.22s;
 --ring:rgba(37,99,235,.2);
 --shadow2:0 8px 26px rgba(16,24,40,.10),0 2px 6px rgba(16,24,40,.05);
}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:76px}
body{margin:0;background:var(--bg);color:var(--ink);
 font:16px/1.75 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;}
a{color:var(--brand);text-decoration:none;transition:color var(--dur) var(--easeout)}
a:hover{text-decoration:underline}
img{max-width:100%;display:block}
/* 点击/键盘聚焦都要看得见（很多人只做 hover，键盘用户就完全失去反馈） */
a:focus-visible,button:focus-visible,.chip:focus-visible,input:focus-visible{
 outline:none;box-shadow:0 0 0 3px var(--ring);border-radius:8px}
::selection{background:#dbe6fb;color:var(--ink)}
@media(prefers-reduced-motion:reduce){
 html{scroll-behavior:auto}
 *,*::before,*::after{transition-duration:.001ms!important;animation-duration:.001ms!important}
 /* 动效关掉时，滚动进入的初始隐藏态也必须一起关掉，否则内容会真的看不见 */
 html.js .main>section,html.js .main>div.pager{opacity:1!important;transform:none!important}
}
.wrap{max-width:1120px;margin:0 auto;padding:0 22px}
.topbar{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.88);
 backdrop-filter:saturate(180%) blur(12px);border-bottom:1px solid var(--line)}
.topbar .wrap{display:flex;align-items:center;gap:14px;height:56px}
.topbar .brand{font-weight:700;font-size:15px;color:var(--ink);display:flex;align-items:center;gap:8px}
.topbar .brand span.dot{width:8px;height:8px;border-radius:50%;background:var(--brand);display:inline-block}
.topbar nav{margin-left:auto;display:flex;gap:16px;font-size:13.5px;color:var(--ink3)}
.topbar nav a{color:var(--ink3);position:relative;padding-bottom:2px}
/* 划过去时下划线从左侧展开——比直接变色更有反馈感，但幅度很小 */
.topbar nav a::after{content:"";position:absolute;left:0;right:0;bottom:-3px;height:2px;
 border-radius:2px;background:var(--brand);transform:scaleX(0);transform-origin:left;
 transition:transform var(--dur) var(--easeout)}
.topbar nav a:hover{color:var(--brand);text-decoration:none}
.topbar nav a:hover::after{transform:scaleX(1)}
/* hero */
.hero{padding:52px 0 34px;border-bottom:1px solid var(--line);
 background:radial-gradient(880px 300px at 10% -14%,#e6eeff 0%,rgba(230,238,255,0) 62%),
  linear-gradient(180deg,#fff 0%,#f7f8fa 100%)}
.hero .kicker{font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--brand);font-weight:700}
.hero h1{font-size:38px;line-height:1.25;margin:12px 0 14px;letter-spacing:-.5px}
.hero p.sub{font-size:16.5px;color:var(--ink2);max-width:760px;margin:0}
.stats{display:flex;flex-wrap:wrap;gap:10px;margin-top:24px}
.stats div{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:10px 16px;box-shadow:var(--shadow)}
.stats b{display:block;font-size:21px;line-height:1.2}
.stats small{color:var(--ink3);font-size:12.5px}
/* sections */
section{padding:44px 0}
section+section{border-top:1px solid var(--line)}
h2.sec{font-size:23px;margin:0 0 6px;letter-spacing:-.2px;display:flex;align-items:center;gap:10px}
h2.sec i{font-style:normal;font-size:19px}
p.secsub{color:var(--ink3);font-size:14px;margin:0 0 26px}
/* category grid */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(258px,1fr));gap:14px}
.cat{display:block;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
 padding:18px;box-shadow:var(--shadow);color:inherit;
 transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--easeout),
  border-color var(--dur) var(--easeout)}
.cat:hover{transform:translateY(-3px);border-color:#c8d5ee;box-shadow:var(--shadow2);text-decoration:none}
.cat:active{transform:translateY(-1px);box-shadow:var(--shadow)}
.cat .ic{font-size:22px;display:inline-block;transition:transform .3s var(--ease)}
.cat:hover .ic{transform:scale(1.14) rotate(-5deg)}
.cat h3{margin:8px 0 6px;font-size:16.5px}
.cat p{margin:0;font-size:13.5px;color:var(--ink2);line-height:1.6;min-height:44px}
.cat .meta{margin-top:12px;padding-top:11px;border-top:1px solid var(--line2);
 font-size:12.5px;color:var(--ink3);display:flex;justify-content:space-between}
.cat .meta b{color:var(--brand);font-weight:600;display:inline-block;
 transition:transform var(--dur) var(--ease)}
.cat:hover .meta b{transform:translateX(3px)}
/* moves */
.moves{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}
.move{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--brand);
 border-radius:10px;padding:16px 18px;box-shadow:var(--shadow);
 transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--easeout),
  border-left-color var(--dur) var(--easeout)}
.move:hover{transform:translateY(-2px);box-shadow:var(--shadow2);border-left-color:var(--accent)}
.move b{display:block;font-size:14.5px;margin-bottom:6px}
.move span{font-size:13.5px;color:var(--ink2);line-height:1.65}
/* tool cards */
.tool{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
 overflow:hidden;box-shadow:var(--shadow);margin-bottom:20px;
 transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--easeout),
  border-color var(--dur) var(--easeout)}
.tool:hover{border-color:#dfe5f1;box-shadow:var(--shadow2)}
.tool .shot{background:#f2f4f7;border-bottom:1px solid var(--line);position:relative;overflow:hidden}
.tool .shot img{width:100%;cursor:zoom-in;
 transition:transform .45s var(--easeout)}
.tool .shot a:hover img{transform:scale(1.03)}
.tool .shot .tag{position:absolute;left:12px;top:12px;background:rgba(17,24,39,.72);color:#fff;
 font-size:11.5px;padding:4px 9px;border-radius:20px;letter-spacing:.02em}
.tool .body{padding:20px 22px 22px}
.tool h3{margin:0 0 4px;font-size:19px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.tool .who{font-size:13px;color:var(--accent);background:var(--accent-soft);
 border:1px solid #fde9d0;border-radius:20px;padding:2px 10px;font-weight:500}
.tool .intro{color:var(--ink2);font-size:14.5px;margin:10px 0 0}
.tool .tips{margin:14px 0 0;padding:0;list-style:none;counter-reset:t}
.tool .tips li{counter-increment:t;position:relative;padding-left:30px;margin-bottom:9px;
 font-size:14.2px;color:var(--ink2);line-height:1.68}
.tool .tips li::before{content:counter(t);position:absolute;left:0;top:2px;width:20px;height:20px;
 border-radius:50%;background:var(--brand-soft);color:var(--brand);font-size:12px;font-weight:700;
 display:flex;align-items:center;justify-content:center}
.tool .go{display:flex;align-items:center;gap:12px;margin-top:16px;flex-wrap:wrap}
.tool .go .nogo{font-size:13px;color:#7c858e}
.btn{display:inline-flex;align-items:center;gap:7px;background:var(--brand);color:#fff;
 padding:9px 16px;border-radius:9px;font-size:13.5px;font-weight:600;
 box-shadow:0 1px 2px rgba(37,99,235,.25);
 transition:background var(--dur) var(--easeout),transform var(--dur) var(--ease),
  box-shadow var(--dur) var(--easeout)}
.btn:hover{background:var(--brand-d);text-decoration:none;color:#fff;
 transform:translateY(-1px);box-shadow:0 6px 16px rgba(37,99,235,.28)}
/* 按下要有明确的“压下去”反馈，否则点击会显得没反应 */
.btn:active{transform:translateY(0) scale(.975);box-shadow:0 1px 2px rgba(37,99,235,.2)}
.btn.ghost{background:#fff;color:var(--ink2);border:1px solid var(--line);box-shadow:none}
.btn.ghost:hover{background:#f7f8fa;color:var(--ink);border-color:#c8d5ee;
 box-shadow:0 4px 14px rgba(16,24,40,.07)}
.btn.ghost:active{box-shadow:none;background:#f2f4f7}
.tool .noshot{padding:26px 22px;background:#f2f4f7;border-bottom:1px solid var(--line);
 color:var(--ink3);font-size:13.5px;text-align:center}
/* flow */
.flow{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
 padding:24px;box-shadow:var(--shadow)}
.flow .fh{font-size:17px;font-weight:700;margin:0 0 4px}
.flow .fs{color:var(--ink3);font-size:13px;margin:0 0 20px}
.steps{list-style:none;margin:0;padding:0;position:relative}
.steps::before{content:"";position:absolute;left:15px;top:8px;bottom:8px;width:2px;background:var(--line)}
.steps li{position:relative;padding:0 0 20px 46px}
.steps li:last-child{padding-bottom:0}
.steps li .n{position:absolute;left:0;top:0;width:32px;height:32px;border-radius:50%;
 background:var(--panel);border:2px solid var(--brand);color:var(--brand);font-weight:700;font-size:13px;
 display:flex;align-items:center;justify-content:center}
.steps li b{display:block;font-size:15px;margin-bottom:5px}
.steps li p{margin:0;font-size:14.2px;color:var(--ink2);line-height:1.7}
/* pitfalls */
ul.pit{list-style:none;margin:0;padding:0}
ul.pit li{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--accent);
 border-radius:10px;padding:14px 18px;margin-bottom:11px;font-size:14.3px;color:var(--ink2);
 line-height:1.7;box-shadow:var(--shadow)}
ul.pit li strong{color:var(--ink)}
/* table */
.tablebox{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius);
 background:var(--panel);box-shadow:var(--shadow)}
table{width:100%;border-collapse:collapse;font-size:14px}
th,td{padding:11px 14px;text-align:left;border-bottom:1px solid var(--line2);vertical-align:top}
th{background:#fbfcfd;font-size:12.5px;color:var(--ink3);font-weight:600;
 letter-spacing:.04em;text-transform:uppercase;position:sticky;top:0;z-index:2}
tbody tr td{transition:background .14s var(--easeout)}
/* 悬停整行高亮 + 左侧一道品牌色，长表格里特别有用：能一眼跟住当前这一行 */
tbody tr:hover td{background:var(--brand-soft)}
tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--brand)}
td.no{color:var(--ink3);width:46px;font-variant-numeric:tabular-nums}
td.nm{font-weight:600;white-space:nowrap}
td.ds{color:var(--ink2);font-size:13.4px}
td.lk{white-space:nowrap;font-size:13px}
tbody tr.catrow td{background:var(--brand-soft);font-weight:700;color:#1e40af;font-size:13.5px;
 border-bottom:1px solid #dbe6fb}
.catgroup{margin-bottom:36px}
.catgroup h3{font-size:17px;margin:0 0 12px;display:flex;align-items:center;gap:9px}
.catgroup h3 a{font-size:13px;font-weight:400;color:var(--ink3);margin-left:auto;
 transition:color var(--dur) var(--easeout)}
.catgroup h3 a:hover{color:var(--brand);text-decoration:none}
/* 【已删除】总表关键词输入框的 .bar（2026-10-04 二次调整）：
   那个输入框跟着总表一起搬去了 tools.html，而那一页不再放大搜索框
   （用顶栏那唯一一个），所以 .bar 全站已无引用，整块删掉。 */
/* 「全部工具」页的筛选行：chips 下面紧跟 413 行的表格分组，中间要留口气 */
#alltools .chips{margin-bottom:22px}
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip{border:1px solid var(--line);background:var(--panel);border-radius:20px;padding:6px 13px;
 font-size:13px;color:var(--ink2);cursor:pointer;
 transition:background var(--dur) var(--easeout),border-color var(--dur) var(--easeout),
  color var(--dur) var(--easeout),transform var(--dur) var(--ease)}
.chip:hover{border-color:var(--brand);color:var(--brand);transform:translateY(-1px)}
.chip:active{transform:translateY(0) scale(.96)}
.chip.on{background:var(--brand);border-color:var(--brand);color:#fff}
.chip.on:hover{color:#fff;transform:none}
/* nav */
.pager{display:flex;gap:12px;justify-content:space-between;padding:34px 0 46px;flex-wrap:wrap}
.pager a{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:14px 18px;
 color:inherit;box-shadow:var(--shadow);flex:1;min-width:220px;
 transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--easeout),
  border-color var(--dur) var(--easeout)}
.pager a:hover{text-decoration:none;border-color:#c8d5ee;transform:translateY(-2px);box-shadow:var(--shadow2)}
.pager a:active{transform:translateY(0);box-shadow:var(--shadow)}
.pager small{display:block;color:var(--ink3);font-size:12px;margin-bottom:3px}
.pager b{font-size:14.5px;display:inline-block;transition:transform var(--dur) var(--ease)}
.pager a:hover b{transform:translateX(3px)}
.pager a.nx:hover b{transform:translateX(-3px)}
.pager a.nx{text-align:right}
.crumb{font-size:13px;color:var(--ink3);padding:20px 0 0}
.crumb a{color:var(--ink3);transition:color var(--dur) var(--easeout)}
.crumb a:hover{color:var(--brand)}
footer a{transition:color var(--dur) var(--easeout)}
footer a:hover{color:var(--brand)}
footer{border-top:1px solid var(--line);margin-top:20px;padding:26px 0 46px;color:var(--ink3);font-size:13px;background:#fff}
footer p{margin:0 0 6px}
/* 访客数：不公开显示，只出现在不公开的统计页（stats.html） */
.vstat{display:flex;flex-wrap:wrap;gap:14px;margin-top:22px}
.vstat div{flex:1 1 160px;background:var(--panel);border:1px solid var(--line);
 border-radius:12px;padding:18px 20px;box-shadow:var(--shadow)}
.vstat b{display:block;font-size:38px;line-height:1.1;color:var(--brand);font-variant-numeric:tabular-nums}
.vstat small{color:var(--ink3);font-size:12.5px}
/* lightbox：用透明度过渡代替 display 切换，打开/关闭才有「淡入淡出」而不是硬闪 */
#lb{position:fixed;inset:0;background:rgba(16,24,40,.9);display:flex;z-index:200;
 align-items:center;justify-content:center;padding:28px;cursor:zoom-out;
 opacity:0;visibility:hidden;pointer-events:none;
 transition:opacity .22s var(--easeout),visibility .22s}
#lb.on{opacity:1;visibility:visible;pointer-events:auto}
#lb img{max-width:100%;max-height:100%;border-radius:8px;box-shadow:0 20px 60px rgba(0,0,0,.5);
 transform:scale(.94);transition:transform .3s var(--ease)}
#lb.on img{transform:scale(1)}
.lead p{font-size:16px;color:var(--ink2);line-height:1.85;margin:0 0 16px}
.lead p:last-child{margin-bottom:0}
/* ===== 双栏：正文 + 右侧栏 ===== */
.layout{display:grid;grid-template-columns:minmax(0,1fr) 246px;gap:32px;align-items:start}
.main{min-width:0}
.main>section:first-child{padding-top:34px}
.side{position:sticky;top:72px;display:flex;flex-direction:column;gap:16px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
 padding:20px 16px;box-shadow:var(--shadow)}
/* 站长名片 */
.pcard{text-align:center;position:relative}
.pcard .av{width:68px;height:68px;border-radius:50%;margin:0 auto 11px;background:#f2f4f7;
 border:1px solid var(--line);display:flex;align-items:center;justify-content:center;overflow:hidden}
.pcard .av img{width:100%;height:100%;object-fit:cover}
.pcard .av i{font-style:normal;font-size:11.5px;color:var(--ink3);line-height:1.3;text-align:center}
.pcard .nm{font-weight:700;font-size:15.5px;letter-spacing:.01em}
.pcard .bio{font-size:12.6px;color:var(--ink2);line-height:1.62;margin:8px 0 0}
.pnum{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;
 margin:15px 0 0;padding:13px 0 0;border-top:1px solid var(--line2)}
.pnum b{display:block;font-size:16.5px;line-height:1.25;font-variant-numeric:tabular-nums}
.pnum small{font-size:11.5px;color:var(--ink3)}
.pcard .btn{width:100%;justify-content:center;margin-top:15px}
[hidden]{display:none!important}
/* 微信号文字兜底（不公开二维码时用） */
.wxid{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:13px;
 background:#fafbfc;border:1px solid var(--line2);border-radius:10px;padding:9px 11px}
.wxid span{font-size:12.8px;font-weight:700;color:var(--ink);word-break:break-all;
 user-select:all;-webkit-user-select:all}
.wxid .cp{flex:none;font-size:11.5px;font-weight:700;color:var(--brand);
 border:1px solid currentColor;border-radius:7px;padding:3px 9px;text-decoration:none;
 cursor:pointer;transition:.15s}
.wxid .cp:hover{background:var(--brand);color:#fff;text-decoration:none}
.wxid .cp:active{transform:scale(.94)}
/* 公告 */
.notice h4{margin:0 0 11px;font-size:14px;display:flex;align-items:center;gap:7px}
.notice p{margin:0;font-size:12.8px;color:var(--ink2);line-height:1.6;text-align:center;
 background:#fafbfc;border:1px solid var(--line2);border-radius:10px;padding:10px 12px}
/* 打赏弹层：鼠标划到按钮上，收款码从按钮下方弹出来。
   刻意向下弹：这张卡上方紧挨着吸顶导航栏，向上弹会顶出卡片并压在导航栏上；
   向下虽然会盖住下面的公告卡，但弹层是临时的浮层，视觉上更自然。
   hover（鼠标）/ focus-within（键盘）/ .on（触屏，由脚本切换）三条触发路径都要有，
   少一条就有一类用户永远打不开这个码。绝对定位所以不会把下面的内容顶下去。 */
.rw{position:relative;display:block}
.rw-pop{position:absolute;left:50%;top:calc(100% + 12px);z-index:60;width:236px;
 margin-left:-118px;padding:12px;background:#fff;border:1px solid var(--line);border-radius:14px;
 box-shadow:0 18px 44px rgba(16,24,40,.16),0 2px 6px rgba(16,24,40,.06);text-align:center;
 opacity:0;visibility:hidden;pointer-events:none;transform:translateY(-8px) scale(.94);
 transition:opacity .18s var(--easeout),transform .3s var(--ease),visibility .2s}
.rw:hover .rw-pop,.rw:focus-within .rw-pop,.rw.on .rw-pop{
 opacity:1;visibility:visible;pointer-events:auto;transform:translateY(0) scale(1)}
.rw-pop::after{content:"";position:absolute;left:50%;top:-6px;width:12px;height:12px;
 margin-left:-6px;background:#fff;border-left:1px solid var(--line);border-top:1px solid var(--line);
 transform:rotate(45deg);border-radius:3px 0 0 0}
.rw-pop strong{display:block;font-size:12.5px;color:var(--ink);margin-bottom:8px}
.rw-pop em{display:block;font-style:normal;font-size:11.5px;color:var(--ink3);margin-top:8px}
/* 码给到 208px：微信「赞赏码」是圆形放射状自研编码，细线点比标准 QR 密，
   缩到 160 出头会糊成一团扫不动。object-fit 用 contain —— cover 遇上非正方形
   的码图会直接裁掉码点，宁可留白也不能裁。 */
.rw-pop .qb{width:208px;height:208px;padding:0;margin:0 auto;border:1px solid var(--line2);
 border-radius:10px;background:#fff;display:flex;align-items:center;justify-content:center;overflow:hidden}
.rw-pop .qb img{width:100%;height:100%;object-fit:contain}
/* 回到顶部：滚过一屏才淡入（首页总表 413 行，没这个很折磨） */
.totop{position:fixed;right:22px;bottom:26px;z-index:80;width:42px;height:42px;
 border:1px solid var(--line);border-radius:50%;background:rgba(255,255,255,.94);
 backdrop-filter:blur(8px);color:var(--ink2);font-size:17px;line-height:1;cursor:pointer;
 box-shadow:var(--shadow);opacity:0;visibility:hidden;transform:translateY(10px) scale(.9);
 transition:opacity .24s var(--easeout),transform .3s var(--ease),visibility .24s,
  color var(--dur) var(--easeout),border-color var(--dur) var(--easeout),box-shadow var(--dur) var(--easeout)}
.totop.on{opacity:1;visibility:visible;transform:translateY(0) scale(1)}
.totop:hover{color:var(--brand);border-color:var(--brand);box-shadow:var(--shadow2)}
.totop:active{transform:translateY(1px) scale(.94)}
/* 滚动进入：只作用于正文区块。隐藏态挂在 html.js 下——脚本没跑（被拦/被禁）时
   html 上不会有 js 类，内容直接可见，绝不会白屏；脚本里另有 1.5 秒兜底强制显示。 */
html.js .main>section,html.js .main>div.pager{opacity:0;transform:translateY(16px)}
html.js .main>section.in,html.js .main>div.pager.in{opacity:1;transform:none;
 transition:opacity .5s var(--easeout),transform .62s var(--easeout)}
/* ============================================================
   交互升级层（2026-09-29）
   原则：动效只挂在「用户主动划过/点过」的元素上，幅度小、曲线带回弹；
   装饰层不参与布局、不支持时静默降级；正文可读性优先，绝不为了炫牺牲对比度。
   ============================================================ */

/* --- 1. 跟着鼠标走的柔光。JS 把光标位置写成 --mx/--my，卡片上就有一团随光标移动的
       亮斑。只给「纯文字卡片」加，不铺到表格行上——首页总表 413 行全挂会明显掉帧。 --- */
.cat,.move,.flow{position:relative;overflow:hidden}
.cat::before,.move::before,.flow::before{
 content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
 background:radial-gradient(300px circle at var(--mx,50%) var(--my,0%),
  rgba(37,99,235,.17),transparent 62%);
 opacity:0;transition:opacity .3s var(--easeout)}
.cat:hover::before,.move:hover::before,.flow:hover::before{opacity:1}

/* --- 2. 按钮流光：一道斜向高光扫过。ghost 按钮底色是白的，用品牌色高光否则看不见。 --- */
.btn{position:relative;overflow:hidden}
.btn::after{content:"";position:absolute;top:-60%;bottom:-60%;left:-70%;width:42%;
 background:linear-gradient(100deg,transparent,rgba(255,255,255,.5),transparent);
 transform:skewX(-18deg);opacity:0;pointer-events:none}
.btn.ghost::after{background:linear-gradient(100deg,transparent,rgba(37,99,235,.16),transparent)}
.btn:hover::after{opacity:1;animation:shine .72s var(--easeout)}
@keyframes shine{from{left:-70%}to{left:132%}}

/* --- 3. 两个名片入口（请我喝咖啡 / 商务合作）：纵向排列、等宽，卡片才不会歪 --- */
.acts{display:flex;flex-direction:column;gap:10px;margin-top:15px}
.acts .btn{margin-top:0}
/* 划上去有一圈向外扩散的脉冲光环，配合流光让「这里可以点」这件事很难被忽略。
   光环挂在 .rw 上而不是 .btn 上：.btn 为了让流光被裁住挂了 overflow:hidden，
   而 overflow 会把**后代自己的** box-shadow 一并裁掉，光环放 .btn 里根本扩散不出去。
   .rw 内部只有按钮走常规流（弹层是绝对定位、脱流），所以 .rw 的盒子正好贴住按钮。 */
.rw::before{content:"";position:absolute;inset:0;border-radius:9px;
 box-shadow:0 0 0 0 rgba(37,99,235,.42);opacity:0;pointer-events:none}
.rw:hover::before,.rw.on::before{opacity:1;animation:ring 1.8s var(--easeout) infinite}
@keyframes ring{
 0%{box-shadow:0 0 0 0 rgba(37,99,235,.42)}
 70%{box-shadow:0 0 0 13px rgba(37,99,235,0)}
 100%{box-shadow:0 0 0 0 rgba(37,99,235,0)}}

/* --- 4. 弹层「旋转弹出」，码本体再绕一圈展开 —— 这是「按钮会旋转弹出码」的核心 --- */
.rw-pop{transform-origin:50% -8px;
 transform:translateY(-12px) rotate(-6deg) scale(.72)}
.rw-pop .qb{transform:rotate(-160deg) scale(.34);opacity:0;
 transition:transform .62s var(--ease) .05s,opacity .32s var(--easeout) .05s}
.rw:hover .rw-pop,.rw:focus-within .rw-pop,.rw.on .rw-pop{transform:none}
.rw:hover .rw-pop .qb,.rw:focus-within .rw-pop .qb,.rw.on .rw-pop .qb{transform:none;opacity:1}

/* --- 5. Hero 氛围层：两团缓慢飘移的柔光。用 z-index 把正文抬到氛围层之上，
       保证标题/正文的对比度不受影响。 --- */
.hero{position:relative;overflow:hidden}
.hero::before,.hero::after{content:"";position:absolute;border-radius:50%;
 pointer-events:none;filter:blur(42px)}
.hero::before{width:430px;height:430px;left:-90px;top:-180px;opacity:.55;
 background:radial-gradient(circle,rgba(37,99,235,.30),transparent 68%);
 animation:drift1 17s ease-in-out infinite}
.hero::after{width:370px;height:370px;right:-70px;top:-140px;opacity:.45;
 background:radial-gradient(circle,rgba(180,83,9,.22),transparent 68%);
 animation:drift2 21s ease-in-out infinite}
.hero>.wrap{position:relative;z-index:1}
@keyframes drift1{50%{transform:translate3d(46px,28px,0) scale(1.09)}}
@keyframes drift2{50%{transform:translate3d(-38px,32px,0) scale(1.11)}}

/* --- 6. 顶栏：滚动后轻轻浮起，和内容分开层次 --- */
.topbar.scrolled{box-shadow:0 6px 22px rgba(16,24,40,.07);border-bottom-color:#dbe1ea}
/* 阅读进度线：贴着顶栏下沿，2px，滚起来才有。首页总表 413 行，有它比没有强。
   宽度用 transform:scaleX 而不是 width —— 不触发布局，走合成层。 */
.pgbar{position:absolute;left:0;right:0;bottom:-1px;height:2px;pointer-events:none;
 background:linear-gradient(90deg,var(--brand),#7aa8ff);border-radius:0 2px 2px 0;
 transform:scaleX(0);transform-origin:0 50%;opacity:0;
 transition:opacity .3s var(--easeout)}
.topbar.scrolled .pgbar{opacity:1}
/* 品牌圆点呼吸一下，静态页面里也有一点活的细节 */
.topbar .brand span.dot{animation:breathe 3.4s ease-in-out infinite}
@keyframes breathe{50%{transform:scale(1.35);box-shadow:0 0 0 4px rgba(37,99,235,.14)}}

/* --- 7. 数字滚动：等宽数字，避免跳动时宽度变化把布局带得发抖 --- */
.stats b{font-variant-numeric:tabular-nums}

/* --- 8. 回到顶部：悬停时转一圈再浮起来 --- */
.totop:hover{transform:translateY(-3px) rotate(360deg);color:var(--brand);
 border-color:var(--brand);box-shadow:var(--shadow2)}
/* 上面这条 :hover 在本层里晚于基础层，会把基础层的 :active「压下去」反馈盖掉，
   所以按下态必须在这里再写一遍（否则鼠标用户点下去毫无反馈）。 */
.totop:hover:active{transform:translateY(0) scale(.94) rotate(360deg)}

/* --- 9. 截图卡悬停时给缩略图一点点提亮，和抬升配合 --- */
.tool:hover .shot img{filter:saturate(1.04) contrast(1.02)}

/* --- 10. 光标尾迹（「锅气」火星）：一串小点拉着走，停下约半秒自己散掉。
       整块由脚本建出来，只在「有 hover 且没开减弱动效」的设备上存在 ——
       触屏 / 无脚本 / 开了减动效时 DOM 里根本没有 .ct 这个节点，一行样式都不生效。
       安全底线：容器 inset:0 + position:fixed + pointer-events:none ——
       固定定位的元素不进文档流、不参与可滚动溢出计算，所以永远撑不出横向滚动条；
       pointer-events 关掉则永远挡不住链接和按钮的点击。
       z-index 90 高于顶栏(50)，光标划过顶栏时尾迹不会突然消失；仍低于图片灯箱(200)。 */
.ct{position:fixed;inset:0;overflow:hidden;pointer-events:none;z-index:90;
 opacity:0;transition:opacity .26s linear}
/* 淡入要比淡出快：鼠标一动就该立刻看见尾巴，不然前半秒是「半透明幽灵」；
   停下之后反而可以慢一点化开，比「啪」一下消失自然。 */
.ct.on{opacity:1;transition:opacity .1s linear}
.ct i{position:absolute;left:0;top:0;display:block;border-radius:50%;
 transform:translate3d(-80px,-80px,0) translate(-50%,-50%);
 will-change:transform,opacity;
 /* 渐变的实色区必须一直顶到 78% 才开始衰减：原来 55% 就淡出，小节点上
    真正不透明的只剩中间 3px，配上逐节的低 opacity 直接等于看不见
    （实测远端 3 节在浅色卡片上完全消失）。 */
 background:radial-gradient(circle at 40% 36%,#ffd89a,#f2a52c 58%,#e8912a 78%,
  rgba(226,140,26,.45) 92%,rgba(226,140,26,0) 100%)}
.ct i:nth-child(1){width:13px;height:13px;box-shadow:0 0 16px 4px rgba(242,165,44,.5)}
.ct i:nth-child(2){width:10px;height:10px;opacity:.85}
.ct i:nth-child(3){width:7.6px;height:7.6px;opacity:.68}
.ct i:nth-child(4){width:5.6px;height:5.6px;opacity:.52}
.ct i:nth-child(5){width:4.4px;height:4.4px;opacity:.38}
.ct i:nth-child(6){width:3.2px;height:3.2px;opacity:.26}
/* 双保险：脚本已经判过 prefers-reduced-motion，样式层再兜一次；打印时一律不出现。 */
@media (prefers-reduced-motion:reduce){.ct{display:none}}
@media print{.ct{display:none}}

/* ============================================================
   导航式首页（2026-10-04）
   ── 版式对齐「AI 导航站」那套：左栏分类导航常驻，右栏是内容墙。
      首页单独用 .nlayout，不复用文章页的 .layout —— 那个是「正文 + 右侧名片卡」，
      导航在左、内容在右，语义和方向都不一样，硬套会让两边的断点互相打架。
   ============================================================ */
.nlayout{display:grid;grid-template-columns:214px minmax(0,1fr);gap:26px;align-items:start;
 padding:26px 0 34px}
/* .nlayout 自己已经有上下内边距，section 的通用上边距会在 hero 和第一个区块之间
   叠出 60px 的空白。这里把首尾两块的额外内边距清掉。 */
.nlayout .main>section:first-child{padding-top:0}
.nlayout .main>section:last-child{padding-bottom:0}
.rail{position:sticky;top:70px;display:flex;flex-direction:column;gap:14px}
.railnav{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
 box-shadow:var(--shadow);padding:9px}
.railnav h4{margin:6px 8px 8px;font-size:11.5px;letter-spacing:.1em;color:var(--ink3);font-weight:700}
.railnav a{display:flex;align-items:center;gap:9px;padding:7px 9px;border-radius:9px;
 font-size:13.4px;color:var(--ink2);line-height:1.4;
 transition:background var(--dur) var(--easeout),color var(--dur) var(--easeout),
  transform var(--dur) var(--ease)}
.railnav a i{font-style:normal;font-size:15px;width:19px;flex:none;text-align:center}
.railnav a em{font-style:normal;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
 white-space:nowrap}
.railnav a b{font-size:11.5px;font-weight:600;color:var(--ink3);flex:none;
 font-variant-numeric:tabular-nums}
.railnav a:hover{background:var(--brand-soft);color:var(--brand-d);text-decoration:none;
 transform:translateX(2px)}
.railnav a:hover b{color:var(--brand)}
/* 左栏只有 214px 宽，默认那个 236px 的弹层会从卡片左边溢出去。
   收到 196px 后：卡片内居中，左右各留 ~9px，整个弹层都落在栏内，不会撑出横向滚动条。 */
.rail .rw-pop{width:196px;margin-left:-98px}
.rail .rw-pop .qb{width:172px;height:172px}
/* 【已删除】hero 大搜索框的 .hsearch（2026-10-04 二次调整）。
   同一屏出现两个搜索框，用户会先犹豫「这两个是不是搜不同东西」，郭子的原话是
   「搜索框太多了，就保留一个右上角的」。现在全站唯一的搜索框是顶栏的 .tsearch，
   它在「全部工具」页是就地筛选、在别的页是跳过去搜。
   样式整块删掉而不是留着不用：留着下一个人会以为它还挂在某个模板上。 */

/* 顶栏站内搜索：宽度固定，避免打字时输入框忽宽忽窄把整条导航挤来挤去 */
.topbar nav{margin-left:6px}
.tsearch{position:relative;margin-left:auto;display:flex;align-items:center;flex:none;width:212px}
.tsearch::before{content:"🔍";position:absolute;left:12px;font-size:12px;opacity:.5;
 pointer-events:none;line-height:1}
.tsearch input{width:100%;padding:7px 52px 7px 31px;border:1px solid var(--line);border-radius:20px;
 font-size:13px;background:#f5f7fa;outline:none;color:var(--ink);
 transition:border-color var(--dur) var(--easeout),background var(--dur) var(--easeout),
  box-shadow var(--dur) var(--easeout)}
.tsearch input:hover{border-color:#c8d5ee}
.tsearch input:focus{background:#fff;border-color:var(--brand);
 box-shadow:0 0 0 3px rgba(37,99,235,.12)}
/* 提交按钮压在输入框右端。不加按钮的话手机上只能靠软键盘「前往」键，太难发现 */
.tsearch button{position:absolute;right:3px;top:50%;transform:translateY(-50%);border:0;
 cursor:pointer;background:var(--brand);color:#fff;font-size:11.5px;font-weight:600;
 padding:4px 11px;border-radius:16px;line-height:1.5;
 transition:background var(--dur) var(--easeout)}
.tsearch button:hover{background:var(--brand-d)}
/* 快捷入口 */
.qk{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}
.qk a{display:flex;align-items:center;gap:11px;background:var(--panel);border:1px solid var(--line);
 border-radius:12px;padding:13px 14px;box-shadow:var(--shadow);color:inherit;
 transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--easeout),
  border-color var(--dur) var(--easeout)}
.qk a:hover{transform:translateY(-3px);border-color:#c8d5ee;box-shadow:var(--shadow2);
 text-decoration:none}
.qk a:active{transform:translateY(-1px)}
.qk .qi{width:36px;height:36px;flex:none;border-radius:10px;background:var(--brand-soft);
 display:flex;align-items:center;justify-content:center;font-size:18px}
.qk .qt{min-width:0}
.qk b{display:block;font-size:13.8px}
.qk .qt span{display:block;font-size:11.8px;color:var(--ink3);line-height:1.45}
/* 工具卡片墙 */
.wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(202px,1fr));gap:12px}
.tcard{display:flex;gap:11px;padding:12px 13px;background:var(--panel);border:1px solid var(--line);
 border-radius:12px;box-shadow:var(--shadow);color:inherit;min-width:0;
 transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--easeout),
  border-color var(--dur) var(--easeout)}
.tcard:hover{transform:translateY(-3px);border-color:#c8d5ee;box-shadow:var(--shadow2);
 text-decoration:none}
.tcard:active{transform:translateY(-1px)}
/* logo 是 96×96 透明底原图缩到 36px。留 3px 内边距 + 白底：
   有些 logo 是深色满幅方图，贴着圆角边会显得很挤。 */
.tcard .lg{width:36px;height:36px;flex:none;border-radius:9px;background:#fff;
 border:1px solid var(--line2);object-fit:contain;padding:3px}
.tcard .tx{min-width:0;flex:1}
.tcard b{display:block;font-size:13.8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tcard .hs{display:block;font-size:11.4px;color:var(--brand);margin-top:1px;
 white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tcard p.ds{margin:4px 0 0;font-size:12.2px;color:var(--ink3);line-height:1.5;
 display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* 分类卡底部的迷你 logo 排 */
.cat .minis{display:flex;align-items:center;gap:5px;margin-top:11px}
.cat .minis img{width:24px;height:24px;border-radius:7px;background:#fff;
 border:1px solid var(--line2);object-fit:contain;padding:2px;flex:none}
.cat .minis .mmore{margin-left:auto;font-size:11.5px;color:var(--ink3)}
/* 推广位：虚线框 + 右上角「推广」角标。是广告位就明确标出来，别假装成正文卡片 */
.promo{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.promocard{position:relative;display:flex;flex-direction:column;gap:8px;
 border:1px dashed #cfd8e3;border-radius:var(--radius);padding:17px 19px;
 background:linear-gradient(135deg,#fff 0%,#f6f9ff 100%)}
.promocard::before{content:"推广";position:absolute;right:12px;top:12px;font-size:10.5px;
 color:var(--ink3);background:#fff;border:1px solid var(--line);border-radius:20px;padding:1px 8px}
.promocard strong{display:block;font-size:15px;padding-right:52px}
.promocard p{margin:0;font-size:13.2px;color:var(--ink2);line-height:1.65}
.promocard .pact{align-self:flex-start;margin-top:2px}
/* 推广位上的 .rw 弹层是「浮在卡片外」的，卡片自己不能裁；但 .btn 又必须裁（流光要贴边）。
   所以这里只放开 .promocard 的裁切，不改 .btn。 */
.promocard{overflow:visible}
/* 跳到名片卡时的脉冲高亮：推广位 → 商务合作，让用户知道该看哪儿 */
.card.flash{animation:flash 1.6s var(--easeout) 1}
@keyframes flash{
 0%,100%{box-shadow:var(--shadow)}
 30%{box-shadow:0 0 0 4px rgba(37,99,235,.22),var(--shadow2)}}
/* 名片卡 + 公告（首页）。文章页那份仍在右栏（.side），这里是首页的横向两栏版。
   卡片被拉到 500px 宽，两个按钮如果各自撑满会又粗又难看，所以限个宽再居中。 */
.me{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:14px;align-items:start}
.me .pcard{padding:22px 20px}
.me .pcard .acts{max-width:300px;margin-left:auto;margin-right:auto}
.me .notice p{padding:12px 14px}

@media(max-width:940px){
 .layout{grid-template-columns:minmax(0,1fr);gap:0}
 .side{position:static;flex-direction:row;flex-wrap:wrap;padding:34px 0 0}
 .side .card{flex:1 1 250px}
 /* 单栏时名片的卡变矮，弹层相应收一点，避免顶出屏幕 */
 .rw-pop{width:222px;margin-left:-111px}
 .rw-pop .qb{width:196px;height:196px}
 /* 首页左栏落到内容上方：分类导航从「竖排一长条」改成「横向一条，能左右滑」——
    16 项竖着排有 400px 高，直接把首屏内容挤到屏幕外。 */
 .nlayout{grid-template-columns:minmax(0,1fr);gap:0;row-gap:12px;padding:18px 0 30px}
 .rail{position:static}
 .railnav{display:flex;align-items:center;gap:6px;overflow-x:auto;padding:8px;
  -webkit-overflow-scrolling:touch;scrollbar-width:none}
 .railnav::-webkit-scrollbar{display:none}
 .railnav h4{display:none}
 .railnav a{flex:none;padding:6px 11px;border:1px solid var(--line);border-radius:20px;
  white-space:nowrap}
 .railnav a:hover{transform:none}
 .railnav a i{font-size:13px;width:auto}
 .railnav a b{display:none}
 .me{grid-template-columns:minmax(0,1fr)}
 .qk{grid-template-columns:repeat(2,minmax(0,1fr))}
 .promo{grid-template-columns:minmax(0,1fr)}
 .wall{grid-template-columns:repeat(auto-fill,minmax(176px,1fr))}
 .tsearch{width:172px}
}
/* 顶栏菜单先让位给搜索框：窄屏上「品牌 + 5 个菜单 + 搜索框」会挤成一团，
    而搜索是导航站最常用的入口。分类导航在左栏（手机上在顶部横条）已经全都有。 */
@media(max-width:860px){
 .topbar nav{display:none}
}
@media(max-width:640px){
 .hero h1{font-size:27px}.hero{padding:34px 0 26px}
 /* 手机首屏的 4 个数字：flex 换行会排成 3+1，右下角吊着一个特别扎眼。
    改成 2×2 网格，四个格子等宽对齐，看着才「整洁」。 */
 .stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
 h2.sec{font-size:20px}section{padding:32px 0}
 .main>section:first-child{padding-top:26px}
 .tool .body{padding:16px}.tablebox{border-radius:10px}
 th,td{padding:9px 10px}td.ds{display:none}
 .topbar nav{display:none}
 .side{padding-top:26px}
 .totop{right:14px;bottom:16px;width:38px;height:38px;font-size:15px}
 /* 首页：卡片墙降到单列，一行一张才看得清 logo 和两行说明 */
 .nlayout{padding:12px 0 24px}
 .wall{grid-template-columns:minmax(0,1fr)}
 .qk{gap:10px}
 .qk a{padding:11px 12px;gap:9px}
 .promocard{padding:15px 16px}
 .tsearch{width:148px}
 .tsearch::before{left:10px}
 .tsearch input{padding-left:28px;padding-right:48px}
}
