Files
story-edit-web/web/static/style.css
邓雨鹏 021080dd56 feat(timeline): P2 并行编排——scene 多轨编辑器 + 白模重叠预览
剧情 Timeline P2 前端 + 共享内核(与 SGame 源真同步):
- ir_core/IR_SCHEMA/样张:scene v0.3 + scene 校验 + 导出 gate(D3),与 SGame 仓逐字一致
- timeline.js:appendScene 按 authored start 铺多轨 clip(自然重叠预览),move from 同 actor 跨轨续连(D4);
  drawStage 改逐 actor 查对话→多人气泡同时计时;导出 _clipDur 纯函数;show() 加 startId 参;常量加 CAMERA_DUR
- scene_edit.js(新):演出段编辑模态——拖 clip 改 start(吸附 0.1s)、拖右缘改 dur、增删 clip/轨道、
  选中属性条精确编辑、客户端轻量 lint(镜像 validate.py)、▶ 预览此段(复用播放核)
- graph.js:scene 节点(KIND_CN/summary/nodeInner 列轨道)+双击进编辑模态
- form.js:右栏 renderScene 精确数值编辑(轨道/clip 的 start/dur/kind/目标)+打开编辑器按钮
- app.py export:捕获 CompileError 并入 report(scene 被拦时不再 500)
- test_scene.js:离线 10 断言全过(重叠确凿/晚 1.5s 起步/from 续连);gitignore 忽略本地 _localdemo.db

待浏览器目测拖拽编辑落 IR + 白模重叠演出。
2026-06-13 22:34:29 +08:00

387 lines
25 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

* { box-sizing: border-box; }
body { margin:0; font-family:"Microsoft YaHei","PingFang SC",sans-serif;
background:#161310; color:#e8e0d4; height:100vh; overflow:hidden;
display:flex; flex-direction:column; }
/* ---- header / toolbar ---- */
header { padding:10px 18px; background:#1f1a15; border-bottom:1px solid #3a322a;
display:flex; align-items:center; gap:18px; flex:none; }
header h1 { margin:0; font-size:18px; color:#e6c878; white-space:nowrap; }
header h1 .ver { font-size:12px; color:#9a8f7e; }
.toolbar { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.toolbar .sep { width:1px; height:20px; background:#3a322a; margin:0 4px; }
.toolbar .who { margin-left:10px; font-size:12px; color:#9a8f7e; }
button { background:#3a3024; color:#e6c878; border:1px solid #5a4a32;
padding:6px 13px; border-radius:5px; cursor:pointer; font-size:13px; }
button:hover:not(:disabled) { background:#4a3d2c; }
button:disabled { opacity:.4; cursor:not-allowed; }
button.primary { background:#5a4a26; border-color:#8a7038; color:#f3dca0; }
button.mini { padding:2px 8px; font-size:12px; }
/* ---- layout ---- */
#wrap { display:flex; flex:1; min-height:0; }
#list-pane { width:250px; background:#19150f; border-right:1px solid #3a322a;
display:flex; flex-direction:column; flex:none; }
.filters { padding:10px; display:flex; gap:6px; border-bottom:1px solid #3a322a; }
.filters select, .filters input, #login input, #import-text {
background:#241f18; color:#e8e0d4; border:1px solid #4a4030; border-radius:4px;
padding:6px 8px; font-size:13px; }
.filters select { flex:none; }
.filters input { flex:1; min-width:0; }
#event-list { overflow:auto; flex:1; }
.ev { padding:9px 12px; border-bottom:1px solid #241f18; cursor:pointer; }
.ev:hover { background:#221d16; }
.ev.sel { background:#2a2316; border-left:3px solid #e6c878; padding-left:9px; }
.ev .t { font-size:13.5px; color:#ddd3c2; }
.ev .g { font-size:11px; color:#7a7264; margin-top:2px; }
.ev .badge { float:right; font-size:11px; padding:1px 7px; border-radius:9px; }
.b-pending { background:#3a3320; color:#d8c060; }
.b-confirmed{ background:#1f3a24; color:#7ad88a; }
.b-discarded{ background:#3a2020; color:#d88; }
#graph-pane { flex:1; min-width:0; display:flex; flex-direction:column; position:relative; }
#graph-tools { flex:none; display:flex; align-items:center; gap:8px; padding:6px 10px;
background:#19150f; border-bottom:1px solid #3a322a; }
#graph-tools .tip { font-size:11.5px; color:#7a7264; }
#graph-tools .gsep { width:1px; height:16px; background:#3a322a; margin:0 3px; }
#drawflow { position:relative; flex:1; min-height:0; background:#161310;
background-image:radial-gradient(#2a2419 1.1px, transparent 1.1px);
background-size:22px 22px; }
.empty-center { position:absolute; inset:0; display:flex; align-items:center;
justify-content:center; color:#6a6256; font-size:15px; pointer-events:none; }
#edit-pane { width:370px; background:#1c1813; border-left:1px solid #3a322a;
overflow:auto; flex:none; }
.sec-title { padding:10px 14px; font-size:13px; color:#9a8f7e;
border-bottom:1px solid #3a322a; background:#19150f; letter-spacing:1px;
display:flex; justify-content:space-between; align-items:center; }
#meta-edit, #node-edit { padding:12px 14px; }
.empty { color:#6a6256; font-size:13px; padding:8px 0; }
/* ---- nodes (tree) ---- */
.node { background:#262019; border:1.5px solid #4a4030; border-radius:9px;
padding:9px 12px; width:188px; cursor:pointer; transition:.15s;
box-shadow:0 2px 6px rgba(0,0,0,.4); position:absolute; }
.node:hover { border-color:#e6c878; transform:translateY(-2px); }
.node.sel { border-color:#e6c878; box-shadow:0 0 0 2px rgba(230,200,120,.4); z-index:20; }
.node-acts { position:absolute; display:flex; gap:4px; z-index:30; transform:translateX(-100%); }
.nact { border:none; border-radius:5px; font-size:11px; line-height:1; padding:4px 6px;
cursor:pointer; color:#161310; font-weight:bold; box-shadow:0 1px 3px rgba(0,0,0,.5); }
.nact.add { background:#e6c878; }
.nact.add:hover { background:#f0d68a; }
.nact.del { background:#d87878; color:#fff; }
.nact.del:hover { background:#e89090; }
.node .k { font-size:11px; color:#b89a5a; font-weight:bold; }
.node .t { font-size:13px; margin-top:3px; line-height:1.4; color:#ddd3c2; }
.node.kind-ending { background:#3a2a17; border-color:#e0a850; }
.node.kind-ending .k { color:#f2c463; }
.node.kind-ending .rw { font-size:11.5px; color:#c9a86a; margin-top:4px;
border-top:1px dashed #6a5630; padding-top:4px; }
.node.kind-fight { border-color:#7a4a4a; background:#2a1c1c; }
.node.kind-fight .k { color:#d87878; }
.node.kind-out_ref { border-style:dashed; border-color:#7a7ad8; background:#1d1d2a; }
.node.kind-out_ref .k { color:#9e9ef0; }
.node.kind-choice, .node.kind-choice_once {
background:#1d2840; border:none; padding-left:26px; padding-right:26px;
clip-path: polygon(16px 0, calc(100% - 16px) 0, 100% 50%, calc(100% - 16px) 100%, 16px 100%, 0 50%); }
.node.kind-choice .k, .node.kind-choice_once .k { color:#9ec0f0; }
/* ---- Drawflow 节点(拖拽连线版) ---- */
#drawflow .drawflow-node { background:#262019; border:1.5px solid #4a4030; border-radius:9px;
padding:8px 12px; width:192px; color:#e8e0d4; box-shadow:0 2px 6px rgba(0,0,0,.4); }
#drawflow .drawflow-node:hover { border-color:#e6c878; }
#drawflow .drawflow-node.selected { border-color:#e6c878; box-shadow:0 0 0 2px rgba(230,200,120,.45); }
#drawflow .drawflow_content_node { width:100%; }
/* 顶边框标牌legend边框在文字处断开 */
#drawflow .drawflow_content_node { position:relative; }
.drawflow-node .nlabel { position:absolute; top:-18px; left:50%; transform:translateX(-50%);
background:#161310; padding:0 7px; font-size:11.5px; font-weight:bold; white-space:nowrap; color:#b89a5a; }
.drawflow-node .nbody { padding-top:3px; }
.drawflow-node .who { font-size:11px; color:#b89a5a; margin-bottom:2px; }
.drawflow-node .t { font-size:12.5px; line-height:1.35; color:#ddd3c2; word-break:break-all; }
.drawflow-node .rw { font-size:11px; color:#c9a86a; margin-top:4px;
border-top:1px dashed #6a5630; padding-top:4px; }
#drawflow .kind-ending { background:#3a2a17; border-color:#e0a850; }
#drawflow .kind-ending .nlabel { color:#f2c463; }
#drawflow .kind-fight { border-color:#7a4a4a; background:#2a1c1c; }
#drawflow .kind-fight .nlabel { color:#d87878; }
#drawflow .kind-out_ref { border-style:dashed; border-color:#7a7ad8; background:#1d1d2a; }
#drawflow .kind-out_ref .nlabel { color:#9e9ef0; }
#drawflow .kind-choice, #drawflow .kind-choice_once { background:#1d2840; border-color:#3a527a; }
#drawflow .kind-choice .nlabel, #drawflow .kind-choice_once .nlabel { color:#9ec0f0; }
#drawflow .kind-random .nlabel { color:#c0a0e0; }
/* 端口圆点 */
#drawflow .drawflow-node .input, #drawflow .drawflow-node .output {
background:#e6c878; border:2px solid #161310; width:15px; height:15px; }
#drawflow .drawflow-node .input:hover, #drawflow .drawflow-node .output:hover { background:#f0d68a; }
/* 输出端口纵向行距=选项行距:默认是普通块流,相邻端口 margin-bottom/margin-top 会“外边距折叠”→行距仍是 20px
与 .ch-opt 的 25px 错位(越往下越偏)。把 .outputs 改成 flex 纵向列flex 项目外边距不折叠),
再给每个端口 margin:5px 0 → 端口格子 5+15+5=25px、圆点居中与各选项行逐行平齐任意选项数通用。 */
#drawflow .drawflow-node .outputs { display:flex; flex-direction:column; }
#drawflow .drawflow-node .output { margin:5px 0; }
/* 连线 */
#drawflow .connection .main-path { stroke:#7a96c8; stroke-width:2.4px; }
#drawflow .connection .main-path:hover { stroke:#e6c878; }
/* 开头节点标识 */
#drawflow .drawflow-node.isstart { border-color:#7ad88a; }
.drawflow-node .startflag { color:#7ad88a; font-weight:bold; }
/* 多出口节点每出口一行唯一流内容→垂直居中→与居中黄点逐行平齐top:2px 对齐端口偏移 */
.ch-opts { position:relative; top:2px; }
.ch-opt { height:25px; line-height:25px; text-align:right; font-size:12px; color:#dfe7f2;
overflow:hidden; text-overflow:ellipsis; white-space:nowrap; padding-right:3px; }
/* 战斗节点:左右两栏——左栏战斗描述(填满左侧大空间、可换行、垂直居中),右栏胜/败出口行 */
.drawflow-node .fbody { display:flex; align-items:flex-end; gap:10px; }
.drawflow-node .fbody .fdesc { flex:1; min-width:0; align-self:center; font-size:12px;
color:#e6b8a0; line-height:1.45; text-align:left; word-break:break-all; }
.drawflow-node .fbody .ch-opts { flex:none; }
/* 描述使内容变高,故让胜/败两个黄点贴底部两行,与右栏出口行逐行对齐 */
#drawflow .kind-fight .outputs { align-self:stretch; justify-content:flex-end; }
/* ---- toast ---- */
#toast { position:fixed; left:50%; bottom:38px; transform:translateX(-50%) translateY(10px);
background:#2a2316; color:#f3dca0; border:1px solid #6a5630; border-radius:7px;
padding:10px 18px; font-size:13.5px; box-shadow:0 4px 16px rgba(0,0,0,.5);
opacity:0; pointer-events:none; transition:.25s; z-index:9999; }
#toast.show { opacity:1; transform:translateX(-50%) translateY(0); }
/* ---- form ---- */
.fld { margin:9px 0; }
.fld > label { display:block; font-size:12px; color:#9a8f7e; margin-bottom:3px; }
.fld input, .fld select, .fld textarea {
width:100%; background:#241f18; color:#e8e0d4; border:1px solid #4a4030;
border-radius:4px; padding:6px 8px; font-size:13px; }
.fld textarea { min-height:60px; resize:vertical; font-family:inherit; }
.fld.inline { display:flex; gap:6px; align-items:center; }
.fld.inline > label { margin:0; flex:none; }
.subbox { border:1px solid #3a322a; border-radius:6px; padding:8px; margin:8px 0;
background:#19150f; }
.subbox .hd { display:flex; justify-content:space-between; align-items:center;
font-size:12px; color:#b89a5a; margin-bottom:6px; }
.row2 { display:flex; gap:6px; }
.row2 > * { flex:1; }
.tag-pick { display:flex; flex-wrap:wrap; gap:5px; }
.tag-pick label { font-size:12px; background:#241f18; border:1px solid #4a4030;
padding:3px 8px; border-radius:11px; cursor:pointer; }
.tag-pick input { margin-right:4px; }
.node-id { color:#7a7264; font-size:11px; }
.optdet { border:1px solid #3a322a; border-radius:6px; margin:6px 0; background:#19150f; }
.optdet > summary { cursor:pointer; padding:7px 10px; font-size:12.5px; color:#cdbf9a; user-select:none;
overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.optdet[open] > summary { border-bottom:1px solid #3a322a; color:#e6c878; margin-bottom:4px; }
.optbody { padding:0 10px 8px; }
/* ---- overlays / modals ---- */
.overlay { position:fixed; inset:0; background:rgba(0,0,0,.72); z-index:100;
display:flex; align-items:center; justify-content:center; }
.overlay.hidden { display:none; }
.login-box, .modal { background:#221d16; border:1px solid #4a4030; border-radius:10px;
padding:24px; width:380px; box-shadow:0 8px 30px rgba(0,0,0,.6); }
.modal { width:520px; max-height:82vh; overflow:auto; }
.modal.wide { width:760px; }
.login-box h2, .modal h3 { margin:0 0 12px; color:#e6c878; }
.login-box .hint { color:#9a8f7e; font-size:13px; margin:0 0 14px; }
.login-box input { width:100%; margin-bottom:10px; }
.login-box button { width:100%; }
.err { color:#e08a7a; font-size:13px; margin-top:8px; min-height:18px; }
.modal textarea { width:100%; min-height:160px; background:#19150f; color:#e8e0d4;
border:1px solid #4a4030; border-radius:5px; padding:8px;
font-family:monospace; font-size:12px; }
.modal-actions { margin-top:10px; display:flex; gap:8px; }
.drop { border:1.5px dashed #4a4030; border-radius:8px; padding:22px 12px; text-align:center;
cursor:pointer; color:#bdb29c; transition:border-color .15s, background .15s; }
.drop:hover { border-color:#6a5d40; background:#1c1810; }
.drop.over { border-color:#e6c878; background:#241d10; color:#e6c878; }
.drop p { margin:0; }
.drop .hint { margin-top:6px; font-size:12px; color:#8a8068; }
.filelist { margin-top:8px; }
.fileitem { display:flex; align-items:center; gap:8px; padding:5px 8px; margin-top:5px;
background:#19150f; border:1px solid #3a3326; border-radius:5px; font-size:13px; }
.fileitem .fn { flex:1; color:#e8e0d4; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.fileitem .fsz { color:#8a8068; font-size:12px; }
.fileitem .rm { background:none; border:none; color:#e08a7a; cursor:pointer; font-size:13px; padding:0 4px; }
.import-paste { margin-top:10px; }
.import-paste summary { cursor:pointer; color:#bdb29c; font-size:13px; user-select:none; }
.import-paste textarea { margin-top:8px; min-height:110px; }
.v-err { color:#e08a7a; margin:4px 0; font-size:13px; }
.v-warn { color:#d8c060; margin:4px 0; font-size:13px; }
.v-ok { color:#7ad88a; font-size:14px; }
/* ---- playtest ---- */
#pt-layout { display:flex; gap:14px; }
#pt-flow { flex:1; max-height:62vh; overflow:auto; }
#pt-ledger { width:230px; flex:none; background:#19150f; border:1px solid #3a322a;
border-radius:6px; padding:10px; font-size:13px; align-self:flex-start; }
#pt-ledger h4 { margin:0 0 8px; color:#e6c878; font-size:13px; }
#pt-ledger .lg { margin:4px 0; }
.pt-step { background:#241f18; border-left:3px solid #4a4030; padding:7px 10px;
margin:7px 0; border-radius:4px; font-size:13px; }
.pt-step.spk { color:#cdddf0; }
.pt-step.sys { color:#9a8f7e; font-style:italic; }
.pt-step.end { border-left-color:#e0a850; color:#eccf95; }
.pt-choices button { display:block; width:100%; text-align:left; margin:5px 0; }
.pt-choices button.locked { opacity:.55; }
.pt-q { color:#b89a5a; font-size:12px; margin:8px 0 4px; }
/* ---- 模式切换 ---- */
.mode-switch { display:flex; gap:0; border:1px solid #5a4a32; border-radius:6px; overflow:hidden; }
.mode-btn { background:#241f18; color:#9a8f7e; border:none; border-radius:0; padding:6px 14px; }
.mode-btn:hover:not(:disabled) { background:#2e2820; }
.mode-btn.active { background:#5a4a26; color:#f3dca0; }
header .who { margin-left:auto; font-size:12px; color:#9a8f7e; }
/* ---- 模式背景区分:海选审核=暖棕(默认) / 演出配置=冷青绿 ---- */
body.perform-mode { background:#0c1513; }
body.perform-mode header { background:#10211c; border-bottom-color:#244a3e; }
body.perform-mode .mode-btn.active { background:#1f5040; border-color:#2f7a60; color:#aee6d0; }
body.perform-mode .mode-switch { border-color:#2f7a60; }
/* ---- 演出配置页 ---- */
#perform-wrap { display:flex; flex:1; min-height:0; background:#0c1513; }
#perform-wrap #perform-list-pane { background:#0e1c18; border-right-color:#1c3a30; }
#perform-wrap .perform-listhead { background:#10211c; color:#8fc9b3; border-bottom-color:#1c3a30; }
#perform-wrap .ev { border-bottom-color:#13241f; }
#perform-wrap .ev:hover { background:#13241f; }
#perform-wrap .ev.sel { background:#163027; border-left-color:#3fb98a; }
#perform-wrap .tl-stagewrap { border-color:#1c3a30; }
#perform-wrap .tl-timelinepanel .tl-tracks { border-color:#1c3a30; }
#perform-wrap .tl-mapinfo { color:#7fae9c; }
#wrap.hidden, #perform-wrap.hidden { display:none; }
#perform-list-pane { width:250px; background:#19150f; border-right:1px solid #3a322a;
display:flex; flex-direction:column; flex:none; }
.perform-listhead { padding:10px 12px; font-size:12px; color:#9a8f7e; letter-spacing:1px;
border-bottom:1px solid #3a322a; background:#1f1a15; }
#perform-list { overflow:auto; flex:1; }
#perform-main { flex:1; min-width:0; display:flex; flex-direction:column; padding:14px 16px; min-height:0; }
#perform-main .empty-center { position:static; inset:auto; min-height:240px; }
/* ---- 演出预览:上=舞台面板(自适应放大) / 下=时间轴面板(可拖高度) ---- */
.tl-stagepanel { flex:1 1 auto; min-height:150px; display:flex; flex-direction:column; }
.tl-mapinfo { flex:none; font-size:12px; color:#9a8f7e; margin-bottom:6px; }
.tl-stagewrap { position:relative; flex:1; min-height:0; background:#15130d; border:1px solid #3a322a;
border-radius:6px; overflow:hidden; }
.tl-stage { width:100%; height:100%; object-fit:contain; display:block; }
/* 分隔条:拖动调时间轴高度 */
.tl-resizer { flex:none; height:10px; margin:5px 0; cursor:row-resize; border-radius:5px;
background:#16120d; position:relative; }
.tl-resizer::after { content:""; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
width:48px; height:3px; border-radius:2px; background:#5a4a32; }
.tl-resizer:hover::after { background:#e6c878; }
.tl-controls { flex:none; display:flex; align-items:center; gap:10px; margin:8px 0 0; flex-wrap:wrap; }
.tl-controls .tip { font-size:11.5px; color:#7a7264; }
.tl-time { font-size:13px; color:#e6c878; font-variant-numeric:tabular-nums; min-width:90px; }
.tl-startbtn { max-width:300px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tl-fitbtn.on { background:#5a4a26; border-color:#8a7038; color:#f3dca0; }
.tl-tracks .tl-clip.startable { cursor:pointer; }
.tl-tracks .tl-clip.sel { box-shadow:0 0 0 2px #ff5a4a, 0 1px 3px rgba(0,0,0,.5); z-index:3; }
/* 选项浮层:镜头下方(舞台底部居中),模拟玩家看到的位置 */
.tl-choices { position:absolute; left:0; right:0; bottom:12px; display:flex; flex-direction:column;
align-items:center; gap:6px; padding:0 12px; line-height:normal; z-index:5; }
.tl-choices.hidden { display:none; }
.tl-choices-q { font-size:12px; color:#e6c878; background:rgba(20,18,12,.72); padding:2px 10px; border-radius:10px; }
.tl-choice-btn { min-width:240px; max-width:92%; background:rgba(36,31,24,.96); color:#f0e6c8;
border:1px solid #8a7038; border-radius:6px; padding:8px 14px; font-size:13px;
cursor:pointer; box-shadow:0 2px 8px rgba(0,0,0,.55); }
.tl-choice-btn:hover { background:#5a4a26; border-color:#e6c878; }
/* 结局浮层:金色星标,区别于普通选项 */
.tl-ending-q { color:#f2c463 !important; background:rgba(42,30,14,.9) !important; border:1px solid #8a6a30; font-size:13px; max-width:92%; }
.tl-ending-btn { border-color:#b8893a; }
.tl-ending-btn:hover { background:#5a4426; border-color:#f2c463; }
/* 时间轴面板:固定/可拖高度、自己横向滚动 */
.tl-timelinepanel { flex:none; height:200px; min-height:80px; display:flex; }
.tl-tracks { position:relative; flex:1; min-width:0; overflow-x:auto; overflow-y:auto; cursor:grab;
background:#19150f; border:1px solid #3a322a; border-radius:6px; padding-top:20px;
scrollbar-width:thin; scrollbar-color:#5a4a32 transparent; }
/* 纤细主题化滚动条(替代默认丑滚动条) */
.tl-tracks::-webkit-scrollbar { height:9px; width:9px; }
.tl-tracks::-webkit-scrollbar-track { background:transparent; }
.tl-tracks::-webkit-scrollbar-thumb { background:#4a4030; border-radius:6px; border:2px solid #19150f; }
.tl-tracks::-webkit-scrollbar-thumb:hover { background:#6a5a3c; }
.tl-tracks::-webkit-scrollbar-corner { background:transparent; }
#perform-wrap .tl-tracks { scrollbar-color:#2f5a48 transparent; }
#perform-wrap .tl-tracks::-webkit-scrollbar-thumb { background:#2a4a3e; border-color:#0e1c18; }
#perform-wrap .tl-resizer::after { background:#2f5a48; }
#perform-wrap .tl-resizer:hover::after { background:#3fb98a; }
.tl-ruler { position:relative; height:16px; border-bottom:1px solid #2a2419; }
.tl-tick { position:absolute; top:0; height:16px; border-left:1px solid #2a2419; }
.tl-tick span { font-size:9px; color:#6a6256; padding-left:3px; }
.tl-lane { position:relative; border-bottom:1px solid #211c15; }
.tl-lane-label { position:sticky; left:0; z-index:3; display:inline-block; min-width:54px;
padding:2px 6px; font-size:11px; color:#b89a5a; background:#211c15;
border-right:1px solid #2a2419; height:100%; box-sizing:border-box; line-height:26px; }
.tl-clip { position:absolute; top:3px; height:22px; line-height:22px; padding:0 5px;
font-size:11px; color:#1a1710; border-radius:3px; overflow:hidden; white-space:nowrap;
text-overflow:ellipsis; cursor:pointer; box-sizing:border-box; box-shadow:0 1px 2px rgba(0,0,0,.4);
user-select:none; -webkit-user-select:none; }
.tl-tracks .tl-clip.active { outline:2px solid #fff; outline-offset:-1px; z-index:2; }
.tl-clip.k-dialogue { background:#7ec8e3; }
.tl-clip.k-move { background:#e6c878; }
.tl-clip.k-anim { background:#9ee37e; }
.tl-clip.k-camera { background:#c89ee3; }
.tl-clip.k-branch { background:#9ec0f0; }
.tl-clip.k-fight { background:#e38f7e; }
.tl-clip.k-reward { background:#e0c060; }
.tl-clip.k-ending { background:#e0a850; }
.tl-clip.k-stop { background:#d87878; color:#fff; }
.tl-playhead { position:absolute; top:0; bottom:0; width:2px; background:#ff5a4a;
pointer-events:none; z-index:4; box-shadow:0 0 4px rgba(255,90,74,.7); }
/* ===== 演出段 scene 节点(分支图)===== */
#drawflow .kind-scene { background:#16241f; border-color:#3a7a64; }
#drawflow .kind-scene .nlabel { color:#7ee3c8; }
.drawflow-node .scenebody { padding-top:2px; }
.drawflow-node .scenebody .screl { font-size:11px; color:#bfe6d8; line-height:1.5; }
.drawflow-node .scenebody .screl.more { color:#7a8a82; }
.drawflow-node .scenebody .schint { font-size:10px; color:#5a8a7a; margin-top:3px; font-style:italic; }
/* ===== 演出段编辑模态 ===== */
.scene-edit { width:92vw; max-width:1280px; max-height:92vh; }
.se-psinfo { font-size:12px; color:#9a907e; font-weight:normal; }
.se-toolbar { display:flex; align-items:center; gap:10px; margin:4px 0 8px; flex-wrap:wrap; }
.se-toolbar .se-tip { font-size:11px; color:#8a8275; }
.se-toolbar .se-total { margin-left:auto; font-size:12px; color:#e6c878; }
.se-trackswrap { overflow-x:auto; background:#15130d; border:1px solid #2a2419; border-radius:6px; padding-bottom:4px; }
.se-ruler { position:relative; height:16px; border-bottom:1px solid #2a2419; min-width:100%; }
.se-tick { position:absolute; top:0; height:16px; border-left:1px solid #2a2419; }
.se-tick span { font-size:9px; color:#6a6256; padding-left:3px; }
.se-lanes { position:relative; min-width:100%; }
.se-lane { position:relative; border-bottom:1px solid #211c15; }
.se-lane-label { position:sticky; left:0; z-index:5; display:inline-flex; align-items:center; gap:3px;
width:54px; height:100%; background:#1d1810; color:#d8cda0; font-size:11px; padding:0 3px;
border-right:1px solid #2a2419; box-sizing:border-box; }
.se-lane-label button { background:none; border:none; color:#9a8f78; cursor:pointer; font-size:11px; padding:0 1px; }
.se-lane-label .se-addclip:hover { color:#7ee3c8; }
.se-lane-label .se-deltrack:hover { color:#e38f7e; }
.se-clip { position:absolute; top:5px; height:24px; line-height:24px; padding:0 6px; border-radius:4px;
font-size:11px; color:#1a1710; white-space:nowrap; overflow:hidden; cursor:grab; user-select:none;
box-shadow:0 1px 3px rgba(0,0,0,.5); }
.se-clip.sel { box-shadow:0 0 0 2px #ff5a4a, 0 1px 3px rgba(0,0,0,.5); z-index:3; }
.se-clip.k-dialogue { background:#7ec8e3; }
.se-clip.k-move { background:#e6c878; }
.se-clip.k-anim { background:#9ee37e; }
.se-clip.k-camera { background:#c89ee3; }
.se-clip.k-wait { background:#9a9488; color:#fff; }
.se-resize { position:absolute; top:0; right:0; width:7px; height:100%; cursor:ew-resize; background:rgba(0,0,0,.18); border-radius:0 4px 4px 0; }
.se-empty, .se-prop-empty { padding:14px; color:#8a8275; font-size:12px; text-align:center; }
.se-lint { margin:8px 0 4px; font-size:11.5px; padding:5px 8px; border-radius:5px; }
.se-lint.ok { color:#7ee3a0; background:rgba(60,120,80,.12); }
.se-lint.bad { color:#f0b070; background:rgba(160,90,40,.14); }
.se-prop { background:#19150f; border:1px solid #2a2419; border-radius:6px; padding:8px; min-height:40px; }
.se-prop-row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.se-prop-kind { font-size:12px; color:#e6c878; font-weight:bold; }
.se-f { font-size:11px; color:#a89e88; display:flex; align-items:center; gap:4px; }
.se-f input, .se-f select { width:auto; min-width:64px; background:#221d16; color:#e8e0d4; border:1px solid #3a3326; border-radius:4px; padding:2px 4px; font-size:12px; }
.se-f input[type=number] { width:64px; }
.se-delclip { margin-left:auto; color:#e38f7e !important; }
.se-preview { margin-top:10px; }
.se-prev-head { font-size:12px; color:#7ee3c8; margin-bottom:4px; }
.se-prev-host { height:560px; background:#100e09; border:1px solid #2a2419; border-radius:6px; overflow:hidden; position:relative; }
/* scene 右栏 clip 行form.js 精确数值编辑) */
.se-cliprow { display:flex; align-items:flex-end; gap:5px; flex-wrap:wrap; padding:5px 0; border-top:1px dashed #2a2419; }
.se-cliprow .fld { margin:0; }
.se-cliprow .fld label { font-size:10px; }
.se-cliprow input[type=number] { width:52px; }
.se-cliprow select { min-width:60px; }
#edit-pane .optdet-like { border:1px solid #2a2419; border-radius:5px; padding:6px; margin-bottom:6px; }