diff --git a/A00_Common/design/design_profile_frame.ts b/A00_Common/design/design_profile_frame.ts
index f014d74a0..7e3d82d70 100644
--- a/A00_Common/design/design_profile_frame.ts
+++ b/A00_Common/design/design_profile_frame.ts
@@ -10,6 +10,7 @@ import "../../B06_Section/B06_Section_UI_Style.css";
// SVG 차트 색상(.b06-chart__*)의 정의처는 _Style_Cross.css다. 이걸 빼면 B05로 바로 진입했을 때
// 배경 rect가 브라우저 기본 fill(검정)로 그려진다 — B06을 먼저 방문해야 정상으로 보이던 원인.
import "../../B06_Section/B06_Section_UI_Style_Cross.css";
+import "../../B06_Section/B06_Section_UI_Style_Cross_Chart.css";
import "../../B06_Section/B06_Section_UI_Style_Cross_Areas.css";
export function createProfileFrame(view: string) {
diff --git a/A00_Common/design/design_view_cross.ts b/A00_Common/design/design_view_cross.ts
index ccee54e26..a90c8a790 100644
--- a/A00_Common/design/design_view_cross.ts
+++ b/A00_Common/design/design_view_cross.ts
@@ -64,6 +64,7 @@ import {
} from "../../B06_Section/B06_Section_UI_Page_Structures_Selection";
import "../../B06_Section/B06_Section_UI_Style.css";
import "../../B06_Section/B06_Section_UI_Style_Cross.css";
+import "../../B06_Section/B06_Section_UI_Style_Cross_Chart.css";
import "../../B06_Section/B06_Section_UI_Style_Cross_Controls.css";
import "../../B06_Section/B06_Section_UI_Style_Cross_Areas.css";
import { loadSectionDetail } from "../../B06_Section/B06_Section_Section_Store";
diff --git a/B01_Dashboard/B01_Dashboard_UI_Page.ts b/B01_Dashboard/B01_Dashboard_UI_Page.ts
index c56b848d1..cdd21d765 100644
--- a/B01_Dashboard/B01_Dashboard_UI_Page.ts
+++ b/B01_Dashboard/B01_Dashboard_UI_Page.ts
@@ -49,6 +49,7 @@ import { buildResourcePanel } from "./B01_Dashboard_UI_Resources";
import { buildTempUploadSection } from "./B01_Dashboard_UI_TempUpload";
import { buildKnowledgeChat } from "./B01_Dashboard_UI_Knowledge_Chat";
import "./B01_Dashboard_UI_Style.css";
+import "./B01_Dashboard_UI_Style_Company.css";
export interface DashboardState {
user: DashboardUser;
diff --git a/B01_Dashboard/B01_Dashboard_UI_Style.css b/B01_Dashboard/B01_Dashboard_UI_Style.css
index c25e72392..0430258c7 100644
--- a/B01_Dashboard/B01_Dashboard_UI_Style.css
+++ b/B01_Dashboard/B01_Dashboard_UI_Style.css
@@ -385,428 +385,3 @@
grid-template-columns: 1fr;
}
}
-
-/* 회사 주소 입력 — 검색해서 고르는 칸 (2026-09-13).
- 라벨·입력·버튼을 한 줄에 세운다. ui-field 가 기본이 세로(라벨 위·입력 아래·오류 슬롯)라
- 그대로 두면 버튼이 오류 슬롯 높이만큼 밀려 수평이 어긋난다 — 이 칸에서만 가로로 눕힌다. */
-.b01-dashboard__address {
- display: flex;
- flex-direction: column;
- gap: var(--spacing-8, 8px);
-}
-
-.b01-dashboard__address-row {
- display: flex;
- align-items: center;
- gap: var(--spacing-8, 8px);
-}
-
-.b01-dashboard__address-row > .ui-field {
- display: flex;
- flex: 1 1 auto;
- flex-direction: row;
- align-items: center;
- gap: var(--spacing-8, 8px);
- min-width: 0;
- margin: 0;
-}
-
-.b01-dashboard__address .ui-field__label {
- flex: 0 0 64px;
- margin: 0;
- white-space: nowrap;
-}
-
-.b01-dashboard__address .ui-input {
- flex: 1 1 auto;
- min-width: 0;
-}
-
-.b01-dashboard__address .ui-field__error {
- display: none;
-}
-
-.b01-dashboard__address-row > .ui-btn {
- flex: 0 0 auto;
-}
-
-.b01-dashboard__address-zip {
- flex: 0 0 auto;
- color: var(--color-text-muted, #666);
- font-size: 0.85rem;
- white-space: nowrap;
-}
-
-.b01-dashboard__address-list {
- display: flex;
- flex-direction: column;
- max-height: 220px;
- overflow-y: auto;
- overscroll-behavior: contain;
- border: 1px solid var(--color-border);
- border-radius: var(--radius-8, 8px);
-}
-
-.b01-dashboard__address-item {
- display: flex;
- flex-direction: column;
- gap: 2px;
- padding: var(--spacing-8, 8px);
- border: 0;
- border-bottom: 1px solid var(--color-border);
- background: transparent;
- color: inherit;
- text-align: left;
- cursor: pointer;
-}
-
-.b01-dashboard__address-item:last-child {
- border-bottom: 0;
-}
-
-.b01-dashboard__address-item:hover,
-.b01-dashboard__address-item:focus-visible {
- background: var(--color-surface-hover, rgba(0, 0, 0, 0.04));
-}
-
-.b01-dashboard__address-item small {
- color: var(--color-text-muted, #666);
-}
-
-.b01-dashboard__map-zoom {
- display: flex;
- gap: var(--spacing-8, 8px);
- margin-bottom: var(--spacing-8, 8px);
-}
-
-/* 회사 주소 지도 미리보기 — 타일 3×3 을 붙이고 가운데 표식을 찍는다 (2026-09-06). */
-.b01-dashboard__map-frame {
- position: relative;
- width: 100%;
- max-width: 384px;
- aspect-ratio: 1;
- overflow: hidden;
- border: 1px solid var(--color-border);
- border-radius: var(--radius-8, 8px);
-}
-
-.b01-dashboard__map-grid {
- display: grid;
- grid-template-columns: repeat(3, 256px);
- transform: scale(0.5);
- transform-origin: top left;
-}
-
-.b01-dashboard__map-marker {
- position: absolute;
- width: 12px;
- height: 12px;
- margin: -6px 0 0 -6px;
- border: 2px solid var(--color-surface, #fff);
- border-radius: 50%;
- background: var(--color-danger, #d33);
-}
-
-/* 프로젝트 참여자 고르기 (2026-09-06). */
-.b01-dashboard__members {
- display: flex;
- flex-direction: column;
- gap: var(--spacing-4, 4px);
- max-height: 160px;
- overflow-y: auto;
-}
-
-.b01-dashboard__member-row {
- display: flex;
- align-items: center;
- gap: var(--spacing-8);
-}
-
-.b01-knowledge-chat {
- position: fixed;
- right: 24px;
- bottom: 24px;
- z-index: 100;
- display: flex;
- flex-direction: column-reverse;
- align-items: flex-end;
- gap: 8px;
-}
-
-.b01-knowledge-chat__toggle,
-.b01-knowledge-chat__form button {
- border: 0;
- background: var(--color-primary);
- color: var(--color-primary-text);
- font: inherit;
- cursor: pointer;
-}
-
-.b01-knowledge-chat__toggle {
- display: grid;
- width: 58px;
- height: 58px;
- place-items: center;
- border-radius: 50%;
- box-shadow: 0 4px 16px #0004;
-}
-
-.b01-knowledge-chat__toggle svg {
- width: 30px;
- height: 30px;
-}
-
-.b01-knowledge-chat__panel {
- display: flex;
- flex-direction: column;
- width: min(380px, calc(100vw - 32px));
- height: min(680px, calc(100dvh - 104px));
- border: 1px solid var(--color-border);
- border-radius: 12px;
- background: var(--color-surface, #fff);
- box-shadow: 0 8px 28px #0003;
- color: var(--color-text-body);
- overflow: hidden;
- overscroll-behavior: contain;
-}
-
-.b01-knowledge-chat__panel[hidden] {
- display: none;
-}
-
-.b01-knowledge-chat__panel header {
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 10px 14px;
- border-bottom: 1px solid var(--color-border);
-}
-
-.b01-knowledge-chat__avatar {
- display: grid;
- width: 34px;
- height: 34px;
- place-items: center;
- border-radius: 50%;
- background: var(--color-primary);
- color: var(--color-primary-text);
-}
-
-.b01-knowledge-chat__avatar svg {
- width: 21px;
- height: 21px;
-}
-
-.b01-knowledge-chat__close {
- margin-left: auto;
- border: 0;
- background: transparent;
- color: inherit;
- font: inherit;
- font-size: 26px;
- cursor: pointer;
-}
-
-.b01-knowledge-chat__messages {
- display: flex;
- flex: 1;
- flex-direction: column;
- gap: 12px;
- min-height: 0;
- padding: 16px 12px;
- overflow-y: auto;
- overscroll-behavior: contain;
-}
-
-.b01-knowledge-chat__user,
-.b01-knowledge-chat__reply {
- max-width: 88%;
- margin: 0;
- padding: 10px 12px;
- border-radius: 14px;
- overflow-wrap: anywhere;
- white-space: pre-wrap;
-}
-
-.b01-knowledge-chat__user {
- align-self: flex-end;
- border-bottom-right-radius: 4px;
- background: var(--color-primary);
- color: var(--color-primary-text);
-}
-
-.b01-knowledge-chat__reply {
- align-self: flex-start;
- border: 1px solid var(--color-border);
- border-bottom-left-radius: 4px;
- background: var(--color-surface-raised);
-}
-
-.b01-knowledge-chat__reply details {
- margin-top: 8px;
- font-size: 0.9em;
-}
-
-.b01-knowledge-chat__reply summary {
- cursor: pointer;
- overflow-wrap: anywhere;
-}
-
-.b01-knowledge-chat__reply pre {
- max-height: 220px;
- overflow: auto;
- white-space: pre-wrap;
- font: inherit;
-}
-
-.b01-knowledge-chat__sources {
- display: grid;
- gap: 6px;
- margin-top: 12px;
- padding-top: 10px;
- border-top: 1px solid var(--color-border);
-}
-
-.b01-knowledge-chat__sources > summary {
- margin-bottom: 3px;
- color: var(--color-text-secondary, #666);
- font-size: 0.85em;
-}
-
-.b01-knowledge-chat__source {
- display: grid;
- gap: 3px;
- width: 100%;
- padding: 8px 10px;
- border: 1px solid var(--color-border);
- border-radius: 8px;
- background: var(--color-surface, #fff);
- color: inherit;
- text-align: left;
- cursor: pointer;
-}
-
-.b01-knowledge-chat__source span {
- color: var(--color-text-secondary, #666);
- font-size: 0.8em;
- overflow-wrap: anywhere;
-}
-
-.b01-knowledge-source-modal.ui-modal {
- width: min(900px, 94vw);
- --modal-max: 88vh;
-}
-
-.b01-knowledge-source-modal__content {
- max-height: calc(88vh - 100px);
- overflow: auto;
- overscroll-behavior: contain;
- padding: 8px 16px;
- line-height: 1.75;
- overflow-wrap: anywhere;
-}
-
-.b01-knowledge-source-modal__content h2,
-.b01-knowledge-source-modal__content h3,
-.b01-knowledge-source-modal__content h4,
-.b01-knowledge-source-modal__content h5 {
- margin: 1.4em 0 0.5em;
- line-height: 1.4;
-}
-
-.b01-knowledge-source-modal__content p,
-.b01-knowledge-source-modal__content ul,
-.b01-knowledge-source-modal__content ol {
- margin: 0.6em 0 1em;
-}
-
-.b01-knowledge-source-modal__content code {
- padding: 0.1em 0.35em;
- border-radius: 4px;
- background: var(--color-surface);
-}
-
-.b01-knowledge-source-modal__content .ui-markdown-table {
- max-width: 100%;
- overflow-x: auto;
- overscroll-behavior: contain;
-}
-
-.b01-knowledge-source-modal__content table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.92em;
-}
-
-.b01-knowledge-source-modal__content th,
-.b01-knowledge-source-modal__content td {
- padding: 8px 10px;
- border: 1px solid var(--color-border);
- text-align: left;
- vertical-align: top;
-}
-
-.b01-knowledge-source-modal__content th {
- background: var(--color-surface);
-}
-
-.b01-knowledge-chat__form {
- display: flex;
- align-items: flex-end;
- gap: 8px;
- padding: 8px;
- border-top: 1px solid var(--color-border);
-}
-
-.b01-knowledge-chat__form textarea {
- min-width: 0;
- flex: 1;
- min-height: 56px;
- max-height: 140px;
- padding: 8px;
- border: 1px solid var(--color-border);
- border-radius: 6px;
- background: var(--color-canvas);
- color: var(--color-text-body);
- font: inherit;
- resize: vertical;
- overflow-y: auto;
-}
-
-.b01-knowledge-chat__form textarea::placeholder {
- color: var(--color-text-muted);
-}
-
-.b01-knowledge-chat__form button {
- padding: 9px 14px;
- border-radius: 8px;
-}
-
-.b01-knowledge-chat button:focus-visible,
-.b01-knowledge-chat textarea:focus-visible {
- outline: 2px solid var(--color-royal-amethyst, #6843a7);
- outline-offset: 2px;
-}
-
-/* 계산 자리 창(504-2) — 묶음 · 까닭 글은 줄바꿈 · 체크 칸은 가운데 */
-.b01-dashboard__calc-sites .b01-dashboard__table td {
- white-space: normal;
-}
-.b01-dashboard__calc-sites .b01-dashboard__table td:nth-child(2),
-.b01-dashboard__calc-sites .b01-dashboard__table td:nth-child(3) {
- text-align: center;
-}
-.b01-dashboard__calc-sites .b01-dashboard__calc-group td {
- background: var(--color-surface);
- font-weight: var(--font-weight-medium);
-}
-.b01-dashboard__calc-sites .b01-dashboard__calc-name {
- padding-left: var(--spacing-16);
-}
-.b01-dashboard__calc-sites .b01-dashboard__calc-group .b01-dashboard__calc-name {
- padding-left: 0;
-}
-.b01-dashboard__calc-count,
-.b01-dashboard__calc-note {
- margin: 0 0 0.5rem;
-}
diff --git a/B01_Dashboard/B01_Dashboard_UI_Style_Company.css b/B01_Dashboard/B01_Dashboard_UI_Style_Company.css
new file mode 100644
index 000000000..c6c31bcb1
--- /dev/null
+++ b/B01_Dashboard/B01_Dashboard_UI_Style_Company.css
@@ -0,0 +1,424 @@
+/* 회사 주소 입력 — 검색해서 고르는 칸 (2026-09-13).
+ 라벨·입력·버튼을 한 줄에 세운다. ui-field 가 기본이 세로(라벨 위·입력 아래·오류 슬롯)라
+ 그대로 두면 버튼이 오류 슬롯 높이만큼 밀려 수평이 어긋난다 — 이 칸에서만 가로로 눕힌다. */
+.b01-dashboard__address {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-8, 8px);
+}
+
+.b01-dashboard__address-row {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-8, 8px);
+}
+
+.b01-dashboard__address-row > .ui-field {
+ display: flex;
+ flex: 1 1 auto;
+ flex-direction: row;
+ align-items: center;
+ gap: var(--spacing-8, 8px);
+ min-width: 0;
+ margin: 0;
+}
+
+.b01-dashboard__address .ui-field__label {
+ flex: 0 0 64px;
+ margin: 0;
+ white-space: nowrap;
+}
+
+.b01-dashboard__address .ui-input {
+ flex: 1 1 auto;
+ min-width: 0;
+}
+
+.b01-dashboard__address .ui-field__error {
+ display: none;
+}
+
+.b01-dashboard__address-row > .ui-btn {
+ flex: 0 0 auto;
+}
+
+.b01-dashboard__address-zip {
+ flex: 0 0 auto;
+ color: var(--color-text-muted, #666);
+ font-size: 0.85rem;
+ white-space: nowrap;
+}
+
+.b01-dashboard__address-list {
+ display: flex;
+ flex-direction: column;
+ max-height: 220px;
+ overflow-y: auto;
+ overscroll-behavior: contain;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-8, 8px);
+}
+
+.b01-dashboard__address-item {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ padding: var(--spacing-8, 8px);
+ border: 0;
+ border-bottom: 1px solid var(--color-border);
+ background: transparent;
+ color: inherit;
+ text-align: left;
+ cursor: pointer;
+}
+
+.b01-dashboard__address-item:last-child {
+ border-bottom: 0;
+}
+
+.b01-dashboard__address-item:hover,
+.b01-dashboard__address-item:focus-visible {
+ background: var(--color-surface-hover, rgba(0, 0, 0, 0.04));
+}
+
+.b01-dashboard__address-item small {
+ color: var(--color-text-muted, #666);
+}
+
+.b01-dashboard__map-zoom {
+ display: flex;
+ gap: var(--spacing-8, 8px);
+ margin-bottom: var(--spacing-8, 8px);
+}
+
+/* 회사 주소 지도 미리보기 — 타일 3×3 을 붙이고 가운데 표식을 찍는다 (2026-09-06). */
+.b01-dashboard__map-frame {
+ position: relative;
+ width: 100%;
+ max-width: 384px;
+ aspect-ratio: 1;
+ overflow: hidden;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-8, 8px);
+}
+
+.b01-dashboard__map-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 256px);
+ transform: scale(0.5);
+ transform-origin: top left;
+}
+
+.b01-dashboard__map-marker {
+ position: absolute;
+ width: 12px;
+ height: 12px;
+ margin: -6px 0 0 -6px;
+ border: 2px solid var(--color-surface, #fff);
+ border-radius: 50%;
+ background: var(--color-danger, #d33);
+}
+
+/* 프로젝트 참여자 고르기 (2026-09-06). */
+.b01-dashboard__members {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-4, 4px);
+ max-height: 160px;
+ overflow-y: auto;
+}
+
+.b01-dashboard__member-row {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-8);
+}
+
+.b01-knowledge-chat {
+ position: fixed;
+ right: 24px;
+ bottom: 24px;
+ z-index: 100;
+ display: flex;
+ flex-direction: column-reverse;
+ align-items: flex-end;
+ gap: 8px;
+}
+
+.b01-knowledge-chat__toggle,
+.b01-knowledge-chat__form button {
+ border: 0;
+ background: var(--color-primary);
+ color: var(--color-primary-text);
+ font: inherit;
+ cursor: pointer;
+}
+
+.b01-knowledge-chat__toggle {
+ display: grid;
+ width: 58px;
+ height: 58px;
+ place-items: center;
+ border-radius: 50%;
+ box-shadow: 0 4px 16px #0004;
+}
+
+.b01-knowledge-chat__toggle svg {
+ width: 30px;
+ height: 30px;
+}
+
+.b01-knowledge-chat__panel {
+ display: flex;
+ flex-direction: column;
+ width: min(380px, calc(100vw - 32px));
+ height: min(680px, calc(100dvh - 104px));
+ border: 1px solid var(--color-border);
+ border-radius: 12px;
+ background: var(--color-surface, #fff);
+ box-shadow: 0 8px 28px #0003;
+ color: var(--color-text-body);
+ overflow: hidden;
+ overscroll-behavior: contain;
+}
+
+.b01-knowledge-chat__panel[hidden] {
+ display: none;
+}
+
+.b01-knowledge-chat__panel header {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 14px;
+ border-bottom: 1px solid var(--color-border);
+}
+
+.b01-knowledge-chat__avatar {
+ display: grid;
+ width: 34px;
+ height: 34px;
+ place-items: center;
+ border-radius: 50%;
+ background: var(--color-primary);
+ color: var(--color-primary-text);
+}
+
+.b01-knowledge-chat__avatar svg {
+ width: 21px;
+ height: 21px;
+}
+
+.b01-knowledge-chat__close {
+ margin-left: auto;
+ border: 0;
+ background: transparent;
+ color: inherit;
+ font: inherit;
+ font-size: 26px;
+ cursor: pointer;
+}
+
+.b01-knowledge-chat__messages {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: 12px;
+ min-height: 0;
+ padding: 16px 12px;
+ overflow-y: auto;
+ overscroll-behavior: contain;
+}
+
+.b01-knowledge-chat__user,
+.b01-knowledge-chat__reply {
+ max-width: 88%;
+ margin: 0;
+ padding: 10px 12px;
+ border-radius: 14px;
+ overflow-wrap: anywhere;
+ white-space: pre-wrap;
+}
+
+.b01-knowledge-chat__user {
+ align-self: flex-end;
+ border-bottom-right-radius: 4px;
+ background: var(--color-primary);
+ color: var(--color-primary-text);
+}
+
+.b01-knowledge-chat__reply {
+ align-self: flex-start;
+ border: 1px solid var(--color-border);
+ border-bottom-left-radius: 4px;
+ background: var(--color-surface-raised);
+}
+
+.b01-knowledge-chat__reply details {
+ margin-top: 8px;
+ font-size: 0.9em;
+}
+
+.b01-knowledge-chat__reply summary {
+ cursor: pointer;
+ overflow-wrap: anywhere;
+}
+
+.b01-knowledge-chat__reply pre {
+ max-height: 220px;
+ overflow: auto;
+ white-space: pre-wrap;
+ font: inherit;
+}
+
+.b01-knowledge-chat__sources {
+ display: grid;
+ gap: 6px;
+ margin-top: 12px;
+ padding-top: 10px;
+ border-top: 1px solid var(--color-border);
+}
+
+.b01-knowledge-chat__sources > summary {
+ margin-bottom: 3px;
+ color: var(--color-text-secondary, #666);
+ font-size: 0.85em;
+}
+
+.b01-knowledge-chat__source {
+ display: grid;
+ gap: 3px;
+ width: 100%;
+ padding: 8px 10px;
+ border: 1px solid var(--color-border);
+ border-radius: 8px;
+ background: var(--color-surface, #fff);
+ color: inherit;
+ text-align: left;
+ cursor: pointer;
+}
+
+.b01-knowledge-chat__source span {
+ color: var(--color-text-secondary, #666);
+ font-size: 0.8em;
+ overflow-wrap: anywhere;
+}
+
+.b01-knowledge-source-modal.ui-modal {
+ width: min(900px, 94vw);
+ --modal-max: 88vh;
+}
+
+.b01-knowledge-source-modal__content {
+ max-height: calc(88vh - 100px);
+ overflow: auto;
+ overscroll-behavior: contain;
+ padding: 8px 16px;
+ line-height: 1.75;
+ overflow-wrap: anywhere;
+}
+
+.b01-knowledge-source-modal__content h2,
+.b01-knowledge-source-modal__content h3,
+.b01-knowledge-source-modal__content h4,
+.b01-knowledge-source-modal__content h5 {
+ margin: 1.4em 0 0.5em;
+ line-height: 1.4;
+}
+
+.b01-knowledge-source-modal__content p,
+.b01-knowledge-source-modal__content ul,
+.b01-knowledge-source-modal__content ol {
+ margin: 0.6em 0 1em;
+}
+
+.b01-knowledge-source-modal__content code {
+ padding: 0.1em 0.35em;
+ border-radius: 4px;
+ background: var(--color-surface);
+}
+
+.b01-knowledge-source-modal__content .ui-markdown-table {
+ max-width: 100%;
+ overflow-x: auto;
+ overscroll-behavior: contain;
+}
+
+.b01-knowledge-source-modal__content table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.92em;
+}
+
+.b01-knowledge-source-modal__content th,
+.b01-knowledge-source-modal__content td {
+ padding: 8px 10px;
+ border: 1px solid var(--color-border);
+ text-align: left;
+ vertical-align: top;
+}
+
+.b01-knowledge-source-modal__content th {
+ background: var(--color-surface);
+}
+
+.b01-knowledge-chat__form {
+ display: flex;
+ align-items: flex-end;
+ gap: 8px;
+ padding: 8px;
+ border-top: 1px solid var(--color-border);
+}
+
+.b01-knowledge-chat__form textarea {
+ min-width: 0;
+ flex: 1;
+ min-height: 56px;
+ max-height: 140px;
+ padding: 8px;
+ border: 1px solid var(--color-border);
+ border-radius: 6px;
+ background: var(--color-canvas);
+ color: var(--color-text-body);
+ font: inherit;
+ resize: vertical;
+ overflow-y: auto;
+}
+
+.b01-knowledge-chat__form textarea::placeholder {
+ color: var(--color-text-muted);
+}
+
+.b01-knowledge-chat__form button {
+ padding: 9px 14px;
+ border-radius: 8px;
+}
+
+.b01-knowledge-chat button:focus-visible,
+.b01-knowledge-chat textarea:focus-visible {
+ outline: 2px solid var(--color-royal-amethyst, #6843a7);
+ outline-offset: 2px;
+}
+
+/* 계산 자리 창(504-2) — 묶음 · 까닭 글은 줄바꿈 · 체크 칸은 가운데 */
+.b01-dashboard__calc-sites .b01-dashboard__table td {
+ white-space: normal;
+}
+.b01-dashboard__calc-sites .b01-dashboard__table td:nth-child(2),
+.b01-dashboard__calc-sites .b01-dashboard__table td:nth-child(3) {
+ text-align: center;
+}
+.b01-dashboard__calc-sites .b01-dashboard__calc-group td {
+ background: var(--color-surface);
+ font-weight: var(--font-weight-medium);
+}
+.b01-dashboard__calc-sites .b01-dashboard__calc-name {
+ padding-left: var(--spacing-16);
+}
+.b01-dashboard__calc-sites .b01-dashboard__calc-group .b01-dashboard__calc-name {
+ padding-left: 0;
+}
+.b01-dashboard__calc-count,
+.b01-dashboard__calc-note {
+ margin: 0 0 0.5rem;
+}
diff --git a/B03_FileInput/B03_FileInput_UI_Page.ts b/B03_FileInput/B03_FileInput_UI_Page.ts
index cd9a87b93..6f97ac3b6 100644
--- a/B03_FileInput/B03_FileInput_UI_Page.ts
+++ b/B03_FileInput/B03_FileInput_UI_Page.ts
@@ -48,6 +48,7 @@ import {
type UploadStatus,
} from "./B03_FileInput_UI_Support";
import "./B03_FileInput_UI_Style.css";
+import "./B03_FileInput_UI_Style_Card.css";
function L(key: keyof typeof ui_locales): string {
return ui_locales[key][currentLanguageIndex];
diff --git a/B03_FileInput/B03_FileInput_UI_Style.css b/B03_FileInput/B03_FileInput_UI_Style.css
index 6719bdcd3..fb01e0657 100644
--- a/B03_FileInput/B03_FileInput_UI_Style.css
+++ b/B03_FileInput/B03_FileInput_UI_Style.css
@@ -348,367 +348,3 @@
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;
-}
diff --git a/B03_FileInput/B03_FileInput_UI_Style_Card.css b/B03_FileInput/B03_FileInput_UI_Style_Card.css
new file mode 100644
index 000000000..74cc766e2
--- /dev/null
+++ b/B03_FileInput/B03_FileInput_UI_Style_Card.css
@@ -0,0 +1,363 @@
+/* 업로드 중에는 화면 조작을 막는다 — 중복 업로드·단계 이동 방지(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;
+}
diff --git a/B06_Section/B06_Section_UI_Style_Cross.css b/B06_Section/B06_Section_UI_Style_Cross.css
index 1ac1dd830..45f1b3d25 100644
--- a/B06_Section/B06_Section_UI_Style_Cross.css
+++ b/B06_Section/B06_Section_UI_Style_Cross.css
@@ -367,377 +367,3 @@ html.is-bm-route .b06-section__notice-bar {
color: var(--color-text-muted);
background: var(--color-surface);
}
-
-/* SVG 차트 색상은 테마 토큰만 사용한다. */
-.b06-chart__bg {
- fill: var(--color-surface-raised);
-}
-
-/* 세로 창을 변환으로 옮기는 겹(2026-09-04) — 세로로 눌리거나 늘어나도 선 굵기·점선 간격은
- 그대로여야 한다. 변환이 걸려 있을 때만 적용해 B06 종단·횡단은 예전 그대로 그려진다. */
-.b06-chart__ywindow[transform] * {
- vector-effect: non-scaling-stroke;
-}
-
-.b06-chart__grid {
- stroke: var(--color-border);
- stroke-width: 1;
-}
-
-.b06-chart__axis {
- stroke: var(--color-text-secondary);
- stroke-width: 1;
-}
-
-.b06-chart__tick,
-.b06-chart__station-label,
-.b06-chart__axis-label {
- fill: var(--color-text-secondary);
- font-family: var(--font-body);
-}
-
-.b06-chart__tick,
-.b06-chart__station-label {
- font-size: 10px;
-}
-
-/* MC(곡선 가운데) 측점 = 사용자가 고칠 자리(507-3) — 한 단계 크게 · 굵게 · 경고색. 고름 빨강은 아래가 이김. */
-.b06-chart__station-label--mc {
- font-size: 12px;
- font-weight: var(--font-weight-bold);
- fill: var(--color-warning);
-}
-
-.b06-station--mc {
- font-size: 1.15em;
- font-weight: var(--font-weight-bold);
- color: var(--color-warning);
-}
-
-/* 중심고 Y축 라벨(318-2) — 눈금과 같은 10px · 둥근 상자 · 축선 앞에서 멈춤 ·
- 바탕 = 불투명 섞음(겹친 눈금 글을 위에서 가림 · 319-1) · 색 = 원지반선 · 설계선(379-3 · `--b06-tag` = _Cross_Areas.css) */
-.b06-chart__center-box {
- fill: color-mix(in srgb, var(--b06-tag) 14%, var(--color-surface-raised));
- stroke: var(--b06-tag);
- stroke-width: 1;
-}
-
-.b06-chart__center-text {
- fill: var(--b06-tag);
- font-weight: var(--font-weight-medium);
-}
-
-/* 겹쳐 위 단으로 올린 측점 이름(407-4) — 선 · 지반선 위라 바탕색 테두리로 읽히게. */
-.b06-chart__station-label--lifted {
- paint-order: stroke;
- stroke: var(--color-surface-raised);
- stroke-width: 3px;
- stroke-linejoin: round;
- pointer-events: none;
-}
-
-/* 구조물(비정규) 측점 이름 — 종단면도 측점선 상단 표기. */
-.b06-chart__structure-label {
- font-size: 9px;
- font-weight: var(--font-weight-medium);
- fill: rgb(180 83 9);
-}
-
-.b06-chart__axis-label {
- fill: var(--color-text-body);
- font-size: var(--text-caption);
- font-weight: var(--font-weight-medium);
-}
-
-.b06-chart__profile {
- fill: none;
- stroke: var(--color-chart-0);
- stroke-width: 2.5;
-}
-
-/* 지반선 · 계획선은 누름을 통과 — 겹친 측점선 누름이 측점 고름 · 임시 횡단으로 감(505-3) */
-.b06-chart__profile,
-.b06-chart__design-profile {
- pointer-events: none;
-}
-
-.b06-chart__cross-profile {
- fill: none;
- stroke: var(--color-chart-1);
- stroke-width: 2.4;
-}
-
-/* 종단 계획선(시공계획고): 지반선과 구분되도록 파선 + 강조색 */
-.b06-chart__design-profile {
- fill: none;
- stroke: var(--color-royal-amethyst);
- stroke-width: 2.2;
- stroke-dasharray: 8 4;
-}
-
-/* 절토(계획고가 지반고보다 낮음) / 성토 구간 음영 */
-.b06-chart__band {
- stroke: none;
-}
-
-.b06-chart__band--cut {
- fill: rgb(220 38 38 / 14%);
-}
-
-.b06-chart__band--fill {
- fill: rgb(37 99 235 / 14%);
-}
-
-.b06-chart__balance-boundary {
- stroke: var(--color-royal-amethyst);
- stroke-width: 1.2;
- stroke-dasharray: 3 3;
- opacity: 0.55;
-}
-
-.b06-chart__station {
- cursor: pointer;
-}
-
-/* 구조물 측점선은 끌어 옮길 수 있다 — 커서로 그 사실을 알린다(2026-08-01 사용자 지시). */
-.b06-chart__station--draggable {
- cursor: ew-resize;
- touch-action: none;
-}
-
-.b06-chart__station-line {
- stroke-width: 1.2;
-}
-
-.b06-chart__station-hit {
- stroke: transparent;
- stroke-width: 14;
- pointer-events: stroke;
-}
-
-.b06-chart__station-line--bp,
-.b06-chart__station-line--regular,
-.b06-chart__station-line--curve {
- stroke: var(--color-warning);
-}
-
-.b06-chart__station-line--ep {
- stroke: var(--color-accent);
- stroke-dasharray: 4 3;
-}
-
-/* 비정규 측점(구조물)은 종단면도에서도 자수정색 파선으로 구분한다(B05 종단 규칙과 정합).
- 미선택 시 stroke 미정의로 세로선이 안 그려지던 문제 해소. */
-.b06-chart__station-line--irregular {
- stroke: var(--color-royal-amethyst, rgb(139 92 246));
- stroke-width: 1.4;
- stroke-dasharray: 5 3;
-}
-
-/* 추가 측점(368-3) = 일반측점 색 점선 */
-.b06-chart__station-line--plus {
- stroke: var(--color-warning);
- stroke-dasharray: 5 3;
-}
-
-.b06-chart__station-line--selected,
-.b06-chart__center-marker {
- stroke: var(--color-danger);
- stroke-width: 2.5;
-}
-
-/* 십자선이 계획 노선(계획고) 위치를 가리킬 때: 종단 계획선과 동일 색으로 대응시킨다 */
-.b06-chart__center-marker--design {
- stroke: var(--color-royal-amethyst);
-}
-
-.b06-chart__station--selected .b06-chart__station-label,
-.b06-chart__station-label--selected {
- fill: var(--color-danger);
- font-weight: var(--font-weight-bold);
-}
-
-/* 측점 표준횡단 설계 지정 컨트롤 (카드 헤더 아래) — 좌측 여유 추가(2번).
- 한 행 고정(nowrap): 넘치는 컨트롤은 다음 행으로 밀지 않고 "⋯" 드롭다운으로 이동(N-2-2). */
-.b06-design {
- display: flex;
- flex-wrap: nowrap;
- align-items: center;
- gap: var(--spacing-8) var(--spacing-16);
- padding: var(--spacing-8) 0 var(--spacing-8) var(--spacing-16);
- border-bottom: 1px solid var(--color-border);
- margin-bottom: var(--spacing-8);
-}
-
-/* 오버플로 드롭다운(N-2-2): 넘친 컨트롤을 담는 우측 맞춤 "⋯" 메뉴. 세로 배치. */
-.b06-design__more {
- position: relative;
- flex: 0 0 auto;
- margin-left: auto;
-}
-
-.b06-design__more-summary {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 24px;
- height: 22px;
- border: 1px solid var(--color-border);
- border-radius: var(--radius-inputs);
- background: var(--color-surface);
- color: var(--color-text-secondary);
- font-size: 0.9rem;
- line-height: 1;
- cursor: pointer;
- list-style: none;
-}
-
-.b06-design__more-summary::-webkit-details-marker {
- display: none;
-}
-
-.b06-design__more[open] .b06-design__more-summary {
- color: var(--color-surface);
- background: var(--color-royal-amethyst);
- border-color: var(--color-royal-amethyst);
-}
-
-.b06-design__more-panel {
- position: absolute;
- right: 0;
- top: calc(100% + 4px);
- z-index: 3;
- display: flex;
- flex-direction: column;
- gap: var(--spacing-8);
- padding: var(--spacing-8);
- border: 1px solid var(--color-border);
- border-radius: var(--radius-inputs);
- background: var(--color-surface-raised);
- box-shadow: var(--shadow-sm);
-}
-
-.b06-design__seg {
- display: flex;
- align-items: center;
- gap: var(--spacing-8);
-}
-
-.b06-design__seg-legend {
- font-size: 0.72rem;
- color: var(--color-text-secondary);
- white-space: nowrap;
-}
-
-/* 선행 조건 미충족 옵션 — 숨김(179-2 · 옛 E-6 「흐리게 늘 보임」 폐기 · 쪽은 단면유형 알약에). */
-.b06-design__seg--disabled {
- display: none;
-}
-
-.b06-design__seg-buttons {
- display: inline-flex;
- border: 1px solid var(--color-border);
- border-radius: var(--radius-inputs);
- overflow: hidden;
-}
-
-.b06-design__btn {
- padding: 3px 8px;
- font-size: 0.72rem;
- color: var(--color-text-secondary);
- background: var(--color-surface);
- border: none;
- border-left: 1px solid var(--color-border);
- cursor: pointer;
-}
-
-.b06-design__btn:first-child {
- border-left: none;
-}
-
-.b06-design__btn--active {
- color: var(--color-surface);
- background: var(--color-royal-amethyst);
- font-weight: var(--font-weight-medium);
-}
-
-.b06-design__areas {
- display: inline-flex;
- gap: var(--spacing-8);
- margin-left: auto;
- font-size: 0.72rem;
- font-family: var(--font-mono);
-}
-
-/* 암 경계선 제어(E-7) — 하단 정보 행 **왼쪽 맞춤**(318-2 · 중심고는 그래프 Y축 라벨 상자로 옮김). */
-.b06-cross-card__rockb {
- flex: 0 0 auto;
- border-radius: var(--radius-inputs);
- padding: 1px 4px;
-}
-
-/* 선 공용 칸(370-3) — 고른 선 제목 · 버튼 · 값 한 줄(넘치면 말줄임) · 빈 칸도 자리(띠 높이) 그대로. */
-.b06-cross-card__linecell {
- flex: 0 1 auto;
- min-width: 0;
-}
-
-.b06-cross-card__linecell.is-empty {
- visibility: hidden;
-}
-
-.b06-cross-card__linecell .b06-design__seg-buttons {
- min-width: 0;
-}
-
-.b06-cross-card__linecell .b06-design__rockb-readout {
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.b06-cross-card__linecell .b06-design__rockb-btn {
- flex: 0 0 auto;
- border-left: none;
-}
-
-.b06-cross-card__linecell
- .b06-design__rockb-btn:not([hidden])
- ~ .b06-design__rockb-btn:not([hidden]) {
- border-left: 1px solid var(--color-border);
-}
-
-/* 측점별 암 절토 경사(2026-09-07) — 행의 **오른쪽 끝**(암 경계 = 왼쪽). */
-.b06-cross-card__cutslope {
- margin-left: auto;
- flex: 0 0 auto;
- border-radius: var(--radius-inputs);
- padding: 1px 4px;
-}
-
-.b06-design__cutslope-input {
- width: 44px;
- padding: 0 2px;
- font-size: 0.72rem;
- font-family: var(--font-mono);
- text-align: right;
- color: var(--color-text);
- background: var(--color-surface);
- border: 1px solid var(--color-border);
- border-radius: var(--radius-inputs);
-}
-
-/* 화살표(스피너)는 칸이 좁아 지운다 — 값은 직접 넣거나 ↺ 로 되돌린다. */
-.b06-design__cutslope-input::-webkit-outer-spin-button,
-.b06-design__cutslope-input::-webkit-inner-spin-button {
- margin: 0;
- appearance: none;
-}
-
-.b06-design__cutslope-unit {
- padding: 0 2px 0 1px;
- font-size: 0.72rem;
- color: var(--color-text-secondary);
- align-self: center;
-}
diff --git a/B06_Section/B06_Section_UI_Style_Cross_Chart.css b/B06_Section/B06_Section_UI_Style_Cross_Chart.css
new file mode 100644
index 000000000..7f447bcbd
--- /dev/null
+++ b/B06_Section/B06_Section_UI_Style_Cross_Chart.css
@@ -0,0 +1,373 @@
+/* SVG 차트 색상은 테마 토큰만 사용한다. */
+.b06-chart__bg {
+ fill: var(--color-surface-raised);
+}
+
+/* 세로 창을 변환으로 옮기는 겹(2026-09-04) — 세로로 눌리거나 늘어나도 선 굵기·점선 간격은
+ 그대로여야 한다. 변환이 걸려 있을 때만 적용해 B06 종단·횡단은 예전 그대로 그려진다. */
+.b06-chart__ywindow[transform] * {
+ vector-effect: non-scaling-stroke;
+}
+
+.b06-chart__grid {
+ stroke: var(--color-border);
+ stroke-width: 1;
+}
+
+.b06-chart__axis {
+ stroke: var(--color-text-secondary);
+ stroke-width: 1;
+}
+
+.b06-chart__tick,
+.b06-chart__station-label,
+.b06-chart__axis-label {
+ fill: var(--color-text-secondary);
+ font-family: var(--font-body);
+}
+
+.b06-chart__tick,
+.b06-chart__station-label {
+ font-size: 10px;
+}
+
+/* MC(곡선 가운데) 측점 = 사용자가 고칠 자리(507-3) — 한 단계 크게 · 굵게 · 경고색. 고름 빨강은 아래가 이김. */
+.b06-chart__station-label--mc {
+ font-size: 12px;
+ font-weight: var(--font-weight-bold);
+ fill: var(--color-warning);
+}
+
+.b06-station--mc {
+ font-size: 1.15em;
+ font-weight: var(--font-weight-bold);
+ color: var(--color-warning);
+}
+
+/* 중심고 Y축 라벨(318-2) — 눈금과 같은 10px · 둥근 상자 · 축선 앞에서 멈춤 ·
+ 바탕 = 불투명 섞음(겹친 눈금 글을 위에서 가림 · 319-1) · 색 = 원지반선 · 설계선(379-3 · `--b06-tag` = _Cross_Areas.css) */
+.b06-chart__center-box {
+ fill: color-mix(in srgb, var(--b06-tag) 14%, var(--color-surface-raised));
+ stroke: var(--b06-tag);
+ stroke-width: 1;
+}
+
+.b06-chart__center-text {
+ fill: var(--b06-tag);
+ font-weight: var(--font-weight-medium);
+}
+
+/* 겹쳐 위 단으로 올린 측점 이름(407-4) — 선 · 지반선 위라 바탕색 테두리로 읽히게. */
+.b06-chart__station-label--lifted {
+ paint-order: stroke;
+ stroke: var(--color-surface-raised);
+ stroke-width: 3px;
+ stroke-linejoin: round;
+ pointer-events: none;
+}
+
+/* 구조물(비정규) 측점 이름 — 종단면도 측점선 상단 표기. */
+.b06-chart__structure-label {
+ font-size: 9px;
+ font-weight: var(--font-weight-medium);
+ fill: rgb(180 83 9);
+}
+
+.b06-chart__axis-label {
+ fill: var(--color-text-body);
+ font-size: var(--text-caption);
+ font-weight: var(--font-weight-medium);
+}
+
+.b06-chart__profile {
+ fill: none;
+ stroke: var(--color-chart-0);
+ stroke-width: 2.5;
+}
+
+/* 지반선 · 계획선은 누름을 통과 — 겹친 측점선 누름이 측점 고름 · 임시 횡단으로 감(505-3) */
+.b06-chart__profile,
+.b06-chart__design-profile {
+ pointer-events: none;
+}
+
+.b06-chart__cross-profile {
+ fill: none;
+ stroke: var(--color-chart-1);
+ stroke-width: 2.4;
+}
+
+/* 종단 계획선(시공계획고): 지반선과 구분되도록 파선 + 강조색 */
+.b06-chart__design-profile {
+ fill: none;
+ stroke: var(--color-royal-amethyst);
+ stroke-width: 2.2;
+ stroke-dasharray: 8 4;
+}
+
+/* 절토(계획고가 지반고보다 낮음) / 성토 구간 음영 */
+.b06-chart__band {
+ stroke: none;
+}
+
+.b06-chart__band--cut {
+ fill: rgb(220 38 38 / 14%);
+}
+
+.b06-chart__band--fill {
+ fill: rgb(37 99 235 / 14%);
+}
+
+.b06-chart__balance-boundary {
+ stroke: var(--color-royal-amethyst);
+ stroke-width: 1.2;
+ stroke-dasharray: 3 3;
+ opacity: 0.55;
+}
+
+.b06-chart__station {
+ cursor: pointer;
+}
+
+/* 구조물 측점선은 끌어 옮길 수 있다 — 커서로 그 사실을 알린다(2026-08-01 사용자 지시). */
+.b06-chart__station--draggable {
+ cursor: ew-resize;
+ touch-action: none;
+}
+
+.b06-chart__station-line {
+ stroke-width: 1.2;
+}
+
+.b06-chart__station-hit {
+ stroke: transparent;
+ stroke-width: 14;
+ pointer-events: stroke;
+}
+
+.b06-chart__station-line--bp,
+.b06-chart__station-line--regular,
+.b06-chart__station-line--curve {
+ stroke: var(--color-warning);
+}
+
+.b06-chart__station-line--ep {
+ stroke: var(--color-accent);
+ stroke-dasharray: 4 3;
+}
+
+/* 비정규 측점(구조물)은 종단면도에서도 자수정색 파선으로 구분한다(B05 종단 규칙과 정합).
+ 미선택 시 stroke 미정의로 세로선이 안 그려지던 문제 해소. */
+.b06-chart__station-line--irregular {
+ stroke: var(--color-royal-amethyst, rgb(139 92 246));
+ stroke-width: 1.4;
+ stroke-dasharray: 5 3;
+}
+
+/* 추가 측점(368-3) = 일반측점 색 점선 */
+.b06-chart__station-line--plus {
+ stroke: var(--color-warning);
+ stroke-dasharray: 5 3;
+}
+
+.b06-chart__station-line--selected,
+.b06-chart__center-marker {
+ stroke: var(--color-danger);
+ stroke-width: 2.5;
+}
+
+/* 십자선이 계획 노선(계획고) 위치를 가리킬 때: 종단 계획선과 동일 색으로 대응시킨다 */
+.b06-chart__center-marker--design {
+ stroke: var(--color-royal-amethyst);
+}
+
+.b06-chart__station--selected .b06-chart__station-label,
+.b06-chart__station-label--selected {
+ fill: var(--color-danger);
+ font-weight: var(--font-weight-bold);
+}
+
+/* 측점 표준횡단 설계 지정 컨트롤 (카드 헤더 아래) — 좌측 여유 추가(2번).
+ 한 행 고정(nowrap): 넘치는 컨트롤은 다음 행으로 밀지 않고 "⋯" 드롭다운으로 이동(N-2-2). */
+.b06-design {
+ display: flex;
+ flex-wrap: nowrap;
+ align-items: center;
+ gap: var(--spacing-8) var(--spacing-16);
+ padding: var(--spacing-8) 0 var(--spacing-8) var(--spacing-16);
+ border-bottom: 1px solid var(--color-border);
+ margin-bottom: var(--spacing-8);
+}
+
+/* 오버플로 드롭다운(N-2-2): 넘친 컨트롤을 담는 우측 맞춤 "⋯" 메뉴. 세로 배치. */
+.b06-design__more {
+ position: relative;
+ flex: 0 0 auto;
+ margin-left: auto;
+}
+
+.b06-design__more-summary {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 22px;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-inputs);
+ background: var(--color-surface);
+ color: var(--color-text-secondary);
+ font-size: 0.9rem;
+ line-height: 1;
+ cursor: pointer;
+ list-style: none;
+}
+
+.b06-design__more-summary::-webkit-details-marker {
+ display: none;
+}
+
+.b06-design__more[open] .b06-design__more-summary {
+ color: var(--color-surface);
+ background: var(--color-royal-amethyst);
+ border-color: var(--color-royal-amethyst);
+}
+
+.b06-design__more-panel {
+ position: absolute;
+ right: 0;
+ top: calc(100% + 4px);
+ z-index: 3;
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-8);
+ padding: var(--spacing-8);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-inputs);
+ background: var(--color-surface-raised);
+ box-shadow: var(--shadow-sm);
+}
+
+.b06-design__seg {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-8);
+}
+
+.b06-design__seg-legend {
+ font-size: 0.72rem;
+ color: var(--color-text-secondary);
+ white-space: nowrap;
+}
+
+/* 선행 조건 미충족 옵션 — 숨김(179-2 · 옛 E-6 「흐리게 늘 보임」 폐기 · 쪽은 단면유형 알약에). */
+.b06-design__seg--disabled {
+ display: none;
+}
+
+.b06-design__seg-buttons {
+ display: inline-flex;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-inputs);
+ overflow: hidden;
+}
+
+.b06-design__btn {
+ padding: 3px 8px;
+ font-size: 0.72rem;
+ color: var(--color-text-secondary);
+ background: var(--color-surface);
+ border: none;
+ border-left: 1px solid var(--color-border);
+ cursor: pointer;
+}
+
+.b06-design__btn:first-child {
+ border-left: none;
+}
+
+.b06-design__btn--active {
+ color: var(--color-surface);
+ background: var(--color-royal-amethyst);
+ font-weight: var(--font-weight-medium);
+}
+
+.b06-design__areas {
+ display: inline-flex;
+ gap: var(--spacing-8);
+ margin-left: auto;
+ font-size: 0.72rem;
+ font-family: var(--font-mono);
+}
+
+/* 암 경계선 제어(E-7) — 하단 정보 행 **왼쪽 맞춤**(318-2 · 중심고는 그래프 Y축 라벨 상자로 옮김). */
+.b06-cross-card__rockb {
+ flex: 0 0 auto;
+ border-radius: var(--radius-inputs);
+ padding: 1px 4px;
+}
+
+/* 선 공용 칸(370-3) — 고른 선 제목 · 버튼 · 값 한 줄(넘치면 말줄임) · 빈 칸도 자리(띠 높이) 그대로. */
+.b06-cross-card__linecell {
+ flex: 0 1 auto;
+ min-width: 0;
+}
+
+.b06-cross-card__linecell.is-empty {
+ visibility: hidden;
+}
+
+.b06-cross-card__linecell .b06-design__seg-buttons {
+ min-width: 0;
+}
+
+.b06-cross-card__linecell .b06-design__rockb-readout {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.b06-cross-card__linecell .b06-design__rockb-btn {
+ flex: 0 0 auto;
+ border-left: none;
+}
+
+.b06-cross-card__linecell
+ .b06-design__rockb-btn:not([hidden])
+ ~ .b06-design__rockb-btn:not([hidden]) {
+ border-left: 1px solid var(--color-border);
+}
+
+/* 측점별 암 절토 경사(2026-09-07) — 행의 **오른쪽 끝**(암 경계 = 왼쪽). */
+.b06-cross-card__cutslope {
+ margin-left: auto;
+ flex: 0 0 auto;
+ border-radius: var(--radius-inputs);
+ padding: 1px 4px;
+}
+
+.b06-design__cutslope-input {
+ width: 44px;
+ padding: 0 2px;
+ font-size: 0.72rem;
+ font-family: var(--font-mono);
+ text-align: right;
+ color: var(--color-text);
+ background: var(--color-surface);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-inputs);
+}
+
+/* 화살표(스피너)는 칸이 좁아 지운다 — 값은 직접 넣거나 ↺ 로 되돌린다. */
+.b06-design__cutslope-input::-webkit-outer-spin-button,
+.b06-design__cutslope-input::-webkit-inner-spin-button {
+ margin: 0;
+ appearance: none;
+}
+
+.b06-design__cutslope-unit {
+ padding: 0 2px 0 1px;
+ font-size: 0.72rem;
+ color: var(--color-text-secondary);
+ align-self: center;
+}
diff --git a/B07_DesignDetail/openwebcad/src/App.css b/B07_DesignDetail/openwebcad/src/App.css
index c4b983701..7239e8173 100644
--- a/B07_DesignDetail/openwebcad/src/App.css
+++ b/B07_DesignDetail/openwebcad/src/App.css
@@ -431,480 +431,3 @@ input[type="color"][data-mixed="true"]::-webkit-color-swatch { background: trans
padding-top: 6px;
padding-bottom: 6px;
}
-/* 도면층 행: 이름은 줄여 담고 아이콘은 줄이지 않는다. 이름이 안 줄면 오른쪽 아이콘이
- 행 밖으로 밀려 잘린다 (2026-09-01 실측: 내용 237~286px / 보이는 폭 229px). */
-.cad-layer-manager .layer > button > span {
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.cad-layer-manager .layer > button > div {
- flex-shrink: 0;
-}
-/* 행 안의 아이콘 버튼은 여백을 줄여 이름 몫을 남긴다 — 아이콘 6개가 한 행을 다 먹었다. */
-.cad-layer-manager .layer > button [data-size="small"] {
- padding-left: 2px;
- padding-right: 2px;
- min-width: 0;
-}
-/* 도면층 버튼 — 색은 토큰으로만, 상태는 Button이 붙이는 data-* 속성으로 가른다. */
-.cad-layer-manager button[data-type="regular"] {
- background: var(--cad-chrome-sunken);
- color: var(--cad-accent);
-}
-.cad-layer-manager button[data-type="transparent"] {
- background: transparent;
- color: var(--cad-accent);
-}
-.cad-layer-manager button:hover {
- background: var(--cad-hover);
- color: var(--color-text);
-}
-.cad-layer-manager button[data-active="true"] {
- background: var(--color-primary);
- color: var(--color-primary-text);
-}
-
-.cad-view-controls {
- position: fixed;
- z-index: 3;
- right: 14px;
- bottom: calc(var(--cad-command-height) + var(--cad-status-height) + 14px);
- display: flex;
- align-items: center;
- overflow: hidden;
- border: 1px solid var(--cad-line);
- border-radius: 4px;
- background: var(--cad-chrome-raised);
- box-shadow: var(--shadow-lg);
-}
-/* 오토캐드 파일 끌어다 놓기 안내 — 캔버스 오른쪽 위 흐린 글씨(빠른 특성 창이 뜨면 그 아래로 가려짐) */
-.cad-drop-hint {
- position: fixed;
- z-index: 2;
- top: calc(var(--cad-title-height) + var(--cad-ribbon-height) + 8px);
- right: 14px;
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 2px;
- white-space: nowrap;
- padding: 2px 4px;
- border: 0;
- background: transparent;
- color: var(--cad-text-muted);
- font-size: 11px;
- text-align: right;
- opacity: 0.55;
- cursor: pointer;
-}
-.cad-drop-hint:hover {
- opacity: 1;
-}
-.cad-drop-hint__steps {
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- color: var(--cad-text-dim);
- font-size: 10px;
-}
-/* 파일을 끄는 동안 — 화면 가장자리 흐린 테두리(`dxf-clip-paste.ts`) */
-body.cad-file-dragging::after {
- content: '';
- position: fixed;
- z-index: 50;
- inset: 6px;
- border: 2px dashed var(--cad-accent);
- border-radius: 6px;
- opacity: 0.6;
- pointer-events: none;
-}
-
-.cad-view-controls button {
- width: 34px;
- height: 32px;
- border: 0;
- border-right: 1px solid var(--cad-line);
- background: transparent;
- font-size: 17px;
-}
-.cad-view-controls button:hover {
- background: var(--cad-hover);
-}
-.cad-view-controls__fit {
- color: var(--cad-accent);
- font-size: 15px;
-}
-.cad-view-controls span {
- min-width: 48px;
- color: var(--cad-text-dim);
- font-size: 10px;
- text-align: center;
-}
-
-/* 하단 명령어 입력창은 숨김 처리 (마우스 커서 단축키 입력으로 대체) */
-.cad-command-area {
- position: fixed;
- z-index: 3;
- right: 0;
- bottom: var(--cad-status-height);
- left: var(--cad-panel-width);
- height: var(--cad-command-height);
- display: flex;
- flex-direction: column;
- gap: 4px;
- padding: 6px 10px;
- background: var(--cad-chrome);
- border-top: 1px solid var(--cad-line);
-}
-.cad-command-history {
- display: flex;
- flex-direction: column;
- flex: 1;
- justify-content: flex-end;
- overflow: hidden;
- color: var(--cad-text-muted);
- font: 11px Consolas, monospace;
-}
-.cad-command-suggestions {
- position: absolute;
- z-index: 6;
- bottom: 100%;
- left: 10px;
- display: flex;
- flex-direction: column;
- min-width: 220px;
- padding: 4px;
- background: var(--cad-chrome-raised);
- border: 1px solid var(--cad-line);
- border-radius: 4px;
- box-shadow: var(--shadow-lg);
-}
-.cad-command-suggestions button {
- padding: 4px 8px;
- border: 0;
- border-radius: 3px;
- background: transparent;
- font: 11px Consolas, monospace;
- text-align: left;
-}
-.cad-command-suggestions button:hover {
- background: var(--cad-hover);
-}
-.cad-prop--wide select {
- min-width: 132px;
-}
-.cad-command-prompt {
- max-width: 42%;
- overflow: hidden;
- color: var(--cad-text-dim);
- font-size: 11px;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-.cad-command-area form {
- display: flex;
- align-items: center;
- gap: 7px;
- height: 28px;
-}
-.cad-command-area label {
- color: var(--color-text);
- font-size: 11px;
- font-weight: 600;
-}
-.cad-command-area input {
- flex: 1;
- height: 26px;
- padding: 0 8px;
- border: 1px solid var(--cad-line);
- border-radius: 2px;
- outline: none;
- background: var(--cad-chrome-sunken);
- color: var(--cad-text);
- font: 11px Consolas, monospace;
-}
-.cad-command-area input:focus {
- border-color: var(--color-focus-ring);
- box-shadow: 0 0 0 1px var(--color-focus-ring);
-}
-
-.cad-statusbar {
- position: fixed;
- z-index: 3;
- right: 0;
- bottom: 0;
- left: 0;
- height: var(--cad-status-height);
- display: flex;
- align-items: center;
- gap: 2px;
- padding: 0 8px;
- background: var(--cad-chrome);
- border-top: 1px solid var(--cad-line);
-}
-.cad-statusbar button {
- height: 21px;
- padding: 0 8px;
- border: 1px solid transparent;
- border-radius: 2px;
- background: transparent;
- color: var(--cad-text-dim);
- font-size: 10px;
-}
-.cad-statusbar button:hover {
- background: var(--cad-hover);
-}
-.cad-statusbar button[data-active="true"] {
- border-color: var(--cad-accent);
- background: var(--color-primary);
- color: var(--color-primary-text);
-}
-.cad-statusbar__hint {
- margin-left: auto;
- color: var(--cad-text-muted);
- font-size: 10px;
-}
-
-@media (max-width: 800px) {
- :root {
- --cad-panel-width: 200px;
- }
- .cad-statusbar__hint {
- display: none;
- }
-}
-
-/* 특성 팔레트 — 값을 바로 고치는 입력들 */
-.cad-properties-editor {
- display: flex;
- flex-direction: column;
- gap: 7px;
-}
-.cad-properties-editor__title {
- color: var(--color-text);
- font-size: 13px;
- font-weight: 600;
-}
-.cad-properties-editor label {
- display: grid;
- grid-template-columns: 72px 1fr;
- align-items: center;
- gap: 8px;
- font-size: 11px;
- color: var(--cad-text-dim);
-}
-.cad-properties-editor select,
-.cad-properties-editor input {
- height: 24px;
- min-width: 0;
- padding: 0 4px;
- border: 1px solid var(--cad-line);
- border-radius: 3px;
- background: var(--cad-chrome-sunken);
- color: var(--cad-text);
- font-size: 11px;
-}
-.cad-properties-editor__readout {
- margin: 6px 0 0;
- border-top: 1px solid var(--cad-line);
-}
-.cad-properties-editor__readout div {
- display: grid;
- grid-template-columns: 72px 1fr;
- padding: 5px 0;
- border-bottom: 1px solid var(--cad-line);
- font-size: 11px;
-}
-.cad-properties-editor__readout dt {
- color: var(--cad-text-dim);
-}
-.cad-properties-editor__readout dd {
- margin: 0;
- overflow: hidden;
- color: var(--cad-text);
- text-overflow: ellipsis;
-}
-.cad-properties__empty {
- margin: 0;
- color: var(--cad-text-muted);
- font-size: 11px;
-}
-
-/* 빠른 특성 — 화면 위에 뜨는 작은 상자 */
-.cad-quick-properties {
- position: fixed;
- z-index: 5;
- top: calc(var(--cad-title-height) + var(--cad-ribbon-height) + 12px);
- right: 14px;
- width: 240px;
- padding: 8px 10px 10px;
- background: var(--cad-chrome-raised);
- border: 1px solid var(--cad-line);
- border-radius: 5px;
- box-shadow: var(--shadow-lg);
-}
-.cad-quick-properties__header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 6px;
- color: var(--cad-text-dim);
- font-size: 11px;
-}
-.cad-quick-properties__header button {
- border: 0;
- background: transparent;
- color: var(--cad-text-muted);
- font-size: 12px;
-}
-
-/* 블록 라이브러리 팔레트 (INSERT/BLOCK) */
-.cad-block-library {
- position: fixed;
- z-index: 5;
- top: calc(var(--cad-title-height) + var(--cad-ribbon-height) + 12px);
- right: 14px;
- width: 240px;
- padding: 8px 10px 10px;
- background: var(--cad-chrome-raised);
- border: 1px solid var(--cad-line);
- border-radius: 5px;
- box-shadow: var(--shadow-lg);
-}
-.cad-block-library__empty {
- margin: 0;
- color: var(--cad-text-muted);
- font-size: 11px;
- line-height: 1.5;
-}
-.cad-block-library__list {
- max-height: 220px;
- margin: 0;
- padding: 0;
- overflow-y: auto;
- list-style: none;
-}
-.cad-block-library__list li {
- display: flex;
- align-items: center;
- gap: 4px;
-}
-.cad-block-library__list li button {
- border: 0;
- background: transparent;
- color: var(--cad-text);
- font-size: 12px;
-}
-.cad-block-library__name {
- flex: 1;
- overflow: hidden;
- padding: 3px 4px;
- text-align: left;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.cad-block-library__name:hover {
- background: var(--cad-chrome-sunken);
-}
-.cad-block-library__actions {
- display: flex;
- gap: 6px;
- margin-top: 8px;
-}
-.cad-block-library__actions button {
- flex: 1;
- padding: 4px 0;
- border: 1px solid var(--cad-line);
- border-radius: 3px;
- background: transparent;
- color: var(--cad-text-dim);
- font-size: 11px;
-}
-
-/* 도각 자리표 패널 — 도각 편집으로 도면을 실었을 때만 뜬다 (2026-09-06 사용자 지시로
- 부모 사이드바에서 캐드 안으로 옮김). 도면 오른쪽 위, 리본 아래에 붙는다. */
-.cad-frame-tokens {
- position: fixed;
- /* 오른쪽 위는 진행단계 패널이 쓴다 — 아래쪽(상태막대·명령행 위)에 붙인다. */
- right: 12px;
- bottom: calc(var(--cad-status-height) + var(--cad-command-height) + 8px);
- z-index: 3;
- max-height: 46vh;
- overflow-y: auto;
- display: flex;
- flex-direction: column;
- gap: 6px;
- width: 236px;
- padding: 8px;
- border: 1px solid var(--cad-line);
- border-radius: 6px;
- background: var(--cad-chrome-raised);
- box-shadow: var(--shadow-lg);
- color: var(--cad-text);
-}
-
-.cad-frame-tokens__header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- gap: 6px;
- color: var(--cad-text-dim);
- font-size: 11px;
- line-height: 1.4;
-}
-
-.cad-frame-tokens__fold {
- flex: none;
- border: 1px solid var(--cad-line);
- border-radius: 4px;
- background: transparent;
- color: var(--cad-text);
- cursor: pointer;
-}
-
-.cad-frame-tokens__group {
- display: flex;
- flex-wrap: wrap;
- gap: 4px;
- align-items: center;
-}
-
-.cad-frame-tokens__title {
- width: 100%;
- color: var(--cad-text-dim);
- font-size: 11px;
-}
-
-.cad-frame-tokens__button {
- padding: 3px 7px;
- border: 1px solid var(--cad-line);
- border-radius: 4px;
- background: var(--cad-chrome);
- color: var(--cad-text);
- font-size: 11px;
- cursor: pointer;
-}
-
-.cad-frame-tokens__button:hover {
- background: var(--cad-accent-soft, var(--cad-chrome-raised));
-}
-
-/* 자리표 칸 크기 입력 (2026-09-06) */
-.cad-frame-tokens__size {
- display: flex;
- align-items: center;
- gap: 4px;
- color: var(--cad-text-dim);
- font-size: 11px;
-}
-
-.cad-frame-tokens__size input {
- width: 64px;
- padding: 2px 4px;
- border: 1px solid var(--cad-line);
- border-radius: 4px;
- background: var(--cad-chrome);
- color: var(--cad-text);
- font-size: 11px;
-}
diff --git a/B07_DesignDetail/openwebcad/src/App.tsx b/B07_DesignDetail/openwebcad/src/App.tsx
index 370698bba..e5cbee69d 100644
--- a/B07_DesignDetail/openwebcad/src/App.tsx
+++ b/B07_DesignDetail/openwebcad/src/App.tsx
@@ -1,4 +1,5 @@
import './App.css';
+import './App_Layers.css';
import { ToastContainer } from 'react-toastify';
import { FramePlaceholderPanel } from './components/FramePlaceholderPanel.tsx';
import { Toolbar } from './components/Toolbar.tsx';
diff --git a/B07_DesignDetail/openwebcad/src/App_Layers.css b/B07_DesignDetail/openwebcad/src/App_Layers.css
new file mode 100644
index 000000000..c46a6d7d1
--- /dev/null
+++ b/B07_DesignDetail/openwebcad/src/App_Layers.css
@@ -0,0 +1,477 @@
+/* 도면층 행: 이름은 줄여 담고 아이콘은 줄이지 않는다. 이름이 안 줄면 오른쪽 아이콘이
+ 행 밖으로 밀려 잘린다 (2026-09-01 실측: 내용 237~286px / 보이는 폭 229px). */
+.cad-layer-manager .layer > button > span {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.cad-layer-manager .layer > button > div {
+ flex-shrink: 0;
+}
+/* 행 안의 아이콘 버튼은 여백을 줄여 이름 몫을 남긴다 — 아이콘 6개가 한 행을 다 먹었다. */
+.cad-layer-manager .layer > button [data-size="small"] {
+ padding-left: 2px;
+ padding-right: 2px;
+ min-width: 0;
+}
+/* 도면층 버튼 — 색은 토큰으로만, 상태는 Button이 붙이는 data-* 속성으로 가른다. */
+.cad-layer-manager button[data-type="regular"] {
+ background: var(--cad-chrome-sunken);
+ color: var(--cad-accent);
+}
+.cad-layer-manager button[data-type="transparent"] {
+ background: transparent;
+ color: var(--cad-accent);
+}
+.cad-layer-manager button:hover {
+ background: var(--cad-hover);
+ color: var(--color-text);
+}
+.cad-layer-manager button[data-active="true"] {
+ background: var(--color-primary);
+ color: var(--color-primary-text);
+}
+
+.cad-view-controls {
+ position: fixed;
+ z-index: 3;
+ right: 14px;
+ bottom: calc(var(--cad-command-height) + var(--cad-status-height) + 14px);
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+ border: 1px solid var(--cad-line);
+ border-radius: 4px;
+ background: var(--cad-chrome-raised);
+ box-shadow: var(--shadow-lg);
+}
+/* 오토캐드 파일 끌어다 놓기 안내 — 캔버스 오른쪽 위 흐린 글씨(빠른 특성 창이 뜨면 그 아래로 가려짐) */
+.cad-drop-hint {
+ position: fixed;
+ z-index: 2;
+ top: calc(var(--cad-title-height) + var(--cad-ribbon-height) + 8px);
+ right: 14px;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 2px;
+ white-space: nowrap;
+ padding: 2px 4px;
+ border: 0;
+ background: transparent;
+ color: var(--cad-text-muted);
+ font-size: 11px;
+ text-align: right;
+ opacity: 0.55;
+ cursor: pointer;
+}
+.cad-drop-hint:hover {
+ opacity: 1;
+}
+.cad-drop-hint__steps {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ color: var(--cad-text-dim);
+ font-size: 10px;
+}
+/* 파일을 끄는 동안 — 화면 가장자리 흐린 테두리(`dxf-clip-paste.ts`) */
+body.cad-file-dragging::after {
+ content: '';
+ position: fixed;
+ z-index: 50;
+ inset: 6px;
+ border: 2px dashed var(--cad-accent);
+ border-radius: 6px;
+ opacity: 0.6;
+ pointer-events: none;
+}
+
+.cad-view-controls button {
+ width: 34px;
+ height: 32px;
+ border: 0;
+ border-right: 1px solid var(--cad-line);
+ background: transparent;
+ font-size: 17px;
+}
+.cad-view-controls button:hover {
+ background: var(--cad-hover);
+}
+.cad-view-controls__fit {
+ color: var(--cad-accent);
+ font-size: 15px;
+}
+.cad-view-controls span {
+ min-width: 48px;
+ color: var(--cad-text-dim);
+ font-size: 10px;
+ text-align: center;
+}
+
+/* 하단 명령어 입력창은 숨김 처리 (마우스 커서 단축키 입력으로 대체) */
+.cad-command-area {
+ position: fixed;
+ z-index: 3;
+ right: 0;
+ bottom: var(--cad-status-height);
+ left: var(--cad-panel-width);
+ height: var(--cad-command-height);
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ padding: 6px 10px;
+ background: var(--cad-chrome);
+ border-top: 1px solid var(--cad-line);
+}
+.cad-command-history {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ justify-content: flex-end;
+ overflow: hidden;
+ color: var(--cad-text-muted);
+ font: 11px Consolas, monospace;
+}
+.cad-command-suggestions {
+ position: absolute;
+ z-index: 6;
+ bottom: 100%;
+ left: 10px;
+ display: flex;
+ flex-direction: column;
+ min-width: 220px;
+ padding: 4px;
+ background: var(--cad-chrome-raised);
+ border: 1px solid var(--cad-line);
+ border-radius: 4px;
+ box-shadow: var(--shadow-lg);
+}
+.cad-command-suggestions button {
+ padding: 4px 8px;
+ border: 0;
+ border-radius: 3px;
+ background: transparent;
+ font: 11px Consolas, monospace;
+ text-align: left;
+}
+.cad-command-suggestions button:hover {
+ background: var(--cad-hover);
+}
+.cad-prop--wide select {
+ min-width: 132px;
+}
+.cad-command-prompt {
+ max-width: 42%;
+ overflow: hidden;
+ color: var(--cad-text-dim);
+ font-size: 11px;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+.cad-command-area form {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ height: 28px;
+}
+.cad-command-area label {
+ color: var(--color-text);
+ font-size: 11px;
+ font-weight: 600;
+}
+.cad-command-area input {
+ flex: 1;
+ height: 26px;
+ padding: 0 8px;
+ border: 1px solid var(--cad-line);
+ border-radius: 2px;
+ outline: none;
+ background: var(--cad-chrome-sunken);
+ color: var(--cad-text);
+ font: 11px Consolas, monospace;
+}
+.cad-command-area input:focus {
+ border-color: var(--color-focus-ring);
+ box-shadow: 0 0 0 1px var(--color-focus-ring);
+}
+
+.cad-statusbar {
+ position: fixed;
+ z-index: 3;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: var(--cad-status-height);
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ padding: 0 8px;
+ background: var(--cad-chrome);
+ border-top: 1px solid var(--cad-line);
+}
+.cad-statusbar button {
+ height: 21px;
+ padding: 0 8px;
+ border: 1px solid transparent;
+ border-radius: 2px;
+ background: transparent;
+ color: var(--cad-text-dim);
+ font-size: 10px;
+}
+.cad-statusbar button:hover {
+ background: var(--cad-hover);
+}
+.cad-statusbar button[data-active="true"] {
+ border-color: var(--cad-accent);
+ background: var(--color-primary);
+ color: var(--color-primary-text);
+}
+.cad-statusbar__hint {
+ margin-left: auto;
+ color: var(--cad-text-muted);
+ font-size: 10px;
+}
+
+@media (max-width: 800px) {
+ :root {
+ --cad-panel-width: 200px;
+ }
+ .cad-statusbar__hint {
+ display: none;
+ }
+}
+
+/* 특성 팔레트 — 값을 바로 고치는 입력들 */
+.cad-properties-editor {
+ display: flex;
+ flex-direction: column;
+ gap: 7px;
+}
+.cad-properties-editor__title {
+ color: var(--color-text);
+ font-size: 13px;
+ font-weight: 600;
+}
+.cad-properties-editor label {
+ display: grid;
+ grid-template-columns: 72px 1fr;
+ align-items: center;
+ gap: 8px;
+ font-size: 11px;
+ color: var(--cad-text-dim);
+}
+.cad-properties-editor select,
+.cad-properties-editor input {
+ height: 24px;
+ min-width: 0;
+ padding: 0 4px;
+ border: 1px solid var(--cad-line);
+ border-radius: 3px;
+ background: var(--cad-chrome-sunken);
+ color: var(--cad-text);
+ font-size: 11px;
+}
+.cad-properties-editor__readout {
+ margin: 6px 0 0;
+ border-top: 1px solid var(--cad-line);
+}
+.cad-properties-editor__readout div {
+ display: grid;
+ grid-template-columns: 72px 1fr;
+ padding: 5px 0;
+ border-bottom: 1px solid var(--cad-line);
+ font-size: 11px;
+}
+.cad-properties-editor__readout dt {
+ color: var(--cad-text-dim);
+}
+.cad-properties-editor__readout dd {
+ margin: 0;
+ overflow: hidden;
+ color: var(--cad-text);
+ text-overflow: ellipsis;
+}
+.cad-properties__empty {
+ margin: 0;
+ color: var(--cad-text-muted);
+ font-size: 11px;
+}
+
+/* 빠른 특성 — 화면 위에 뜨는 작은 상자 */
+.cad-quick-properties {
+ position: fixed;
+ z-index: 5;
+ top: calc(var(--cad-title-height) + var(--cad-ribbon-height) + 12px);
+ right: 14px;
+ width: 240px;
+ padding: 8px 10px 10px;
+ background: var(--cad-chrome-raised);
+ border: 1px solid var(--cad-line);
+ border-radius: 5px;
+ box-shadow: var(--shadow-lg);
+}
+.cad-quick-properties__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 6px;
+ color: var(--cad-text-dim);
+ font-size: 11px;
+}
+.cad-quick-properties__header button {
+ border: 0;
+ background: transparent;
+ color: var(--cad-text-muted);
+ font-size: 12px;
+}
+
+/* 블록 라이브러리 팔레트 (INSERT/BLOCK) */
+.cad-block-library {
+ position: fixed;
+ z-index: 5;
+ top: calc(var(--cad-title-height) + var(--cad-ribbon-height) + 12px);
+ right: 14px;
+ width: 240px;
+ padding: 8px 10px 10px;
+ background: var(--cad-chrome-raised);
+ border: 1px solid var(--cad-line);
+ border-radius: 5px;
+ box-shadow: var(--shadow-lg);
+}
+.cad-block-library__empty {
+ margin: 0;
+ color: var(--cad-text-muted);
+ font-size: 11px;
+ line-height: 1.5;
+}
+.cad-block-library__list {
+ max-height: 220px;
+ margin: 0;
+ padding: 0;
+ overflow-y: auto;
+ list-style: none;
+}
+.cad-block-library__list li {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+.cad-block-library__list li button {
+ border: 0;
+ background: transparent;
+ color: var(--cad-text);
+ font-size: 12px;
+}
+.cad-block-library__name {
+ flex: 1;
+ overflow: hidden;
+ padding: 3px 4px;
+ text-align: left;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.cad-block-library__name:hover {
+ background: var(--cad-chrome-sunken);
+}
+.cad-block-library__actions {
+ display: flex;
+ gap: 6px;
+ margin-top: 8px;
+}
+.cad-block-library__actions button {
+ flex: 1;
+ padding: 4px 0;
+ border: 1px solid var(--cad-line);
+ border-radius: 3px;
+ background: transparent;
+ color: var(--cad-text-dim);
+ font-size: 11px;
+}
+
+/* 도각 자리표 패널 — 도각 편집으로 도면을 실었을 때만 뜬다 (2026-09-06 사용자 지시로
+ 부모 사이드바에서 캐드 안으로 옮김). 도면 오른쪽 위, 리본 아래에 붙는다. */
+.cad-frame-tokens {
+ position: fixed;
+ /* 오른쪽 위는 진행단계 패널이 쓴다 — 아래쪽(상태막대·명령행 위)에 붙인다. */
+ right: 12px;
+ bottom: calc(var(--cad-status-height) + var(--cad-command-height) + 8px);
+ z-index: 3;
+ max-height: 46vh;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ width: 236px;
+ padding: 8px;
+ border: 1px solid var(--cad-line);
+ border-radius: 6px;
+ background: var(--cad-chrome-raised);
+ box-shadow: var(--shadow-lg);
+ color: var(--cad-text);
+}
+
+.cad-frame-tokens__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 6px;
+ color: var(--cad-text-dim);
+ font-size: 11px;
+ line-height: 1.4;
+}
+
+.cad-frame-tokens__fold {
+ flex: none;
+ border: 1px solid var(--cad-line);
+ border-radius: 4px;
+ background: transparent;
+ color: var(--cad-text);
+ cursor: pointer;
+}
+
+.cad-frame-tokens__group {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+ align-items: center;
+}
+
+.cad-frame-tokens__title {
+ width: 100%;
+ color: var(--cad-text-dim);
+ font-size: 11px;
+}
+
+.cad-frame-tokens__button {
+ padding: 3px 7px;
+ border: 1px solid var(--cad-line);
+ border-radius: 4px;
+ background: var(--cad-chrome);
+ color: var(--cad-text);
+ font-size: 11px;
+ cursor: pointer;
+}
+
+.cad-frame-tokens__button:hover {
+ background: var(--cad-accent-soft, var(--cad-chrome-raised));
+}
+
+/* 자리표 칸 크기 입력 (2026-09-06) */
+.cad-frame-tokens__size {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ color: var(--cad-text-dim);
+ font-size: 11px;
+}
+
+.cad-frame-tokens__size input {
+ width: 64px;
+ padding: 2px 4px;
+ border: 1px solid var(--cad-line);
+ border-radius: 4px;
+ background: var(--cad-chrome);
+ color: var(--cad-text);
+ font-size: 11px;
+}
diff --git a/B08_Quantity/B08_Quantity_UI_Milestone_Modal.ts b/B08_Quantity/B08_Quantity_UI_Milestone_Modal.ts
index 97c93a15f..e665d5969 100644
--- a/B08_Quantity/B08_Quantity_UI_Milestone_Modal.ts
+++ b/B08_Quantity/B08_Quantity_UI_Milestone_Modal.ts
@@ -16,6 +16,7 @@
* ========================================================================== */
import "../B01_Dashboard/B01_Dashboard_UI_Style.css";
+import "../B01_Dashboard/B01_Dashboard_UI_Style_Company.css";
import {
createButton,
createInputField,
diff --git a/resources/tester/test_179_2_ditch_row_compact.py b/resources/tester/test_179_2_ditch_row_compact.py
index c1c0866ba..1a175923d 100644
--- a/resources/tester/test_179_2_ditch_row_compact.py
+++ b/resources/tester/test_179_2_ditch_row_compact.py
@@ -12,7 +12,7 @@ def _src(rel: str) -> str:
def test_막힌_묶음은_숨김():
- css = _src("B06_Section/B06_Section_UI_Style_Cross.css")
+ css = _src("B06_Section/B06_Section_UI_Style_Cross.css") + _src("B06_Section/B06_Section_UI_Style_Cross_Chart.css")
body = re.search(r"\.b06-design__seg--disabled\s*\{([^}]*)\}", css).group(1)
assert "display: none;" in body
assert "opacity" not in body
diff --git a/resources/tester/test_318_cross_card.py b/resources/tester/test_318_cross_card.py
index 2ba716448..65300ab7a 100644
--- a/resources/tester/test_318_cross_card.py
+++ b/resources/tester/test_318_cross_card.py
@@ -182,7 +182,9 @@ def _rule(css: str, selector: str) -> str:
def test_css_layout() -> None:
- css = _src("B06_Section", "B06_Section_UI_Style_Cross.css")
+ css = _src("B06_Section", "B06_Section_UI_Style_Cross.css") + _src(
+ "B06_Section", "B06_Section_UI_Style_Cross_Chart.css"
+ )
assert "align-items: start" in _rule(css, ".b06-section__grid") # 카드 = 내용 높이
rock = _rule(css, ".b06-cross-card__rockb")
assert "position: absolute" not in rock and "translateX" not in rock # 왼쪽 맞춤
diff --git a/resources/tester/test_368_3_cross_modal.py b/resources/tester/test_368_3_cross_modal.py
index 3ea4faadc..4ed5f1e28 100644
--- a/resources/tester/test_368_3_cross_modal.py
+++ b/resources/tester/test_368_3_cross_modal.py
@@ -16,7 +16,7 @@ def test_추가_측점_선_점선_끌기_없음() -> None:
graph = _read("B06_Section/B06_Section_UI_Longitudinal.ts")
assert 'station.kind === "irregular" && !station.plus' in graph
assert 'station.plus ? "plus" : station.kind' in graph
- css = _read("B06_Section/B06_Section_UI_Style_Cross.css")
+ css = _read("B06_Section/B06_Section_UI_Style_Cross.css") + _read("B06_Section/B06_Section_UI_Style_Cross_Chart.css")
rule = css[css.index(".b06-chart__station-line--plus") :].split("}")[0]
assert "var(--color-warning)" in rule and "stroke-dasharray: 5 3" in rule
assert "PLUS_OWNER_PREFIX" in _read("B05_Profile/B05_Profile_UI_Profile_Layout.ts")
diff --git a/resources/tester/test_370_3_rock_cell.py b/resources/tester/test_370_3_rock_cell.py
index 1dd9ca9cc..439d74441 100644
--- a/resources/tester/test_370_3_rock_cell.py
+++ b/resources/tester/test_370_3_rock_cell.py
@@ -91,5 +91,7 @@ def test_배선_떠_있는_선_조정창_걷음() -> None:
assert "buildRockBoundaryControl" not in chrome # 479 — 그림 없는 암 카드도 빈 칸
detail = (B06 / "B06_Section_UI_Cross_Detail_Pick.ts").read_text(encoding="utf-8")
assert ".b06-chart__design-hit:not(.b06-chart__rock-hit)" in detail # 상세 표 강조에 안 섞임
- css = (B06 / "B06_Section_UI_Style_Cross.css").read_text(encoding="utf-8")
+ css = (B06 / "B06_Section_UI_Style_Cross.css").read_text(encoding="utf-8") + (
+ B06 / "B06_Section_UI_Style_Cross_Chart.css"
+ ).read_text(encoding="utf-8")
assert ".b06-cross-card__linecell.is-empty {" in css and "text-overflow: ellipsis;" in css
diff --git a/resources/tester/test_505_3_cross_card_text.py b/resources/tester/test_505_3_cross_card_text.py
index 05ecc02e1..a734832fb 100644
--- a/resources/tester/test_505_3_cross_card_text.py
+++ b/resources/tester/test_505_3_cross_card_text.py
@@ -71,7 +71,9 @@ def test_곡선_판_가둠_도구줄_횡단판_종단판() -> None:
def test_지반선_계획선_누름_통과() -> None:
- css = _read("B06_Section", "B06_Section_UI_Style_Cross.css")
+ css = _read("B06_Section", "B06_Section_UI_Style_Cross.css") + _read(
+ "B06_Section", "B06_Section_UI_Style_Cross_Chart.css"
+ )
assert ".b06-chart__profile,\n.b06-chart__design-profile {\n pointer-events: none;" in css
diff --git a/resources/tester/test_507_3_mc_label.py b/resources/tester/test_507_3_mc_label.py
index 02b8d94ca..87e6cfd4d 100644
--- a/resources/tester/test_507_3_mc_label.py
+++ b/resources/tester/test_507_3_mc_label.py
@@ -65,7 +65,7 @@ def test_b08_b09_earthwork_station_mc() -> None:
def test_b05_b06_screen_mc_emphasis() -> None:
- css = _src("B06_Section/B06_Section_UI_Style_Cross.css")
+ css = _src("B06_Section/B06_Section_UI_Style_Cross.css") + _src("B06_Section/B06_Section_UI_Style_Cross_Chart.css")
assert "header strong.b06-station--mc {" in css # 카드 머리 strong 규칙을 이김
for rule in ("\n.b06-chart__station-label--mc {", "\n.b06-station--mc {"):
body = css[css.index(rule) : css.index("}", css.index(rule))]
diff --git a/resources/tester/test_cad_host_tabs.py b/resources/tester/test_cad_host_tabs.py
index d5ba48fce..884ad53b6 100644
--- a/resources/tester/test_cad_host_tabs.py
+++ b/resources/tester/test_cad_host_tabs.py
@@ -225,7 +225,7 @@ def test_CAD_머리줄_없음_탭줄_빈자리_변수():
src = ROOT / "B07_DesignDetail/openwebcad/src"
ribbon = (src / "ribbon/Ribbon.tsx").read_text("utf-8")
quick = (src / "components/QuickAccessBar.tsx").read_text("utf-8")
- css = (src / "App.css").read_text("utf-8")
+ css = (src / "App.css").read_text("utf-8") + (src / "App_Layers.css").read_text("utf-8")
assert '' in ribbon
assert ribbon.index("cad-ribbon-tabs__slot") < ribbon.index("")
flat = " ".join(ribbon.split()) # 줄바꿈 · 들여쓰기 무관
diff --git a/resources/tester/test_modal_top_and_add_word.py b/resources/tester/test_modal_top_and_add_word.py
index 4b719fe42..89dc80eb1 100644
--- a/resources/tester/test_modal_top_and_add_word.py
+++ b/resources/tester/test_modal_top_and_add_word.py
@@ -53,7 +53,9 @@ def test_따로_둔_모달도_위_고정():
m01 = _text("M01_MasterData/M01_MasterData_UI_Style.css")
assert "align-items: flex-start;" in _block(m01, ".m01-procure")
assert "margin-top: 10vh;" in _block(m01, ".m01-procure__box")
- b01 = _text("B01_Dashboard/B01_Dashboard_UI_Style.css")
+ b01 = _text("B01_Dashboard/B01_Dashboard_UI_Style.css") + _text(
+ "B01_Dashboard/B01_Dashboard_UI_Style_Company.css"
+ )
assert "align-items: flex-start;" in _block(b01, ".b01-dashboard__modal")