/* style.css — 365Lab Word Cloud. Light + dark theme, desktop + mobile responsive. */

:root {
  --bg: #f2f4fb;
  --panel: #ffffff;
  --panel2: #f7f8fd;
  --ink: #1c2333;
  --muted: #667085;
  --line: #e5e8f2;
  --brand: #4a57ec;  /* R115: deepened from #5b6cf9 (4.24:1) so brand TEXT/links/highlights clear WCAG AA 4.5:1 on all light surfaces */
  --brand-fill: #4f46e5; /* white text on brand fills passes WCAG AA; --brand deepened to #4a57ec so brand TEXT/links also clear 4.5:1 on light surfaces */
  --brand-2: #8b5cf6;
  --accent: #ec4899;
  --grad: linear-gradient(135deg, #2563eb, #4f46e5 55%, #be185d); /* white-text-safe stops (all ≥6:1); old bright cyan/pink failed AA at 2.1/3.5 */
  --danger: #c0392b;  /* R116: deepened from #e5484d (3.54:1 on #f2f4fb) so .btn-link.danger text clears WCAG AA 4.5:1 */
  --ok: #16a34a;
  --radius: 14px;
  --radius-sm: 9px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .05), 0 8px 24px -12px rgba(16, 24, 40, .12);
  --shadow-lg: 0 12px 40px -8px rgba(16, 24, 40, .22);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  --brand-soft: rgba(74, 87, 236, .14);
  --brand-soft: color-mix(in srgb, var(--brand) 14%, transparent);
  --surface: var(--panel2);
  --text: var(--ink);
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --input: var(--panel2);
}

[data-theme="dark"] {
  --bg: #0e1320;
  --panel: #161d30;
  --panel2: #1c2440;
  --ink: #e9edf7;
  --muted: #aab4cc;
  --line: #273252;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .5);
  --shadow-lg: 0 12px 40px -8px rgba(0, 0, 0, .6);
  --brand-soft: rgba(129, 140, 248, .24);
  --brand-soft: color-mix(in srgb, var(--brand) 24%, transparent);
  /* In dark mode the page surfaces are much darker, so the light-tuned brand
     indigo reads as ~4:1 text — below AA. Lift it for TEXT on dark surfaces,
     and keep a deeper indigo (--brand-fill) for white-on-brand FILLS so the
     white label stays ≥6:1. Danger likewise needs lifting as text. */
  --brand: #818cf8;
  --brand-fill: #4f46e5;
  --danger: #f87171;
}

/* Dark-mode transparency checker: light gray on dark panel (Photoshop-style)
   so the empty canvas area clearly signals "transparent" instead of blending
   into the page background. */
[data-theme="dark"] .canvas-wrap {
  background:
    linear-gradient(45deg, color-mix(in srgb, var(--muted) 22%, transparent) 25%, transparent 25%, transparent 75%, color-mix(in srgb, var(--muted) 22%, transparent) 75%) 0 0 / 22px 22px,
    linear-gradient(45deg, color-mix(in srgb, var(--muted) 22%, transparent) 25%, transparent 25%, transparent 75%, color-mix(in srgb, var(--muted) 22%, transparent) 75%) 11px 11px / 22px 22px,
    var(--panel2);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
.hidden { display: none !important; }
.muted { color: var(--muted); font-size: 12px; }
.hint { color: var(--muted); font-size: 12px; margin: 6px 0 0; }
.shape-fill-hint { border-left: 3px solid var(--brand); background: var(--brand-soft); border-radius: 8px; padding: 8px 10px; color: var(--text); font-size: 12px; line-height: 1.65; margin-top: 10px; }
.shape-outline-ctl { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel2); display: flex; flex-direction: column; gap: 8px; }
.shape-outline-ctl .check { font-size: 13px; font-weight: 600; }
.outline-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.outline-row .label { font-size: 12px; color: var(--muted); margin: 0; }
.outline-row input[type=color] { width: 34px; height: 26px; padding: 0; border: 1px solid var(--line); border-radius: 6px; background: none; cursor: pointer; }
.outline-row input[type=range] { flex: 1; min-width: 80px; max-width: 160px; }
.out-val { font-size: 12px; color: var(--muted); min-width: 14px; text-align: center; }
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }
/* ...but buttons are not prose links. Anchor-based buttons inherit the rule above,
   so every button element/role opts out; genuine text links keep their underline. */
.btn, .btn:hover, .btn:focus-visible, .btn:active,
.nav-cta, .nav-cta:hover, .nav-cta:focus-visible,
.email-copy, .email-copy:hover, .email-copy:focus-visible,
.brand-link, .brand-link:hover, .brand-link:focus-visible,
button, button:hover, button:focus-visible { text-decoration: none; }

/* Clear, consistent keyboard focus indicator for all interactive elements */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 6px;
}
/* Don't draw the outline on mouse click (only keyboard) — the gradient brand
   text and range thumbs already have their own focus treatment. */
a.brand-link { display: inline-flex; align-items: center; min-height: 24px; }
a.brand-link:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 10px; }
.brand-name:focus-visible { outline: none; }

.skip-link {
  position: absolute; left: -999px; top: 0; z-index: 99;
  background: var(--brand-fill); color: #fff; padding: 8px 14px; border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }
/* Skip-link target: receives focus on activation but must not paint a ring */
#app:focus, #app:focus-visible { outline: none; }

/* ================= Top bar ================= */
.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 18px;
  padding: 10px 20px;
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
.brand .logo { flex: none; filter: drop-shadow(0 3px 6px rgba(99, 102, 241, .35)); }
.brand-text h1, .brand-text .brand-name {
  display: block; margin: 0; font-size: 17px; line-height: 1.2; white-space: nowrap;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.tagline { margin: 0; font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-nav { display: flex; gap: 16px; margin-left: 8px; }
.top-nav a { color: var(--muted); font-size: 13px;
  /* WCAG 2.5.8 target size: 13px text is only 20px tall */
  display: inline-flex; align-items: center; min-height: 24px; }
.top-nav a:hover { color: var(--brand); text-decoration: none; }
.top-actions { margin-left: auto; display: flex; align-items: center; gap: 10px; }
/* Content-width top bar: the bar itself stays full-bleed (background + bottom border
   reach the viewport edges) while its contents are constrained to the same column as
   <main>.  main is 1340px incl. 20px gutters -> 1300px here, since .topbar already
   pads 20px, so the brand/nav line up exactly with the page content on wide screens.
   tool.html deliberately keeps the full-width bar (no .topbar-inner wrapper). */
.topbar-inner { width: 100%; max-width: 1300px; margin: 0 auto; display: flex; align-items: center; gap: 18px; }

.icon-btn {
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--panel2); color: var(--ink);
  cursor: pointer; font-size: 15px; display: grid; place-items: center;
  transition: transform .15s;
}
.icon-btn:hover { transform: translateY(-1px); }

.lang-switch {
  display: flex; border: 1px solid var(--line); border-radius: 999px; overflow: hidden;
  background: var(--panel2);
}
.lang-switch button {
  border: 0; background: transparent; color: var(--muted);
  padding: 6px 13px; font-size: 12.5px; cursor: pointer; font-family: inherit;
}
.lang-switch button.active {
  background: var(--grad); color: #fff; font-weight: 600;
}

/* ================= Layout ================= */
main { max-width: 1340px; margin: 0 auto; padding: 18px 20px 40px; }
/* Tool page: full-width layout (no 1340px cap) */
body.tool-page main { max-width: none; padding: 16px 18px 40px; }
body.tool-page .workspace { grid-template-columns: 430px minmax(0, 1fr); gap: 20px; }
@media (min-width: 1700px) { body.tool-page .workspace { grid-template-columns: 460px minmax(0, 1fr); } }
.workspace {
  display: grid; grid-template-columns: 390px minmax(0, 1fr);
  gap: 18px; align-items: start;
}
.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.side-panel { padding: 14px; position: sticky; top: 66px; max-height: calc(100vh - 84px); overflow-y: auto; min-width: 0; }
.stage-panel { padding: 14px; display: flex; flex-direction: column; gap: 12px; min-width: 0; }

/* Tabs */
.tabs {
  display: flex; gap: 4px; padding: 4px;
  background: var(--panel2); border-radius: 10px; margin-bottom: 12px;
}
.tab {
  flex: 1; border: 0; background: transparent; color: var(--muted);
  padding: 8px 4px; font-size: 13.5px; border-radius: 8px; cursor: pointer;
  font-family: inherit; transition: all .15s;
}
.tab.active { background: var(--panel); color: var(--ink); font-weight: 600; box-shadow: var(--shadow); }
/* Word-count badge next to the 词表 section heading — rendered via ::after so a
   language switch (which rewrites the heading text) cannot strip it. It sits on the
   heading, not on the 词表 tab. */
.group-title[data-count]:not([data-count="0"])::after {
  content: " (" attr(data-count) ")";
  font-size: 11px; font-weight: 500; opacity: .7;
  margin-left: 2px; font-variant-numeric: tabular-nums;
}
.pane { display: none; }
.pane.active { display: block; animation: fadeIn .2s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

/* Fields */
.field { margin-bottom: 14px; }
.label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink); margin-bottom: 6px; }
label.label { cursor: pointer; }
.gap { margin-top: 12px; }

textarea, input[type="text"], select {
  width: 100%; padding: 9px 11px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--panel2); color: var(--ink);
  font-family: inherit; font-size: 13.5px; outline: none;
  transition: border-color .15s, box-shadow .15s;
}
textarea { resize: vertical; line-height: 1.6; }
textarea:focus, input[type="text"]:focus, select:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent);
}
.textarea-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 5px; }
.mini-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.btn-link {
  border: 0; background: transparent; color: var(--brand);
  font-size: 12px; cursor: pointer; padding: 0; font-family: inherit;
  /* WCAG 2.5.8: 12px text is only ~22px tall */
  display: inline-flex; align-items: center; min-height: 24px;
}
.btn-link:hover { text-decoration: none; color: color-mix(in srgb, var(--brand) 68%, var(--ink)); }
.btn-link.danger:hover { color: color-mix(in srgb, var(--danger) 74%, var(--ink)); }
.btn-link.danger { color: var(--danger); }

/* R33 — 内容输入区（textarea + 字数 + 工具条）精细化 (incremental; no DOM change). */
/* 字数计数：等宽数字 + 细微胶囊，数字变化不抖动且读起来像刻意徽章。 */
#charCount {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, var(--muted) 14%, transparent);
}
/* textarea 头部与 textarea 间加一点节奏。 */
.textarea-head { margin-bottom: 8px; }
/* mini-actions：清晰间距 + 柔和 hover 背景，扩大点击热区。 */
.mini-actions { gap: 12px; }
.mini-actions .btn-link { padding: 3px 6px; border-radius: 5px; font-weight: 500; }
.mini-actions .btn-link:hover { background: color-mix(in srgb, var(--brand) 10%, transparent); }

/* Segmented control */
.seg { display: flex; gap: 4px; padding: 3px; background: var(--panel2); border-radius: 9px; flex-wrap: wrap; }
.seg-btn {
  flex: 1; border: 0; background: transparent; color: var(--muted);
  padding: 7px 8px; border-radius: 7px; cursor: pointer; font-size: 12.5px;
  font-family: inherit; white-space: nowrap; transition: all .15s;
}
.seg-btn.active { background: var(--brand-fill); color: #fff; font-weight: 600; }
.seg.mini { flex: none; }
.seg.mini .seg-btn { flex: none; padding: 4px 10px; font-size: 12px; }

/* Buttons */
.btn {
  border: 1px solid var(--line); background: var(--panel2); color: var(--ink);
  padding: 8px 14px; border-radius: 9px; font-size: 13px; cursor: pointer;
  font-family: inherit; transition: all .15s; white-space: nowrap;
  min-height: 36px; /* default; .stage-toolbar overrides to 38px (incl. .btn.primary) for visual parity with the canvas chrome */
}
.btn:hover { border-color: var(--brand); color: var(--brand); }
.btn.primary {
  background: var(--grad); border: 0; color: #fff; font-weight: 600;
  box-shadow: 0 4px 14px -4px color-mix(in srgb, var(--brand) 60%, transparent);
}
.btn.primary:hover { color: #fff; transform: translateY(-1px); filter: brightness(1.06); }
.btn.ghost { background: transparent; }
.btn.sm { padding: 5px 10px; font-size: 12px; border-radius: 7px; }
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.row > select { flex: 1; min-width: 0; }

/* Accordion (details) */
.acc { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 8px 10px; background: var(--panel2); }
.acc summary { cursor: pointer; font-size: 13px; font-weight: 600; user-select: none; }
.acc[open] summary { margin-bottom: 10px; }
.check { display: flex; align-items: center; gap: 7px; font-size: 13px; margin: 7px 0; cursor: pointer; }
.check input { accent-color: var(--brand); width: 15px; height: 15px; }

/* Shapes */
/* Wrap onto as many rows as needed instead of a single scrolling row: 10 category
   tabs no longer fit one line, and the horizontal scrollbar looked like clutter. */
.shape-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.shape-tab { flex: 0 0 auto; border: 1.5px solid var(--line); background: var(--panel2); color: var(--muted); padding: 6px 11px; font-size: 12.5px; border-radius: 999px; cursor: pointer; font-family: inherit; white-space: nowrap; transition: all .15s; }
.shape-tab:hover { border-color: var(--brand); color: var(--brand); }
.shape-tab.active { background: var(--brand-fill); color: #fff; border-color: var(--brand-fill); font-weight: 600; }
.shape-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.shape-btn {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 4px 8px; border: 1.5px solid var(--line); border-radius: 10px;
  background: var(--panel2); color: var(--muted); cursor: pointer;
  font-family: inherit; font-size: 11.5px; transition: all .15s;
}
.shape-btn svg { width: 26px; height: 26px; }
.shape-btn:hover { border-color: var(--brand); color: var(--brand); }
.shape-btn.active {
  border-color: var(--brand); color: var(--brand);
  background: color-mix(in srgb, var(--brand) 8%, var(--panel2));
  font-weight: 600;
}
.mask-preview { margin: 8px 0; }
.mask-preview img { max-width: 110px; max-height: 80px; border-radius: 8px; border: 1px solid var(--line); background: #fff; }

/* Palettes */
.palette-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.palette-btn {
  display: flex; align-items: center; gap: 8px;
  border: 1.5px solid var(--line); border-radius: 10px; background: var(--panel2);
  padding: 8px 10px; cursor: pointer; font-family: inherit; font-size: 12px;
  color: var(--ink); transition: all .15s;
}
.palette-btn:hover { border-color: var(--brand); }
.palette-btn.active { border-color: var(--brand); box-shadow: 0 0 0 2.5px color-mix(in srgb, var(--brand) 22%, transparent); font-weight: 600; }
.palette-swatches { display: flex; gap: 2px; flex: none; }
.palette-swatches i { width: 10px; height: 16px; border-radius: 2.5px; display: block; }

/* Harmony color generator */
.harmony-card-wrap .row { margin-top: 8px; }
.harmony-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 10px; }
.harmony-card {
  display: flex; flex-direction: column; gap: 6px; align-items: stretch;
  border: 1.5px solid var(--line); border-radius: 10px; background: var(--panel2);
  padding: 8px; cursor: pointer; font-family: inherit; font-size: 12px;
  color: var(--ink); transition: all .15s;
}
.harmony-card:hover { border-color: var(--brand); transform: translateY(-1px); }
.harmony-sw { display: flex; gap: 2px; height: 18px; }
.harmony-sw i { flex: 1; border-radius: 3px; display: block; min-width: 4px; }

.color-pair { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.color-pair label { font-size: 12px; color: var(--muted); display: block; margin-bottom: 2px; }
input[type="color"] {
  width: 44px; height: 32px; padding: 2px; border: 1px solid var(--line);
  border-radius: 7px; background: var(--panel2); cursor: pointer;
  /* R87 — 色块被 flex 行挤成 2px 竖线（轮廓颜色看不见）：色块永不收缩，宁可换行 */
  flex: none;
}

/* Chips */
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  border: 1px solid var(--line); background: var(--panel2); color: var(--ink);
  padding: 4px 11px; border-radius: 999px; font-size: 12px; cursor: pointer;
  font-family: inherit; transition: all .15s; display: inline-flex; align-items: center; gap: 5px;
}
.chip:hover { border-color: var(--brand); color: var(--brand); }
.chip .cnt { color: var(--muted); font-size: 11px; }
.chip .swatch { width: 14px; height: 14px; border-radius: 4px; display: inline-block; border: 1px solid rgba(0,0,0,.12); }
/* Compact action chips: keeps icon-only chips tight instead of full-width pills. */
.chip.icon { padding: 4px 8px; }

/* Sliders */
input[type="range"] {
  width: 100%; appearance: none; -webkit-appearance: none; height: 6px;
  background: var(--line); border-radius: 999px; outline: none; margin: 8px 0 2px;
  min-height: 24px;
}
input[type="range"]::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%;
  background: var(--grad); border: 2.5px solid #fff; cursor: pointer;
  box-shadow: 0 1px 5px rgba(0, 0, 0, .25);
}
input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--brand-fill); border: 2.5px solid #fff; cursor: pointer;
}
input[type="range"]:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 25%, transparent); }
.field output { font-size: 12px; color: var(--brand); font-weight: 700; float: right; margin-top: -20px; }
.range-row { gap: 10px; }
.range-row input { flex: 1; margin: 0; }

/* ================= Stage ================= */
.stage-toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.stats { margin-left: auto; }

.canvas-wrap {
  position: relative; border-radius: 12px; overflow: hidden;
  border: 1px solid var(--line);
  background:
    linear-gradient(45deg, color-mix(in srgb, var(--line) 55%, transparent) 25%, transparent 25%, transparent 75%, color-mix(in srgb, var(--line) 55%, transparent) 75%) 0 0 / 22px 22px,
    linear-gradient(45deg, color-mix(in srgb, var(--line) 55%, transparent) 25%, transparent 25%, transparent 75%, color-mix(in srgb, var(--line) 55%, transparent) 75%) 11px 11px / 22px 22px,
    var(--panel2);
  min-height: 300px; display: grid; place-items: center;
}
.canvas-bg {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-size: cover; background-position: center; background-repeat: no-repeat;
  transform-origin: center;
}
#wcCanvas { display: block; max-width: 100%; height: auto; position: relative; z-index: 1; }
#wcCanvas.entrance { animation: pop .45s ease; }
@keyframes pop { from { opacity: .25; transform: scale(.985); } to { opacity: 1; transform: none; } }

.empty-state {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px; text-align: center;
  padding: 24px; background: var(--panel2);
}
.empty-state h2 { margin: 0; font-size: 17px; }
.empty-state p { margin: 0; color: var(--muted); font-size: 13px; max-width: 420px; }
.empty-cloud { font-size: 44px; animation: floaty 3s ease-in-out infinite; }
@keyframes floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }

.wc-tip {
  position: absolute; z-index: 5; pointer-events: none;
  background: rgba(20, 26, 40, .92); color: #fff;
  padding: 5px 10px; border-radius: 7px; font-size: 12px; white-space: nowrap;
  transform: translate(-50%, -135%); box-shadow: var(--shadow);
}

.render-busy {
  position: absolute; z-index: 8; top: 12px; left: 12px;
  display: inline-flex; align-items: center; gap: 8px;
  background: rgba(20, 26, 40, .9); color: #fff;
  padding: 6px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  box-shadow: var(--shadow); pointer-events: none;
}
.render-busy::before {
  content: ""; width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .35); border-top-color: #fff;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.chips-row { display: flex; gap: 8px; align-items: flex-start; flex-wrap: wrap; }
.chips-row .label { margin: 4px 0 0; flex: none; }
.freq-panel { display: flex; gap: 8px; align-items: flex-start; }
.freq-panel .label { margin: 4px 0 0; flex: none; }
.freq-panel .chips { max-height: 92px; overflow-y: auto; }

/* Export */
/* inside its own tab the bar is the first thing in the pane, so the separator
   (which used to divide it from the stage toolbar above) is not needed */
/* the export pane is much narrower than the old stage toolbar, so the inline
   control labels ("导出尺寸" / "导出倍率") must never break mid-word */
.export-head .label, .export-head .muted { white-space: nowrap; }
.export-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.export-head .label { margin: 0; }
.scale-seg { display: flex; align-items: center; gap: 8px; }
.size-select { display: flex; align-items: center; gap: 8px; }
.size-select select { padding: 5px 8px; border-radius: 8px; border: 1px solid var(--line); background: var(--surface); color: var(--text); font-size: 12px; max-width: 190px; }
.export-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Strips (presets / my clouds) */
.strip { margin-top: 18px; padding: 16px 18px; display: grid; gap: 18px; }
.strip-block { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.strip-block .label { margin: 0; flex: none; }
.strip-head { display: flex; align-items: center; justify-content: space-between; width: 100%; }
.saved-list { display: flex; gap: 12px; flex-wrap: wrap; width: 100%; }
.saved-card {
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  background: var(--panel2); width: 150px; font-size: 12px;
}
.saved-card img { width: 100%; height: 84px; object-fit: cover; display: block; background: #fff; }
.saved-card .meta { padding: 6px 8px 3px; display: flex; justify-content: space-between; gap: 6px; }
.saved-card .name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.saved-card .acts { display: flex; gap: 8px; padding: 2px 8px 8px; }

/* R32 — presets / my-clouds strip polish overlay (incremental; no DOM change). */
/* My-clouds thumbnails: tactile hover lift + keyboard focus ring. */
.saved-card { transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease; }
.saved-card:hover {
  transform: translateY(-2px);
  border-color: var(--brand);
  box-shadow: var(--shadow);
}
.saved-card:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand) 22%, transparent);
}

/* R97 — visual template gallery (complements the preset chips). */
.template-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 10px;
  width: 100%;
  margin: 10px 0 2px;
}
.tpl-card {
  position: relative;
  display: flex; flex-direction: column; align-items: stretch; gap: 0;
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  background: var(--panel2); padding: 0; cursor: pointer; font-family: inherit;
  text-align: left; color: var(--text);
  transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.tpl-card:hover { transform: translateY(-2px); border-color: var(--brand); box-shadow: var(--shadow); }
.tpl-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.tpl-card.active {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand) 28%, transparent);
}
.tpl-thumb { width: 100%; height: auto; display: block; background: #fff; border-bottom: 1px solid var(--line); }
.tpl-name { display: block; font-weight: 600; font-size: 12.5px; padding: 7px 9px 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tpl-swatches { display: flex; gap: 4px; padding: 0 9px 9px; }
.tpl-swatch { width: 13px; height: 13px; border-radius: 4px; border: 1px solid rgba(0,0,0,.12); }

/* ================= Content sections (SEO) ================= */
.content-block { margin-top: clamp(40px, 6vw, 64px); }
.content-block h2 { font-size: 22px; margin: 0 0 18px; }
/* R138 — 区块标题统一的渐变下划线「眉标」，强化分区节奏；FAQ 标题居中时同步居中。 */
.content-block h2::after {
  content: ""; display: block; width: 46px; height: 3px; border-radius: 3px;
  background: var(--grad); margin-top: 10px;
}
#faq h2::after { margin: 10px auto 0; }
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.cards .card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px; box-shadow: var(--shadow);
  display: flex; flex-wrap: wrap; align-items: center; column-gap: 12px; row-gap: 8px;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.cards .card h3 { margin: 0; font-size: 15px; flex: 1 1 0; min-width: 0; }
.card h3::before { content: ""; display: inline-block; width: 9px; height: 9px; border-radius: 3px; background: var(--grad); margin-right: 8px; }
.cards .card p { margin: 0; font-size: 13px; color: var(--muted); flex: 1 1 100%; }
/* R138 — 功能卡悬停微反馈：仅描边变色 + 阴影着色，不做位移/指针，避免暗示「可点击」。 */
.cards .card:hover {
  border-color: color-mix(in srgb, var(--brand) 35%, var(--line));
  box-shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 14px 30px -14px color-mix(in srgb, var(--brand) 38%, transparent);
}

/* R50 — 功能卡图标徽章：取代原 h3::before 的 9px 小色块，让 6 张卡片能被一眼扫读。
   徽章底色走 --brand 12% 混色，随明暗主题自适应；图标为 Unicode 字符（无授权问题）。 */
.card-icon {
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; margin-bottom: 0;
  border-radius: 11px;
  font-size: 18px; line-height: 1;
  background: color-mix(in srgb, var(--brand) 12%, transparent);
}
/* 图标已承担视觉锚点，隐藏旧的装饰小方块，避免重复 */
.card h3::before { display: none; }

.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.step {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px; box-shadow: var(--shadow); position: relative;
}
.step h3 { margin: 0 0 8px; font-size: 15px; }
.step p { margin: 0; font-size: 13px; color: var(--muted); }
/* R51 — 步骤卡顶部渐变条：强化「1→2→3」的流程节奏感。
   刻意不加 hover 上浮——步骤卡不可点击，位移会误导为可交互。 */
.step::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--grad);
}

.faq-list { display: grid; gap: 10px; max-width: 860px; margin: 0 auto; }
#faq h2 { text-align: center; }
.faq-item {
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 16px; box-shadow: var(--shadow);
}
/* R50 — FAQ 折叠指示：自定义箭头替代浏览器默认三角，展开时旋转指向上方，
   并给 summary 加悬停反馈，明确「可点」。 */
.faq-item summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  cursor: pointer; font-weight: 600; font-size: 14px;
  list-style: none;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: ""; flex: none; width: 7px; height: 7px; margin-right: 3px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  transition: transform .18s ease;
}
.faq-item[open] summary::after { transform: rotate(-135deg); }
.faq-item summary:hover { color: var(--brand); }
.faq-item p { margin: 10px 0 2px; color: var(--muted); font-size: 13.5px; }

/* Footer */
.footer { text-align: center; padding: 26px 16px 34px; font-size: 13px; }
.footer p { margin: 4px 0; }
/* the "processed locally" note and the © line share one row (they used to stack) */
.footer-line { display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 4px 16px; }
.footer-line p { margin: 0; }
/* R51 — 页脚友链改轻量胶囊（并移除 HTML 中的「·」分隔符），
   提升 365Lab 生态内其他小工具的辨识度与点击意愿。 */
.footer a {
  display: inline-block; padding: 3px 11px; margin: 2px 3px;
  border: 1px solid var(--line); border-radius: 999px;
  color: var(--muted); font-size: 12.5px;
}
.footer a:hover {
  border-color: var(--brand); color: var(--brand);
  background: color-mix(in srgb, var(--brand) 8%, transparent);
  text-decoration: none;
}

/* Toast */
.toast {
  position: fixed; left: 50%; top: 76px; bottom: auto; transform: translateX(-50%);
  z-index: 95; background: rgba(20, 26, 40, .94); color: #fff;
  padding: 10px 20px; border-radius: 999px; font-size: 13px;
  box-shadow: var(--shadow-lg); animation: toastIn .25s ease; max-width: 90vw;
}
@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* Lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 80; background: rgba(10, 14, 24, .9);
  display: grid; place-items: center; padding: 28px;
}
.lightbox img { max-width: 96vw; max-height: 92vh; border-radius: 8px; box-shadow: var(--shadow-lg); background: #fff; }
.lightbox-close {
  position: absolute; top: 16px; right: 20px; width: 40px; height: 40px;
  border-radius: 50%; border: 0; background: rgba(255, 255, 255, .14); color: #fff;
  font-size: 17px; cursor: pointer;
}
.lightbox-close:hover { background: rgba(255, 255, 255, .28); }

/* ================= Words pane (word table) ================= */
.words-toolbar { display: flex; gap: 8px; align-items: center; }
.words-toolbar .wt-search { flex: 1; min-width: 0; }
.words-toolbar select { flex: none; width: auto; min-width: 108px; }

.words-batch { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.words-batch .muted { margin-left: auto; }

.word-table-wrap {
  max-height: 430px; overflow: auto; min-width: 0;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--panel2);
}
.word-table { width: 100%; min-width: 540px; border-collapse: collapse; font-size: 12.5px; }
.word-table thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--panel); color: var(--muted);
  font-size: 11px; font-weight: 600; text-align: left; letter-spacing: .3px;
  padding: 7px 6px; border-bottom: 1px solid var(--line); white-space: nowrap;
}
.word-table td {
  padding: 4px 5px; border-bottom: 1px solid var(--line);
  vertical-align: middle; white-space: nowrap;
}
.word-table tbody tr:hover td { background: color-mix(in srgb, var(--brand) 6%, transparent); }
.word-table tbody tr:last-child td { border-bottom: 0; }
.word-table tbody tr { transition: background .12s; }
.word-table tbody tr.wt-dragging { opacity: .4; }
.word-table tbody tr.wt-dragover { box-shadow: inset 2px 0 0 var(--brand); background: var(--brand-soft); }

.word-table .wt-check { width: 26px; text-align: center; }
.word-table .wt-check input { accent-color: var(--brand); width: 14px; height: 14px; cursor: pointer; }
.word-table .wt-sort { cursor: pointer; user-select: none; white-space: nowrap; }
.word-table .wt-sort:hover { color: var(--brand); }
.word-table .wt-sort::after { content: '\2195'; opacity: .35; margin-left: 4px; font-size: 11px; }
.word-table .wt-sort.asc::after { content: '\2191'; opacity: .9; }
.word-table .wt-sort.desc::after { content: '\2193'; opacity: .9; }

.word-table .wt-word { max-width: 130px; display: flex; align-items: center; gap: 6px; overflow: hidden; font-weight: 600; }
.wt-label { cursor: text; border-bottom: 1px dashed transparent; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1 1 auto; }
.wt-label:hover { border-bottom-color: var(--brand); color: var(--brand); }
.wt-hl { background: var(--brand-soft); color: var(--brand-fill); border-radius: 3px; padding: 0 1px; }
.wt-new {
  flex: none;
  font-size: 10px; font-weight: 700; line-height: 1; padding: 2px 5px; border-radius: 6px; white-space: nowrap;
  background: color-mix(in srgb, var(--brand) 16%, transparent); color: var(--brand-fill);
  border: 1px solid color-mix(in srgb, var(--brand) 30%, transparent);
}
.wt-rename {
  width: 100%; min-width: 72px; padding: 4px 6px; font-size: 12.5px;
  border: 1px solid var(--brand); border-radius: 6px;
  background: var(--panel); color: var(--ink); outline: none; font-family: inherit;
}

.word-table .wt-num input.wt-in {
  width: 60px; padding: 4px 6px; font-size: 12.5px;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--panel); color: var(--ink); outline: none; font-family: inherit;
}
.word-table .wt-num input.wt-in:focus { border-color: var(--brand); }
.word-table .wt-num input.wt-in::placeholder { color: var(--muted); opacity: .8; }
/* R101 — per-row frequency bar inside the freq cell: a thin track whose fill is
   proportional to the word's effective frequency vs the list max. */
.word-table .wt-num.has-bar { position: relative; padding-bottom: 7px; }
.word-table .wt-freqbar {
  position: absolute; left: 6px; right: 6px; bottom: 3px; height: 3px;
  border-radius: 2px; background: color-mix(in srgb, var(--brand) 16%, transparent);
  overflow: hidden; pointer-events: none;
}
.word-table .wt-freqbar > i { display: block; height: 100%; border-radius: 2px; background: var(--brand); }

.word-table .wt-color { text-align: left; }
.word-table .wt-repeat { width: 34px; text-align: center; }
.word-table .wt-repeat input { accent-color: var(--brand); width: 14px; height: 14px; cursor: pointer; }
.word-table .wt-color input[type="checkbox"] { accent-color: var(--brand); width: 13px; height: 13px; cursor: pointer; vertical-align: middle; margin-right: 3px; }
.word-table .wt-color input[type="color"] {
  width: 28px; height: 22px; padding: 1px; border-radius: 5px; vertical-align: middle;
}
.word-table .wt-color input[type="color"]:disabled { opacity: .3; cursor: default; }

.word-table select.wt-sel {
  width: auto; min-width: 58px; max-width: 86px; padding: 4px 4px; font-size: 12px;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--panel); color: var(--ink); outline: none;
}
.word-table select.wt-sel:focus { border-color: var(--brand); }

.word-table .wt-ops { white-space: nowrap; }
.wt-op {
  width: 22px; height: 22px; padding: 0; margin-right: 2px;
  border: 1px solid transparent; border-radius: 6px;
  background: transparent; color: var(--muted); cursor: pointer;
  font-size: 12px; line-height: 1; font-family: inherit; transition: all .12s;
}
.wt-op:hover { color: var(--brand); border-color: var(--line); background: var(--panel); }

.words-foot { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-top: 10px; }

/* R31 — word-table panel polish overlay (incremental; no DOM change). */
/* 1. Scrollable table card: add depth so it reads as a contained surface like .card. */
.word-table-wrap { box-shadow: var(--shadow); }
/* 2. Sticky header: faint shadow so rows read as scrolling beneath it. */
.word-table thead th {
  box-shadow: 0 2px 5px -2px color-mix(in srgb, var(--ink) 14%, transparent);
}
/* 3. Add-word row: equal 36px control height (text/number) matching .btn.sm. */
.add-word-row .wt-search { height: 36px; padding: 0 11px; }
.add-word-row .wt-in { height: 36px; padding: 0 9px; }
/* 4. Batch controls: align color/select/number to a tidy 32px rail. */
.word-batch-row select,
.word-batch-row input[type="number"] { height: 32px; }
.word-batch-row #batchColor { height: 32px; }
/* 5. Selected rows get a faint brand tint for quick scan (progressive; no-op if :has() unsupported). */
.word-table tbody tr:has(.wt-check input:checked) td {
  background: color-mix(in srgb, var(--brand) 9%, transparent);
}
.word-table tbody tr:has(.wt-check input:checked):hover td {
  background: color-mix(in srgb, var(--brand) 13%, transparent);
}

/* ================= Responsive ================= */
@media (max-width: 1020px) {
  .workspace, body.tool-page .workspace { grid-template-columns: 1fr; }
  .side-panel { position: static; max-height: none; }
  body.tool-page .stage-panel { margin-top: 14px; }
  .cards, .steps { grid-template-columns: repeat(2, 1fr); }
  /* R49 — 小屏不再隐藏顶栏导航：换行成独立一行并可横向滚动。
     此前 .top-nav{display:none} 会让「功能/教程/常见问题」锚点
     与「在线工具」主 CTA 在 ≤1020px 时连同顶栏一起消失。 */
  .topbar, .topbar-inner { flex-wrap: wrap; row-gap: 8px; }
  .top-nav {
    display: flex; order: 3; flex: 1 1 100%; margin-left: 0;
    gap: 16px; overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .top-nav::-webkit-scrollbar { display: none; }
  .top-nav a { white-space: nowrap; }
}

/* grid blowout guard on small screens */
@media (max-width: 1020px) {
  .workspace, body.tool-page .workspace { grid-template-columns: 1fr; }
  .panel, .side-panel, .stage-panel { min-width: 0; width: 100%; }
  .side-panel { position: static; max-height: none; }
  body.tool-page .stage-panel { margin-top: 14px; }
}
@media (max-width: 640px) {
  main, body.tool-page main { padding: 10px 10px 28px; }
  /* 10px (not 12px) so the top-bar contents share <main>'s 10px gutter at this size */
  .topbar { padding: 8px 10px; gap: 10px; }
  .topbar-inner { gap: 10px; }
  .tagline { display: none; }
  .brand-text h1, .brand-text .brand-name { font-size: 15px; }
  .cards, .steps { grid-template-columns: 1fr; }
  body.tool-page .workspace { gap: 14px; }
  .shape-grid { grid-template-columns: repeat(3, 1fr); }
  .palette-grid { grid-template-columns: 1fr 1fr; }
  .stage-toolbar .stats { width: auto; margin: 0; align-self: flex-start; }
  .stage-toolbar { gap: 6px; }
  .stage-toolbar .btn { padding: 7px 10px; font-size: 12px; }
  .content-block h2 { font-size: 19px; }
  .field output { margin-top: -18px; }
  .word-table-wrap { max-height: 320px; }
  .word-table .wt-word { max-width: 84px; }
  .words-batch { gap: 9px; }
  /* R59 — WCAG 2.5.8 目标尺寸：把移动端 <24px 的点按目标抬到合规/舒适区。
     实测：导航链接 26x20、品牌链接 85x18、mini 按钮 36x22、滑块 22 → 均 <24。 */
  /* 内联 <a> 内包块级 <h1>：只加 padding 会触发匿名块盒换行（实测高度 18→72px），
     必须先 inline-block 把盒子原子化。 */
  a.brand-link { display: inline-block; padding: 4px 2px; }
  .top-nav a { padding: 8px 2px; }
  .mini-actions .btn-link { padding: 7px 8px; }
  /* 复选框本体 15x15，真正点按区是整行 label（实测仅 21px 高）→ 抬到 ~33px */
  .check { padding: 6px 0; }
  input[type="range"]::-webkit-slider-thumb { width: 22px; height: 22px; }
  input[type="range"]::-moz-range-thumb { width: 20px; height: 20px; }
  /* 320px 极窄屏：网格轨道按 max-content 撑到 300px 把画布裁掉 6px。
     只给 .canvas-zoom 加 max-width 不够（轨道已按 max-content 定宽，二者循环），
     必须用 minmax(0,1fr) 约束轨道本身。 */
  .canvas-wrap { grid-template-columns: minmax(0, 1fr); }
  .canvas-zoom { max-width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ================= Homepage (index.html) ================= */
.brand-link { color: inherit; text-decoration: none; }
.brand-link:hover { text-decoration: none; }
.nav-cta {
  padding: 6px 14px; border-radius: 999px; background: var(--grad);
  color: #fff !important; font-size: 13px; font-weight: 600;
}
.nav-cta:hover { text-decoration: none; filter: brightness(1.06); }
.top-nav a.active { color: var(--brand); font-weight: 600; }

.hero {
  display: grid; grid-template-columns: 1.05fr 0.95fr; gap: clamp(24px, 4vw, 40px); align-items: center;
  margin: 30px auto 8px; padding: clamp(28px, 4vw, 40px) clamp(22px, 3vw, 40px);
  background:
    radial-gradient(90% 130% at 88% -12%, color-mix(in srgb, var(--brand) 14%, transparent) 0%, transparent 52%),
    linear-gradient(135deg, color-mix(in srgb, var(--brand) 12%, var(--panel)) 0%, var(--panel) 62%);
  border: 1px solid var(--line); border-radius: 24px;
}
.hero-title { margin: 0 0 14px; font-size: clamp(26px, 3.4vw, 40px); line-height: 1.18; letter-spacing: -.5px; }
.hero-sub { margin: 0 0 22px; font-size: 15.5px; line-height: 1.7; color: var(--muted); max-width: 520px; }

/* Headings: balance line lengths so a single character never sits alone on
   its own line (e.g. hero's trailing "云" used to wrap by itself). */
.hero-title,
.content-block h2,
.card h3,
.step h3,
.faq-item summary,
.empty-state h2 { text-wrap: balance; }
.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; }
.hero-cta .btn { padding: 12px 24px; font-size: 15px; }
.hero-badges { list-style: none; margin: 22px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.hero-badges li {
  font-size: 12.5px; color: var(--ink); padding: 5px 11px; border-radius: 999px;
  background: var(--panel2); border: 1px solid var(--line);
}
.hero-badges li::before { content: "✓ "; color: var(--brand); font-weight: 700; }
.hero-visual { display: flex; justify-content: center; position: relative; z-index: 1; }
.hero-visual img {
  width: 100%; max-width: 460px; border-radius: 16px;
  box-shadow: var(--shadow-lg), 0 0 0 4px color-mix(in srgb, var(--brand) 9%, transparent);
  border: 1px solid var(--line); background: #fff;
  transition: transform .3s ease, box-shadow .3s ease;
}
.hero-visual:hover img { transform: scale(1.02); }

/* ---- Bar chart modal polish ---- */
.bar-card {
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px 22px 18px; box-shadow: var(--shadow-lg);
  max-width: min(92vw, 780px); width: 100%;
}
.bar-card h3 { margin: 0 0 12px; font-size: 16px; }
.bar-actions { margin-top: 14px; justify-content: flex-end; gap: 10px; }
#barCanvas { width: 100%; height: auto; max-height: 64vh; border-radius: var(--radius-sm); background: var(--panel2); }

/* ---- Batch color/word controls spacing ---- */
.word-batch-row { margin-top: 4px; margin-bottom: 12px; }
.word-batch-row select, .word-batch-row input[type="number"] { padding: 4px 8px; font-size: 13px; border-radius: 6px; border: 1px solid var(--line); background: var(--surface); color: var(--text); }
.word-export-row { margin-bottom: 12px; }
.word-export-row { margin-bottom: 12px; }
#wordTableCapNote { display: inline-block; }
#wordTableCapNote.hidden { display: none; }
.word-batch-row #batchColor { width: 34px; height: 30px; padding: 0; border: 1px solid var(--line); border-radius: 8px; background: none; cursor: pointer; }
.word-batch-row .btn, .word-batch-row select { flex: 0 1 auto; }

/* ---- Layout reset spacing ---- */
.layout-reset { margin-top: 18px; }

/* ---- Canvas zoom & pan ---- */
.canvas-zoom {
  position: relative; z-index: 1;
  transform-origin: 0 0;
  transition: transform .12s ease;
  will-change: transform;
  width: max-content;
}
.zoom-ctl { display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px; border: 1px solid var(--line); border-radius: 999px; background: var(--panel2); }
.zoom-ctl .btn.icon { min-width: 26px; padding: 2px 8px; line-height: 1; font-size: 16px; border-radius: 999px; }
.zoom-label { min-width: 42px; text-align: center; font-variant-numeric: tabular-nums; color: var(--muted); font-size: 12px; }
.canvas-wrap { cursor: grab; }
.canvas-wrap.grabbing { cursor: grabbing; }
.canvas-wrap.drop-over, #textInput.drop-over { outline: 2px dashed var(--accent, #4f8cff); outline-offset: -6px; box-shadow: inset 0 0 0 9999px rgba(79,140,255,0.08); }

/* 教程页的快捷键列表（原本只在工具页弹窗里用） */
.shortcut-list { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 10px; }
.shortcut-list li { display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 14px; }
.shortcut-list kbd { display: inline-flex; align-items: center; justify-content: center; min-width: 28px; height: 28px; padding: 0 8px; background: var(--bg); border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 7px; font-family: var(--mono, monospace); font-size: 13px; font-weight: 700; color: var(--text); }


/* export button grouping */
.export-actions { align-items: center; }
.export-more { display: flex; flex-wrap: wrap; gap: 8px; width: 100%; margin-top: 8px; }
/* Group headings inside the export card. The card is a wrapping flex row, so a
   100%-wide heading naturally starts a new line — no wrapper divs needed. */
.exp-group { flex: 0 0 100%; width: 100%; font-size: 11.5px; font-weight: 700;
  letter-spacing: .06em; color: var(--muted); margin: 4px 0 -2px; }
.exp-group:first-child { margin-top: 0; }


/* R30 — secondary export actions card: a tidy, scroll-guarded grid instead of a
   flat 11-button row. It used to sit behind a "更多" toggle, but the toggle was
   non-functional (.export-more's display:flex overrode [hidden]), so the card is
   now always open and the toggle is gone. */
/* The card used to be clamped to 280px with its own scrollbar. Now that the export
   controls live in the (already scrollable) side pane, that nested 845px-in-278px
   scroll box was pure friction — let the card grow and the pane scroll instead. */
#exportMore {
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel2);
  box-shadow: var(--shadow);
}
#exportMore .btn {
  flex: 1 1 150px;
  justify-content: center;
  text-align: center;
}
.export-actions .btn:not(.primary):hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}

/* WCAG 2.5.8 touch target size for remaining checkboxes */
@media (pointer: coarse) {
  .check input[type="checkbox"],
  .word-table .wt-color input[type="checkbox"] { width: 18px; height: 18px; }
}

/* ===== UI polish pass (2026-08-15) ===== */
/* slider value labels: higher contrast */
.slider-row output, .field output, output {
  color: var(--ink); font-weight: 600; font-size: 13px;
}
/* slider track more visible */
input[type=range] { height: 22px; }
input[type=range]::-webkit-slider-runnable-track { height: 5px; border-radius: 3px; background: var(--line); }
input[type=range]::-moz-range-track { height: 5px; border-radius: 3px; background: var(--line); }

/* shape buttons: tighter, hover, border */
.shape-btn {
  min-height: 66px; border: 1px solid var(--line); background: var(--panel);
  border-radius: 12px; transition: border-color .15s, background .15s, transform .1s, box-shadow .15s;
}
.shape-btn:hover { border-color: var(--brand); transform: translateY(-1px); box-shadow: var(--shadow); }
.shape-btn.active { border-color: var(--brand); background: color-mix(in srgb, var(--brand) 10%, var(--panel)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand) 25%, transparent); }
.shape-btn svg { width: 26px; height: 26px; }
.shape-grid { gap: 10px; }

/* palette grid: bigger chips + name */
.palette-grid { gap: 10px; }
.palette-card { padding: 8px; border-radius: 12px; border: 1px solid var(--line); }
.palette-card .sw { height: 22px; border-radius: 7px; }
.palette-card .name { font-size: 12px; }

/* word table: slightly roomier inputs */
.wt-in { width: 56px; }
.wt-color { width: 34px; height: 30px; }

/* export-actions: consistent gaps */
.export-actions { gap: 8px; }
.btn.ghost, .btn.primary, .export-actions .btn { min-height: 36px; }

/* toolbar buttons uniform height (include .btn.primary — it outranks ".stage-toolbar button" on specificity) */
.stage-toolbar button, .stage-toolbar .seg, .stage-toolbar .btn.primary { min-height: 38px; }
.zoom-label { font-weight: 600; color: var(--ink); }

/* modal kbd contrast (help modal uses .modal, not .help-modal) */
.modal .kbd { border: 1px solid var(--line); background: var(--panel2); color: var(--ink); }



/* bg-fit segmented control */
.bg-fit-seg { margin-top: 10px; }
.bg-fit-seg .seg-btn { padding: 5px 12px; font-size: 12px; }


/* word search clear */
.wt-search-wrap { position: relative; display: flex; align-items: center; }
.wt-search-wrap .wt-search { width: 100%; padding-right: 30px; }
.wt-search-clear { position: absolute; right: 6px; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; border: none; background: transparent; color: var(--muted); font-size: 18px; line-height: 1; border-radius: 50%; cursor: pointer; }
.wt-search-clear:hover { background: var(--panel2); color: var(--ink); }


/* add word row */
.add-word-row { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; }
.add-word-row .wt-search { flex: 1; }
.add-word-row .wt-in { width: 72px; }

/* R36 — control-sidebar slider value chips (incremental; no DOM change).
   Replaces the fragile `.field output { float:right; margin-top:-20px }`
   hack with a robust top-right chip pinned to the field and aligned to the
   label line. Targets direct-child outputs only; inline outputs nested in
   labels (e.g. 背景模糊/暗化蒙版) are intentionally left untouched. */
.side-panel .field { position: relative; }
.side-panel .field > output {
  position: absolute; top: 0; right: 0;
  float: none; margin: 0;
  font-size: 11.5px; font-weight: 700; color: var(--brand);
  font-variant-numeric: tabular-nums; line-height: 1.4;
  background: var(--brand-soft);
  padding: 1px 8px; border-radius: 999px; white-space: nowrap;
}

/* R38 — render status pill (incremental; no DOM change).
   Pairs with the dark .render-busy "渲染中" pill: a calm, light "done" chip
   pinned to the toolbar right. Hides cleanly when empty (pre-render). */
.stage-toolbar .stats {
  background: var(--brand-soft);
  color: var(--brand);
  padding: 3px 11px;
  border-radius: 999px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  line-height: 1.5;
}
.stage-toolbar .stats:empty { background: none; padding: 0; }

/* R45 — 画布舞台区视觉打磨 (incremental; CSS only, no DOM/JS change).
   The canvas-wrap holds the transparent wordcloud canvas; painting on the
   wrap's background shows through transparent canvas pixels, so a subtle
   center spotlight naturally frames the cloud without affecting exports
   (exports capture canvas pixels only, never wrap CSS). */
/* Slightly stronger outer shadow + 1px inset edge for a "framed art" stage. */
.canvas-wrap {
  box-shadow: var(--shadow), inset 0 0 0 1px color-mix(in srgb, var(--ink) 5%, transparent);
}
/* Center spotlight: transparent in the middle (cloud stays bright), very
   gently darkened at the edges (draws the eye to the cloud area). */
.canvas-wrap::after {
  content: "";
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(ellipse 62% 64% at 50% 46%, transparent 0%, transparent 52%, color-mix(in srgb, var(--ink) 7%, transparent) 100%);
}
/* Empty state: a soft pulsing ring around the floating cloud emoji to
   reinforce the "drop your text here" affordance. The ring scales outward
   and fades; the existing floaty animation still lifts the whole cluster. */
.empty-state .empty-cloud {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 84px; height: 84px;
}
.empty-state .empty-cloud::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: 50%;
  background: color-mix(in srgb, var(--brand) 14%, transparent);
  animation: pulse-ring 2.4s ease-out infinite;
}
@keyframes pulse-ring {
  0%   { transform: scale(.78); opacity: .9; }
  80%  { transform: scale(1.35); opacity: 0; }
  100% { transform: scale(1.35); opacity: 0; }
}

/* R46 — 控件侧栏 节奏细化 + 分组分隔线 (incremental; CSS + semantic <hr>
   dividers in the style pane). Refines scannability of the long control
   wall without restructuring. */
/* Subtle tracking on every label — calmer, more readable field column. */
.label { letter-spacing: .01em; }
/* A hair more breathing room between fields; the last item in a pane trims
   its bottom margin so the pane doesn't feel bottom-heavy near the scroll. */
.field { margin-bottom: 15px; }
.pane > .field:last-child,
.pane > details:last-child { margin-bottom: 10px; }
/* <hr class="divider"> — a thin section separator used between logical groups
   in the style pane (配色 / 字体 / 阴影 / 背景). Slightly more space above
   the line than below so the break reads as "previous group ended" and
   the next group begins closer to its own controls. */
hr.divider {
  border: 0; border-top: 1px solid var(--line);
  margin: 18px 0 14px;
}

/* R47 — 控件分组小标题（与 R46 分隔线配合，强化四组可扫读性） */
.group-title {
  margin: 0 0 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--muted);
}
.pane > .group-title:first-child { margin-top: 2px; }

@media (max-width: 860px) {
  .hero { grid-template-columns: 1fr; padding: 20px 16px 26px; }
  .hero-visual { order: -1; }
  .hero-visual img { max-width: 320px; }
}

/* ================= R75 - 词表内联控件键盘焦点环（可访问性一致性） =================
   问题：.word-table .wt-num input.wt-in / .word-table select.wt-sel / .wt-rename 的
   base 规则含 `outline: none`，且特异性（0,3,1 / 0,2,1 / 0,1,0 且位置更靠后）高于全局
   `:focus-visible`（0,1,0），导致全站统一的 2px 品牌色焦点描边被压制 —— 键盘聚焦时
   只剩 1px 边框变色（.wt-rename 的 base 边框本就是品牌色，故几乎无变化）。
   修法：以更高特异性补回与全站一致的焦点描边。仅增量叠加，不改既有规则。 */
.word-table .wt-num input.wt-in:focus-visible,
.word-table select.wt-sel:focus-visible,
.wt-rename:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* R127 — 控件侧栏滑块、分段器、下拉框视觉精修 (incremental; no DOM change).
   针对排版/样式面板中长列表控件做可读性与触感提升：更明显的滑轨、
   更立体的滑块、分段器 active 态层次、下拉框自定义箭头与焦点环。 */

/* Slider: clear the input's own flat track so the pseudo-element track is authoritative. */
input[type=range] {
  height: 24px;
  margin: 8px 0 4px;
  background: transparent;
}
input[type=range]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--line) 78%, var(--muted)), var(--line));
  box-shadow: inset 0 1px 2px rgba(0,0,0,.07);
}
input[type=range]::-moz-range-track {
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--line) 78%, var(--muted)), var(--line));
  box-shadow: inset 0 1px 2px rgba(0,0,0,.07);
}

/* Thumb: larger, crisper ring, stronger hover lift. */
input[type=range]::-webkit-slider-thumb {
  width: 20px; height: 20px;
  border: 3px solid #fff;
  background: var(--grad);
  box-shadow: 0 2px 6px rgba(0,0,0,.28), 0 0 0 1px rgba(0,0,0,.05);
  transition: transform .12s ease, box-shadow .12s ease;
}
input[type=range]::-webkit-slider-thumb:hover { transform: scale(1.12); }
input[type=range]::-moz-range-thumb {
  width: 18px; height: 18px;
  border: 3px solid #fff;
  background: var(--grad);
  box-shadow: 0 2px 6px rgba(0,0,0,.28), 0 0 0 1px rgba(0,0,0,.05);
  transition: transform .12s ease, box-shadow .12s ease;
}
input[type=range]::-moz-range-thumb:hover { transform: scale(1.12); }
input[type=range]:focus-visible {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand) 16%, transparent);
}

/* Segmented control: subtle border around the rail, active pill feels elevated. */
.seg {
  padding: 4px;
  gap: 5px;
  border-radius: 10px;
  background: var(--panel2);
  border: 1px solid var(--line);
}
.seg-btn {
  padding: 8px 10px;
  border-radius: 8px;
  font-weight: 500;
  color: var(--muted);
  transition: all .15s ease;
}
.seg-btn:hover {
  background: var(--brand-soft);
  color: var(--brand);
}
.seg-btn.active {
  background: var(--brand-fill);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(0,0,0,.12), inset 0 1px 0 rgba(255,255,255,.15);
}

/* Select in side panel: custom chevron + consistent focus ring. */
.side-panel .field select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 14px;
  cursor: pointer;
}
.side-panel .field select:hover { border-color: color-mix(in srgb, var(--brand) 60%, var(--line)); }
.side-panel .field select:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 16%, transparent);
}
[data-theme="dark"] .side-panel .field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23aab4cc' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

/* Value chips: crisper pill border + micro shadow so it sits above the label line. */
.side-panel .field > output {
  padding: 2px 9px;
  font-size: 12px;
  border: 1px solid color-mix(in srgb, var(--brand) 22%, transparent);
  box-shadow: 0 1px 2px rgba(0,0,0,.04);
}

/* Range-row side labels (e.g. 紧密 / 疏松): fixed width so they don't jump. */
.range-row .muted {
  flex: 0 0 auto;
  min-width: 28px;
  text-align: center;
  font-weight: 500;
  color: color-mix(in srgb, var(--muted) 82%, var(--ink));
}

/* R128 — 多角度旋转「角度预设」可视选择器 (rotation angle preset picker).
   仅在旋转=多角度时显示；纯文字卡片（R42 起移除量角器图标），active 态高亮。 */
#rotateAngleField {
  margin-left: 4px;
  padding-left: 12px;
  border-left: 2px solid var(--line);
}
.angle-presets {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
  gap: 8px;
  margin-top: 8px;
}
.angle-chip {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px 6px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel2);
  color: var(--muted);
  cursor: pointer;
  font: inherit;
  transition: all .15s ease;
}
.angle-chip:hover {
  border-color: color-mix(in srgb, var(--brand) 55%, var(--line));
  color: var(--brand);
  transform: translateY(-1px);
}
.angle-chip:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 22%, transparent);
}
.angle-chip.active {
  border-color: var(--brand-fill);
  background: color-mix(in srgb, var(--brand) 10%, var(--panel));
  color: var(--brand);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--brand) 22%, transparent);
}
.angle-name {
  font-size: 12px;
  line-height: 1.2;
  text-align: center;
  white-space: nowrap;
}

/* ===== Static content pages (tutorial / faq / about / terms / privacy) ===== */
.doc-page { max-width: 880px; margin: 0 auto; padding-top: 6px; }
.doc-page .doc-hero { margin: clamp(18px, 3vw, 30px) 0 clamp(22px, 4vw, 34px); }
.doc-page .doc-hero h1 { font-size: clamp(26px, 3.4vw, 36px); margin: 0 0 12px; letter-spacing: -.4px; }
.doc-page .doc-hero p { color: var(--muted); font-size: 15px; line-height: 1.75; margin: 0; max-width: 680px; }
.doc-updated { color: var(--muted); font-size: 13px; margin: 8px 0 0; }

.legal-section { margin-top: clamp(20px, 3vw, 30px); }
.legal-section h2 { font-size: 18px; margin: 0 0 10px; display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.legal-section h2 .sec-num { color: var(--brand); font-weight: 700; }
.legal-section p { color: var(--text); font-size: 14.5px; line-height: 1.8; margin: 0; }

.doc-list { margin: 14px 0 0; padding: 0; display: grid; gap: 10px; list-style: none; }
.doc-list li { background: var(--panel2); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; font-size: 14px; line-height: 1.7; color: var(--text); }
.doc-list li b { color: var(--brand); }

.contact-card { margin-top: clamp(22px, 3vw, 32px); border: 1px solid var(--line); border-radius: 16px; padding: 20px 22px; background: var(--panel2); }
.contact-card h2 { margin: 0 0 8px; font-size: 19px; }
.contact-card > p { color: var(--muted); font-size: 14px; line-height: 1.75; margin: 0 0 14px; }
.email-label { display: block; font-size: 12.5px; color: var(--muted); margin-bottom: 8px; }
.email-copy { display: inline-flex; align-items: center; gap: 10px; padding: 12px 16px; border-radius: 12px; border: 1.5px dashed color-mix(in srgb, var(--brand) 45%, var(--line)); background: color-mix(in srgb, var(--brand) 7%, transparent); color: var(--text); font-weight: 600; font-size: 15px; cursor: pointer; text-decoration: none; transition: border-color .18s ease, transform .18s ease; }
.email-copy:hover { border-color: var(--brand); transform: translateY(-1px); }
.email-copy .ico { font-size: 17px; }

.brand-link-card { margin-top: 16px; }
.brand-link-card a.btn { display: inline-flex; align-items: center; gap: 8px; }

.doc-cta { margin-top: clamp(24px, 3vw, 34px); text-align: center; }
.doc-cta h2 { font-size: 20px; margin: 0 0 14px; }
.doc-cta .btn { padding: 12px 24px; font-size: 15px; }

.faq-page .faq-list { margin-top: 10px; }

/* ===== Self-hosted open-source web fonts (lazy-loaded on use) =====
 * All SIL Open Font License 1.1 - free for commercial use (see README credits).
 * assets/fonts/*.woff2 | A font file is only fetched when that font is selected.
 * CJK faces declare a latin subset first so pure-English text pulls ~13 KB, not ~1 MB.
 */

@font-face { font-family: 'Noto Sans SC'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/noto-sans-sc-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Noto Sans SC'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/noto-sans-sc-cn-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }

@font-face { font-family: 'Noto Serif SC'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/noto-serif-sc-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Noto Serif SC'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/noto-serif-sc-cn-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }

@font-face { font-family: 'Ma Shan Zheng'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/ma-shan-zheng-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Ma Shan Zheng'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/ma-shan-zheng-cn-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }

@font-face { font-family: 'ZCOOL KuaiLe'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-kuaile-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'ZCOOL KuaiLe'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-kuaile-cn-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }

@font-face { font-family: 'ZCOOL XiaoWei'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-xiaowei-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'ZCOOL XiaoWei'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-xiaowei-cn-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }

@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/inter-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

@font-face { font-family: 'Playfair Display'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/playfair-display-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

@font-face { font-family: 'Oswald'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/oswald-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

@font-face { font-family: 'Caveat'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/caveat-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/jetbrains-mono-latin-400.woff2?v=20260923a) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

@font-face { font-family: 'ZCOOL QingKe HuangYou'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-huangyou-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'ZCOOL QingKe HuangYou'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-huangyou-cn-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }
@font-face { font-family: 'Long Cang'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/long-cang-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Long Cang'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/long-cang-cn-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }
@font-face { font-family: 'Zhi Mang Xing'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zhi-mang-xing-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Zhi Mang Xing'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zhi-mang-xing-cn-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }
@font-face { font-family: 'Liu Jian Mao Cao'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/liu-jian-mao-cao-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Liu Jian Mao Cao'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/liu-jian-mao-cao-cn-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }
@font-face { font-family: 'Bebas Neue'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/bebas-neue-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Archivo Black'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/archivo-black-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Pacifico'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/pacifico-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Lobster'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/lobster-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'DM Serif Display'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/dm-serif-display-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'VT323'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/vt323-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

/* ==================== R-CARTOON — 糖果贴纸漫画风（仅首页营销区；工具工作台 data-page="tool" 完全不受影响） ==================== */
body[data-page="home"]{
  --sticker-edge:#bcc4ec;                 /* 浅色主题：淡糖果描边（R13 调淡；装饰非文本） */
  --sticker-shadow:#c7cff2;               /* 硬投影色（浅色） */
  --pop-a:#ff8fb1; --pop-b:#7c5cff; --pop-c:#33c6f2; --pop-d:#ffb02e; --pop-e:#3ad59b;
  --stk-num:#1c2333;
  --font-display:"ZCOOL KuaiLe","Caveat",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
}
[data-theme="dark"] body[data-page="home"]{
  --sticker-edge:#55619c;                 /* 深色主题：淡靛描边（R13 调淡） */
  --sticker-shadow:#05070f;               /* 近黑硬投影 */
  --stk-num:#0b0f1c;
}
/* 显示字体：标题走 ZCOOL 快乐体（自托管、swap），文本色不变→AA 维持 */
body[data-page="home"] .hero-title,
body[data-page="home"] .content-block h2,
body[data-page="home"] .card h3,
body[data-page="home"] .step h3,
body[data-page="home"] .nav-cta,
body[data-page="home"] .btn.primary,
body[data-page="home"] .btn.ghost{
  font-family:var(--font-display); font-weight:400;
}
body[data-page="home"] .hero-title{ letter-spacing:.5px; font-size:clamp(28px,4.2vw,46px); }
body[data-page="home"] .content-block h2{ font-size:clamp(22px,3vw,28px); letter-spacing:.3px; }
body[data-page="home"] .card h3,body[data-page="home"] .step h3{ font-size:16px; letter-spacing:.2px; }

/* Hero：加位 + 裁切光晕 + 内容抬到光晕之上 */
body[data-page="home"] .hero{ position:relative; overflow:hidden; border:1.5px solid var(--sticker-edge); border-radius:26px; }
body[data-page="home"] .hero-copy{ position:relative; z-index:1; }
body[data-page="home"] .hero::before,
body[data-page="home"] .hero::after{
  content:""; position:absolute; z-index:0; width:240px; height:240px; border-radius:50%;
  pointer-events:none; opacity:.42; will-change:transform;
}
body[data-page="home"] .hero::before{
  left:-72px; bottom:-92px;
  background:radial-gradient(circle at 32% 30%, var(--pop-b) 0 42%, transparent 66%), radial-gradient(circle at 72% 66%, var(--pop-a) 0 40%, transparent 66%);
  animation:wcFloat 10s ease-in-out infinite;
}
body[data-page="home"] .hero::after{
  right:-84px; top:-72px;
  background:radial-gradient(circle at 40% 36%, var(--pop-c) 0 44%, transparent 66%), radial-gradient(circle at 66% 70%, var(--pop-d) 0 40%, transparent 66%);
  animation:wcFloat 12s ease-in-out infinite reverse;
}
@keyframes wcFloat{ 0%,100%{ transform:translateY(0) } 50%{ transform:translateY(-18px) } }

/* Hero 效果图贴纸化：歪斜 + 粗描边 + 硬投影，悬停归正 */
body[data-page="home"] .hero-visual img{
  border:1.5px solid var(--sticker-edge); border-radius:22px;
  box-shadow:10px 12px 0 -2px var(--sticker-shadow), var(--shadow-lg);
}
body[data-page="home"] .hero-visual:hover img{ transform:scale(1.02); }
/* 「NEW!」爆炸贴 */
body[data-page="home"] .hero-visual::after{
  content:"NEW!"; position:absolute; z-index:3; right:-6px; top:-14px;
  font-family:var(--font-display); font-size:15px; color:var(--stk-num); letter-spacing:.5px;
  padding:9px 10px; background:var(--pop-a);
  border:1.5px solid var(--sticker-edge);
  clip-path:polygon(50% 0,61% 20%,84% 12%,80% 35%,100% 42%,84% 55%,97% 74%,73% 72%,66% 95%,50% 80%,34% 95%,27% 72%,3% 74%,16% 55%,0 42%,20% 35%,16% 12%,39% 20%);
  transform:rotate(12deg); pointer-events:none;
}
/* 徽章胶囊贴纸化 */
body[data-page="home"] .hero-badges li{ border:1.5px solid var(--sticker-edge); background:var(--panel); box-shadow:2px 3px 0 var(--sticker-shadow); font-weight:600; }
/* 主/次按钮：粗边 + 硬底 */
body[data-page="home"] .btn.primary{ border:1.5px solid var(--sticker-edge); border-radius:999px; box-shadow:4px 5px 0 var(--sticker-edge); }
body[data-page="home"] .btn.primary:hover{ transform:translate(-1px,-1px); box-shadow:6px 8px 0 var(--sticker-edge); color:#fff; }
body[data-page="home"] .btn.ghost{ border:1.5px solid var(--sticker-edge); border-radius:999px; background:var(--panel); box-shadow:4px 5px 0 var(--sticker-shadow); }
body[data-page="home"] .btn.ghost:hover{ transform:translate(-1px,-1px); box-shadow:6px 8px 0 var(--sticker-shadow); }

/* 功能卡：糖果贴纸 —— 粗描边 + 硬投影 + 轻微交替歪斜；悬停归正抬起 */
body[data-page="home"] .cards .card{
  border:1.5px solid var(--sticker-edge); border-radius:20px;
  box-shadow:5px 6px 0 var(--sticker-shadow);
  transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
body[data-page="home"] .cards .card:hover{ transform:translateY(-5px); box-shadow:9px 13px 0 var(--sticker-shadow); border-color:var(--sticker-edge); }
/* 图标徽章：彩色糖果圆角，逐卡换色 */
body[data-page="home"] .card-icon{ width:46px; height:46px; border-radius:15px; font-size:22px; border:1.5px solid var(--sticker-edge); box-shadow:3px 3px 0 var(--sticker-shadow); }
body[data-page="home"] .cards .card:nth-child(6n+1) .card-icon{ background:color-mix(in srgb, var(--pop-a) 34%, var(--panel)); }
body[data-page="home"] .cards .card:nth-child(6n+2) .card-icon{ background:color-mix(in srgb, var(--pop-c) 34%, var(--panel)); }
body[data-page="home"] .cards .card:nth-child(6n+3) .card-icon{ background:color-mix(in srgb, var(--pop-b) 32%, var(--panel)); }
body[data-page="home"] .cards .card:nth-child(6n+4) .card-icon{ background:color-mix(in srgb, var(--pop-d) 36%, var(--panel)); }
body[data-page="home"] .cards .card:nth-child(6n+5) .card-icon{ background:color-mix(in srgb, var(--pop-e) 34%, var(--panel)); }
body[data-page="home"] .cards .card:nth-child(6n+6) .card-icon{ background:color-mix(in srgb, var(--pop-a) 30%, var(--panel)); }
/* 步骤卡：把顶部渐变条改成漂浮编号圆贴（CSS 计数器，无需改 HTML） */
body[data-page="home"] .steps{ counter-reset:wcstep; }
body[data-page="home"] .step{
  counter-increment:wcstep;
  border:1.5px solid var(--sticker-edge); border-radius:20px;
  box-shadow:5px 6px 0 var(--sticker-shadow); padding-top:32px;
  transition:transform .18s ease, box-shadow .18s ease;
}
body[data-page="home"] .step:hover{ transform:translateY(-4px); box-shadow:8px 11px 0 var(--sticker-shadow); }
body[data-page="home"] .step::before{
  content:counter(wcstep);
  left:16px; right:auto; top:-16px; width:42px; height:42px;
  border-radius:50%; display:grid; place-items:center;
  font-family:var(--font-display); font-size:21px; color:var(--stk-num); line-height:1;
  background:var(--pop-b); border:1.5px solid var(--sticker-edge);
  box-shadow:3px 3px 0 var(--sticker-shadow);
}
body[data-page="home"] .step:nth-child(2)::before{ background:var(--pop-c); }
body[data-page="home"] .step:nth-child(3)::before{ background:var(--pop-a); }
/* FAQ 卡片描边统一 */
body[data-page="home"] .faq-item{ border:1.5px solid var(--sticker-edge); border-radius:14px; box-shadow:4px 5px 0 var(--sticker-shadow); }
/* 区块标题眉标：改硬投影同色，节奏更漫画 */
body[data-page="home"] .content-block h2::after{ height:4px; width:54px; border-radius:4px; }
/* 入场：仅对无静态 transform 的块做错峰弹入，避免与卡片歪斜冲突 */
@keyframes wcPop{ from{ opacity:0; transform:translateY(16px) scale(.97) } to{ opacity:1 } }
body[data-page="home"] .hero-copy > *{ animation:wcPop .55s both; }
body[data-page="home"] .hero-copy > *:nth-child(2){ animation-delay:.08s; }
body[data-page="home"] .hero-copy > *:nth-child(3){ animation-delay:.16s; }
body[data-page="home"] .hero-copy > *:nth-child(4){ animation-delay:.24s; }
body[data-page="home"] .hero-visual{ animation:wcPop .6s .12s both; }
body[data-page="home"] .content-block{ animation:wcPop .5s both; }

/* ==================== R7 (2026-09-23) — 顶栏导航胶囊化（全站统一，含工具页） ==================== */
.top-nav a { padding: 6px 13px; border-radius: 999px; transition: background-color .16s ease, color .16s ease; }
.top-nav a:hover { background: var(--brand-soft); color: var(--brand); }
.top-nav a.active { background: var(--brand-soft); color: var(--brand); font-weight: 700; }
@media (max-width: 640px) { .top-nav a { padding: 6px 10px; } }

/* ==================== R8 (2026-09-23) — 内容页糖果贴纸化（5 个 doc 页）+ 取消眉标横线 ==================== */
/* 用户点名：标题下的装饰横线移除 */
body:not([data-page="tool"]) .content-block h2::after{ display:none; }
/* 贴纸设计令牌扩展到全部内容页（与首页同一套糖果色） */
body:not([data-page="tool"]){
  --sticker-edge:#bcc4ec; --sticker-shadow:#c7cff2;
  --pop-a:#ff8fb1; --pop-b:#7c5cff; --pop-c:#33c6f2; --pop-d:#ffb02e; --pop-e:#3ad59b;
  --stk-num:#1c2333;
  --font-display:"ZCOOL KuaiLe","Caveat",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
  background-image:
    radial-gradient(56% 42% at 100% 0%, color-mix(in srgb, var(--accent) 7%, transparent), transparent 60%),
    radial-gradient(50% 38% at 0% 9%, color-mix(in srgb, #38bdf8 9%, transparent), transparent 58%),
    radial-gradient(46% 34% at 50% 100%, color-mix(in srgb, var(--brand) 6%, transparent), transparent 62%);
}
[data-theme="dark"] body:not([data-page="tool"]){ --sticker-edge:#55619c; --sticker-shadow:#05070f; --stk-num:#0b0f1c; }
/* 页首大标题：青色荧光笔贴纸带 */
body:not([data-page="tool"]) .doc-page .doc-hero h1{
  font-family:var(--font-display); font-weight:400; letter-spacing:.02em;
  display:inline-block; padding:2px 14px 5px;
  background:linear-gradient(transparent 56%, color-mix(in srgb, var(--pop-c) 30%, transparent) 56%, color-mix(in srgb, var(--pop-c) 30%, transparent) 93%, transparent 93%);
}
/* 每个内容小节 = 一张贴纸卡 */
body:not([data-page="tool"]) .legal-section{
  background:var(--panel); border:1.5px solid var(--sticker-edge); border-radius:18px;
  box-shadow:4px 5px 0 var(--sticker-shadow); padding:18px 20px;
}
body:not([data-page="tool"]) .legal-section h2{ font-family:var(--font-display); font-weight:400; font-size:19px; width:fit-content; }
/* 技巧列表：糖果条目 */
body:not([data-page="tool"]) .doc-list li{
  background:var(--panel); border:1.5px solid var(--sticker-edge);
  box-shadow:3px 3px 0 var(--sticker-shadow);
}
body:not([data-page="tool"]) .doc-list li::before{ content:"✦ "; color:var(--pop-b); font-weight:700; }
/* FAQ 条目贴纸化（faq.html 与首页共用同一观感） */
body:not([data-page="tool"]) .faq-item{
  background:var(--panel); border:1.5px solid var(--sticker-edge); border-radius:14px;
  box-shadow:4px 5px 0 var(--sticker-shadow);
}
/* 行动召唤区：整块贴纸面板 */
body:not([data-page="tool"]) .doc-cta{
  background:linear-gradient(135deg, color-mix(in srgb, var(--brand) 10%, var(--panel)), var(--panel) 68%);
  border:1.5px solid var(--sticker-edge); border-radius:20px;
  box-shadow:5px 6px 0 var(--sticker-shadow); padding:26px 20px;
}
body:not([data-page="tool"]) .doc-cta h2{ font-family:var(--font-display); font-weight:400; font-size:21px; }
body:not([data-page="tool"]) .doc-cta .btn.primary{
  font-family:var(--font-display); border:1.5px solid var(--sticker-edge);
  border-radius:999px; box-shadow:3px 4px 0 var(--sticker-edge);
}
body:not([data-page="tool"]) .doc-cta .btn.primary:hover{ transform:translate(-1px,-1px); box-shadow:5px 7px 0 var(--sticker-edge); color:#fff; }
/* 联系我们卡（about） */
body:not([data-page="tool"]) .contact-card{ border:1.5px solid var(--sticker-edge); box-shadow:4px 5px 0 var(--sticker-shadow); }
body:not([data-page="tool"]) .contact-card h2{ font-family:var(--font-display); font-weight:400; }
/* 更新日期小胶囊 */
body:not([data-page="tool"]) .doc-updated{
  display:inline-block; padding:3px 12px; border-radius:999px;
  border:1.5px dashed color-mix(in srgb, var(--brand) 45%, var(--line)); background:var(--panel);
}
/* 内容块弹入 */
body:not([data-page="tool"]) .doc-page > *{ animation:wcPop .5s backwards; }
body:not([data-page="tool"]) .doc-page > :nth-child(2){ animation-delay:.07s; }
body:not([data-page="tool"]) .doc-page > :nth-child(3){ animation-delay:.13s; }
body:not([data-page="tool"]) .doc-page > :nth-child(4){ animation-delay:.19s; }

/* ==================== R12 (2026-09-23) — 工具页糖果贴纸风格统一 ====================
   用户点名工具页并入统一风格。纪律：边框≤1.5px、零歪斜、零装饰条；只动视觉属性
   (border/radius/shadow/font-family/background)，不碰布局尺寸与任何文本颜色。 */
body[data-page="tool"]{
  --sticker-edge:#bcc4ec; --sticker-shadow:#c7cff2; --stk-num:#1c2333;
  --font-display:"ZCOOL KuaiLe","Caveat",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
  background-image:
    radial-gradient(56% 42% at 100% 0%, color-mix(in srgb, var(--accent) 6%, transparent), transparent 60%),
    radial-gradient(50% 38% at 0% 9%, color-mix(in srgb, #38bdf8 8%, transparent), transparent 58%),
    radial-gradient(46% 34% at 50% 100%, color-mix(in srgb, var(--brand) 5%, transparent), transparent 62%);
}
[data-theme="dark"] body[data-page="tool"]{ --sticker-edge:#55619c; --sticker-shadow:#05070f; --stk-num:#0b0f1c; }
/* 双面板 = 贴纸卡 */
body[data-page="tool"] .panel{ border:1.5px solid var(--sticker-edge); border-radius:16px; } /* R120: uniform border, no offset shadow */
/* 七页签：胶囊轨道 + active 品牌软底（与顶栏导航同一语言） */
body[data-page="tool"] .tabs{ background:var(--panel2); border:1.5px solid color-mix(in srgb, var(--sticker-edge) 35%, transparent); border-radius:999px; padding:5px; }
body[data-page="tool"] .tab{ border-radius:999px; }
body[data-page="tool"] .tab.active{ background:var(--brand-soft); color:var(--brand); font-weight:700; box-shadow:none; }
/* 分组小标题 = 快乐体 */
body[data-page="tool"] .group-title{ font-family:var(--font-display); font-weight:400; letter-spacing:.02em; }
/* 主行动按钮贴纸化 */
body[data-page="tool"] .btn.primary{ font-family:var(--font-display); border:1.5px solid var(--sticker-edge); box-shadow:3px 4px 0 var(--sticker-shadow); }
body[data-page="tool"] .btn.primary:hover{ transform:translate(-1px,-1px); box-shadow:5px 7px 0 var(--sticker-shadow); color:#fff; }
body[data-page="tool"] .btn.primary:active{ transform:translate(1px,2px); box-shadow:1px 1px 0 var(--sticker-shadow); }
/* 画布框贴纸化 */
body[data-page="tool"] .canvas-wrap{ border:1.5px solid var(--sticker-edge); border-radius:16px; box-shadow:5px 6px 0 var(--sticker-shadow); }
/* 形状分类 active = 渐变胶囊（与预设/语言钮统一） */
body[data-page="tool"] .shape-tab.active{ background:var(--grad); border-color:transparent; }
/* 空状态标题 */
body[data-page="tool"] .empty-state h2{ font-family:var(--font-display); font-weight:400; }
/* 帮助弹窗：修复「无样式裸内容」缺陷 + 贴纸化（遮罩/卡片/关闭钮） */
body[data-page="tool"] .modal{ position:fixed; inset:0; z-index:90; display:grid; place-items:center; padding:24px; background:rgba(10,14,24,.72); }
body[data-page="tool"] .modal-card{ position:relative; width:100%; max-width:520px; background:var(--panel); color:var(--ink); border:1.5px solid var(--sticker-edge); border-radius:18px; box-shadow:6px 8px 0 var(--sticker-shadow); padding:22px 24px; }
body[data-page="tool"] .modal-card h3{ margin:0 0 12px; padding-right:36px; font-family:var(--font-display); font-weight:400; font-size:19px; }
body[data-page="tool"] .modal-close{ position:absolute; top:12px; right:12px; width:32px; height:32px; border-radius:50%; border:1.5px solid var(--sticker-edge); background:var(--panel2); color:var(--ink); font-size:18px; line-height:1; cursor:pointer; display:grid; place-items:center; }
body[data-page="tool"] .modal-close:hover{ border-color:var(--brand); color:var(--brand); }
/* 柱状图弹窗 / 灯箱贴纸化 */
body[data-page="tool"] .bar-card{ border:1.5px solid var(--sticker-edge); box-shadow:6px 8px 0 var(--sticker-shadow); }
body[data-page="tool"] .bar-card h3{ font-family:var(--font-display); font-weight:400; }
body[data-page="tool"] .lightbox img{ border:1.5px solid var(--sticker-edge); }
/* R17 — 表情贴纸条与形状搜索框（工具页） */
.emoji-strip { margin-top: 8px; }
.emoji-strip .chip.icon { font-size: 18px; padding: 4px 9px; line-height: 1.25; }
/* R20 — 手绘形状弹窗 */
.draw-card { text-align: center; }
#drawCanvas { width: min(340px, 78vw); aspect-ratio: 1 / 1; touch-action: none; display: block; margin: 10px auto 12px; background: #fff; border: 1.5px solid var(--sticker-edge, #bcc4ec); border-radius: 14px; cursor: crosshair; }
.draw-tools { justify-content: center; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.draw-tools .btn.sm.active { background: var(--brand-fill); color: #fff; border-color: var(--brand-fill); }
.draw-tools input[type="range"] { width: 110px; }
.draw-tools .label { margin: 0; }
.draw-actions { justify-content: center; gap: 10px; }
/* R22 — 对比图例 / 对比弹窗（R39：收藏/最近使用条已移除） */
.cmp-legend { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 6px; }
.cmp-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink); background: var(--panel2); border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px; }
.cmp-chip::before { content: ""; width: 10px; height: 10px; border-radius: 3px; background: var(--muted); }
.cmp-chip.a::before { background: #2563eb; } .cmp-chip.b::before { background: #db2777; } .cmp-chip.both::before { background: #7c3aed; }
.cmp-card textarea { width: 100%; margin-bottom: 10px; padding: 8px 10px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--input); color: var(--ink); font-family: inherit; font-size: 13px; resize: vertical; }
.cmp-card textarea:focus { outline: 2px solid var(--brand); outline-offset: 1px; }
/* R23 — 图例可点筛选 */
.cmp-chip { cursor: pointer; font-family: inherit; transition: border-color .15s ease, box-shadow .15s ease; }
.cmp-chip:hover { border-color: var(--brand); }
.cmp-chip.active { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-soft); font-weight: 700; }
.cmp-hint { font-size: 11.5px; color: var(--muted); margin-left: 2px; }
/* R24 — 历史版本面板 */
.hist-list { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 6px; max-height: 320px; overflow: auto; }
.hist-item { width: 100%; text-align: left; padding: 8px 12px; border: 1.5px solid var(--line); border-radius: 10px; background: var(--panel2); color: var(--ink); font-size: 13px; cursor: pointer; font-family: inherit; transition: border-color .15s ease, color .15s ease; }
.hist-item:hover { border-color: var(--brand); color: var(--brand); }
.hist-item.cur { background: var(--brand-soft); border-color: var(--brand); color: var(--brand); font-weight: 700; cursor: default; }
.hist-empty { font-size: 12.5px; color: var(--muted); padding: 4px 2px; }

/* R25 — 高亮定位 + 停用词包 + 语境弹窗 */
.hl-ctl { display: inline-flex; align-items: center; gap: 6px; }
.hl-input { width: 150px; padding: 7px 12px; border: 1.5px solid var(--sticker-edge, var(--line)); border-radius: 999px; background: var(--panel2); color: var(--ink); font-size: 13px; font-family: inherit; }
.hl-input:focus { outline: 2px solid var(--brand); outline-offset: 1px; }
.stop-pack-row { gap: 8px; margin-top: 6px; }
.ctx-card { max-width: 560px; }
.ctx-list { list-style: none; margin: 10px 0 4px; padding: 0 2px 0 0; max-height: 320px; overflow: auto; display: flex; flex-direction: column; gap: 8px; }
.ctx-list li { padding: 9px 12px; border: 1.5px solid var(--sticker-edge, var(--line)); border-radius: 10px; background: var(--panel2); font-size: 14px; line-height: 1.6; color: var(--ink); }
.ctx-list mark { background: #fde68a; color: #1c2333; padding: 0 2px; border-radius: 4px; }
.ctx-count { margin: 2px 0 0; font-size: 13px; }
@media (max-width: 640px) { .hl-input { width: 110px; } }

/* R26（R115 起幻灯片已删除）— 历史时间 + 只看选中 */
.hist-item { display: flex; align-items: center; gap: 8px; }
.hist-time { margin-left: auto; font-size: 12px; opacity: 0.62; }
.btn-link.active { color: var(--brand); font-weight: 700; }

/* R27 — 填充控制块与描边控制块同构（成对控件统一样式契约） */
.shape-fill-ctl { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel2); display: flex; flex-direction: column; gap: 8px; }
.shape-fill-ctl .check { font-size: 13px; font-weight: 600; }
.fill-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.fill-row .label { font-size: 12px; color: var(--muted); margin: 0; }
.fill-row input[type="color"] { width: 34px; height: 26px; padding: 0; border: 1px solid var(--line); border-radius: 6px; background: none; cursor: pointer; }

/* R27b — 移动端英文长按钮换行，消除 2px 横向溢出 */
@media (max-width: 640px) {
  .strip-head { flex-wrap: wrap; }
  .strip-head .row { min-width: 0; max-width: 100%; }
  .strip-head .btn.sm { white-space: normal; text-align: center; }
}

/* R30 — 无缩略图存档占位 */
.saved-noimg { width: 100%; height: 84px; display: flex; align-items: center; justify-content: center; font-size: 30px; color: var(--muted); background: var(--panel2); }

/* R31 — 排版修复（字数胶囊防挤压/工具条右对齐）+ 词频标签与 FAQ 加浓 */
#charCount { flex: none; white-space: nowrap; }
.textarea-head { align-items: flex-start; gap: 10px; }
.mini-actions { justify-content: flex-end; row-gap: 4px; }
#freqPanelTitle { padding: 4px 11px; border-radius: 999px; background: color-mix(in srgb, var(--brand) 12%, transparent); }
.faq-item { border-color: var(--sticker-edge, var(--line)); background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 5%, var(--panel)), var(--panel)); }
.faq-item[open] { box-shadow: 0 8px 20px rgba(91, 108, 249, 0.12); }
.faq-item summary::after { border-color: var(--brand); }

/* R32 — 桌面端文本输入区加高，消除左面板底部空档（文本/词频成对同高） */
@media (min-width: 1000px) {
  #textInput, #freqInput { min-height: 320px; }
}

/* R33 — 英文标题字体分流（ZCOOL 拉丁字形小字号不可读）+ 移动端导航可滑渐隐提示 */
html[lang="en"], html[lang="en"] body { --font-display: "Oswald", "Caveat", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; }
@media (max-width: 640px) {
  .top-nav { -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%); mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%); }
}

/* R37 — 滑杆行：标签+滑杆+数值框同行；数值框胶囊化（支持手输/上下箭头） */
.slider-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.slider-row > .label, .slider-row > label { margin: 0; flex: 0 0 auto; }
.slider-row > input[type="range"] { flex: 1 1 120px; min-width: 90px; margin: 0; }
.slider-num { width: 72px; flex: 0 0 auto; padding: 4px 6px; border: 1.5px solid var(--sticker-edge, var(--line)); border-radius: 10px; background: var(--panel2); color: var(--ink); font-family: inherit; font-size: 12.5px; text-align: center; font-variant-numeric: tabular-nums; }
.slider-num:focus { outline: 2px solid var(--brand); outline-offset: 1px; }
@media (max-width: 640px) { .slider-num { width: 64px; min-height: 32px; } }

/* R41 — 滑杆行对齐：禁换行、数值列固定右缘、轨道统一 */
.slider-row { flex-wrap: nowrap; row-gap: 0; }
.slider-row > .label, .slider-row > label { flex: 0 0 auto; }
.slider-row > input[type="range"] { flex: 1 1 60px; min-width: 60px; max-width: none; }
.slider-row > span { flex: 0 0 auto; }
.slider-num { width: 72px; min-width: 56px; }
.slider-row input[type="range"]::-webkit-slider-runnable-track { height: 5px; border-radius: 3px; }
.slider-row input[type="range"]::-moz-range-track { height: 5px; border-radius: 3px; }
@media (max-width: 640px) {
  .slider-row > input[type="range"] { flex: 1 1 46px; min-width: 46px; }
  .slider-num { width: 64px; min-width: 50px; }
}

/* R44 — 批量操作文字钮升级为贴纸胶囊钮（激活实心、禁用降透、危险色独立） */
.words-batch .btn-link {
  padding: 6px 14px; border: 1.5px solid var(--sticker-edge); border-radius: 999px;
  background: var(--panel2); color: var(--brand); font-weight: 600; font-size: 12.5px;
  min-height: 30px; transition: background .15s ease, border-color .15s ease, color .15s ease, box-shadow .15s ease, opacity .15s ease;
}
.words-batch .btn-link:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--brand) 55%, var(--sticker-edge));
  background: color-mix(in srgb, var(--brand) 8%, var(--panel2)); color: var(--brand);
}
.words-batch .btn-link:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 22%, transparent); }
.words-batch .btn-link.danger { color: var(--danger); }
.words-batch .btn-link.danger:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--danger) 55%, var(--sticker-edge));
  background: color-mix(in srgb, var(--danger) 8%, var(--panel2)); color: var(--danger);
}
.words-batch .btn-link:disabled { opacity: .45; cursor: not-allowed; }
.words-batch .btn-link.active { background: var(--brand-fill); border-color: var(--brand-fill); color: #fff; }
.words-batch .btn-link.active:hover:not(:disabled) { color: #fff; background: var(--brand-fill); border-color: var(--brand-fill); }

/* R45 batch-pair — 批量设置区：控件与其按钮一行成对，按钮右列对齐，圆角/高度统一 */
.word-batch-row { display: flex; flex-direction: column; align-items: stretch; gap: 8px; }
.batch-pair { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; }
.batch-pair > input[type="color"], .batch-pair > input[type="checkbox"] { justify-self: start; }
.batch-pair select { width: 100%; border-radius: 10px; border: 1.5px solid var(--sticker-edge, var(--line)); background: var(--panel2); height: 34px; }
.batch-pair input[type="number"] { border-radius: 10px; border: 1.5px solid var(--sticker-edge, var(--line)); background: var(--panel2); height: 34px; width: 100% !important; }
.batch-pair #batchColor { width: 46px; height: 34px; border-radius: 10px; border: 1.5px solid var(--sticker-edge, var(--line)); }
.batch-pair #batchRepeat { width: 18px; height: 18px; accent-color: var(--brand); }
.batch-pair .btn.sm { min-width: 88px; min-height: 34px; justify-content: center; border-radius: 10px; border: 1.5px solid var(--sticker-edge, var(--line)); }

/* R50 3col — 工具页三栏：左 内容/词表 · 中 画布 · 右 形状/样式/排版/预设/导出 */
body.tool-page .workspace { grid-template-columns: minmax(300px, 380px) minmax(0, 1fr) minmax(280px, 360px); }
@media (min-width: 1700px) {
  body.tool-page .workspace { grid-template-columns: 440px minmax(0, 1fr) 400px; }
}
@media (max-width: 1279px) {
  body.tool-page .workspace { grid-template-columns: 1fr; }
  .side-panel { position: static; max-height: none; }
  .stage-panel { min-height: 56vh; }
}
.side-panel .tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
.side-panel .tabs::-webkit-scrollbar { display: none; }
.side-panel .tab { flex: 1 0 auto; white-space: nowrap; padding: 8px 10px; }

/* R52 saved-pane — 我的词云并入左栏页签：窄栏两列卡片 + 头部按钮换行 */
.side-panel-left .saved-list { gap: 10px; }
.side-panel-left .saved-card { width: calc(50% - 5px); min-width: 130px; }
.side-panel-left #pane-saved .row.gap { flex-wrap: wrap; }
.side-panel-left #savedEmpty { margin-top: 4px; }

/* R53 batch-one-row — 批量操作六钮挤进同一行：紧凑胶囊、计数移至标题行右侧、超窄时横向滚动 */
.batch-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.words-batch { flex-wrap: nowrap; gap: 5px; overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
.words-batch::-webkit-scrollbar { display: none; }
.words-batch .btn-link { padding: 5px 8px; font-size: 11px; min-height: 26px; white-space: nowrap; flex: 0 0 auto; }
@media (max-width: 1500px) {
  .words-batch { gap: 4px; }
  .words-batch .btn-link { padding: 4px 6px; font-size: 10.5px; }
}
.batch-head .muted { font-size: 11px; white-space: nowrap; }

/* R54 batch-2up — 批量设置五组两列排布：一行两组，控件+按钮更紧凑 */
.word-batch-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; }
.batch-pair { gap: 6px; }
.batch-pair select, .batch-pair input[type="number"] { height: 30px; font-size: 12px; border-radius: 9px; }
.batch-pair .btn.sm { min-width: 72px; min-height: 30px; font-size: 11.5px; padding: 4px 8px; border-radius: 9px; }
.batch-pair #batchColor { width: 40px; height: 30px; }
@media (max-width: 520px) {
  .word-batch-row { grid-template-columns: 1fr; }
}

/* R55 row-wrap-safety — 含说明文字的滑杆行允许换行；提示永不压成竖排；成对控件不拆行 */
.slider-row:has(.hint) { flex-wrap: wrap; row-gap: 4px; }
.slider-row .hint { flex: 1 1 100%; min-width: 0; white-space: normal; }
.slider-row .check { flex: 0 0 auto; white-space: nowrap; }
.slider-row .color-pair { flex: 0 0 auto; }
.side-panel .row:has(.hint) { flex-wrap: wrap; row-gap: 4px; }
.side-panel .row > .hint { flex: 1 1 100%; }

/* R56 shape-size — 形状尺寸控件行：宽/高/半径三格 */
.shape-size-dims { margin-top: 8px; }
.ss-cell { display: flex; align-items: center; gap: 6px; flex: 1 1 auto; min-width: 0; }
.ss-cell .label { margin: 0; font-size: 12px; white-space: nowrap; }
.ss-cell .slider-num { width: 84px; }

/* R59 batch-3up — 批量组一行三组（字体/角度/字号 + 设色/重复），单元格紧凑 */
.word-batch-row { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 8px; }
.batch-pair { gap: 4px; min-width: 0; }
.batch-pair select, .batch-pair input[type="number"] { min-width: 0; height: 28px; font-size: 11px; border-radius: 8px; padding: 2px 4px; }
.batch-pair .btn.sm { min-width: 0; flex: 0 0 auto; min-height: 28px; font-size: 11px; padding: 3px 6px; border-radius: 8px; }
.batch-pair #batchColor { width: 34px; height: 28px; }
.batch-pair #batchRepeat { width: 16px; height: 16px; }
@media (max-width: 1500px) { .batch-pair select { font-size: 10.5px; } }
@media (max-width: 520px) { .word-batch-row { grid-template-columns: 1fr; } .batch-pair select { font-size: 12px; } }

/* R60 batch-box — 批量操作整体装箱：描边圆角框 + 框内标题，导出行留在框外 */
.batch-box { border: 1.5px solid var(--sticker-edge); border-radius: 12px; padding: 10px 12px 12px; margin: 0 0 12px; background: var(--panel); }
.batch-box .batch-head { margin-bottom: 8px; }
.batch-box .group-title { margin: 0; }
.batch-box .words-batch { margin-bottom: 10px; }
.batch-box .word-batch-row { margin-top: 0; margin-bottom: 0; }
/* R72 — 批量胶囊行：装不下时换行，不再被隐藏滚动条裁掉（宽面板仍保持一行） */
.words-batch { flex-wrap: wrap; overflow-x: visible; row-gap: 6px; }

/* R73 batch-2up — 批量组一行两组，每组「文字标签 + 控件 + 应用」三件套 */
.word-batch-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.batch-pair { grid-template-columns: auto minmax(0, 1fr) auto; }
.bp-label { font-size: 11px; color: var(--muted); white-space: nowrap; }
@media (max-width: 520px) { .word-batch-row { grid-template-columns: 1fr; } }

/* R74 angle-box — 角度预设加外框：与批量操作同款贴纸盒，替换旧左竖线 */
#rotateAngleField { margin-left: 0; padding: 10px 12px 12px; border: 1.5px solid var(--sticker-edge); border-radius: 12px; background: var(--panel); }
#rotateAngleField .label { margin-bottom: 2px; }

/* R79 — 手绘全屏画板：弹窗铺满视口，画布吃满剩余高度（位图仍 1040²，pos() 自动换算） */
#drawModal.draw-full .modal-card { width: 96vw; max-width: none; height: 94vh; display: flex; flex-direction: column; }
#drawModal.draw-full #drawCanvas { width: min(94vw, calc(94vh - 210px)); margin: 8px auto 10px; }
.shape-btn.draw-entry { border-style: dashed; }

/* R80 pane-box — 设置面板分组装盒：与批量操作同款贴纸盒，盒头即组标题 */
.pane-box { border: 1.5px solid var(--sticker-edge); border-radius: 12px; padding: 10px 12px 12px; background: var(--panel); margin: 0 0 12px; }
.pane-box > .group-title, .pane-box > .exp-group, .pane-box > .label:first-child { margin-top: 0; }
.pane-box > .field:first-of-type { margin-top: 0; }
.pane-box > .field:last-child, .pane-box > .row:last-child, .pane-box > .chips:last-child { margin-bottom: 0; }
.pane-box .hint:last-child { margin-bottom: 0; }

/* R83 angle-gap — 角度预设盒与旋转段控件之间留出呼吸间距 */
#rotateAngleField { margin-top: 12px; }
/* R87 — 轮廓行拆成两个不换行小组（色块+滑杆），面板窄时整组换行，色块与数值框都不再被挤扁 */
.outline-row .octl { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.outline-row .octl input[type=range] { flex: none; width: 60px; min-width: 60px; max-width: 60px; }
/* R88 — 手绘弹窗美化：标题+区域徽章同行、虚线提示条、画布空态引导、模式分段钮、禁用态 */
#drawModal .draw-card { max-width: 560px; }
.draw-head { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 0 0 8px; }
body[data-page="tool"] .draw-head h3 { margin: 0; padding-right: 0; }
.draw-stat { font-size: 12px; color: var(--muted); background: var(--panel2); border: 1.5px solid var(--sticker-edge); border-radius: 999px; padding: 2px 10px; font-variant-numeric: tabular-nums; }
.draw-hint { text-align: left; background: var(--panel2); border: 1px dashed var(--sticker-edge); border-radius: 12px; padding: 8px 12px; font-size: 12.5px; line-height: 1.7; }
.draw-canvas-wrap { position: relative; display: flex; justify-content: center; }
.draw-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; text-align: center; padding: 0 28px; font-size: 13px; color: var(--muted); pointer-events: none; }
.draw-empty.hidden { display: none; }
.draw-tools .btn.sm:disabled { opacity: .45; cursor: not-allowed; }
.draw-tools .seg { align-self: center; }

/* R89 — 文字/图片浮层面板：元素缩略列表 + 编辑器分组 + 危险删除钮 */
.ov-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 2px; }
.ov-chips:empty { display: none; }
.ov-chip { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 5px 10px 5px 6px; font-size: 12.5px; color: var(--ink); background: var(--panel2); border: 1.5px solid var(--sticker-edge); border-radius: 999px; cursor: pointer; }
.ov-chip.active { border-color: var(--brand-fill); background: var(--panel); color: var(--brand-fill); }
.ov-chip .ov-tx { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 96px; }
.ov-ic { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--brand-fill); color: #fff; font-size: 12px; flex: none; }
.ov-editor { margin-top: 12px; padding-top: 12px; border-top: 1.5px dashed var(--sticker-edge); display: flex; flex-direction: column; gap: 10px; }
.ov-editor .seg.mini { align-self: flex-start; }
.ov-editor .field { margin: 0; }
#ovText { width: 100%; }
#ovFont { flex: 1; min-width: 0; }
.btn.danger { color: #b42318; border-color: rgba(180, 35, 24, .45); }
.btn.danger:hover { background: rgba(180, 35, 24, .1); }

/* R91 — 颜色控件统一：取色器 + 可手输 #RRGGBB 色值框；带标签的颜色行竖排，色块单独成行 */
.color-pair:has(> div > input[type="color"]) { flex-direction: column; align-items: stretch; gap: 8px; }
.color-pair > div { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.color-pair > div > label { display: inline-block; margin: 0; flex: 0 0 auto; min-width: 66px; font-size: 12.5px; color: var(--muted); }
.color-pair > div > input[type="color"] { flex: 0 0 auto; }
.color-pair > div > label, .octl > label { white-space: nowrap; flex: 0 0 auto; }
input.color-hex { flex: 0 0 auto; width: 92px; padding: 5px 8px; font-family: ui-monospace, Consolas, "Courier New", monospace; font-size: 12.5px; text-transform: uppercase; text-align: center; letter-spacing: .5px; color: var(--ink); background: var(--panel2); border: 1.5px solid var(--sticker-edge); border-radius: 9px; }
.color-hex:focus { outline: 2px solid var(--brand); outline-offset: 1px; border-color: var(--brand); }
.color-hex.bad { border-color: #d14343; color: #d14343; }

/* R92 — 二级选项块与上方控件统一留 10px：描边粗细块此前与「文字样式」分段钮 0 间距贴在一起 */
#strokeWidthField, #strokeGradField, #textOutlineOptsField, #textGradOptsField, #textPlateOptsField, #textGrainOptsField, #shadowOptsField, #shapeSizeDims { margin-top: 10px; }

/* R92b — 折叠面板标题与首个选项、说明文字与其后控件之间同样留 10px */
.acc summary + *, .hint + .check, .hint + .row { margin-top: 10px; }

/* R93 — 浮层编辑器排版：统一「标签 + 控件」行，标签固定宽不被挤换行，控件占满剩余 */
.ov-editor .ov-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ov-editor .ov-row > .label { flex: 0 0 62px; margin: 0; white-space: nowrap; }
.ov-editor .ov-row > input[type="range"] { flex: 1 1 60px; min-width: 60px; max-width: none; }
.ov-editor .ov-row > input[type="text"], .ov-editor .ov-row > select { flex: 1 1 120px; min-width: 0; }
.ov-editor .ov-row > output, .ov-editor .ov-row > .slider-num { flex: 0 0 auto; }
.ov-editor .ov-row-seg > .seg { flex: 1 1 auto; }
.ov-editor > label.check { align-self: flex-start; }

/* R96 — 工具页去掉「某几条边更粗」的效果：硬偏移投影会让右/下边看起来像加粗边框，
   改为四边只由等宽描边表达（首页/文档页的贴纸投影不受影响）。 */
body[data-page="tool"] .canvas-wrap { box-shadow: none; }
body[data-page="tool"] .panel { box-shadow: none; }
body[data-page="tool"] .side-panel,
body[data-page="tool"] .stage-panel { box-shadow: none; }
/* ============ R100: 面板内堆叠控件统一 10px 呼吸位 ============
   用户点名：文字浮层编辑器 内容/字体/字号/颜色 四行贴死（行距 0），形状背景「图片」的
   缩放/左右/上下 三行同样贴死。r100_gap_audit.cjs 扫遍 8 个 pane × 各展开态后一并补齐。
   只补间距、不动尺寸；标题(.label)与它自己的控件仍保持原有 6px 贴合。 */
body[data-page="tool"] .side-panel #ovTextCtl,
body[data-page="tool"] .side-panel #ovImageCtl,
body[data-page="tool"] .side-panel #ovBorderRow,
body[data-page="tool"] .side-panel #ovGradRow,
body[data-page="tool"] .side-panel #sfillImagePosRow,
body[data-page="tool"] .side-panel [id$="OptsField"]:not(.color-pair) { display: flex; flex-direction: column; gap: 10px; }
body[data-page="tool"] .side-panel .acc > * + *,
body[data-page="tool"] .side-panel .batch-box > * + *,
body[data-page="tool"] .side-panel .field > * + *:not(output),
body[data-page="tool"] .side-panel .pane-box > .exp-group + *,
body[data-page="tool"] .side-panel .words-foot + *,
body[data-page="tool"] .side-panel .textarea-head + *,
body[data-page="tool"] .side-panel .muted + .field { margin-top: 10px; }
body[data-page="tool"] .side-panel .field > .label + *:not(output),
body[data-page="tool"] .side-panel .acc > .label + * { margin-top: 0; }
body[data-page="tool"] .side-panel .textarea-head { margin-bottom: 0; }
body[data-page="tool"] .side-panel .pane-box > .hint { margin-top: 8px; }
/* R100c — gap 与子元素自带 margin 会叠加（.check 自带 7px 时实测 17/24px）：分组内一律清零。 */
body[data-page="tool"] .side-panel :is(#ovTextCtl, #ovImageCtl, #ovBorderRow, #ovGradRow, #sfillImagePosRow, [id$="OptsField"]:not(.color-pair), .ov-editor) > *,
body[data-page="tool"] .side-panel :is(.shape-fill-ctl, .shape-outline-ctl, .word-batch-row) > * { margin-top: 0; margin-bottom: 0; }
/* 这些容器本来就是纵向 flex，节奏交给 gap */
body[data-page="tool"] .side-panel :is(.shape-fill-ctl, .shape-outline-ctl, .word-batch-row) { gap: 10px; }
body[data-page="tool"] .side-panel .color-pair:has(> div > input[type="color"]) { gap: 10px; }
/* ============ R102: 导出下载框（标题 + 两列三行，PNG 移入框内） ============ */
/* #exportMore 原本靠 .export-more{display:flex} 排版；现在框内是「标题 + 网格」，改成块级。 */
body[data-page="tool"] #exportMore { display: block; margin-top: 10px; }
body[data-page="tool"] #exportMore .dl-title { display: block; font-size: 11.5px; font-weight: 700;
  letter-spacing: .06em; color: var(--muted); }
body[data-page="tool"] #exportMore .dl-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-top: 10px; }
body[data-page="tool"] #exportMore .dl-grid .btn { min-height: 36px; justify-content: center; text-align: center; }
/* 原来这两条挂在 .export-actions 上，按钮换容器后要原样复活 */
body[data-page="tool"] #exportMore .dl-grid .btn:not(.primary):hover { transform: translateY(-1px); box-shadow: var(--shadow); }
@media (max-width: 520px) { body[data-page="tool"] #exportMore .dl-grid { grid-template-columns: 1fr; } }
/* ================= /R102 ================= */
/* ============ R105: 全站取消「硬偏移投影」这种额外粗框 ============
   用户点名手绘弹窗（含全屏）右/下那条粗边，并要求所有页面都不要这类额外的粗框。
   这些粗框全部是 blur=0 的硬偏移 box-shadow（R96 已为工具页面板/画布台去掉，本轮清全站）。
   做法：把只被 box-shadow 引用的 --sticker-shadow 令牌在全部 6 个定义处改成 transparent，
   于是所有 Xpx Ypx 0 var(--sticker-shadow) 一次性失效；少数把 --sticker-edge 当投影色的按钮
   再单独清零。1.5px 贴纸描边、圆角、糖果底色、显示字体全部保留 = 与其他元素一致的细框语言。 */
body[data-page="home"], [data-theme="dark"] body[data-page="home"],
body:not([data-page="tool"]), [data-theme="dark"] body:not([data-page="tool"]),
body[data-page="tool"], [data-theme="dark"] body[data-page="tool"] { --sticker-shadow: transparent; }
body[data-page="home"] .btn.primary, body[data-page="home"] .btn.primary:hover,
body:not([data-page="tool"]) .doc-cta .btn.primary,
body:not([data-page="tool"]) .doc-cta .btn.primary:hover { box-shadow: none; }
/* ================= /R105 ================= */
/* ============ R107: 词表词频框对齐主题（R109 起这是唯一的添加行） ============
   #addWordFreq(.add-word-row .wt-in) 历史上只拿到 height/padding，没有任何边框、圆角、
   底色与字色规则 —— 于是它掉回浏览器默认的「白底 + 2px inset 灰边 + 黑字」。这里把主题化
   规则直接挂到本行选择器上（原先寄存在已被删除的重复行规则里）。 */
body[data-page="tool"] .add-word-row .wt-in {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--panel2); color: var(--ink); font-family: inherit; font-size: 13px; outline: none;
  width: 68px; flex: none;
}
body[data-page="tool"] .add-word-row .wt-in:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent);
}
/* ================= /R107 ================= */

/* ================= /R102 ================= */
/* ============ R110: 「数据导出」去掉两个分享按钮后改为一行两个 ============
   与上方 #exportMore .dl-grid 同形状：两列等宽网格，窄屏收成单列。 */
body[data-page="tool"] .export-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
body[data-page="tool"] .export-actions .btn { min-height: 36px; justify-content: center; text-align: center; }
@media (max-width: 520px) { body[data-page="tool"] .export-actions { grid-template-columns: 1fr; } }
/* ================= /R110 ================= */
/* ============ R113: 缩放工具条高度协调 ============
   .zoom-ctl 原本是 44px 高（内部 .btn.icon 继承 min-height:38 + 2px 内衬 + 1px 边框），
   比同一行的搜索框(33)和上一行的主按钮(38)都高，视觉上鼓出来一截。压到 34px 与搜索框齐平；
   触屏设备保留 38px 命中区（胶囊随之 44px，触摸下不追求与搜索框等高）。
   注意：本层内 coarse 断点写在基础规则之后，同特异性下按层叠顺序生效。 */
body[data-page="tool"] .zoom-ctl { padding: 2px 5px; }
body[data-page="tool"] .zoom-ctl .btn.icon { min-height: 28px; height: 28px; padding: 0 8px; font-size: 15px; }
body[data-page="tool"] .hl-input { min-height: 34px; }
@media (pointer: coarse) {
  body[data-page="tool"] .zoom-ctl .btn.icon { min-height: 38px; height: 38px; }
  body[data-page="tool"] .zoom-ctl { padding: 2px 6px; }
}
/* ================= /R113 ================= */
/* ============ R115: 「我的」面板卡片美化 ============
   原来两张卡靠 flex 换行 + calc(50% - 5px)，缩略图矮、标题与日期挤成一行、三个操作是散着的文字链。
   改成两列等宽网格（与导出框同款节奏）：缩略图加高、名称/日期分行对齐、操作收进带分隔线的等宽页脚条，
   空列表时给一个虚线占位面板，避免只剩一颗孤零零的卡。页脚宽度一律用百分比（flex-grow 在用户浏览器上
   曾出现 CSSOM 不生效导致 0 宽的老问题）。 */
body[data-page="tool"] #pane-saved .saved-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
body[data-page="tool"] #pane-saved .saved-card { width: auto; min-width: 0; border-radius: 14px; background: var(--panel); }
body[data-page="tool"] #pane-saved .saved-card img { height: 112px; }
body[data-page="tool"] #pane-saved .saved-card .meta { flex-direction: column; align-items: stretch; gap: 1px; padding: 8px 10px 6px; }
body[data-page="tool"] #pane-saved .saved-card .name { font-size: 12.5px; line-height: 1.35; }
body[data-page="tool"] #pane-saved .saved-card .muted { font-size: 11px; letter-spacing: .02em; font-variant-numeric: tabular-nums; }
body[data-page="tool"] #pane-saved .saved-card .acts { margin-top: 2px; padding: 0; border-top: 1px solid var(--line); }
body[data-page="tool"] #pane-saved .saved-card .acts .btn-link { flex: none; width: 33.3333%; min-width: 0; height: 30px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center; font-size: 11.5px; border-radius: 0; transition: background .14s ease; }
body[data-page="tool"] #pane-saved .saved-card .acts .btn-link + .btn-link { border-left: 1px solid var(--line); }
body[data-page="tool"] #pane-saved .saved-card .acts .btn-link:hover { background: color-mix(in srgb, var(--brand) 12%, transparent); }
body[data-page="tool"] #pane-saved .saved-card .acts .btn-link.danger:hover { background: color-mix(in srgb, var(--danger) 16%, transparent); }
body[data-page="tool"] #pane-saved #savedEmpty { margin-top: 10px; padding: 18px 12px; text-align: center;
  border: 1.5px dashed var(--line); border-radius: 14px; background: color-mix(in srgb, var(--panel2) 55%, transparent); }
@media (max-width: 520px) { body[data-page="tool"] #pane-saved .saved-list { grid-template-columns: 1fr; } }
/* ================= /R115 ================= */
/* ============ R116: 可达性与口径修复层 ============
   全站体检（8 页 × 双语 × 双主题 × 三视口，真实像素采样）只剩两处不达标：
   ① 页脚链接沿用 --muted(#667085)，在最浅的背景补丁上只有 4.38:1（AA 要 4.5）；
      链接是可操作控件，不能用次级说明色 —— 浅色主题下改用更深的次级墨色，暗色维持 --muted。
   ② 同层的形状尺寸下拉首项文案与词典死键清理见 i18n.js。 */
.footer a { color: #545e73; }
[data-theme="dark"] .footer a { color: var(--muted); }
/* ================= /R116 ================= */

/* ============ R120: 在线工具页底部收拢（仅此页；其余 6 页页脚保持两行 + 法务链接） ============
   工具页页脚现在只有一行版权与本地处理说明，26/34px 的上下留白显得空荡 —— 收到 10/12px。 */
body[data-page="tool"] .footer { padding: 10px 16px 12px; font-size: 12.5px; }
body[data-page="tool"] .footer .footer-line { gap: 4px 8px; }
body[data-page="tool"] .footer p { margin: 0; }
/* 用户二次点名：文字上方仍空一截 —— 那 40px 不在页脚里，是工具页 main 的下内边距（body.tool-page main 的 40px）。 */
body[data-page="tool"] main { padding-bottom: 10px; }
/* ================= /R120-footer ================= */

/* ============ R125: 可达性与可读性修复层 ============
   ① 品牌色压在品牌软底上不达 AA：实测浅色 --brand(#4a57ec) on #e6e7fc = 4.45、
      --muted(#667085) on 同一底 = 4.07；暗色 --brand(#818cf8) on #33395e = 3.73。
      这类「强调态」（.tab.active / .seg-btn:hover / .top-nav a.active / .stats / 逐词 output 等）
      全站有 8 条规则命中，补一个 --brand-ink 专门用在品牌软底上（浅 5.83 / 暗 4.96）。
      暗色取 #a4adfb 而不是更早的 #98a2f8：页签压在 --panel2 上合成出 #343d6c，
      实测 #98a2f8 只有 4.42（不到 AA），#a4adfb 才到 4.96。
   ② 批量字体下拉在桌面只有 ~91px（文字区 37px），选中「Archivo Black 超粗无衬线」(117px)
      这类长名被硬裁切且没有省略号；逐词字体列只有 62px 可用（最长 134px）。
   ③ 粗指针（手机）下批量框控件 26–28px、复选框 16px，低于本站 34px 的触控约定。 */
:root { --brand-ink: #3d49c4; --muted-on-soft: #545e73; }
[data-theme="dark"] { --brand-ink: #a4adfb; --muted-on-soft: var(--muted); }
.side-panel .field > output, .stage-toolbar .stats, .seg-btn:hover, .top-nav a:hover,
.top-nav a.active, body[data-page="tool"] .tab.active, .hist-item.cur { color: var(--brand-ink); }
.stage-toolbar .stats.muted, .side-panel #charCount { color: var(--muted-on-soft); }
body[data-page="tool"] .batch-box .word-batch-row > .batch-pair:first-child { grid-column: 1 / -1; }
body[data-page="tool"] .batch-box .batch-pair select { min-width: 0; text-overflow: ellipsis; }
body[data-page="tool"] .word-table select.wt-sel { text-overflow: ellipsis; }
body[data-page="tool"] .word-table .wt-font select.wt-sel { min-width: 96px; max-width: 150px; }
@media (pointer: coarse) {
  body[data-page="tool"] .batch-box .words-batch .btn-link { min-height: 34px; padding: 6px 12px; }
  body[data-page="tool"] .batch-box .batch-pair select,
  body[data-page="tool"] .batch-box .batch-pair input[type="number"],
  body[data-page="tool"] .batch-box .batch-pair .btn.sm { min-height: 34px; }
  body[data-page="tool"] .batch-box .batch-pair #batchColor { width: 44px; height: 34px; }
  body[data-page="tool"] .batch-box .batch-pair #batchRepeat { width: 22px; height: 22px; }
}
/* ================= /R125 ================= */

/* ============ R127: 兼容性兜底与移动视口 ============
   ① color-mix() 全站 75 处，老引擎（Safari<16.2 / Chrome<111 / FF<113）判整条无效 →
      吸顶栏背景、焦点环、选中态底全部消失。这里只兜「功能必需」的十几条：
      对 transparent 的百分比混合可精确换成同 alpha 的 rgba；对不透明基色的（形状按钮选中底）
      按 mix 公式预算成静态 hex（浅 #edeefd / 暗 #212844）。装饰性的棋盘格/悬停阴影不兜，
      丢了只是不好看，不影响可用性。
   ② 侧栏 max-height 用 100vh 在移动端会被浏览器工具栏吃掉一截（滚到底也露不出来），
      双声明补 100dvh（老引擎保留 vh，新引擎用 dvh）。
   现代浏览器整段 @supports 不生效，级联零影响 —— 由 r127_verify 断言。 */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
  .topbar { background: rgba(255, 255, 255, .88); }
  [data-theme="dark"] .topbar { background: rgba(22, 29, 48, .88); }
  textarea:focus, input[type="text"]:focus, select:focus { box-shadow: 0 0 0 3px rgba(74, 87, 236, .18); }
  [data-theme="dark"] textarea:focus, [data-theme="dark"] input[type="text"]:focus, [data-theme="dark"] select:focus { box-shadow: 0 0 0 3px rgba(129, 140, 248, .18); }
  input[type="range"]:focus-visible { box-shadow: 0 0 0 4px rgba(74, 87, 236, .16); }
  [data-theme="dark"] input[type="range"]:focus-visible { box-shadow: 0 0 0 4px rgba(129, 140, 248, .16); }
  .side-panel .field select:focus { box-shadow: 0 0 0 3px rgba(74, 87, 236, .16); }
  [data-theme="dark"] .side-panel .field select:focus { box-shadow: 0 0 0 3px rgba(129, 140, 248, .16); }
  .saved-card:focus-within { box-shadow: 0 0 0 2px rgba(74, 87, 236, .22); }
  [data-theme="dark"] .saved-card:focus-within { box-shadow: 0 0 0 2px rgba(129, 140, 248, .22); }
  .palette-btn.active { box-shadow: 0 0 0 2.5px rgba(74, 87, 236, .22); }
  [data-theme="dark"] .palette-btn.active { box-shadow: 0 0 0 2.5px rgba(129, 140, 248, .22); }
  .tpl-card.active { box-shadow: 0 0 0 2px rgba(74, 87, 236, .28); }
  [data-theme="dark"] .tpl-card.active { box-shadow: 0 0 0 2px rgba(129, 140, 248, .28); }
  .shape-btn.active { background: #edeefd; box-shadow: 0 0 0 2px rgba(74, 87, 236, .25); }
  [data-theme="dark"] .shape-btn.active { background: #212844; box-shadow: 0 0 0 2px rgba(129, 140, 248, .25); }
  .canvas-wrap { box-shadow: var(--shadow), inset 0 0 0 1px rgba(28, 35, 51, .05); }
  [data-theme="dark"] .canvas-wrap { box-shadow: var(--shadow), inset 0 0 0 1px rgba(233, 237, 247, .05); }
}
@media (min-width: 1021px) {
  .side-panel { max-height: calc(100vh - 84px); max-height: calc(100dvh - 84px); }
}
.lightbox img { max-height: 92vh; max-height: 92dvh; }
/* ================= /R127-compat ================= */
/* R127 启动看门狗横条：出错时才存在，贴在顶部、不遮挡操作 */
.boot-error { position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 999; background: var(--panel); border: 1.5px solid var(--danger); border-radius: 12px; box-shadow: var(--shadow-lg); padding: 12px 14px; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.boot-error-txt { margin: 0; font-size: 13px; font-weight: 600; color: var(--danger); flex: 1 1 240px; }
.boot-error-acts { display: flex; gap: 8px; flex: none; }
/* ================= /R127-boot ================= */
/* ============ R128: 首屏图比例 / 锚点落点 / 降级动效 / 焦点环回退 ============
   ① 首屏海报 og-image.png 是 1200×630，CSS 只写 width:100% + max-width:460px；R127 为防 CLS
     补的 width/height 属性会把**渲染高度钉成 630px**（属性映射成 CSS 高度，而 CSS 没写高度），
     于是海报被纵向拉伸 2.6 倍（实测 460×630）。height:auto 让比例回来，属性继续提供占位比例。
   ② 吸顶栏 66px，跳到主内容 / 页内锚点落点被压住 46px（实测 appTop 17.6 < headBottom 63.6）。
   ③ prefers-reduced-motion 段只压了 duration，没管 html{scroll-behavior:smooth}。
   ④ :focus-visible 在老引擎里整条无效 → 全站 20 处焦点环一起消失；用 @supports not(selector())
     给它们退回 :focus（老浏览器没有"鼠标也聚焦"的概念冲突，宁可多画环也不能没有环）。
   现代浏览器只多吃 ①②，③④ 整段按条件生效。 */
.hero-visual img { height: auto; }
#app { scroll-margin-top: 76px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
@supports not (selector(:focus-visible)) {
  :focus { outline: 2px solid var(--brand); outline-offset: 2px; }
  .btn:focus, .btn-link:focus, .tab:focus, .seg-btn:focus, .shape-btn:focus, .palette-btn:focus {
    outline: 2px solid var(--brand); outline-offset: 2px;
  }
  a:focus, [role="button"]:focus, summary:focus { outline: 2px solid var(--brand); outline-offset: 2px; }
}
/* picture 变成 flex 子元素后，拉伸的是它自己而不是 img；给它同款宽度并把视觉居中。 */
body[data-page="home"] .hero-visual { align-items: center; }
.hero-visual .hero-picture { display: block; width: 100%; max-width: 460px; margin: 0 auto; }
@media (max-width: 640px) { .hero-visual .hero-picture { max-width: 320px; } }
/* ================= /R128-perf ================= */
/* ==================== R129 (2026-09-25) — 标题字体首访瘦身 ====================
   动因：实测首访 1003KB 里 714KB 是站酷快乐体中文面（每页都下）。它只服务标题/按钮这类
   "文案来自词典与静态 HTML"的元素，字集有限（852 码点），因此裁一个 UI 子集先下，
   完整中文面退到"真遇到子集外生僻字/画布选它时"才拉 —— 同一字族，视觉不变。
   生成脚本：.workbuddy/fonts/subset_ui.py（从本站已在的 woff2 再裁，授权链不变）。 */
@font-face { font-family: 'ZCOOL KuaiLe UI'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-kuaile-latin-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'ZCOOL KuaiLe UI'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/zcool-kuaile-ui-cn-400.woff2?v=20260925b) format('woff2');
  unicode-range: U+2E80-2EFF,U+3000-303F,U+31C0-31EF,U+3200-32FF,U+3300-33FF,U+3400-4DBF,U+4E00-9FFF,U+F900-FAFF,U+FE30-FE4F,U+FF00-FFEF; }
/* 三处 --font-display 定义（home / 内容页 / 工具页）全部并入子集优先的栈；选择器与原块一致，
   追加在文件末尾所以层叠上必然胜出。 */
body[data-page="home"], body:not([data-page="tool"]), body[data-page="tool"] { --font-display:"ZCOOL KuaiLe UI","ZCOOL KuaiLe","Caveat",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif; }
/* ==================== /R129-font ==================== */
