/* ========== 无限画布 ========== */
.canvas-module{position:relative;height:calc(100vh - 140px)}
.canvas-toolbar{display:flex;align-items:center;gap:12px;padding:10px 16px;margin-bottom:8px;background:#1a1a2e;border-radius:12px;border:1px solid #2a2a4a}
.canvas-toolbar-title{font-size:15px;font-weight:600;color:#fff}
.canvas-toolbar-hint{font-size:12px;color:#666;flex:1}
.canvas-toolbar-btn{font-size:12px}
.canvas-viewport{position:relative;width:100%;height:calc(100% - 56px);overflow:hidden;background:#0a0a14;border-radius:16px;border:1px solid #2a2a4a;cursor:grab}
.canvas-viewport:active{cursor:grabbing}
.canvas-world{position:absolute;left:0;top:0;transform-origin:0 0}
/* SVG连线层：在viewport内、world外，不受pan/zoom影响 */
.canvas-svg{position:absolute;left:0;top:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:10}
.canvas-svg path{pointer-events:none}
.canvas-svg path.hit-area{pointer-events:stroke;cursor:pointer}
.canvas-svg g{pointer-events:all}
/* 临时拖拽线 */
.canvas-svg .temp-line{stroke:#6366f1;stroke-width:2;fill:none;stroke-dasharray:6 3;pointer-events:none}
/* 右键菜单 */
.canvas-ctx-menu{position:fixed;z-index:3000;background:#1a1a2e;border:1px solid #3a3a5a;border-radius:12px;padding:6px 0;min-width:160px;box-shadow:0 8px 32px rgba(0,0,0,.6)}
.ctx-item{padding:10px 18px;font-size:13px;color:#ccc;cursor:pointer;transition:all .15s}
.ctx-item:hover{background:rgba(99,102,241,.15);color:#a5b4fc}
.ctx-sep{height:1px;background:#2a2a4a;margin:4px 0}
/* 节点通用 */
.canvas-node{position:absolute;width:280px;background:#1a1a2e;border:1px solid #2a2a4a;border-radius:14px;z-index:2;box-shadow:0 4px 16px rgba(0,0,0,.3);transition:box-shadow .2s,border-color .2s;user-select:none}
.canvas-node:hover{border-color:#3a3a5a;box-shadow:0 6px 24px rgba(0,0,0,.4)}
.canvas-node.selected{border-color:#6366f1;box-shadow:0 0 0 2px rgba(99,102,241,.3)}
.node-header{display:flex;align-items:center;gap:8px;padding:10px 14px;cursor:move;border-bottom:1px solid #2a2a4a;border-radius:14px 14px 0 0;background:rgba(255,255,255,.02);user-select:none}
.node-icon{font-size:16px}
.node-title{flex:1;font-size:13px;font-weight:600;color:#fff}
.node-delete{background:none;border:none;color:#555;font-size:18px;cursor:pointer;padding:0 4px;line-height:1}
.node-delete:hover{color:#ef4444}
.node-body{padding:12px 14px}
/* 素材节点 URL + 上传 */
.node-url-row{display:flex;gap:6px;margin-bottom:8px}
.node-url-row input{flex:1;background:#12121f;border:1px solid #2a2a4a;border-radius:8px;padding:6px 10px;color:#fff;font-size:12px;outline:none}
.node-url-row input:focus{border-color:#6366f1}
.node-url-row button{background:#2a2a4a;color:#aaa;border:1px solid #3a3a5a;padding:6px 12px;border-radius:8px;font-size:12px;cursor:pointer;white-space:nowrap}
.node-url-row button:hover{border-color:#6366f1;color:#6366f1}
.node-url-row button:disabled{opacity:.5;cursor:not-allowed}
/* 素材预览 */
.node-preview{border:2px dashed #2a2a4a;border-radius:10px;min-height:48px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;overflow:hidden}
.node-preview:hover{border-color:#6366f1}
.node-preview.has-media{border-style:solid;padding:6px;cursor:default}
.node-preview-hint{font-size:11px;color:#555}
.node-preview img{max-width:100%;max-height:80px;object-fit:contain;border-radius:4px}
.node-preview audio{width:100%;height:32px}
.node-preview video{width:100%;max-height:80px;border-radius:4px}
.canvas-video-placeholder{width:100%;height:80px;border-radius:6px;background:linear-gradient(135deg,#090912,#18182a);border:1px solid #2a2a4a;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;color:#c7d2fe;cursor:pointer;position:relative;overflow:hidden}
.canvas-video-placeholder:before{content:'';position:absolute;inset:0;background:radial-gradient(circle at 50% 45%,rgba(99,102,241,.25),transparent 55%);pointer-events:none}
.canvas-video-play{width:34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45);color:#fff;font-size:16px;z-index:1}
.canvas-video-label{font-size:11px;color:#aaa;z-index:1}
.canvas-is-panning .node-preview img{visibility:hidden}
.canvas-is-panning .canvas-video-placeholder{background:#0b0b15}
.canvas-is-panning .canvas-node{box-shadow:none}
/* 提示词节点 */
.node-textarea{width:100%;background:#12121f;border:1px solid #2a2a4a;border-radius:8px;padding:8px 10px;color:#fff;font-size:13px;min-height:60px;resize:vertical;outline:none;font-family:inherit}
.node-textarea:focus{border-color:#6366f1}
/* 端口 */
.node-port{width:14px;height:14px;border-radius:50%;background:#2a2a4a;border:2px solid #4a4a6a;cursor:crosshair;transition:all .15s;z-index:3}
.node-port:hover{background:#6366f1;border-color:#8b5cf6;transform:scale(1.3)}
.node-port-out{position:absolute;right:-7px;top:50%;margin-top:-7px}
.node-port-out:hover{transform:scale(1.3)}
/* 生成节点底部输出端口 */.node-port-in{position:absolute;left:-7px;top:50%;margin-top:-7px;flex-shrink:0}
.node-port-in-left{position:absolute;left:-7px;top:50%;margin-top:-7px}
.node-port-in:hover{transform:scale(1.3)}
.node-input-ports{margin-bottom:10px;margin-left:-21px}
.node-port-row{position:relative;display:flex;align-items:center;gap:4px;padding:4px 0 4px 28px;font-size:12px;color:#888}
/* 生成节点参数 */
.gen-params{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:10px}
.gen-select{width:100%;background:#12121f;border:1px solid #2a2a4a;border-radius:8px;padding:5px 8px;color:#fff;font-size:11px;outline:none}
.gen-select:focus{border-color:#6366f1}
.gen-submit-btn{width:100%;padding:10px;font-size:13px;margin-bottom:8px}
.gen-result{margin-top:6px}
.gen-status{font-size:12px;font-weight:600;margin-bottom:4px}
.gen-status.pending{color:#999}
.gen-status.running{color:#f59e0b}
.gen-status.succeeded{color:#22c55e}
.gen-status.failed{color:#ef4444}
.gen-result video{background:#000;border-radius:8px;width:100%;max-height:200px}
.gen-result .task-error{margin-top:6px}

/* ========== 上传按钮 & 云端选择器 ========== */
.upload-local-btn,.upload-cloud-btn{padding:5px 12px;border-radius:8px;font-size:12px;cursor:pointer;border:1px solid;transition:all .2s}
.upload-local-btn{background:rgba(99,102,241,.1);border-color:rgba(99,102,241,.3);color:#a0a0c0}
.upload-local-btn:hover{background:rgba(99,102,241,.25);border-color:#6366f1;color:#e0e0ff}
.upload-cloud-btn{background:rgba(34,197,94,.1);border-color:rgba(34,197,94,.3);color:#86efac}
.upload-cloud-btn:hover{background:rgba(34,197,94,.25);border-color:#22c55e;color:#fff}
.upload-btn-row{display:flex;flex-direction:row;align-items:center;justify-content:center;gap:8px}
.node-preview.upload-btn-row{min-height:48px}
.cloud-picker-overlay{position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:2000;display:flex;align-items:center;justify-content:center}
.cloud-picker-inner{background:#12121f;border:1px solid #2a2a4a;border-radius:14px;width:680px;max-width:95vw;max-height:80vh;display:flex;flex-direction:column;overflow:hidden}
.cloud-picker-header{display:flex;align-items:center;justify-content:space-between;padding:14px 18px;border-bottom:1px solid #2a2a4a;flex-shrink:0}
.cloud-picker-header span{font-size:15px;font-weight:600;color:#e0e0ff}
.cloud-picker-header button{background:none;border:none;color:#a0a0c0;font-size:22px;cursor:pointer;line-height:1}
.cloud-picker-tabs{display:flex;gap:6px;padding:10px 18px;flex-shrink:0;border-bottom:1px solid #2a2a4a}
.res-tab{background:rgba(99,102,241,.1);border:1px solid rgba(99,102,241,.3);color:#a0a0c0;padding:4px 10px;border-radius:8px;font-size:12px;cursor:pointer;transition:all .2s}
.res-tab.active{background:rgba(99,102,241,.3);border-color:#6366f1;color:#e0e0ff}
.cloud-picker-grid{flex:1;overflow-y:auto;display:grid;grid-template-columns:repeat(5,1fr);gap:8px;padding:12px 18px;align-content:start}
.cloud-picker-item{aspect-ratio:1;border-radius:8px;overflow:hidden;background:#1a1a2e;border:2px solid transparent;transition:border-color .2s}
.cloud-picker-item:hover{border-color:#6366f1}
.cloud-picker-item img,.cloud-picker-item video{width:100%;height:100%;object-fit:cover;display:block}
.cloud-picker-pager{display:flex;align-items:center;justify-content:center;gap:10px;padding:10px 18px;border-top:1px solid #2a2a4a;flex-shrink:0;color:#888;font-size:12px;text-align:center;width:100%;box-sizing:border-box}
.cloud-picker-pager button{background:rgba(99,102,241,.12);border:1px solid rgba(99,102,241,.3);color:#a5b4fc;padding:4px 12px;border-radius:8px;font-size:12px;cursor:pointer}
.cloud-picker-pager button:disabled{opacity:.35;cursor:default}
.cloud-picker-pager button:not(:disabled):hover{background:rgba(99,102,241,.28)}
