/* 강남구 공공시설 디지털 아카이브 — 전량 로컬 CSS (외부 폰트·아이콘 없음) */
/* 강남구 CI: GN Deep Blue #0f4290 (심벌마크·로고타입 단일색) */

/* ---------- v3.7 본문 서체 ----------
   Pretendard GOV — 행정안전부 디지털정부 표준 서체(2024.04). SIL OFL 이므로
   설치 파일에 함께 담아도 된다. 외부 통신은 하지 않는다.
   가변축 하나(wght 45–930)로 굵기를 모두 내므로 파일이 하나면 충분하다.
   숫자는 원본이 고정폭이라 표에서 자릿수가 어긋나지 않는다. */
@font-face{
  font-family:'Pretendard GOV';
  src:url('../assets/fonts/pretendard-gov.woff2') format('woff2-variations'),
      url('../assets/fonts/pretendard-gov.woff2') format('woff2');
  font-weight:45 930; font-style:normal; font-display:block;
}
:root{
  /* 바탕·표면 — 표면을 바탕보다 밝게 두어 카드가 떠 보이게 한다 */
  --bg:var(--color-paint-f4f6f9); --panel:var(--color-paint-ffffff); --line:var(--color-line-e3e8ef); --line-soft:var(--color-line-eef1f5);
  --txt:var(--color-ink-111826); --sub:var(--color-ink-5c6b7f); --faint:var(--ink4-light);
  --pri:var(--color-paint-0f4290); --pri-d:var(--color-paint-0a306c); --pri-soft:var(--color-paint-eaf1fb);
  --acc:var(--color-paint-0d7a5f); --warn:var(--color-paint-a1610a); --err:var(--color-paint-b3261e);
  --gn:var(--color-paint-0f4290); --gn-dark:var(--color-paint-0a2a5c);
  /* 모서리·그림자 — 그림자는 2단(윤곽 1px + 확산)으로 둔다.
     1단짜리는 흐리기만 하고 경계가 서지 않는다 */
  --r:10px; --r-sm:7px;
  --shadow:0 1px 2px var(--color-shadow-416fc73499), 0 1px 3px var(--color-shadow-b7e6c475fd);
  --shadow-md:0 1px 2px var(--color-shadow-416fc73499), 0 4px 12px var(--color-shadow-d873a3f8bf);
  --shadow-lg:0 8px 32px var(--color-shadow-6c355eab73), 0 2px 8px var(--color-shadow-d873a3f8bf);
  /* 여백 척도 — 4의 배수로 통일한다 */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:20px; --s6:24px;
}
*{box-sizing:border-box; margin:0; padding:0}
html,body{height:100%}
/* 담당자 연령대가 넓다. 기본 글씨를 14px → 15px 로 올리고 줄간격을 1.6 으로 둔다.
   그래도 모자란 사람을 위해 사이드바에 3단계 조절(보통·크게·아주 크게)을 따로 둔다. */
body{font-family:'Pretendard GOV','Malgun Gothic','맑은 고딕','Segoe UI',AppleGothic,sans-serif;
  font-size:15px; line-height:1.6; color:var(--txt); background:var(--bg); overflow:hidden;
  -webkit-font-smoothing:antialiased; letter-spacing:-.005em}
/* 표·통계의 숫자는 자릿수가 세로로 맞아야 읽힌다 */
body{font-variant-numeric:tabular-nums; font-feature-settings:'tnum' 1}
button{font-family:inherit}
#app{display:flex; height:calc(100 * var(--gn-vh,1vh))}

/* ---------- 사이드바 ---------- */
#sidebar{width:228px; min-width:228px; background:var(--gn-dark); color:var(--color-ink-dbe6f1); display:flex; flex-direction:column; overflow-y:auto}
/* 강남구 CI — 흰 판 위에 원본 비율 그대로 올린다. 변형·재색상은 CI 규정에서 금지한다 */
.brand{padding:14px 14px 13px; border-bottom:1px solid var(--color-line-edf6a60092)}
.brand-logo{background:var(--color-surface-fff); border-radius:9px; padding:9px 12px; display:flex; align-items:center; justify-content:center}
.brand-logo img{width:100%; max-width:170px; height:auto; display:block}
.brand-title{font-size:15.5px; font-weight:700; line-height:1.35; color:var(--color-ink-fff); margin-top:11px; letter-spacing:-.01em}
.brand-sub{font-size:12px; color:var(--color-ink-93aac2); margin-top:5px}
#sidebar nav{padding:10px 8px; display:flex; flex-direction:column; gap:2px}
#sidebar nav a{display:flex; align-items:center; min-height:36px; padding:8px 12px; color:var(--color-ink-c3d3e5); text-decoration:none; border-radius:var(--r-sm); font-size:14px; font-weight:500}
#sidebar nav a:hover{background:var(--color-surface-0d923d3819); color:var(--color-ink-eaf2fa)}
#sidebar nav a.active{background:var(--pri); color:var(--color-ink-fff); font-weight:600; box-shadow:0 1px 3px var(--color-shadow-5111224827)}
.side-section{padding:12px 12px; border-top:1px solid var(--color-line-b34d3e7911); flex:1}
.side-heading{font-size:12px; color:var(--color-ink-8fa5b800); color:var(--color-ink-8ba5bd); margin-bottom:6px}
.recent-list a{display:block; font-size:12.5px; color:var(--color-ink-b9cbdc); text-decoration:none; padding:4px 6px; border-radius:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.recent-list a:hover{background:var(--color-surface-c201d2dab2)}
.side-users{padding:10px 12px; border-top:1px solid var(--color-line-b34d3e7911)}
.side-users .u{display:flex; align-items:center; gap:6px; font-size:12.5px; color:var(--color-ink-b9cbdc); padding:3px 4px}
.side-users .u .dot{width:7px; height:7px; border-radius:50%; background:var(--color-surface-39c98e); flex:none}
.side-users .u .dot.read{background:var(--color-surface-8fa5b8)}
.my-identity{font-size:12px; color:var(--color-ink-8ba5bd); margin-top:6px; cursor:pointer}
.my-identity:hover{color:var(--color-ink-cfe0f0); text-decoration:underline}
.ro-banner{position:fixed; top:0; left:228px; right:0; z-index:8000; background:var(--color-surface-9c6511); color:var(--color-ink-fff); font-size:13.5px; padding:6px 14px; text-align:center}
.side-foot{padding:10px 12px; border-top:1px solid var(--color-line-b34d3e7911)}
.net-badge{font-size:12px; color:var(--color-ink-7fd7b8); background:var(--color-surface-15400b89d8); padding:5px 8px; border-radius:4px; text-align:center}

/* ---------- 메인 ---------- */
#main{flex:1; overflow-y:auto; padding:20px 24px; position:relative}
.loading-page{color:var(--sub); padding:40px; text-align:center}
.page-head{display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--s4); flex-wrap:wrap; gap:var(--s2)}
.page-title{font-size:21px; font-weight:800; letter-spacing:-.02em}
.page-sub{font-size:13.5px; color:var(--sub); margin-top:4px}

/* ---------- 공통 요소 ---------- */
.card{background:var(--panel); border:1px solid var(--line); border-radius:var(--r); box-shadow:var(--shadow)}
.btn{display:inline-flex; align-items:center; gap:6px; border:1px solid var(--line); background:var(--color-surface-fff); color:var(--txt);
  padding:7px 13px; border-radius:var(--r-sm); font-size:14px; font-weight:500; cursor:pointer; user-select:none;
  box-shadow:0 1px 1px var(--color-shadow-fef7ced924)}
.btn:hover{background:var(--color-surface-f5f8fb); border-color:var(--color-line-cfd8e3)}
.btn:disabled{opacity:.45; cursor:not-allowed}
.btn.pri{background:var(--pri); border-color:var(--pri); color:var(--color-ink-fff); font-weight:600; box-shadow:0 1px 2px var(--color-shadow-5555b1636d)}
.btn.pri:hover{background:var(--pri-d); border-color:var(--pri-d)}
.btn.acc{background:var(--ok); border-color:var(--ok); color:var(--color-ink-fff); font-weight:600}
.btn.danger{background:var(--color-surface-fff); color:var(--err); border-color:var(--color-line-e6c3bf)}
.btn.danger:hover{background:var(--color-surface-fdf3f2); border-color:var(--color-line-d9a9a4)}
.btn.sm{padding:4px 9px; font-size:12.5px}
.btn.ghost{border-color:transparent; background:transparent; box-shadow:none}
.btn.ghost:hover{background:var(--color-surface-eef2f6)}
/* 누를 수 있는 곳은 눌린 것이 보여야 한다 — 초점 테는 키보드로 옮겼을 때만 낸다 */
.btn:focus-visible,.chip:focus-visible,.tab:focus-visible{outline:2px solid var(--pri); outline-offset:2px}
input:not([type]),input[type=text],input[type=number],input[type=date],select,textarea{
  font-family:inherit; font-size:14px; padding:8px 10px; border:1px solid var(--line); border-radius:var(--r-sm); background:var(--color-surface-fff); color:var(--txt); outline:none; max-width:100%; transition:border-color 140ms var(--e-out,ease), box-shadow 140ms var(--e-out,ease)}
input:focus,select:focus,textarea:focus{border-color:var(--pri); box-shadow:0 0 0 3px var(--color-shadow-6bd8ba8f18)}
textarea{resize:vertical; min-height:64px}
label.fld{display:flex; flex-direction:column; gap:4px; font-size:12.5px; color:var(--sub)}
.badge{display:inline-block; font-size:12px; font-weight:600; padding:2px 8px; border-radius:6px; border:1px solid transparent; white-space:nowrap; letter-spacing:-.01em}
.badge.gray{background:var(--color-surface-eef1f5); color:var(--color-ink-5c6b7f)}
.badge.blue{background:var(--pri-soft); color:var(--color-ink-0f4290)}
.badge.green{background:var(--color-surface-e4f4ed); color:var(--color-ink-0a6249)}
.badge.red{background:var(--color-surface-fceceb); color:var(--color-ink-8f1d17)}
.badge.orange{background:var(--color-surface-fdf1de); color:var(--color-ink-7d4b06)}
.hidden{display:none !important}
.muted{color:var(--sub); font-size:12.5px}
.mono{font-family:Consolas,'Courier New',monospace; font-size:12.5px}
.hr{border:none; border-top:1px solid var(--line); margin:12px 0}

/* ---------- 토스트/모달/버지 ---------- */
#toast-root{position:fixed; right:18px; bottom:18px; z-index:9999; display:flex; flex-direction:column; gap:8px}
.toast{background:var(--color-surface-243447); color:var(--color-ink-fff); padding:10px 16px; border-radius:6px; font-size:14px; box-shadow:0 4px 14px var(--color-shadow-78eab87e61); max-width:420px; animation:fadein .18s}
.toast.ok{background:var(--color-surface-0d6b52)}
.toast.err{background:var(--color-surface-a93226)}
@keyframes fadein{from{opacity:0; transform:translateY(6px)} to{opacity:1}}
.busy{position:fixed; left:50%; top:12px; transform:translateX(-50%); background:var(--color-surface-243447); color:var(--color-ink-fff); font-size:12.5px; padding:6px 14px; border-radius:14px; z-index:9998}
.modal-back{position:fixed; inset:0; background:var(--color-surface-973d84be42); backdrop-filter:blur(2px); z-index:9000; display:flex; align-items:center; justify-content:center; padding:24px}
.modal{background:var(--color-surface-fff); border-radius:14px; max-height:calc(94 * var(--gn-vh,1vh)); display:flex; flex-direction:column; box-shadow:var(--shadow-lg); min-width:340px}
.modal.wide{width:min(1280px,calc(96 * var(--gn-vw,1vw)))}
.modal.full{width:calc(96 * var(--gn-vw,1vw)); height:calc(94 * var(--gn-vh,1vh))}
.modal-head{display:flex; align-items:center; justify-content:space-between; padding:12px 16px; border-bottom:1px solid var(--line)}
.modal-title{font-size:15px; font-weight:700}
.modal-body{padding:14px 16px; overflow:auto; flex:1}
.modal-foot{padding:10px 16px; border-top:1px solid var(--line); display:flex; justify-content:flex-end; gap:8px}

/* ---------- 대시보드 ---------- */
.stat-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(168px,1fr)); gap:12px; margin-bottom:18px}
.stat{padding:14px 16px 15px; cursor:pointer; transition:transform .06s; position:relative; overflow:hidden}
.stat:hover{transform:translateY(-1px); box-shadow:var(--shadow-md)}
.stat .k{font-size:12.5px; color:var(--sub); font-weight:500}
/* 숫자가 이 카드의 본문이다. 라벨보다 세 배 크게 두어 멀리서도 읽히게 한다 */
.stat .v{font-size:30px; font-weight:800; margin-top:3px; line-height:1.1; letter-spacing:-.02em; font-variant-numeric:tabular-nums}
.stat .v small{font-size:12.5px; font-weight:500; color:var(--sub); letter-spacing:0; margin-left:2px}
/* 왼쪽 굵은 띠 대신 아래쪽 얇은 띠로 옮긴다 — 글자와 부딪히지 않는다 */
.stat[class*=hl-]::after{content:''; position:absolute; left:0; right:0; bottom:0; height:3px}
.stat.hl-blue::after{background:var(--pri)}
.stat.hl-green::after{background:var(--ok)}
.stat.hl-red::after{background:var(--err)}
.stat.hl-orange::after{background:var(--warn)}
/* 값이 0이면 «할 일 없음»이다. 빨갛게 둘 이유가 없다 */
.stat.is-zero .v{color:var(--faint); font-weight:700}
.stat.is-zero::after{background:var(--line)}
.dash-cols{display:grid; grid-template-columns:1fr 1fr; gap:14px}
@media (max-width:1100px){ .dash-cols{grid-template-columns:1fr} }
.dash-panel{padding:14px}
.dash-panel h3{font-size:15px; margin-bottom:10px}

/* ---------- 목록 ---------- */
.toolbar{display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:10px}
.toolbar .search{flex:1; min-width:240px; position:relative}
.toolbar .search input{width:100%; padding-left:12px}
.search-loading{position:absolute; right:10px; top:8px; font-size:12px; color:var(--pri)}
.chips{display:flex; gap:6px; flex-wrap:wrap; margin-bottom:10px; align-items:center}
.chip{font-size:12.5px; font-weight:500; padding:5px 12px; border-radius:8px; border:1px solid var(--line); background:var(--color-surface-fff); cursor:pointer; color:var(--color-ink-41505f); white-space:nowrap}
.chip:hover{border-color:var(--color-line-b9c8db); background:var(--color-surface-f7fafd); color:var(--pri)}
.chip.on{background:var(--pri); border-color:var(--pri); color:var(--color-ink-fff); font-weight:600}
.chip.on:hover{background:var(--pri-d); color:var(--color-ink-fff)}
/* v3.5 실측 자료 — 구역별 산출물을 한 줄에 늘어놓아 도면·3D를 바로 연다 */
.scan-chips{display:flex; gap:6px; flex-wrap:wrap; margin-top:6px}
.scan-chips .chip{background:var(--color-surface-f6f9fd); border-color:var(--color-line-dbe6f2); transition:transform var(--d-press,90ms) var(--e-out,ease), border-color 140ms}
.scan-chips .chip:active{transform:scale(.96)}
/* 기록·원본은 담당자가 매번 열 자료가 아니다. 도면·3D가 먼저 보이도록 눌러 둔다 */
.scan-chips .chip.sub{background:var(--color-surface-fbfcfd); border-color:var(--color-line-e9edf2); color:var(--color-ink-8b98a6)}
.scan-chips .chip.sub:hover{color:var(--pri); border-color:var(--color-line-c9d6e4)}
/* 대상 시설 — 어디로 들어가는지가 이 화면에서 가장 먼저 보여야 한다 */
.scan-target{border:1px solid var(--line); border-left-width:4px; border-radius:8px; padding:10px 12px; background:var(--color-surface-fafcfe)}
.scan-target.ok{border-left-color:var(--color-line-0d8a6a); background:var(--color-surface-f2faf7)}
.scan-target.warn{border-left-color:var(--color-line-e8890c); background:var(--color-surface-fffaf2)}
.scan-target.bad{border-left-color:var(--color-line-c0392b); background:var(--color-surface-fdf4f3)}
.scan-target .tl{font-size:12px; color:var(--sub); letter-spacing:.02em}
.scan-target .tn{font-size:15px; font-weight:800; color:var(--color-ink-12263c); margin:2px 0 3px}
.scan-target .tm{font-size:12.5px; line-height:1.6; color:var(--color-ink-4a5b6d)}
.scan-target .tb{display:flex; gap:6px; flex-wrap:wrap; margin-top:8px}
/* 회차 단위 정리 단추 — 자료 하나씩 다루지 않아도 되게 회차 머리에 붙인다 */
.scan-ops{display:flex; gap:6px; flex-wrap:wrap; margin-top:8px; padding-top:8px; border-top:1px solid var(--line)}
.filter-panel{padding:12px; margin-bottom:10px; display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)); gap:10px}
.filter-panel .fld select,.filter-panel .fld input{width:100%}
.filter-actions{grid-column:1/-1; display:flex; gap:8px; justify-content:flex-end}
.list-meta{display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; font-size:13.5px; color:var(--sub)}
/* 448행을 훑는 화면이다. 행 높이 40px·머리 고정·0은 흐리게가 읽는 속도를 정한다 */
.tbl-wrap{overflow:auto; max-height:calc(calc(100 * var(--gn-vh,1vh)) - 320px); border-radius:var(--r); border:1px solid var(--line); background:var(--color-surface-fff); box-shadow:var(--shadow)}
table.tbl{width:100%; border-collapse:collapse; font-size:13.5px; background:var(--color-surface-fff)}
.tbl th{position:sticky; top:0; background:var(--color-surface-fff); z-index:5; font-weight:600; color:var(--color-ink-5c6b7f); font-size:12.5px;
  border-bottom:1px solid var(--line); box-shadow:0 1px 0 var(--line); padding:0 10px; height:38px; text-align:left; white-space:nowrap; letter-spacing:.01em}
.tbl td{border-bottom:1px solid var(--line-soft); padding:0 10px; height:40px; vertical-align:middle}
.tbl tbody tr:last-child td{border-bottom:none}
.tbl tbody tr{cursor:pointer}
.tbl tbody tr:hover{background:var(--color-surface-f6f9fd)}
.tbl .num{text-align:right; font-variant-numeric:tabular-nums}
.tbl .zero{color:var(--faint)}
.cnt-dot{display:inline-block; min-width:20px; text-align:center; font-size:12px; background:var(--color-surface-f0f3f7); border-radius:6px; padding:1px 5px; color:var(--faint)}
.cnt-dot.has{background:var(--pri-soft); color:var(--color-ink-0f4290); font-weight:700}
.card-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(250px,1fr)); gap:10px}
.fac-card{padding:12px; cursor:pointer}
.fac-card:hover{border-color:var(--pri)}
.fac-card .nm{font-weight:700; font-size:15px; margin:4px 0 6px}
.fac-card .row{font-size:12.5px; color:var(--sub); margin-top:2px}

/* ---------- 상세 ---------- */
.detail-head{display:flex; align-items:flex-start; justify-content:space-between; gap:10px; margin-bottom:12px; flex-wrap:wrap}
.detail-title{font-size:21px; font-weight:800; letter-spacing:-.02em}
.detail-sub{font-size:13.5px; color:var(--sub); margin-top:5px; display:flex; gap:6px; flex-wrap:wrap; align-items:center}
.tabs{display:flex; gap:2px; border-bottom:1px solid var(--line); margin-bottom:var(--s4); flex-wrap:wrap}
.tab{padding:9px 15px; font-size:14px; font-weight:500; cursor:pointer; border:none; background:none; color:var(--sub); border-bottom:2px solid transparent; margin-bottom:-1px; border-radius:var(--r-sm) var(--r-sm) 0 0}
.tab:hover{color:var(--pri); background:var(--color-surface-f2f6fb)}
.tab.on{color:var(--pri); font-weight:700; border-bottom-color:var(--pri); background:transparent}
.info-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(230px,1fr)); gap:10px 14px; padding:14px}
.info-grid .full{grid-column:1/-1}
.group-title{grid-column:1/-1; font-size:14px; font-weight:700; color:var(--gn); border-bottom:1px solid var(--line); padding-bottom:4px; margin-top:6px}
.asset-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr)); gap:10px}
.asset-card{overflow:hidden; display:flex; flex-direction:column}
.asset-thumb{height:140px; background:var(--color-surface-e9edf2) center/cover no-repeat; display:flex; align-items:center; justify-content:center; color:var(--color-ink-8296aa); font-size:26px; font-weight:700; cursor:pointer}
.asset-thumb img{width:100%; height:100%; object-fit:cover}
.asset-body{padding:8px 10px}
.asset-body .t{font-size:14px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.asset-body .s{font-size:12px; color:var(--sub); margin-top:2px}
.asset-actions{display:flex; gap:4px; padding:6px 8px; border-top:1px solid var(--color-line-f0f3f6); flex-wrap:wrap}
.ver-list{font-size:12.5px}
.ver-list .ver{display:flex; gap:8px; align-items:center; padding:6px 4px; border-bottom:1px solid var(--color-line-f0f2f5)}
.log-tbl td,.log-tbl th{font-size:12.5px}

/* ---------- 편집기 ---------- */
.editor-wrap{display:flex; gap:10px; height:100%; min-height:0}
.editor-tools{width:210px; min-width:210px; overflow-y:auto; padding:10px; display:flex; flex-direction:column; gap:8px}
.tool-grid{display:grid; grid-template-columns:1fr 1fr; gap:4px}
.tool-btn{padding:7px 4px; font-size:12.5px; border:1px solid var(--line); background:var(--color-surface-fff); border-radius:5px; cursor:pointer}
.tool-btn:hover{border-color:var(--pri)}
.tool-btn.on{background:var(--pri); color:var(--color-ink-fff); border-color:var(--pri)}
.tool-sec{font-size:12px; color:var(--sub); margin-top:4px; border-top:1px solid var(--line); padding-top:8px}
.editor-stage{flex:1; overflow:auto; background:var(--color-surface-39424d); border-radius:8px; display:flex; align-items:center; justify-content:center; position:relative}
.editor-stage .canvas-holder{position:relative; margin:auto}
.slider-row{display:flex; align-items:center; gap:6px; font-size:12px; color:var(--sub)}
.slider-row input[type=range]{flex:1}
.color-row{display:flex; gap:4px; flex-wrap:wrap}
.color-dot{width:22px; height:22px; border-radius:50%; cursor:pointer; border:2px solid var(--color-line-fff); box-shadow:0 0 0 1px var(--color-shadow-ccc)}
.color-dot.on{box-shadow:0 0 0 2px var(--pri)}
.pdf-nav{display:flex; align-items:center; gap:8px; font-size:13.5px}

/* ---------- 3D ---------- */
.v3d-stage{flex:1; position:relative; border-radius:8px; overflow:hidden; background:var(--color-surface-20262e)}
.v3d-stage canvas{display:block}
.v3d-hud{position:absolute; left:10px; top:10px; display:flex; gap:6px; flex-wrap:wrap; z-index:5}
.v3d-hud .btn{background:var(--color-surface-3283c5139c)}

/* ---------- 정비 ---------- */
.maint-sum{display:flex; gap:10px; flex-wrap:wrap; margin-bottom:10px}
.maint-sum .card{padding:10px 14px; font-size:12.5px; color:var(--sub)}
.maint-sum .card b{display:block; font-size:18px; color:var(--txt)}
.phase-row{display:flex; gap:10px; flex-wrap:wrap}
.phase-col{flex:1; min-width:180px; border:1px dashed var(--line); border-radius:8px; padding:8px}
.phase-col h5{font-size:12.5px; color:var(--sub); margin-bottom:6px}
.overdue{color:var(--err); font-weight:700}
.soon{color:var(--warn); font-weight:700}

/* ---------- 데이터 관리 ---------- */
.dm-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;align-items:start;max-width:1680px;margin-inline:auto}
.dm-card{padding:20px;min-width:0;overflow-wrap:anywhere}.dm-wide{grid-column:1/-1}.dm-table-scroll{max-width:100%;overflow-x:auto;overscroll-behavior-inline:contain;margin-top:16px}.dm-users-table{width:100%;min-width:700px;table-layout:auto}.dm-users-table td:last-child{white-space:normal}.dm-users-table td:last-child .btn{margin:3px}.dm-card .log-tbl{min-width:0;width:100%;table-layout:fixed}.dm-card input{max-width:100%;box-sizing:border-box}.dm-card [data-perfcfg]{max-width:900px}@media(max-width:1300px){.dm-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:850px){.dm-grid{grid-template-columns:minmax(0,1fr)}.dm-card{padding:16px}}
.dm-card h3{font-size:15px; margin-bottom:6px}
.dm-card p{font-size:13.5px; color:var(--sub); margin-bottom:12px; line-height:1.6}
/* 자동 백업 카드 — 한 줄에 조작, 그 아래 상태표 */
.ab-row{display:flex; gap:14px; align-items:center; flex-wrap:wrap; margin-bottom:10px}
.ab-row label{font-size:13.5px; color:var(--txt); display:flex; gap:6px; align-items:center}
.ab-row select{min-width:96px}
.ab-sw{font-weight:600}
.ab-sw input{width:auto; margin:0}
.ab-path{display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:10px; font-size:13px}
.ab-path .ab-k{color:var(--sub); font-weight:600; white-space:nowrap}
.ab-path .ab-v{max-width:min(560px,calc(52 * var(--gn-vw,1vw))); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  background:var(--color-surface-f4f6f9); border:1px solid var(--line); border-radius:6px; padding:3px 8px; font-size:12.5px}
.ab-tbl{width:auto; min-width:0; margin:0}
.ab-tbl th{width:110px; text-align:left; color:var(--sub); font-weight:600; background:transparent}
.ab-tbl td{padding-right:26px}
.ab-err{color:var(--color-ink-8f1d17); background:var(--color-surface-fceceb); border:1px solid var(--color-line-f3cfcc); border-radius:6px;
  padding:8px 10px; font-size:13px; margin-top:10px}
.ab-list{margin-top:10px; font-size:13px}
.ab-list summary{cursor:pointer; color:var(--sub); padding:4px 0}
.ab-list .tbl{min-width:0; margin-top:6px}
.diff-item{border:1px solid var(--line); border-radius:6px; padding:8px 10px; margin-bottom:6px; font-size:13.5px}
.diff-item .chg{color:var(--sub); font-size:12.5px; margin-top:4px}
kbd{background:var(--color-surface-eef1f5); border:1px solid var(--color-line-d5dbe2); border-radius:4px; padding:1px 5px; font-size:12px}

@media (max-width:900px){
  #sidebar{width:64px; min-width:64px}
  .brand-title,.brand-sub,.side-heading,.recent-list,.net-badge{display:none}
  #sidebar nav a{font-size:12px; padding:10px 4px; text-align:center}
  #main{padding:12px}
}
::-webkit-scrollbar{width:10px; height:10px}
::-webkit-scrollbar-thumb{background:var(--color-surface-c3ccd6); border-radius:5px}
::-webkit-scrollbar-track{background:transparent}

/* ================= v3.1 모션 시스템 (폰 웹과 동일 규격) =================
   SwiftUI Spring(duration:bounce:) 를 CSS linear() 로 변환한 이징을 사용한다.
   폰과 데스크톱의 조작 반응 속도를 통일해 동일 제품으로 인지되도록 하였다.
   ==================================================================== */
:root{
  --e-smooth:linear(0, 0.0165, 0.0582, 0.1158, 0.1823, 0.2527, 0.3238, 0.393, 0.4588, 0.5202, 0.5768, 0.6284, 0.6749, 0.7165, 0.7536, 0.7864, 0.8153, 0.8406, 0.8628, 0.8821, 0.8988, 0.9133, 0.9259, 0.9367, 0.946, 0.954, 0.9608, 0.9667, 0.9717, 0.976, 0.9796, 0.9827, 1);
  --e-snappy:linear(0, 0.0178, 0.0635, 0.1275, 0.2023, 0.2822, 0.363, 0.4418, 0.5165, 0.5858, 0.6488, 0.7054, 0.7554, 0.7991, 0.8369, 0.8691, 0.8964, 0.9193, 0.9382, 0.9537, 0.9662, 0.9763, 0.9842, 0.9903, 0.995, 0.9985, 1.001, 1.0028, 1.0039, 1.0046, 1.0049, 1.005, 1);
  --e-bouncy:linear(0, 0.0238, 0.0853, 0.1711, 0.2708, 0.3759, 0.4803, 0.5794, 0.6702, 0.7508, 0.8205, 0.8791, 0.927, 0.9649, 0.994, 1.0154, 1.0301, 1.0394, 1.0444, 1.046, 1.045, 1.0423, 1.0385, 1.0339, 1.0291, 1.0243, 1.0197, 1.0155, 1.0117, 1.0085, 1.0058, 1.0035, 1);
  --d-smooth:335ms; --d-snappy:305ms; --d-bouncy:470ms;
  --e-ios:cubic-bezier(.32,.72,0,1); --e-out:cubic-bezier(.25,.46,.45,.94);
  --d-press:90ms;
}
@keyframes modalIn{from{opacity:0; transform:translateY(14px) scale(.975)} to{opacity:1; transform:none}}
@keyframes backIn{from{opacity:0} to{opacity:1}}
.modal-back{animation:backIn 180ms var(--e-out)}
.modal{animation:modalIn var(--d-snappy) var(--e-snappy)}
#main>*{animation:fadein 220ms var(--e-out)}
.card{animation:fadein var(--d-smooth) var(--e-out) backwards}
.card:nth-child(2){animation-delay:.02s} .card:nth-child(3){animation-delay:.04s}
.card:nth-child(4){animation-delay:.06s} .card:nth-child(n+5){animation-delay:.075s}
tbody tr{transition:background 140ms var(--e-out)}
.btn{transition:transform var(--d-snappy) var(--e-snappy), background-color 150ms var(--e-out), border-color 150ms var(--e-out)}
.btn:active{transform:scale(.96); transition:transform var(--d-press) var(--e-out)}
.stat{transition:transform var(--d-snappy) var(--e-snappy), box-shadow 180ms var(--e-out)}
.stat:hover{transform:translateY(-2px)}
.stat:active{transform:scale(.98); transition:transform var(--d-press) var(--e-out)}
/* 좌측 내비게이션 — 선택 표식이 미끄러지듯 이동 */
nav a{transition:background-color 160ms var(--e-out), color 160ms var(--e-out), padding-left var(--d-snappy) var(--e-snappy)}
nav a.on{padding-left:calc(var(--navpad,14px) + 4px)}
/* 토스트 — 폰과 동일한 스프링 진입 */
.toast{animation:toastIn var(--d-bouncy) var(--e-bouncy)}
@keyframes toastIn{from{opacity:0; transform:translateY(16px) scale(.95)} to{opacity:1; transform:none}}
/* 진행바·막대 값 변화 */
.bar i,.progress i{transition:width var(--d-smooth) var(--e-smooth)}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important; animation-iteration-count:1!important;
                        transition-duration:.01ms!important}
}

/* ---------- v2.3 다중 선택(일괄 이동·삭제) ---------- */
.selbar{display:flex; align-items:center; gap:8px; flex-wrap:wrap; background:var(--color-surface-eef4fb); border:1px solid var(--color-line-c9d9ec); border-radius:8px; padding:8px 12px; margin-bottom:10px; font-size:14px}
.asset-card{position:relative}
.asset-card.selmode{cursor:pointer}
.asset-card.sel{outline:2.5px solid var(--gn, var(--color-line-0f4290)); outline-offset:-1px}
.selchk{position:absolute; top:8px; left:8px; z-index:5; background:var(--color-surface-3283c5139c); border-radius:6px; padding:4px 6px; box-shadow:0 1px 4px var(--color-shadow-18a22573f7); cursor:pointer}
.selchk input{width:16px; height:16px; cursor:pointer}
.asset-card.selmode .asset-actions{opacity:.35; pointer-events:none}

/* ---------- v3.3 터치 기기가 데스크톱 화면을 쓸 때의 크기 보정 ----------
   아이패드에서 관리 기능(백업·계정 등)을 다루려고 데스크톱 화면에 머무르는 경우,
   마우스 기준으로 만들어진 클릭 대상이 손가락에 비해 작다.
   최소 44px 규격(애플 휴먼 인터페이스 가이드라인)에 맞춰 넓힌다. */
html.gn-touch .btn{padding:10px 14px;font-size:15px;min-height:44px}
html.gn-touch .btn.sm{padding:8px 12px;font-size:14px;min-height:38px}
html.gn-touch nav a{min-height:44px;display:flex;align-items:center;padding-top:11px;padding-bottom:11px;font-size:15px}
html.gn-touch tbody tr{height:auto}
html.gn-touch tbody td{padding-top:12px;padding-bottom:12px;font-size:15px}
html.gn-touch .chip{padding:9px 14px;font-size:14px;min-height:38px}
html.gn-touch input,html.gn-touch select,html.gn-touch textarea{min-height:42px;font-size:15px}
html.gn-touch .modal{max-height:calc(92 * var(--gn-vh,1vh))}
html.gn-touch .modal-head{padding:14px 18px}
html.gn-touch .stat{min-height:96px}
/* 터치에는 hover 가 없으므로 hover 로만 드러나는 조작은 항상 보이게 한다 */
html.gn-touch-device .asset-actions{opacity:1!important}

/* ---------- v3.3 결과 확인 (폰·아이패드와 동일 규칙) ---------- */
.toast{display:flex; align-items:center; gap:9px}
.toast .tm{flex:none; width:19px; height:19px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; font-size:12.5px; font-weight:800; font-style:normal; background:var(--color-surface-fff); color:var(--color-ink-243447)}
.toast.good{background:var(--color-surface-0d6b52)}
.toast.good .tm{background:var(--color-surface-7fe3c0); color:var(--color-ink-0a4d3a)}
.toast.warn{background:var(--color-surface-9c6511)}
.toast.warn .tm{background:var(--color-surface-ffd79a); color:var(--color-ink-6b4408)}
.toast.err .tm{background:var(--color-surface-ffc7bf); color:var(--color-ink-7a231a)}
/* 진동 장치가 없는 기기에서 결과를 놓치지 않도록 화면 가장자리를 한 번 물들인다 */
.gnglow{position:fixed; inset:0; pointer-events:none; z-index:8999; opacity:0}
.gnglow.on{animation:gnGlow 620ms var(--e-out)}
@keyframes gnGlow{
  0%{opacity:0; box-shadow:inset 0 0 0 0 var(--gc)}
  22%{opacity:.8; box-shadow:inset 0 0 46px 6px var(--gc)}
  100%{opacity:0; box-shadow:inset 0 0 64px 0 var(--gc)}}

/* ================= v3.7 대시보드 재구성 ==================================
   카드 20장을 늘어놓으면 «무엇부터 봐야 하는가»가 사라진다.
   머리 숫자 하나 → 지표 4개 → 오늘 할 일 묶음 → 그림 순으로 세운다.
   구역 사이 간격을 28px 로 벌려 화면이 빽빽해 보이지 않게 한다.
   ====================================================================== */
.dash-sec{margin-bottom:28px}
.dash-sec:last-child{margin-bottom:8px}
.sec-head{display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:12px}
.sec-title{font-size:15px; font-weight:700; letter-spacing:-.01em}
.sec-note{font-size:12.5px; color:var(--sub)}

/* 머리 줄 — 전체 규모 하나를 크게, 옆에 살펴볼 지표 넷 */
.hero-row{display:grid; grid-template-columns:minmax(280px,1.35fr) repeat(4,1fr); gap:12px}
@media (max-width:1240px){ .hero-row{grid-template-columns:1fr 1fr 1fr} }
@media (max-width:820px){ .hero-row{grid-template-columns:1fr 1fr} }
.hero{padding:18px 22px 20px; display:flex; flex-direction:column; justify-content:center}
.hero .k{font-size:13px; color:var(--sub); font-weight:500}
.hero .v{font-size:52px; font-weight:800; line-height:1.02; letter-spacing:-.035em; margin-top:4px}
.hero .v small{font-size:17px; font-weight:600; color:var(--sub); letter-spacing:0; margin-left:4px}
.hero .u{font-size:12.5px; color:var(--sub); margin-top:12px; padding-top:11px; border-top:1px solid var(--line-soft)}
/* 옆 지표 카드는 머리 숫자와 키가 같아진다. 내용을 세로 가운데로 모아 빈 공간을 없앤다 */
.hero-row .stat{display:flex; flex-direction:column; justify-content:center; padding:18px 20px}
.hero-row .stat .v{font-size:34px; margin-top:5px}

/* 오늘 할 일 — 표처럼 줄을 맞춰 숫자·이름·설명을 한 눈에 훑게 한다 */
.todo-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:0; overflow:hidden}
@media (max-width:1240px){ .todo-grid{grid-template-columns:repeat(2,1fr)} }
@media (max-width:820px){ .todo-grid{grid-template-columns:1fr} }
.todo{display:flex; align-items:center; gap:13px; padding:15px 18px; cursor:pointer;
  border-right:1px solid var(--line-soft); border-bottom:1px solid var(--line-soft);
  transition:background 150ms var(--e-out), transform var(--d-press) var(--e-out)}
.todo:hover{background:var(--color-surface-f6f9fd)}
.todo:active{transform:scale(.985)}
.todo .n{font-size:26px; font-weight:800; letter-spacing:-.02em; min-width:62px; text-align:right; flex:none}
.todo .tx{flex:1; min-width:0}
.todo .tt{font-size:14px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.todo .ts{font-size:12.5px; color:var(--sub); margin-top:1px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.todo .go{color:var(--faint); font-size:16px; flex:none; transition:transform 180ms var(--e-out), color 150ms}
.todo:hover .go{color:var(--pri); transform:translateX(3px)}
.todo.warn .n{color:var(--warn)} .todo.danger .n{color:var(--err)} .todo.info .n{color:var(--pri)}
/* 오른쪽 끝·아래 끝 칸의 칸막이는 지운다 */
.todo-grid .todo:nth-child(3n){border-right:none}
@media (max-width:1240px){ .todo-grid .todo:nth-child(3n){border-right:1px solid var(--line-soft)}
  .todo-grid .todo:nth-child(2n){border-right:none} }
@media (max-width:820px){ .todo-grid .todo{border-right:none} }
/* 0건은 카드로 세우지 않는다. 「이상 없음」 한 줄로 접어 자리를 비운다 */
.todo-ok{display:flex; align-items:center; gap:9px; flex-wrap:wrap; padding:12px 18px; font-size:12.5px; color:var(--sub)}
.todo-ok b{color:var(--ok); font-weight:700; font-size:13px}
.todo-ok .it{color:var(--sub)}
.todo-ok .it b{color:var(--txt); font-weight:600}

/* ---------- 현장 촬영분 취합 ---------- */
.cl-intro{padding:20px 22px; max-width:940px}
.cl-intro h3{font-size:15px; margin-bottom:8px}
.cl-steps{margin:0 0 4px 20px; font-size:13.5px; line-height:1.85; color:var(--sub)}
.cl-steps b{color:var(--txt)}
.cl-rule{min-width:0; width:100%}
.cl-rule td{padding:7px 10px; font-size:13.5px; vertical-align:top}
.cl-rule td:first-child{width:74px; white-space:nowrap}

.cl-sums{display:flex; gap:10px; flex-wrap:wrap; margin-bottom:10px}
.cl-sum{flex:1 1 106px; background:var(--panel); border:1px solid var(--line); border-radius:10px; padding:11px 14px}
.cl-sum .k{font-size:12.5px; color:var(--sub); font-weight:600}
.cl-sum .v{font-size:22px; font-weight:800; letter-spacing:-.02em; margin-top:2px}
.cl-sum.green .v{color:var(--color-ink-0a6249)} .cl-sum.blue .v{color:var(--pri)}
.cl-sum.orange .v{color:var(--warn)} .cl-sum.gray .v{color:var(--faint)}
.cl-note{font-size:12.5px; margin-bottom:14px; display:flex; gap:8px; align-items:center; flex-wrap:wrap}

.cl-list{display:flex; flex-direction:column; gap:12px; padding-bottom:78px}
.cl-grp{padding:14px 16px}
.cl-grp.off{opacity:.5}
.cl-grp-head{display:flex; gap:10px; align-items:center; flex-wrap:wrap}
.cl-on input{width:auto; margin:0; transform:scale(1.25)}
.cl-fac{display:flex; gap:8px; align-items:center; flex-wrap:wrap; font-size:15px}
.cl-need{color:var(--err)}
.cl-meta{margin-left:auto; font-size:12.5px; color:var(--sub); white-space:nowrap}
.cl-why{font-size:13px; color:var(--sub); margin-top:7px}
.cl-alts{display:flex; gap:6px; align-items:center; flex-wrap:wrap; margin-top:8px; font-size:12.5px; color:var(--sub)}
.cl-thumbs{display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; align-items:flex-start}
.cl-th{margin:0; width:132px}
.cl-th .ph{width:132px; height:99px; border-radius:8px; background:var(--color-surface-eef1f5) center/cover no-repeat;
  border:1px solid var(--line); display:flex; align-items:center; justify-content:center;
  font-size:12px; color:var(--faint)}
.cl-th .ph.none{background:var(--color-surface-f7f8fa)}
.cl-th figcaption{font-size:12px; color:var(--sub); margin-top:4px; line-height:1.4;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.cl-more{align-self:center; font-size:13px; color:var(--sub); padding:0 8px}

.cl-bar{position:sticky; bottom:0; margin-top:14px; display:flex; gap:14px; align-items:center;
  justify-content:space-between; flex-wrap:wrap; background:var(--panel); border:1px solid var(--line);
  border-radius:10px; padding:12px 16px; font-size:14px; box-shadow:0 -2px 14px var(--color-shadow-32728f4e63)}

.cl-th{cursor:zoom-in}
.cl-th:hover .ph{border-color:var(--pri)}
.cl-big{text-align:center}
.cl-big img{max-width:100%; max-height:calc(76 * var(--gn-vh,1vh)); border-radius:8px; border:1px solid var(--line)}
.cl-big .ph{padding:60px; color:var(--sub); font-size:13.5px}
.cl-big .cap{margin-top:8px; font-size:12.5px; color:var(--sub); word-break:break-all}

.cl-pick input{width:100%; margin-bottom:10px}
.cl-hits{max-height:calc(52 * var(--gn-vh,1vh)); overflow:auto; border:1px solid var(--line); border-radius:8px}
.cl-hit{display:flex; gap:10px; align-items:center; width:100%; text-align:left; padding:9px 12px;
  background:none; border:none; border-bottom:1px solid var(--line-soft); cursor:pointer; font-size:13.5px}
.cl-hit:hover{background:var(--pri-soft)}
.cl-hit.on{background:var(--pri-soft); font-weight:700}
.cl-hit .sq{min-width:44px; color:var(--faint); font-variant-numeric:tabular-nums}
.cl-hit .nm{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.cl-hit .dp{color:var(--sub); font-size:12.5px; white-space:nowrap}
.cl-errs{margin-top:10px; font-size:12.5px; color:var(--color-ink-8f1d17); max-height:180px; overflow:auto}

/* 시설 위치 보기 — 바탕 지도 없이 좌표만 찍는다 */
.mp-wrap{padding:14px 16px}
.mp-legend{display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:10px}
.mp-lg{display:inline-flex; align-items:center; gap:6px; font-size:13px; cursor:pointer;
  background:var(--color-surface-fff); border:1px solid var(--line); border-radius:16px; padding:4px 11px; color:var(--txt)}
.mp-lg:hover{border-color:var(--pri); background:var(--pri-soft)}
.mp-lg .sw{width:11px; height:11px; border-radius:50%; flex:none; box-shadow:0 0 0 1px var(--color-shadow-c49006b2ff)}
.mp-note{margin-left:auto; font-size:12.5px; color:var(--sub)}
.mp-warn{color:var(--warn)}
/* 화면보다 커지면 스크롤해야 전체가 보인다 — 한눈에 들어오도록 높이를 묶는다 */
.mp-svg{width:100%; height:auto; max-height:calc(calc(100 * var(--gn-vh,1vh)) - 250px); display:block; border-radius:8px}
.mp-bg{fill:var(--color-ink-f7f9fb)}
/* 겹치는 점은 흰 테로 갈라 준다 — 붙어 있으면 몇 개인지 세어지지 않는다 */
.mp-pt{stroke:var(--color-ink-fff); stroke-width:1.5; cursor:pointer; transition:r 120ms var(--e-out,ease)}
.mp-pt:hover{stroke:var(--color-ink-111826); stroke-width:2}
.mp-pt.off{opacity:.16; stroke-width:.8; pointer-events:none}
.mp-dong{fill:var(--color-ink-5c6b7f); font-size:12.5px; font-weight:700; text-anchor:middle; pointer-events:none;
  paint-order:stroke; stroke:var(--color-ink-ffffff); stroke-width:3.5px; stroke-linejoin:round}
.mp-scale line{stroke:var(--color-ink-5c6b7f); stroke-width:1.5}
.mp-scale text{fill:var(--color-ink-5c6b7f); font-size:12px; text-anchor:middle}

/* 분석·보고 — 두 화면을 탭으로 묶는다 */
.an-tabs{margin-bottom:14px}
.ct-h{font-size:15px; font-weight:700; margin:18px 0 8px}
.ct-tbl{min-width:0; width:100%}
.ct-tbl .num{text-align:right}
.ct-tbl tbody tr[data-fid]{cursor:pointer}
.ct-de td{background:var(--color-surface-fdf8f7)}
.ct-warn{color:var(--err); font-weight:700}
.ct-note{font-size:12.5px; color:var(--sub); line-height:1.65; margin-top:8px; max-width:900px}
.ct-empty{padding:22px}
.ct-empty b{font-size:14.5px}
.ct-empty p{margin-top:6px}
.ct-tbl .bar{display:inline-block; width:90px; height:8px; background:var(--line-soft); border-radius:4px; overflow:hidden; vertical-align:middle}
.ct-tbl .bar i{display:block; height:100%; background:var(--pri); border-radius:4px}

/* 변경이력·실적 화면 */
.lg-sums{display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px}
.lg-sum{flex:0 0 150px; background:var(--panel); border:1px solid var(--line); border-radius:10px; padding:11px 16px}
.lg-sum .k{font-size:12.5px; color:var(--sub); font-weight:600}
.lg-sum .v{font-size:24px; font-weight:800; letter-spacing:-.02em; margin-top:2px}
.lg-charts{display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:12px; margin-bottom:14px}
.lg-charts .cbody{max-height:280px; overflow:auto}
.lg-note{font-size:12.5px; color:var(--sub); margin-bottom:8px}
.lg-tbl{min-width:1080px}
.lg-tbl tbody tr{cursor:pointer}
/* 표 칸(td)에는 max-width 가 듣지 않는다. 안에 인라인블록을 하나 두어 거기서 자른다 */
.lg-v{display:inline-block; max-width:230px; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; vertical-align:middle; font-size:13px}
.lg-empty{padding:26px 22px}
.lg-empty b{font-size:14.5px}
.lg-empty p{margin-top:6px}

/* 조사 검토·승인 화면 */
.rv-list{display:flex; flex-direction:column; gap:10px}
.rv-item{padding:14px 16px}
.rv-head{display:flex; gap:10px; align-items:center; flex-wrap:wrap}
.rv-name{font-size:15.5px}
.rv-when{margin-left:auto; font-size:12.5px; color:var(--sub); white-space:nowrap}
.rv-body{display:flex; gap:16px; align-items:center; flex-wrap:wrap; margin-top:10px}
.rv-prog{flex:1; min-width:220px; display:flex; gap:10px; align-items:center; font-size:13px; color:var(--sub)}
.rv-prog .bar{flex:1; height:9px; background:var(--line-soft); border-radius:5px; overflow:hidden; min-width:90px}
.rv-prog .bar i{display:block; height:100%; background:var(--pri); border-radius:5px}
.rv-acts{display:flex; gap:6px; flex-wrap:wrap}
.rv-empty{padding:26px 22px}
.rv-empty b{color:var(--ok); font-size:14.5px}
.rv-empty p{margin-top:6px}

/* 조사 검토·승인 — 지금 무엇을 기다리는 상태인지 문장으로 말한다 */
.sv-pending{font-size:13px; line-height:1.6; margin-bottom:8px; padding:9px 12px; border-radius:8px;
  background:var(--color-surface-fdf7ea); border:1px solid var(--color-line-f0d9a8); color:var(--color-ink-6b4405)}
.sv-reject{font-size:13px; line-height:1.6; margin-bottom:8px; padding:9px 12px; border-radius:8px;
  background:var(--color-surface-fceceb); border:1px solid var(--color-line-f3cfcc); color:var(--color-ink-8f1d17)}

/* 점검 주기 — 자주 쓰는 값 단추. 법정 주기는 프로그램이 정해 주지 않는다 */
.cyc-presets{display:flex; gap:4px; flex-wrap:wrap; margin-top:5px}
.cyc-presets .btn{padding:3px 8px; font-size:12px}

/* 담당 배정 — 아무도 배정되지 않았으면 이 칸 자체가 나오지 않는다 */
.mgr-row{display:flex; gap:20px; align-items:stretch; padding:16px 20px; flex-wrap:wrap}
.mgr-me,.mgr-none{flex:none; min-width:150px; cursor:pointer; padding:2px 0}
.mgr-me .k,.mgr-none .k{font-size:13px; color:var(--sub); font-weight:600}
.mgr-me .v,.mgr-none .v{font-size:30px; font-weight:800; letter-spacing:-.02em; margin-top:2px}
.mgr-me .v{color:var(--pri)}
.mgr-none .v{color:var(--faint)}
.mgr-none.hot .v{color:var(--warn)}
.mgr-me:hover .v,.mgr-none:hover .v{text-decoration:underline}
.mgr-bars{flex:1; min-width:260px; border-left:1px solid var(--line-soft); border-right:1px solid var(--line-soft);
  padding:0 20px; display:flex; flex-direction:column; gap:5px; justify-content:center}
.mgr-b{display:flex; align-items:center; gap:10px; font-size:13px; cursor:pointer}
.mgr-b:hover .lbl{color:var(--pri)}
.mgr-b .lbl{width:96px; flex:none; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--sub)}
.mgr-b .bar{flex:1; height:9px; background:var(--line-soft); border-radius:5px; overflow:hidden}
.mgr-b .bar i{display:block; height:100%; background:var(--pri); border-radius:5px}
.mgr-b .num{width:44px; text-align:right; font-weight:600}

/* 백업 경고 띠 — 문제가 있을 때만 나온다. 늘 떠 있으면 아무도 읽지 않는다 */
.dash-warn{display:flex; align-items:center; gap:12px; flex-wrap:wrap; cursor:pointer;
  padding:13px 18px; margin-bottom:16px; border-radius:10px; font-size:13.5px; line-height:1.5;
  border:1px solid var(--color-line-f0d9a8); background:var(--color-surface-fdf7ea); color:var(--color-ink-6b4405)}
.dash-warn b{font-weight:700; flex:none}
.dash-warn span{min-width:0}
.dash-warn .go{margin-left:auto; font-weight:600; color:var(--pri); white-space:nowrap;
  transition:transform 180ms var(--e-out)}
.dash-warn:hover .go{transform:translateX(3px)}
.dash-warn.danger{border-color:var(--color-line-f3cfcc); background:var(--color-surface-fceceb); color:var(--color-ink-8f1d17)}

/* 그림 판 — 제목·부제·본문·주석의 간격을 정해 둔다 */
.chart-panel{padding:18px 20px 16px}
.chart-panel .ct{font-size:15px; font-weight:700; letter-spacing:-.01em}
.chart-panel .cs{font-size:12.5px; color:var(--sub); margin-top:2px}
.chart-panel .cbody{margin-top:14px}
.chart-panel .cnote{font-size:12.5px; color:var(--sub); margin-top:12px; padding-top:11px; border-top:1px solid var(--line-soft); line-height:1.65}
.bar-row{display:flex; align-items:center; gap:10px; margin:7px 0; font-size:12.5px}
.bar-row .lbl{width:132px; color:var(--sub); text-align:right; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:none}
.bar-row .bar{flex:1; background:var(--color-surface-eef2f7); border-radius:5px; height:18px; overflow:hidden}
.bar-row .bar i{display:block; height:100%; background:var(--pri); border-radius:5px}
.bar-row .num{width:96px; font-size:12.5px; color:var(--txt); font-weight:600; text-align:right; flex:none}
/* 나머지를 하나로 묶은 줄은 회색으로 낮춘다 — 값이 아니라 잔여라는 뜻이다 */
.bar-row.rest .lbl,.bar-row.rest .num{color:var(--faint); font-weight:500}
.bar-row.rest .bar i{background:var(--color-surface-c6d0dc)}

/* ================= v3.7 목록 표 =========================================
   확인 사항은 글자 그대로 둔다. 기호로 줄이면 뜻을 매번 범례에서 찾아야 해
   읽는 품이 오히려 늘어난다. 대신 급한 것을 왼쪽에 놓아 잘려도 중요한 것이
   먼저 보이게 하고, 배지가 줄바꿈으로 행 높이를 흔들지 않게 한 줄로 묶는다.
   ====================================================================== */
.tbl td.flags{white-space:nowrap; max-width:340px; overflow:hidden; text-overflow:ellipsis}
/* 배지가 든 행만 3px 커져 448행이 들쭉날쭉해진다. 줄 높이를 낮추고 가운데로 맞춰
   배지가 줄 상자를 밀어 올리지 못하게 한다 */
.tbl td{line-height:1.4}
/* 창이 좁아지면 주소·용도가 두 줄로 접히며 행 높이가 제각각이 된다.
   표에는 최소 폭을 주어 접히지 않게 하고, 그보다 좁으면 가로로 밀어 본다.
   글자를 자르는 것보다 미는 편이 읽기에 낫다. */
table.tbl{min-width:1180px}
.tbl td,.tbl th{white-space:nowrap}
/* 시설명은 자르지 않는다 — 이름이 잘리면 목록의 쓸모가 없다.
   긴 이름 몇 건은 두 줄이 되지만 그 행만 3px 높아질 뿐이다 */
.tbl td:nth-child(2){white-space:normal; min-width:215px}
.tbl .badge{vertical-align:middle; line-height:1.45}
.tbl .cnt-dot{vertical-align:middle}
.tbl tbody tr{transition:background 140ms var(--e-out), transform var(--d-press) var(--e-out)}
.tbl tbody tr:active{transform:scale(.997)}

/* ================= v3.7 글씨 크기 조절 =================================
   메뉴 속에 묻으면 정작 필요한 사람이 못 찾는다. 사이드바 아래에 늘 보이게 둔다.
   ====================================================================== */
.textsize{padding:10px 12px; border-top:1px solid var(--color-line-b34d3e7911)}
.textsize .tl{font-size:12px; color:var(--color-ink-8ba5bd); margin-bottom:6px}
.textsize .tg{display:flex; gap:4px}
.textsize button{flex:1; background:var(--color-surface-c201d2dab2); border:1px solid var(--color-line-06ff57dd04);
  color:var(--color-ink-cfdcea); border-radius:6px; padding:6px 0; cursor:pointer; line-height:1;
  transition:background 150ms var(--e-out), color 150ms var(--e-out)}
.textsize button:hover{background:var(--color-surface-57c94231f5); color:var(--color-ink-fff)}
.textsize button.on{background:var(--color-surface-fff); border-color:var(--color-line-fff); color:var(--gn-dark); font-weight:700}
.textsize .tg:not(.mo) button:nth-child(1){font-size:12px}
.textsize .tg:not(.mo) button:nth-child(2){font-size:15px}
.textsize .tg:not(.mo) button:nth-child(3){font-size:18px}
.textsize .tg.mo button{font-size:12.5px; padding:5px 0}
.textsize .tn{font-size:12px; color:var(--color-ink-93aac2); margin-top:6px; line-height:1.5}

/* ================= v3.7 확대·축소 전환 ==================================
   누른 자리에서 자라나고 그 자리로 줄어든다. 열려 있는 동안 원본 자리는
   눌린 상태로 두어, 지금 보고 있는 것이 어디서 나왔는지 남긴다.
   ====================================================================== */
.zoom-src{opacity:.35; transform:scale(.97); transition:opacity 200ms var(--e-out), transform 200ms var(--e-out)}
/* 누르는 순간의 반응 — 애플 기기와 같은 폭(4%)·시간(90ms)으로 맞춘다 */
.stat:active,.todo:active,.fac-card:active,.asset-card:active,.chip:active,.tab:active{
  transform:scale(.97); transition:transform var(--d-press) var(--e-out)}
.asset-thumb{transition:transform 240ms var(--e-out)}
.asset-card:hover .asset-thumb{transform:scale(1.03)}
.asset-card{transition:box-shadow 180ms var(--e-out), border-color 150ms var(--e-out), transform var(--d-press) var(--e-out)}
.asset-card:hover{box-shadow:var(--shadow-md); border-color:var(--color-line-cfdae7)}
/* ---------- 화면 전환 ----------
   본문만 바뀌고 사이드바는 제자리에 있어야 «같은 앱 안에서 이동했다»로 읽힌다.
   화면 전환 API 는 쓰지 않는다 — 448행 표가 든 본문을 통째로 스냅숏 떠서 겹치느라
   전환 내내 프레임의 37%가 유실됐다(같은 조건에서 밝기·이동만 쓰면 4.6%).
   깊이가 늘면(목록 → 상세) 오른쪽에서, 줄면 왼쪽에서 들어온다. 움직임은 22px 이다.
   실제 전환은 ui.js 의 pageSwap 이 걸고, 여기서는 「줄임·끔」만 다룬다. */

/* 「줄임」 — 움직임 없이 밝기만. 화면이 흔들리는 것이 불편한 사람용 */
html[data-motion=less] .stat:hover,html[data-motion=less] .asset-card:hover .asset-thumb,
html[data-motion=less] .stat:active,html[data-motion=less] .todo:active{transform:none}
html[data-motion=less] .card{animation:none}
/* 「끔」 — 즉시 바뀐다. 사양이 낮은 PC 나 하루 종일 쓰는 사람용 */
html[data-motion=off] *,html[data-motion=off] *::before,html[data-motion=off] *::after{
  animation-duration:.01ms !important; animation-delay:0s !important; transition-duration:.01ms !important}
html[data-motion=off]::view-transition-old(gnmain),
html[data-motion=off]::view-transition-new(gnmain){animation:none}
/* 누른 자리 — «여기서 나갔다»를 한 번 알린다. 눈이 그 자리를 붙잡고 있어야
   거기서 자라나는 화면이 같은 물체로 읽힌다. */
@keyframes navPop{0%{transform:scale(1)} 30%{transform:scale(.94)} 100%{transform:scale(1)}}
#sidebar nav a.zoom-out,.recent-list a.zoom-out{animation:navPop 480ms var(--e-snappy)}
#sidebar nav a.zoom-out{background:var(--pri); color:var(--color-ink-fff)}
/* 표의 행은 폭이 넓어 눌러도 티가 안 난다. 눌린 줄을 잠깐 물들여 둔다 */
@keyframes rowPick{0%{background:var(--pri-soft)} 100%{background:var(--pri-soft)}}
.tbl tbody tr.zoom-out{animation:rowPick 480ms linear}
.stat.zoom-out,.todo.zoom-out,.hero.zoom-out,.fac-card.zoom-out{animation:navPop 480ms var(--e-snappy)}

/* ================= v3.7 인쇄 ===========================================
   점 네 개는 흑백 종이에서 구분되지 않는다. 인쇄할 때만 글자로 펼친다.
   ====================================================================== */
@media print{
  body{background:var(--color-surface-fff); font-size:10pt; overflow:visible}
  #sidebar,.toolbar,.chips,.textsize,.page-head button,.tabs{display:none !important}
  #app,#main{display:block; height:auto; overflow:visible; padding:0}
  .card,.tbl-wrap{box-shadow:none !important; border-color:var(--color-line-999)}
  .tbl-wrap{max-height:none; overflow:visible}
  .tbl th{background:var(--color-surface-eee) !important; -webkit-print-color-adjust:exact; print-color-adjust:exact}
  .tbl td,.tbl th{height:auto; padding:4px 6px}
  tr{break-inside:avoid}
  /* 종이에서는 색이 옅은 배지가 사라진다. 테두리를 넣어 글자가 살아 있게 한다 */
  .badge{border:1px solid var(--color-line-999) !important; background:var(--color-surface-fff) !important; color:var(--color-ink-000) !important}
}

/* 닫히는 중인 창 — modal-* 이름을 뗀 뒤에도 줄어드는 동안 생김새는 그대로여야 한다.
   «지금 열려 있는 창»을 묻는 쪽에는 잡히지 않으면서 화면에서는 자연스럽게 사라진다. */
.mg-back{position:fixed; inset:0; background:var(--color-surface-973d84be42); z-index:9000;
  display:flex; align-items:center; justify-content:center; padding:24px; pointer-events:none}
.mg{background:var(--color-surface-fff); border-radius:14px; max-height:calc(94 * var(--gn-vh,1vh)); display:flex; flex-direction:column;
  box-shadow:var(--shadow-lg); min-width:340px; overflow:hidden}
.mg.wide{width:min(1280px,calc(96 * var(--gn-vw,1vw)))}
.mg.full{width:calc(96 * var(--gn-vw,1vw)); height:calc(94 * var(--gn-vh,1vh))}
.mg-head{display:flex; align-items:center; justify-content:space-between; padding:12px 16px; border-bottom:1px solid var(--line)}
.mg-body{padding:14px 16px; overflow:hidden; flex:1}
.mg-foot{padding:10px 16px; border-top:1px solid var(--line); display:flex; justify-content:flex-end; gap:8px}

/* ── 도면 일괄 가져오기 (v3.9) ─────────────────────────────── */
.dg-path{font-size:12.5px; color:var(--sub); margin-bottom:10px; word-break:break-all}
.dg-bar{display:flex; justify-content:space-between; align-items:center; gap:12px;
  margin-bottom:12px; flex-wrap:wrap}
.dg-note{color:var(--sub); font-size:13px; line-height:1.65; margin:10px 0 0}
.dg-note code{background:var(--color-surface-eef1f5); padding:1px 5px; border-radius:4px; font-size:12px}
.dg-tbl td{vertical-align:middle}
.dg-tbl .s{color:var(--sub); font-size:12px; margin-top:2px}
.dg-tbl tr.dg-dim td{background:var(--color-surface-f6f9fd)}
.dg-tbl input[type=checkbox]{width:17px; height:17px; cursor:pointer}

/* ── 성능지표 사전 (v3.9) ─────────────────────────────── */
.pf-cards{display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px}
.pf-card{flex:1 1 170px; background:var(--panel); border:1px solid var(--line);
  border-radius:10px; padding:11px 14px}
.pf-card.pf-old{border-color:var(--color-line-e0a96d)}
.pf-card .k{font-size:12.5px; color:var(--sub); font-weight:600}
.pf-card .v{font-size:26px; font-weight:800; letter-spacing:-.02em; margin-top:2px}
.pf-card .s{font-size:12px; color:var(--sub); margin-top:3px}
.pf-note{font-size:12.5px; color:var(--sub); line-height:1.7; margin:10px 0 0}
.pf-warn{background:var(--color-surface-fdf3e8); border-left:3px solid var(--color-line-e0a96d); padding:8px 12px; border-radius:0 6px 6px 0}
.pf-bar{display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-bottom:10px}
.pf-tabs{display:flex; gap:6px}
.pf-filters{display:flex; gap:6px; flex-wrap:wrap}
.pf-filters select,.pf-filters input{height:32px; font-size:13px; border:1px solid var(--line);
  border-radius:7px; padding:0 9px; background:var(--color-surface-fff)}
.pf-filters input{min-width:190px}
.pf-count{font-size:12.5px; color:var(--sub); margin-bottom:8px}
.pf-tbl{table-layout:fixed; width:100%}
.pf-tbl th{white-space:normal; line-height:1.35}
.pf-tbl td{white-space:normal; vertical-align:top; word-break:break-word; overflow-wrap:anywhere; padding-top:9px; padding-bottom:9px; height:auto}
.pf-ind th:nth-child(1),.pf-ind td:nth-child(1){width:9%}
.pf-ind th:nth-child(2),.pf-ind td:nth-child(2){width:9%}
.pf-ind th:nth-child(3),.pf-ind td:nth-child(3){width:12%}
.pf-ind th:nth-child(4),.pf-ind td:nth-child(4){width:9%}
.pf-ind th:nth-child(5),.pf-ind td:nth-child(5){width:29%}
.pf-ind th:nth-child(6),.pf-ind td:nth-child(6){width:7%}
.pf-ind th:nth-child(7),.pf-ind td:nth-child(7){width:25%}
.pf-chk th:nth-child(1),.pf-chk td:nth-child(1){width:9%}
.pf-chk th:nth-child(2),.pf-chk td:nth-child(2){width:9%}
.pf-chk th:nth-child(3),.pf-chk td:nth-child(3){width:11%}
.pf-chk th:nth-child(4),.pf-chk td:nth-child(4){width:10%}
.pf-chk th:nth-child(5),.pf-chk td:nth-child(5){width:20%}
.pf-chk th:nth-child(6),.pf-chk td:nth-child(6){width:27%}
.pf-chk th:nth-child(7),.pf-chk td:nth-child(7){width:14%}
.pf-tbl .pf-detail td{width:auto}
.pf-tbl .mono{font-family:ui-monospace,Menlo,Consolas,monospace; font-size:12.5px; white-space:nowrap}
.pf-tbl .s{color:var(--sub); font-size:12px; margin-top:2px}
.pf-r{cursor:pointer}
.pf-r:hover td{background:var(--color-surface-f6f9fd)}
.pf-detail td{background:var(--color-surface-f6f9fd); padding:12px 14px}
.pf-d{margin-bottom:9px}
.pf-d b{font-size:12.5px; color:var(--sub)}
.pf-d p{margin:3px 0 0; font-size:13px; line-height:1.6}
.pf-crit p{color:var(--color-ink-8f1d17)}
.pf-grades{display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:6px; margin-top:8px}
.pf-g{display:flex; gap:8px; align-items:flex-start; font-size:12.5px; line-height:1.55}

.dm-card table.tbl{min-width:0;width:100%;table-layout:fixed}.dm-card .tbl td,.dm-card .tbl th{white-space:normal;overflow-wrap:anywhere}.dm-card .tbl td:nth-child(2){min-width:0}.dm-card table.dm-users-table{min-width:720px;table-layout:auto}.dm-card .ab-tbl th{width:110px}

/* 3.22.0: UI modal opened from a native drawing dialog stays in the top layer. */
/* B2: 폭·높이는 inset:0으로 화면에 맞춤(100vw는 화면 배율 1.1에서 한 번 더 커져 창이 오른쪽으로 96px 치우침) */
dialog.modal-back,dialog.mg-back{margin:0;inset:0;width:auto;height:auto;max-width:none;max-height:none;border:0;color:inherit}
/* B2: 큰 도면 창(.bv-dialog)도 화면 가운데에(전체 초기화 *{margin:0} 때문에 왼쪽 위에 붙어 있었음 — 3.21.0부터) */
dialog.bv-dialog{margin:auto}
dialog.modal-back::backdrop,dialog.mg-back::backdrop{background:transparent}
