/* 365Lab 艺术字生成器 - 亮色创意风全站样式 */
:root {
  --bg: #f7f5ff;
  --bg-soft: #fdfbff;
  --card: #ffffff;
  --ink: #2b2350;
  --ink-soft: #6b6390;
  --line: #ece7fb;
  --brand: #7c3aed;
  --brand2: #ec4899;
  --brand3: #f97316;
  --grad: linear-gradient(120deg, #7c3aed, #ec4899 55%, #f97316);
  --grad-soft: linear-gradient(120deg, #f3e8ff, #fce7f3 55%, #ffedd5);
  --shadow: 0 10px 30px rgba(124, 58, 237, 0.10);
  --shadow-lg: 0 20px 50px rgba(124, 58, 237, 0.16);
  --radius: 18px;
  --radius-lg: 26px;
  --nav-h: 64px;
  --toast-bg: var(--ink);
  --toast-fg: #ffffff;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
/* R40：键盘焦点滚动不被 sticky nav 遮挡 */
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; scroll-padding-top: calc(var(--nav-h) + 10px); }
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.7;
  font-size: 16px;
  overflow-x: clip;
}
img { max-width: 100%; display: block; }
a { color: var(--brand-ink); text-decoration: none; } /* R164：前景走 --brand-ink，暗色自动提亮一档 */
a:hover { opacity: .85; }
h1, h2, h3, h4 { line-height: 1.3; font-weight: 800; }
.container { width: min(1180px, 92%); margin: 0 auto; }

/* ---------- 导航 ---------- */
.nav {
  position: sticky; top: 0; z-index: 100;
  height: var(--nav-h);
  background: rgba(253, 251, 255, 0.86);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.nav-inner { display: flex; align-items: center; gap: 18px; height: var(--nav-h); }
.brand { display: flex; align-items: center; gap: 10px; font-weight: 900; font-size: 19px; color: var(--ink); white-space: nowrap; }
.brand-logo {
  width: 34px; height: 34px; border-radius: 11px;
  background: var(--grad);
  display: grid; place-items: center;
  color: #fff; font-size: 17px; font-weight: 900;
  box-shadow: 0 4px 12px rgba(236, 72, 153, 0.35);
}
.brand small { display: block; font-size: 10px; font-weight: 600; color: var(--ink-soft); letter-spacing: .4px; line-height: 1; }
.nav-menu { display: flex; align-items: center; gap: 4px; flex: 1; }
.nav-link {
  padding: 8px 14px; border-radius: 10px;
  color: var(--ink-soft); font-weight: 600; font-size: 15px;
  transition: all .2s;
}
.nav-link:hover { color: var(--brand-ink); background: var(--grad-soft); opacity: 1; }
.nav-link.active { color: var(--brand-ink); background: var(--grad-soft); }
.nav-cta { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.btn-lang {
  border: 1px solid var(--line); background: var(--card);
  color: var(--ink); font-weight: 700; font-size: 13.5px;
  /* R39 美化：与 .btn-theme 等高（40px）对齐，inline-flex 垂直居中 */
  padding: 0 14px; height: 40px; border-radius: 12px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: all .2s;
}
.btn-lang:hover { border-color: var(--brand); color: var(--brand-ink); }
.btn-theme {
  border: 1px solid var(--line); background: var(--card);
  color: var(--ink); border-radius: 12px; cursor: pointer;
  width: 40px; height: 40px; padding: 0; font-size: 18px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  transition: all .2s;
}
.btn-theme:hover { border-color: var(--brand); transform: translateY(-2px); }
.nav-burger { display: none; background: none; border: 0; cursor: pointer; padding: 6px; }
.nav-burger span { display: block; width: 22px; height: 2px; background: var(--ink); margin: 5px 0; border-radius: 2px; transition: .25s; }

/* ---------- 按钮 ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 26px; border-radius: 999px; border: 0;
  font-weight: 700; font-size: 15.5px; cursor: pointer;
  transition: all .25s; text-decoration: none; font-family: inherit;
}
.btn-primary { background: var(--grad); color: #fff; box-shadow: 0 8px 22px rgba(236, 72, 153, 0.35); /* R45：CTA 白字对比不足（#ec4899 上 3.53）——加字重+投影提升可读性 */ font-weight: 900; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.28); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 12px 30px rgba(236, 72, 153, 0.45); opacity: 1; }
.btn-ghost { background: var(--card); color: var(--brand-ink); border: 1.5px solid var(--brand-ink); }
.btn-soft { background: var(--grad-soft); color: var(--brand-ink); }
.btn-soft:hover { opacity: 1; transform: translateY(-2px); }
.btn-sm { padding: 8px 16px; font-size: 13.5px; }
.btn-block { width: 100%; }

/* ---------- Hero ---------- */
.hero { position: relative; padding: 70px 0 90px; overflow: hidden; }
.hero::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(600px 300px at 12% 12%, rgba(124, 58, 237, 0.14), transparent 60%),
    radial-gradient(600px 300px at 88% 20%, rgba(236, 72, 153, 0.14), transparent 60%),
    radial-gradient(700px 400px at 50% 110%, rgba(249, 115, 22, 0.12), transparent 60%);
}
.hero-inner { display: grid; grid-template-columns: 1.05fr .95fr; gap: 48px; align-items: center; }
.eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--card); border: 1px solid var(--line);
  padding: 7px 16px; border-radius: 999px;
  font-size: 13px; font-weight: 700; color: var(--brand-ink);
  box-shadow: var(--shadow);
}
.hero h1 { font-size: clamp(34px, 5vw, 56px); font-weight: 900; margin: 20px 0 8px; letter-spacing: -.5px; }
.grad-text {
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.hero-sub { font-size: 17px; color: var(--ink-soft); margin: 16px 0 28px; max-width: 560px; }
.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; }
.hero-stats { display: flex; gap: 34px; margin-top: 44px; flex-wrap: wrap; }
.stat b { display: block; font-size: 26px; font-weight: 900; background: var(--grad); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.stat span { font-size: 13px; color: var(--ink-soft); font-weight: 600; }

.hero-demo { position: relative; }
.demo-card {
  background: var(--card); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: 26px;
  border: 1px solid var(--line);
  transform: rotate(1.5deg);
  transition: transform .3s;
}
.demo-card:hover { transform: rotate(0deg) scale(1.01); }
.demo-canvas { width: 100%; border-radius: 14px; }
.demo-badge {
  position: absolute; top: -14px; right: -8px;
  background: var(--grad); color: #fff;
  padding: 8px 16px; border-radius: 999px;
  font-size: 13px; font-weight: 800;
  box-shadow: 0 8px 20px rgba(236, 72, 153, 0.4);
  transform: rotate(4deg);
}
.demo-float {
  position: absolute; bottom: -18px; left: -12px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 14px; padding: 10px 16px;
  font-size: 13px; font-weight: 700; color: var(--ink-soft);
  box-shadow: var(--shadow);
  display: flex; align-items: center; gap: 8px;
}
.demo-float .dot { width: 8px; height: 8px; border-radius: 50%; background: #22c55e; }

/* ---------- 区块 ---------- */
.section { padding: 64px 0; }
.section-alt { background: var(--bg-soft); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.section-head { text-align: center; margin-bottom: 44px; }
.section-head h2 { font-size: clamp(26px, 3.4vw, 38px); font-weight: 900; }
.section-head p { color: var(--ink-soft); margin-top: 10px; font-size: 16px; }
.kicker {
  display: inline-block; background: var(--grad-soft); color: var(--brand-ink);
  font-size: 13px; font-weight: 800; padding: 5px 14px; border-radius: 999px;
  margin-bottom: 14px; letter-spacing: .5px;
}

/* ---------- 特性卡片 ---------- */
.grid { display: grid; gap: 22px; }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 26px;
  transition: all .25s;
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
.card-icon {
  width: 50px; height: 50px; border-radius: 15px;
  background: var(--grad-soft); display: grid; place-items: center;
  font-size: 24px; margin-bottom: 16px;
}
.card h3 { font-size: 17.5px; margin-bottom: 8px; }
.card p { color: var(--ink-soft); font-size: 14.5px; }

/* ---------- 步骤 ---------- */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; counter-reset: step; }
.step { position: relative; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 30px 26px; }
.step::before {
  counter-increment: step; content: counter(step);
  position: absolute; top: -16px; left: 26px;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--grad); color: #fff; font-weight: 900;
  display: grid; place-items: center;
  box-shadow: 0 6px 14px rgba(236, 72, 153, 0.4);
}
.step h3 { margin: 10px 0 8px; }
.step p { color: var(--ink-soft); font-size: 14.5px; }

/* ---------- 模板展示 ---------- */
.tpl-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.tpl-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  transition: all .25s; cursor: pointer;
}
.tpl-card:hover { transform: translateY(-4px) scale(1.01); box-shadow: var(--shadow-lg); }
.tpl-preview { width: 100%; aspect-ratio: 3/2; display: block; background: var(--grad-soft); }
.tpl-card-body { padding: 14px 18px; display: flex; align-items: center; justify-content: space-between; }
.tpl-card-body b { font-size: 15px; }
.tpl-card-body span { font-size: 12.5px; color: var(--ink-soft); }

/* ---------- 字体条 ---------- */
.font-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.font-chip {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px;
  text-align: center; transition: all .25s;
}
.font-chip:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.font-chip .sample { font-size: 26px; font-weight: 800; color: var(--brand-ink); white-space: nowrap; overflow: hidden; }
.font-chip .name { margin-top: 8px; font-size: 13px; color: var(--ink-soft); font-weight: 600; }

/* ---------- FAQ ---------- */
.faq { max-width: 820px; margin: 0 auto; }
.faq-item {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 16px; margin-bottom: 14px; overflow: hidden;
}
.faq-q {
  width: 100%; text-align: left; background: none; border: 0;
  padding: 18px 22px; font-size: 16px; font-weight: 700;
  color: var(--ink); cursor: pointer; font-family: inherit;
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
}
.faq-q::after { content: '+'; font-size: 22px; color: var(--brand-ink); font-weight: 800; transition: transform .25s; }
.faq-item.open .faq-q::after { transform: rotate(45deg); }
.faq-a { display: none; padding: 0 22px 18px; color: var(--ink-soft); font-size: 15px; }
.faq-item.open .faq-a { display: block; }

/* ---------- SEO 长文 ---------- */
.seo-article { max-width: 860px; margin: 0 auto; }
.seo-article h3 { margin: 22px 0 10px; font-size: 20px; }
.seo-article p { color: var(--ink-soft); margin-bottom: 14px; font-size: 15.5px; text-align: justify; }

/* ---------- 页脚 ---------- */
.footer { background: #241b4e; color: #cfc6f2; padding: 56px 0 30px; margin-top: 40px; }
.footer a { color: #cfc6f2; }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 34px; margin-bottom: 34px; }
.footer h4 { color: #fff; font-size: 15px; margin-bottom: 14px; }
.footer p { font-size: 14px; line-height: 1.8; }
.footer-links { list-style: none; }
.footer-links li { margin-bottom: 8px; }
.footer-links a { font-size: 14px; }
.footer-bottom { border-top: 1px solid rgba(255, 255, 255, 0.12); padding-top: 22px; font-size: 13px; color: #9d92d6; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px; }

/* ---------- 回到顶部 ---------- */
.back-top {
  position: fixed; right: 22px; bottom: 26px; z-index: 90;
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--grad); color: #fff; border: 0; cursor: pointer;
  font-size: 20px; box-shadow: 0 10px 24px rgba(236, 72, 153, 0.4);
  opacity: 0; pointer-events: none; transform: translateY(12px);
  transition: all .3s;
}
.back-top.visible { opacity: 1; pointer-events: auto; transform: translateY(0); }

/* ---------- 滚动入场 ---------- */
[data-reveal] { opacity: 0; transform: translateY(26px); transition: opacity .6s ease, transform .6s ease; }
[data-reveal].revealed { opacity: 1; transform: none; }

/* ---------- 页面横幅 ---------- */
.page-banner { padding: 54px 0 40px; text-align: center; position: relative; }
.page-banner::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(600px 260px at 50% 0%, rgba(124, 58, 237, 0.12), transparent 65%);
}
.page-banner h1 { font-size: clamp(28px, 4vw, 40px); font-weight: 900; }
.page-banner p { color: var(--ink-soft); margin-top: 10px; max-width: 640px; margin-left: auto; margin-right: auto; }

/* ---------- 工具页 ---------- */
.tool-page { display: flex; flex-direction: column; height: calc(100vh - var(--nav-h)); height: calc(100dvh - var(--nav-h)); min-height: 560px; }
.tool-main { flex: 1; display: flex; overflow: hidden; }
.tool-panel {
  width: 340px; min-width: 300px;
  background: var(--bg-soft);
  border-right: 1px solid var(--line);
  overflow-y: auto; padding: 14px;
}
.tool-stage { flex: 1; display: flex; flex-direction: column; overflow: hidden; position: relative; background: #efeafb; }
.tool-toolbar {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  background: var(--bg-soft); border-bottom: 1px solid var(--line); flex-wrap: wrap;
}
.tool-zoom { display: flex; align-items: center; gap: 6px; margin-left: auto; flex-wrap: wrap; justify-content: flex-end; }
.tool-canvas-wrap { flex: 1; overflow: auto; display: grid; place-items: safe center; padding: 26px; position: relative; }
/* R45：空文字引导提示（覆盖画布居中，文字输入后隐藏） */
.canvas-empty-hint {
  position: absolute; inset: 0; display: none;
  place-items: center; pointer-events: none; z-index: 2;
  color: var(--ink-soft); font-size: 17px; font-weight: 700; letter-spacing: .3px;
}
.canvas-empty-hint.show { display: grid; }
#toolCanvas { background: #fff; box-shadow: var(--shadow-lg); border-radius: 6px; max-width: none; transition: width .15s, height .15s; touch-action: none; }
/* R46（增强）：透明背景棋盘格预览——canvas 透明像素透出棋盘格 */
.tool-canvas-wrap.checker #toolCanvas { background: repeating-conic-gradient(#e8e4f5 0% 25%, #ffffff 0% 50%) 0 0 / 24px 24px; }
.app-dark .tool-canvas-wrap.checker #toolCanvas { background: repeating-conic-gradient(#2a2440 0% 25%, #221d35 0% 50%) 0 0 / 24px 24px; }

.panel-group {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 14px; margin-bottom: 12px; overflow: hidden;
}
/* R135：分节标题只是标题（R135 前是可点的折叠钮，带箭头与 hover） */
.panel-group > .pg-head {
  padding: 13px 16px; font-size: 14.5px; font-weight: 800;
  color: var(--ink); display: flex; align-items: center; gap: 9px;
}
.panel-group > .pg-head .pg-ico { font-size: 16px; flex: none; }
.panel-group > .pg-body { display: block; padding: 4px 16px 16px; }

.f-row { margin: 12px 0; }
.f-label { font-size: 12.5px; font-weight: 700; color: var(--ink-soft); display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.f-row > .val, .val { color: var(--brand-ink); font-weight: 800; font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; /* R50：.val 是行内 span，右对齐需块级化——落到滑块下方右侧（修复挂账左对齐） */ display: block; margin-top: 2px; }
.f-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

input[type=text], input[type=number], select, .inp, textarea {
  width: 100%; padding: 9px 12px; border: 1px solid var(--line);
  border-radius: 11px; background: var(--bg-soft);
  font-family: inherit; font-size: 14px; color: var(--ink);
  outline: none; transition: border .2s;
}
/* R39：iOS Safari 聚焦自动缩放防护——输入字号 <16px 聚焦必缩放，≤768px 全升 16px（-webkit-text-size-adjust 不解决聚焦缩放） */
@media (max-width: 768px) {
  input[type=text], input[type=number], select, .inp, textarea { font-size: 16px; }
}
input:focus, select:focus, .inp:focus, textarea:focus { border-color: var(--brand); background: #fff; }
textarea { resize: vertical; min-height: 72px; line-height: 1.5; }
input[type=range] { width: 100%; height: 28px; accent-color: var(--brand); cursor: pointer; }
input[type=range]::-webkit-slider-thumb { width: 22px; height: 22px; border-radius: 50%; background: var(--brand); border: 2px solid #fff; box-shadow: var(--shadow); margin-top: -8px; }
input[type=range]::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: var(--brand); border: 2px solid #fff; box-shadow: var(--shadow); }
input[type=range]::-webkit-slider-runnable-track { height: 6px; border-radius: 3px; background: var(--line); }
input[type=range]::-moz-range-track { height: 6px; border-radius: 3px; background: var(--line); }
/* R40：滑块暗色轨道提亮（--line 在 #17131f 上过暗） */
.app-dark input[type=range]::-webkit-slider-runnable-track { background: #3a3357; }
.app-dark input[type=range]::-moz-range-track { background: #3a3357; }
input[type=color] { width: 100%; height: 40px; border: 1px solid var(--line); border-radius: 10px; background: none; padding: 3px; cursor: pointer; }
/* R39 美化：file 输入补边框/圆角/内边距，与暗色态一致（原亮色无边框显得粗糙） */
input[type=file] { width: 100%; font-size: 12.5px; border: 1px solid var(--line); border-radius: 11px; padding: 9px 12px; background: var(--bg-soft); color: var(--ink-soft); cursor: pointer; }

.switch { position: relative; display: inline-block; width: 42px; height: 24px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute; inset: 0; border-radius: 999px;
  background: #d9d2f2; transition: .25s; cursor: pointer;
}
.switch .slider::before {
  content: ''; position: absolute; width: 18px; height: 18px; border-radius: 50%;
  left: 3px; top: 3px; background: #fff; transition: .25s;
  box-shadow: 0 2px 5px rgba(0,0,0,.18);
}
.switch input:checked + .slider { background: var(--grad); }
.switch input:checked + .slider::before { transform: translateX(18px); }
.sw-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 10px 0; }
.sw-row .f-label { margin-bottom: 0; }

.seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; background: #efeafb; padding: 4px; border-radius: 11px; }
/* R49：emoji 分类栏下间距（原内联迁入） */
#emojiCatSeg { margin-bottom: 8px; }
#patternTypeSeg, #bgPatternSeg { grid-auto-flow: row; grid-template-columns: repeat(5, 1fr); }
#bgTypeSeg { grid-auto-flow: row; grid-template-columns: repeat(4, 1fr); } /* R29 美化：8 个背景类型选项 2×4 换行，避免单行挤压（径向渐变等长标签被截断） */
/* R160：导出倍率改原生下拉（#exportScaleSeg 现在是 <select>），这条为网格胶囊写的规则永远匹配不到元素，删净 */
.seg button {
  border: 0; background: none; padding: 7px 4px; border-radius: 8px;
  font-size: 12.5px; font-weight: 700; color: var(--ink-soft); cursor: pointer; font-family: inherit;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* R41：补 hover 反馈 + transition（全站最常用控件原先零反馈、切 active 生硬） */
  transition: background .15s, color .15s;
}
.seg button:hover { color: var(--brand-ink); background: rgba(255, 255, 255, 0.65); }
.app-dark .seg button:hover { color: #c4b5fd; background: #2a2440; }
.seg button.active { background: #fff; color: var(--brand-ink); box-shadow: 0 2px 8px rgba(124, 58, 237, 0.15); }
/* R43（增强）：图案按钮缩略预览——SVG data-URI 背景 + 文字下移（26 图案由纯文字变图形） */
.seg button.pattern-thumb {
  height: 46px; padding: 26px 2px 3px;
  background-repeat: no-repeat; background-position: center 7px; background-size: 22px 22px;
}
/* 暗色下 active 背景不遮挡缩略图（背景色用透明容器色） */
.app-dark .seg button.pattern-thumb.active { background-color: #2e2748; }

.act-btn {
  padding: 9px 6px; border-radius: 11px; border: 1px solid var(--line);
  background: var(--bg-soft); font-size: 13px; font-weight: 700;
  color: var(--ink); cursor: pointer; font-family: inherit; transition: all .2s;
}
.act-btn:hover { border-color: var(--brand); color: var(--brand-ink); background: var(--grad-soft); }
/* R48：act-btn 激活态（棋盘格预览等开关类按钮的状态反馈） */
.act-btn.active { border-color: var(--brand); color: var(--brand-ink); background: var(--grad-soft); box-shadow: inset 0 0 0 1px rgba(124, 58, 237, 0.25); }
.app-dark .act-btn.active { color: #c4b5fd; }
/* R48：btn-ghost hover 位移与家族一致（-2px） */
.btn-ghost:hover { background: var(--grad-soft); opacity: 1; transform: translateY(-2px); }
/* R43：禁用态视觉（undo/redo 等） */
.act-btn:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.seg button:disabled { opacity: 0.45; cursor: not-allowed; }
/* R49：按压缩放微动效 */
.act-btn:active, .seg button:active, .btn:active, .tpl-filter button:active { transform: scale(.97); }
.pg-ico { display: inline-block; }
/* R49：搜索框/试写框聚焦光晕 */
.search-box:focus, .font-tryout input:focus { box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.15); border-color: var(--brand); }
/* R50：暗色聚焦光晕提亮（深底上 .15 几乎不可见） */
.app-dark .search-box:focus, .app-dark .font-tryout input:focus { box-shadow: 0 0 0 3px rgba(167, 139, 250, 0.3); }
/* R50：confirm-card 顶部品牌渐变条（提升品牌感） */
.confirm-card::before { content: ''; display: block; height: 3px; background: var(--grad); border-radius: 3px; margin: -24px -28px 18px; border-radius: var(--radius) var(--radius) 0 0; }

/* R49：自定义确认弹窗（替代原生 confirm） */
.confirm-modal { position: fixed; inset: 0; z-index: 300; background: rgba(0, 0, 0, 0.45); display: grid; place-items: center; opacity: 0; pointer-events: none; transition: opacity .2s; }
.confirm-modal.show { opacity: 1; pointer-events: auto; }
.confirm-card { background: var(--card); border-radius: var(--radius); padding: 24px 28px; max-width: 340px; width: calc(100% - 40px); box-shadow: var(--shadow-lg); transform: scale(.95); transition: transform .2s; }
.confirm-modal.show .confirm-card { transform: scale(1); }
.confirm-card p { margin-bottom: 18px; font-size: 15px; line-height: 1.6; color: var(--ink); }
.confirm-btns { display: flex; gap: 10px; justify-content: flex-end; }
@media (prefers-reduced-motion: reduce) { .confirm-modal, .confirm-card { transition: none; } }

.swatches { display: grid; grid-template-columns: repeat(5, 1fr); gap: 7px; }
/* R39：色板圆角统一 8px（swatch 9px / rc-swatch 7px / grad-presets 8px → 统一） */
.swatch { height: 30px; border-radius: 8px; cursor: pointer; border: 2px solid transparent; transition: .15s; }
.swatch:hover { transform: scale(1.08); border-color: var(--brand); }
.rc-list { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; min-height: 26px; align-items: center; }
.rc-swatch { height: 26px; border-radius: 8px; cursor: pointer; border: 2px solid transparent; transition: .15s; padding: 0; }
.rc-swatch:hover { transform: scale(1.08); border-color: var(--brand); }
.rc-swatch:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* R52：填充渐变多色编辑行（3-6 色标，每行 颜色输入 + 移除钮）；R58：行内含色标位置滑杆 */
.fill-stops { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.fill-stop { display: flex; flex-direction: column; gap: 6px; }
.fill-stop-side { display: flex; align-items: center; gap: 8px; }
.fill-stop-side input[type=color] { flex: 1; width: auto; height: 34px; }
.fill-stop input[type=color] { height: 34px; }
.stop-pos { display: flex; align-items: center; gap: 8px; }
.stop-pos .f-label { flex: none; font-size: 12px; }
.stop-pos input[type=range] { flex: 1; min-width: 0; }
.stop-pos .val { flex: none; min-width: 34px; }
.fill-stop-del { flex: none; width: 34px; height: 34px; border-radius: 10px; border: 1px solid var(--line); background: var(--bg-soft); color: var(--ink-soft); font-size: 13px; line-height: 1; cursor: pointer; transition: .15s; }
.fill-stop-del:hover { border-color: #ef4444; color: #ef4444; }
.fill-stop-del:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.fill-stops + .btn-block { margin-top: 8px; } /* R53：填充/描边/背景三处添加钮通用 */
.rc-hint { color: var(--ink-soft); font-size: 13px; }

/* 底板快捷色板：复用 .swatch，但父容器是 .sw-row(flex)，需显式网格给宽度，否则色块塌成 0 宽不可点 */
/* R155：底板快捷色板与主色板是同一份 SWATCHES（15 颗），原来一个一行 5 格、一个一行 6 格，
   结果两边都留空尾。拉齐成 5 格：同一份色板就该长同一个样，末行也正好排满。 */
#plaqueSwatches { display: grid; grid-template-columns: repeat(5, 1fr); gap: 7px; margin: 10px 0; }

.grad-presets { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; }
#gradPresetsBg { margin-top: 10px; } /* R31：背景渐变预设间距迁移到样式表（原为内联样式） */
.grad-presets button { height: 26px; border-radius: 8px; cursor: pointer; border: 2px solid transparent; transition: .15s; }
.grad-presets button:hover { transform: scale(1.07); border-color: var(--brand); }
/* R41：渐变预设持久选中态（亮色品牌边框 + 暗色浅紫） */
.grad-presets button.active { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.app-dark .grad-presets button.active { border-color: #a78bfa; box-shadow: 0 0 0 1px #a78bfa; }

.emoji-row { display: flex; flex-wrap: wrap; gap: 6px; }
.emoji-row button {
  font-size: 17px; padding: 3px 7px; border: 1px solid var(--line);
  background: var(--bg-soft); border-radius: 9px; cursor: pointer; transition: .15s; line-height: 1.3;
}
.emoji-row button:hover { border-color: var(--brand); transform: scale(1.12); }

/* 手机端抽屉 */
.tool-drawer-btn { display: none; }
.tool-scrim { display: none; }
@media (max-width: 900px) {
  .tool-main { position: relative; }
  .tool-panel {
    /* fixed 脱离 .tool-main 的 overflow:hidden，避免左侧阴影被裁切 */
    position: fixed; inset: var(--nav-h) auto 0 0; z-index: 60;
    width: min(86vw, 360px);
    transform: translateX(-105%);
    transition: transform .3s ease;
    box-shadow: var(--shadow-lg);
  }
  .tool-panel.open { transform: none; }
  .tool-drawer-btn {
    display: grid; place-items: center;
    position: absolute; top: 10px; left: 10px; z-index: 61;
    width: 42px; height: 42px; border-radius: 12px;
    background: var(--card); border: 1px solid var(--line);
    box-shadow: var(--shadow); font-size: 19px; cursor: pointer;
  }
  .tool-scrim { position: fixed; inset: 0; z-index: 59; background: rgba(0, 0, 0, 0.4); opacity: 0; pointer-events: none; transition: opacity .25s; }
  .tool-scrim.show { opacity: 1; pointer-events: auto; }
  .tool-toolbar { padding-top: 56px; }
  .tool-canvas-wrap { padding: 16px 10px; }
}

/* R47：字体页试写输入框（分类筛选下方居中） */
.font-tryout { max-width: 460px; margin: 0 auto 30px; }
/* R48：模板/字体页搜索框（与分类筛选/试写框样式统一） */
.search-box { max-width: 460px; margin: 0 auto 28px; display: block; }
/* R54：模板搜索行（搜索框 + 随机模板钮） */
.tpl-search-row { display: flex; gap: 10px; align-items: center; justify-content: center; max-width: 560px; margin: 0 auto 28px; }
.tpl-search-row .search-box { flex: 1; min-width: 0; max-width: none; margin: 0; }
.tpl-random { flex: none; white-space: nowrap; }
/* ---------- 模板页 ---------- */
.tpl-filter { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-bottom: 34px; }
.tpl-filter button {
  padding: 9px 20px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--card); font-size: 14px; font-weight: 700; color: var(--ink-soft);
  cursor: pointer; font-family: inherit; transition: all .2s;
}
.tpl-filter button.active { background: var(--grad); color: #fff; border-color: transparent; box-shadow: 0 6px 16px rgba(236, 72, 153, 0.35); }
.tpl-grid-page { grid-template-columns: repeat(3, 1fr); }
.tpl-card .btn { width: 100%; border-radius: 0 0 var(--radius) var(--radius); }

/* ---------- 字体页 ---------- */
.font-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.font-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  display: flex; flex-direction: column;
}
.font-card-canvas { width: 100%; aspect-ratio: 16/5; background: var(--grad-soft); }
.font-card-body { padding: 18px 20px; flex: 1; }
.font-card-body h3 { font-size: 17px; }
.font-card-body .fc-meta { font-size: 12.5px; color: var(--ink-soft); margin: 6px 0 10px; display: flex; gap: 8px; flex-wrap: wrap; }
.badge { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 800; }
.badge-ofl { background: #e0f2f1; color: #00695c; }
.badge-apache { background: #fce4ec; color: #ad1457; }
.badge-sys { background: #ede7f6; color: #4527a0; }
.font-card-body p { color: var(--ink-soft); font-size: 14px; }

/* ---------- 知识页 ---------- */
.know-chapter {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 30px 34px; margin-bottom: 24px;
}
.know-chapter h2 { font-size: 22px; margin-bottom: 14px; display: flex; align-items: center; gap: 12px; }
.know-chapter h2 .num {
  width: 36px; height: 36px; border-radius: 12px; background: var(--grad);
  color: #fff; display: grid; place-items: center; font-size: 17px; flex-shrink: 0;
}
.know-chapter p { color: var(--ink-soft); font-size: 15.5px; margin-bottom: 12px; }

/* 测验 */
.quiz-box { max-width: 720px; margin: 0 auto; }
/* R39：quiz 标题居中、内容左对齐（原 knowledge.html 内联 style 迁入，消除装饰性内联） */
.quiz-box h2 { justify-content: center; }
#quizWrap { text-align: left; margin-top: 22px; }
/* R40：知识页正文容器限宽（原 knowledge.html 内联 max-width:920px 迁入） */
#knowWrap { max-width: 920px; }
.quiz-q {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 24px 26px; margin-bottom: 18px;
}
.quiz-q h3 { font-size: 16.5px; margin-bottom: 14px; }
.quiz-opts { display: grid; gap: 9px; }
.quiz-opt {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 15px; border: 1.5px solid var(--line);
  border-radius: 12px; cursor: pointer; font-size: 14.5px; font-weight: 600;
  transition: all .18s; background: var(--bg-soft);
}
.quiz-opt:hover { border-color: var(--brand); }
.quiz-opt input { accent-color: var(--brand); }
.quiz-opt.correct { border-color: #22c55e; background: #ecfdf3; }
.quiz-opt.wrong { border-color: #ef4444; background: #fef2f2; }
.quiz-result { text-align: center; font-size: 19px; font-weight: 800; margin-top: 8px; }
/* R66（修复）：测验未作答的题目标出 */
.quiz-q.unanswered { border-color: #f59e0b; box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.25); }

/* ---------- 404 ---------- */
.err-page { text-align: center; padding: 90px 0 110px; }
.err-page h1 { font-size: clamp(90px, 18vw, 160px); font-weight: 900; background: var(--grad); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; line-height: 1; }
.err-page p { color: var(--ink-soft); font-size: 18px; margin: 16px 0 30px; }
.err-page .btn { margin: 0 6px; }

/* ---------- 响应式 ---------- */
@media (max-width: 1024px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .tpl-grid-page { grid-template-columns: repeat(2, 1fr); }
  .font-strip { grid-template-columns: repeat(2, 1fr); }
}
/* R30 修复：导航抽屉断点从 768 提到 900 —— 内联导航会溢出被 body overflow-x:clip 裁切，导致语言/主题按钮不可达。
   R113 曾为 7 项导航提到 1099；R114 顶部菜单收敛成 5 项（首页/在线制作/使用教程/常见问题/关于我们），
   实测 900px 起单行不挤压（880px 会折成 67px 高），故断点回到 899；tool 页三栏布局仍按 900px 走 */
@media (max-width: 899px) {
  .nav-menu {
    position: fixed; top: var(--nav-h); left: 0; right: 0;
    background: var(--bg-soft); flex-direction: column; align-items: stretch;
    padding: 14px; gap: 6px; border-bottom: 1px solid var(--line);
    transform: translateY(-130%); transition: transform .3s;
    box-shadow: var(--shadow-lg);
  }
  .nav-menu.open { transform: none; }
  .nav-burger { display: block; margin-left: auto; }
  .nav-burger.active span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav-burger.active span:nth-child(2) { opacity: 0; }
  .nav-burger.active span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
  .nav-cta { margin-left: 0; }
  /* R116：导航内联 CTA 已整站撤除（与「在线制作」同义重复），原先为它写的窄屏隐藏规则一并删除 */
}
@media (max-width: 768px) {
  .hero-inner { grid-template-columns: 1fr; }
  .hero-demo { max-width: 460px; margin: 0 auto; }
  .steps { grid-template-columns: 1fr; }
  .tpl-grid { grid-template-columns: 1fr 1fr; }
  .font-grid, .footer-grid { grid-template-columns: 1fr; }
  .hero-stats { gap: 22px; }
}
@media (max-width: 560px) {
  .tpl-grid, .tpl-grid-page { grid-template-columns: 1fr; }
  .font-strip { grid-template-columns: 1fr 1fr; }
  .section { padding: 46px 0; }
  /* R29/R31 美化：窄屏下 22 个图案选项改 4 列，减少按钮截断 */
  #patternTypeSeg, #bgPatternSeg { grid-template-columns: repeat(4, 1fr); }
}
/* R31 美化：≤380px（如 iPhone SE 320px）缩小品牌并收紧导航间距，避免导航右端被 overflow-x:clip 裁切（R33 提为独立块，避免嵌在 560px 内） */
@media (max-width: 380px) {
  .brand small { display: none; }
  .brand { font-size: 15px; }
  .nav-inner { gap: 10px; padding: 0 12px; }
  /* R32：≤380px 图案选项改 3 列，减少长标签（concentric/honeycomb 等）截断 */
  #patternTypeSeg, #bgPatternSeg { grid-template-columns: repeat(3, 1fr); }
}
/* R32 曾按 ≤360px 隐藏语言切换给汉堡让位（那时是「中/EN」两颗 + 导航内联 CTA）。
   R115b 收成一颗 52px 的钮、R116 撤掉导航 CTA、R120 又撤了页脚那颗之后，
   实测 320px 下 品牌122 / 语言132-184 / 主题194-234 / 汉堡261 起，零重叠零溢出、
   汉堡中心命中测试通过 → 隐藏规则失去理由，删掉，语言切换在最小屏上也保持可达。 */

@media (max-width: 480px) {
  .tool-toolbar { gap: 8px; padding: 56px 10px 8px; }
  .tool-zoom { width: 100%; margin-left: 0; justify-content: flex-start; }
  .tool-panel { padding: 12px; min-width: 0; }
  .tool-canvas-wrap { padding: 14px 8px; }
  .tool-zoom { gap: 5px; }
}

/* 打印/高对比友好 */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
  html { scroll-behavior: auto; }
  [data-reveal] { opacity: 1; transform: none; }
}

/* R40：面板/画布容器暗色自定义滚动条（原亮色系统条突兀） */
.tool-canvas-wrap, .tool-panel { scrollbar-width: thin; scrollbar-color: #c9c2e4 transparent; }
.app-dark .tool-canvas-wrap, .app-dark .tool-panel { scrollbar-width: thin; scrollbar-color: #3a3357 transparent; }
.tool-canvas-wrap::-webkit-scrollbar, .tool-panel::-webkit-scrollbar { width: 8px; height: 8px; }
.tool-canvas-wrap::-webkit-scrollbar-thumb, .tool-panel::-webkit-scrollbar-thumb { background: #c9c2e4; border-radius: 4px; }
.app-dark .tool-canvas-wrap::-webkit-scrollbar-thumb, .app-dark .tool-panel::-webkit-scrollbar-thumb { background: #3a3357; }

/* ---------- 暗色模式（手动切换 / 跟随系统） ---------- */
:root.app-dark {
  --bg: #14121f;
  --bg-soft: #1c182c;
  --card: #221d35;
  --ink: #f1edff;
  --toast-bg: var(--card);
  --toast-fg: var(--ink);
  --ink-soft: #b6accf;
  --line: #322b4d;
  --grad-soft: linear-gradient(120deg, #2a2140, #3a2545 55%, #3a2a1e);
  --shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 20px 50px rgba(0, 0, 0, 0.6);
}
.app-dark body { background: var(--bg); color: var(--ink); }
.app-dark .nav { background: rgba(28, 24, 44, 0.86); }
.app-dark .tool-panel { background: var(--bg-soft); }
.app-dark .tool-stage, .app-dark .tool-canvas-wrap { background: #17131f; }
.app-dark .tool-toolbar { background: var(--bg-soft); }
.app-dark .footer { background: #0f0c19; }
.app-dark .nav-menu { background: var(--bg-soft); }
.app-dark input[type=text], .app-dark input[type=number], .app-dark select, .app-dark textarea, .app-dark .inp { background: #16121f; color: var(--ink); border-color: var(--line); }
.app-dark input:focus, .app-dark select:focus, .app-dark textarea:focus, .app-dark .inp:focus { background: #1c1830; }
.app-dark .seg { background: #16121f; }
/* R40（P1-10）：暗色 active 态加内描边提升对比（原仅换背景 #221d35 vs 容器 #16121f 对比 ~5% 过弱） */
.app-dark .seg button.active { background: #2e2748; box-shadow: inset 0 0 0 1px rgba(124, 58, 237, 0.35); }
.app-dark .act-btn { background: #16121f; }
.app-dark .btn-lang { background: var(--card); color: var(--ink); }
.app-dark .emoji-row button, .app-dark .swatch, .app-dark .grad-presets button { background: var(--bg-soft); }
/* R40（P1-10）：暗色下深色色板（#1f2937 等）与卡片同色不可辨——内联 background 优先级高于类规则，
   改用 2px 透明边框高亮（色块四边可见）；rc-swatch 补亮色描边 */
.app-dark .swatch, .app-dark .rc-swatch, .app-dark .grad-presets button { border-color: rgba(255, 255, 255, 0.22); }
.app-dark .rc-swatch { border-color: rgba(255, 255, 255, 0.22); }
.app-dark .hero::before, .app-dark .page-banner::before { opacity: .55; }
.app-dark #toolCanvas { background: #fff; }
.app-dark input[type=color] { border-color: var(--line); }
.app-dark input[type=file] { color: var(--ink-soft); background: var(--card); border: 1px solid var(--line); border-radius: 11px; padding: 9px 12px; }
.app-dark .switch .slider { background: #3a3357; }
/* R39：quiz 对错底色与 badge 浅底在暗色下过亮突兀，改半透明深底 + 亮色文字 */
.app-dark .quiz-opt.correct { border-color: #22c55e; background: rgba(34, 197, 94, 0.16); color: #86efac; }
.app-dark .quiz-opt.wrong { border-color: #ef4444; background: rgba(239, 68, 68, 0.16); color: #fca5a5; }
.app-dark .badge-ofl { background: rgba(0, 150, 136, 0.22); color: #5eead4; }
.app-dark .badge-apache { background: rgba(236, 72, 153, 0.22); color: #f9a8d4; }
.app-dark .badge-sys { background: rgba(124, 58, 237, 0.24); color: #c4b5fd; }
/* 暗色下缩略图底色跟随卡片，避免浅色方块突兀 */
.app-dark .style-card canvas, .app-dark .my-style-card canvas { background: #221d35; }

/* ---------- 渐变描边（受启用状态控制） ---------- */
.stroke-only { display: none; margin-top: 12px; }
.stroke-only.show { display: block; }
.stroke-grad-only { display: none; }
.stroke-grad-only.show { display: block; }

/* ---------- 条件面板默认隐藏态（脚本未执行时兜底，防界面错乱） ----------
   这些类由 tool.js 用 el.style.display=''/'none' 行内切换；正常执行时内联覆盖。
   为防脚本未加载/首屏 FOUC 时面板全部展开，这里仅在 body 未加 .js-on 时隐藏。
   tool.js 初始化完成后会给 body 添加 .js-on，此时本规则失效，元素恢复自然 display
   （.f-row=block / .sw-row=flex 等），与 JS 的 display='' 切换互不冲突。
   涵盖：fill-only / bg-only / wave-only / ring-only / arc-wave-only /
   plaque-sub / bg-pattern-shape / bg-pattern-scale / stroke-only / stroke-grad-only / deco-sub / deco-blocked */
body:not(.js-on) .fill-only, body:not(.js-on) .bg-only, body:not(.js-on) .wave-only,
body:not(.js-on) .ring-only, body:not(.js-on) .arc-wave-only, body:not(.js-on) .plaque-sub,
body:not(.js-on) .bg-pattern-shape, body:not(.js-on) .bg-pattern-scale,
body:not(.js-on) .stroke-only, body:not(.js-on) .stroke-grad-only, body:not(.js-on) .deco-sub, body:not(.js-on) .deco-blocked { display: none; }

/* ---------- 创意风格 / 快捷模板缩略卡 ---------- */
.styles-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 12px; }
.style-card {
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  background: var(--bg-soft); cursor: pointer; transition: all .2s; text-align: center;
}
.style-card:hover { border-color: var(--brand); transform: translateY(-2px); box-shadow: var(--shadow); }
.style-card canvas { width: 100%; display: block; background: #f0edfa; aspect-ratio: 12 / 7; }
.style-card span { display: block; font-size: 12px; font-weight: 700; padding: 6px 4px; color: var(--ink-soft); }


/* ---------- 我的样式 ---------- */
.my-styles-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
.my-style-card {
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  background: var(--bg-soft); transition: all .2s; display: flex; flex-direction: column;
}
.my-style-card:hover { border-color: var(--brand); box-shadow: var(--shadow); }
.my-style-card canvas { width: 100%; display: block; background: #f0edfa; aspect-ratio: 3/2; }
.my-style-card .ms-name { font-size: 12.5px; font-weight: 700; padding: 6px 8px 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); }
.my-style-card .ms-actions { display: flex; gap: 6px; padding: 4px 8px 8px; }
.my-style-card .ms-actions button { flex: 1; font-size: 12px; padding: 5px 4px; border-radius: 8px; border: 1px solid var(--line); background: var(--card); cursor: pointer; font-weight: 700; color: var(--ink-soft); font-family: inherit; transition: all .2s; }
.my-style-card .ms-actions .apply { color: var(--brand-ink); border-color: var(--brand); }
.my-style-card .ms-actions .apply:hover { background: var(--grad-soft); }
.my-style-card .ms-actions .del:hover { color: #ef4444; border-color: #ef4444; }
.my-empty { font-size: 12.5px; color: var(--ink-soft); margin-top: 10px; line-height: 1.7; display: none; }
.my-empty.show { display: block; }

/* ---------- 无障碍：键盘可达性与焦点环 ---------- */
.style-card, .my-style-card { outline: none; }
.style-card:focus-visible, .my-style-card:focus-visible {
  outline: 2px solid var(--brand); outline-offset: 2px; border-color: var(--brand);
}
.btn:focus-visible, .act-btn:focus-visible, .seg button:focus-visible,
.tool-drawer-btn:focus-visible, .ms-actions button:focus-visible,
.switch input:focus-visible + .slider { outline: 2px solid var(--brand); outline-offset: 2px; }
/* R45：:focus 兜底——Safari<15.4 无 :focus-visible，键盘焦点无环；@supports not 仅旧浏览器生效 */
@supports not selector(:focus-visible) {
  .btn:focus, .act-btn:focus, .seg button:focus, .nav-link:focus, .btn-lang:focus,
  .btn-theme:focus, .tpl-filter button:focus, .faq-q:focus, .nav-burger:focus,
  .back-top:focus, .swatch:focus, .grad-presets button:focus, .emoji-row button:focus { outline: 2px solid var(--brand); outline-offset: 2px; }
}
.btn-lang:focus-visible, .nav-link:focus-visible, .tpl-filter button:focus-visible,
.swatch:focus-visible, .grad-presets button:focus-visible, .emoji-row button:focus-visible,
.quiz-opt:focus-within, .btn-theme:focus-visible, .faq-q:focus-visible,
.nav-burger:focus-visible, .back-top:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
@media (max-width: 768px) {
  .swatch, .grad-presets button, .seg button, .emoji-row button, .act-btn,
  .my-style-card .ms-actions button, .rc-swatch, .export-row .btn-sm, .plan-row .btn { min-height: 40px; }
  .swatch { height: 40px; }
  .grad-presets button { height: 40px; }
  .switch::after { content: ''; position: absolute; inset: -9px; }
}
/* R39 美化：桌面工具栏控件统一最小高度 38px（seg 按钮 ≈30 / act-btn ≈35 / btn-sm ≈38 混高 → 统一）。
   R43 修正：限 ≥769px 桌面——原规则特异性压过 ≤768 的 40px 触控目标，移动端导出按钮实测仅 38px */
@media (min-width: 769px) {
  .tool-toolbar .act-btn, .export-row .btn-sm, .plan-row .btn { min-height: 38px; }
}

/* ---------- Toast 提示 & 用户字体列表（原 tool.html 内联 <style> 迁入） ---------- */
.toast {
  position: fixed; bottom: 30px; left: 50%; transform: translateX(-50%) translateY(80px);
  background: var(--toast-bg); color: var(--toast-fg); padding: 11px 24px; border-radius: 999px;
  font-size: 14px; font-weight: 600; z-index: 200; opacity: 0;
  transition: all .3s; pointer-events: none; box-shadow: var(--shadow-lg);
}
.toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
/* R77：带操作按钮的提示（特效越界体检）——只有此时才吃点击 */
.toast.act { pointer-events: auto; }
.toast-act { margin-left: 12px; border: 1px solid rgba(255, 255, 255, 0.45); background: rgba(255, 255, 255, 0.16); color: inherit; border-radius: 999px; padding: 3px 12px; font-size: 13px; font-weight: 700; cursor: pointer; }
.toast-act:hover { background: rgba(255, 255, 255, 0.3); }
#userFontList .uf-row { display: flex; align-items: center; gap: 8px; margin: 6px 0; }
#userFontList .uf-row b { font-size: 13px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#userFontList .uf-row button { border: 1px solid var(--line); background: var(--bg-soft); border-radius: 8px; padding: 3px 9px; font-size: 12px; cursor: pointer; color: var(--ink-soft); }
#userFontList .uf-row button:hover { color: #ef4444; border-color: #ef4444; }

/* ---------- 移动端：解除固定高度下限，允许整页滚动避免裁切导出按钮 ---------- */
@media (max-width: 768px) {
  .tool-page { height: auto; min-height: 0; }
  .tool-main { overflow: visible; }
}

/* R44：场景尺寸速查表 */
.size-table { width: 100%; border-collapse: collapse; margin: 14px 0 4px; font-size: 14px; }
.size-table th, .size-table td { border: 1px solid var(--line); padding: 9px 14px; text-align: left; }
.size-table th { background: var(--grad-soft); color: var(--brand-ink); font-weight: 800; }
/* R46：暗色下表头 --brand on 深 grad-soft 对比 2.7:1 不足——提亮 */
.app-dark .size-table th { color: #a78bfa; }
.size-table td { color: var(--ink); }
.size-table tr:nth-child(even) td { background: var(--bg-soft); }
.size-table td:nth-child(2) { font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 480px) { .size-table { font-size: 12.5px; } .size-table th, .size-table td { padding: 7px 9px; } }

/* ---------- 通用工具类（替代 HTML 内联样式，减少重复） ---------- */
.hint-sm { font-size: 12px; color: var(--ink-soft); margin-top: 6px; line-height: 1.7; }
.hint-xs { font-size: 11.5px; color: var(--ink-soft); margin-top: 5px; line-height: 1.7; }
.mt-8 { margin-top: 8px; }
.mt-10 { margin-top: 10px; }
.mt-30 { margin-top: 30px; }
.mt-48 { margin-top: 48px; }
.mt-52 { margin-top: 52px; }
.mb-22 { margin-bottom: 22px; }
.pt-36 { padding: 36px; }
.pt-10 { padding-top: 10px; }
.center { text-align: center; }
.ta-left { text-align: left; }
.ink-soft { color: var(--ink-soft); }
.rc-row { margin: 12px 0; }
.seo-h2 { font-size: 26px; text-align: center; margin-bottom: 20px; }
.lbl-hidden { opacity: 0; pointer-events: none; }
.lbl-sm { font-size: 13px; color: var(--ink-soft); line-height: 1.9; }
.lbl-size { font-size: 13px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.lbl-zoom { font-size: 12.5px; color: var(--ink-soft); min-width: 40px; text-align: center; font-variant-numeric: tabular-nums; }

/* ---------- R45：打印规则（原全站无 @media print——tool 页画布被单屏裁切、FAQ 答案不打印） ---------- */
@media print {
  .nav, .tool-toolbar, .tool-drawer-btn, .tool-scrim, .back-top, .footer, .btn, .act-btn, .tpl-filter, #fontFilter, .tpl-peek { display: none !important; } /* R67 加固：悬停预览浮层若打印瞬间在场会漏进纸面 */
  body { background: #fff !important; color: #000 !important; }
  .tool-page { height: auto !important; min-height: 0 !important; }
  .tool-main { overflow: visible !important; }
  .tool-canvas-wrap { overflow: visible !important; padding: 0 !important; }
  #toolCanvas { box-shadow: none !important; border-radius: 0 !important; }
  .faq-a { display: block !important; }
  .know-chapter, .card, .font-card, .tpl-card { box-shadow: none !important; }
  a { color: #000 !important; text-decoration: underline; }
}

/* ---------- R41：补全 hover 反馈（faq-q / tpl-filter / font-card / drawer / back-top） ---------- */
.faq-q:hover { background: var(--bg-soft); }
.tpl-filter button:hover { border-color: var(--brand); color: var(--brand-ink); }
.font-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.tool-drawer-btn:hover { border-color: var(--brand); }
.back-top:hover { transform: translateY(-2px); color: var(--brand-ink); }
.back-top { transition: all .2s; }

/* ---------- R41：触屏 hover 粘滞防护 ----------
   触屏设备点按后 :hover 位移/缩放动效会粘滞（卡片浮着/图标放大），@media(hover:none) 关闭位移
   （保留 border/背景变色反馈，避免无响应感） */
@media (hover: none) {
  .btn-primary:hover, .btn-ghost:hover, .btn-soft:hover, .btn-theme:hover,
  .card:hover, .tpl-card:hover, .font-card:hover, .font-chip:hover,
  .swatch:hover, .grad-presets button:hover, .emoji-row button:hover,
  .style-card:hover, .demo-card:hover, .back-top:hover {
    transform: none;
  }
}

/* ---------- R41：横屏短高手机（landscape）tool 页解除固定高度，允许整页滚动 ---------- */
@media (max-width: 900px) and (max-height: 520px) {
  .tool-page { height: auto; min-height: 0; }
  .tool-main { overflow: visible; }
  .tool-toolbar { padding-top: 56px; }
}

/* ---------- R41：901–1100px 面板收窄（原 340px 常驻挤压画布区至 ~560px） ---------- */
@media (min-width: 901px) and (max-width: 1100px) {
  .tool-panel { width: 300px; }
}

/* ---------- R43：移动端细节 ---------- */
/* iPhone 全面屏安全区：抽屉面板底部不被 home indicator 遮挡 */
@media (max-width: 900px) {
  .tool-panel { padding-bottom: max(12px, env(safe-area-inset-bottom)); }
}
/* 768–900px（iPad/大屏安卓）100dvh 随地址栏跳变：svh 兜底更稳 */
@media (min-width: 769px) and (max-width: 900px) {
  .tool-page { height: calc(100svh - var(--nav-h)); height: calc(100dvh - var(--nav-h)); }
}
/* my-style-card hover 与 style-card 一致的位移反馈 */
.my-style-card:hover { transform: translateY(-2px); }

/* ---------- R55：工具页三栏布局（≥1280px：左内容栏 | 画布栏 | 右样式栏） ---------- */
.tool-panel-right { display: none; border-right: 0; border-left: 1px solid var(--line); }
@media (min-width: 1280px) {
  .tool-main > .tool-panel { width: 316px; min-width: 280px; }
  .tool-panel-right { display: block; }
}

/* ---------- R57：字体库最近字体快捷区 + 我的样式重命名态 ---------- */
.my-style-card .ms-actions .ren:hover { color: var(--brand-ink); border-color: var(--brand); }
#inStyleName.renaming { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.15); }

/* ---------- R59：我的样式操作区两行布局（套用独占一行，置顶/重命名/删除并排第二行） ---------- */
.my-style-card .ms-actions { flex-wrap: wrap; }
.my-style-card .ms-actions .apply { flex: 0 0 100%; }
.my-style-card .ms-actions .pin:hover { color: var(--brand-ink); border-color: var(--brand); }

/* ---------- R60：收藏计数徽标（历史缩略图随 R170 撤除） ---------- */
.ms-head { display: flex; align-items: center; gap: 8px; }
.ms-head .f-label { flex: 1; min-width: 0; }
.ms-count { flex: none; font-size: 11px; font-family: ui-monospace, Consolas, monospace; color: var(--ink-soft); border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px; background: var(--card); }
.ms-count.warn { color: #d97706; border-color: #f59e0b; }

/* ---------- R61：导出文件名设置区（R111：首页续编辑入口已撤除） ---------- */
.fname-row { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line); }
.fname-row input[type=text] { width: 100%; }

/* R111：首页续编辑入口与其缩略图样式随功能一起撤除（R98 撤的是工具页概览条） */

/* ---------- R65：模板卡悬停放大预览浮层 ---------- */
.tpl-peek { position: fixed; z-index: 130; pointer-events: none; border-radius: 14px; overflow: hidden; border: 1px solid var(--line); box-shadow: var(--shadow-lg); background: var(--card); opacity: 0; transform: scale(.96); transition: opacity .15s ease, transform .15s ease; }
.tpl-peek.show { opacity: 1; transform: none; }
.tpl-peek canvas { width: 100%; height: 100%; display: block; }
@media (prefers-reduced-motion: reduce) { .tpl-peek { transition: none; } }

/* ---------- R67：画布双指捏合缩放 ---------- */
#toolCanvas { touch-action: none; } /* 常驻：手势起点落在画布时浏览器不再抢作页面缩放/滚动 */

/* ---------- R68：浮层模板名胶囊 ---------- */
.tpl-peek { position: fixed; }
.tpl-peek-name { position: absolute; left: 10px; bottom: 10px; max-width: calc(100% - 20px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; color: #fff; background: rgba(43, 35, 80, 0.72); border-radius: 999px; padding: 3px 12px; }

/* ============ R88 工具页排版美化（末尾追加层：只覆盖必要项，不整表重写） ============ */

/* 1) 预览区上方工具条：稳定两行——第一行「尺寸 + 视图控制」，第二行「导出倍率 + 导出/文件」右对齐。
      原先 10 个按钮与两组控件挤在 flex-wrap 里换出三行，右端参差、白吃约 34px 高度。 */
.tool-toolbar { padding: 9px 14px; row-gap: 8px; }
.lbl-size { font-size: 13.5px; font-weight: 900; letter-spacing: .2px; color: var(--ink); font-variant-numeric: tabular-nums; }
.lbl-zoom { font-size: 12.5px; font-weight: 800; color: var(--brand-ink); font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; }

/* 2) 分段钮标签不再被截断（"线性…"、"每字整…"）：五段填色按 3 列换行、四段逐字分色按 2 列换行，
      与 R29 给 #bgTypeSeg 做过的处理同一手法。 */
#fillTypeSeg { grid-auto-flow: row; grid-template-columns: repeat(3, minmax(0, 1fr)); }
#perCharSeg { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* 4) 舞台加纵深（顶部品牌光 + 由浅到深的落底渐变），画布补一圈描边，
      让"白纸浮在紫底上"不再像没背景。装饰只走整块容器底色，不加任何条/框线元素。 */
.tool-stage {
  background:
    radial-gradient(760px 320px at 50% -60px, rgba(124, 58, 237, .13), transparent 72%),
    linear-gradient(180deg, #f3eefe 0%, #eae4f8 62%, #e4ddf4 100%);
}
.app-dark .tool-stage {
  background:
    radial-gradient(760px 320px at 50% -60px, rgba(139, 92, 246, .20), transparent 72%),
    linear-gradient(180deg, #1a1526 0%, #15111f 62%, #120f1b 100%);
}
.tool-canvas-wrap { padding: 22px; }
#toolCanvas { border: 1px solid rgba(124, 58, 237, .16); }
.app-dark #toolCanvas { border-color: rgba(196, 181, 253, .24); }
/* 棋盘格预览开启时描边会干扰透明判断，退回无描边 */
.tool-canvas-wrap.checker #toolCanvas { border-color: transparent; }

/* 5) 右栏面板：标题与正文的层级再拉开一点，正文左右留白收紧一档，
      给分段钮与滑杆多出可用宽度（窄栏里标签截断的根因之一是留白过厚）。 */
.tool-panel-right .panel-group > .pg-head { padding: 12px 14px; }
.tool-panel-right .panel-group > .pg-body { padding: 4px 14px 16px; }
.f-label { letter-spacing: .1px; }
/* 6) 工具条：收紧内边距与行距，方案类按钮降一档视觉重量（导出是主操作，方案文件是次操作）。 */
.tool-toolbar { row-gap: 6px; padding: 8px 14px; }

/* 8) 窄一点的舞台（视口 ≤1360，含手机/平板/双栏态）工具条改单行横向滑动：原先换行吃掉 195~231px，画布被挤到首屏之外。
      单行不换行 + 隐藏滚动条，控件全部保留可点（右侧留 8px 渐隐提示还有内容）。 */
@media (max-width: 1620px) {
  .tool-toolbar { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; padding: 7px 10px;
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 18px), transparent 100%); mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 18px), transparent 100%); }
  .tool-toolbar > * { flex: none; }
  .tool-toolbar::-webkit-scrollbar { display: none; }
  /* 覆盖 ≤480 老规则 .tool-zoom{width:100%}：单行滚动容器里若各簇都是 100% 宽会互相叠在一起 */
  .tool-toolbar > .tool-zoom, .tool-toolbar > .tb-group { margin-left: 0; flex-wrap: nowrap; width: auto; flex: none; }
  /* R162：分簇之后组间 10px 的 margin 在滚动容器里会把首组顶离左缘，这里归零；组内节奏由 gap 管 */
  .tool-toolbar > .tb-group + .tb-group { margin-left: 10px; }
}

/* ============ R89 工具页排版美化（第二批，末尾追加层） ============ */

/* 1) 滑杆行：标签与数值同一行两端对齐，滑杆独占下一行。
      原先数值挂在滑杆下方右侧，像另一行标题；一屏十几个滑杆时节奏很碎。 */
.f-row:has(> input[type="range"]) { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 10px; row-gap: 4px; align-items: baseline; }
.f-row:has(> input[type="range"]) > .f-label { margin-bottom: 0; grid-column: 1; }
.f-row:has(> input[type="range"]) > .val { grid-column: 2; grid-row: 1; margin-top: 0; min-width: 0; font-size: 13px; }
.f-row:has(> input[type="range"]) > input[type="range"] { grid-column: 1 / -1; grid-row: 2; }

/* 2) 浅色色块在白底卡片上会"消失"（银白、浅粉等），统一补一圈内描边；暗色下用浅墨描边 */
.swatch, .grad-presets button, .rc-swatch { box-shadow: inset 0 0 0 1px rgba(43, 35, 80, .16); }
.app-dark .swatch, .app-dark .grad-presets button, .app-dark .rc-swatch { box-shadow: inset 0 0 0 1px rgba(241, 237, 255, .26); }

/* 3) 文字主输入区：多给一行高度，字数计数常驻在标签右端（触顶前变警示色） */
#inText { min-height: 96px; }
.ta-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.ta-head .f-label { margin-bottom: 0; }
.ta-count { font-size: 11.5px; font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; flex: none; }
.ta-count.warn { color: var(--brand2); }

/* ============ R90 工具页排版美化（第三批，末尾追加层） ============ */

/* 1) 单个取色器的行：桌面端收成「标签在左、色块在右」一行（原先 100% 宽 × 40px 的色条，
      一屏里连着出现十几条，整块面板像被色条占满）。窄屏保留大块，保证手指可点。 */
@media (min-width: 769px) {
  .f-row:has(> input[type="color"]) { display: grid; grid-template-columns: minmax(0, 1fr) 68px; column-gap: 10px; align-items: center; }
  .f-row:has(> input[type="color"]) > .f-label { margin-bottom: 0; grid-column: 1; }
  .f-row:has(> input[type="color"]) > input[type="color"] { grid-column: 2; height: 30px; border-radius: 8px; padding: 2px; }
  .f-row:has(> input[type="color"]) > input[type="color"]:hover { border-color: var(--brand); }
}

/* 2) 渐变色带更密（6→7 列）：42 个预设从 7 行收到 6 行，填充面板首屏能多露出「推荐配色」一组。 */
.grad-presets { grid-template-columns: repeat(7, minmax(0, 1fr)); }

/* ============ R91 工具页排版美化（第四批：渐变预设按色系分组） ============ */

/* 42 个色块连排下去是一片「马赛克」，想找暖色只能逐个看。现在按色系分 6 组，
   组首一行小标题——用文字本身着色做身份，不加装饰条；标题占满整行，色块仍走 7 列网格。 */
.grad-presets .gp-cap {
  grid-column: 1 / -1;
  margin-top: 6px;
  font-size: 10.5px;
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--ink-soft);
}
.grad-presets .gp-cap:first-child { margin-top: 0; }
/* 色系身份色必须比基样式多一层类，否则被上面 `.grad-presets .gp-cap` 的特指度压住（首版就踩了：六组全是灰） */
.grad-presets .gp-cap.gp-cap-warm { color: #b83a06; }
.grad-presets .gp-cap.gp-cap-nature { color: #3f6212; }
.grad-presets .gp-cap.gp-cap-cool { color: #1d4ed8; }
.grad-presets .gp-cap.gp-cap-vivid { color: #86198f; }
.grad-presets .gp-cap.gp-cap-quiet { color: #55607a; }
.grad-presets .gp-cap.gp-cap-multi { color: #6d28d9; }
.app-dark .grad-presets .gp-cap.gp-cap-warm { color: #fdba74; }
.app-dark .grad-presets .gp-cap.gp-cap-nature { color: #bef264; }
.app-dark .grad-presets .gp-cap.gp-cap-cool { color: #93c5fd; }
.app-dark .grad-presets .gp-cap.gp-cap-vivid { color: #f0abfc; }
.app-dark .grad-presets .gp-cap.gp-cap-quiet { color: #cbd5e1; }
.app-dark .grad-presets .gp-cap.gp-cap-multi { color: #c4b5fd; }
/* 选中态此前只在点击瞬间点亮，撤销后仍亮着过期的一条；现在选中项自身也抬起来一点 */
.grad-presets button.active { transform: scale(1.05); }

/* ============ R92 工具页排版美化（第五批：纯色板分组 + 最近使用） ============ */

/* 1) 把 R91 的组名从「只服务渐变色带」泛化成通用组标题（推荐配色／底板色板共用同一套字号与身份色）。
      身份色必须带 .gp-cap 双类，单类会被 `.grad-presets .gp-cap` 的特指度压住。 */
.gp-cap { grid-column: 1 / -1; margin-top: 6px; font-size: 10.5px; line-height: 1.2; font-weight: 700; letter-spacing: .04em; color: var(--ink-soft); }
.gp-cap:first-child { margin-top: 0; }
.gp-cap.gp-cap-warm { color: #b83a06; }
.gp-cap.gp-cap-nature { color: #3f6212; }
.gp-cap.gp-cap-cool { color: #1d4ed8; }
.gp-cap.gp-cap-vivid { color: #86198f; }
.gp-cap.gp-cap-quiet { color: #55607a; }
.gp-cap.gp-cap-multi { color: #6d28d9; }
.app-dark .gp-cap.gp-cap-warm { color: #fdba74; }
.app-dark .gp-cap.gp-cap-nature { color: #bef264; }
.app-dark .gp-cap.gp-cap-cool { color: #93c5fd; }
.app-dark .gp-cap.gp-cap-vivid { color: #f0abfc; }
.app-dark .gp-cap.gp-cap-quiet { color: #cbd5e1; }
.app-dark .gp-cap.gp-cap-multi { color: #c4b5fd; }

/* 2）纯色板选中态：12 块里当前用的是哪一块，此前点了毫无回显（渐变预设 R41 管了、纯色板漏了） */
.swatch.active { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand), 0 0 0 3px rgba(124, 58, 237, .18); }
.app-dark .swatch.active { border-color: #a78bfa; box-shadow: inset 0 0 0 1px #a78bfa, 0 0 0 3px rgba(167, 139, 250, .22); }

/* 3）最近使用：标题行配一个清空钮（无记录时不摆空钮）、最新一枚给标记、空态给一句人话 */
.rc-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.rc-head .f-label { margin-bottom: 0; }
.rc-clear { border: 1px solid var(--line); background: var(--bg-soft); color: var(--ink-soft); font-size: 11px; line-height: 1; padding: 5px 10px; border-radius: 8px; cursor: pointer; transition: .15s; }
.rc-clear:hover { border-color: var(--brand); color: var(--brand-ink); }
.rc-clear:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.rc-clear[hidden] { display: none; }
.rc-swatch.rc-new { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand), 0 0 0 3px rgba(124, 58, 237, .18); }
.app-dark .rc-swatch.rc-new { border-color: #a78bfa; box-shadow: inset 0 0 0 1px #a78bfa, 0 0 0 3px rgba(167, 139, 250, .22); }
.rc-hint { font-size: 11.5px; grid-column: 1 / -1; }
@media (max-width: 768px) {
  .rc-clear { min-height: 40px; padding: 8px 14px; font-size: 12.5px; }
}

/* ============ R93 面板头部图标：emoji → 统一线性 SVG ============ */

/* 图标一律 16px 线性描边、随文字取色（currentColor），比 14.5px 粗体标题淡一档，层级更清楚。
   svg.pg-ico 比旧的 .pg-ico 多一层类型选择器，压得住 emoji 时代留下的 font-size 规则。 */
.ico-defs { display: none; }
svg.pg-ico {
  width: 16px; height: 16px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
  color: var(--ink-soft); transition: transform .15s, color .15s;
}
@media (max-width: 768px) {
  svg.pg-ico { width: 18px; height: 18px; }
}

/* ============ R94 四页排版复查（内容页与工具页统一图标语言 + 移动端触控目标） ============ */

/* 1) 页脚链接此前是裸 inline 文本，手机上整块只有 19px 高——它是全站最常被点的一组导航，
      必须够按；桌面保持原样（那里指针精细，改行高反而破坏紧凑的三栏节奏）。 */
@media (max-width: 768px) {
  .footer-links li { margin-bottom: 2px; }
  .footer-links a { display: inline-flex; align-items: center; min-height: 42px; font-size: 14.5px; }
}

/* 2）主题钮：emoji → 内联线性 SVG（图形由 common.js 单源注入，按钮盒子尺寸不变） */
.theme-ico { display: block; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

/* 3）首页功能卡图标同上一套线性语言；底板是品牌色浅染，故描边用品牌紫，暗底换浅紫墨 */
.card-icon svg { display: block; fill: none; stroke: var(--brand); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.app-dark .card-icon svg { stroke: #c4b5fd; }

/* ============ R96 滑杆行改造：标签 + 滑杆 + 可键入数值 同一行 ============ */

/* 1）数值框：平时看不出和旧回显有何不同，点进去才能改；右侧步进箭头始终占位（visibility 切换），
      聚焦时才显形——用 display 切换会让整行宽度跳一下。 */
.vnum { position: relative; display: inline-flex; align-items: center; gap: 2px; min-width: 0; }
input.val-num {
  width: 54px; min-width: 0; height: 26px; padding: 0 4px; text-align: right;
  font-size: 12.5px; font-weight: 800; color: var(--brand-ink); font-variant-numeric: tabular-nums;
  border: 1px solid transparent; border-radius: 7px; background: transparent;
  -moz-appearance: textfield; appearance: textfield;
}
input.val-num::-webkit-outer-spin-button, input.val-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input.val-num:hover { border-color: var(--line); background: var(--bg-soft); }
input.val-num:focus { outline: none; border-color: var(--brand); background: var(--card); color: var(--ink); }
.vunit { font-style: normal; font-size: 11px; font-weight: 700; color: var(--ink-soft); }
.vstep { display: flex; flex-direction: column; gap: 1px; visibility: hidden; }
.vnum:focus-within .vstep { visibility: visible; }
.vs {
  width: 15px; height: 10px; padding: 0; line-height: 8px; font-size: 7px;
  border: 1px solid var(--line); border-radius: 3px; background: var(--bg-soft); color: var(--ink-soft); cursor: pointer;
}
.vs:hover { border-color: var(--brand); color: var(--brand-ink); background: var(--card); }
.vs:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

/* 2）桌面 ≥769：三段一行（标签占满剩余、滑杆居中、数值靠右） */
.f-row:has(> input[type="range"]) { grid-template-columns: minmax(0, 1fr) minmax(70px, 1.15fr) auto; align-items: center; column-gap: 10px; }
.f-row:has(> input[type="range"]) > .f-label { grid-column: 1; grid-row: 1; }
.f-row:has(> input[type="range"]) > input[type="range"] { grid-column: 2; grid-row: 1; }
.f-row:has(> input[type="range"]) > .vnum { grid-column: 3; grid-row: 1; }

/* 3）窄屏 ≤768：数值仍与标签同行，滑杆独占下一行——390px 挤三段会把滑杆压到没法拖 */
@media (max-width: 768px) {
  .f-row:has(> input[type="range"]) { grid-template-columns: minmax(0, 1fr) auto; }
  .f-row:has(> input[type="range"]) > input[type="range"] { grid-column: 1 / -1; grid-row: 2; }
  .f-row:has(> input[type="range"]) > .vnum { grid-column: 2; grid-row: 1; }
  input.val-num { height: 34px; width: 62px; font-size: 16px; } /* iOS 聚焦不放大 */
  .vs { width: 18px; height: 14px; line-height: 12px; font-size: 8px; }
}

/* 4）色标位置子行（flex 布局）同样吃这套控件 */
.stop-pos .vnum { flex: none; }

/* ============ R99 画布尺寸：宽高一行 + 下拉不塌陷 ============ */

/* 1）「宽 [框] 高 [框]」排在同一行：标签紧贴自己的数值框，两对均分一行；
      极窄处允许换行（换成「宽高」两行也比把输入框挤到 40px 宽好拖）。 */
.wh-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.wh-row > .f-label { flex: none; margin-bottom: 0; }
.wh-row > .wh-inp { flex: 1 1 90px; min-width: 72px; width: auto; height: 34px; text-align: center; }
.wh-row > .wh-inp:focus { border-color: var(--brand); background: var(--card); }
@media (max-width: 768px) {
  .wh-row > .wh-inp { height: 40px; }
}

/* 2）下拉的 option 由 JS 填充，填充前它会塌成一条细线（刷新时看得见）——给它最小高度兜住 */
.f-row select.inp, select.inp { min-height: 38px; }
@media (max-width: 768px) {
  .f-row select.inp, select.inp { min-height: 44px; }
}

/* ============ R110 起：成对滑杆已改「一行一个」，R100 的「半宽列退回两行」层整体删除 ============
   （那层的 .f-row-2 .f-row:has(...) 特异性更高，会把三段同行的新层压回两行，留着就是死灰复燃。） */

/* ============ R101 上传字体版权提醒：暖底说明卡（明暗双主题令牌） ============ */
:root { --lic-ink: #4b4172; --lic-link: #7c3aed; }
:root.app-dark { --lic-ink: #d6cdef; --lic-link: #c4b5fd; }

/* ============ R110 滑杆行：一行一个 + 「标签 | 滑杆 | 数值」同行 ============ */
/* 1）成对滑杆（水平/垂直位置、阴影 X/Y、内阴影 X/Y、旋转/倾斜…）拆成一行一个：
      三段同行要占满整行宽度，两两并排时滑杆被挤到 120px 以下没法拖。 */
.f-row-2:has(input[type="range"]) { grid-template-columns: minmax(0, 1fr); row-gap: 0; }

/* 2）三段同行——桌面与窄屏同一套规则（R96 的 ≤768 两段回退被这里覆盖）：
      标签列可压缩（超出省略号 + title 补全文），滑杆吃掉剩余宽度且不低于 92px，数值列按内容自适应。 */
.f-row:has(> input[type="range"]) {
  grid-template-columns: minmax(0, max-content) minmax(112px, 1fr) auto;
  align-items: center; column-gap: 9px; row-gap: 0; margin: 9px 0;
}
.f-row:has(> input[type="range"]) > .f-label {
  grid-column: 1; grid-row: 1; margin-bottom: 0; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.f-row:has(> input[type="range"]) > input[type="range"] { grid-column: 2; grid-row: 1; }
.f-row:has(> input[type="range"]) > .vnum { grid-column: 3; grid-row: 1; }
@media (max-width: 768px) {
  .f-row:has(> input[type="range"]) { grid-template-columns: minmax(0, max-content) minmax(104px, 1fr) auto; column-gap: 8px; margin: 8px 0; }
  .f-row:has(> input[type="range"]) > input[type="range"] { height: 34px; } /* 触摸：整行都是拖拽热区 */
  input.val-num { width: 52px; }
}

/* 3）轨道：6px → 8px，并把「已走过」的一段染成品牌色（百分比由 JS 写进 --fill）
      暗色轨道是另一套底色，梯度必须各写一份——只写一条会被 .app-dark 的老规则压住（同源色令牌改动的老坑）。 */
:root { --rng-ring: rgba(124, 58, 237, .16); --rng-ring-2: rgba(124, 58, 237, .26); }
:root.app-dark { --rng-ring: rgba(196, 181, 253, .18); --rng-ring-2: rgba(196, 181, 253, .3); }
input[type=range]::-webkit-slider-runnable-track {
  height: 8px; border-radius: 4px;
  background: linear-gradient(90deg, var(--brand) 0 var(--fill, 50%), var(--line) var(--fill, 50%) 100%);
}
.app-dark input[type=range]::-webkit-slider-runnable-track {
  background: linear-gradient(90deg, var(--brand) 0 var(--fill, 50%), #3a3357 var(--fill, 50%) 100%);
}
input[type=range]::-moz-range-track { height: 8px; border-radius: 4px; background: var(--line); }
input[type=range]::-moz-range-progress { height: 8px; border-radius: 4px; background: var(--brand); }

/* 4）拇指：悬停/聚焦/拖动时套一圈品牌色光晕（只加阴影，边框宽度不变→几何不跳） */
input[type=range]::-webkit-slider-thumb { transition: box-shadow .15s ease; }
input[type=range]:hover::-webkit-slider-thumb { box-shadow: 0 0 0 5px var(--rng-ring), var(--shadow); }
input[type=range]:active::-webkit-slider-thumb, input[type=range]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 7px var(--rng-ring-2), var(--shadow); }
input[type=range]::-moz-range-thumb { transition: box-shadow .15s ease; }
input[type=range]:hover::-moz-range-thumb { box-shadow: 0 0 0 5px var(--rng-ring); }
input[type=range]:active::-moz-range-thumb { box-shadow: 0 0 0 7px var(--rng-ring-2); }

/* 5）数值框：平时像纯回显，聚焦才成「可编辑」的样子（边框 + 步进箭头显形） */
input.val-num:focus { box-shadow: 0 0 0 3px var(--rng-ring); }

/* R109：图片行的逐层说明 */
.img-note { margin: 2px 0 0; color: var(--ink-soft); }
.lic-line { margin-top: 6px; color: var(--lic-ink); }
.lic-more { margin-left: 6px; font-weight: 700; color: var(--lic-link); text-decoration: none; white-space: nowrap; }
@media (max-width: 768px) { .lic-more { padding: 6px 10px; margin: 2px -10px -6px -4px; border-radius: 999px; } }
.lic-more:hover, .lic-more:focus { color: #ffffff; background: var(--brand); border-radius: 999px; padding: 1px 7px; margin: -1px -7px; }

/* ============ R107 两侧面板页签：吸顶分组切换（与 .seg 同一套形状与圆角） ============ */
.col-tabs {
  position: sticky; top: 0; z-index: 4;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px;
  background: var(--bg-soft); box-shadow: 0 1px 0 var(--line);
  margin: 0 -14px 12px; padding: 14px 12px 10px;
}
.col-tab {
  border: 0; background: none; padding: 8px 4px; border-radius: 9px;
  font-size: 12.5px; font-weight: 700; color: var(--ink-soft); cursor: pointer; font-family: inherit;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: background .15s, color .15s;
}
.col-tab:hover { color: var(--brand-ink); background: rgba(255, 255, 255, 0.65); }
.app-dark .col-tab:hover { color: #c4b5fd; background: #2a2440; }
.col-tab.active { background: var(--card); color: var(--brand-ink); box-shadow: 0 2px 8px rgba(124, 58, 237, 0.15); }
.app-dark .col-tab.active { background: #2e2748; color: #c4b5fd; }
.tool-panel { padding-top: 0; }
/* 无 JS 时页签条收起，面板自己补回顶部间距 */
body:not(.js-on) .tool-panel { padding-top: 14px; }
.col-tab:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* 无 JS 时页签条没有行为可言：整条收起，面板全部照常显示 */
body:not(.js-on) .col-tabs { display: none; }
@media (max-width: 768px) {
  .col-tabs { margin: 0 -14px 12px; padding: 10px 10px 9px; }
  .col-tab { padding: 10px 2px; font-size: 13px; }
}

/* ============ R104 图层面板 ============ */
.ly-count { margin-left: auto; margin-right: 8px; min-width: 22px; padding: 1px 7px; border-radius: 999px; background: var(--grad-soft); color: var(--ink); font-size: 11.5px; font-weight: 800; }
.ly-list { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.ly-row { display: grid; grid-template-columns: 30px 1fr auto auto auto auto; align-items: center; gap: 4px; padding: 6px 6px 6px 4px; border-radius: 12px; background: var(--card); box-shadow: inset 0 0 0 1px var(--line); }
.ly-row.active { box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--bg-soft); }
.ly-row.off { opacity: .55; }
.ly-main { border: 0; background: none; text-align: left; cursor: pointer; padding: 2px 4px; color: var(--ink); font-family: inherit; min-width: 0; }
.ly-name { display: block; font-size: 12.5px; font-weight: 800; }
.ly-sum { display: block; font-size: 11px; color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ly-eye, .ly-mv { border: 0; background: none; cursor: pointer; color: var(--ink-soft); font-size: 13px; font-family: inherit; padding: 6px; border-radius: 8px; }
.ly-eye:hover, .ly-mv:hover, .ly-act:hover { background: var(--grad-soft); color: var(--ink); }
.ly-mv:disabled { opacity: .3; cursor: default; background: none; }
.ly-act { border: 0; background: none; cursor: pointer; color: var(--ink-soft); font-size: 11.5px; font-weight: 700; font-family: inherit; padding: 6px 7px; border-radius: 8px; white-space: nowrap; }
.ly-del { color: #c2325e; }
.app-dark .ly-del { color: #ff8aa8; }
.ly-main:focus-visible, .ly-eye:focus-visible, .ly-mv:focus-visible, .ly-act:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
@media (max-width: 768px) {
  .ly-row { grid-template-columns: 34px 1fr auto auto auto auto; padding: 5px 4px; }
  .ly-eye, .ly-mv, .ly-act { padding: 10px 8px; }
}

/* ============ R112 首页特性卡：图标在左 · 标题在右 · 说明另起一行 ============ */
/* 卡片只有首页这 8 张（fonts/templates/knowledge 都不复用 .card），所以直接给 .card 建网格是安全的。
   图标列按内容宽、标题列吃掉剩余宽度（minmax(0,1fr) 才能换行不溢出）；说明横跨两列另起一行。 */
.card { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 14px; }
.card > .card-icon { grid-column: 1; grid-row: 1; align-self: center; margin-bottom: 0; }
.card > h3 { grid-column: 2; grid-row: 1; align-self: center; margin-bottom: 0; min-width: 0; }
.card > p { grid-column: 1 / -1; grid-row: 2; margin-top: 13px; }

/* 悬停上浮自 R1xx 入场动画上线后一直是死的：[data-reveal].revealed{transform:none} 与 .card:hover
   特异度相同 (0,2,0) 且写在后面，把 translateY(-4px) 盖掉了。补在文件末尾（同特异度靠顺序取胜）把它救回来。 */
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
@media (max-width: 768px) {
  .card { column-gap: 12px; padding: 22px; }
  .card > .card-icon { width: 44px; height: 44px; border-radius: 13px; }
  .card > h3 { font-size: 16.5px; }
  .card > p { margin-top: 11px; }
}

/* ---------- R113：内容与法务页（使用教程 / 常见问题 / 关于我们 / 服务条款 / 隐私政策） ---------- */
.doc-wrap { max-width: 920px; margin: 0 auto; }
.doc-toc { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 13px 16px; margin-bottom: 24px; }
.doc-toc-h { font-size: 12px; font-weight: 800; letter-spacing: .6px; color: var(--ink-soft); margin-right: 4px; }
.doc-toc a { padding: 6px 13px; border-radius: 999px; background: var(--bg-soft); color: var(--ink-soft); font-size: 13.5px; font-weight: 700; transition: all .2s; }
.doc-toc a:hover { background: var(--grad-soft); color: var(--brand-ink); opacity: 1; }
.doc-toc a.here { background: var(--grad-soft); color: var(--brand-ink); box-shadow: inset 0 0 0 1.5px var(--brand); }
.doc-list { list-style: none; margin: 6px 0 2px; display: grid; gap: 11px; }
.doc-list li { position: relative; padding-left: 24px; color: var(--ink-soft); font-size: 15.5px; line-height: 1.78; }
.doc-list li::before { content: ''; position: absolute; left: 2px; top: .66em; width: 9px; height: 9px; border-radius: 3px; background: var(--grad); }
.doc-list li b { color: var(--ink); font-weight: 800; margin-right: 4px; }
.ext-list li { padding-left: 24px; }
.ext-list li a { display: inline-block; font-weight: 800; color: var(--brand-ink); font-size: 15px; overflow-wrap: anywhere; }
.ext-list li span { display: block; font-size: 13.5px; }
.legal-note { background: var(--grad-soft); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 24px 28px; margin-bottom: 22px; }
.legal-note h2 { font-size: 19px; font-weight: 900; margin-bottom: 10px; }
.legal-note p { color: #4b4172; font-size: 15px; line-height: 1.8; }
.legal-note .doc-list li { color: #43376c; }
.legal-note .hint-xs { color: #6f6398; }
.app-dark .legal-note p, .app-dark .legal-note .doc-list li { color: var(--ink-soft); }
.app-dark .legal-note .hint-xs { color: var(--ink-soft); }
.doc-card { background: var(--bg-soft); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px 22px; margin-top: 16px; }
.doc-card h3 { font-size: 16.5px; font-weight: 900; margin-bottom: 8px; }
.doc-card p { color: var(--ink-soft); font-size: 14.5px; line-height: 1.78; }
.doc-card-acts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.know-chapter .doc-card-acts:last-child, .doc-card .doc-card-acts { margin-bottom: 2px; }
.contact-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px; margin: 6px 0 18px; }
.contact-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.contact-lab { font-size: 12.5px; font-weight: 800; letter-spacing: .5px; color: var(--ink-soft); }
.contact-note { color: var(--ink-soft); font-size: 13.5px; line-height: 1.75; margin-top: 11px; }
.copy-mail { border: 1.5px solid var(--line); background: var(--bg-soft); color: var(--brand-ink); font-family: inherit; font-size: 16.5px; font-weight: 800; letter-spacing: .2px; padding: 10px 18px; border-radius: 13px; cursor: pointer; transition: border-color .2s, background .2s, color .2s; }
.copy-mail:hover { border-color: var(--brand); background: var(--grad-soft); opacity: 1; }
.copy-mail:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
.copy-mail.copied { border-color: #0f766e; background: #ecfdf5; color: #0f766e; }
.copy-mail.copy-fail { border-color: #b91c1c; background: #fef2f2; color: #b91c1c; }
.app-dark .copy-mail.copied { border-color: #5eead4; background: rgba(15, 118, 110, .24); color: #5eead4; }
.app-dark .copy-mail.copy-fail { border-color: #fca5a5; background: rgba(185, 28, 28, .26); color: #fca5a5; }
.tut-steps { display: grid; gap: 16px; counter-reset: tstep; margin-top: 8px; }
.tut-step { position: relative; display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 16px; align-items: start; background: var(--bg-soft); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px 22px; }
.tut-step::before { counter-increment: tstep; content: counter(tstep); grid-column: 1; grid-row: 1; width: 44px; height: 44px; border-radius: 14px; background: var(--grad); color: #fff; font-size: 18px; font-weight: 900; display: grid; place-items: center; }
.tut-step h3 { grid-column: 2; grid-row: 1; align-self: center; margin: 0; font-size: 17px; font-weight: 900; }
.tut-step p { grid-column: 1 / -1; grid-row: 2; margin: 6px 0 0; color: var(--ink-soft); font-size: 14.5px; line-height: 1.8; }
.footer-grid { grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 28px; }
/* R79 教训：末尾层叠会盖掉上方同名媒体查询，故窄屏断点在后面重新声明一次 */
@media (max-width: 768px) { .footer-grid { grid-template-columns: 1fr; gap: 26px; } .doc-toc { padding: 12px 14px; } .legal-note { padding: 20px 22px; } .know-chapter { padding: 24px 20px; } }
@media (max-width: 560px) { .tut-step { grid-template-columns: 1fr; gap: 10px; padding: 18px; } .tut-step h3 { grid-column: 1; grid-row: 2; } .tut-step p { grid-column: 1; grid-row: 3; } .doc-list li { font-size: 15px; } }

/* R113 补丁：文档页宽表在 420px 溢出（auto 布局会顶到 min-content 宽）→ 固定布局塞满容器并允许逐词折行 */
.doc-wrap .size-table { table-layout: fixed; width: 100%; }
.doc-wrap .size-table th:first-child, .doc-wrap .size-table td:first-child { width: 26%; }
.doc-wrap .size-table th, .doc-wrap .size-table td { overflow-wrap: anywhere; }
/* 原 .size-table td:nth-child(2) 为尺寸列设了 nowrap，宽表里会顶破容器 → 文档页一律放行折行 */
.doc-wrap .size-table td:nth-child(2) { white-space: normal; }
@media print { .doc-toc, .back-top { display: none !important; } .legal-note, .know-chapter, .contact-card, .tut-step { break-inside: avoid; } }

/* ---------- R115b：语言切换单颗钮（中文态「中」/ 英文态「EN」） ---------- */
/* 两个字形宽度不同（中 14px vs EN 22px），给个下限免得每次切换导航跟着抖一下 */
.btn-lang { min-width: 52px; justify-content: center; letter-spacing: .6px; }
@media print { .btn-lang { display: none !important; } }

/* ---------- R116：教程配图（真实界面截图） ---------- */
.doc-fig { margin: 20px 0 6px; }
.doc-fig img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-soft); }
.doc-fig figcaption { margin-top: 10px; font-size: 13px; line-height: 1.75; color: var(--ink-soft); text-align: center; }
/* 局部特写图按原尺寸上限显示，拉满会被插值放大糊掉。
   尺寸上限写在 figure 上而不是 img 的 width:auto —— lazy 图在滚动到之前 intrinsic 为 0，
   img 会塌成边框宽度（实测 2px），图片到达瞬间整块弹出、图注下移；写在容器上则空盒也占位。 */
.doc-fig-narrow { width: 287px; max-width: 100%; margin-left: auto; margin-right: auto; }
.doc-fig-narrow img { margin: 0 auto; }
@media (max-width: 560px) { .doc-fig { margin: 16px 0 4px; } .doc-fig figcaption { font-size: 12.5px; } }
@media print { .doc-fig { break-inside: avoid; } }

/* ---------- R117：仅「在线制作」页导航放宽（其余 10 页保持 1180 居中） ---------- */
/* tool 页下方工作台整屏出血，导航却仍按 .container 的 min(1180px,92%) 居中：
   实测 1600 屏上导航壳只有 1180，5 个入口以 4px 间距挤在左半，右侧空出 420px。
   这里把该页导航壳拉到整屏（留 20px 呼吸），间距与内边距只在桌面档放宽，
   ≤899px 的汉堡面板尺寸交给既有规则，免得动掉 R113/R114 钉过的触摸高度。 */
.page-tool .nav-inner { width: calc(100% - 40px); max-width: none; }
@media (min-width: 900px) {
  .page-tool .nav-menu { gap: 10px; }
  .page-tool .nav-link { padding: 8px 16px; }
}

/* ---------- R119：首页 hero 演示卡加浓（纸堆叠层 + 品牌柔光 + 画布内嵌感） ---------- */
/* 原来是一张平白卡片浮在平底色上：加一张反向倾斜的衬纸做厚度、加一层品牌径向柔光，
   画布与徽标/浮标补上发丝环与落影，读起来像"摆在桌上的设计稿"而不是贴上去的方块。
   横向只探出 10px：320px 屏上 .container(92%) 距视口只剩 13px 余量，再多就顶出横向滚动条。 */
.hero-demo { position: relative; isolation: isolate; }
.hero-demo::before {
  content: ''; position: absolute; inset: 22px -10px -16px 20px;
  background: var(--grad-soft); border: 1px solid var(--line);
  border-radius: var(--radius-lg); transform: rotate(-2.4deg); z-index: -2;
  transition: transform .35s ease;
}
.hero-demo::after {
  content: ''; position: absolute; inset: -14px -10px;
  background: radial-gradient(48% 44% at 62% 36%, rgba(124, 58, 237, .22), transparent 70%),
              radial-gradient(42% 40% at 28% 74%, rgba(236, 72, 153, .18), transparent 72%);
  filter: blur(8px); z-index: -3; pointer-events: none;
}
.demo-card {
  position: relative; z-index: 1;
  background: linear-gradient(168deg, var(--card), var(--bg-soft));
  box-shadow: var(--shadow-lg), 0 18px 40px rgba(124, 58, 237, .10);
}
.demo-canvas { border-radius: 16px; box-shadow: 0 0 0 1px var(--line), 0 14px 30px rgba(124, 58, 237, .16); }
.demo-badge { box-shadow: 0 10px 24px rgba(236, 72, 153, .42), 0 0 0 3px var(--bg); }
.demo-float {
  background: color-mix(in srgb, var(--card) 86%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--shadow-lg);
}
.demo-float .dot { box-shadow: 0 0 0 4px rgba(34, 197, 94, .16); animation: demoDot 2.4s ease-in-out infinite; }
@keyframes demoDot { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.3); opacity: .7; } }
/* hover 规则必须关在 (hover: hover) 里：R41 的触屏豁免块在本层之前，
   同特异性的后置规则会把它的 transform:none 顶掉，触屏点完卡片就"粘"在浮起态 */
@media (hover: hover) {
  .demo-card:hover { transform: rotate(0deg) translateY(-4px) scale(1.012); }
  .hero-demo:hover::before { transform: rotate(-1.2deg) translate(5px, 5px); }
}
@media (max-width: 620px) {
  .hero-demo::before { inset: 16px -6px -12px 14px; }
  .hero-demo::after { inset: -10px -6px; }
}
/* 动效豁免不在此另写一层：style.css 顶部 R41 的
   @media (prefers-reduced-motion: reduce) { * { transition:none !important; animation:none !important } }
   已覆盖本轮新增的呼吸点与过渡，重复声明就是死规则。 */

/* ---------- R127：顶部菜单整体靠右 ---------- */
/* .nav-menu 本来就 flex:1 吃掉中间余量，链接默认贴左 → 五个入口挤在品牌旁边、右侧空一大片。
   改成 flex-end 后入口贴着语言/主题钮排成一列，品牌仍居最左。
   ≤899px 的抽屉是 flex-direction:column + align-items:stretch，justify-content 只管主轴（此时是纵向），
   不会把面板里的链接也横排——已由 r127 在 700/390 两档实测钉住。 */
.nav-menu { justify-content: flex-end; }

/* ---------- R128：居中区块下面的动作行必须同轴 ---------- */
/* 首页 FAQ 收成预览后，两颗入口钮沿用 .doc-card-acts 的左对齐，挂在居中的问答列下面
   就成了掉出版面的孤儿行；这里让"居中区块里的动作行"自己居中。 */
.faq-more { justify-content: center; }

/* ---------- R124：面板内的轻量二级折叠（上传字体区默认收起） ---------- */
/* 顶层面板用的是 .pg-head 那套重型头（图标 + 大字），嵌进面板会像二级面板；
   这里用原生 <details>：默认收起、键盘可达、焦点与展开态浏览器自己管，不另写状态机。 */
.sub-fold { display: block; padding: 0; }
.sub-fold-h { display: flex; align-items: center; justify-content: space-between; gap: 10px; cursor: pointer; list-style: none; user-select: none; padding: 6px 0; border-radius: 8px; }
.sub-fold-h::-webkit-details-marker { display: none; }
.sub-fold-h::after { content: ''; width: 8px; height: 8px; border-right: 1.5px solid var(--ink-soft); border-bottom: 1.5px solid var(--ink-soft); transform: rotate(45deg) translate(-2px, -2px); transition: transform .2s; flex: none; }
.sub-fold[open] > .sub-fold-h::after { transform: rotate(-135deg) translate(-3px, -3px); }
.sub-fold-h:hover { color: var(--brand-ink); }
.sub-fold-b { padding: 2px 0 4px; }
@media print { .sub-fold { display: block; } .sub-fold > .sub-fold-b { display: block !important; } }

/* ---------- R126：颜色行三件套（标签 + 色块 + 颜色代码框）同一行 ---------- */
/* 代码框是"能自己敲"的入口，高度必须与色块严格相等（成对控件同尺寸）；宽度按 7 字符（#RRGGBB）定，
   等宽字体是本站对代码类数据的统一规矩。两列并排的色对改成上下两行——三件套塞进半列必然互相挤压。 */
/* 注意特异性：R74 时代有一条 `.f-row:has(> input[type="color"]) { display:grid; ... }`，
   :has() 会把参数算进特异性 → 它比裸类选择器高，必须用同样带 :has 的复合选择器才压得住，
   否则代码框会被那张旧网格推到第二行（实测 hexY=42、色块高被钳成 30px）。 */
.f-row.color-row:has(> input[type="color"]),
.sw-row.color-row:has(> input[type="color"]),
.color-row { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; }
/* 标签给固定基准宽：三件套的色块/代码框要在竖排的多行里对齐成两条竖线，
   标签按内容缩的话「描边颜色」和「渐变颜色二」会把色块推到不同 x 上（实测左缘差 ≥4px）*/
.color-row > .f-label { flex: 0 0 104px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 0; }
.f-row.color-row:has(> input[type="color"]) > input[type="color"],
.color-row > input[type=color] { flex: none; width: 46px; height: 40px; border-radius: 10px; padding: 3px; }
.color-row > input.inp-hex, .inp-hex {
  flex: 0 1 92px; min-width: calc(7ch + 20px); width: 92px; height: 40px;
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
  font-size: 13px; letter-spacing: .4px; text-transform: uppercase;
}
.inp-hex.bad { border-color: #dc2626; box-shadow: 0 0 0 3px rgba(220, 38, 38, .16); }
.app-dark .inp-hex.bad { border-color: #f87171; box-shadow: 0 0 0 3px rgba(248, 113, 113, .22); }
/* 两列并排的网格只要含色块就改上下堆叠：半列宽（~179px）塞不下 104+46+92 三件，
   不堆叠的话代码框会被挤到色块下面一行（实测 dy=42、宽 179）。用 :has 覆盖"格子里直接角色块"
   与"格子里再套 .f-row"两种嵌套形态。 */
.f-row-2:has(.color-row) { display: block; }
.f-row-2:has(.color-row) > * + * { margin-top: 8px; }
@media (max-width: 560px) {
  .color-row { gap: 8px; }
  .color-row > .f-label { flex-basis: 76px; }
  .color-row > input.inp-hex, .inp-hex { flex-basis: 80px; width: 80px; }
}

/* ---------- R132：画布上的图层选择框与旋转手柄 ---------- */
.layer-hud { position: absolute; inset: 0; pointer-events: none; z-index: 4; display: none; }
.layer-hud.on { display: block; }
.layer-hud .hud-frame {
  position: absolute; box-sizing: border-box; border: 1.5px solid var(--brand); border-radius: 8px;
  box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .62); pointer-events: none; transform-origin: 50% 50%;
}
.app-dark .layer-hud .hud-frame { box-shadow: 0 0 0 1.5px rgba(20, 16, 38, .55); }
/* 手柄收在框内侧，不往外探——画布容器是 overflow:auto，探出去会顶出滚动条 */
.layer-hud .hud-rot {
  position: absolute; left: 50%; top: 5px; width: 16px; height: 16px; margin-left: -8px;
  border-radius: 50%; background: var(--brand); border: 1.5px solid #fff; box-sizing: border-box;
  box-shadow: 0 1px 4px rgba(24, 18, 54, .3); pointer-events: auto; cursor: grab; touch-action: none;
}
.app-dark .layer-hud .hud-rot { border-color: #f5f3ff; }
.layer-hud .hud-rot:active { cursor: grabbing; }
.layer-hud.tight .hud-rot { display: none; }
@media print { .layer-hud { display: none !important; } }

/* ---------- R133：下划线 / 删除线各自成框（开哪条露哪个，框头写明是哪条线） ---------- */
.deco-box {
  border: 1.5px solid var(--card-line); border-radius: 12px; padding: 10px 12px 12px;
  margin-top: 10px; background: var(--grad-soft);
}
.app-dark .deco-box { border-color: var(--card-line-dark); }
.deco-box-h {
  font-size: 12.5px; font-weight: 700; letter-spacing: .4px; color: var(--brand-ink); margin-bottom: 6px;
}
.app-dark .deco-box-h { color: #c4b5fd; }

/* ---------- R136：上传字体区整块加框（用户点名「这些内容用一个框，框起来」） ---------- */
/* 框语言与 R133 的 .deco-box 同一套（1.5px 描边 + 12px 圆角 + --grad-soft 浅染底），
   暗色只换描边不另加深底，免得折叠区看着像第二层面板。summary 标题留在框外：
   框的是内容，那行可点的标题本身不该被框成一个假卡纸。 */
.sub-fold-b {
  border: 1.5px solid var(--card-line); border-radius: 12px;
  padding: 12px 12px 13px; margin-top: 4px; background: var(--grad-soft);
}
.app-dark .sub-fold-b { border-color: var(--card-line-dark); }
/* 装饰底色上的小字要独立深墨 token：.hint-xs 原本按 --ink-soft 算，压在渐变底上明暗两态都得重审。
   注意别顺手给 .lic-more 也写一条：(0,3,0) 会压过 .lic-more:hover (0,2,0) 的反白态（r101 D1c 抓到）。
   链接色交给 --lic-link 令牌，它本来就是为渐变底配的双主题值。 */
.sub-fold-b .hint-xs { color: #4c3d6b; }
.app-dark .sub-fold-b .hint-xs { color: #d9d3f0; }

/* ---------- R136：抽屉里那 2px 横向橡皮筋滚动（实测 320/360 都中） ---------- */
/* .col-tabs 的负 margin 是用来抵消面板 14px 内边距做全出血吸顶条的；≤480 面板内边距收成 12px，
   负 margin 还留在 -14 → 页签条比内容盒宽 4px，面板 scrollWidth 就多出 2px。两者必须同源。 */
@media (max-width: 480px) {
  .col-tabs { margin-left: -12px; margin-right: -12px; }
}

/* ---------- R136：图层行加「重命名 + 拖拽排序」，三个动作钮自成一行 ---------- */
/* 原来 6 列网格一对一塞 6 个直接子元素；现在把复制/重命名/删除收进 .ly-acts 容器另起一行，
   300px 宽的面板里三个文字动作钮再和 ↑↓ 挤同一行，必然被压成省略号（同 R125 的教训）。 */
.ly-row { grid-template-columns: 30px 1fr auto auto; row-gap: 2px; }
.ly-acts { grid-column: 1 / -1; display: flex; gap: 4px; justify-content: flex-end; align-items: center; }
.ly-row[draggable="true"] { cursor: grab; }
.ly-row.dragging { opacity: .45; cursor: grabbing; }
.ly-row.drop-target { box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--grad-soft); }
.ly-name-inp { width: 100%; min-width: 0; font-size: 12.5px; font-weight: 800; padding: 2px 6px; border-radius: 7px; }
@media (max-width: 768px) {
  .ly-row { grid-template-columns: 34px 1fr auto auto; }
}

/* ---------- R136：选择框四角缩放手柄 ---------- */
/* 手柄一律收在框内侧：.tool-canvas-wrap 是 overflow:auto，往外探就凭空多一条滚动条（R132 同一条规矩）。
   只在精确指针上出现——14px 的抓取点在触摸上是假 affordance，手指该走「字号」滑杆。 */
.layer-hud .hud-sz { display: none; }
@media (hover: hover) and (pointer: fine) {
  .layer-hud .hud-sz {
    display: block; position: absolute; width: 14px; height: 14px; box-sizing: border-box;
    background: var(--card); border: 1.5px solid var(--brand); border-radius: 4px;
    pointer-events: auto; touch-action: none;
  }
  .layer-hud .hud-sz:hover { background: var(--brand); }
  .hud-sz-nw { left: 3px; top: 3px; cursor: nwse-resize; }
  .hud-sz-se { right: 3px; bottom: 3px; cursor: nwse-resize; }
  .hud-sz-ne { right: 3px; top: 3px; cursor: nesw-resize; }
  .hud-sz-sw { left: 3px; bottom: 3px; cursor: nesw-resize; }
}
.app-dark .layer-hud .hud-sz { border-color: #c4b5fd; }

/* ---------- R137：带自己内边距的卡片里，行基准必须跟着收（用户点名"这个排版存在问题"） ---------- */
/* R126 的三件套基准（标签 104 + 色块 46 + 代码框 92 + 两个 10 间距 = 262）是按"面板满宽"定的；
   塞进 R133 的 .deco-box 后行只剩 227px（320 视口只剩 190），nowrap 就把代码框顶出框外——
   实测 hex 的 scrollWidth 比 clientWidth 多 7px，#7C3AE5 少显示一位（用户截图里那个 #7C3AE）。
   规则：卡片里的标签与代码框都能收缩、色块略窄、间距收窄；滑杆行同理，标签让宽才有拖拽行程。 */
.deco-box { padding: 10px 10px 12px; }
.deco-box .color-row { gap: 6px; }
.deco-box .color-row > .f-label { flex: 0 1 76px; min-width: 56px; }
.deco-box .color-row > input[type=color] { width: 40px; }
.deco-box .color-row > input.inp-hex { flex: 1 1 76px; min-width: calc(7ch + 20px); }
/* R144 修正：这条写的是 flex 规则，可滑杆行是 grid 容器——flex 是空操作，而 min-width:64px 会让标签
   实物盒宽过它自己那一列（实测列宽 33.5、盒宽 64），整块压进滑杆，滑块正好盖住最后一个字（用户截图点名）。
   列宽交给 R144 层的「标签列先给足 + 装不下改两排」。 */
/* 数值那一格是 R96 的 span.vnum 包着 input.val-num——flex 项是外面那颗 span，
   只写 .val-num 永远匹配不上（实测被挤到 17px 只放得下一个数字）。 */
.deco-box .f-row > .vnum, .deco-box .f-row > .val, .deco-box .f-row > .val-num { flex: 0 0 auto; min-width: 34px; }
@media (max-width: 480px) {
  .deco-box { padding: 8px; }
  .deco-box .f-row { gap: 4px; }
  .deco-box .color-row { gap: 4px; }
  .deco-box .color-row > .f-label,
  .deco-box .f-row:has(> input[type="range"]) > .f-label { flex-basis: 64px; }
  /* 320 视口里代码框只剩 86px，等宽 13px + .4 字距的 #RRGGBB 要 95px → 少 9px 就吃掉最后一位。
     缩字号与字距，不缩标签：标签被截是丢语义，代码框被截是丢一个字符。 */
  .deco-box .color-row > input.inp-hex { font-size: 12px; letter-spacing: 0; padding-left: 4px; padding-right: 4px; }
  .deco-box .color-row > input[type=color] { width: 36px; }
}

/* ============ R139 导出进面板、动作钮进工具条（末尾追加层） ============ */
/* 1) 面板里的导出区：倍率栅格独占一行（不再被工具条挤压），PNG 是主导出所以满宽，
      其余四种格式 2×2 等分、方案两颗各占一半——每一行都排得满，不留半空行。 */
.export-row { margin: 12px 0; }
.export-row > .btn-block { margin-bottom: 8px; }
.export-more { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
/* R170：备份/恢复两颗钮改一行一个——两字动词加四字宾语挤在半格里会断成「备份全部数/据」 */
.plan-row { display: grid; grid-template-columns: 1fr; gap: 8px; margin: 12px 0; }
/* 2) 工具条动作簇：与缩放簇同一基线；窄屏随单行滑动容器一起排，不换行压高度。 */
/* R162：旧的动作簇容器类已被 tb-group 取代，这三条规则永远匹配不到元素——留着就是一盏没人看的灯。
   （R156 之后工具条按钮全是 .act-btn.ico-btn，自带 padding:0 与固定宽。注释里不写那个类名，
     是因为 r34/r105 那类"残留归零"扫描会把注释里的字面量也算一份。） */
/* 4) 倍率档搬进面板后就成了「面板里的分段钮」，从此归 r88 Z2a 那套截断门禁管：
      英文标签是 1x Standard 这种长串，≤480 四等分一定咬字。窄屏改 2×2，一行两档读得完。 */
.panel-group { container-type: inline-size; container-name: pg; }
/* 量的是面板组自己的宽度而不是视口：1100px 视口下面板只有 237px，视口口径根本量不到。
      老浏览器不认 @container，就用 ≤480 的视口兜底（抽屉态）。 */
/* R160：导出倍率改原生下拉（#exportScaleSeg 现在是 <select>），这条为网格胶囊写的规则永远匹配不到元素，删净 */
/* R160：导出倍率改原生下拉（#exportScaleSeg 现在是 <select>），这条为网格胶囊写的规则永远匹配不到元素，删净 */


/* ============ R140 我的样式：横排整行卡（末尾追加层） ============ */
/* 原先两列窄卡里四颗文字钮被 flex-wrap 挤成一列竖排胶囊（用户截图点名）。改成一行一卡：
   缩略图定宽在左，名称与操作钮在右各占一行；四颗钮走 2×2 等分栅格——桌面态右栏只有 ~107px
   可用宽度，一行四颗一定咬字，两行两颗才排得满。 */
.my-styles-grid { grid-template-columns: 1fr; gap: 10px; }
.my-style-card { display: grid; grid-template-columns: 104px minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 10px; align-items: center; padding: 8px; }
.my-style-card canvas { grid-column: 1; grid-row: 1 / 3; width: 104px; height: 70px; aspect-ratio: auto; border-radius: 8px; }
.my-style-card .ms-name { grid-column: 2; grid-row: 1; padding: 0; font-size: 13px; }
.my-style-card .ms-actions { grid-column: 2; grid-row: 2; padding: 0; margin-top: 6px; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.my-style-card .ms-actions button, .my-style-card .ms-actions .apply { flex: none; min-width: 0; font-size: 11.5px; padding: 5px 2px; }
/* 提醒行：小字灰墨，说清「存在哪、怎么备份」。 */
.ms-note { margin-top: 12px; font-size: 11.5px; line-height: 1.7; color: var(--ink-soft); }
@media (max-width: 480px) {
  .my-style-card { grid-template-columns: 84px minmax(0, 1fr); }
  .my-style-card canvas { width: 84px; height: 56px; }
}

/* ============ R142 渐变色标：一个色标一张卡（末尾追加层） ============ */
/* 原来「色标位置 N」一行、色条一行，两行之间没有任何归属线索，读起来像两组无关控件。
   改成一个色标一张卡：卡头是编号 + 位置滑杆 + 百分比，卡体是这条色标的取色器与删除钮。
   第二色的取色器常驻在上方「渐变颜色二」里，所以它只有卡头，用同一种卡片节奏排，避免孤行。 */
.fill-stop, .fill-stops > .stop-head {
  border: 1.5px solid var(--line); border-radius: 12px; background: var(--card);
  padding: 8px 10px;
}
.fill-stop { display: flex; flex-direction: column; gap: 8px; }
.fill-stop .stop-pos { padding: 0; border: 0; background: none; }
.fill-stops { gap: 8px; }
/* 卡头：编号标签定宽、滑杆吃满剩余、百分比贴右缘——三档宽度下同一节奏 */
.stop-pos .f-label { flex: none; min-width: 46px; font-weight: 800; color: var(--ink); }
.stop-pos input[type=range] { flex: 1 1 88px; min-width: 88px; }
/* 卡体：色块从整行大条收成 40px 方块（与面板其它颜色控件同尺寸、同触控目标），删除钮与它等高 */
.fill-stop-side { display: flex; align-items: center; gap: 8px; }
.fill-stop-side input[type=color] { flex: none; width: 40px; height: 40px; padding: 0; border-radius: 10px; }
.fill-stop input[type=color] { height: 40px; }
.fill-stop-del { width: 40px; height: 40px; border-radius: 10px; font-size: 14px; }
/* 添加钮：虚线框 + 品牌色，一眼看出是"往这组里再加一条"，而不是又一个动作 */
.fill-stops + .btn-block { margin-top: 8px; border-style: dashed; border-color: var(--brand); color: var(--brand-ink); }
@media (max-width: 480px) {
  /* 窄屏不再挤成一行：卡头与卡体各占一行，色块仍然 40px，滑杆吃满 */
  .stop-pos .f-label { min-width: 40px; }
}

/* ============ R143 镂空描边与被它盖住的开关（末尾追加层） ============ */
/* 置灰只降透明度、不加装饰；disabled 的开关本身点不动，标题行负责说明是谁盖住了它。 */
.sw-row.shadowed { opacity: .45; }
.sw-row.shadowed .slider { cursor: not-allowed; }
/* R145：被色板盖住的单色格同样置灰——沿用 R143 那条 opacity .45 的视觉语言（.shadowed 现在是通用态） */
.f-row.shadowed { opacity: .45; }
.f-row.shadowed input { cursor: not-allowed; }
.sw-row.shadowed input[type=checkbox]:focus-visible + .slider { outline: 0; }

/* ============ R152 全屏预览：真全屏与页面内覆盖层共用一套版面 ============ */
/* 两条路都要：隐藏编辑浮层与抽屉、画布按屏幕重新 fit。底色用页面自己的 --bg 而不是硬写深色——
   工具条里的按钮文字走主题令牌，强制深底会把浅色主题下的按钮变成"深字压深底"。 */
.tool-stage:fullscreen, .tool-stage.stage-full { background: var(--bg); padding: 0; }
.tool-stage:fullscreen #layerHud, .tool-stage.stage-full #layerHud { display: none !important; }
.tool-stage:fullscreen .tool-drawer-btn, .tool-stage.stage-full .tool-drawer-btn { display: none; }
.tool-stage.stage-full { position: fixed; inset: 0; z-index: 300; }
body.full-lock { overflow: hidden; }

/* ============ R144 滑杆行：标签先给足宽度，装不下就整行改两排（用户三张截图点名） ============ */
/* 1）两排回退得按「这一行到底多宽」判，视口宽度说了不算——同一视口下左栏 253、右栏 257、卡片里只剩 231。
   所以把行的直接容器（面板正文 / 嵌套卡片）声明成查询容器。 */
.pg-body { container-type: inline-size; container-name: pgb colr; }
.deco-box { container-type: inline-size; container-name: card colr; }
/* 2）标签列先按内容给足（上限 112px，再长才省略号 + title 兜底），滑杆保底 80px 仍可拖，数值列自适应。
   旧规则 minmax(0, max-content) 的 min 是 0，一挤就先吃标签：5 个字的「描边透明度」在 237px 行里被截掉 9px。 */
.f-row:has(> input[type="range"]) { grid-template-columns: fit-content(112px) minmax(80px, 1fr) auto; }
/* 中文标签最长 5 字（63px）永远一行排完；英文同义的标签有 20 字符，硬撑一行就只能把尾巴截掉
   （实测 "Inner shadow strength" 在 257px 行里只剩 "Inner shadow s"）。截掉的词是语义损失，
   触屏又查不到 title——所以超宽就折行，滑杆保住 80px 行程，一个字都不裁。 */
.f-row:has(> input[type="range"]) > .f-label { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.25; }
/* 3）连「标签 + 80px 滑杆 + 数值」都排不下时，滑杆独占第二排、吃满整行宽——拖拽行程从 80px 变成 230px，
   比把标签截掉划算得多。卡片里的行比面板还窄 20px，所以两个容器各钉各的阈值。 */
@container pgb (max-width: 226px) {
  .f-row:has(> input[type="range"]) { grid-template-columns: minmax(0, 1fr) auto; }
  .f-row:has(> input[type="range"]) > .f-label { grid-column: 1; grid-row: 1; }
  .f-row:has(> input[type="range"]) > .vnum { grid-column: 2; grid-row: 1; }
  .f-row:has(> input[type="range"]) > input[type="range"] { grid-column: 1 / -1; grid-row: 2; }

}
@container card (max-width: 226px) {
  .f-row:has(> input[type="range"]) { grid-template-columns: minmax(0, 1fr) auto; }
  .f-row:has(> input[type="range"]) > .f-label { grid-column: 1; grid-row: 1; }
  .f-row:has(> input[type="range"]) > .vnum { grid-column: 2; grid-row: 1; }
  .f-row:has(> input[type="range"]) > input[type="range"] { grid-column: 1 / -1; grid-row: 2; }
}
/* 4）颜色行同病：代码框在 237/216px 的行里少显示一位（#7C3AED 只剩 #7C3AE），整行还往外溢 5px。
   标签改成可收缩——同栏多行的基准与收缩系数相同，缩也一起缩同样的量，两条竖线仍对齐。
   代码框的保底宽度不写死数字：#RRGGBB 就是七个字符，calc(7ch + 20px) 现读元素自己的字号——
   桌面 13px、≤768 因 iOS 聚焦放大规矩升到 16px、卡片 ≤480 又压回 12px，三档各算各的够宽框；
   为每档补一个常量＝下一处「少显示一位」的来源。 */
.color-row > .f-label { flex: 0 1 104px; min-width: 66px; white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.25; }
.color-row > .inp-hex, .inp-hex { flex: 0 1 92px; min-width: calc(7ch + 20px); padding-left: 8px; padding-right: 8px; letter-spacing: 0; }
/* 3b）颜色三件套的折行阈值单独定：三件套的最小宽度是 66(标签)+8+46(色块)+8+75(代码框) ≈ 203，
     滑杆行两排回退要 236——共用一个数会把本来放得下的色卡也拆成两行（实测 1280 下色块与代码框差 50px，
     R126 的竖线契约直接破）。所以同一个容器起两个名字：range 看 card/pgb，颜色行看 colr。
     位置必须在这两条基础规则之后：容器查询不改特异性，写在前面会被 .color-row > .f-label 顶掉，
     卡片里的色卡就排成「标签+色块 / 代码框单独一行」——色块与代码框不同轴，R126 C5 报的就是它。 */
@container colr (max-width: 208px) {
  /* 选择器必须带 :has，否则 (0,1,0) 压不住 R126 那条 flex-wrap:nowrap */
  .f-row.color-row:has(> input[type="color"]), .color-row { flex-wrap: wrap; }
  .f-row.color-row:has(> input[type="color"]) > .f-label, .color-row > .f-label { flex: 0 0 100%; min-width: 0; margin-bottom: 4px; }
}
/* ≤480 行只剩 216px：66(标签)+8+46(色块)+8+87(16px 字号的代码框) = 215 会往外戳 2px。
   收的是色块（40px，与卡片里同一档），不折行——R126 的「标签|色块|代码框」三件套同行是既定契约。 */
@media (max-width: 480px) {
  .color-row > input[type=color] { width: 40px; }
}
/* ============ R146 滑杆行三段预算随卡片收紧（末尾追加层） ============ */
/* 卡片（.fx-box）比面板正文又窄 20px：原来「5 字标签 + 9px 间距 + 80px 滑杆 + 数值」要 234px，
   在 233px 的卡里刚好差 1px 而被迫折成两排——面板凭空长高 24 行。
   让出 12px（数值列 52→46、列间距 9→8）后同一行仍排得下，滑杆实测 89~91px，r137 钉的 ≥88px 契约不破。 */
.f-row:has(> input[type="range"]) { column-gap: 8px; }
input.val-num { width: 46px; }
/* 5）半栏里的开关行：英文一个词就有 13 个字母（Strikethrough），排不下时开关换到第二行——
      标签一个字不裁，开关也还在原地可点（实测 320 视口整行原本戳出正文 23px）。
      这里只留这一道保护：曾同时改过「列 minmax(0,1fr)」，变异跑批证明它不承重（撤掉后全站零红），
      留着只会让人以为有两层保险。 */
.f-row-2 .sw-row { flex-wrap: wrap; }

/* ============ R146 相关功能收进同一个方框（沿用 R133/R136 的卡片语言，不另造一套视觉） ============ */
/* 三张卡（R133 的 .deco-box、R136 的 .sub-fold-b、R146 的 .fx-box）共用同一根描边色，
   抽成一个令牌改一处全站跟；再抄第二份数字＝下一处"看着像同一种卡其实不是"。 */
:root { --card-line: rgba(124, 58, 237, .26); --card-line-dark: rgba(196, 181, 253, .26); }
/* 一个开关和它管辖的子控件同吃一张卡：卡内不再画虚线（框本身就是分隔），
   首尾行的外边距收掉，免得卡里卡外两层留白叠成 24px。 */
.fx-box { border: 1.5px solid var(--card-line); border-radius: 12px; padding: 10px 10px 12px; margin: 0 0 10px; background: var(--grad-soft);
  container-type: inline-size; container-name: card colr; }
.app-dark .fx-box { border-color: var(--card-line-dark); }
.fx-box > :first-child { margin-top: 0; }
/* R110 那条 .f-row:has(> input[type="range"]) { margin: 9px 0 } 特异性更高，裸写 :first-child 顶不过它——
   描边四张卡的首行因此还带着 9px（卡内卡外两层留白）。规则要按同形状重写一遍。 */
.fx-box > .f-row:first-child:has(> input[type="range"]), .fx-box > .f-row:first-child:has(> select), .fx-box > .f-row:first-child:has(> input[type="color"]) { margin-top: 0; }
.fx-box > :last-child { margin-bottom: 0; }
/* 卡内不画虚线＝不需要 `.fx-box .sep-dashed{display:none}` 这条规则：卡片化那一轮已把全站唯一的
   虚线类 <hr class="sep-dashed"> 全部删净（r146 B2/E6 双向钉住）。留着一条永远匹配不到元素的规则，
   等于挂一盏永远不会亮的灯。 */
.fx-box-h { font-size: 12.5px; font-weight: 700; letter-spacing: .4px; color: var(--brand-ink); margin-bottom: 6px; }
.app-dark .fx-box-h { color: #c4b5fd; }
/* 渐变底上的小字要独立深墨 token（R136 同一条规矩）：图片纹理块的说明、底板卡的提示都走它 */
.fx-box .hint-xs { color: #4c3d6b; }
.app-dark .fx-box .hint-xs { color: #d9d3f0; }
/* 卡里再套卡（波浪/弹跳在「弧形文字」卡内）只留描边不重复上底色，否则浅染底叠两层会发灰 */
.fx-box .fx-box { background: transparent; }

/* ============ R156 工具条改图标显示（用户红框点名：适应/全屏/左右居中/上下居中/随机风格/随机配色/撤销/重做/清空文字/重置全部） ============ */
/* 一条图标语言：整条工具条统一走内联 SVG，不再混 ▦ − + 这类吃字体渲染、各平台字形不一致的字符。
   svg 尺寸写两道：HTML 上的 width/height 属性 + 这里一道 CSS——没有固有尺寸的 inline svg 会按 300×150 撑开，压垮 flex 兄弟。 */
.tool-toolbar svg.tb-ico, .tool-drawer-btn svg.tb-ico { display: block; width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* 方形图标钮：宽高都写死 px（分排宽度一律用 px，勿靠 flex-grow——某些浏览器 CSSOM 上 grow 不生效会量出 0 宽）。
   文案搬进 aria-label（读屏）+ title（悬停 tooltip），图标语言不牺牲可读性；触控目标沿用既有的 ≥38 桌面 / ≥40 移动规则。 */
.act-btn.ico-btn { display: inline-flex; align-items: center; justify-content: center; width: 38px; padding: 0; }
@media (max-width: 768px) { .act-btn.ico-btn { width: 40px; height: 40px; } }
/* 图标钮的选中/禁用态走 currentColor，棋盘格开启时与 hover 同一支品牌色，不额外画底 */
.act-btn.ico-btn.active svg.tb-ico { stroke-width: 2; }
/* 抽屉钮在 .tool-toolbar 之外（绝对定位浮在画布左上角），比工具条大一号才按得住。 */
.tool-drawer-btn svg.tb-ico { width: 20px; height: 20px; }
/* R157：底板图案六挡排一行会把「棋盘格」这类三字标签截掉（35 盒吃 42 文，搬家前在左栏是 34/42，同一件事）。 */
#plaquePatternSeg { grid-auto-flow: row; grid-template-columns: repeat(3, 1fr); }

/* ============ R158 色标卡：一张卡一个色标 + 顶部渐变预览条 ============ */
/* 预览条：真实渐变当底，刻度点标出色标落在哪儿——"色标是什么"用眼睛回答，不靠说明书。 */
.stop-ramp-wrap { margin: 0 0 8px; }
.stop-ramp { position: relative; height: 26px; border-radius: 8px; border: 1px solid var(--line); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .35); }
.app-dark .stop-ramp { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12); }
.ramp-tick { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; border-radius: 2px; background: var(--ink); box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .85); }
.app-dark .ramp-tick { box-shadow: 0 0 0 1.5px rgba(20, 14, 34, .8); }
.ramp-ends { display: flex; justify-content: space-between; font-size: 10.5px; font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; margin-top: 3px; letter-spacing: .3px; }
.stop-hint { margin: 4px 0 0; }
/* 一张卡一行：编号在左、位置居中、色块与删除在右——原来"编号+滑杆"一张卡、"色块"另一张卡，
   第一张卡没颜色、最后一张卡没编号，看起来像渲染坏了。 */
/* 一张卡两行（沿用 R142 量过的形状）：235px 的栏里一行塞不下「编号+滑杆+色块+代码框+删除」，
   而且删不掉的那颗删除钮会让色块左右跳——分行后色块都在第二行左端，纵着看是一条直线。 */
.fill-stop.stop-card { display: block; border: 1.5px solid var(--card-line); border-radius: 11px; padding: 7px 9px 8px; margin: 0 0 6px; background: var(--bg-soft); }
.app-dark .fill-stop.stop-card { border-color: var(--card-line-dark); background: #16121f; }
.fill-stop.stop-card:last-of-type { margin-bottom: 0; }
.stop-head { display: flex; align-items: center; gap: 8px; min-width: 0; min-height: 29px; } /* 29px：带滑杆的行与带 0%/100% 胶囊的行同高，一列卡上下沿才齐 */
.fill-stop .stop-head > .f-label { margin-bottom: 0; } /* .f-label 基础规则带 4px 下边距，卡内第一行不需要 */
.stop-name { font-size: 12px; font-weight: 800; color: var(--ink); letter-spacing: .2px; white-space: nowrap; }
.stop-fix { font-size: 11.5px; font-weight: 800; color: var(--brand-ink); font-variant-numeric: tabular-nums; padding: 2px 7px; border-radius: 7px; background: var(--grad-soft); cursor: help; }
.app-dark .stop-fix { color: #c4b5fd; }
.fill-stop .stop-pos { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 6px; }
.fill-stop .stop-pos input[type="range"] { flex: 1 1 auto; min-width: 56px; }
.fill-stop-side { display: flex; align-items: center; gap: 6px; margin-top: 6px; }
.stop-cell { display: flex; align-items: center; gap: 6px; min-width: 0; }
/* 常驻那两个取色器进卡后，卡头已经写着「色标 1/2」，行内那份标签就收掉——
   同一张卡里出现两个名字才是这次"看着像坏了"的根因。输入框的可读名由 JS 写成「色标 N」。 */
.stop-cell.in-card > .f-label { display: none; }
.stop-cell.in-card { margin: 0; }
/* 被相邻色标夹住时的就地说明：静默回弹会被读成"控件坏了"，说一句就自解。 */
.stop-stuck { display: none; font-size: 10.5px; font-weight: 700; color: #b45309; line-height: 1.25; }
.app-dark .stop-stuck { color: #fbbf24; }
.stop-stuck.on { display: block; }
.fill-stop input[type="range"]:disabled { opacity: .45; cursor: not-allowed; }
@container card (max-width: 208px) { .stop-head { flex-wrap: wrap; } .fill-stop .stop-pos input[type="range"] { min-width: 44px; } }
/* R158：色标卡的「编号 + 滑杆 + 百分比」一行只有 217px（卡片内边距吃掉 18px），
   回显里的 ±1% 步进箭头再吃 15px 就会把滑杆压到 82px——低于 r142 B2 承诺的 88px「滑杆吃到剩余宽度」。
   位置本来就是拖的（要精确值直接键入），步进箭头在这一行让位；实测滑杆回到 99px。 */
.stop-head .vnum .vstep { display: none; }
/* ============ R159 特效家族卡：把同一族的效果收进同一个方框（用户点名：投影与霓虹发光看着是两件事，其实同族） ============ */
/* 一个容器只留一种节奏源：家族卡用 gap 排节，节内首尾元素的上下边距归零，否则 gap+margin 会叠成 24px。 */
.fx-fam { display: flex; flex-direction: column; gap: 15px; padding: 10px 10px 12px; }
.fx-fam > .fx-box-h { margin-bottom: 0; }
.fx-eff > :first-child { margin-top: 0; }
.fx-eff > :last-child { margin-bottom: 0; }
/* R110 那条 .f-row:has(> input[type="range"]) { margin: 8px 0 } 的特异性比裸 :last-child 高，顶不过它——
   节内首尾是这类行时要按同样的形状各补一条，否则长投影那一节尾巴多出 9px、家族卡里的节奏从 15 变成 24（A5 量"看得见的空隙"才揭出来）。 */
.fx-eff > :last-child:has(> input[type="range"]), .fx-eff > :last-child:has(> select), .fx-eff > :last-child:has(> input[type="color"]),
.fx-eff > :first-child:has(> input[type="range"]), .fx-eff > :first-child:has(> select), .fx-eff > :first-child:has(> input[type="color"]) { margin-top: 0; margin-bottom: 0; }
/* 节与节之间不画线（R146 B2：框本身就是分隔），靠效果名加重来立小节标题。 */
.fx-eff > .sw-row .f-label { font-weight: 800; color: var(--ink); }

/* ============ R162 美化轮：工具条分簇、页签 segmented、面板头层级、画布纸浮、首页卡片密度 ============ */
/* 1) 工具条分簇（R162 把 13 颗图标钮按功能分成视图｜对齐｜生成｜历史｜清理）：组内 6px、组间 10px。
      分组只靠"空气"表达——分隔线/装饰条是历史上被逐个点名删掉的东西，不再加回来。 */
.tb-group { display: flex; align-items: center; gap: 6px; flex: none; }
.tool-toolbar > .tb-group { margin-left: 10px; }
/* 2) 页签条：从"贴着面板顶的文字链"改成一条带浅染底的吸顶容器 + 选中白底浮起，
      让人一眼看出这是切换整栏内容的主导航，而不是几排普通链接。
      这条是 position:sticky 的吸顶件，两个写法是有命门的：底色必须写 background-color（实色）而不是
      只交给 --grad-soft 那支渐变——渐变是 background-image，背景色仍是透明的，r107 R6 会当场判它漏底；
      圆角必须是 0——圆角会把背景一起裁掉，滚动内容正好从四个楔形缝里钻出来。胶囊感落在 .col-tab 自己身上。 */
.col-tabs { margin: 0 0 12px; padding: 6px 5px; gap: 3px; background-color: var(--bg-soft); background-image: var(--grad-soft); box-shadow: 0 1px 0 var(--line); }
.app-dark .col-tabs { background-color: #221c33; }
.col-tab { padding: 9px 4px; }
.col-tab.active { font-weight: 800; box-shadow: 0 3px 10px rgba(124, 58, 237, .20); }
.app-dark .col-tab.active { box-shadow: 0 3px 10px rgba(0, 0, 0, .45); }
/* 3) 面板头：浅染带 + 一根同色发丝线收尾。标题(14.5px/800 主墨) 与字段标签(12.5px 次级墨) 分属两层，
      之前两层只差颜色，扫一眼分不清"这是标题还是又一个字段"。 */
.panel-group > .pg-head { background: var(--grad-soft); box-shadow: inset 0 -1px 0 rgba(124, 58, 237, .14); }
.app-dark .panel-group > .pg-head { background: #221c33; box-shadow: inset 0 -1px 0 rgba(196, 181, 253, .16); }
/* 4) 画布：双层柔和投影做出"纸浮在桌上"。描边仍是那一圈 1px 品牌色——加粗边框不是这里的语言。 */
#toolCanvas { border-radius: 10px; box-shadow: 0 14px 34px rgba(28, 10, 54, .15), 0 3px 8px rgba(28, 10, 54, .10); }
.app-dark #toolCanvas { box-shadow: 0 14px 34px rgba(0, 0, 0, .55), 0 3px 8px rgba(0, 0, 0, .35); }
/* 5) 首页：功能卡图标底加一圈同色发丝、标题抬一档；三步卡编号块加大、正文与功能卡同级。
      抬到 18px 要把标题列腾出来：九字的那两条名字在 160px 列里是 162px，会折成两行，
      同一排八张卡的说明文字就参差了（r112 A5 钉"一行放得下"）。列宽从间距与内边距两侧各让一点：
      图标↔标题 14→12（r112 的下限就是 12px，不再低）、卡内边距 26→24 → 列宽 166px。 */
.card-icon { box-shadow: inset 0 0 0 1px rgba(124, 58, 237, .16); }
.card h3 { font-size: 18px; }
.card { padding: 24px; column-gap: 12px; }
.step { padding: 32px 26px 28px; }
.step::before { top: -19px; width: 38px; height: 38px; box-shadow: 0 8px 18px rgba(236, 72, 153, .38); }
.step h3 { font-size: 17px; }
/* 6) 首页字体条：卡高与行数一致（8 张 4 列 2 行），说明两行封顶——长描述不许把某一张卡顶高。 */
.font-chip { padding: 20px 16px 16px; min-width: 0; }
.font-chip .sample { font-size: 30px; text-overflow: ellipsis; }
/* min-width:0 是必需的：示例串 white-space:nowrap，1fr 轨默认 min-width:auto 会被它顶到 172px，
   360px 视口下整条字体带横向溢出 14px——轨道收缩后由省略号收尾。≤420 再收一档，让「艺术字 Aa」
   五个字形在双列里完整可读，而不是靠裁字过关。 */
@media (max-width: 420px) {
  .font-chip { padding: 16px 12px 14px; }
  .font-chip .sample { font-size: 23px; }
}
.font-chip .desc { margin-top: 7px; font-size: 12px; line-height: 1.5; color: var(--ink-soft); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 36px; }
.app-dark .font-chip .desc { color: #b9b0d6; }
/* 7) 桌面图标钮收到 35px 正方形：1440 这一档单行还差 39px，与其让最后一组被渐隐藏住，
      不如 13 颗一起收 3px——收的是鼠标指针下的余量，手指不吃亏。
      两个限定都不是可有可无：min-height 被 R39 的「≥769 统一 38px」条款压着，只写 height 会量出
      35×38 的竖长方形（成对控件同形状是红线）；min-width 是因为 ≤768 的 40px 触控目标写在更前面，
      不限定窗口宽的话，35px 会一路盖到手机上。 */
@media (hover: hover) and (pointer: fine) and (min-width: 769px) { .tool-toolbar .act-btn.ico-btn { width: 35px; height: 35px; min-height: 35px; } }


/* ============ R163 首页 hero：特效墙与浮层归属 ============ */
/* 1) 徽标与浮标曾被演示卡盖掉半截（R119 给 .demo-card 加了 z-index:1，而这两颗是 z-index:auto，
      于是 absolute 的它们排在带层级的卡片之下——用户红箭头指的就是这个）。归属要显式写：浮层在卡片之上。 */
.demo-badge, .demo-float { z-index: 3; }
/* 2) 卡内留白收一档：墙有 6 格，框越厚越像相框而不是作品；说明行与卡片同宽、次级墨。 */
.demo-card { padding: 20px; }
.demo-cap { margin-top: 12px; text-align: center; font-size: 12.5px; font-weight: 700; letter-spacing: .3px; color: var(--ink-soft); }
.app-dark .demo-cap { color: #b9b0d6; }

/* ============ R164 暗色选中态品牌紫补齐（全站体检：对比度 <3:1 的两处） ============ */
/* 亮色下 .nav-link.active / .seg button.active 用 var(--brand)（#7c3aed）。
   暗色底分别是 #221c33 渐变与 #2e2748，实测只有 2.5:1——小字（13/12.5px）根本读不动。
   同族的 .act-btn.active、.col-tab.active 早就各自提亮到 #c4b5fd，这两处是漏网，不是设计选择。 */
.app-dark .nav-link.active { color: #c4b5fd; }
.app-dark .seg button.active { color: #c4b5fd; }

/* ============ R164 品牌前景 token（一处收口整族暗色对比度） ============ */
/* --brand 同时被当文字色与描边/底色用：暗色下把"前景"这一路单独提成 #c4b5fd，
   其余（渐变底上的白字、描边轨迹）不受影响。与 .act-btn.active / .col-tab.active 用的是同一支浅紫。 */
:root { --brand-ink: var(--brand); }
.app-dark { --brand-ink: #c4b5fd; }

/* R171：字体卡上的体积，与许可徽标同一行、同一档次级墨色（不新造色值） */
.fc-size { margin-left: 6px; font-variant-numeric: tabular-nums; }

/* ============ R168 老浏览器诚实提示条 ============ */
/* 缺特性时不静默变形：一条可关闭的状态条说清楚"是浏览器旧了，功能没坏"。
   颜色走既有 token，不新造色值；提示条本身不用 :has/color-mix，否则老浏览器正好看不见它。 */
#legacyHint { display: flex; align-items: center; gap: 10px; width: min(1180px, 92%); margin: 12px auto 14px;
  padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--bg-soft);
  color: var(--ink); font-size: 13px; font-weight: 600; line-height: 1.55; }
#legacyHint .lh-ico { flex: none; width: 10px; height: 10px; border-radius: 50%; background: #f59e0b; }
#legacyHint .lh-txt { flex: 1 1 auto; min-width: 0; }
#legacyHint .lh-x { flex: none; width: 28px; height: 28px; border: 0; border-radius: 8px;
  background: transparent; color: var(--ink-soft); font-size: 18px; line-height: 1; cursor: pointer; }
#legacyHint .lh-x:hover { background: var(--card); color: var(--ink); }
.app-dark #legacyHint { background: #221c33; color: #e9e4f7; }
.app-dark #legacyHint .lh-x { color: #b9b0d6; }
.app-dark #legacyHint .lh-x:hover { background: #2e2748; color: #ffffff; }
