.b03-file { min-height: calc(100vh - var(--app-header-height, 0px)); background: linear-gradient( 180deg, var(--color-canvas, #ffffff) 0%, var(--color-mist-violet, #edecff) 100% ); padding: 0 var(--spacing-24) var(--spacing-48) var(--spacing-24); /* 상단 여백은 main-layout 마진으로 조정하므로 padding-top은 0 */ } .b03-file__main-layout { max-width: var(--page-max-width, 1200px); margin: var(--spacing-40) auto 0 auto; /* 상단 구분선(헤더)과의 간격을 확실하게 40px 벌림 */ display: flex; flex-direction: column; gap: var(--spacing-32); /* ⚠ flex 자식은 기본이 `min-width: auto` 라 **내용보다 안 줄어든다** — 그래서 안쪽 격자가 넘치면 페이지 몸통이 통째로 가로로 밀렸다(2026-09-08). 여기서 끊는다. */ min-width: 0; } .b03-file__main-layout > * { min-width: 0; } .b03-file__control-panel { display: flex; flex-direction: column; gap: var(--spacing-16); background: var(--color-canvas, #ffffff); /* 여백 32 → 16 (2026-09-03) — 고르는 자리만 남기고 안내를 좌측 패널로 뺐다. `--spacing-20`은 테마에 없는 토큰이라 선언째 무효가 된다(패딩이 통째로 사라짐). */ padding: var(--spacing-16); border-radius: var(--radius-large, 24px); /* Wiza 24px 대형 둥글기 */ border: 1px solid var(--color-mist, #e6e2e3); box-shadow: var(--shadow-lg); } .b03-file__cards-container-panel { margin-top: 0; /* 단일 layout gap에 의해 제어되도록 설정 */ } .b03-file__subtitle { font-size: var(--text-body-sm, 14px); color: var(--color-slate, #615e6e); margin: 0 0 var(--spacing-8) 0; } .b03-file__native-input, .b03-file__slot-input { display: none; } /* Wiza 스타일 가이드의 Lavender Glow 그라데이션 및 soft purple border hover */ /* 고르는 자리 한 줄 — [입력 파일 선택] · [임시 보관함] · [파일 업로드](2026-09-03). 좁아지면 아래로 접히되, 선택 영역이 남는 폭을 먹는다. */ /* 셋을 같은 폭·같은 높이로 나눈다 — 열 1:1:1(2026-09-03 사용자 지시). flex 로는 버튼·드롭존의 내용 폭이 배분에 섞여 288·254·288 로 어긋났다. 격자는 칸을 먼저 나누므로 내용과 무관하게 정확히 1:1:1 이 된다. 좁아지면 칸이 접힌다. */ .b03-file__pick-row { display: grid; /* ⚠ 좁은 폭에서는 200px 도 넘친다 — `min(200px, 100%)` 로 컨테이너까지만 줄인다. */ grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); align-items: stretch; gap: var(--spacing-8); } .b03-file__pick-row > * { min-width: 0; } /* 칸을 꽉 채워야 세 칸의 높이가 같아진다 — 버튼은 기본이 내용 크기다. */ .b03-file__pick-row .b03-file__temp-picker > .ui-btn, .b03-file__pick-row > .ui-btn { width: 100%; height: 100%; } /* 한 줄 바(2026-09-03) — 종전 160px 블록은 안내 문구를 담느라 컸다. 문구는 좌측 패널로 갔으므로 여기는 「끌어 놓거나 눌러서 고르는 자리」 표시만 한다. */ .b03-file__dropzone { padding: var(--spacing-12) var(--spacing-16); border: 1px dashed var(--color-mist, #e6e2e3); border-radius: var(--radius-cards, 8px); background: var(--color-paper, #f6f7fa); display: flex; flex-direction: row; flex-wrap: wrap; align-items: baseline; justify-content: center; gap: var(--spacing-8); cursor: pointer; text-align: center; transition: background var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s), box-shadow var(--transition-base, 0.2s); } .b03-file__dropzone:hover { background: var(--color-mist-violet, #edecff); border-color: var(--color-royal-amethyst, #3e0079); } .b03-file__dropzone:focus-visible, .b03-file__dropzone.is-dragging { outline: none; background: var(--color-mist-violet, #edecff); border-color: var(--color-royal-amethyst, #3e0079); box-shadow: 0 0 0 4px rgba(62, 0, 121, 0.15); } .b03-file__dropzone strong { color: var(--color-deep-iris, #26114a); font-size: var(--text-body-sm, 14px); font-weight: var(--font-weight-medium, 500); } .b03-file__dropzone span { font-size: var(--text-body-sm, 14px); color: var(--color-slate, #615e6e); } /* 빈 오류 줄이 자리를 잡고 있으면 토글 아래가 통째로 비어 보인다 — 글자가 있을 때만 자리를 차지한다(2026-09-03 사용자 지시). */ .b03-file__error { color: var(--color-danger, #dc2626); font-size: var(--text-body-sm, 14px); margin: 0; } .b03-file__error:empty { display: none; } .b03-file__resume { display: none; align-items: center; gap: var(--spacing-8); flex-wrap: wrap; padding: var(--spacing-12) var(--spacing-16); border: 1px solid var(--color-mist, #e6e2e3); border-radius: var(--radius-cards, 8px); background: var(--color-paper, #f6f7fa); color: var(--color-deep-iris, #26114a); font-size: var(--text-body-sm, 14px); margin-top: var(--spacing-8); } .b03-file__resume.is-visible { display: flex; } /* 재접속 현황(서버 정본) 배너 — 완료 안내와 중단 세션 이어올리기 안내를 담는다. */ .b03-file__overview { display: none; flex-direction: column; gap: var(--spacing-4); margin-top: var(--spacing-8); padding: var(--spacing-12) var(--spacing-16); border: 1px solid var(--color-border); border-radius: var(--radius-cards, 8px); background: var(--color-surface); font-size: var(--text-body-sm, 14px); } .b03-file__overview.is-visible { display: flex; } .b03-file__overview-complete { margin: 0; color: var(--color-success, #3fbb6f); font-weight: 600; } .b03-file__overview-pending { margin: 0; color: var(--color-text-secondary); } /* 잠금 표시 — 지금 누가 올리는 중인지. 막힌 까닭이라 눈에 띄게 둔다. */ .b03-file__overview-lock { margin: 0; color: var(--color-warning, #d98324); font-weight: 600; } /* 완료 슬롯 재업로드 확인 모달 — 페이지 위를 덮는 단순 확인창. */ .b03-file__modal-backdrop { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; background: rgb(0 0 0 / 45%); } .b03-file__modal { display: flex; flex-direction: column; gap: var(--spacing-12); max-width: 420px; padding: var(--spacing-24); border: 1px solid var(--color-border); border-radius: var(--radius-cards, 8px); background: var(--color-surface-raised); box-shadow: 0 12px 32px rgb(0 0 0 / 30%); } .b03-file__modal p { margin: 0; color: var(--color-text-secondary); white-space: pre-line; } .b03-file__modal-actions { display: flex; gap: var(--spacing-8); justify-content: flex-end; } .b03-file__cards-grid { display: grid; grid-template-columns: 1fr; gap: var(--spacing-32); } /* 계획노선 | 지형(LAS) — 컨테이너를 둘로 나눈다(2026-08-31 사용자 지시). 노선은 카드 5장(shapefile 한 벌), 지형은 4장이라 폭을 5:4 비슷하게 준다. ⚠ **좁아지면 한 줄로 접는다**(2026-09-08 사용자 지적) — 2열을 고정하면 좁은 폭에서 각 열이 카드 하나도 못 담아 내용이 컨테이너 밖으로 넘치고 글자가 안 읽혔다. `auto-fit` + `min(360px, 100%)` 이라, 폭이 모자라면 칸 수가 스스로 1로 줄고 **최소폭이 컨테이너를 넘지 않는다**(고정 minmax 는 그 아래에서 넘친다). */ .b03-file__columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr)); gap: var(--spacing-16); align-items: start; } /* LAS 없이 설계 토글 — 파일 입력 컨테이너의 스위치(2026-09-03 사용자 지시). B04 좌측 패널의 체크 줄(`b04-surface__check`)과 같은 서식이다. */ .b03-file__lasfree { display: flex; align-items: center; gap: var(--spacing-8); align-self: flex-start; padding: var(--spacing-8) var(--spacing-12); border: 1px solid var(--color-mist, #e6e2e3); border-radius: var(--radius-buttons, 8px); font-size: var(--text-body-sm, 14px); color: var(--color-deep-iris, #26114a); cursor: pointer; transition: border-color var(--transition-base, 0.2s); } .b03-file__lasfree:hover { border-color: var(--color-royal-amethyst, #3e0079); } .b03-file__lasfree input { width: 16px; height: 16px; margin: 0; accent-color: var(--color-royal-amethyst, #3e0079); cursor: pointer; } /* 켜져 있으면 스위치 자신도 켜진 티를 낸다 — 지형 컨테이너가 왜 잠겼는지의 근거. */ .b03-file__lasfree:has(input:checked) { border-color: var(--color-royal-amethyst, #3e0079); background: var(--color-mist-violet, #edecff); font-weight: var(--font-weight-medium, 500); } /* LAS 없이 설계를 켜면 지형 컨테이너는 받지 않는다 — 잠긴 것이 보이게 흐린다. */ .b03-file__group--disabled { opacity: 0.55; } .b03-file__card--disabled { background: var(--color-paper, #f6f7fa); border-style: dashed; } .b03-file__card--disabled .b03-file__card-select { cursor: not-allowed; } /* 좌측 안내 패널이 열리면 본문을 그만큼 밀어낸다 — 공용 워크플로 레이아웃(B04·B05)의 `.ui-workflow-layout__body` 규칙과 같은 값. 접히면 손잡이 폭만 남긴다. */ .b03-file__main-layout { transition: padding-left var(--transition-base); } .b03-file.is-options-open .b03-file__main-layout { padding-left: min(var(--wf-left-panel-width), calc(100vw - var(--spacing-48))); } .b03-file:not(.is-options-open) .b03-file__main-layout { padding-left: var(--spacing-24); } @media (max-width: 860px) { .b03-file.is-options-open .b03-file__main-layout { padding-left: 0; } } /* --- 좌측 안내 패널 (2026-09-03) — 본문에서 뺀 설명이 사는 자리. 양식은 B04~B07 좌측 패널과 **같은 공용 양식**이다: 루트 `__form`, 문단은 `ui-collapsible ui-sidebar-section`(외곽선·접힘·캐럿은 공용 CSS 몫), 제목은 `__group-legend` 크기. 여기서는 값만 맞추고 새로 만들지 않는다. --- */ .b03-file__form { display: flex; flex-direction: column; gap: var(--spacing-16); padding: var(--spacing-16); } .b03-file__guide-group { display: flex; flex-direction: column; gap: var(--spacing-8); margin: 0; padding: var(--spacing-16); border-radius: var(--radius-cards); background-color: var(--color-surface-raised); } .b03-file__guide-legend { margin: 0; padding: 0 var(--spacing-8); font-size: var(--text-caption); font-weight: var(--font-weight-medium); color: var(--color-text-secondary); } /* 글자 크기·색도 공용 양식 그대로 — B04 좌측 패널 본문(`b04-surface__check`)과 같은 `--text-body-sm` · `--color-text-body`(2026-09-03 사용자 지시: 양식 = 글자 크기 포함). */ .b03-file__guide-list { margin: 0; padding-left: var(--spacing-16); display: flex; flex-direction: column; gap: var(--spacing-4); font-size: var(--text-body-sm); color: var(--color-text-body); } .b03-file__group { display: flex; flex-direction: column; gap: var(--spacing-12); } .b03-file__group-hint { font-size: var(--text-body-sm, 14px); color: var(--color-slate, #615e6e); margin: calc(var(--spacing-8) * -1) 0 0 0; } /* 제목 24px → 본문 크기(2026-09-03) — 컨테이너가 둘뿐이라 큰 제목이 자리만 먹었다. */ .b03-file__group-title { font-size: var(--text-body, 16px); color: var(--color-deep-iris, #26114a); font-family: var(--font-britti-sans, inherit); margin: 0; } /* 카드가 좁아지면 한 줄에 제목·상태·[선택]이 못 들어가 제목이 글자 단위로 접힌다 (2026-09-03 실측: 안내 패널을 연 상태에서 카드 폭 210px). 폭이 모자라면 열을 줄인다. */ /* ⚠ `minmax(260px, …)` 는 **칸이 260px 보다 좁아질 수 없다**는 뜻이라, 컨테이너가 그보다 좁아지면 카드가 밖으로 넘친다(2026-09-08 좁은 폭 실측). `min(260px, 100%)` 으로 두면 좁을 때 **컨테이너 폭까지 줄어들어** 넘치지 않는다. */ .b03-file__group-content { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: var(--spacing-12); } /* 업로드 중에는 화면 조작을 막는다 — 중복 업로드·단계 이동 방지(2026-08-08 사용자 지시). */ .b03-file--busy { pointer-events: none; } .b03-file--busy .b03-file__card-select, .b03-file--busy .b03-file__card-remove, .b03-file--busy .b03-file__dropzone { opacity: 0.5; } /* 업로드 버튼 안에서 도는 원 — 공용 스피너를 버튼 글자 크기에 맞춰 줄인다. */ .b03-file__upload-spinner { width: 14px; height: 14px; border-width: 2px; border-color: rgb(255 255 255 / 40%); border-top-color: var(--color-primary-text); } /* Wiza 8px radius 카드 */ /* 카드 한 장 = 파일 한 칸. 빈 칸은 **한 줄**로 끝난다(2026-09-03 사용자 지시) — 파일이 붙거나 올라가는 중에만 아래 내용(파일명·진행바)이 펼쳐진다. */ .b03-file__card { padding: var(--spacing-12) var(--spacing-16); border: 1px solid var(--color-mist, #e6e2e3); border-radius: var(--radius-cards, 8px); background: var(--color-canvas, #ffffff); box-shadow: var(--shadow-sm); display: flex; flex-direction: column; gap: var(--spacing-8); transition: transform var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s), box-shadow var(--transition-base, 0.2s); } .b03-file__card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); border-color: var(--color-royal-amethyst, #3e0079); } .b03-file__card--selected { border-color: var(--color-royal-amethyst, #3e0079); background: var(--color-paper, #f6f7fa); } .b03-file__card--uploading { border-color: var(--color-royal-amethyst, #3e0079); box-shadow: var(--shadow-lg-2); } .b03-file__card--completed { border-color: #10b981; /* Success Green */ } .b03-file__card--error { border-color: var(--color-danger, #dc2626); } /* 카드가 좁아졌다(컨테이너 2열 × 카드 2열, 2026-08-31). 격자로 고정하면 제목이 글자 단위로 접히므로, 자리가 모자라면 배지·삭제 버튼이 다음 줄로 내려가게 한다. */ /* 제목·상태·[선택]이 **한 줄**에 선다(2026-09-03) — 줄바꿈을 허용하면 [선택]이 아래로 내려가 카드가 두 줄이 됐다. 자리가 모자라면 제목이 줄어든다(min-width: 0). */ /* ⚠ 좁은 폭에서 배지·[선택]·[×] 가 밀려 나가지 않게 **줄 자체가 넘치지 않도록** 막는다 (2026-09-08). 제목은 이미 말줄임이라, 넘치는 것은 늘 오른쪽 붙박이들이었다. */ .b03-file__card-header { display: flex; flex-wrap: nowrap; gap: var(--spacing-8); align-items: center; min-width: 0; max-width: 100%; } .b03-file__card-header > * { min-width: 0; } .b03-file__card-icon { flex: 0 0 auto; width: 28px; height: 28px; border-radius: var(--radius-icons, 8px); display: inline-flex; align-items: center; justify-content: center; color: var(--color-royal-amethyst, #3e0079); background: var(--color-mist-violet, #edecff); font-size: var(--text-body-sm, 14px); margin-right: var(--spacing-8); /* 아이콘 우측 마진 추가 (아이콘 좌측 여유 확대 효과) */ } .b03-file__card-heading { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: 1px; } .b03-file__card-label { color: var(--color-deep-iris, #26114a); font-size: var(--text-body-sm, 14px); font-weight: var(--font-weight-medium, 500); /* 제목은 한 줄로 두고 모자라면 말줄임 — 접히면 카드가 세로로 길어진다(2026-09-03). */ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .b03-file__card-ext, .b03-file__file-size, .b03-file__progress-info { color: var(--color-slate, #615e6e); font-size: var(--text-caption, 12px); } .b03-file__card-badge-container { display: flex; align-items: center; margin-left: auto; margin-right: var(--spacing-4); } .b03-file__card-remove { width: 24px; height: 24px; border: 1px solid var(--color-mist, #e6e2e3); border-radius: var(--radius-buttons, 8px); color: var(--color-slate, #615e6e); background: var(--color-canvas, #ffffff); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: var(--text-body-sm, 14px); line-height: 1; padding: 0; margin-left: var(--spacing-8); /* 취소 버튼 좌측 여유 추가 (취소 버튼 우측 여유 확보) */ transition: all var(--transition-base, 0.2s); } .b03-file__card-remove:hover { color: var(--color-danger, #dc2626); border-color: var(--color-danger, #dc2626); background: #fef2f2; } .b03-file__card-content { display: flex; flex-direction: column; gap: var(--spacing-8); } /* 빈 칸은 제목 줄만 남긴다 — 파일이 붙으면 이름·크기가, 올라가는 중에는 진행바가 선다. */ .b03-file__card--empty .b03-file__card-content { display: none; } /* [선택]은 제목 줄 오른쪽 끝의 작은 버튼 — 종전 전폭 40px 버튼이 카드 높이를 키웠다. */ .b03-file__card-select { flex: 0 0 auto; min-height: 26px; padding: 0 var(--spacing-8); border: 1px solid var(--color-mist, #e6e2e3); border-radius: var(--radius-buttons, 8px); color: var(--color-deep-iris, #26114a); background: var(--color-canvas, #ffffff); font-weight: var(--font-weight-medium, 500); font-size: var(--text-caption, 12px); white-space: nowrap; cursor: pointer; transition: background var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s); } .b03-file__file-info { display: flex; flex-direction: column; gap: 4px; min-width: 0; } .b03-file__file-name { color: var(--color-deep-iris, #26114a); font-size: var(--text-body-sm, 14px); font-weight: var(--font-weight-medium, 500); overflow-wrap: anywhere; } /* 진행바·속도·예상완료는 **올라가는 동안만** 보인다(2026-09-03) — 끝난 카드에 남겨 두면 읽을 일 없는 세 줄이 카드 높이를 그대로 차지했다. */ .b03-file__progress-section { display: none; flex-direction: column; gap: var(--spacing-8); } .b03-file__card--uploading .b03-file__progress-section { display: flex; } .b03-file__progress-bar-container { width: 100%; height: 6px; overflow: hidden; border-radius: var(--radius-pills, 1440px); background: var(--color-mist, #e6e2e3); } .b03-file__progress-bar { width: 0; height: 100%; border-radius: var(--radius-pills, 1440px); background: var(--color-royal-amethyst, #3e0079); transition: width var(--transition-base, 0.2s); } .b03-file__progress-info { display: flex; flex-direction: column; gap: 2px; } .b03-file__error-message { display: none; padding: var(--spacing-8) var(--spacing-12); border-radius: var(--radius-cards, 8px); color: var(--color-danger, #dc2626); background: #fef2f2; font-size: var(--text-caption, 12px); border: 1px solid rgba(220, 38, 38, 0.15); } .b03-file__card--empty .b03-file__file-info, .b03-file__card--empty .b03-file__preview, .b03-file__card--empty .b03-file__progress-section, .b03-file__card--empty .b03-file__error-message { display: none; } /* 업로드 자료 미리보기(2026-09-04) — 분석 메타데이터의 범위만으로 그리는 작은 도형. 값이 없으면 `is-visible` 이 안 붙어 자리를 차지하지 않는다. */ .b03-file__preview { display: none; margin-top: 6px; } /* 카드 한 행을 전부 쓰고 높이는 고정한다 (2026-09-04 사용자 지시) — 카드 높이가 파일마다 들쭉날쭉하지 않게. 그림·썸네일·값 표시가 모두 같은 상자를 쓴다. */ .b03-file__preview.is-visible { display: flex; grid-column: 1 / -1; align-items: center; justify-content: center; width: 100%; height: 120px; overflow: hidden; border: 1px solid var(--color-border, #dcdce6); border-radius: var(--radius-cards, 8px); background: var(--color-surface, #fff); } .b03-file__preview svg { display: block; width: 100%; height: 100%; } /* 라이다 탑뷰 점 그림 — 점이 5천 개라 선 하나로 묶어 그린다. */ .b03-file__preview-cloud { fill: none; stroke: var(--color-text-muted, #5a5a72); stroke-linecap: round; stroke-opacity: 0.55; stroke-width: 0.7; } /* GeoTIFF 저해상 썸네일 — 원본 비율을 지켜 상자 안에 맞춘다. 썸네일이 곧 자료 범위라 다른 그림의 점선 사각형과 같은 테두리를 둘러 셋이 같은 모양으로 보이게 한다 (2026-09-04 사용자 지적). */ .b03-file__preview-thumb { max-width: 100%; max-height: 100%; border: 1px dashed var(--color-border, #9aa); image-rendering: pixelated; object-fit: contain; } /* 그릴 도형이 없는 부속 파일 — 구분되는 값을 큰 글씨로. */ .b03-file__preview-facts { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px; text-align: center; } .b03-file__preview-fact { color: var(--color-text, #1c1c28); font-size: var(--text-body, 15px); font-weight: 600; } .b03-file__preview-fact-sub { color: var(--color-text-muted, #5a5a72); font-size: var(--text-caption, 12px); } .b03-file__preview-empty { color: var(--color-text-muted, #8a8aa0); font-size: var(--text-caption, 12px); } .b03-file__preview-extent { fill: color-mix(in srgb, var(--color-border, #9aa) 12%, transparent); stroke: var(--color-border, #9aa); stroke-dasharray: 4 3; stroke-width: 1; } .b03-file__preview-route { fill: none; /* 계획노선 선 색 — 녹색(2026-09-04 사용자 지시). 지형 범위를 벗어나면 아래에서 붉은색으로 덮어써 경고로 쓴다. */ stroke: var(--color-success, #16a34a); stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.5; } /* 계획노선이 지형 자료 범위를 벗어난 경우 — 눈으로 바로 잡히게 경고색. */ .b03-file__preview.is-warning .b03-file__preview-route { stroke: var(--color-danger, #d33); } .b03-file__preview.is-warning .b03-file__preview-extent { stroke: var(--color-danger, #d33); stroke-dasharray: 3 2; } .b03-file__card--selected .b03-file__progress-section { display: none; } /* 올리는 중에만 [파일 선택]을 감춘다. 끝난 카드에도 남겨 두어야 파일 하나를 갈아 끼우고 [파일 업로드]로 다시 돌릴 수 있다(2026-09-04 사용자 지시). */ .b03-file__card--uploading .b03-file__card-select { display: none; } .b03-file__card--error .b03-file__error-message { display: block; } .b03-file__card--error .b03-file__progress-section { display: none; }