/* ============================================================
 * Trace Studio：离线单文件工具
 * 功能1：图片 -> SVG / 静态 HTML（VTracer WASM 浏览器端描摹）
 * 功能2：把描摹结果编排成手绘过程动画，导出独立 HTML
 * ============================================================ */
:root {
  --bg0: #0b1413; --bg1: #101d1b; --panel: #142523; --line: #1f3833;
  --txt: #cfe8e0; --dim: #6f938a; --acc: #2fbf9a; --acc2: #7dfade; --warn: #e8b34b;
}
* { box-sizing: border-box; }
html, body { margin: 0; min-height: 100%; }
body {
  background: radial-gradient(120% 140% at 80% 0%, #122522 0%, var(--bg0) 55%, #071010 100%);
  color: var(--txt);
  font-family: "Segoe UI", system-ui, sans-serif;
  font-size: 14px;
}
header {
  padding: 18px 28px 14px;
  border-bottom: 1px solid var(--line);
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
}
header h1 { margin: 0; font-size: 20px; letter-spacing: .02em; }
header h1 b { color: var(--acc2); }
header span { color: var(--dim); font-size: 12.5px; }
.layout { display: grid; grid-template-columns: 280px 1fr; min-height: calc(100vh - 62px); }
/* ---------- 侧栏 ---------- */
aside { border-right: 1px solid var(--line); padding: 18px; display: flex; flex-direction: column; gap: 18px; }
.sec { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 14px; }
.sec h2 { margin: 0 0 10px; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); }
.row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 8px 0; }
.row label { color: var(--txt); font-size: 13px; }
.row .val { color: var(--acc2); font-variant-numeric: tabular-nums; font-size: 12.5px; min-width: 34px; text-align: right; }
input[type=range] { width: 130px; accent-color: var(--acc); }
select {
  background: var(--bg1); color: var(--txt); border: 1px solid var(--line);
  border-radius: 6px; padding: 5px 8px; font-size: 13px;
}
.check { display: flex; align-items: center; gap: 8px; margin: 8px 0; cursor: pointer; }
.check input { accent-color: var(--acc); width: 15px; height: 15px; }
.hint { color: var(--dim); font-size: 11.5px; line-height: 1.5; margin-top: 8px; }
/* ---------- 主区 ---------- */
main { padding: 20px 26px 40px; display: flex; flex-direction: column; gap: 16px; align-items: center; }
.drop {
  width: min(760px, 100%); border: 1.5px dashed #2a4a42; border-radius: 12px;
  padding: 26px 20px; text-align: center; color: var(--dim); cursor: pointer;
  transition: border-color .2s, background .2s;
}
.drop:hover, .drop.over { border-color: var(--acc); background: rgba(47,191,154,.06); color: var(--txt); }
.drop b { color: var(--acc2); }
.stats { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }
.chip { background: var(--panel); border: 1px solid var(--line); border-radius: 99px; padding: 5px 14px; font-size: 12.5px; color: var(--txt); }
.chip b { color: var(--acc2); font-variant-numeric: tabular-nums; }
.pv-wrap { display: grid; grid-template-columns: auto auto; gap: 22px; align-items: start; justify-content: center; }
@media (max-width: 860px) {
  .layout { grid-template-columns: 1fr; }
  aside { order: 2; border-right: none; border-top: 1px solid var(--line); }
  main { order: 1; padding: 14px 12px 32px; }
  .pv-wrap { grid-template-columns: 1fr; gap: 16px; justify-items: center; }
  header { padding: 14px 16px 12px; }
  .drop { padding: 20px 12px; }
}
.pv {
  position: relative; overflow: hidden; border-radius: 10px; background: #fff;
  box-shadow: 0 0 0 1px rgba(94,234,200,.14), 0 14px 40px -12px rgba(0,0,0,.7);
}
.pv svg { display: block; width: 100%; height: 100%; }
.pv canvas { display: block; max-width: 100%; }
.pv .tag {
  position: absolute; left: 8px; top: 8px; background: rgba(6,20,19,.72); color: var(--acc2);
  font-size: 11px; padding: 3px 10px; border-radius: 99px; letter-spacing: .08em; z-index: 2;
}
.pv-src-tag { position: absolute; }
.pv-title { text-align: center; color: var(--dim); font-size: 12px; margin-top: 6px; }
.btns { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }
button.bt {
  appearance: none; border: 1px solid rgba(94,234,200,.35); cursor: pointer;
  padding: 9px 20px; border-radius: 99px; font-size: 13.5px; font-weight: 600;
  background: rgba(23,168,132,.16); color: var(--acc2);
  transition: transform .15s, background .15s, box-shadow .15s;
}
button.bt:hover:not(:disabled) { transform: translateY(-1px); background: rgba(23,168,132,.3); box-shadow: 0 0 22px -4px rgba(63,246,211,.5); }
button.bt:disabled { opacity: .35; cursor: not-allowed; }
button.bt.primary { background: var(--acc); color: #06231c; border-color: transparent; }
button.bt.primary:hover:not(:disabled) { background: #35d1a9; }
.spin {
  width: 15px; height: 15px; border: 2px solid rgba(125,250,222,.25); border-top-color: var(--acc2);
  border-radius: 50%; display: inline-block; vertical-align: -3px; margin-right: 7px;
  animation: rot .8s linear infinite;
}
@keyframes rot { to { transform: rotate(360deg); } }
#log { color: var(--dim); font-size: 12.5px; min-height: 18px; text-align: center; }
/* ---------- 预览动画内的元素 ---------- */
.skb path { fill: none; stroke: #9aa1a8; stroke-width: var(--skb-w, 1.8); stroke-linejoin: round; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; }
.playing .skb path { animation: draw .34s ease-out both; animation-delay: calc(.2s + var(--i) * .11s); }
.playing .skst { animation: skst-out .8s ease both var(--out); }
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes skst-out { from { opacity: 1; } to { opacity: 0; } }
/* 图层原地落笔：短淡入，无位移无缩放。不用 clip-path——它在 SVG 上
   逐帧重栅格化，大 viewBox 非整数缩放时每帧像素吸附漂移 -> 抖动。 */
/* 逐笔上色：每条路径单独落点，延迟 --d / 时长 --f 逐路径内联指定 */
.ps { }
.playing .ps { animation: pg-in var(--f, .22s) ease-out both; animation-delay: var(--d); }
@keyframes pg-in { from { opacity: 0; } to { opacity: 1; } }
.playing #art { animation: settle .9s ease-out forwards; animation-delay: var(--settle); }
@keyframes settle { from { filter: saturate(.95) brightness(1.02); } to { filter: none; } }
/* 光束模式 */
.beam-svg {
  transform: scale(1.06); filter: brightness(.85) saturate(.95);
  -webkit-mask-image: linear-gradient(105deg,#000 42%,rgba(0,0,0,.35) 50%,transparent 58%);
          mask-image: linear-gradient(105deg,#000 42%,rgba(0,0,0,.35) 50%,transparent 58%);
  -webkit-mask-size: 260% 100%; mask-size: 260% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
.playing .beam-svg { animation: reveal 2.6s cubic-bezier(.55,.06,.28,.99) forwards, bzoom 3.4s cubic-bezier(.2,.6,.2,1) forwards, bbright 3.4s ease forwards; }
@keyframes reveal { from { -webkit-mask-position: 100% 0; mask-position: 100% 0; } to { -webkit-mask-position: 0% 0; mask-position: 0% 0; } }
@keyframes bzoom { to { transform: scale(1); } }
@keyframes bbright { to { filter: brightness(1) saturate(1); } }
.glow {
  position: absolute; top: -10%; bottom: -10%; left: 0; width: 110px; opacity: 0; pointer-events: none;
  background: linear-gradient(90deg, transparent 0%, rgba(63,246,211,.06) 25%, rgba(63,246,211,.55) 55%, rgba(255,255,255,.95) 60%, rgba(63,246,211,.55) 65%, transparent 100%);
  filter: blur(7px); mix-blend-mode: screen;
}
.playing .glow { animation: sweep 2.6s cubic-bezier(.55,.06,.28,.99) forwards; }
.shine {
  position: absolute; inset: 0; opacity: 0; pointer-events: none; mix-blend-mode: screen;
  background: linear-gradient(75deg, transparent 30%, rgba(255,255,255,.10) 42%, rgba(210,255,245,.35) 50%, rgba(255,255,255,.10) 58%, transparent 70%);
}
.playing .shine { animation: shine2 1.1s cubic-bezier(.4,.05,.3,1) 2.9s forwards; }
@keyframes shine2 { 0% { opacity: 0; transform: translateX(-130%); } 25% { opacity: .75; } 100% { opacity: 0; transform: translateX(130%); } }
@keyframes sweep { 0% { transform: translateX(-160px); opacity: 0; } 6% { opacity: 1; } 92% { opacity: 1; } 100% { transform: translateX(calc(100cqw + 60px)); opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .pg, .ps { animation: none !important; opacity: 1 !important; }
  #art { animation: none !important; }
}
