/* 概念图实验室 · 共享样式（fork 自 MBL lab，token 保持一致） */
:root{
  --teal:#0e9488; --teal-d:#0b6f66; --teal-l:#e6f4f2;
  --ink:#1f2d2b; --ink-soft:#4b5d5b; --line:#dce7e4;
  --card:#ffffff; --bg:#f4f9f8; --warn:#e11d48; --amber:#f59e0b;
  --radius:14px; --shadow:0 4px 16px rgba(14,148,136,.10);
}
*{box-sizing:border-box;margin:0;padding:0}
/* touch-action:manipulation 关掉双击缩放（iOS Safari 会忽略 viewport 的 user-scalable=no）；
   -webkit-text-size-adjust 防止横竖屏切换时 iOS 自作主张放大字号 */
html,body{height:100%;touch-action:manipulation;-webkit-text-size-adjust:100%}
body{font-family:"Microsoft YaHei","PingFang SC",sans-serif;background:var(--bg);color:var(--ink);font-size:15px;line-height:1.65}
.topbar{background:linear-gradient(90deg,var(--teal-d),var(--teal));color:#fff;padding:10px 0;flex:none}
.topbar-inner{max-width:1180px;margin:0 auto;padding:0 16px;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.brand{font-weight:800;font-size:17px;color:#fff;text-decoration:none;display:flex;align-items:center;gap:8px}
.brand .dot{width:10px;height:10px;border-radius:50%;background:#8ff0e4;display:inline-block}
.tasktag{margin-left:auto;font-size:13px;font-weight:700;background:rgba(255,255,255,.15);color:#d9f3ef;padding:5px 14px;border-radius:999px}
.who{font-size:13px;color:#d9f3ef}
.wrap{max-width:1180px;margin:0 auto;padding:18px 16px 60px}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:20px 22px;margin-bottom:16px}
.sec{font-size:17px;color:var(--teal-d);margin-bottom:10px;font-weight:800}
.hint{font-size:13px;color:var(--ink-soft);background:#fff8ec;border:1px solid #f6e3bd;border-radius:8px;padding:8px 12px;margin:8px 0}
.btn{cursor:pointer;border:none;border-radius:10px;font-weight:700;padding:10px 22px;font-size:15px;font-family:inherit}
.btn.main{background:var(--teal);color:#fff}
.btn.main:disabled{background:#b9d4d0;cursor:not-allowed}
.btn.ghost{background:var(--teal-l);color:var(--teal-d)}
.btn.warn{background:var(--warn);color:#fff}
.btn.small{padding:6px 14px;font-size:13px;border-radius:8px}
.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.screen{display:none}
.screen.on{display:block}
.screen.flex.on{display:flex}
.foot{margin-top:30px;text-align:center;font-size:12.5px;color:var(--ink-soft)}
/* 登记页 */
.regbox{max-width:430px;margin:60px auto;background:#fff;border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:30px}
.regbox h1{font-size:20px;color:var(--teal-d);margin-bottom:4px}
.regbox p{font-size:13.5px;color:var(--ink-soft);margin-bottom:16px}
.regbox .field{margin:12px 0}
.regbox .field label{display:block;font-weight:700;font-size:14px;margin-bottom:4px}
.regbox input,.regbox select{width:100%;font-family:inherit;font-size:15px;padding:9px 10px;border:1.5px solid var(--line);border-radius:8px}
.regbox input:focus{border-color:var(--teal);outline:none}
/* 单元选择 */
.unitcard{display:block;width:100%;text-align:left;border:1.5px solid var(--line);background:#fff;border-radius:var(--radius);padding:16px 20px;margin:10px 0;cursor:pointer;font-family:inherit;box-shadow:var(--shadow)}
.unitcard:hover:not(:disabled){border-color:var(--teal)}
.unitcard:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}
.unitcard b{font-size:17px;color:var(--teal-d)}
.unitcard span{display:block;font-size:13px;color:var(--ink-soft);margin-top:2px}
/* 画布布局 */
.canvas-wrap{flex:1;display:flex;min-height:0;position:relative}   /* 2026-10-25：提示条/框选条/空画布提示以画布区为参照，不再压住顶栏 */
.sidebar-left{width:60px;flex:none;background:#fff;border-right:1px solid var(--line);display:flex;flex-direction:column;align-items:center;gap:8px;padding:12px 0}
.sidebar-left button{width:46px;height:46px;border:1.5px solid var(--line);border-radius:12px;background:#fff;cursor:pointer;font-size:19px;line-height:1;font-family:inherit}
.sidebar-left button:hover{border-color:var(--teal);background:var(--teal-l)}
.sidebar-left button span{display:block;font-size:10px;color:var(--ink-soft);line-height:1.1}
.sidebar-left .spacer{flex:1}
.canvas-scroller{flex:1;overflow-y:auto;overflow-x:hidden;position:relative;touch-action:pan-y;overscroll-behavior:none;
  background:#fbfdfd;background-image:radial-gradient(circle,#d8e8e5 1px,transparent 1px);background-size:26px 26px}
.canvas-content{position:relative;width:100%}
/* 边层压在节点上方（z7）：弧线路由绕开卡内部，盖不住内容；容器底色再也挡不住容器内弧线。
   命中线单独一层 z9 全局最上（容器面上的弧线也能点选）；手柄点击优先权由 app 几何判定保护 */
svg.edge-layer{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:7}
svg.edge-layer.edge-hit-layer{z-index:9}
svg.edge-layer .edge-hit{pointer-events:stroke;cursor:pointer;touch-action:none}
/* 节点 */
.node{position:absolute;min-width:118px;max-width:220px;min-height:46px;background:#fff;border:2px solid var(--teal);border-radius:10px;
  padding:12px 14px;font-weight:600;font-size:14.5px;text-align:center;line-height:1.4;cursor:grab;
  display:flex;flex-direction:column;justify-content:center;
  touch-action:none;user-select:none;-webkit-user-select:none;box-shadow:0 2px 8px rgba(14,148,136,.12);z-index:5}
.node.sel{border-color:var(--amber);box-shadow:0 2px 12px rgba(245,158,11,.35);z-index:8}   /* 高于边层，保证连线手柄可点 */
.node.flash{outline:3px solid var(--amber);outline-offset:2px}
.node .ntext{pointer-events:none;white-space:pre-wrap;word-break:break-all}
.node .ntext:empty::before{content:"（空）";color:#b6c6c3;font-weight:400}
.node textarea{width:100%;min-width:100px;border:none;outline:none;resize:none;font-family:inherit;font-size:14.5px;font-weight:600;text-align:center;background:var(--teal-l);border-radius:6px;padding:2px 4px}
/* 容器卡（有子卡的节点）：标题行 + 子项流式区，宽度随内容撑大 */
.node.container{max-width:min(720px,calc(100vw - 90px));text-align:left;padding:10px 12px 28px;justify-content:flex-start;
  background:repeating-linear-gradient(45deg,#f6fbfa,#f6fbfa 6px,#edf5f3 6px,#edf5f3 12px)}
.node.container>.ntitle{display:flex;align-items:center;gap:8px;padding:0 2px 6px;font-weight:800;color:var(--teal-d)}
/* 标题字号分级：最外层容器最大 > 内层容器 > 普通卡（14.5px 基准） */
.node.container:not(.nested)>.ntitle{font-size:17.5px}
.node.container.nested>.ntitle{font-size:15.5px}
.node.container>.ntitle textarea{flex:1;text-align:left}
.node.container.collapsed{padding-bottom:8px;padding-right:42px}
.node.container.collapsed>.ntitle{padding-bottom:0}
.node .nbadge{flex:none;font-size:12px;font-weight:700;color:#fff;background:var(--teal);border-radius:999px;padding:1px 8px;pointer-events:none}
/* 子卡摆成网格：row→行、ord→列。同列严格对齐、缺的列自动留白，
   所以"某行只有一张卡"时它也能待在第二列（紧密左对齐的行布局做不到）。
   列宽取该列最宽的卡，顶对齐不拉伸高度（拉伸会把内容挤到溢出重叠、矮卡被拉成邻居的高度） */
.node .nbody{display:grid;gap:14px 16px;align-items:start;justify-items:stretch;min-width:130px;min-height:20px}
/* 只有最外层容器带绿条纹，内层容器一律白底（靠标题字号和边框区分层级） */
.node.container.nested{background:#fff}
/* 容器内的子卡：脱离绝对定位，进流式布局（宽度上限沿用普通卡/容器各自的规则） */
.node.nested{position:relative;z-index:auto;box-shadow:0 1px 4px rgba(14,148,136,.10)}
/* 收放按钮（容器右下角小三角） */
.collapse-toggle{position:absolute;right:0;bottom:0;width:36px;height:26px;text-align:center;line-height:26px;
  font-size:14px;color:var(--teal-d);cursor:pointer;touch-action:none;user-select:none;-webkit-user-select:none}
/* 拖拽中：整棵子树跟手；悬停目标高亮提示"松手放入"；目标被大容器盖住时被拖卡自己也亮边 */
.node.dragging{opacity:.75;pointer-events:none;z-index:20}
.node.drop-hint{outline:3px solid var(--amber);outline-offset:2px}
/* 拉线时悬停的目标卡：绿色系高亮（与主题一致） */
.node.link-hint{outline:3px solid var(--teal);outline-offset:2px;background-color:var(--teal-l)}
/* ===== 视野（P 维度） ===== */
.pers-eye{display:inline-flex;align-items:center;flex:none;cursor:pointer;padding:2px;touch-action:none;transition:transform .15s}
.pers-eye.on{transform:scale(1.5)}   /* 查看中：眼睛放大，再点一下退出 */
.pers-dot{display:inline-block;flex:none;width:11px;height:11px;border-radius:50%;border:2px solid #fff;
  box-shadow:0 0 0 1px rgba(0,0,0,.12);margin-left:6px;cursor:pointer;touch-action:none;vertical-align:middle}
.node>.ntitle{display:flex;align-items:center;gap:5px;justify-content:center}
.node.container>.ntitle{justify-content:flex-start}
.node>.ntitle .ntext{min-width:0}   /* 挂了眼睛/圆点后长标题仍可换行 */
/* 笔记卡：浮在目标卡右侧，同色边框浅色底，左侧短线连向卡 */
.pers-note{position:absolute;display:flex;align-items:center;gap:6px;max-width:280px;min-width:150px;
  border:1.5px solid;border-radius:8px;padding:6px 8px;font-size:13px;z-index:6;background:#fff}
.pers-note .pn-line{position:absolute;left:-18px;top:50%;width:18px;height:2px}
.pers-note b{flex:none;font-size:12.5px;color:var(--ink)}
.pers-note .pn-eye{display:inline-flex;flex:none}
.pers-note .pn-text{flex:1;min-width:60px;color:var(--ink);white-space:pre-wrap;word-break:break-all;cursor:text}
.pers-note .pn-text.empty{color:#9ab0ad}
.pers-note .pn-del{flex:none;cursor:pointer;font-size:13px;opacity:.55}
.pers-note .pn-del:hover{opacity:1}
.pers-note input{flex:1;min-width:80px;border:none;outline:none;background:rgba(255,255,255,.7);
  border-radius:5px;font-family:inherit;font-size:13px;padding:2px 4px}
/* 查看模式：无关内容模糊降透明并锁交互（连线和标签同步压暗） */
.node.pers-dim{filter:blur(2px);opacity:.35;pointer-events:none}
.pers-note.pers-dim{filter:blur(2px);opacity:.3;pointer-events:none}
.pers-dim-e{opacity:.04}
.edge-hit.pers-dim-e{pointer-events:none}
/* 添加视野模式：可选目标直接标出（触屏没有悬停预览，不能等指针移上去才提示） */
.node.pers-pick{outline:2px dashed var(--pick);outline-offset:2px}
.node.pers-source{outline:3px solid var(--pick);outline-offset:2px}
/* 框选多选 */
#marqueeBox{position:absolute;border:2px dashed var(--teal);background:rgba(14,148,136,.08);
  border-radius:6px;z-index:30;pointer-events:none}
.node.msel{outline:3px dashed var(--teal);outline-offset:3px}
/* 框选后的批量操作条（画布顶部居中——放底部会和 toast 提示叠在一起互相遮挡） */
.msel-bar{position:absolute;left:50%;transform:translateX(-50%);top:14px;display:flex;align-items:center;gap:10px;
  background:#fff;border:1px solid var(--line);border-radius:12px;padding:10px 16px;
  box-shadow:0 6px 18px rgba(0,0,0,.16);z-index:46;font-size:13.5px}
.msel-bar span{font-weight:700;color:var(--teal-d)}
/* 拖放落点插入条（竖=并排，横=新行） */
#dropMarker{position:absolute;background:var(--amber);border-radius:3px;z-index:25;pointer-events:none;
  box-shadow:0 0 0 2px rgba(245,158,11,.25)}
#persBanner{position:fixed;left:50%;transform:translateX(-50%);top:64px;display:flex;align-items:center;gap:10px;
  background:#fff;border:1px solid var(--line);border-radius:12px;padding:8px 16px;
  box-shadow:0 6px 18px rgba(0,0,0,.15);z-index:60;font-size:14px;font-weight:700}
#persBanner .pb-name{display:flex;align-items:center;gap:6px;padding:3px 10px;border-radius:8px}
#persBanner button{border:none;background:var(--teal-l);color:var(--teal-d);font-weight:700;
  border-radius:8px;padding:6px 14px;cursor:pointer;font-family:inherit;font-size:13.5px}
.node.dragging.can-drop{outline:3px solid var(--amber);outline-offset:2px}
.link-handle{position:absolute;right:-16px;top:50%;transform:translateY(-50%);width:32px;height:32px;border-radius:50%;
  background:var(--teal);color:#fff;font-size:16px;line-height:32px;text-align:center;cursor:crosshair;
  touch-action:none;display:none;box-shadow:0 2px 6px rgba(0,0,0,.2)}
/* 容器内的子卡：弧线朝左走，手柄也挪到左边（右侧留给视角笔记） */
.node.nested>.link-handle{right:auto;left:-16px}
.node.sel > .link-handle{display:block}   /* 只弹自己的手柄：选中容器时不连带子卡的 */
/* 载入上次的图：画布顶部的提示条 */
.load-bar{position:absolute;left:50%;transform:translateX(-50%);top:14px;display:flex;align-items:center;gap:10px;
  background:#fff;border:1px solid var(--line);border-radius:12px;padding:10px 16px;
  box-shadow:0 6px 18px rgba(0,0,0,.14);z-index:45;font-size:13.5px;max-width:calc(100% - 40px)}
/* 浮层 */
.mini-toolbar{position:fixed;display:flex;gap:4px;background:#fff;border:1px solid var(--line);border-radius:10px;
  padding:4px;box-shadow:0 4px 14px rgba(0,0,0,.15);z-index:40}
.mini-toolbar button{width:38px;height:38px;border:none;border-radius:8px;background:#fff;font-size:17px;cursor:pointer;font-family:inherit}
.mini-toolbar button:hover{background:var(--teal-l)}
.edge-popover{position:fixed;display:flex;flex-direction:column;gap:4px;background:#fff;border:1px solid var(--line);border-radius:10px;
  padding:6px;box-shadow:0 4px 14px rgba(0,0,0,.15);z-index:40}
.edge-popover .ep-row{display:flex;gap:4px;align-items:center}
.edge-popover input{width:150px;font-family:inherit;font-size:14px;padding:6px 8px;border:1.5px solid var(--line);border-radius:8px}
.edge-popover input:focus{border-color:var(--teal);outline:none}
.edge-popover button{width:36px;height:36px;border:none;border-radius:8px;background:#fff;font-size:16px;cursor:pointer;font-family:inherit}
.edge-popover button:hover{background:var(--teal-l)}
.edge-popover button.on{background:var(--teal);color:#fff}   /* 当前箭头样式 */
.edge-popover button.cross{color:#d03a2e;font-weight:700}       /* 无关线用红叉 */
.edge-popover button.cross.on{background:#d03a2e;color:#fff}
.hint-pill{position:absolute;left:50%;transform:translateX(-50%);top:200px;background:#eef4f3;border-radius:999px;
  padding:14px 30px;color:var(--ink-soft);font-size:15px;pointer-events:none;white-space:nowrap}
.toast{position:fixed;left:50%;bottom:30px;transform:translateX(-50%);background:rgba(31,45,43,.9);color:#fff;
  padding:9px 20px;border-radius:999px;font-size:13.5px;z-index:99;transition:opacity .3s;pointer-events:none}
/* 回放器 */
.replay-layout{flex:1;display:flex;min-height:0}
.replay-canvas{flex:1;overflow-y:auto;position:relative;background:#fbfdfd;background-image:radial-gradient(circle,#d8e8e5 1px,transparent 1px);background-size:26px 26px}
.replay-canvas .canvas-content{pointer-events:none}
.evlist{width:300px;flex:none;border-left:1px solid var(--line);background:#fff;overflow-y:auto;font-size:12.5px}
.evlist .ev{padding:4px 10px;border-bottom:1px solid #f0f5f4;cursor:pointer;display:flex;gap:8px}
.evlist .ev:hover{background:var(--teal-l)}
.evlist .ev.cur{background:var(--teal);color:#fff}
.evlist .ev.gap{background:#fde8ec;color:var(--warn)}
.evlist .ev .no{flex:none;width:44px;color:inherit;opacity:.6}
.evlist .ev.sys{color:var(--ink-soft);font-style:italic}
.evlist .ev.cur.sys{color:#d9f3ef}
.replay-ctl{flex:none;background:#fff;border-top:1px solid var(--line);padding:8px 16px}
.replay-ctl .bar{display:flex;gap:12px;align-items:center}
.replay-ctl input[type=range]{flex:1}
.replay-ctl select{font-family:inherit;font-size:13px;padding:4px 6px;border:1px solid var(--line);border-radius:6px}
.replay-ctl .cap{font-size:13px;color:var(--teal-d);font-weight:700;min-height:22px;margin-top:2px}
.markstrip{position:relative;height:8px;margin:0 2px}
.markstrip i{position:absolute;top:0;width:3px;height:8px;border-radius:2px;background:var(--amber)}
.markstrip i.task{background:var(--teal)}
.topbar .home{color:#d9f3ef;text-decoration:none;font-size:13px;border:1px solid rgba(255,255,255,.45);border-radius:999px;padding:3px 12px}
.topbar .home:hover{background:rgba(255,255,255,.15)}
/* 云载图清单 + 侧栏四个存/载按钮（2026-10-25） */
.sidebar-left button span{font-size:9.5px}
.cloud-modal{position:fixed;inset:0;background:rgba(31,45,43,.45);z-index:60;display:flex;align-items:center;justify-content:center}
.cloud-box{background:#fff;border-radius:14px;box-shadow:0 10px 30px rgba(0,0,0,.25);width:min(520px,calc(100% - 40px));max-height:80vh;display:flex;flex-direction:column;padding:16px 18px}
.cloud-box .cl-head{display:flex;justify-content:space-between;align-items:center;font-size:16px;color:var(--teal-d)}
.cloud-box .cl-tip{font-size:12.5px;color:var(--ink-soft);margin:6px 0 10px}
.cl-list{overflow-y:auto;display:flex;flex-direction:column;gap:8px}
.cl-row{text-align:left;border:1.5px solid var(--line);border-radius:10px;background:#fff;padding:10px 14px;cursor:pointer;font-family:inherit}
.cl-row:hover{border-color:var(--teal);background:var(--teal-l)}
.cl-row b{display:block;font-size:14.5px;color:var(--ink)}
.cl-row span{display:block;font-size:12.5px;color:var(--ink-soft);margin-top:2px}
.cl-empty{font-size:13.5px;color:var(--ink-soft);padding:14px 4px}
.load-bar button{white-space:nowrap}
