/* ==========================================================================
   Vault · 在线工具箱
   设计基调：午夜冷调玻璃 (Midnight Cold Glass)
   取自背景图：深夜墨蓝 #0A121C / 冷雾蓝 #587A9B / 幽蓝辉光 #9CC0DC
   强调色仅用于主按钮、选中态与图标描边，占画面 < 8%
   ========================================================================== */

/* ---------- 1. 设计令牌 ---------- */
:root{
  /* 底色 */
  --bg-deep:      #060c14;
  --bg:           #080d14;
  --bg-soft:      #0c141f;

  /* 文字（在深色玻璃上均满足 WCAG AA 4.5:1 以上） */
  --ink:          #eaf2fa;
  --ink-2:        #a9bccf;
  --ink-3:        #8ba3ba;
  --ink-4:        #7d94ab;
  --ink-ph:       #a9bccf;   /* 占位符：比正文暗、但明显高于背景 */

  /* 强调（取自画面辉光的提亮版） */
  --accent:       #7fc4e8;
  --accent-2:     #5fd0e8;
  --accent-deep:  #3f7fa8;
  --accent-glow:  rgba(127,196,232,.30);

  /* 语义色（冷色系内的低饱和变体，避免破坏整体调性） */
  --ok:           #6ee7c0;
  --warn:         #e8c47f;
  --err:          #e88a9a;

  /* 玻璃 */
  --glass:        rgba(16,26,38,.46);
  --glass-2:      rgba(14,23,34,.62);
  --glass-3:      rgba(11,19,29,.82);
  --glass-panel:  rgba(13,21,33,.70);
  --glass-card:   rgba(24,37,54,.74);
  --glass-hi:     rgba(34,50,70,.80);
  --blur:         22px;
  --blur-lg:      34px;
  --sat:          140%;

  /* 描边 */
  --stroke:       rgba(255,255,255,.10);
  --stroke-soft:  rgba(255,255,255,.06);
  --stroke-hi:    rgba(255,255,255,.20);

  /* 圆角 */
  --r-xs: 8px;
  --r-sm: 12px;
  --r:    18px;
  --r-lg: 22px;
  --r-xl: 28px;

  /* 阴影 */
  --shadow:       0 8px 32px rgba(0,0,0,.45);
  --shadow-lg:    0 24px 70px rgba(0,0,0,.62);
  --shadow-inset: inset 0 1px 0 rgba(255,255,255,.14);

  /* 排版 */
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI Variable Display",
          "Segoe UI", Inter, "HarmonyOS Sans SC", "PingFang SC", "Hiragino Sans GB",
          "Noto Sans CJK SC", "Source Han Sans SC", "Microsoft YaHei UI", "Microsoft YaHei",
          system-ui, sans-serif;
  --mono: "SF Mono", "JetBrains Mono", "Cascadia Code", "Fira Code", ui-monospace,
          Menlo, Consolas, "Liberation Mono", "Courier New", monospace;

  /* 布局 */
  --page:  1240px;
  --gap:   18px;
  --topbar-h: 64px;

  /* 动效 */
  --ease: cubic-bezier(.22,.61,.36,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
}

/* ---------- 2. 基础重置 ---------- */
*,*::before,*::after{ box-sizing:border-box; }

html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  height:100%;
}
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{ animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; }
}

body{
  margin:0;
  min-height:100%;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--sans);
  font-size:15px;
  line-height:1.65;
  font-weight:400;
  letter-spacing:.01em;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
body.is-locked{ overflow:hidden; }

h1,h2,h3,h4{ margin:0; font-weight:300; letter-spacing:-.015em; line-height:1.25; }
p{ margin:0; }
a{ color:inherit; text-decoration:none; }
button,input,select,textarea{ font:inherit; color:inherit; }
button{ cursor:pointer; background:none; border:0; }
img,svg{ display:block; max-width:100%; }
/* 图标默认跟随字号：任何漏写尺寸的 svg 都会被限制在 1em，绝不会撑破布局。
   （曾因为 svg 默认 100%×100% 导致分类胶囊里的图标被放大成巨型方块）
   ⚠️ 例外：MathJax 渲染出来的公式也是 <svg>，它靠 width/height 属性定尺寸，
      而 CSS 优先级高于呈现属性 —— 不放行的话每条公式都会被压成 15×15 像素（实测整图只剩 2 个深色像素）。 */
svg{ width:1em; height:1em; }
mjx-container svg, svg[data-mml-node]{ width:auto; height:auto; }
::selection{ background:rgba(127,196,232,.32); color:#fff; }

:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:2px;
  border-radius:4px;
}

/* 滚动条 */
*{ scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.16) transparent; }
*::-webkit-scrollbar{ width:10px; height:10px; }
*::-webkit-scrollbar-track{ background:transparent; }
*::-webkit-scrollbar-thumb{
  background:rgba(255,255,255,.14);
  border:3px solid transparent;
  border-radius:99px;
  background-clip:padding-box;
}
*::-webkit-scrollbar-thumb:hover{ background:rgba(255,255,255,.24); background-clip:padding-box; }

.skip{
  position:fixed; top:-100px; left:16px; z-index:200;
  padding:10px 16px; border-radius:0 0 var(--r-sm) var(--r-sm);
  background:var(--accent); color:#04202e; font-weight:600; font-size:13px;
  transition:top .2s var(--ease);
}
.skip:focus{ top:0; }

/* ---------- 3. 背景层 ---------- */
.bg{ position:fixed; inset:0; z-index:-1; overflow:hidden; background:var(--bg-deep); }

.bg__img{
  position:absolute; inset:-4%;
  background-image:url("../img/bg.webp");
  background-size:cover;
  background-position:52% 26%;
  background-repeat:no-repeat;
  /* 轻度模糊让面部细节退后、只留蓝雾与辉光的氛围 */
  filter:saturate(.98) contrast(1.02) brightness(1.02) blur(2px);
  transform:scale(1.045);
  animation:breathe 28s var(--ease) infinite alternate;
  will-change:transform;
}
@keyframes breathe{
  from{ transform:scale(1.045) translate3d(0,0,0); }
  to  { transform:scale(1.0)   translate3d(0,-.8%,0); }
}

/* 从左上暗到右下亮的斜向遮罩：让文字落在暗部，辉光留在明部 */
.bg__tint{
  position:absolute; inset:0;
  background:
    linear-gradient(135deg, rgba(6,12,20,.86) 0%, rgba(6,12,20,.68) 38%, rgba(6,12,20,.40) 68%, rgba(6,12,20,.26) 100%);
}
/* 顶部与底部的进出场过渡，保证顶栏与页脚可读 */
.bg__vignette{
  position:absolute; inset:0;
  background:
    radial-gradient(120% 78% at 50% 8%,  rgba(6,12,20,.60) 0%, rgba(6,12,20,0) 58%),
    radial-gradient(100% 60% at 50% 106%, rgba(6,12,20,.76) 0%, rgba(6,12,20,0) 62%),
    radial-gradient(140% 120% at 50% 50%,  rgba(6,12,20,0) 46%, rgba(6,12,20,.46) 100%);
}
/* 胶片颗粒：强化插画的材质感，同时抑制背景的带状色阶 */
.bg__grain{
  position:absolute; inset:0; opacity:.16; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px;
}
/* 跟随鼠标的柔光 —— 已停用。
   它是纯装饰，没有携带任何状态或信息，属于「AI 页面」的典型堆料。
   保留规则但把透明度压到 0，这样 app.js 里设置 --mx/--my 的逻辑不用改。 */
.bg__spot{
  position:absolute; inset:0; opacity:0;
}
body.immersed .bg__img{ filter:saturate(.4) brightness(.34) blur(26px); }
body.immersed .bg__grain{ opacity:.08; }

/* ---------- 4. 玻璃基类 ---------- */
.glass{
  position:relative;
  background:var(--glass);
  -webkit-backdrop-filter:blur(var(--blur)) saturate(var(--sat)) brightness(1.06);
  backdrop-filter:blur(var(--blur)) saturate(var(--sat)) brightness(1.06);
  border-radius:var(--r-lg);
  box-shadow:var(--shadow), var(--shadow-inset);
}
/* 顶部/左侧亮边、底部/右侧暗边的玻璃棱边 */
.glass::before{
  content:""; position:absolute; inset:0; border-radius:inherit; padding:1px;
  background:linear-gradient(150deg, var(--stroke-hi), rgba(255,255,255,.03) 42%, rgba(255,255,255,.02) 62%, rgba(255,255,255,.09));
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite:exclude;
  pointer-events:none; z-index:1;
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass{ background:var(--glass-2); }
}

/* ---------- 5. 顶栏 ----------
   原来是一条悬浮的圆角玻璃胶囊（圆角+半透明+描边+backdrop-blur 全占），
   飘在背景图上没有归属感，也是最典型的「模板默认皮肤」长相。
   改成通栏 + 底部 1px 分隔线，只在滚动时把底色加深。 */
.topbar{
  position:sticky; top:0; z-index:60;
  border-bottom:1px solid transparent;
  transition:background .3s var(--ease), border-color .3s var(--ease);
}
.topbar.is-stuck{
  background:rgba(6,11,17,.86);
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
  border-bottom-color:var(--stroke);
}
.topbar__inner{
  max-width:var(--page); margin:0 auto;
  display:flex; align-items:center; gap:16px;
  padding:11px clamp(20px,3vw,28px);
}

.brand{ display:flex; align-items:center; gap:10px; flex:0 0 auto; }
.brand__mark{
  width:32px; height:32px; color:var(--accent); flex:0 0 auto;
  filter:drop-shadow(0 0 10px var(--accent-glow));
}
.brand__mark svg{ width:100%; height:100%; }
.brand__text{ display:flex; flex-direction:column; line-height:1.05; }
.brand__text b{ font-size:16px; font-weight:600; letter-spacing:.02em; }
.brand__text i{
  font-style:normal; font-size:10.5px; color:var(--ink-3);
  letter-spacing:.16em; text-transform:uppercase; margin-top:2px;
}

/* 搜索 */
.search{
  position:relative; flex:1 1 auto; min-width:0;
  display:flex; align-items:center;
  height:40px; border-radius:12px;
  background:rgba(255,255,255,.045);
  border:1px solid var(--stroke-soft);
  transition:background .3s var(--ease), border-color .3s var(--ease), box-shadow .3s var(--ease);
}
.search:focus-within{
  background:rgba(255,255,255,.075);
  border-color:rgba(127,196,232,.42);
  box-shadow:0 0 0 4px rgba(127,196,232,.10);
}
.search__icon{ width:17px; height:17px; margin:0 2px 0 13px; color:var(--ink-3); flex:0 0 auto; }
.search:focus-within .search__icon{ color:var(--accent); }
.search input{
  flex:1 1 auto; min-width:0; height:100%;
  background:none; border:0; outline:none;
  padding:0 10px; font-size:14px; color:var(--ink);
}
.search input::placeholder{ color:var(--ink-4); }
.search input::-webkit-search-cancel-button{ display:none; }
.search__kbd{
  flex:0 0 auto; margin-right:10px; padding:2px 7px;
  font-family:var(--mono); font-size:11px; color:var(--ink-3);
  border:1px solid var(--stroke); border-radius:6px;
  background:rgba(255,255,255,.04);
  transition:opacity .2s;
}
.search:focus-within .search__kbd{ opacity:0; }
.search__clear{
  flex:0 0 auto; width:26px; height:26px; margin-right:6px;
  display:grid; place-items:center; border-radius:8px; color:var(--ink-3);
}
.search__clear svg{ width:15px; height:15px; }
.search__clear:hover{ background:rgba(255,255,255,.09); color:var(--ink); }

.topbar__actions{ display:flex; align-items:center; gap:6px; flex:0 0 auto; }
.iconbtn{
  width:38px; height:38px; flex:0 0 auto;
  display:grid; place-items:center; border-radius:11px;
  color:var(--ink-2);
  border:1px solid transparent;
  transition:background .22s var(--ease), color .22s var(--ease), border-color .22s var(--ease), transform .22s var(--ease);
}
.iconbtn svg{ width:19px; height:19px; }
.iconbtn:hover{ background:rgba(255,255,255,.09); color:var(--ink); border-color:var(--stroke-soft); }
.iconbtn:active{ transform:scale(.94); }
.iconbtn[aria-pressed="true"]{ color:var(--accent); background:rgba(127,196,232,.13); border-color:rgba(127,196,232,.3); }
.iconbtn.is-on svg path{ fill:var(--accent); }

/* ---------- 6. Hero ---------- */
main{ width:100%; }

/* ==========================================================================
   Hero
   --------------------------------------------------------------------------
   原来这里是「徽章 + 76px 渐变标题 + 三行说明 + 七个快捷胶囊」，
   上下内边距最大 116px —— 首屏七成高度被吃掉，73 个工具一个都露不出来，
   而快捷胶囊和下面的工具列表内容完全重复。
   压成「一行标题 + 一行说明」，让工具网格直接出现在首屏。
   ========================================================================== */
.hero{
  max-width:var(--page); margin:0 auto;
  padding:clamp(26px,4vw,46px) clamp(20px,3vw,28px) clamp(16px,2vw,22px);
}
.hero__title{
  font-size:clamp(22px,3vw,31px);
  font-weight:600;
  line-height:1.3;
  letter-spacing:-.02em;
  color:var(--ink);
  margin:0 0 9px;
  max-width:24em;
  animation:riseIn .6s var(--ease-out) both;
}
.hero__sub{
  max-width:56em; font-size:14px; line-height:1.75; color:var(--ink-3);
  margin:0;
  animation:riseIn .6s .06s var(--ease-out) both;
}
.hero__sub b{ color:var(--ink-2); font-weight:600; font-variant-numeric:tabular-nums; }

@keyframes riseIn{
  from{ opacity:0; transform:translateY(10px); }
  to{ opacity:1; transform:translateY(0); }
}

/* ---------- 7. 目录区 ---------- */
.catalog{
  max-width:var(--page); margin:0 auto;
  padding:clamp(22px,4vw,40px) clamp(20px,3vw,28px) clamp(60px,9vw,110px);
}
.catalog__head{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:18px; flex-wrap:wrap; margin-bottom:20px;
}
.section-title{
  font-size:clamp(20px,2.6vw,26px); font-weight:300; letter-spacing:-.02em;
}
.catalog__meta{ font-size:12.5px; color:var(--ink-2); letter-spacing:.04em; font-variant-numeric:tabular-nums; }

/* 分类胶囊 */
.cats{
  display:flex; gap:8px; flex-wrap:wrap;
  margin-bottom:26px; padding-bottom:2px;
}
.cat{
  display:inline-flex; align-items:center; gap:8px;
  padding:9px 16px; border-radius:11px;
  font-size:13.5px; color:var(--ink-2);
  border:1px solid var(--stroke);
  background:rgba(255,255,255,.055);
  transition:all .22s var(--ease);
  white-space:nowrap;
}
.cat i{
  font-style:normal; font-size:11px; color:var(--ink-4);
  font-variant-numeric:tabular-nums;
  transition:color .22s var(--ease);
}
.cat svg{ width:15px; height:15px; flex:0 0 auto; }
.cat:hover{ color:var(--ink); background:rgba(255,255,255,.08); border-color:var(--stroke); }
.cat[aria-current="true"]{
  color:#04202e; font-weight:600;
  background:linear-gradient(135deg, var(--accent), var(--accent-2));
  border-color:transparent;
  box-shadow:0 4px 14px rgba(95,208,232,.20);
}
.cat[aria-current="true"] i{ color:rgba(4,32,46,.6); }

/* ---------- 8. 工具卡片网格 ---------- */
.grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(268px, 1fr));
  gap:var(--gap);
}

/* ==========================================================================
   分组（改法 B）
   --------------------------------------------------------------------------
   73 张卡片四列平铺时，每张的元素量完全一样 → 没有视觉落点。
   现在按分类分组，每组默认露 6 个，其余折叠。
   折叠用 display:none 而不是移除 DOM，展开时不用重渲染，切换才有"丝滑"感。
   ========================================================================== */
.section{ margin-bottom:34px; }
.section:last-child{ margin-bottom:0; }

.section__head{
  display:flex; align-items:center; gap:10px;
  margin-bottom:13px;
}
.section__icon{
  width:24px; height:24px; flex:0 0 auto;
  display:grid; place-items:center;
  color:var(--accent);
  background:rgba(127,196,232,.10);
  border-radius:7px;
}
.section__icon svg{ width:14px; height:14px; stroke-width:1.9; }
.section__title{
  font-size:16px; font-weight:600; letter-spacing:-.01em;
  color:var(--ink); margin:0;
}
.section__count{
  font-size:12px; color:var(--ink-4);
  font-variant-numeric:tabular-nums;
}
/* 一条淡淡的横向分隔线，把标题和右侧按钮连起来 */
.section__line{
  flex:1 1 auto; height:1px;
  background:linear-gradient(90deg, var(--stroke), transparent 78%);
}
.section__more{
  display:inline-flex; align-items:center; gap:5px;
  font:inherit; font-size:12.5px; color:var(--ink-3);
  background:none; border:0; padding:4px 6px; border-radius:7px;
  cursor:pointer; white-space:nowrap;
  transition:color .2s var(--ease), background .2s var(--ease);
}
.section__more:hover{ color:var(--accent); background:rgba(127,196,232,.09); }
.section__more svg{
  width:13px; height:13px;
  transition:transform .28s var(--ease-out);
}
.section__more.is-open svg{ transform:rotate(180deg); }

.section__grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(268px, 1fr));
  gap:var(--gap);
}

/* ★ 折叠项用 display:none；展开时配合 keyframes 让它"长出来"。
   prefers-reduced-motion 下动画会自动关掉（文件顶部已有全局规则）。 */
.card.is-folded{ display:none; }
.section.is-open .card{
  animation:foldIn .34s var(--ease-out) both;
}
@keyframes foldIn{
  from{ opacity:0; transform:translateY(-6px); }
  to{ opacity:1; transform:none; }
}
/* 折叠态下只对前 6 张做轻微的错开入场，避免一次性几十张一起动 */
.section:not(.is-open) .card:nth-child(-n+6){ animation:foldIn .3s var(--ease-out) both; }
.section:not(.is-open) .card:nth-child(2){ animation-delay:.03s; }
.section:not(.is-open) .card:nth-child(3){ animation-delay:.06s; }
.section:not(.is-open) .card:nth-child(4){ animation-delay:.09s; }
.section:not(.is-open) .card:nth-child(5){ animation-delay:.12s; }
.section:not(.is-open) .card:nth-child(6){ animation-delay:.15s; }
/* 卡片：去掉外发光和重模糊，改成 1px 描边 + 悬停变色。
   原来每张卡片都带 backdrop-blur(22px) + 34px 扩散的大阴影 +
   一层渐变描边伪元素 —— 73 张卡片同时做高斯模糊，在低端机上很吃性能，
   而视觉上又因为「每张都一样」而失去重点（AI 页面的典型特征）。 */
.card{
  position:relative; display:flex; flex-direction:column;
  padding:17px 18px 15px; min-height:auto;
  border-radius:8px;
  cursor:pointer;
  background:rgba(19,29,42,.52);
  border:1px solid var(--stroke-soft);
  overflow:hidden;
  text-align:left; width:100%;
  transition:background .2s var(--ease), border-color .2s var(--ease), transform .2s var(--ease-out);
  animation:cardIn .4s var(--ease-out) both;
}
/* 原来卡片有两层伪元素：一层渐变棱边（::before）+ 一层 hover 时沿边扫过的光带（::after）。
   两个都去掉 —— 渐变描边和扫描光效是纯装饰，73 张卡片同时有就是"堆料"。
   现在靠 1px 描边 + 悬停时描边变亮来表达状态，够了。 */
.card::before,
.card::after{ display:none; }

.card:hover{
  background:rgba(26,39,55,.72);
  border-color:rgba(127,196,232,.34);
  transform:translateY(-1px);
}
.card:hover::after{ display:none; }
.card:active{ transform:translateY(0) scale(.995); }

/* 原来 73 张卡片每张都有 0.6s 的入场动画、还按序号错开最多 612ms 才开始。
   一屏工具要花一秒多才「长出来」，既拖慢感知速度也是典型的堆料。
   直接不做动画。 */
@keyframes cardIn{ from{ opacity:1; } to{ opacity:1; } }

.card__top{ display:flex; align-items:flex-start; gap:13px; margin-bottom:14px; }
.card__icon{
  flex:0 0 auto; width:40px; height:40px; border-radius:12px;
  display:grid; place-items:center;
  color:var(--accent);
  background:linear-gradient(150deg, rgba(127,196,232,.16), rgba(127,196,232,.05));
  border:1px solid rgba(127,196,232,.20);
  transition:transform .34s var(--ease-out), box-shadow .34s var(--ease);
}
.card__icon svg{ width:20px; height:20px; }
.card:hover .card__icon{
  transform:scale(1.06) rotate(-3deg);
  box-shadow:0 6px 18px rgba(127,196,232,.20);
}
.card__head{ min-width:0; flex:1 1 auto; padding-top:1px; }
.card__name{
  font-size:15px; font-weight:500; letter-spacing:-.005em; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.card__cat{
  display:inline-block; margin-top:5px;
  font-size:11px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--ink-3);
}
.card__desc{
  font-size:12.5px; line-height:1.7; color:var(--ink-2);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden; flex:1 1 auto;
}
.card__foot{
  display:flex; align-items:center; justify-content:space-between;
  gap:10px; margin-top:14px;
}
.card__tags{ display:flex; gap:6px; flex-wrap:wrap; min-width:0; }
.card__tag{
  font-size:11px; padding:3px 8px; border-radius:6px;
  color:var(--ink-2); background:rgba(255,255,255,.06);
  border:1px solid var(--stroke-soft);
  white-space:nowrap;
}
.card__go{
  flex:0 0 auto; width:26px; height:26px; border-radius:50%;
  display:grid; place-items:center; color:var(--ink-4);
  border:1px solid var(--stroke-soft);
  transition:all .28s var(--ease);
}
.card__go svg{ width:14px; height:14px; }
.card:hover .card__go{
  color:#04202e; background:var(--accent); border-color:var(--accent);
  transform:translateX(3px);
}

.card__fav{
  position:absolute; top:12px; right:12px; z-index:3;
  width:28px; height:28px; border-radius:9px;
  display:grid; place-items:center; color:var(--ink-4);
  opacity:0; transition:all .24s var(--ease);
}
.card__fav svg{ width:15px; height:15px; }
.card:hover .card__fav{ opacity:1; }
.card__fav:hover{ background:rgba(255,255,255,.1); color:var(--accent); }
.card__fav.is-on{ opacity:1; color:var(--accent); }
.card__fav.is-on svg path{ fill:currentColor; }

/* 收藏/最近使用 标记行 */
.rails:not([hidden]){ margin-bottom:30px; }
.rail + .rail{ margin-top:22px; }
.rail__head{
  display:flex; align-items:center; gap:9px; margin-bottom:13px;
  font-size:12px; letter-spacing:.13em; text-transform:uppercase; color:var(--ink-3);
}
.rail__head svg{ width:14px; height:14px; color:var(--accent); }
.rail__row{ display:flex; gap:9px; flex-wrap:wrap; }
.railchip{
  display:inline-flex; align-items:center; gap:9px;
  padding:8px 14px; border-radius:11px; font-size:13px; color:var(--ink-2);
  background:var(--glass-card); border:1px solid var(--stroke-soft);
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
  transition:all .24s var(--ease);
}
.railchip svg{ width:15px; height:15px; color:var(--accent); flex:0 0 auto; }
.railchip:hover{ color:var(--ink); background:var(--glass-hi); transform:translateY(-2px); border-color:rgba(127,196,232,.3); }

.empty{
  display:flex; align-items:center; justify-content:center; gap:14px;
  padding:70px 20px; color:var(--ink-3); font-size:14px;
}
.linkbtn{
  color:var(--accent); font-size:13px; padding:5px 12px; border-radius:9px;
  border:1px solid rgba(127,196,232,.28); background:rgba(127,196,232,.08);
  transition:all .2s var(--ease);
}
.linkbtn:hover{ background:rgba(127,196,232,.16); }

/* ---------- 9. 工作区 ---------- */
.ws{ position:fixed; inset:0; z-index:100; display:flex; align-items:center; justify-content:center; }
.ws[hidden]{ display:none; }
.ws__scrim{
  position:absolute; inset:0;
  background:rgba(4,9,15,.36);
  -webkit-backdrop-filter:blur(16px) saturate(120%); backdrop-filter:blur(16px) saturate(120%);
  animation:fadeIn .3s var(--ease) both;
}
@keyframes fadeIn{ from{ opacity:0; } to{ opacity:1; } }

.ws__panel{
  position:relative; z-index:1;
  width:min(1080px, calc(100vw - 40px));
  height:min(860px, calc(100vh - 56px));
  display:flex; flex-direction:column;
  background:var(--glass-panel);
  -webkit-backdrop-filter:blur(var(--blur-lg)) saturate(var(--sat)) brightness(1.04);
  backdrop-filter:blur(var(--blur-lg)) saturate(var(--sat)) brightness(1.04);
  border-radius:var(--r-xl);
  overflow:hidden;
  animation:wsIn .42s var(--ease-out) both;
}
@keyframes wsIn{
  from{ opacity:0; transform:translateY(22px) scale(.985); }
  to{ opacity:1; transform:translateY(0) scale(1); }
}
.ws__head{
  display:flex; align-items:center; gap:14px;
  padding:16px 18px; flex:0 0 auto;
  border-bottom:1px solid var(--stroke-soft);
  background:rgba(255,255,255,.02);
}
.ws__back{
  display:inline-flex; align-items:center; gap:5px;
  padding:8px 13px 8px 9px; border-radius:11px;
  font-size:13px; color:var(--ink-2);
  border:1px solid var(--stroke-soft);
  background:rgba(255,255,255,.04);
  flex:0 0 auto;
  transition:all .22s var(--ease);
}
.ws__back svg{ width:16px; height:16px; }
.ws__back:hover{ color:var(--ink); background:rgba(255,255,255,.1); border-color:var(--stroke); }
.ws__titlewrap{ flex:1 1 auto; min-width:0; }
.ws__title{ font-size:17px; font-weight:500; letter-spacing:-.01em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ws__desc{
  font-size:12.5px; color:var(--ink-2); margin-top:2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.ws__tools{ display:flex; gap:4px; flex:0 0 auto; }
.ws__body{
  flex:1 1 auto; min-height:0; overflow-y:auto; overflow-x:hidden;
  padding:22px clamp(16px,2.4vw,26px) 26px;
  scrollbar-gutter:stable;
}

/* ---------- 10. 工具 UI 原子 ---------- */
.t{ display:flex; flex-direction:column; gap:18px; }

.pane{ display:grid; gap:16px; }
.pane--2{ grid-template-columns:1fr 1fr; }
@media (max-width:760px){ .pane--2{ grid-template-columns:1fr; } }

.box{
  display:flex; flex-direction:column; gap:9px;
  padding:16px; border-radius:var(--r);
  background:rgba(255,255,255,.032);
  border:1px solid var(--stroke-soft);
}
.box--flat{ background:none; padding:0; border:0; }

.lbl{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  font-size:11.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3);
}
.lbl b{ font-weight:600; color:var(--ink-2); }
.lbl__right{ display:flex; align-items:center; gap:8px; text-transform:none; letter-spacing:0; }

.hint{ font-size:12.5px; line-height:1.75; color:var(--ink-3); }
.hint b{ color:var(--ink-3); font-weight:500; }

.fld{
  width:100%; padding:11px 13px;
  background:rgba(4,9,15,.42);
  border:1px solid var(--stroke);
  border-radius:var(--r-sm);
  font-size:13.5px; color:var(--ink);
  outline:none;
  transition:border-color .22s var(--ease), box-shadow .22s var(--ease), background .22s var(--ease);
}
.fld::placeholder{ color:var(--ink-ph); }
.fld:focus{ border-color:rgba(127,196,232,.5); box-shadow:0 0 0 3px rgba(127,196,232,.11); background:rgba(4,9,15,.55); }
.fld:disabled{ opacity:.5; cursor:not-allowed; }
.fld[readonly]{ color:var(--ink-2); }

textarea.fld{
  resize:vertical; min-height:120px; line-height:1.7;
  font-family:var(--mono); font-size:12.5px;
  tab-size:2;
}
/* 并排两栏里禁用拖拽把手：单侧变高会破坏左右对齐 */
.pane--2 textarea.fld{ resize:none; }
textarea.fld.is-plain{ font-family:var(--sans); font-size:13.5px; }

select.fld{
  appearance:none; cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239fb3c6' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 10px center; background-size:15px;
  padding-right:34px;
}
select.fld option{ background:#0d1520; color:var(--ink); }

.row{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.row--tight{ gap:7px; }
.row--end{ justify-content:flex-end; }
.row--between{ justify-content:space-between; }
.spacer{ flex:1 1 auto; }

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  padding:9px 16px; border-radius:11px;
  font-size:13px; font-weight:500; white-space:nowrap;
  color:var(--ink-2);
  background:rgba(255,255,255,.055);
  border:1px solid var(--stroke-soft);
  transition:all .22s var(--ease);
}
.btn svg{ width:15px; height:15px; flex:0 0 auto; }
.btn:hover{ color:var(--ink); background:rgba(255,255,255,.11); border-color:var(--stroke); transform:translateY(-1px); }
.btn:active{ transform:translateY(0) scale(.98); }
.btn[disabled]{ opacity:.42; cursor:not-allowed; transform:none; }
.btn--primary{
  color:#04202e; font-weight:650;
  background:linear-gradient(135deg, var(--accent), var(--accent-2));
  border-color:transparent;
  box-shadow:0 6px 20px rgba(95,208,232,.22);
}
.btn--primary:hover{ color:#04202e; box-shadow:0 10px 28px rgba(95,208,232,.34); filter:brightness(1.06); }
.btn--ghost{ background:none; border-color:transparent; color:var(--ink-2); }
.btn--ghost:hover{ background:rgba(255,255,255,.07); color:var(--ink); }
.btn--sm{ padding:6px 11px; font-size:12px; border-radius:9px; }
.btn--sm svg{ width:13px; height:13px; }
.btn--block{ width:100%; }

.seg{
  display:inline-flex; padding:3px; gap:2px;
  background:rgba(4,9,15,.42);
  border:1px solid var(--stroke-soft);
  border-radius:12px;
  flex-wrap:wrap;
}
.seg__i{
  padding:7px 14px; border-radius:9px;
  font-size:12.5px; color:var(--ink-3); white-space:nowrap;
  transition:all .2s var(--ease);
}
.seg__i:hover{ color:var(--ink); background:rgba(255,255,255,.06); }
.seg__i[aria-selected="true"]{
  color:var(--ink); font-weight:500;
  background:rgba(127,196,232,.18);
  box-shadow:inset 0 0 0 1px rgba(127,196,232,.30);
}

.sw{ display:inline-flex; align-items:center; gap:9px; font-size:13px; color:var(--ink-2); cursor:pointer; user-select:none; }
.sw input{ position:absolute; opacity:0; pointer-events:none; }
.sw__track{
  width:38px; height:22px; border-radius:99px; flex:0 0 auto;
  background:rgba(255,255,255,.11); border:1px solid var(--stroke-soft);
  position:relative; transition:background .24s var(--ease);
}
.sw__track::after{
  content:""; position:absolute; top:2px; left:2px;
  width:16px; height:16px; border-radius:50%;
  background:var(--ink-2); transition:all .24s var(--ease);
}
.sw input:checked + .sw__track{ background:rgba(127,196,232,.34); border-color:rgba(127,196,232,.4); }
.sw input:checked + .sw__track::after{ left:18px; background:var(--accent); }
.sw input:focus-visible + .sw__track{ box-shadow:0 0 0 3px rgba(127,196,232,.2); }

.drop{
  position:relative;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:9px;
  padding:34px 20px; border-radius:var(--r);
  border:1.5px dashed rgba(255,255,255,.16);
  background:rgba(255,255,255,.022);
  color:var(--ink-3); font-size:13px; text-align:center;
  transition:all .24s var(--ease); cursor:pointer;
}
.drop svg{ width:26px; height:26px; color:var(--ink-4); transition:color .24s var(--ease); }
.drop:hover,.drop.is-over{
  border-color:rgba(127,196,232,.5); background:rgba(127,196,232,.07); color:var(--ink-2);
}
.drop:hover svg,.drop.is-over svg{ color:var(--accent); }
.drop b{ color:var(--ink-2); font-weight:500; }
.drop input[type=file]{ display:none; }

.out{
  min-height:120px; padding:13px 15px;
  background:rgba(4,9,15,.5);
  border:1px solid var(--stroke-soft);
  border-radius:var(--r-sm);
  font-family:var(--mono); font-size:12.5px; line-height:1.75;
  color:var(--ink); white-space:pre-wrap; word-break:break-all;
  overflow:auto; max-height:460px;
}
.out:empty::before{ content:attr(data-ph); color:var(--ink-3); font-family:var(--sans); }
.out--plain{ font-family:var(--sans); font-size:13.5px; white-space:normal; word-break:normal; }

.stats{ display:grid; grid-template-columns:repeat(auto-fit,minmax(104px,1fr)); gap:10px; }
.stat{
  padding:13px 15px; border-radius:var(--r-sm);
  background:rgba(255,255,255,.035);
  border:1px solid var(--stroke-soft);
}
.stat__v{ font-size:21px; font-weight:300; color:var(--ink); font-variant-numeric:tabular-nums; letter-spacing:-.02em; }
.stat__k{ font-size:11px; color:var(--ink-4); letter-spacing:.08em; margin-top:3px; }

.tbl{ width:100%; border-collapse:collapse; font-size:13px; }
.tbl th,.tbl td{
  padding:10px 13px; text-align:left;
  border-bottom:1px solid var(--stroke-soft);
  vertical-align:top;
}
.tbl th{
  font-size:11px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--ink-3); font-weight:600; white-space:nowrap;
}
/* 斑马纹 + 悬停：大表格里更容易横向追踪 */
.tbl tbody tr:nth-child(even){ background:rgba(255,255,255,.016); }
.tbl tbody tr:hover{ background:rgba(127,196,232,.075); }
.tbl tbody tr:hover td{ border-bottom-color:rgba(127,196,232,.18); }
.tbl code{ font-family:var(--mono); font-size:12px; color:var(--accent); }
.tblwrap{ overflow:auto; max-height:520px; border-radius:var(--r-sm); border:1px solid var(--stroke-soft); }
.tblwrap .tbl{ min-width:100%; }
.tblwrap .tbl th{ position:sticky; top:0; background:#0d1622; z-index:1; }

.mark{ background:rgba(232,196,127,.22); border-radius:3px; padding:0 2px; color:#f3dcae; }
.mark--hit{ background:rgba(110,231,192,.2); color:#a9f2da; }
.mark--del{ background:rgba(232,138,154,.22); color:#f3b6c1; text-decoration:line-through; }
.mark--ins{ background:rgba(110,231,192,.18); color:#a9f2da; }

.pill{
  display:inline-flex; align-items:center; gap:6px;
  padding:3px 10px; border-radius:99px; font-size:11.5px;
  background:rgba(255,255,255,.06); border:1px solid var(--stroke-soft);
  color:var(--ink-3);
}
.pill--ok{ color:var(--ok); background:rgba(110,231,192,.12); border-color:rgba(110,231,192,.26); }
.pill--err{ color:var(--err); background:rgba(232,138,154,.12); border-color:rgba(232,138,154,.26); }
.pill--warn{ color:var(--warn); background:rgba(232,196,127,.12); border-color:rgba(232,196,127,.26); }

.kv{ display:grid; grid-template-columns:auto 1fr; gap:8px 18px; font-size:13px; }
.kv dt{ color:var(--ink-4); white-space:nowrap; }
.kv dd{ margin:0; color:var(--ink); font-family:var(--mono); font-size:12.5px; word-break:break-all; }

.swatch{
  width:100%; aspect-ratio:1.4; border-radius:var(--r-sm);
  border:1px solid var(--stroke); cursor:pointer;
  transition:transform .2s var(--ease);
}
.swatch:hover{ transform:scale(1.04); }

/* ---------- 11. 提示条 ---------- */
.toasts{
  position:fixed; left:50%; bottom:28px; transform:translateX(-50%);
  z-index:300; display:flex; flex-direction:column; gap:9px; align-items:center;
  pointer-events:none; width:max-content; max-width:calc(100vw - 32px);
}
.toast{
  display:flex; align-items:center; gap:10px;
  padding:11px 18px; border-radius:13px;
  font-size:13px; color:var(--ink);
  background:rgba(14,23,34,.9);
  -webkit-backdrop-filter:blur(20px) saturate(150%); backdrop-filter:blur(20px) saturate(150%);
  border:1px solid var(--stroke);
  box-shadow:var(--shadow-lg);
  animation:toastIn .34s var(--ease-out) both;
}
.toast svg{ width:16px; height:16px; flex:0 0 auto; color:var(--accent); }
.toast--ok svg{ color:var(--ok); }
.toast--err svg{ color:var(--err); }
.toast.is-out{ animation:toastOut .28s var(--ease) both; }
@keyframes toastIn{ from{ opacity:0; transform:translateY(14px) scale(.96); } to{ opacity:1; transform:none; } }
@keyframes toastOut{ to{ opacity:0; transform:translateY(8px) scale(.97); } }

/* ---------- 12. 页脚 ---------- */
.foot{
  max-width:var(--page); margin:0 auto;
  padding:0 clamp(20px,3vw,28px) 46px;
}
.foot__inner{
  display:grid; grid-template-columns:1.3fr 1fr 1fr 1fr; gap:26px;
  padding:26px 28px; border-radius:var(--r-lg);
}
.foot__col h3{
  font-size:12px; letter-spacing:.13em; text-transform:uppercase;
  color:var(--ink-4); margin-bottom:9px; font-weight:500;
}
.foot__col p{ font-size:12.5px; line-height:1.85; color:var(--ink-3); }
.foot__brand{ display:flex; align-items:center; gap:9px; margin-bottom:9px; }
.foot__brand svg{ width:22px; height:22px; color:var(--accent); }
.foot__brand b{ font-size:15px; font-weight:600; letter-spacing:.02em; }
.foot__col kbd{
  font-family:var(--mono); font-size:11px; padding:1px 6px;
  border:1px solid var(--stroke); border-radius:5px;
  background:rgba(255,255,255,.04); color:var(--ink-2);
}
.foot__legal{
  display:flex; align-items:center; justify-content:center; gap:9px;
  margin-top:20px; font-size:12px; color:var(--ink-4); letter-spacing:.04em;
}
.foot__dot{ opacity:.5; }

/* ---------- 13. 响应式 ---------- */
@media (max-width:1000px){
  .foot__inner{ grid-template-columns:1fr 1fr; }
}
@media (max-width:820px){
  :root{ --blur:16px; --blur-lg:24px; --gap:14px; }
  .brand__text i{ display:none; }
  .topbar__actions #btnHome{ display:none; }
  .grid{ grid-template-columns:repeat(auto-fill, minmax(232px, 1fr)); }
  .ws__panel{ width:100vw; height:100dvh; max-height:100dvh; border-radius:0; }
  .ws{ align-items:stretch; }
  .ws__body{ padding:18px 15px 30px; }
}
@media (max-width:560px){
  .hero{ padding-top:40px; }
  .hero__title{ font-size:clamp(30px,9vw,42px); }
  .grid{ grid-template-columns:1fr; }
  .card{ min-height:auto; }
  .foot__inner{ grid-template-columns:1fr; gap:20px; padding:22px 20px; }
  .topbar__inner{ padding:8px 10px; gap:10px; }
  .search__kbd{ display:none; }
  .ws__back span{ display:none; }
  .ws__back{ padding:8px; }
}
@media (hover:none){
  .card__fav{ opacity:1; }
}

/* ---------- 15. 视频链接解析工具 ---------- */
.vp-notice{
  display:flex; gap:10px; align-items:flex-start;
  padding:12px 15px; border-radius:var(--r-sm);
  background:rgba(255,255,255,.03);
  border:1px solid var(--stroke-soft);
  font-size:12.5px; line-height:1.8; color:var(--ink-3);
}
.vp-notice svg{ width:16px; height:16px; flex:0 0 auto; color:var(--warn); margin-top:3px; opacity:.85; }
.vp-notice b{ color:var(--ink-2); font-weight:600; }
/* 数据格收紧，避免在宽卡片里横向散开 */
.vp-meta .stats{ grid-template-columns:repeat(auto-fill, minmax(92px, 1fr)); max-width:560px; }
.vp-meta .stat{ padding:10px 12px; }
.vp-meta .stat__v{ font-size:18px; }

.vp-legal{
  display:flex; gap:10px; align-items:flex-start;
  padding-top:4px;
  font-size:13px; line-height:1.8; color:var(--ink-2);
}
.vp-legal svg{ width:16px; height:16px; flex:0 0 auto; margin-top:3px; color:var(--ink-3); }

.vp-plat{
  font-size:11.5px; padding:3px 10px; border-radius:99px;
  color:var(--ink-2); background:rgba(127,196,232,.10);
  border:1px solid rgba(127,196,232,.22);
}

/* 高级：使用自己的登录态 */
.vp-adv{
  border:1px solid var(--stroke-soft); border-radius:var(--r-sm);
  background:rgba(255,255,255,.028); overflow:hidden;
}
.vp-adv > summary{
  display:flex; align-items:center; gap:9px;
  padding:13px 16px; cursor:pointer; list-style:none;
  font-size:13px; color:var(--ink-2);
}
.vp-adv > summary::-webkit-details-marker{ display:none; }
.vp-adv > summary:hover{ background:rgba(255,255,255,.045); color:var(--ink); }
.vp-adv > summary svg{ width:16px; height:16px; flex:0 0 auto; color:var(--accent); }
.vp-adv[open] > summary{ border-bottom:1px solid var(--stroke-soft); }
.vp-adv__body{ display:flex; flex-direction:column; gap:12px; padding:15px 16px; }
.vp-adv__how{
  display:flex; gap:8px; flex-wrap:wrap;
  font-size:12.5px; line-height:1.8; color:var(--ink-3);
}
.vp-adv__how b{ color:var(--ink-2); font-weight:600; }

.vp-head{
  display:flex; gap:18px; align-items:flex-start;
  padding:18px; border-radius:var(--r);
  background:rgba(255,255,255,.032);
  border:1px solid var(--stroke-soft);
}
.vp-cover{
  width:132px; flex:0 0 auto; aspect-ratio:3/4; object-fit:cover;
  border-radius:var(--r-sm); border:1px solid var(--stroke);
  background:rgba(0,0,0,.3);
}
.vp-meta{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:10px; }
.vp-title{
  font-size:16px; font-weight:500; line-height:1.6; color:var(--ink);
  word-break:break-word;
}
.vp-author{ display:flex; align-items:center; gap:9px; font-size:13px; color:var(--ink-2); }
.vp-avatar{ width:26px; height:26px; border-radius:50%; object-fit:cover; border:1px solid var(--stroke); }
.vp-time{ color:var(--ink-4); font-size:12px; }

.vp-video{
  /* 竖屏视频不能强行拉满宽度，否则播放器会变成一大片黑边 */
  width:auto; max-width:100%; max-height:min(64vh, 540px);
  margin:0 auto; border-radius:var(--r-sm);
  background:#000; border:1px solid var(--stroke); display:block;
}

.vp-imgs{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(148px, 1fr));
  gap:10px;
}
.vp-img{
  position:relative; border-radius:var(--r-sm); overflow:hidden;
  border:1px solid var(--stroke); background:rgba(0,0,0,.3);
}
.vp-img img{ width:100%; aspect-ratio:3/4; object-fit:cover; display:block; }
.vp-live{
  position:absolute; top:7px; left:7px; z-index:2;
  font-size:10px; padding:2px 7px; border-radius:6px;
  color:#04202e; background:var(--accent-2); font-weight:600;
}
.vp-img__ops{
  position:absolute; left:0; right:0; bottom:0; z-index:2;
  display:flex; gap:6px; padding:8px;
  background:linear-gradient(to top, rgba(4,9,15,.92), rgba(4,9,15,0));
  opacity:0; transition:opacity .22s var(--ease);
}
.vp-img:hover .vp-img__ops{ opacity:1; }
@media (hover:none){ .vp-img__ops{ opacity:1; } }

.vp-caption{
  max-height:220px; overflow:auto; line-height:1.9;
  white-space:pre-wrap; word-break:break-word;
}

@media (max-width:560px){
  .vp-head{ flex-direction:column; gap:14px; }
  .vp-cover{ width:100%; aspect-ratio:16/9; }
  .vp-imgs{ grid-template-columns:repeat(2, 1fr); }
}

/* ---------- 16. 沉浸模式 / 降噪 ---------- */
body.immersed .glass,
body.immersed .card{
  background:rgba(11,18,27,.72);
}

/* 打印：工具结果可直接打印或存 PDF */
@media print{
  .bg,.topbar,.foot,.ws__head,.toasts{ display:none !important; }
  body{ background:#fff; color:#111; }
  .ws{ position:static; }
  .ws__panel{ box-shadow:none; border:0; background:#fff; height:auto; width:100%; }
  .ws__body{ overflow:visible; }
  .fld,.out{ background:#fff; color:#111; border-color:#ccc; }
}

/* ==========================================================================
   工具页（/tools/<id>）
   --------------------------------------------------------------------------
   这些页面由 index.php 服务端渲染，目的是让每个工具都有可被搜索引擎索引的
   独立页面：独立 title / description / canonical / JSON-LD / h1 / 正文。
   工具本体由 JS 内联挂载到 .toolpage__stage，服务端渲染的说明文字留在下面，
   这样爬虫和用户看到的是同一份内容，不存在"内容藏在遮罩后"的问题。
   ========================================================================== */

.toolpage{
  max-width:1080px; margin:0 auto; padding:28px 22px 60px;
}

/* ---- 面包屑 ---- */
.toolpage__crumb{
  display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  font-size:13.5px; color:var(--ink-3); margin-bottom:18px;
}
.toolpage__crumb a{ color:var(--ink-3); text-decoration:none; transition:color .18s; }
.toolpage__crumb a:hover{ color:var(--accent); }
.toolpage__crumb span[aria-current]{ color:var(--ink-2); }

/* ---- 标题区 ---- */
.toolpage__head{ margin-bottom:22px; }
.toolpage__title{
  font-size:31px; font-weight:650; letter-spacing:-.02em; line-height:1.25;
  margin:0 0 10px; color:var(--ink);
}
.toolpage__desc{
  font-size:15.5px; line-height:1.7; color:var(--ink-2); margin:0; max-width:62ch;
}

/* ---- 工具本体 ---- */
/* ★ 这里刻意**不加**卡片样式（背景/描边/内边距）。
   工具自己 render() 出来的就是一张张玻璃卡片，外面再套一层深色面板
   会形成"黑上黑"的嵌套，视觉上像没做完 —— 视觉评审第一眼就指出了这点。
   让工具直接落在页面背景上。 */
.toolpage__stage{
  margin:24px 0 36px;
}
.toolpage__stage > .t{ padding:0; }

/* ---- 说明正文（给爬虫和用户读的） ---- */
.toolpage__doc h2{
  font-size:17px; font-weight:600; color:var(--ink);
  margin:30px 0 10px; letter-spacing:-.01em;
}
.toolpage__doc h2:first-child{ margin-top:0; }
.toolpage__doc p{
  font-size:14.5px; line-height:1.85; color:var(--ink-2);
  margin:0 0 12px; max-width:70ch;
}
.toolpage__doc b{ color:var(--ink); font-weight:600; }
.toolpage__doc ul{
  margin:0 0 12px; padding-left:20px; color:var(--ink-2);
  font-size:14.5px; line-height:1.9;
}
.toolpage__doc li{ margin-bottom:3px; }

/* ---- 关键词 ---- */
.toolpage__kw{ display:flex; flex-wrap:wrap; gap:8px; margin:0; }
.toolpage__kw span{
  font-size:12.5px; padding:4px 11px; border-radius:99px;
  background:rgba(127,196,232,.10); color:var(--accent);
  border:1px solid rgba(127,196,232,.18);
}

/* ---- 相关工具 ---- */
.toolpage__related{ margin-top:40px; }
.toolpage__related h2{
  font-size:17px; font-weight:600; color:var(--ink); margin:0 0 14px;
}
.toolpage__related ul{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr)); gap:10px;
}
.toolpage__related a{
  display:block; padding:14px 16px; border-radius:var(--r-sm);
  background:var(--glass-card); border:1px solid var(--stroke-soft);
  text-decoration:none; transition:transform .2s var(--ease-out), border-color .2s, box-shadow .2s;
}
.toolpage__related a:hover{
  transform:translateY(-2px); border-color:var(--stroke-hi);
  box-shadow:0 8px 24px rgba(0,0,0,.38);
}
.toolpage__related b{
  display:block; font-size:14.5px; font-weight:600; color:var(--ink); margin-bottom:4px;
}
.toolpage__related span{
  display:block; font-size:12.5px; line-height:1.6; color:var(--ink-3);
}

@media (max-width:640px){
  .toolpage{ padding:20px 15px 44px; }
  .toolpage__title{ font-size:24px; }
  .toolpage__stage{ padding:16px; margin:20px 0 26px; }
  .toolpage__related ul{ grid-template-columns:1fr; }
}

/* ==========================================================================
   ★ 卡片改成 <a> 之后的必要修正
   原来 .card 是 div，现在为了 SEO 换成了真链接，必须去掉链接默认样式，
   否则 73 张卡片会全部变成带下划线的蓝字。
   ========================================================================== */
a.card{ text-decoration:none; color:inherit; }
a.card:hover{ text-decoration:none; }
a.card:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }

/* 侧栏/顶部的快捷链接同理 */
a.railchip{ text-decoration:none; color:inherit; }
a.railchip:hover{ text-decoration:none; }

/* ==========================================================================
   顺滑度与图标打磨
   --------------------------------------------------------------------------
   目标：切换分类、展开分组、悬停卡片时都不"跳"，而是有连续的过渡。
   注意分寸 —— 只给会变化的东西加过渡，不要全站 * { transition:all }，
   那是低端机上卡顿的主因。
   ========================================================================== */

/* 1. 锚点跳转平滑（只影响点击分类锚点/返回顶部这类场景） */
html{ scroll-behavior:smooth; }

/* 2. 分类标签：选中态用背景色平滑过渡，而不是瞬间变色 */
.cat{
  transition:color .18s var(--ease), background .18s var(--ease),
             border-color .18s var(--ease), transform .14s var(--ease-out);
}
.cat:active{ transform:scale(.97); }

/* 3. 工具网格切换分类时整体淡入，避免"啪"地一下换掉 */
.grid{ animation:gridFade .26s var(--ease-out); }
@keyframes gridFade{ from{ opacity:.35; } to{ opacity:1; } }

/* 4. 卡片图标：收一档、去掉旋转（悬停时莫名旋转是廉价感的来源之一）
     改成"底色变亮 + 图标微微上浮"，更克制也更稳。 */
.card__icon{
  width:38px; height:38px; border-radius:10px;
  background:rgba(127,196,232,.09);
  border:1px solid rgba(127,196,232,.16);
  transition:background .22s var(--ease), border-color .22s var(--ease),
             transform .22s var(--ease-out), color .22s var(--ease);
}
.card__icon svg{ width:19px; height:19px; stroke-width:1.8; }
.card:hover .card__icon{
  transform:translateY(-1px);
  background:rgba(127,196,232,.15);
  border-color:rgba(127,196,232,.30);
  box-shadow:none;
}

/* 5. 卡片本身的过渡收短一点：200ms 左右最"跟手"，
     超过 300ms 会有迟滞感（原来 .34s） */
.card{
  transition:background .18s var(--ease), border-color .18s var(--ease),
             transform .18s var(--ease-out);
}

/* 6. 键盘焦点要看得见 —— 全站用同一个焦点样式，不要各处自己发挥 */
a:focus-visible, button:focus-visible, input:focus-visible,
textarea:focus-visible, select:focus-visible, [tabindex]:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:2px;
  border-radius:8px;
}

/* 7. 滚动条：深色底上默认亮色滚动条很刺眼 */
*{ scrollbar-width:thin; scrollbar-color:rgba(127,196,232,.26) transparent; }
*::-webkit-scrollbar{ width:9px; height:9px; }
*::-webkit-scrollbar-track{ background:transparent; }
*::-webkit-scrollbar-thumb{
  background:rgba(127,196,232,.22);
  border-radius:99px;
  border:2px solid transparent;
  background-clip:content-box;
}
*::-webkit-scrollbar-thumb:hover{ background:rgba(127,196,232,.38); background-clip:content-box; }

/* ==========================================================================
   排版修正（依据布局诊断）
   ========================================================================== */

/* ---- 1. 卡片等高：同一行里描述行数不同的卡片，底部原先会参差不齐 ----
   做法是让卡片撑满行高、把描述区设为 flex:1，
   这样标签行会被推到卡片底部，所有卡片的底边对齐。 */
.section__grid > .card,
.grid > .card{
  height:100%;
}
.card__desc{
  flex:1 1 auto;
  /* 描述最多两行，超出省略 —— 避免个别卡片因为多一行而把整行撑高 */
  display:-webkit-box;
  -webkit-line-clamp:2;
  -webkit-box-orient:vertical;
  overflow:hidden;
  /* 中文换行时避免末行只剩一两个字（"孤字"） */
  text-wrap:pretty;
  margin:0 0 12px;
}
.card__foot{ margin-top:auto; }

/* ---- 2. 卡片内部间距节奏 ----
   原来标题和分类标签紧贴在一起、描述到标签又空太多。 */
.card__head{
  display:flex; align-items:baseline; gap:9px;
  min-width:0; flex:1 1 auto; padding-top:1px;
}
.card__name{ min-width:0; }
.card__cat{
  flex:0 0 auto;
  /* 分类名在卡片里是次要信息，压低存在感，别跟标题抢 */
  font-size:11px; color:var(--ink-4);
  padding:1px 7px; border-radius:5px;
  background:rgba(255,255,255,.05);
}
.card__top{ margin-bottom:10px; }

/* ---- 3. 分组标题：去掉图标后重新对齐，并让字号层级正确 ----
   诊断指出「卡片标题比分组标题还抢眼」。分组标题提到 17px，
   卡片标题保持 15px，层级就正过来了。 */
.section__head{ margin-bottom:14px; }
.section__title{
  font-size:17px; font-weight:600; letter-spacing:-.015em;
  color:var(--ink); margin:0;
}
.section__count{
  font-size:12px; color:var(--ink-4);
  font-variant-numeric:tabular-nums;
}
.card__name{ font-size:15px; }

/* ---- 4. 响应式：显式断点，不再只靠 auto-fill 自己算 ----
   auto-fill + minmax 在中间尺寸会给出不好看的列数（比如 5 列每列 220px），
   中文描述会被挤成一行两三个字。这里按断点明确列数。 */
@media (max-width:1280px){
  .section__grid, .grid{ grid-template-columns:repeat(3, minmax(0,1fr)); }
}
@media (max-width:980px){
  .section__grid, .grid{ grid-template-columns:repeat(2, minmax(0,1fr)); }
  .card{ padding:15px 15px 13px; }
}
@media (max-width:620px){
  /* 手机上单列紧凑：去掉描述之外的冗余，一屏能看到更多工具 */
  .section__grid, .grid{ grid-template-columns:1fr; gap:9px; }
  .section{ margin-bottom:26px; }
  .card{ padding:14px 15px; }
  .card__top{ margin-bottom:8px; align-items:center; }
  .card__icon{ width:34px; height:34px; border-radius:9px; }
  .card__icon svg{ width:17px; height:17px; }
  .card__desc{ -webkit-line-clamp:1; margin-bottom:8px; font-size:13px; }
  /* 标签在手机上信息价值最低，隐藏掉换更高的密度 */
  .card__tags{ display:none; }
  .card__go{ opacity:.5; }
  .section__more{ font-size:12px; }
}
@media (max-width:420px){
  .card__cat{ display:none; }
}

/* ==========================================================================
   性能：消除滚动卡顿
   --------------------------------------------------------------------------
   浏览器每帧只有 16.6ms 预算。下面这几项都属于"滚动时每帧都要重新合成"，
   是这类站点卡顿的头号原因，和排版无关。

   排查方法：打开 DevTools → Rendering → Paint flashing，
   滚动时整屏闪绿的就是元凶。
   ========================================================================== */

/* 1. ★ 最大的一项：全屏固定层 + mix-blend-mode。
      overlay 混合要求浏览器把这一层和它下面的所有内容一起重新混合，
      而它是 position:fixed 覆盖整个视口 —— 于是每滚一帧就重混一次。
      改成普通叠加，视觉上几乎看不出差别，代价差一个数量级。 */
.bg__grain{
  mix-blend-mode:normal;
  opacity:.045;
}

/* 2. 背景整层锁进自己的合成层，滚动时不再重绘 */
.bg{
  contain:strict;
  transform:translateZ(0);
  backface-visibility:hidden;
}

/* 3. 吸顶导航去掉 backdrop-filter。
     吸顶元素一旦有背景模糊，滚动时每一帧都要取它后面的像素重新模糊一遍，
     是滚动卡顿的第二大来源。改成接近实色的半透明底，观感差别很小。 */
.topbar.is-stuck{
  background:rgba(6,11,17,.95);
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
}

/* 4. ★ 卡片用 content-visibility 跳过屏幕外渲染。
      73 张卡片全部参与布局和绘制是很浪费的 —— 屏幕上其实只看得到 12 张左右。
      auto 让浏览器跳过视口外的卡片，滚到附近再渲染；
      contain-intrinsic-size 是占位高度，防止滚动条跳动。 */
.card{
  content-visibility:auto;
  contain-intrinsic-size:auto 132px;
}

/* 5. 去掉网格整体淡入动画。
      它每次切换分类都会让 73 个节点重新走一遍 opacity 动画，
      在低端机上就是"点一下卡一下"。 */
.grid, .section__grid{ animation:none; }

/* 6. 分组展开的错开动画也去掉 —— 折叠态下 6 张卡各延迟 30ms 入场，
      看着像"逐张长出来"，实际是 6 次独立合成。直接显示更跟手。 */
.section:not(.is-open) .card,
.section.is-open .card{
  animation:none;
}

/* 7. 卡片悬停只改背景色和描边，不做位移 ——
      位移会触发合成层重建，背景色/描边只触发重绘，便宜得多。 */
.card:hover{ transform:none; }
.card__icon{ transition:background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease); }
.card:hover .card__icon{ transform:none; }

/* 8. 长列表渲染时给浏览器一点提示：卡片之间互不影响 */
.card{ contain:layout style paint; }

/* 9. 尊重系统设置：用户开了"减少动态效果"就全关 */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
}

/* ==========================================================================
   性能第二轮：把背景从 5 层压到 1 层
   --------------------------------------------------------------------------
   第一轮之后实测仍是 43 FPS、P95 帧 69ms、最差 173ms。
   中位帧只有 7ms —— 说明大部分帧很轻，但有周期性的超慢帧，
   这种"双峰"分布通常是某个大面积图层在反复光栅化。

   背景原来是 5 个独立的固定层叠在一起：
     .bg__img（模糊 2px + 缩放 1.045）
     .bg__tint（三段渐变）
     .bg__vignette（两个径向渐变）
     .bg__grain（全屏 SVG 噪点，还带 mix-blend-mode）
     .bg__spot（跟随鼠标的光晕）
   每一层都是 position:fixed 铺满视口 —— 合成器要为它们各维护一个图层。
   现在只留最必要的：底色 + 图片 + 一层压暗。
   ========================================================================== */

/* 图片：去掉 blur 和 scale。
   filter:blur 会让这一层无法直接复用缓存，每次合成都要重新模糊整个视口。
   图片本身已经是暗调模糊感，去掉几乎看不出差别。 */
.bg__img{
  filter:none;
  transform:none;
  will-change:auto;
}

/* 压暗只保留一层线性渐变（原来 tint + vignette 两层共 5 段渐变） */
.bg__tint{
  background:
    linear-gradient(160deg, rgba(6,12,20,.88) 0%, rgba(6,12,20,.70) 42%, rgba(6,12,20,.52) 72%, rgba(6,12,20,.40) 100%);
}

/* 这三层直接不要了 */
.bg__grain,
.bg__vignette,
.bg__spot{ display:none; }

/* 背景层整体固定，含 strict 让浏览器知道它和外界互不影响 */
.bg{ contain:strict; }

/* ★ content-visibility 先撤掉：它虽然能跳过屏外卡片，
   但如果 contain-intrinsic-size 和真实高度差得多，滚动时会不断触发布局修正，
   表现为"滚到某处突然顿一下"。先关掉看帧率变化。 */
.card{
  content-visibility:visible;
  contain-intrinsic-size:none;
  contain:layout style;   /* 保留 layout/style 隔离，这个不会引起重排 */
}
