:root{
 --paper:#F4F1E8;--paper-2:#EAE5D8;--paper-3:#DFD8C7;
 --ink:#15120C;--ink-mid:#4C463A;--ink-light:#6B6455;   /* ink-light 由 #90897A 調深：小字 meta 對比 3.08→5.2（WCAG AA） */
 --rule:#D0C9B8;--rule-2:#E1DBCB;
 --accent:#C04828;--accent-2:#8F3318;--device:#9A9587;
 --accent-text:color-mix(in srgb,var(--accent) 82%,#15120C);   /* accent 當「文字」用的高對比變體;用 color-mix 衍生,主題色 .dot 切換時自動跟隨 */
 --grid:rgba(21,18,12,.05);
 --disp:'Bricolage Grotesque',sans-serif;--mono:'JetBrains Mono',monospace;--zh:'Noto Sans TC',sans-serif;
}
body.dark{--paper:#14110B;--paper-2:#1C1813;--paper-3:#241F18;--ink:#F2EEE2;--ink-mid:#B4AD9C;--ink-light:#908875;--rule:#2C271E;--rule-2:#221E17;--device:#7C776A;--grid:rgba(242,238,226,.04);--paper-canvas:#100D08;--accent-text:color-mix(in srgb,var(--accent) 72%,#F2EEE2);}   /* 深色：ink-light 3.77→5.35;accent-text 改「調亮」衍生 */
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{background:var(--paper-2);color:var(--ink);font-family:var(--zh);display:flex;flex-direction:column;overflow:hidden;transition:background .35s,color .35s}
.mono{font-family:var(--mono)}
/* top bar */
.bar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding:9px 16px;background:var(--paper);border-bottom:1px solid var(--rule);z-index:20}
.brand{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;white-space:nowrap}
.brand b{color:var(--accent)}
.sp{flex:1}
.grp{display:flex;align-items:center;gap:6px}
.grp+.grp{padding-left:12px;border-left:1px solid var(--rule)}
.lbl{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-light)}
.tbtn{font-family:var(--mono);font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-mid);background:transparent;border:1px solid var(--rule);border-radius:2px;padding:5px 9px;cursor:pointer;transition:.15s;white-space:nowrap}
.tbtn:hover{border-color:var(--ink-mid);color:var(--ink)}
.tbtn.on{background:var(--accent);border-color:var(--accent);color:var(--paper)}
.tbtn.solid{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.tbtn.solid:hover{background:var(--accent);border-color:var(--accent)}
.tbtn:disabled{opacity:.3;cursor:default}
.tbtn:disabled:hover{color:var(--ink-mid);border-color:var(--rule)}
.tbtn.busy,.tbtn.busy:disabled,.tbtn.busy:hover{opacity:.82;cursor:progress;color:var(--paper);background:var(--ink);border-color:var(--ink)}
.dot{width:16px;height:16px;border-radius:50%;border:1.5px solid var(--rule);cursor:pointer;transition:.15s;padding:0}
@media (hover:hover) and (pointer:fine){.dot:hover{transform:scale(1.15)}}
.dot.on{box-shadow:0 0 0 2px var(--paper),0 0 0 3.2px var(--ink)}
.moremenu-wrap{position:relative}
.moremenu{position:absolute;top:calc(100% + 9px);right:0;z-index:30;width:214px;background:var(--paper);border:1px solid var(--rule);border-radius:7px;box-shadow:0 18px 44px -18px rgba(21,18,12,.5);padding:13px;transform-origin:top right;animation:ddpop .16s cubic-bezier(.2,.8,.3,1) both}
.moremenu[hidden]{display:none}
.mm-sec{margin-bottom:13px}
.mm-sec:last-child{margin-bottom:0}
.mm-label{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-light);margin-bottom:7px}
.mm-dots{display:flex;gap:10px;padding:2px 3px}
.mm-fs{display:flex;align-items:center;gap:9px;padding:2px 3px}
.mm-fs input[type=range]{flex:1;min-width:0;accent-color:var(--accent);cursor:pointer}
.mm-fsv{font-family:var(--mono);font-size:10px;color:var(--ink-light);min-width:32px;text-align:right}
.mm-item{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;font-family:var(--zh);font-size:11.5px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-radius:4px;padding:7px 10px;cursor:pointer;transition:.12s;margin-bottom:5px;text-align:left}
.mm-item:last-child{margin-bottom:0}
.mm-status{font-family:var(--mono);font-size:10px;color:var(--ink-light);line-height:1.55;margin-bottom:7px;white-space:pre-wrap;word-break:break-word}
.dd{position:relative;display:inline-flex}
.dd-btn .ca{font-size:8px;color:var(--ink-light);margin-left:5px;transition:.12s}
.dd-btn.on .ca,.dd-btn:hover .ca{color:var(--ink)}
.dd-menu{position:absolute;left:0;top:calc(100% + 6px);z-index:60;min-width:238px;background:var(--paper);border:1px solid var(--rule);border-radius:7px;box-shadow:0 16px 40px -16px rgba(21,18,12,.5);padding:15px;transform-origin:top left;animation:ddpop .15s cubic-bezier(.2,.8,.3,1) both}
.dd-menu[hidden]{display:none}
.dd-menu .mm-item:last-child{margin-bottom:0}
.snap-split{gap:0}
.snap-split #snapBtn{border-top-right-radius:0;border-bottom-right-radius:0}
.snap-split .snap-caret{border-top-left-radius:0;border-bottom-left-radius:0;border-left-width:0;padding:5px 7px}
.snap-split .snap-caret.on{background:transparent;color:var(--ink);border-color:var(--rule)}
.snap-menu{min-width:184px}
.snap-chk{font-size:11px;color:var(--accent-text);line-height:1;margin-left:10px}
.snap-menu .mm-item:not(.on) .snap-chk{visibility:hidden}
.dd-custom{margin-top:3px;padding-top:8px;border-top:1px solid var(--rule-2)}
.ddc-row{display:flex;align-items:center;gap:8px;margin-bottom:7px}
.ddc-row label{font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-light);width:34px}
.ddc-row input{flex:1;min-width:0;font-family:var(--mono);font-size:11px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-radius:4px;padding:5px 7px}
.ddc-row input:focus{outline:none;border-color:var(--accent)}
.dd-sec{font-family:var(--mono);font-size:9px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-light);margin:9px 2px 6px;padding-top:8px;border-top:1px solid var(--rule-2)}
.dd-menu .dd-sec:first-child{margin-top:0;padding-top:0;border-top:none}
.ddc-sel{flex:1;min-width:0;font-family:var(--mono);font-size:10.5px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-radius:4px;padding:5px 7px;cursor:pointer}
.ddc-sel:focus{outline:none;border-color:var(--accent)}
.ddc-seg{flex:1;display:flex;border:1px solid var(--rule);border-radius:4px;overflow:hidden}
.ddc-seg button{flex:1;font-family:var(--mono);font-size:10px;color:var(--ink-light);background:var(--paper-2);border:none;border-right:1px solid var(--rule);padding:5px 0;cursor:pointer;transition:.12s}
.ddc-seg button:last-child{border-right:none}
.ddc-seg button:hover{color:var(--ink);background:var(--paper)}
.ddc-seg button.on{background:var(--accent);color:#fff}
.mm-item:hover{border-color:var(--accent);background:var(--paper)}
.mm-item.on{border-color:var(--accent);color:var(--accent-text)}
.mm-item.danger:hover{border-color:var(--accent-2);color:var(--accent-2)}
.mm-item:disabled{opacity:.35;cursor:default}
.mm-item:disabled:hover{border-color:var(--rule);background:var(--paper-2)}
.dd-div{height:1px;background:var(--rule-2);margin:7px 2px}
/* op dialog footer · assets cluster（狀態單行截斷，完整內容放 title） */
.op-assets{display:flex;align-items:center;gap:7px;min-width:0}
.op-astat{font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;color:var(--ink-light);max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* layout */
.work{flex:1;display:flex;min-height:0}
.panel{width:248px;background:var(--paper);border-right:1px solid var(--rule);display:flex;flex-direction:column;overflow:hidden}   /* 與右欄同架構:展開時區塊滿高、清單內捲;收合特例見 :has 規則 */
.panel.right{border-right:none;border-left:1px solid var(--rule)}
.psec{padding:12px 13px 13px;border-bottom:1px solid var(--rule-2)}
.ph{font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent-text);margin-bottom:9px}
/* anchored side panels: fixed top/bottom, scrolling middle */
.panel:not(.right){overflow:hidden}
.panel:not(.right) .sec-add{flex:none;padding-bottom:12px}
.addmain{width:100%;padding:9px 10px;font-size:10px;letter-spacing:.1em;border-radius:3px}
.qins{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:8px}
.qins .full{padding:7px 4px;font-size:9.5px;letter-spacing:.03em;gap:4px}
.panel:not(.right) .sec-layers{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;border-bottom:none}
.panel:not(.right) .sec-layers>.ph{flex:none}
.panel:not(.right) .sec-layers #layers{flex:1 1 auto;min-height:0;max-height:none;overflow-y:auto;padding-right:3px}   /* max-height:none 蓋掉行 397 舊版面的 320px 上限（比照 .palette 既有 pattern） */
.panel:not(.right) .sec-layers.collapsed{flex:0 0 auto}
.panel:not(.right):has(.sec-layers.collapsed){overflow-y:auto}
.sec-env .env-body::-webkit-scrollbar{width:7px}
.sec-env .env-body::-webkit-scrollbar-thumb{background:var(--rule);border-radius:4px}
.sec-env .env-body::-webkit-scrollbar-track{background:transparent}
.panel:not(.right) .sec-symbols{flex:1 1 0;min-height:0;display:flex;flex-direction:column}
.panel:not(.right) .sec-symbols .palette{flex:1 1 auto;min-height:0;max-height:none}
.sec-insert{border-bottom:none}
.panel.right{overflow:hidden}
.panel.right .sec-inspector{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;border-bottom:none}
.panel.right .sec-inspector>.ph{flex:none}
.panel.right .sec-inspector #insp{flex:1 1 auto;min-height:0;overflow-y:auto;padding-right:3px}

.sec-inspector #insp::-webkit-scrollbar,.sec-layers #layers::-webkit-scrollbar{width:7px}
.sec-inspector #insp::-webkit-scrollbar-thumb,.sec-layers #layers::-webkit-scrollbar-thumb{background:var(--rule);border-radius:4px}
.sec-inspector #insp::-webkit-scrollbar-thumb:hover,.sec-layers #layers::-webkit-scrollbar-thumb:hover{background:var(--ink-light)}
.sec-inspector #insp::-webkit-scrollbar-track,.sec-layers #layers::-webkit-scrollbar-track{background:transparent}
.panel .psec>.ph{cursor:pointer;user-select:none;transition:color .12s}
.panel .psec>.ph:hover{color:var(--ink)}
.panel .psec>.ph::before{content:'\25B8';display:inline-block;margin-right:6px;font-size:10px;transform:rotate(90deg);transition:transform .15s ease}
.panel .psec.collapsed>.ph::before{transform:rotate(0deg)}
.panel .psec.collapsed>.ph{margin-bottom:0}
.panel .psec.collapsed>:not(.ph){display:none!important}
.panel .psec.collapsed{padding-bottom:13px}
.panel:not(.right) .sec-symbols.collapsed{flex:0 0 auto}
.panel.right .sec-inspector.collapsed{flex:0 0 auto}
.panel:not(.right):has(.sec-symbols.collapsed){overflow-y:auto}
.panel.right:has(.sec-inspector.collapsed){overflow-y:auto}
.numwrap input:disabled{opacity:.4;cursor:default}
.numwrap input:disabled+span,.numwrap:has(input:disabled) span{opacity:.5}
.valin:disabled{opacity:.4;cursor:default}
input[type=range]:disabled{opacity:.4;cursor:default}
.valwrap:has(.valin:disabled) .unit{opacity:.5}
.palette{display:grid;grid-template-columns:1fr 1fr;gap:7px;max-height:clamp(200px,40vh,420px);overflow-y:auto;padding-right:3px}
.palette::-webkit-scrollbar{width:7px}
.palette::-webkit-scrollbar-thumb{background:var(--rule);border-radius:4px}
.palette::-webkit-scrollbar-thumb:hover{background:var(--ink-light)}
.palette::-webkit-scrollbar-track{background:transparent}
.insert-grid{display:grid;grid-template-columns:1fr 1fr;gap:7px}
.pitem{border:1px solid var(--rule);background:var(--paper-2);border-radius:3px;cursor:pointer;display:flex;flex-direction:column;align-items:center;padding:8px 4px 6px;transition:.15s}
.pitem:hover{border-color:var(--accent);background:var(--paper)}
.pitem svg{width:42px;height:38px;display:block}
.pitem span{font-size:10px;color:var(--ink-mid);margin-top:4px;text-align:center;line-height:1.2}
.pcat{grid-column:1/-1;font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-light);margin:7px 0 1px;padding-top:6px;border-top:1px solid var(--rule-2)}
.pcat:first-child{border-top:none;padding-top:0;margin-top:0}
.pal-searchwrap{position:relative;margin:0 0 7px}
.pal-search{width:100%;font-family:var(--zh);font-size:11px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-radius:3px;padding:6px 26px 6px 9px;transition:.15s}
.pal-search:focus{outline:none;border-color:var(--accent);background:var(--paper)}
.pal-search::placeholder{color:var(--ink-light)}
.pal-clear{position:absolute;right:5px;top:50%;transform:translateY(-50%);width:18px;height:18px;border:none;background:transparent;color:var(--ink-light);cursor:pointer;border-radius:2px;display:none;align-items:center;justify-content:center;font-size:11px;padding:0;line-height:1}
.pal-clear:hover{color:var(--ink)}
.pal-clear.show{display:flex}
.pal-noresult{grid-column:1/-1;font-family:var(--mono);font-size:10px;color:var(--ink-light);text-align:center;padding:16px 4px 6px;letter-spacing:.04em}
/* tabbed palette (符號/人物/設備/物件) */
.ptabs{display:flex;gap:3px;margin:0 0 8px;background:var(--paper-2);border:1px solid var(--rule);border-radius:4px;padding:3px}
.ptab{flex:1;font-family:var(--zh);font-size:10px;letter-spacing:.02em;color:var(--ink-mid);background:transparent;border:none;border-radius:2px;padding:5px 2px;cursor:pointer;transition:.12s;white-space:nowrap}
.ptab:hover{color:var(--ink)}
.ptab.on{background:var(--accent);color:var(--paper)}
/* dual CN / EN legend label */
.pitem{position:relative}
.pitem .nm{display:flex;flex-direction:column;align-items:center;gap:0;margin-top:4px;line-height:1.18}
.pitem .nm b{font-size:10px;font-weight:600;color:var(--ink-mid);text-align:center}
.pitem .nm i{font-family:var(--mono);font-size:8px;font-style:normal;letter-spacing:.02em;color:var(--ink-light);text-align:center;margin-top:1px}
.pitem .nm .dims{color:var(--accent-text)}  /* 1:1 規格件：名稱下的「寬×深×高 mm」尺寸行——這行本身就是與示意件的視覺區別 */
.pitem:hover .nm b{color:var(--ink)}
/* category tag — only shown in flat global-search results */
.pitem .ptag{display:none;position:absolute;top:3px;right:3px;font-family:var(--mono);font-size:8px;letter-spacing:.03em;color:var(--ink-light);background:var(--paper);border:1px solid var(--rule-2);border-radius:2px;padding:1px 3px;line-height:1.15}
.palette.searching .ptag{display:inline-block}
/* per-group hint (e.g. assets not yet loaded) */
.pgrp-hint{grid-column:1/-1;font-family:var(--zh);font-size:10px;color:var(--ink-light);padding:3px 2px 7px;line-height:1.5}
/* full-width upload tile inside the 物件 tab */
.pitem.wide{grid-column:1/-1;flex-direction:row;justify-content:center;gap:8px;padding:11px 8px;border-style:dashed}
.pitem.wide svg{width:20px;height:20px}
.pitem.wide .nm{margin-top:0}
.pitem.wide .nm b{font-size:10px}
.full{width:100%;display:flex;align-items:center;justify-content:center;gap:7px;border:1px dashed var(--rule);background:transparent;border-radius:3px;padding:9px;cursor:pointer;font-family:var(--mono);font-size:10px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-mid);transition:.15s}
.full:hover{border-color:var(--accent);color:var(--accent)}
.full.ctx{border-style:solid}
/* prominent toolbar button (＋ 元件) */
.tbtn.accent{background:var(--accent);border-color:var(--accent);color:var(--paper)}
.tbtn.accent:hover{background:var(--accent-2);border-color:var(--accent-2);color:var(--paper)}
.tbtn.accent.on{background:var(--accent-2);border-color:var(--accent-2)}
/* ===== OP DIALOG — floating component creator (Tab / ＋元件) ===== */
.opscrim{position:fixed;inset:0;z-index:60;background:rgba(21,18,12,.30);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);animation:opfade .14s ease both}
body.dark .opscrim{background:rgba(0,0,0,.52)}
.opdlg{position:fixed;left:50%;top:46%;transform:translate(-50%,-50%);z-index:61;width:min(780px,93vw);max-height:82vh;display:flex;flex-direction:column;background:var(--paper);border:1px solid var(--rule);border-radius:11px;box-shadow:0 34px 90px -26px rgba(21,18,12,.62),0 1px 0 rgba(255,255,255,.05) inset;overflow:hidden;animation:oppop .17s cubic-bezier(.2,.85,.3,1) both}
.opscrim[hidden],.opdlg[hidden]{display:none!important}   /* hidden attr must beat the explicit display above */
@keyframes opfade{from{opacity:0}to{opacity:1}}
@keyframes oppop{from{opacity:0;transform:translate(-50%,-50%) scale(.965)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}
.op-head{display:flex;align-items:center;gap:12px;padding:15px 17px 11px}
.op-title{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-mid);white-space:nowrap}
.op-title b{color:var(--accent-text)}
.op-hint{flex:1;font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;color:var(--ink-light);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:right}
.op-x{flex:none;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--rule);background:var(--paper-2);border-radius:5px;color:var(--ink-light);font-size:12px;cursor:pointer;transition:.12s;padding:0;line-height:1}
.op-x:hover{border-color:var(--accent);color:var(--accent)}
.op-searchwrap{position:relative;padding:0 17px 11px}
.op-search{width:100%;font-family:var(--zh);font-size:14.5px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-radius:7px;padding:11px 36px 11px 14px;transition:.15s}
.op-search:focus{outline:none;border-color:var(--accent);background:var(--paper);box-shadow:0 2px 0 var(--accent)}
.op-search::placeholder{color:var(--ink-light)}
.op-clear{position:absolute;right:24px;top:11px;width:22px;height:22px;border:none;background:transparent;color:var(--ink-light);cursor:pointer;border-radius:3px;display:none;align-items:center;justify-content:center;font-size:12px;padding:0;line-height:1}
.op-clear:hover{color:var(--ink)}
.op-clear.show{display:flex}
.optabs{display:flex;gap:6px;padding:0 17px 13px;flex-wrap:wrap}
.optab{font-family:var(--zh);font-size:11.5px;color:var(--ink-mid);background:var(--paper-2);border:1px solid var(--rule);border-radius:20px;padding:6px 14px;cursor:pointer;transition:.12s}
.optab:hover{color:var(--ink);border-color:var(--ink-light)}
.optab.on{background:var(--accent);border-color:var(--accent);color:var(--paper)}
.optab .buyb{font-style:normal;font-size:9px;margin-left:5px;color:var(--accent-text)}  /* [part] 分類 Tab 的採買標記 ▦（列入 BOM 採買清單） */
.optab.on .buyb{color:var(--paper)}
.opgrid{flex:1 1 auto;min-height:0;overflow-y:auto;padding:4px 17px 8px;display:grid;grid-template-columns:repeat(auto-fill,minmax(106px,1fr));gap:9px;align-content:start}
.opgrid::-webkit-scrollbar{width:9px}
.opgrid::-webkit-scrollbar-thumb{background:var(--rule);border-radius:5px}
.opgrid::-webkit-scrollbar-thumb:hover{background:var(--ink-light)}
.opgrid .pitem{padding:12px 6px 10px}
.opgrid .pitem svg{width:60px;height:52px}
.opgrid .pitem .nm b{font-size:10.5px}
.opgrid .pitem .nm i{font-size:9px}
.opgrid .pitem.kbd{border-color:var(--accent);background:var(--paper);box-shadow:0 0 0 2px var(--accent)}
.opgrid .pitem.wide svg{width:22px;height:22px}
.opgrid.searching .ptag{display:inline-block}
.opgrid .pcat:first-child{border-top:none;padding-top:2px;margin-top:0}
.op-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 17px 12px;border-top:1px solid var(--rule-2)}
.op-foot span{font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;color:var(--ink-light)}
.op-kbd{font-family:var(--mono);font-size:9.5px;border:1px solid var(--rule-2);border-radius:3px;padding:1px 5px;color:var(--ink-light)}
/* canvas */
.canvas-area{flex:1;min-width:0;position:relative;display:flex}
.canvas-ghost{position:absolute;inset:0;z-index:2;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:15px;pointer-events:none;opacity:0;transition:opacity .3s ease;color:var(--ink-light)}
.canvas-ghost.show{opacity:.62}
.canvas-ghost svg{opacity:.85}
.canvas-ghost .cg-main{font-family:var(--zh);font-size:13px;font-weight:500;color:var(--ink-mid);text-align:center;letter-spacing:.02em}
.canvas-ghost .cg-sub{font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;color:var(--ink-light);text-align:center;margin-top:5px}
.canvas-wrap{flex:1;min-width:0;display:grid;place-items:center;padding:26px;background:
  linear-gradient(var(--grid) 1px,transparent 1px) 0 0/24px 24px,
  linear-gradient(90deg,var(--grid) 1px,transparent 1px) 0 0/24px 24px,var(--paper-2);overflow:auto}
.viewzoom{position:absolute;right:14px;bottom:14px;z-index:6;display:flex;align-items:stretch;font-family:var(--mono);background:var(--paper);border:1px solid var(--rule);border-radius:4px;box-shadow:0 6px 18px -10px rgba(21,18,12,.45);overflow:hidden}
.viewzoom button{font-family:var(--mono);font-size:13px;line-height:1;color:var(--ink-mid);background:transparent;border:none;padding:5px 10px;cursor:pointer;transition:.12s}
.viewzoom button:hover{background:var(--paper-2);color:var(--ink)}
.viewzoom .vz-val{padding:6px 9px;min-width:48px;text-align:center;font-size:10px;letter-spacing:.04em;color:var(--ink-mid);border-left:1px solid var(--rule-2);border-right:1px solid var(--rule-2);cursor:pointer;display:flex;align-items:center;justify-content:center}
.viewzoom .vz-val:hover{background:var(--paper-2);color:var(--ink)}
.viewzoom .vz-fit{display:flex;align-items:center;border-right:1px solid var(--rule-2)}
.dragreadout{position:fixed;z-index:50;pointer-events:none;font-family:var(--mono);font-size:10px;letter-spacing:.02em;color:var(--ink);background:var(--paper);border:1px solid var(--rule);border-radius:4px;padding:3px 7px;box-shadow:0 6px 18px -10px rgba(21,18,12,.45);opacity:0;transition:opacity .1s ease;white-space:nowrap}
.dragreadout .dl{color:var(--ink-light);margin-right:5px}
.dragreadout.show{opacity:.96}
.frame{background:var(--paper-canvas,var(--paper));box-shadow:0 16px 48px -22px rgba(21,18,12,.45),0 0 0 1px var(--rule);position:relative}
body.dark .frame{box-shadow:0 16px 48px -20px #000,0 0 0 1px var(--rule)}
#svg{display:block;width:100%;height:auto;touch-action:none}
/* svg art classes */
.s{fill:var(--s-fill,none);stroke-linecap:round;stroke-linejoin:round}
.o{stroke:var(--accent)}.g{stroke:var(--g-stroke,var(--device))}.r{stroke:var(--rule)}.rr{stroke:var(--rule-2)}
.of{fill:var(--accent)}.gf{fill:var(--device)}.fa{fill:var(--accent)}.fp2{fill:var(--paper-2)}.fp3{fill:var(--paper-3)}.fp{fill:var(--paper)}
.w22{stroke-width:2.1}.w15{stroke-width:1.6}.w12{stroke-width:var(--g-w,1.3)}.w10{stroke-width:var(--g-w,1.05)}.w08{stroke-width:var(--g-w,.85)}.w06{stroke-width:.62}
.bn{font-family:var(--mono);font-size:10px;fill:var(--accent)}.bnl{font-family:var(--mono);font-size:10px;fill:var(--ink-light)}
.inkl{stroke:var(--ink-light)}
.tx{font-family:'JetBrains Mono','Noto Sans TC',monospace}.tac{fill:var(--accent)}.tin{fill:var(--ink)}.tml{fill:var(--ink-light)}.tmd{fill:var(--ink-mid)}.ink{stroke:var(--ink)}.dsp{font-family:var(--disp)}
.item{cursor:move}
.item .hov{fill:none;stroke:var(--accent);stroke-width:1;opacity:0;pointer-events:none;transition:opacity .12s}
.item .hov.line{stroke-width:4;stroke-linecap:round;stroke-linejoin:round}
.item:hover .hov{opacity:.42}
.item:hover .hov.line{opacity:.22}
/* 選取不再對作品本身加眩光：保持畫布＝忠實預覽，匯出所見即所得；選取狀態改由四角框(selMarks)＋虛線外框(.sel-outline)＋變形把手表示 */
.selmarks{pointer-events:none}
.selmk{fill:none;stroke:var(--accent);stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.selmk-dot{fill:var(--accent);stroke:var(--paper);stroke-width:1.2}
.ctxmenu{position:fixed;z-index:200;min-width:202px;background:var(--paper);border:1px solid var(--rule);border-radius:7px;box-shadow:0 18px 46px -16px rgba(21,18,12,.55);padding:5px;font-family:var(--zh);transform-origin:top left;animation:ddpop .14s cubic-bezier(.2,.8,.3,1) both}
.ctxmenu[hidden]{display:none}
.cm-item{display:flex;align-items:center;gap:9px;width:100%;font-size:12px;color:var(--ink);background:none;border:0;border-radius:5px;padding:6px 9px;cursor:pointer;text-align:left;transition:background .1s,color .1s}
.cm-item:hover{background:var(--paper-2)}
.cm-item:hover .cm-ico{color:var(--ink-mid)}
.cm-item.danger{color:var(--accent-2)}
.cm-item.danger .cm-ico{color:var(--accent-2)}
.cm-item.danger:hover{background:color-mix(in srgb,var(--accent-2) 13%,transparent)}
.cm-ico{flex:0 0 15px;width:15px;height:15px;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-light);transition:color .1s}
.cm-ico svg{width:15px;height:15px;display:block}
.cm-tx{flex:1 1 auto;min-width:0;white-space:nowrap}
.cm-k{flex:0 0 auto;font-family:var(--mono);font-size:10px;color:var(--ink-light);letter-spacing:.05em}
.cm-div{height:1px;background:var(--rule-2);margin:4px 7px}
.cm-gl{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-light);padding:7px 9px 3px;user-select:none;pointer-events:none}
.cm-sec{padding:6px 9px 7px}
.cm-label{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-light);margin-bottom:6px}
.cm-planes{display:flex;gap:4px}
.cm-planes button{flex:1;min-width:0;font-family:var(--zh);font-size:10.5px;color:var(--ink-mid);background:var(--paper-2);border:1px solid var(--rule);border-radius:3px;padding:5px 2px;cursor:pointer;transition:.1s;white-space:nowrap}
.cm-planes button:hover{border-color:var(--accent);color:var(--accent)}
.sel-outline{fill:none;stroke:var(--accent);stroke-width:1;stroke-dasharray:4 3;opacity:.85;pointer-events:none}
.insp-multi{padding:4px 2px}
.insp-multi .im-head{display:flex;align-items:baseline;gap:7px;margin-bottom:3px}
.insp-multi .im-n{font-family:var(--disp);font-size:26px;font-weight:700;color:var(--accent);line-height:1}
.insp-multi .im-t{font-family:var(--zh);font-size:13px;color:var(--ink)}
.insp-multi .im-hint{font-family:var(--zh);font-size:11px;color:var(--ink-light);margin:0 0 13px}
.insp-multi .tbtn{width:100%;margin-top:7px}
.marquee{fill:color-mix(in srgb,var(--accent) 12%,transparent);stroke:var(--accent);stroke-width:1;stroke-dasharray:4 3;opacity:.9;pointer-events:none}
.handle{fill:var(--paper);stroke:var(--accent);stroke-width:1.4;cursor:grab}
.handle.vsel{fill:var(--accent);stroke:var(--paper);stroke-width:2}                 /* 選取中的折點 */
.handle.wlead{fill:var(--accent);stroke:var(--paper);stroke-width:1.6;cursor:grab}   /* 引線接點 */
svg.altkey .wirehit{cursor:copy}                                                     /* Alt：在線段上插入折點 */
svg.altkey g.item{cursor:copy}                                                       /* Alt：拖曳＝複製副本（線材為插入折點，同用 copy 游標） */
#svg.spacepan{cursor:grab}                                                           /* 空白鍵按住：平移檢視 */
.handle:active{cursor:grabbing}
.thandle-stem{stroke:var(--accent);stroke-width:1.2;opacity:.45;fill:none;pointer-events:none}
.thandle-gly{fill:none;stroke:var(--accent);stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;pointer-events:none}
.thandle-rot circle,.thandle-scl polygon{transition:fill .1s}
.thandle-rot:hover circle,.thandle-scl:hover polygon{fill:var(--accent)}
.thandle-rot:hover .thandle-gly,.thandle-scl:hover .thandle-gly{stroke:var(--paper)}
.thandle-rot{cursor:grab}.thandle-rot:active{cursor:grabbing}
.thandle-scl{cursor:nwse-resize}
.gline{stroke:var(--device);opacity:.55}
.gfill{fill:var(--device)}
/* inspector */
.field{margin-bottom:8px}
.field label{display:flex;justify-content:space-between;align-items:center;font-family:var(--mono);font-size:10px;color:var(--ink-light);letter-spacing:.06em;text-transform:uppercase;margin-bottom:4px}
.field label b{color:var(--ink-mid);font-weight:500}
input[type=range]{width:100%;accent-color:var(--accent);height:3px}
.seg{display:flex;gap:4px;flex-wrap:wrap}
.seg button{flex:1;white-space:nowrap;font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-mid);background:var(--paper-2);border:1px solid var(--rule);border-radius:2px;padding:4px 5px;cursor:pointer;transition:.12s}
.seg button:hover{border-color:var(--ink-mid)}
.seg button.on{background:var(--accent);border-color:var(--accent);color:var(--paper)}
.swatches{display:flex;gap:5px;flex-wrap:wrap;align-items:center}
.swatches .sw{width:18px;height:18px;border-radius:3px;border:1px solid var(--rule);cursor:pointer;padding:0;transition:transform .12s;position:relative}
@media (hover:hover) and (pointer:fine){.swatches .sw:hover{transform:scale(1.12)}}
.swatches .sw.on{box-shadow:0 0 0 2px var(--paper),0 0 0 3px var(--ink)}
.swatches .sw-none{background:var(--paper-2)}
.swatches .sw-none::after{content:'';position:absolute;inset:3px;background:linear-gradient(45deg,transparent 43%,var(--ink-light) 43%,var(--ink-light) 57%,transparent 57%)}
.swatches .sw-custom{width:24px;height:18px;padding:0;border:1px solid var(--rule);border-radius:3px;cursor:pointer;background:none}
.swatches .sw-custom::-webkit-color-swatch-wrapper{padding:1px}
.swatches .sw-custom::-webkit-color-swatch{border:none;border-radius:2px}
.row{display:flex;gap:6px}
.numwrap{flex:1;display:flex;align-items:center;gap:6px}
.numwrap>span{font-family:var(--mono);font-size:10px;color:var(--ink-light);width:8px;flex:none;text-align:center}
input.numin{width:100%;font-family:var(--mono);font-size:11px;color:var(--ink-mid);background:var(--paper-2);border:1px solid var(--rule);border-radius:2px;padding:5px 6px;-moz-appearance:textfield}
input.numin:focus{outline:none;border-color:var(--accent);color:var(--ink)}
input.numin::-webkit-outer-spin-button,input.numin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
input.txin{width:100%;font-family:var(--zh);font-size:11px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-radius:2px;padding:5px 7px}
textarea.txin{width:100%;font-family:var(--mono);font-size:10px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-radius:2px;padding:6px 7px;line-height:1.6;resize:vertical}
textarea.txin:focus{outline:none;border-color:var(--accent)}
input.txin:focus{outline:none;border-color:var(--accent)}
.field label .valwrap{display:inline-flex;align-items:center;gap:2px}
input.valin{width:48px;font-family:var(--mono);font-size:10px;font-weight:500;line-height:1;color:var(--ink-mid);background:transparent;border:1px solid transparent;border-radius:2px;padding:2px 3px;text-align:right;text-transform:none;letter-spacing:0;-moz-appearance:textfield;transition:border-color .12s,background .12s,color .12s}
input.valin:hover{border-color:var(--rule)}
input.valin:focus{outline:none;border-color:var(--accent);background:var(--paper-2);color:var(--ink)}
input.valin::-webkit-outer-spin-button,input.valin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.field label .unit{font-style:normal;font-family:var(--mono);font-size:10px;color:var(--ink-light)}
.empty{font-size:11px;color:var(--ink-light);line-height:1.7;font-weight:300}
.danger{color:var(--accent-2);border-color:color-mix(in srgb,var(--accent) 40%,transparent)}
.danger:hover{background:var(--accent);border-color:var(--accent);color:var(--paper)}
.hint{font-family:var(--mono);font-size:9.5px;color:var(--ink-light);line-height:1.6;letter-spacing:.02em;margin-top:6px}
.dimro{font-family:var(--mono);font-size:15px;font-weight:600;color:var(--accent-text);padding:2px 0}  /* [part] 規格件：Inspector 唯讀 寬×深×高 讀值 */
.hint.faint{opacity:.62} /* 更淡：用於 Shift 吸附等非指令性的輕提示 */
.sh-sec{display:flex;align-items:center;gap:8px;margin:12px 0 7px;padding-top:11px;border-top:1px solid var(--rule-2)}
.sh-sec .sh-ico{flex:none;display:block;color:var(--ink-light)}
.sh-sec .sh-tx{display:flex;flex-direction:column;gap:1px;line-height:1.12}
.sh-sec .sh-cn{font-family:var(--zh);font-size:11px;font-weight:600;color:var(--ink);letter-spacing:.02em}
.sh-sec .sh-en{font-family:var(--mono);font-size:9.5px;color:var(--ink-light);text-transform:uppercase;letter-spacing:.07em}
.env-body>.sh-sec:first-child{margin-top:0;padding-top:2px;border-top:none}
.field:has(>label+input[type=range]){display:grid;grid-template-columns:minmax(0,1fr) 84px;align-items:center;column-gap:8px}
.field:has(>label+input[type=range])>label{margin-bottom:0}
.field:has(>label+input[type=range]) .valin{width:38px}
.envdlg{position:fixed;left:80px;top:64px;z-index:59;width:262px;max-height:min(76vh,660px);display:flex;flex-direction:column;background:var(--paper);border:1px solid var(--rule);border-radius:9px;box-shadow:0 22px 60px -18px rgba(21,18,12,.5)}
.envdlg[hidden]{display:none!important}   /* hidden attr must beat the explicit display above（比照 .opdlg）*/
.envdlg-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 12px 8px;border-bottom:1px solid var(--rule-2);cursor:grab;user-select:none}
.envdlg-head:active{cursor:grabbing}
.envdlg-title{font-family:var(--mono);font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--accent-text)}
.envdlg-title b{color:var(--ink-light);font-weight:400;margin-left:4px}
.envdlg-x{border:none;background:transparent;color:var(--ink-light);font-size:12px;cursor:pointer;padding:2px 5px;border-radius:2px;line-height:1}
.envdlg-x:hover{color:var(--ink);background:var(--paper-2)}
.envdlg-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:11px 13px 14px}
#projBtn .dd-lbl{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;vertical-align:bottom}
.pjscrim{position:fixed;inset:0;background:rgba(21,18,12,.34);z-index:60}
.pjscrim[hidden],.pjdlg[hidden]{display:none!important}   /* hidden attr must beat the explicit display below（教訓已學） */
.pjdlg{position:fixed;left:50%;top:46%;transform:translate(-50%,-50%);z-index:61;width:min(720px,92vw);max-height:80vh;display:flex;flex-direction:column;background:var(--paper);border:1px solid var(--rule);border-radius:11px;box-shadow:0 34px 90px -26px rgba(21,18,12,.62);overflow:hidden}
.pj-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px 10px;border-bottom:1px solid var(--rule-2)}
.pj-title{font-family:var(--mono);font-size:10px;letter-spacing:.15em;text-transform:uppercase;color:var(--ink)}
.pj-title b{color:var(--accent-text);font-weight:600;margin-left:6px}
.pj-x{border:none;background:transparent;color:var(--ink-light);font-size:13px;cursor:pointer;padding:3px 6px;border-radius:3px}
.pj-x:hover{color:var(--ink);background:var(--paper-2)}
.pjgrid{flex:1;min-height:0;overflow-y:auto;padding:14px 16px;display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px;align-content:start}
.pj-new{border:1px dashed var(--rule);background:transparent;border-radius:6px;min-height:150px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;cursor:pointer;font-family:var(--mono);font-size:11px;color:var(--ink-mid);transition:.15s}
.pj-new i{font-style:normal;font-size:9.5px;letter-spacing:.12em;color:var(--ink-light)}
.pj-new:hover{border-color:var(--accent);color:var(--accent)}
.pj-card{border:1px solid var(--rule);border-radius:6px;background:var(--paper);padding:8px;display:flex;flex-direction:column;gap:6px}
.pj-card.cur{border-color:var(--accent)}
.pj-thumb{aspect-ratio:16/9;border:1px solid var(--rule-2);border-radius:4px;background:var(--paper-2);display:flex;align-items:center;justify-content:center;overflow:hidden}
.pj-thumb img{width:100%;height:100%;object-fit:cover}
.pj-noimg{color:var(--ink-light);font-size:20px}
.pj-name{font-family:var(--zh);font-size:12px;font-weight:600;color:var(--ink);cursor:text;display:flex;align-items:center;gap:6px}
.pj-curtag{font-style:normal;font-family:var(--mono);font-size:9px;letter-spacing:.1em;color:var(--paper);background:var(--accent);border-radius:2px;padding:1px 4px}
.pj-meta{font-family:var(--mono);font-size:9.5px;color:var(--ink-light)}
.pj-acts{display:flex;gap:4px;flex-wrap:wrap}
.pj-rename{width:100%;font-family:var(--zh);font-size:12px;font-weight:600;border:1px solid var(--accent);border-radius:2px;background:var(--paper-2);padding:2px 4px}
.pj-snaps{border-top:1px dashed var(--rule-2);padding-top:6px;display:flex;flex-direction:column;gap:4px}
.pj-snap{display:flex;align-items:center;gap:6px;font-family:var(--mono);font-size:9.5px;color:var(--ink-mid)}
.pj-sname{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}
.pj-sdate{color:var(--ink-light)}
.pj-snone{font-family:var(--mono);font-size:9.5px;color:var(--ink-light)}
.pj-empty{grid-column:1/-1;font-family:var(--mono);font-size:10px;color:var(--ink-mid);line-height:1.8;padding:20px}
.exovnote{font-family:var(--mono);font-size:9.5px;color:var(--accent-text);margin:-4px 0 8px;min-height:0}

#layers{max-height:320px;overflow-y:auto;display:flex;flex-direction:column;gap:3px;margin-top:2px}
.lyr{position:relative;display:flex;align-items:center;gap:8px;padding:4px 5px;border:1px solid transparent;border-radius:3px;cursor:pointer;transition:.12s}
.lyr:hover{background:var(--paper-2)}
.lyr.sel{background:var(--paper-2);border-color:var(--accent)}
.lyr .ic{width:30px;height:23px;flex:none;background:var(--paper-2);border:1px solid var(--rule);border-radius:2px;display:flex;align-items:center;justify-content:center;overflow:hidden}
.lyr.sel .ic{background:var(--paper)}
.lyr .ic svg{width:26px;height:19px;display:block}
.lyr .nm{flex:1;min-width:0;font-size:10.5px;color:var(--ink-mid);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.25}
.lyr .nm small{font-family:var(--mono);font-size:9px;color:var(--ink-light);letter-spacing:.04em;display:block}
.lyr-ghead{display:flex;align-items:center;gap:7px;padding:6px 5px 5px;margin-top:8px;cursor:pointer;border-bottom:1px solid var(--rule);user-select:none;transition:.12s}
.lyr-ghead:first-child{margin-top:2px}
.lyr-ghead .lg-eye{display:inline-flex;align-items:center;width:14px;color:var(--ink-light);flex:none}
.lyr-ghead .lg-nm{flex:1;font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink);font-weight:600}
.lyr-ghead .lg-nm small{font-family:var(--mono);font-size:9px;color:var(--ink-light);letter-spacing:.05em;margin-left:5px;text-transform:none}
.lyr-ghead .lg-ct{font-family:var(--mono);font-size:9.5px;color:var(--ink-light);flex:none}
.lyr-ghead .lg-cats{display:flex;gap:3px;flex:none;margin-right:1px}
.lyr-ghead .lcat{font-family:var(--zh);font-size:10px;line-height:1;padding:2px 4px;border:1px solid var(--rule);border-radius:3px;color:var(--ink-mid);cursor:pointer;transition:.12s;user-select:none}
.lyr-ghead .lcat:hover{border-color:var(--accent);color:var(--accent)}
.lyr-ghead .lcat.off{opacity:.32;text-decoration:line-through}
.lyr-ghead.off{opacity:.4}
.lyr-ghead:hover .lg-eye,.lyr-ghead:hover .lg-nm{color:var(--ink)}
.lyr .act{position:absolute;right:3px;top:0;bottom:0;display:flex;align-items:center;gap:1px;opacity:0;pointer-events:none;transition:opacity .12s;padding-left:26px;background:linear-gradient(to right,transparent,var(--paper-2) 40%)}
.lyr:hover .act,.lyr.sel .act{opacity:1;pointer-events:auto}
.lyr .ab{width:19px;height:19px;border:none;background:transparent;color:var(--ink-light);cursor:pointer;border-radius:2px;display:flex;align-items:center;justify-content:center;padding:0}
.lyr .ab:hover{background:var(--paper-3);color:var(--ink)}
.lyr .ab.del:hover{color:var(--accent-2)}
.lyr.ly-hidden .ic,.lyr.ly-hidden .nm{opacity:.4}
.lyr .ab.on,.lyr .ab.on:hover{color:var(--accent)}
.lyr .nlock{display:inline-flex;vertical-align:-1px;color:var(--accent);margin-right:3px}
.lyr .nlock svg{width:9px;height:9px}
.lyr-rename{width:100%;font-family:var(--zh);font-size:11px;color:var(--ink);background:var(--paper);border:1px solid var(--accent);border-radius:3px;padding:2px 5px;outline:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 18%,transparent)}
.lyr{cursor:grab}
.lyr.dragging{opacity:.4}
.lyr.drop-before::after,.lyr.drop-after::after{content:"";position:absolute;left:2px;right:2px;height:2px;background:var(--accent);border-radius:2px;z-index:3;pointer-events:none}
.lyr.drop-before::after{top:-1px}
.lyr.drop-after::after{bottom:-1px}
.item.locked{cursor:default}
.insp-name-wrap{margin-bottom:13px;padding-bottom:12px;border-bottom:1px solid var(--rule-2)}
.insp-name{display:block;width:100%;font-family:var(--disp);font-size:15px;font-weight:700;color:var(--ink);background:transparent;border:1px solid transparent;border-radius:4px;padding:4px 7px;outline:none;transition:.12s}
.insp-name:hover{border-color:var(--rule)}
.insp-name:focus{border-color:var(--accent);background:var(--paper);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 16%,transparent)}
.insp-name::placeholder{color:var(--ink-light);font-weight:400}
.insp-name-sub{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;color:var(--ink-light);margin-top:5px;padding-left:8px}
.lyr-empty{font-size:10px;color:var(--ink-light);padding:6px 4px;line-height:1.6;font-weight:300}
::-webkit-scrollbar{width:9px;height:9px}::-webkit-scrollbar-thumb{background:var(--rule);border-radius:5px}::-webkit-scrollbar-track{background:transparent}
/* modal (PNG background choice) */
.modal-bg{position:fixed;inset:0;z-index:100;background:color-mix(in srgb,var(--ink) 40%,transparent);display:flex;align-items:center;justify-content:center;animation:mfade .14s ease both}
@keyframes mfade{from{opacity:0}to{opacity:1}}
.modal{background:var(--paper);border:1px solid var(--rule);border-radius:7px;box-shadow:0 26px 64px -22px rgba(21,18,12,.55);width:344px;max-width:calc(100vw - 40px);padding:22px;animation:mpop .18s cubic-bezier(.2,.8,.3,1) both}
@keyframes mpop{from{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}
.modal h3{font-family:var(--disp);font-size:16px;font-weight:700;margin-bottom:4px}
.modal p{font-family:var(--mono);font-size:10px;color:var(--ink-light);line-height:1.6;letter-spacing:.02em;margin-bottom:16px}
.modal .opts{display:flex;flex-direction:column;gap:8px}
.modal .mseg{display:flex;border:1px solid var(--rule);border-radius:5px;overflow:hidden;margin-bottom:13px}
.modal .mseg button{flex:1;font-family:var(--mono);font-size:11px;color:var(--ink-light);background:var(--paper-2);border:none;border-right:1px solid var(--rule);padding:8px 0;cursor:pointer;transition:.12s;letter-spacing:.02em}
.modal .mseg button:last-child{border-right:none}
.modal .mseg button:hover{color:var(--ink);background:var(--paper)}
.modal .mseg button.on{background:var(--accent);color:#fff}
.modal .opt{display:flex;align-items:center;gap:12px;text-align:left;border:1px solid var(--rule);background:var(--paper-2);border-radius:5px;padding:11px 12px;cursor:pointer;transition:.13s;font-family:var(--zh);color:var(--ink)}
.modal .opt:hover{border-color:var(--accent);background:var(--paper)}
.modal .opt:focus-visible{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px var(--paper),0 0 0 3px var(--accent)}
.modal .opt .sw{width:28px;height:28px;flex:none;border-radius:5px;border:1px solid var(--rule)}
.modal .opt .tt{font-size:12.5px;font-weight:500}
.modal .opt .tt small{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;color:var(--ink-light);text-transform:uppercase;margin-top:2px;font-weight:400}
.modal .mcancel{margin-top:14px;width:100%;font-family:var(--mono);font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-light);background:transparent;border:none;padding:7px;cursor:pointer;transition:.12s}
.modal .mcancel:hover{color:var(--ink)}
/* unified export modal (PNG / SVG / PDF tabs) */
.modal.exportm{width:380px}
.extabs{display:flex;gap:4px;background:var(--paper-2);border:1px solid var(--rule);border-radius:6px;padding:3px;margin:14px 0 16px}
.extabs button{flex:1;font-family:var(--mono);font-size:10px;letter-spacing:.08em;color:var(--ink-mid);background:transparent;border:none;border-radius:4px;padding:7px 0;cursor:pointer;transition:.12s}
.extabs button:hover{color:var(--ink)}
.extabs button.on{background:var(--accent);color:var(--paper)}
.expanel[hidden]{display:none}
.exrow{margin-bottom:13px}
.exl{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-light);margin-bottom:7px}
.exread{font-family:var(--mono);font-size:10px;color:var(--ink-mid);background:var(--paper-2);border:1px dashed var(--rule);border-radius:5px;padding:8px 10px}
.exread b{color:var(--ink);font-weight:500}
.extg{display:flex;align-items:center;justify-content:space-between;gap:10px;background:var(--paper-2);border:1px solid var(--rule);border-radius:5px;padding:9px 11px;margin-bottom:11px;cursor:pointer}
.extg .extg-t{font-family:var(--zh);font-size:12px;color:var(--ink)}
.extg .extg-t small{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;color:var(--ink-light);margin-top:2px}
.extg input{width:16px;height:16px;accent-color:var(--accent);flex:none;cursor:pointer}
.exnote{font-family:var(--mono);font-size:9.5px;line-height:1.6;letter-spacing:.02em;color:var(--ink-light);margin-bottom:13px}
.exsel{width:100%;font-family:var(--zh);font-size:12px;color:var(--ink);background-color:var(--paper-2);border:1px solid var(--rule);border-radius:5px;padding:9px 30px 9px 11px;cursor:pointer;-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23999' stroke-width='1.4'/></svg>");background-repeat:no-repeat;background-position:right 11px center;transition:.12s}
.exsel:focus{outline:none;border-color:var(--accent);background-color:var(--paper)}
.modal .mseg.dis{opacity:.4;pointer-events:none}
.exdl{width:100%;font-family:var(--zh);font-size:12.5px;font-weight:500;color:var(--paper);background:var(--ink);border:none;border-radius:5px;padding:11px;cursor:pointer;transition:.12s}
.exdl:hover{background:var(--accent)}
.exdl:disabled,.exdl.busy{opacity:.6;cursor:progress;background:var(--ink)}
/* 線路統計 Cable Schedule 彙總表 */
.wstable{width:100%;border-collapse:collapse;margin:2px 0 12px;font-family:var(--zh);font-size:12.5px;color:var(--ink)}
.wstable th{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;color:var(--ink-light);text-align:left;font-weight:600;padding:6px 8px;border-bottom:1px solid var(--rule)}
.wstable td{padding:8px;border-bottom:1px solid var(--rule-2)}
.wstable th:nth-child(n+2),.wstable td:nth-child(n+2){text-align:right;font-family:var(--mono);font-size:11.5px}
.wstable tfoot td{border-top:2px solid var(--ink);border-bottom:none;font-weight:600}
.wstable tr.wsrow{cursor:pointer}
.wstable tr.wsrow:hover td{background:var(--paper-2)}
.wstable tr.wsrow .car{display:inline-block;width:11px;color:var(--ink-light);font-size:9px}
.wstable tr.wsdetail td{background:var(--paper-2);font-family:var(--mono);font-size:10px;color:var(--ink-mid);padding:6px 8px 8px 27px;text-align:left;border-bottom:1px solid var(--rule-2)}
.wstable tr.wssec td{font-family:var(--mono);font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:var(--accent-text);font-weight:600;text-align:left;padding:12px 8px 5px;border-bottom:1px solid var(--rule);background:transparent}  /* 物件統計：採買品項/示意參考 分區列 */
.modal.kbd{width:880px}
.kbd-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
.kbd-head h3{margin:0}
.kbd-x{font-family:var(--mono);font-size:12px;color:var(--ink-light);background:transparent;border:1px solid var(--rule);border-radius:3px;width:26px;height:26px;cursor:pointer;transition:.12s;line-height:1;flex:none}
.kbd-x:hover{color:var(--ink);border-color:var(--ink-mid)}
.kbd-grid{column-count:3;column-gap:30px}
.kbd-sec{margin-bottom:11px;break-inside:avoid;-webkit-column-break-inside:avoid}
.kbd-seclabel{font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin:6px 0 5px;padding-bottom:4px;border-bottom:1px solid var(--rule-2)}
.kbd-row{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:3.5px 0}
.kbd-desc{font-family:var(--zh);font-size:11.5px;color:var(--ink);line-height:1.3}
.kbd-keys{display:flex;align-items:center;gap:3px;flex:none;white-space:nowrap}
.kbd-keys i{font-style:normal;font-family:var(--mono);font-size:9px;color:var(--ink-light);margin:0 2px;text-transform:uppercase;letter-spacing:.05em}
.modal.kbd kbd{font-family:var(--mono);font-size:10px;color:var(--ink);background:var(--paper-2);border:1px solid var(--rule);border-bottom-width:2px;border-radius:4px;padding:2px 6px;min-width:17px;text-align:center;line-height:1.45;display:inline-block}
.kbd-keys .pill{font-family:var(--zh);font-size:10px;color:var(--ink-mid);background:transparent;border:1px dashed color-mix(in srgb,var(--accent) 45%,var(--rule));border-radius:10px;padding:2px 9px;line-height:1.4}
.kbd-foot{margin-top:14px;text-align:center;font-family:var(--mono);font-size:9.5px;letter-spacing:.05em;color:var(--ink-light);text-transform:uppercase}
.kbd-foot kbd{font-family:var(--mono);font-size:9.5px;padding:1px 5px;border:1px solid var(--rule);border-radius:3px;background:var(--paper-2)}
@media(max-width:840px){.kbd-grid{column-count:2}}
@media(max-width:540px){.kbd-grid{column-count:1}}
/* image crop dialog (Slides-style) */
.modal.cropm{width:auto;padding:20px}
.crop-stage{position:relative;margin:2px auto 0;border:1px solid var(--rule);border-radius:3px;touch-action:none;user-select:none;-webkit-user-select:none;
  background-image:linear-gradient(45deg,color-mix(in srgb,var(--ink) 8%,transparent) 25%,transparent 25%,transparent 75%,color-mix(in srgb,var(--ink) 8%,transparent) 75%),linear-gradient(45deg,color-mix(in srgb,var(--ink) 8%,transparent) 25%,transparent 25%,transparent 75%,color-mix(in srgb,var(--ink) 8%,transparent) 75%);
  background-size:16px 16px;background-position:0 0,8px 8px;overflow:visible}
.crop-stage .cs-art{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none}
.crop-stage .cs-dim{position:absolute;background:color-mix(in srgb,var(--ink) 34%,transparent);pointer-events:none}
.crop-rect{position:absolute;box-sizing:border-box;cursor:move;outline:1px solid rgba(255,255,255,.92);box-shadow:0 0 0 1.5px var(--accent),0 0 10px -2px rgba(21,18,12,.4)}
.crop-rect .cgrid{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(rgba(255,255,255,.4),rgba(255,255,255,.4)) calc(100%/3) 0/1px 100% no-repeat,
   linear-gradient(rgba(255,255,255,.4),rgba(255,255,255,.4)) calc(200%/3) 0/1px 100% no-repeat,
   linear-gradient(rgba(255,255,255,.4),rgba(255,255,255,.4)) 0 calc(100%/3)/100% 1px no-repeat,
   linear-gradient(rgba(255,255,255,.4),rgba(255,255,255,.4)) 0 calc(200%/3)/100% 1px no-repeat}
.crop-rect .ch{position:absolute;width:14px;height:14px;box-sizing:border-box;background:#fff;border:1.5px solid var(--accent);border-radius:2px;z-index:2;box-shadow:0 1px 3px -1px rgba(21,18,12,.5)}
.crop-rect .ch.nw{left:-7px;top:-7px;cursor:nwse-resize}.crop-rect .ch.ne{right:-7px;top:-7px;cursor:nesw-resize}
.crop-rect .ch.se{right:-7px;bottom:-7px;cursor:nwse-resize}.crop-rect .ch.sw{left:-7px;bottom:-7px;cursor:nesw-resize}
.crop-rect .ch.n{left:50%;top:-7px;margin-left:-7px;cursor:ns-resize}.crop-rect .ch.s{left:50%;bottom:-7px;margin-left:-7px;cursor:ns-resize}
.crop-rect .ch.w{left:-7px;top:50%;margin-top:-7px;cursor:ew-resize}.crop-rect .ch.e{right:-7px;top:50%;margin-top:-7px;cursor:ew-resize}
.crop-readout{font-family:var(--mono);font-size:10px;color:var(--ink-light);letter-spacing:.04em;margin-top:13px;text-align:center}
.crop-foot{display:flex;align-items:center;gap:8px;margin-top:13px}
.crop-foot .cbtn{font-family:var(--mono);font-size:10px;letter-spacing:.04em;padding:8px 15px;border-radius:5px;border:1px solid var(--rule);background:var(--paper-2);color:var(--ink-light);cursor:pointer;transition:.12s}
.crop-foot .cbtn:hover{color:var(--ink);background:var(--paper);border-color:var(--accent)}
.crop-foot .cbtn.reset{margin-right:auto}
.crop-foot .cbtn.apply{background:var(--accent);color:#fff;border-color:var(--accent)}
.crop-foot .cbtn.apply:hover{filter:brightness(1.07)}
/* ==== 動效打磨 Motion polish ====
   ddpop：選單「從觸發點長出來」——起點貼近 trigger（-4px）、縮放由 transform-origin 決定；
   舊 mpop 從下方 +8px 往上飄，方向與選單錨定位置相反，僅保留給置中 modal 使用。 */
@keyframes ddpop{from{opacity:0;transform:translateY(-4px) scale(.97)}to{opacity:1;transform:none}}
/* 專案庫對話框：補上與 opdlg 一致的進場（原本瞬間出現，突兀）；scrim 同步淡入 */
.pjdlg{animation:oppop .17s cubic-bezier(.2,.85,.3,1) both}
.pjscrim{animation:opfade .14s ease both}
/* 環境浮窗：120ms 純 opacity 微淡入——高頻工具窗不做位移，只消除硬切 */
.envdlg{animation:opfade .12s ease both}
/* Tab 鍵開啟元件面板 = 高頻鍵盤操作 → 不播進場動畫（滑鼠點按鈕開啟仍有動畫） */
.opdlg.instant,.opscrim.instant{animation:none}
/* 按壓回饋：所有可按元素 :active 輕縮（0.95–0.98），讓介面「聽得到」點按；
   transition 沿用各元素既有的 .12–.15s 縮寫（在 100–160ms 回饋預算內） */
.tbtn:not(:disabled):active,.mm-item:not(:disabled):active,.optab:active,.ptab:active,
.modal .opt:active,.modal .mseg button:active,.seg button:active,.ddc-seg button:active,
.exdl:active,.full:active,.pj-new:active,.crop-foot .cbtn:active{transform:scale(.97)}
.pitem:active{transform:scale(.985)}
.op-x:active,.pj-x:active,.envdlg-x:active,.kbd-x:active{transform:scale(.92)}
.dot:active{transform:scale(1.05)}
.swatches .sw:active{transform:scale(1.03)}
/* 鍵盤焦點：所有按鈕統一品牌 focus ring（滑鼠點按不觸發;.modal .opt 已有自訂樣式、特異度較高不受影響） */
button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* 輕量 toast：非阻斷回饋。transition（非 keyframes）→ 快速連發時可中斷重定向;退場比進場快 */
#toasts{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);z-index:300;display:flex;flex-direction:column;align-items:center;gap:8px;pointer-events:none}
.toast{pointer-events:auto;max-width:min(480px,86vw);font-family:var(--zh);font-size:12px;line-height:1.5;color:var(--ink);background:var(--paper);border:1px solid var(--rule);border-left:3px solid var(--ink-mid);border-radius:7px;padding:9px 14px;box-shadow:0 14px 38px -14px rgba(21,18,12,.5);cursor:pointer;opacity:0;transform:translateY(8px);transition:opacity .18s cubic-bezier(.23,1,.32,1),transform .18s cubic-bezier(.23,1,.32,1)}
.toast.in{opacity:1;transform:none}
.toast.out{opacity:0;transform:translateY(6px);transition-duration:.14s}
.toast.ok{border-left-color:#2C6E49}
.toast.err{border-left-color:var(--accent-2)}
/* 減少動態偏好：保留 opacity 淡入（助理解）、移除位移與縮放（防暈眩）。
   注意：只列 UI class，絕不落在畫布 SVG 元素上（其 transform 承載座標）。 */
@media (prefers-reduced-motion:reduce){
  .moremenu,.dd-menu,.ctxmenu,.modal,.opdlg,.pjdlg{animation:opfade .12s ease both}
  .tbtn:active,.mm-item:active,.optab:active,.ptab:active,
  .modal .opt:active,.modal .mseg button:active,.seg button:active,.ddc-seg button:active,
  .exdl:active,.full:active,.pj-new:active,.crop-foot .cbtn:active,.pitem:active,
  .op-x:active,.pj-x:active,.envdlg-x:active,.kbd-x:active,.dot:active,.swatches .sw:active{transform:none}
  .dot:hover,.swatches .sw:hover{transform:none}
  .toast,.toast.out{transform:translateX(0) translateY(0)}
  body{transition:none}
}
