/* ══════════════════════════════════════════════════════
   app.css — DNA 제품관리
   색은 전부 변수로 둔다 (기법 #33). 라이트 모드 전용 — 다크 모드 없음.
   ══════════════════════════════════════════════════════ */
:root{
  --pri:#7c3aed; --pri2:#6d28d9; --nav:#312152; --nav2:#3d2a63;
  --bg:#f4f5f9; --sf:#fff; --sf2:#fafbfd; --line:#e3e6ee;
  --tx:#1c2333; --txm:#6b7280; --txd:#9aa3b2;
  --red:#dc2626; --amb:#d97706; --grn:#059669; --blu:#2563eb;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%}
body{background:var(--bg);color:var(--tx);
  font:13px/1.55 "맑은 고딕","Malgun Gothic",system-ui,-apple-system,sans-serif}
button,input,select,textarea{font:inherit;color:inherit}
a{color:var(--pri2);text-decoration:none}

/* ── 로그인 ── */
.login-wrap{min-height:100%;display:flex;align-items:center;justify-content:center;padding:20px}
.login{background:var(--sf);border:1px solid var(--line);border-radius:14px;padding:30px 32px;width:340px;
  box-shadow:0 6px 28px rgba(49,33,82,.10)}
.login h1{margin:0 0 3px;font-size:23px;letter-spacing:-.4px;color:var(--pri2)}
.login .sub{font-size:11.5px;color:var(--txm);margin-bottom:20px}
.login label{display:block;font-size:11.5px;color:var(--txm);font-weight:700;margin:11px 0 4px}
.login input{width:100%;border:1px solid var(--line);border-radius:8px;padding:9px 11px;background:var(--sf)}
.login input:focus{outline:none;border-color:var(--pri);box-shadow:0 0 0 3px rgba(124,58,237,.12)}
.login button{width:100%;margin-top:18px;border:0;border-radius:8px;padding:10px;background:var(--pri);
  color:#fff;font-weight:800;cursor:pointer}
.login button:hover{background:var(--pri2)}
.login .err{margin-top:12px;font-size:12px;color:var(--red);min-height:17px}

/* ── 뼈대 ── */
.shell{display:none;height:100%}
.shell.on{display:flex}
.lnb{width:200px;flex-shrink:0;background:var(--nav);color:#cfc7e6;padding:14px 0;overflow:auto;
  display:flex;flex-direction:column}
.lnb .logo{padding:0 16px 14px;font-size:21px;font-weight:800;color:#fff;letter-spacing:.5px}
.lnb .logo small{display:block;font-size:10px;font-weight:400;color:#a99cd0;letter-spacing:.4px;margin-top:2px}
.lnb .grp{padding:13px 16px 5px;font-size:10px;color:#8c7fb8;font-weight:700;letter-spacing:.6px}
.lnb a{display:flex;align-items:center;padding:8px 16px;font-size:12.5px;color:#cfc7e6;cursor:pointer}
.lnb a:hover{background:var(--nav2);color:#fff}
.lnb a.on{background:var(--pri);color:#fff;font-weight:700}
.lnb a .cnt{margin-left:auto;font-size:10.5px;background:rgba(255,255,255,.16);border-radius:9px;padding:0 7px}
.lnb .who{margin-top:auto;padding:13px 16px 0;border-top:1px solid rgba(255,255,255,.10);font-size:11px;color:#a99cd0}
.lnb .who b{display:block;color:#fff;font-size:12px;margin-bottom:2px}
.lnb .who button{margin-top:7px;background:none;border:1px solid rgba(255,255,255,.24);color:#cfc7e6;
  border-radius:7px;padding:3px 9px;font-size:11px;cursor:pointer}
.lnb .who button:hover{background:var(--nav2);color:#fff}

.main{flex:1;min-width:0;overflow:auto;padding:17px 20px 40px}

/* ── 머리 ── */
.h{display:flex;align-items:center;gap:9px;margin-bottom:12px;flex-wrap:wrap}
.h h2{margin:0;font-size:17px;letter-spacing:-.3px}
.h .d{font-size:11.5px;color:var(--txm)}
.h .sp{flex:1}
.btn{border:1px solid var(--line);background:var(--sf);border-radius:8px;padding:0 11px;font-size:12px;
  cursor:pointer;white-space:nowrap;height:30px;min-width:92px;
  display:inline-flex;align-items:center;justify-content:center}
.btn:hover{border-color:var(--pri);color:var(--pri2)}
.btn.p{background:var(--pri);border-color:var(--pri);color:#fff;font-weight:700}
.btn.p:hover{background:var(--pri2)}
.btn.d{color:var(--red);border-color:#fecaca}
.btn.d:hover{background:#fef2f2}
.btn:disabled{opacity:.5;cursor:not-allowed}

/* ── 카드 · 표 ── */
.card{background:var(--sf);border:1px solid var(--line);border-radius:11px;padding:13px 15px;margin-bottom:12px}
.card h4{margin:0 0 9px;font-size:13px}
.grid{display:grid;gap:11px;margin-bottom:12px}
.g2{grid-template-columns:1fr 1fr}
.g4{grid-template-columns:repeat(4,1fr)}
.kpi{background:var(--sf);border:1px solid var(--line);border-radius:11px;padding:11px 14px}
.kpi .t{font-size:11px;color:var(--txm);margin-bottom:3px}
.kpi .v{font-size:21px;font-weight:800;letter-spacing:-.5px}
.kpi .s{font-size:10.5px;color:var(--txd);margin-top:2px}

table{width:100%;border-collapse:collapse;background:var(--sf);border:1px solid var(--line);
  border-radius:11px;overflow:hidden}
th{background:var(--sf2);text-align:left;padding:8px 11px;font-size:11.5px;color:var(--txm);
  border-bottom:1px solid var(--line);font-weight:700;white-space:nowrap}
td{padding:8px 11px;font-size:12.5px;border-bottom:1px solid #f0f2f7;vertical-align:top}
tr:last-child td{border-bottom:0}
tbody tr:hover{background:var(--sf2)}
td.r,th.r{text-align:right}
td.c,th.c{text-align:center}
.clickable{cursor:pointer}

.tag{display:inline-block;border-radius:20px;padding:1px 9px;font-size:11px;font-weight:700;white-space:nowrap}
.t-b{background:#eff6ff;color:#1d4ed8}.t-r{background:#fef2f2;color:#b91c1c}
.t-a{background:#fffbeb;color:#b45309}.t-g{background:#ecfdf5;color:#047857}
.t-p{background:#f5f3ff;color:#6d28d9}.t-n{background:#f3f4f6;color:#4b5563}

.note{background:#fffbeb;border:1px solid #fde68a;border-radius:9px;padding:10px 13px;font-size:12px;margin:12px 0}
.note b{color:#92400e}
.note.pp{background:#faf5ff;border-color:#e9d5ff}.note.pp b{color:var(--pri2)}
.note.ok{background:#ecfdf5;border-color:#a7f3d0}.note.ok b{color:#065f46}
.note.rr{background:#fef2f2;border-color:#fecaca}.note.rr b{color:#991b1b}

.empty{padding:26px;text-align:center;color:var(--txd);font-size:12.5px}
.muted{color:var(--txm)}
.dim{color:var(--txd)}

/* ── 입력 폼 ── */
.fld{display:grid;grid-template-columns:96px 1fr;gap:9px;align-items:start;margin-bottom:9px}
.fld>label{font-size:11.5px;color:var(--txm);font-weight:700;padding-top:7px}
.fld input,.fld select,.fld textarea{width:100%;border:1px solid var(--line);border-radius:7px;
  padding:6px 9px;font-size:12.5px;background:var(--sf)}
.fld input:focus,.fld select:focus,.fld textarea:focus{outline:none;border-color:var(--pri);
  box-shadow:0 0 0 3px rgba(124,58,237,.12)}
.fld textarea{min-height:56px;resize:vertical;line-height:1.5}
.row{display:flex;gap:7px;flex-wrap:wrap;align-items:center}

/* ── 모달 ── */
.mask{position:fixed;inset:0;background:rgba(28,35,51,.42);display:none;align-items:flex-start;
  justify-content:center;padding:44px 16px;overflow:auto;z-index:50}
.mask.on{display:flex}
.modal{background:var(--sf);border-radius:13px;width:520px;max-width:100%;padding:19px 21px;
  box-shadow:0 12px 44px rgba(28,35,51,.28)}
.modal h3{margin:0 0 14px;font-size:15px}
.modal .foot{display:flex;gap:7px;justify-content:flex-end;margin-top:16px;
  border-top:1px solid var(--line);padding-top:13px}

/* ── 변이 단계 ── */
.ladder{display:flex;align-items:center;gap:7px;flex-wrap:wrap;font-size:11.5px}
.ladder .st{border:1px solid var(--line);border-radius:20px;padding:2px 11px;background:var(--sf)}
.ladder .st.on{border-color:var(--pri);background:#f5f3ff;color:var(--pri2);font-weight:800}
.ladder .ar{color:var(--txd)}

/* ── 토스트 ── */
.toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);background:var(--nav);color:#fff;
  padding:9px 17px;border-radius:9px;font-size:12.5px;z-index:80;opacity:0;pointer-events:none;
  transition:opacity .18s}
.toast.on{opacity:1}
.toast.bad{background:var(--red)}

@media (max-width:900px){
  .g4{grid-template-columns:1fr 1fr}
  .g2{grid-template-columns:1fr}
  .lnb{width:160px}
}

/* ══════════════════════════════════════════════════════
   ② 모듈 구성도 (2026-08-26)
   지니뷰 서비스 구성도 형태. 구역(세로 칸) × 모듈(네모) × 길(화살표).
   ★글이 들어가는 상자는 flex 로 만들지 않는다 — <b> 가 낱말마다 쪼개진다.
   ══════════════════════════════════════════════════════ */
.zc-ACCESS{--zc:#2563eb}.zc-MASTER{--zc:#0891b2}.zc-WORKFLOW{--zc:#059669}
.zc-INTERFACE{--zc:#d97706}.zc-OPS{--zc:#7c3aed}

.lead{font-size:12.5px;font-weight:700;margin:0 0 11px;line-height:1.6}
.lead b{color:var(--pri2)}

.flow{position:relative;margin-bottom:12px;overflow-x:auto;padding-bottom:2px}
.flowsvg{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:3}
/* ★선은 칸 위에 그린다. 칸(.col)이 흰 배경이라 밑에 두면 칸 사이 틈에서만 보인다 —
   실제로 그렇게 만들었다가 화살표가 토막 나 보였다 (2026-08-26 실측). */
.cols{display:grid;grid-template-columns:repeat(var(--n,5),minmax(178px,1fr));gap:13px;
  align-items:start;position:relative;min-width:min-content}

.col{background:var(--sf);border:1px solid var(--line);border-radius:11px;padding:10px;
  border-top:3px solid var(--zc,var(--line))}
.ch{display:block;margin-bottom:9px}
.ch b{font-size:12.5px;color:var(--zc,var(--tx))}
.ch .en{display:inline-block;margin-left:5px;font-size:9.5px;font-weight:700;color:var(--txd);letter-spacing:.5px}
.ch .cd{font-size:10.5px;color:var(--txm);margin-top:2px;line-height:1.45}

.nd{position:relative;z-index:1;background:var(--sf2);border:1px solid var(--line);border-radius:9px;
  padding:8px 9px;margin-bottom:8px;cursor:pointer;border-left:3px solid var(--zc,var(--line))}
.nd:hover{border-color:var(--pri);box-shadow:0 2px 10px rgba(124,58,237,.13)}
.nd:last-of-type{margin-bottom:0}
.nd.bad{background:#fef4f4;border-color:#fecaca;border-left-color:var(--red)}
.nd .nh{display:flex;align-items:center;gap:6px}
.nd .ic{font-size:15px;line-height:1;flex:0 0 auto}
.nd .nm{flex:1;min-width:0;font-size:12px;font-weight:700;line-height:1.35}
.nd .wy{font-size:10.5px;color:var(--txm);margin-top:3px;line-height:1.45}
.nd .nospec{display:inline-block;margin-top:4px;font-size:10px;font-weight:700;
  color:#b91c1c;background:#fee2e2;border-radius:20px;padding:1px 7px}
/* 진행률 도넛 — 사람이 매긴 점수가 아니라 기능 개수다 */
.dn{flex:0 0 auto;width:31px;height:31px;border-radius:50%;display:grid;place-items:center;position:relative}
.dn::after{content:'';position:absolute;inset:4px;background:var(--sf2);border-radius:50%}
.nd.bad .dn::after{background:#fef4f4}
.dn b{position:relative;z-index:1;font-size:9px;font-weight:800;letter-spacing:-.3px}
.dn.na{background:#eceef3}.dn.na b{color:var(--txd)}

.zfo{margin-top:9px;padding-top:8px;border-top:1px dashed var(--line);font-size:10.5px;color:var(--txm)}
.zfo .dot{display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:5px;vertical-align:1px}

/* 아직 어디에도 안 걸린 것 — 감추지 말고 드러낸다 */
.orphan{background:#fff7f7;border:1px solid #fecaca;border-radius:11px;padding:12px 14px;margin-bottom:12px}
.orphan .oh{font-size:12.5px;font-weight:800;color:#991b1b;margin-bottom:3px}
.orphan .os{font-size:11.5px;color:var(--txm);line-height:1.55;margin-bottom:9px}
.ochips{display:flex;gap:8px;flex-wrap:wrap}
.ochip{background:var(--sf);border:1px solid #fecaca;border-radius:9px;padding:7px 10px;
  font-size:11.5px;max-width:280px;cursor:pointer}
.ochip:hover{border-color:var(--red);box-shadow:0 2px 9px rgba(220,38,38,.12)}
.ochip>b{display:block;font-size:12px;margin-bottom:2px}
.ochip .oy{color:var(--txm);line-height:1.45}

.legend{font-size:11px;color:var(--txm);margin:0 0 10px;line-height:1.7}
.legend i{display:inline-block;width:26px;height:0;border-top:2px solid var(--txd);
  vertical-align:4px;margin:0 5px}
.legend i.gap{border-top:2px dashed var(--red)}

@media (max-width:900px){
  .cols{grid-template-columns:repeat(var(--n,5),minmax(168px,1fr))}
}

/* 길 고르기 (모듈 수정 모달) — 글 상자가 아니라 격자라 grid 를 쓴다 */
.linkbox{border:1px solid var(--line);border-radius:8px;background:var(--sf);
  max-height:96px;overflow:auto}   /* 「기능 명세」 줄이 늘어난 만큼 줄였다 — 창 720 에서도 한 화면 */
.lkh,.lk{display:grid;grid-template-columns:1fr 52px 44px;align-items:center;gap:4px;
  padding:5px 9px;font-size:11.5px}
.lkh{position:sticky;top:0;background:var(--sf2);border-bottom:1px solid var(--line);
  font-size:10.5px;font-weight:700;color:var(--txm);z-index:1}
.lkh i,.lk i{font-style:normal;text-align:center}
.lk{border-bottom:1px solid #f2f4f8}
.lk:last-child{border-bottom:0}
.lk:hover{background:var(--sf2)}
.lk>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lk input{width:14px;height:14px;margin:0;cursor:pointer}

/* 구성도에서 「기능 명세 보기」로 넘어온 줄을 잠깐 밝힌다 */
.flash>td{animation:fl 2.4s ease-out 1}
@keyframes fl{0%,55%{background:#fff5cc}100%{background:transparent}}

/* ── ⑤ 파일 · 버전 ─────────────────────────── */
/* ★.kpi .s 가 색을 잡고 있어 .rd 하나로는 못 이긴다.
   !important 를 쌓지 말고 같은 깊이로 적어 맞춘다 (사내 CSS 규칙 11장). */
.rd,.kpi .s.rd{color:var(--red)}
code{background:var(--sf2);border:1px solid var(--line);border-radius:4px;
  padding:1px 5px;font:11.5px/1.4 Consolas,"D2Coding",monospace;color:var(--txm)}
.card.warn{border-color:#f6cfcf;background:#fffafa}
.card.warn>h4{color:var(--red)}
.wl{margin:0;padding-left:18px}
.wl li{margin:5px 0;line-height:1.6;font-size:12.5px}
.lanes{display:flex;flex-wrap:wrap;gap:7px;margin:0 0 12px}
.lane{display:inline-flex;align-items:center;gap:7px;background:var(--sf);
  border:1px solid var(--line);border-radius:999px;padding:5px 12px;font-size:11.5px;color:var(--txm)}
.lane>b{color:var(--tx);font-size:12px}
.lane.cm{border-color:#c9d6f5;background:#f6f9ff}
.lane.no{border-color:#f0c9c9;background:#fffafa}
.lane.no>i{font-style:normal;color:var(--red);font-weight:700}
tr.rb>td{background:#fffaf5}
tr.rb>td:first-child{box-shadow:inset 3px 0 0 var(--amb)}
.empty.sm{padding:12px 14px;text-align:left;line-height:1.7;background:var(--sf2);
  border:1px dashed var(--line);border-radius:8px;font-size:12px}
/* 판 하나에 「바뀐 기능」 고르는 줄 — 길 고르기와 같은 격자를 쓰되 칸이 하나다 */
.lk2{grid-template-columns:1fr 44px}
#relPick{height:30px;min-width:220px;border:1px solid var(--line);border-radius:7px;
  background:var(--sf);padding:0 9px}
