*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
/* iOS: avoid double-tap zoom stealing taps on controls (delays/breaks button clicks) */
button,input,select,textarea,a,label,summary,.hb,.bt,.preset,.ctx-item{touch-action:manipulation}
:root{
  --bg:#090909;--surface:#111111;--surface2:#181818;--surface3:#222222;
  --border:rgba(249,246,237,0.06);--border2:rgba(249,246,237,0.12);--border3:rgba(249,246,237,0.20);
  --text:#F9F6ED;--text-muted:rgba(249,246,237,0.60);--text-hint:rgba(249,246,237,0.45);
  --accent:#097757;--accent-light:#2dd4a4;--accent-glow:rgba(9,119,87,0.12);
  --brown:#46271E;--brown-light:rgba(70,39,30,0.5);
  --shadow-sm:0 1px 4px rgba(0,0,0,.15);--shadow-md:0 4px 20px rgba(0,0,0,.25);--shadow-lg:0 8px 40px rgba(0,0,0,.35);--shadow-xl:0 16px 56px rgba(0,0,0,.45);
  --success:#22d3a0;--danger:#f87171;--warn:#fbbf24;
  --info:#60a5fa;--info-hover:rgba(96,165,250,0.10);--info-border:rgba(96,165,250,0.30);
  --space-xs:4px;--space-sm:8px;--space-md:12px;--space-lg:16px;--space-xl:24px;--space-xxl:48px;
  --font-ui:'DM Sans',sans-serif;--font-display:'Syne',sans-serif;
  --radius-xs:2px;--radius-sm:6px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:24px;--radius-pill:50px;--radius-full:9999px;
  --glass-icon-bg:rgba(220,238,177,.12);--card-icon-bg:rgba(70,39,30,.45);--text-icon-bg:rgba(197,176,244,.15);
  /* Unified brand-green section accents — previously each panel section used a
     different pastel hue (lime/lilac/mint/cream/coral), clashing with the dark
     glass aesthetic. Now all sections share the accent-mint tint. */
  --sec-text-accent:rgba(45,212,164,.08);--sec-text-border:rgba(45,212,164,.20);
  --sec-colors-accent:rgba(45,212,164,.08);--sec-colors-border:rgba(45,212,164,.20);
  --sec-appearance-accent:rgba(45,212,164,.08);--sec-appearance-border:rgba(45,212,164,.20);
  --sec-position-accent:rgba(45,212,164,.08);--sec-position-border:rgba(45,212,164,.20);
  --sec-actions-accent:rgba(45,212,164,.06);--sec-actions-border:rgba(45,212,164,.18);
  --color-accent-ink:#F9F6ED;
  --accent-hover:#0db578;
  --danger-hover:rgba(248,113,113,0.10);--danger-border:rgba(248,113,113,0.30);
  --warn-hover:rgba(251,191,36,0.10);--warn-border:rgba(251,191,36,0.30);
  --guide-accent:rgba(34,211,160,0.65);
  --accent-border:rgba(9,119,87,0.38);--accent-border-hover:rgba(9,119,87,0.50);
  --empty-icon-color:rgba(249,246,237,0.21);
  --overlay-bg:rgba(15,15,15,0.60);
  --font-mono:'JetBrains Mono','Fira Code',monospace;
  /* z-index scale — 替代任意大数值 */
  --z-dropdown:200;--z-modal:300;--z-toast:400;--z-overlay:500;--z-popover:600;--z-tooltip:700;
  /* Stronger, more intentional easing curves — plain ease/ease-out are too weak */
  --ease-out:cubic-bezier(0.23,1,0.32,1);
  --ease-in-out:cubic-bezier(0.77,0,0.175,1);
  /* Explicit property list (never `all`) so unrelated properties don't animate together */
  --tr:background-color 160ms var(--ease-out),border-color 160ms var(--ease-out),color 160ms var(--ease-out),transform 140ms var(--ease-out),opacity 160ms var(--ease-out),box-shadow 160ms var(--ease-out);
  --tr-fast:transform 120ms var(--ease-out);
  /* Stagger delay for entrance animations */
  --stagger:60ms;
}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:0.01ms!important;animation-iteration-count:1!important;transition-duration:0.01ms!important}
}
html,body{height:100%;background:var(--bg);font-family:var(--font-ui);color:var(--text);overflow-x:clip;overflow-y:auto;overscroll-behavior:contain;-webkit-font-smoothing:antialiased}
button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--radius-sm)}
.preset:focus-visible,.li:focus-visible,.ldel:focus-visible,.ctx-item:focus-visible,.align-btn:focus-visible,.mini-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--radius-sm)}

/* ── App Layout ── */
#app{display:flex;flex-direction:column;height:100vh}

/* ── Header ── */
#header{
  position:relative;
  display:flex;align-items:center;gap:8px;
  padding:0 12px;height:44px;
  background:var(--surface);
  flex-shrink:0;overflow-x:auto;overflow-y:hidden
}
/* Scroll edge gradient mask — replaces hard border-bottom with soft fade */
#header::after{
  content:'';position:absolute;bottom:0;left:0;right:0;height:10px;
  background:linear-gradient(to bottom,rgba(249,246,237,0.06),transparent);
  pointer-events:none;z-index:1
}
#header::-webkit-scrollbar{height:3px}
#header::-webkit-scrollbar-track{background:transparent}
#header::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px}
.logo{display:flex;align-items:center;gap:9px;font-family:var(--font-display);font-size:18px;font-weight:600;letter-spacing:-.022em;white-space:nowrap;cursor:default;user-select:none}
.logo-mark{display:block;flex:0 0 auto;width:24px;height:24px}
.logo-mark rect{vector-effect:non-scaling-stroke}
.logo span{color:var(--accent-light)}
.h-sep{width:1px;height:20px;background:var(--border2);margin:0 4px;flex-shrink:0}
.hg{display:flex;align-items:center;gap:2px}
.hb{
  display:flex;align-items:center;gap:var(--space-xs);
  padding:6px var(--space-md);font-size:12px;font-weight:600;
  border-radius:var(--radius-pill);border:1px solid var(--border2);
  background:transparent;color:var(--text-muted);
  cursor:pointer;transition:var(--tr);white-space:nowrap
}
.hb:hover{background:var(--surface2);color:var(--text);box-shadow:0 0 0 3px var(--accent-glow)}
.hb:disabled,.tb:disabled{opacity:.35;cursor:default;box-shadow:none;pointer-events:none}
.hb:disabled:hover,.tb:disabled:hover{background:transparent;color:var(--text-muted);box-shadow:none}
.hb:active{transform:scale(0.95);transition-duration:60ms}
.hb.primary{background:var(--accent);color:var(--color-accent-ink);border-color:transparent;transition:var(--tr)}
.hb.primary:hover{background:var(--accent-hover)}
.hb.danger-btn:hover{background:var(--danger-hover);color:var(--danger);border-color:var(--danger-border)}
.hb.warn-btn:hover{background:var(--warn-hover);color:var(--warn);border-color:var(--warn-border)}
.hb.info-btn:hover{background:var(--info-hover);color:var(--info);border-color:var(--info-border)}
.spacer{flex:1}
.undo-info{font-size:11px;color:var(--text-hint);white-space:nowrap}

/* ── Presets Bar ──
   Desktop: groups wrap into multiple rows so ALL presets are visible without
   horizontal scrolling (scrollWidth used to reach ~2144px, hiding the last
   presets like 大标题文字 beyond the fold). Mobile re-locks to a single
   scrollable row below (≤768px), where vertical space is scarce. */
#presets-bar{
  display:flex;flex-wrap:wrap;align-content:center;gap:4px 2px;
  padding:var(--space-sm) 12px;
  background:var(--surface);border-bottom:1px solid var(--border);
  overflow-x:auto;flex-shrink:0
}
#presets-bar::-webkit-scrollbar{height:3px}
#presets-bar::-webkit-scrollbar-track{background:transparent}
#presets-bar::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px}
.preset-label{font-size:10.5px;color:var(--text-hint);white-space:nowrap;align-self:center;margin-right:6px;flex-shrink:0}
.preset-group{display:flex;gap:5px;align-items:center}
.preset-sep{width:1px;height:20px;background:var(--border2);margin:0 4px;flex-shrink:0}
.preset{
  flex-shrink:0;display:flex;align-items:center;gap:6px;
  padding:4px 10px;border-radius:var(--radius-pill);
  border:1px solid var(--border2);background:var(--surface2);
  cursor:pointer;transition:var(--tr)
}
.preset:hover{border-color:var(--accent);background:var(--accent-glow)}
.preset:active{transform:scale(0.95)}
.preset.pressed{animation: presetPop 0.3s ease-out}
@keyframes presetPop{
  0%{background:var(--accent-glow);transform:scale(0.95)}
  60%{transform:scale(1.03)}
  100%{background:var(--surface2);transform:scale(1)}
}
.preset-dot{width:10px;height:10px;border-radius:var(--radius-sm);flex-shrink:0}
.preset span{font-size:11px;color:var(--text-muted);white-space:nowrap}
.preset:hover span{color:var(--text)}

/* ── Main Area ── */
#main{display:flex;flex:1;overflow:hidden}

/* ── Left Toolbar ── */
#lp{
  width:48px;background:var(--surface);
  border-right:1px solid var(--border);
  display:flex;flex-direction:column;align-items:center;
  padding:var(--space-sm) 0;gap:2px;flex-shrink:0
}
/* ── Toolbar buttons ── */
.tb{
  width:44px;height:44px;border-radius:var(--radius-pill);
  border:1px solid transparent;background:transparent;
  color:var(--text-muted);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  transition:var(--tr);position:relative
}
.tb:hover{background:var(--surface2);color:var(--text);border-color:var(--border2)}
.tb:active{transform:scale(0.95)}
.tb.active{background:var(--accent-glow);color:var(--accent-light);border-color:var(--accent-border)}
.tsep{width:22px;height:1px;background:linear-gradient(90deg,transparent,var(--border2),transparent);margin:3px 0}
.tip{
  position:absolute;left:42px;background:var(--surface2);
  color:var(--text);font-size:11px;padding:4px 8px;
  border-radius:6px;white-space:nowrap;border:1px solid var(--border2);
  opacity:0;transform:scale(0.94);transform-origin:left center;
  pointer-events:none;transition:opacity 160ms var(--ease-out),transform 160ms var(--ease-out);z-index:200
}
.tb:hover .tip{opacity:1;transform:scale(1)}

/* ── Canvas Area ── */
#canvas-area{
  flex:1;display:flex;flex-direction:column;
  overflow:hidden;position:relative;
  background:var(--bg)
}
#canvas-toolbar{
  display:flex;align-items:center;gap:8px;padding:var(--space-sm) 12px;
  background:rgba(17,17,17,.88);border-bottom:1px solid var(--border);
  flex-shrink:0;backdrop-filter:blur(12px)
}
#canvas-toolbar.hidden{display:none}
#canvas-toolbar .label{font-size:11px;color:var(--text-hint);flex-shrink:0}
.zoom-btn{
  padding:3px 8px;background:var(--surface2);border:1px solid var(--border2);
  border-radius:var(--radius-sm);color:var(--text-muted);cursor:pointer;font-size:11px;
  transition:var(--tr)
}
.zoom-btn:hover{background:var(--surface3);color:var(--text)}
.zoom-btn:active,.zoom-fit-btn:active{transform:scale(0.95)}
#zoom-slider{width:80px;-webkit-appearance:none;height:3px;background:var(--surface3);border-radius:2px;outline:none;cursor:pointer}
#zoom-slider::-webkit-slider-thumb{-webkit-appearance:none;width:16px;height:16px;border-radius:50%;background:var(--accent-light);cursor:pointer}
#zoom-val{font-size:11px;color:var(--accent-light);min-width:32px;text-align:center;cursor:default;position:relative}
#zoom-val::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%) scale(0.9);background:var(--surface2);border:1px solid var(--border2);padding:2px 6px;border-radius:4px;font-size:10px;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity 120ms,transform 120ms var(--ease-out);z-index:10}
#zoom-val:hover::after{opacity:1;transform:translateX(-50%) scale(1)}
.zoom-fit-btn{
  padding:3px 8px;background:var(--surface2);border:1px solid var(--border2);
  border-radius:var(--radius-sm);color:var(--text-muted);cursor:pointer;font-size:11px;transition:var(--tr)
}
/* Unify heights inside the canvas toolbar: the bare −/+ glyphs have a smaller
   natural line box than the 适应/导出 labels, so buttons rendered 20px vs 23px tall. */
#canvas-toolbar .zoom-btn, #canvas-toolbar .zoom-fit-btn{
  display:inline-flex;align-items:center;justify-content:center;
  height:24px;line-height:1
}
.zoom-fit-btn:hover{background:var(--accent-glow);color:var(--accent-light);border-color:var(--accent-border-hover)}
#exp-scale-sel{
  -webkit-appearance:none;appearance:none;font-family:var(--font-ui);
  background-image:linear-gradient(45deg,transparent 50%,var(--text-muted) 50%),linear-gradient(135deg,var(--text-muted) 50%,transparent 50%);
  background-position:calc(100% - 10px) center,calc(100% - 6px) center;background-size:4px 4px,4px 4px;background-repeat:no-repeat;
  padding-right:20px
}
#exp-scale-sel:hover{background-color:var(--surface3);color:var(--text)}
#exp-scale-sel option{background:var(--surface2);color:var(--text)}
#canvas-scroll{
  flex:1;display:flex;align-items:center;justify-content:center;
  overflow:auto;position:relative;padding:40px;
  background-image:linear-gradient(var(--border) 1px,transparent 1px),
                    linear-gradient(90deg,var(--border) 1px,transparent 1px);
  background-size:48px 48px
}
#canvas-scroll::-webkit-scrollbar{width:6px;height:6px}
#canvas-scroll::-webkit-scrollbar-track{background:transparent}
#canvas-scroll::-webkit-scrollbar-thumb{background:var(--border2);border-radius:4px}
#canvas-scroll::-webkit-scrollbar-corner{background:transparent}

#cv{position:relative;box-shadow:var(--shadow-xl),0 0 0 1px var(--border2);border-radius:3px;transform-origin:0 0;transition:transform 140ms var(--ease-out),opacity 250ms var(--ease-out);opacity:0}
#cv.loaded{opacity:1}

/* ── Drop Zone ── */
#dz{
  position:absolute;inset:0;display:flex;
  flex-direction:column;align-items:center;justify-content:center;
  gap:var(--space-lg)
}
#dz-inner{color:var(--accent);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:14px;width:480px;height:320px;
  border:1.5px dashed rgba(9,119,87,.4);border-radius:var(--radius-2xl);
  background:rgba(9,119,87,.04);cursor:pointer;transition:var(--tr);
  position:relative;overflow:hidden
}
#dz-inner::before{
  content:'';position:absolute;inset:-1px;border-radius:var(--radius-2xl);
  background:linear-gradient(135deg,rgba(9,119,87,.15),transparent,rgba(220,238,177,.12));
  opacity:0;transition:opacity 250ms var(--ease-out);pointer-events:none;z-index:-1
}
#dz-inner:hover::before,#dz-inner.drag-on::before{opacity:1}
#dz-inner:hover,#dz-inner.drag-on{border-color:var(--accent);background:rgba(9,119,87,.07);box-shadow:0 0 0 5px rgba(9,119,87,0.10)}
#dz-inner.drag-on{animation:dzPulse 1.2s ease-in-out infinite;transition:none}
@keyframes dzPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(9,119,87,.20),inset 0 0 0 1px rgba(9,119,87,.10)}
  50%{box-shadow:0 0 0 10px rgba(9,119,87,0),inset 0 0 20px 2px rgba(9,119,87,.06)}
}
#dz p{font-size:13.5px;color:var(--text-muted)}
#dz small{font-size:11.5px;color:var(--accent-light)}
#ubm{
  padding:var(--space-sm) var(--space-xl);background:var(--accent);color:var(--color-accent-ink);border:none;
  border-radius:var(--radius-pill);cursor:pointer;font-size:13px;
  font-family:var(--font-ui);transition:var(--tr)
}
#ubm:hover{background:var(--accent-hover)}
#ubm:active{transform:scale(0.95)}

/* ── Guide Lines ── */
.guide{position:absolute;pointer-events:none;z-index:1000;opacity:0;transition:opacity 140ms var(--ease-out)}
.guide.h{height:1px;left:0;right:0;background:var(--guide-accent);box-shadow:0 0 4px var(--guide-accent)}
.guide.v{width:1px;top:0;bottom:0;background:var(--guide-accent);box-shadow:0 0 4px var(--guide-accent)}
.guide.show{opacity:1}
/* Center guides get a brighter color to distinguish from edge snaps */
.guide.center.show{background:#60a5fa;box-shadow:0 0 6px #60a5fa}
.guide.center::before,.guide.center::after{content:'';position:absolute;width:5px;height:5px;border-radius:50%;background:#60a5fa;top:-2px}
.guide.center::before{left:-2px}
.guide.center::after{right:-2px}
/* Multi-element preview guides: dimmed style */
.guide.multi.show{opacity:0.5!important;box-shadow:none!important}
.guide.multi.center.show{opacity:0.55!important;background:#60a5fa!important}
/* Percentage label on guide lines.
   Center guides render their label via the .guide-pct span (::after is used for
   the end dots), so the ::after label must be scoped to non-center guides —
   otherwise center guides show the percentage twice. */
.guide.h.show:not(.center)::after{content:attr(data-pct)'%';position:absolute;right:4px;top:-10px;font-size:9px;font-family:var(--font-mono);color:var(--guide-accent);white-space:nowrap;pointer-events:none;text-shadow:0 0 4px rgba(0,0,0,.8)}
.guide.v.show:not(.center)::after{content:attr(data-pct)'%';position:absolute;right:-28px;top:50%;transform:translateY(-50%);font-size:9px;font-family:var(--font-mono);color:var(--guide-accent);white-space:nowrap;pointer-events:none;text-shadow:0 0 4px rgba(0,0,0,.8)}
.guide.multi.show:not(.center)::after{content:attr(data-pct)'%';opacity:0.6}
/* Center guide percentage: ::before/::after are used for dots, so use a span */
.guide.center.show .guide-pct{position:absolute;font-size:9px;font-family:var(--font-mono);color:#60a5fa;white-space:nowrap;pointer-events:none;text-shadow:0 0 4px rgba(0,0,0,.8);right:4px;top:-10px}

/* ── Spacing Labels ── */
.sp-label{position:absolute;pointer-events:none;z-index:1001;font-size:10px;font-family:var(--font-mono);color:var(--accent-light);background:var(--surface);border:1px solid var(--accent);border-radius:3px;padding:1px 4px;white-space:nowrap;opacity:0;transition:opacity 120ms var(--ease-out),transform 120ms var(--ease-out)}
.sp-label.show{opacity:1;border:1px solid var(--accent)}

/* ── Context Menu ── */
/* Context menu styles are defined below under #ctx-menu (lines 354+) */
.ctx-kb{margin-left:auto;font-size:10px;opacity:.5;font-family:var(--font-mono)}

/* ── Gradient Preview Bar ── */
.gd-preview-bar{height:32px;border-radius:4px}
/* ── Reset Button ── */
.reset-btn{
  width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;
  border-radius:4px;border:none;background:transparent;color:var(--text-hint);
  cursor:pointer;transition:var(--tr);flex-shrink:0;padding:0;
}
.reset-btn:hover{background:var(--surface3);color:var(--text)}
.reset-btn svg{width:10px;height:10px}

/* ── Right Panel ── */
#rp{width:260px;background:var(--surface);border-left:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;flex-shrink:0}
#rp-layers{padding:var(--space-md) 12px var(--space-sm);border-bottom:1px solid var(--border);flex-shrink:0}
#rp-layers .pt{font-size:10px;font-weight:600;letter-spacing:-.06em;text-transform:uppercase;color:var(--text-hint);margin-bottom:8px}
#ll{max-height:170px;overflow-y:auto;display:flex;flex-direction:column;gap:2px}
#ll::-webkit-scrollbar{width:3px}
#ll::-webkit-scrollbar-track{background:transparent}
#ll::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px}
.li{
  display:flex;align-items:center;gap:6px;padding:var(--space-xs) var(--space-sm);
  border-radius:var(--radius-md);cursor:pointer;border:1px solid transparent;
  transition:background 150ms var(--ease-out),border-color 150ms var(--ease-out),transform 120ms var(--ease-out)
}
.li:hover{background:var(--surface2)}
.li:active{transform:scale(0.95)}
.li.sel{background:rgba(220,238,177,.08);border-color:rgba(220,238,177,.25);box-shadow:inset 2px 0 0 rgba(220,238,177,.4)}
.para-row{border:1px solid transparent;border-radius:4px}
.para-row:hover{background:var(--surface2)}
.para-row.selected{background:rgba(220,238,177,.08);border-color:rgba(220,238,177,.25);box-shadow:inset 2px 0 0 rgba(220,238,177,.3)}
.lic{width:22px;height:22px;border-radius:4px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lic.gi{background:var(--glass-icon-bg);border:1px solid rgba(220,238,177,.35)}
.lic.ci{background:var(--card-icon-bg);border:1px solid rgba(255,255,255,.12)}
.lic.ti{background:var(--text-icon-bg);border:1px solid rgba(197,176,244,.35)}
.ln{font-size:11.5px;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ldel{
  width:20px;height:20px;display:flex;align-items:center;justify-content:center;
  border-radius:4px;cursor:pointer;color:var(--text-hint);transition:var(--tr);flex-shrink:0
}
.ldel:hover{color:var(--danger)}
#pscroll{flex:1;overflow-y:auto;padding:var(--space-md) 12px}
#pscroll::-webkit-scrollbar{width:3px}
#pscroll::-webkit-scrollbar-track{background:transparent}
#pscroll::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px}

/* ── Props ── */
.pg{margin-bottom:var(--space-md)}
.pl{font-size:10.5px;color:var(--text-muted);margin-bottom:4px;display:flex;justify-content:space-between}
.pl span{color:var(--accent-light);font-size:10.5px}
.pi{
  width:100%;padding:var(--space-xs) var(--space-sm);background:var(--surface2);
  border:1px solid var(--border2);border-radius:var(--radius-md);
  color:var(--text);font-size:12px;font-family:var(--font-ui);
  outline:none;transition:var(--tr)
}
.pi:focus{border-color:var(--accent)}
.psel{
  width:100%;padding:var(--space-xs) var(--space-sm);background:var(--surface2);
  border:1px solid var(--border2);border-radius:var(--radius-md);
  color:var(--text);font-size:12px;font-family:var(--font-ui);
  outline:none;cursor:pointer;appearance:none
}
/* Number inputs: show a slightly larger tap target, hide spinner arrows on WebKit */
.pi[type=number]{-webkit-appearance:textfield;font-size:11.5px}
.pi[type=number]::-webkit-inner-spin-button,
.pi[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
input[type=range]{flex:1;-webkit-appearance:none;height:3px;background:rgba(255,255,255,0.12);border-radius:2px;outline:none;cursor:pointer}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;border-radius:50%;background:var(--accent-light);cursor:pointer;box-shadow:0 0 0 2px var(--bg),0 0 6px var(--accent-glow)}
input[type=range]::-moz-range-track{height:3px;background:rgba(255,255,255,0.12);border-radius:2px;outline:none;cursor:pointer}
input[type=range]::-moz-range-thumb{width:13px;height:13px;border-radius:50%;background:var(--accent-light);border:none;cursor:pointer;box-shadow:0 0 0 2px var(--bg),0 0 6px var(--accent-glow)}
.crow{display:flex;align-items:center;gap:6px}
.csw{width:28px;height:26px;border-radius:var(--radius-sm);border:1px solid var(--border2);overflow:hidden;flex-shrink:0;cursor:pointer;position:relative}
.csw input{position:absolute;inset:0;width:130%;height:130%;opacity:0;cursor:pointer;margin:-15%}
.divider{height:1px;background:var(--border);margin:10px 0}

/* ── Collapsible Sections ── */
.sec{margin-bottom:var(--space-xs);border-radius:var(--radius-lg);background:rgba(249,246,237,0.025);border:1px solid transparent;transition:border-color 200ms var(--ease-out)}
.sec-hd{display:flex;align-items:center;gap:6px;padding:8px var(--space-md);cursor:pointer;font-size:11px;font-weight:600;color:var(--text);user-select:none;border-radius:var(--radius-lg);transition:background 120ms var(--ease-out),border-color 120ms var(--ease-out)}
.sec-hd:hover{background:rgba(249,246,237,0.08)}
.sec.collapsed .sec-hd{border-radius:var(--radius-lg)}
.sec-content{border-radius:0 0 var(--radius-lg) var(--radius-lg)}
/* Color-block sections — unified accent family, consistent hierarchy */
.sec.sec-text .sec-hd{background:rgba(220,238,177,.12);border:1px solid rgba(220,238,177,.25);border-bottom:none}
.sec.sec-text .sec-content{background:rgba(220,238,177,.06)}
.sec.sec-colors .sec-hd{background:rgba(220,238,177,.10);border:1px solid rgba(220,238,177,.22);border-bottom:none}
.sec.sec-colors .sec-content{background:rgba(220,238,177,.05)}
.sec.sec-appearance .sec-hd{background:rgba(220,238,177,.09);border:1px solid rgba(220,238,177,.20);border-bottom:none}
.sec.sec-appearance .sec-content{background:rgba(220,238,177,.04)}
.sec.sec-position .sec-hd{background:rgba(220,238,177,.08);border:1px solid rgba(220,238,177,.18);border-bottom:none}
.sec.sec-position .sec-content{background:rgba(220,238,177,.03)}
.sec.sec-actions .sec-hd{background:rgba(220,238,177,.07);border:1px solid rgba(220,238,177,.16);border-bottom:none}
.sec.sec-actions .sec-content{background:rgba(220,238,177,.03)}
.sec-arrow{font-size:7px;opacity:.4;transition:transform 0.2s var(--ease-out)}
.sec.collapsed .sec-arrow{transform:rotate(-90deg)}
/* Smooth expand/collapse using grid-template-rows: 0→1 trick */
.sec-bd{padding:2px 10px 6px;transition:opacity 200ms var(--ease-out);display:grid;grid-template-rows:1fr;overflow:hidden}
.sec.collapsed .sec-bd{grid-template-rows:0fr;opacity:0;transition-timing-function:cubic-bezier(0.4,0,1,1)}
.sec-content{min-height:0;overflow:hidden}
.mini-btns{display:flex;gap:4px}
.mini-btn{
  flex:1;padding:var(--space-xs) var(--space-sm);background:var(--surface2);border:1px solid var(--border2);
  border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;
  font-size:11px;font-family:var(--font-ui);transition:var(--tr);text-align:center
}
.mini-btn:hover{background:var(--surface3);color:var(--text)}
.mini-btn.on{background:var(--accent-glow);border-color:var(--accent-border-hover);color:var(--accent-light)}
.mini-btn.danger{color:var(--danger);border-color:var(--danger-border)}
.mini-btn.danger:hover{background:var(--danger-hover);color:var(--danger);border-color:var(--danger)}
.align-btns{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;margin-bottom:8px}
.align-btn{
  padding:var(--space-xs) var(--space-sm);background:var(--surface2);border:1px solid var(--border2);
  border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;
  font-size:10px;text-align:center;transition:var(--tr)
}
.align-btn:hover{background:var(--surface3);color:var(--text)}
.prop-grid{display:grid;grid-template-columns:1fr 1fr;gap:5px;margin-bottom:8px}
.prop-grid .pg{margin-bottom:0}
.shd-row{display:flex;align-items:center;gap:6px;margin-bottom:4px}
.shd-row .shd-lbl{font-size:10.5px;color:var(--text-muted);width:48px;flex-shrink:0}
.shd-row .shd-val{font-size:10.5px;color:var(--accent-light);width:36px;text-align:right;flex-shrink:0}
.shd-row input[type=range]{flex:1}
.empty-st{
  display:flex;flex-direction:column;align-items:center;gap:8px;
  padding:20px 10px
}
.empty-st svg{opacity:.3;color:var(--empty-icon-color)}
.empty-st p{font-size:11px;color:var(--text-muted);text-align:center;line-height:1.5}

/* ── Elements ── */
.gel{position:absolute;cursor:move;user-select:none;overflow-wrap:break-word;word-break:break-word;touch-action:none;transition:outline-color 150ms var(--ease-out),outline-offset 150ms var(--ease-out)}
/* ── Materialize animation (Apple Design) ── */
.gel.materialize-in{animation:matIn 0.4s cubic-bezier(0.25,1,0.5,1) forwards}
.gel.materialize-out{animation:matOut 0.28s cubic-bezier(0.4,0,1,1) forwards;pointer-events:none}
@keyframes matIn{
  from{opacity:0;transform:scale(0.92);filter:blur(8px)}
  to{opacity:1;transform:scale(1);filter:blur(0)}
}
@keyframes matOut{
  from{opacity:1;transform:scale(1);filter:blur(0)}
  to{opacity:0;transform:scale(0.92);filter:blur(8px)}
}
.gel.sel{outline:2px solid var(--accent);outline-offset:2px;box-shadow:0 0 0 5px rgba(9,119,87,0.15);transition:outline 150ms var(--ease-out),box-shadow 150ms var(--ease-out)}
.gel-inner{width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:12px;overflow:hidden}
.gel-inner.text-edit-active{overflow:visible!important}
.el-text{word-break:break-word;white-space:pre-wrap;pointer-events:none;width:100%;text-align:center;line-height:1}
.el-text[hidden]{display:none}
/* 编辑中的编辑器：使用 box-shadow ring 替代 outline（outline 会触发 layout） */
.text-editor-area{cursor:text;outline:none;min-height:1em}
.text-editor-area:focus-visible{box-shadow:0 0 0 2px var(--accent)}
/* contenteditable 编辑器内段落样式同步（bold/italic/underline 由 inline style 驱动） */
.text-editor-area span{display:inline}
.text-editor-area br{line-height:inherit}
/* ── Resize handles ── */
.rh{
  position:absolute;width:8px;height:8px;border-radius:2px;
  background:var(--accent-light);border:1.5px solid var(--text);z-index:20;display:none;touch-action:none;
  transition:transform 120ms var(--ease-out),box-shadow 120ms var(--ease-out);
}
.gel.sel .rh{display:block}
.rh:hover{transform:scale(1.3);box-shadow:0 0 0 3px var(--accent-glow)}
.rh:active{transform:scale(0.9)}
.rh.tl{top:-4px;left:-4px;cursor:nw-resize}
.rh.tr{top:-4px;right:-4px;cursor:ne-resize}
.rh.bl{bottom:-4px;left:-4px;cursor:sw-resize}
.rh.br{bottom:-4px;right:-4px;cursor:se-resize}
.rh.tm{top:-4px;left:calc(50% - 4px);cursor:n-resize}
.rh.bm{bottom:-4px;left:calc(50% - 4px);cursor:s-resize}
.rh.ml{top:calc(50% - 4px);left:-4px;cursor:w-resize}
.rh.mr{top:calc(50% - 4px);right:-4px;cursor:e-resize}
/* Rotation handle — positioned above the top-center resize handle */
.rh.rv{top:-24px;left:calc(50% - 4px);cursor:grab}
.rh.rv:hover{cursor:grabbing}
.rh.rv::before{content:'';position:absolute;inset:0;border-radius:50%}
.gel.locked{cursor:default;transition:none}
.gel.locked .rh{display:none!important}
.gel.dragging{box-shadow:0 0 0 1px var(--border2);transition:box-shadow 140ms var(--ease-out);will-change:left,top,width,height,backdrop-filter}
/* Staggered entrance: new elements fade/scale in sequentially */
.gel:nth-child(1 of .gel){animation-delay:0ms}
.gel:nth-child(2 of .gel){animation-delay:60ms}
.gel:nth-child(3 of .gel){animation-delay:120ms}

/* ── Context Menu ── */
#ctx-menu{
  position:fixed;background:var(--surface2);border:1px solid var(--border2);
  border-radius:var(--radius-lg);padding:5px;z-index:200;min-width:160px;
  box-shadow:var(--shadow-lg),0 0 0 1px rgba(249,246,237,0.04);
  opacity:0;visibility:hidden;pointer-events:none;
  transform:scale(0.95) translateY(4px);transform-origin:top left;
  transition:opacity 180ms var(--ease-out),transform 200ms var(--ease-out),visibility 180ms,box-shadow 180ms var(--ease-out)
}
#ctx-menu.show{opacity:1;visibility:visible;pointer-events:auto;transform:scale(1) translateY(0);box-shadow:var(--shadow-xl),0 0 0 1px rgba(249,246,237,0.04)}
.ctx-item{
  padding:6px 12px;font-size:12.5px;border-radius:6px;cursor:pointer;
  color:var(--text-muted);display:flex;align-items:center;gap:9px;transition:var(--tr)
}
.ctx-item:hover{background:var(--accent-glow);color:var(--text)}
.ctx-item.danger:hover{background:rgba(248,113,113,.1);color:var(--danger)}
.ctx-sep{height:1px;background:var(--border);margin:4px 0}

/* ── Status Bar ── */
#sb{
  height:32px;background:var(--surface);border-top:1px solid var(--border);
  display:flex;align-items:center;padding:0 var(--space-md);gap:12px;flex-shrink:0;
  box-shadow:0 -1px 0 rgba(0,0,0,.15)
}
.sbi{font-size:10.5px;color:var(--text-hint);display:flex;align-items:center;gap:4px}
.sbi b{color:var(--text-muted);font-weight:400}
.sbi.ac{color:var(--accent-light)}

/* ── Shortcuts Panel ── */
#shortcuts-panel{
  position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) scale(0.96);
  background:var(--surface);border:1px solid var(--border2);border-radius:var(--radius-2xl);
  padding:24px 28px;z-index:600;min-width:360px;
  box-shadow:var(--shadow-xl),0 0 0 1px rgba(249,246,237,0.04);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity 180ms var(--ease-out),transform 200ms var(--ease-out),visibility 180ms
}
#shortcuts-panel.show{opacity:1;visibility:visible;pointer-events:auto;transform:translate(-50%,-50%) scale(1)}
#shortcuts-panel h3{font-family:var(--font-display);font-size:15px;margin-bottom:14px;color:var(--text)}
#shortcuts-panel .sc-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px 16px}
#shortcuts-panel .sc-item{display:flex;justify-content:space-between;align-items:center;font-size:11.5px;padding:5px 0;border-bottom:1px solid rgba(249,246,237,0.05)}
#shortcuts-panel .sc-item:last-child{border-bottom:none}
#shortcuts-panel .sc-key{background:var(--surface2);border:1px solid var(--border2);border-radius:4px;padding:2px 6px;font-size:10px;color:var(--accent-light);font-family:var(--font-mono);white-space:nowrap}
#shortcuts-panel .sc-close{position:absolute;top:12px;right:14px;background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:16px}
#shortcuts-panel .sc-close:hover{color:var(--text)}
#shortcuts-overlay{position:fixed;inset:0;background:var(--overlay-bg);z-index:500;opacity:0;visibility:hidden;pointer-events:none;transition:opacity 160ms var(--ease-out),visibility 160ms}
#shortcuts-overlay.show{opacity:1;visibility:visible;pointer-events:auto}

/* ── Confirm Dialog ── */
/* Replaces native confirm(): sandboxed preview iframes silently return false
 * from confirm(), so the "replace image / clear all / restore autosave" flows
 * must use an in-app dialog to actually work. */
#confirm-overlay{
  position:fixed;inset:0;background:var(--overlay-bg);z-index:600;
  display:flex;align-items:center;justify-content:center;
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity 160ms var(--ease-out),visibility 160ms
}
#confirm-overlay.show{opacity:1;visibility:visible;pointer-events:auto}
.confirm-box{
  background:var(--surface);border:1px solid var(--border2);border-radius:var(--radius-2xl);
  padding:22px 24px;max-width:340px;width:calc(100vw - 48px);
  box-shadow:var(--shadow-lg),0 0 0 1px rgba(249,246,237,0.04);display:flex;flex-direction:column;gap:16px;
  transform:scale(0.96);transition:transform 180ms var(--ease-out)
}
#confirm-overlay.show .confirm-box{transform:scale(1)}
#confirm-msg{font-size:13px;color:var(--text);line-height:1.6;margin:0}
.confirm-actions{display:flex;justify-content:flex-end;gap:8px}
.confirm-actions button{
  padding:7px 16px;border-radius:var(--radius-md);font-size:12px;cursor:pointer;
  border:1px solid var(--border2);background:transparent;color:var(--text-muted);transition:var(--tr)
}
.confirm-actions button:hover{background:var(--surface2);color:var(--text)}
.confirm-actions .ok{background:var(--accent);border-color:var(--accent);color:#fff}
.confirm-actions .ok:hover{background:var(--accent-hover)}

/* ── Toast ── */
#toast{
  position:fixed;bottom:40px;left:50%;
  background:var(--surface2);color:var(--text);border:1px solid var(--border2);
  padding:8px 20px;border-radius:var(--radius-pill);font-size:12.5px;z-index:800;
  transform:translateX(-50%) translateY(8px) scale(0.96);transform-origin:center;
  transition:opacity 220ms var(--ease-out),transform 240ms var(--ease-out),visibility 0ms 220ms;
  pointer-events:none;opacity:0;visibility:hidden;white-space:normal;max-width:360px;
  box-shadow:0 4px 24px rgba(0,0,0,.3)
}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0) scale(1);visibility:visible;transition:opacity 220ms var(--ease-out),transform 260ms var(--ease-out),visibility 0ms 0s}
#toast.success{border-color:rgba(34,211,160,.4);background:rgba(34,211,160,.12);color:#22d3a0}
#toast.error  {border-color:rgba(248,113,113,.4);background:rgba(248,113,113,.12);color:#f87171}
#toast.warn   {border-color:rgba(251,191,36,.4);background:rgba(251,191,36,.12);color:#fbbf24}

/* ── Export Overlay ── */
#exp-overlay{
  position:fixed;inset:0;background:rgba(9,9,9,.90);
  display:flex;align-items:center;justify-content:center;z-index:9998;
  backdrop-filter:blur(6px);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity 180ms var(--ease-out),visibility 180ms
}
#exp-overlay.show{opacity:1;visibility:visible;pointer-events:auto}
#exp-box{color:var(--accent);
  background:var(--surface);border:1px solid var(--border2);border-radius:var(--radius-2xl);
  padding:32px 40px;display:flex;flex-direction:column;align-items:center;gap:18px;
  transform:scale(0.96);transform-origin:center;
  transition:transform 180ms var(--ease-out);
  box-shadow:var(--shadow-xl),0 0 0 1px rgba(249,246,237,0.04)
}
#exp-overlay.show #exp-box{transform:scale(1)}
#exp-msg{font-size:14px;color:var(--text)}
#exp-bar-wrap{width:240px;height:5px;background:var(--surface3);border-radius:4px;overflow:hidden;box-shadow:inset 0 1px 3px rgba(0,0,0,.2)}
#exp-bar{height:100%;background:linear-gradient(90deg,var(--accent),var(--accent-light));border-radius:4px;width:0%;transition:width 400ms var(--ease-out)}
#exp-cancel:hover{background:var(--surface3);color:var(--text)}

/* ── Scrollbar Global ── */
::-webkit-scrollbar{width:4px;height:4px}
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:4px}

/* ── Accessibility: prefers-reduced-transparency ── */
@media (prefers-reduced-transparency: reduce){
  .gel{
    background-color:var(--surface2) !important;
    backdrop-filter:none !important;
    -webkit-backdrop-filter:none !important;
  }
  #canvas-toolbar{background:var(--surface);backdrop-filter:none !important;-webkit-backdrop-filter:none !important}
  #exp-overlay{backdrop-filter:none !important}
}
/* ── Accessibility: prefers-contrast ── */
@media (prefers-contrast: more){
  :root{--border:rgba(255,255,255,0.18);--border2:rgba(255,255,255,0.28);--text-muted:#c0c0d0;--text-hint:#9898b0}
  .gel{box-shadow:0 0 0 2px var(--border2) !important}
  #header{box-shadow:0 0 0 1px var(--border)}
}

/* ── Tablet (≤1024px) ── */
@media (max-width: 1024px){
  #rp{width:210px}
  #pscroll{padding:var(--space-sm) 10px}
  .logo{font-size:15px}
}

/* ── Phone (≤768px) ── */
@media (max-width: 768px){
  :root{
    --space-sm:6px;--space-md:8px;--space-lg:10px;
    --radius-sm:5px;--radius-md:6px;--radius-lg:10px;
  }
  /* Fold top bars into a single scrollable toolbar */
  #header, #presets-bar{
    flex-wrap:nowrap;
    overflow-x:auto;
    overflow-y:visible;
    white-space:nowrap;
  }
  #header{height:44px;padding:0 8px;gap:4px}
  #header::-webkit-scrollbar{height:0}
  #presets-bar{height:40px;padding:4px 8px;border-bottom:1px solid var(--border)}
  .preset-label{display:none}
  .preset{padding:3px 8px;font-size:11px}
  .preset span{font-size:10px}
  .preset-dot{width:8px;height:8px}
  .h-sep{display:none}
  .hb{padding:4px 8px;font-size:11px}
  .hb svg{width:11px;height:11px}
  .logo{font-size:15px}
  .logo-mark{width:20px;height:20px}
  /* Collapse left toolbar to floating bottom bar */
  #lp{
    display:none; /* hidden — moved to bottom bar */
  }
  /* Show bottom toolbar instead — single scrollable row, never wraps.
     flex-wrap:wrap previously collapsed 24 buttons into ~3 rows (~159px tall),
     covering the canvas bottom and hiding #sb-mob. nowrap + overflow-x:auto
     keeps every button reachable on one line while preserving scroll. */
  #btm{display:flex !important;flex-wrap:nowrap;justify-content:flex-start}
  #btm .bt{width:40px;height:40px;border-radius:10px;flex-shrink:0}
  #btm .tb{margin:2px;flex-shrink:0}
  #btm .tb svg{width:18px;height:18px}
  #btm .tip{left:50%;top:auto;bottom:calc(100% + 6px);transform:translateX(-50%) scale(0.94)}
  #btm .tb:hover .tip{transform:translateX(-50%) scale(1)}
  /* Stack canvas area; right panel becomes a slide-up drawer */
  #main{flex-direction:column}
  #canvas-area{min-height:0;flex:1}
  /* Toolbar occupies flow below the header+presets instead of floating over them.
     position:fixed;top:0 used to overlay the toolbar on top of the header,
     hiding the header's load/export-scale/format controls after image load. */
  #canvas-toolbar{
    position:relative;flex-shrink:0;
    background:rgba(20,20,24,.92);
    overflow-x:auto;overflow-y:visible;white-space:nowrap;
  }
  #canvas-toolbar::-webkit-scrollbar{height:0}
  #canvas-toolbar .label{font-size:11px;color:var(--text-hint);flex-shrink:0}
  #canvas-toolbar .hg{gap:3px}
  #canvas-toolbar .zoom-btn,#canvas-toolbar .zoom-fit-btn{padding:3px 6px;font-size:11px}
  #zoom-slider{width:60px;flex-shrink:0}
  #canvas-scroll{padding:16px;padding-bottom:calc(64px + env(safe-area-inset-bottom, 0px))}
  /* Right panel → slide-up sheet */
  #rp{
    position:fixed;bottom:0;left:0;right:0;
    height:70vh;max-height:520px;
    width:100%!important;
    border-left:none;
    border-top:1px solid var(--border2);
    border-radius:16px 16px 0 0;
    z-index:500;
    transform:translateY(100%);
    transition:transform 280ms var(--ease-out);
    display:flex!important;
  }
  #rp.open{transform:translateY(0)}
  #rp::before{
    content:'';width:36px;height:4px;
    background:var(--border2);border-radius:2px;
    position:absolute;top:8px;left:50%;
    transform:translateX(-50%);flex-shrink:0;
  }
  /* Mobile panel overlay — full-screen dim layer behind slide-up panel.
     z-index 150 keeps it below the fixed canvas-toolbar (z:100) so toolbar
     buttons remain clickable when the panel is open. */
  #panel-overlay{
    position:fixed;inset:0;z-index:150;
    background:rgba(0,0,0,.45);
    opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity 280ms var(--ease-out),visibility 280ms;
  }
  #panel-overlay.show{opacity:1;visibility:visible;pointer-events:auto}
  #rp-layers{
    padding-top:20px;
    max-height:160px;
  }
  #pscroll{padding:var(--space-md) 14px}
  .sec-hd{padding:8px 12px;font-size:12px}
  /* Panel toggle button in canvas toolbar */
  #panel-toggle{display:flex !important}
  /* Hide status bar, replace with compact floating bar */
  #sb{display:none}
  #sb-mob{display:flex !important}
  /* Shortcuts panel full-screen on phone */
  #shortcuts-panel{
    min-width:auto;margin:16px;
    width:calc(100% - 32px);
    padding:20px;
  }
  #shortcuts-panel .sc-grid{grid-template-columns:1fr}
  /* Context menu full-width on phone */
  #ctx-menu{min-width:calc(100vw - 32px);max-width:320px}
  /* btm 滚动条隐藏 — 与 header/presets-bar 一致 */
  #btm::-webkit-scrollbar{height:0}
  /* Keep toast above the bottom toolbar + slide-up panel on phones */
  #toast{bottom:calc(64px + env(safe-area-inset-bottom, 0px))}
  /* Larger touch targets for resize handles — 44px hit area */
  .rh{width:12px;height:12px}
  .rh::before{content:'';position:absolute;inset:-10px}
  .rh.tl{top:-6px;left:-6px}
  .rh.tr{top:-6px;right:-6px}
  .rh.bl{bottom:-6px;left:-6px}
  .rh.br{bottom:-6px;right:-6px}
  .rh.tm{top:-6px;left:calc(50% - 6px)}
  .rh.bm{bottom:-6px;left:calc(50% - 6px)}
  .rh.ml{top:calc(50% - 6px);left:-6px}
  .rh.mr{top:calc(50% - 6px);right:-6px}
  /* Scale up drop zone for mobile */
  #dz-inner{width:85vw!important;max-width:360px;height:240px!important}
  #dz p{font-size:13px}
  /* Context menu touch-friendly */
  #ctx-menu{min-width:calc(100vw - 24px)!important;max-width:300px!important}
  .ctx-item{padding:10px 14px;font-size:13px}
  /* Disable pointer events on resize handles when not selected on mobile */
  .rh, .gel{touch-action:none}
  /* Hide scrollbars on touch devices (native scroll is smoother) */
  #presets-bar, #header, #ll, #pscroll, #canvas-scroll{
    -ms-overflow-style:auto;
  }
}

/* ── Very small phones (≤380px) ── */
@media (max-width: 380px){
  #header{padding:0 6px;gap:2px}
  .hb{padding:3px 6px;font-size:10px}
  #canvas-scroll{padding:10px}
  .tb{width:38px;height:38px}
  .mini-btn{padding:var(--space-xs) 6px;font-size:10px}
}
