From 5c0c8fd9c4e7d1ae94787a9bac1baf3d597e4bd2 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 6 Oct 2026 23:36:17 +0900 Subject: [PATCH] =?UTF-8?q?fix(B06):=20=ED=9A=A1=EB=8B=A8=20=EC=84=B8?= =?UTF-8?q?=EC=9B=94=EA=B5=90=20=C2=B7=20BOX=20=EB=B3=B8=EC=B2=B4=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=3D=20=EC=A2=8C=EC=B8=A1=20=EB=B3=B8?= =?UTF-8?q?=EC=B2=B4=20=EC=83=81=EC=9E=90=20=EA=B3=A0=EB=A6=84=20=C2=B7=20?= =?UTF-8?q?=EA=B0=95=EC=A1=B0(PLAN=2066-1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 세월교 바닥판 · 관 판정면 추가 → 「세월교」 상자 강조 · 스크롤 · 그림 바닥판 · 관 붉게 - BOX 구체 가운데 1/3 = 본체 · 양쪽 = 그 끝(유입 · 유출 상자 그대로) - 고름 값에 body 추가(FordPick · BoxPick) · 조정창은 본체에서 안 뜸 - B05 넘김 키 body 도 같은 길 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7 --- B06_Section/B06_Section_UI_Adjust_Dock.ts | 13 ++++++ B06_Section/B06_Section_UI_Cross_Box.ts | 42 ++++++++++++------- B06_Section/B06_Section_UI_Cross_Box_Panel.ts | 17 ++++---- B06_Section/B06_Section_UI_Cross_Ford.ts | 35 +++++++++++----- .../B06_Section_UI_Cross_Ford_Panel.ts | 15 +++---- .../B06_Section_UI_Cross_View_Bodies.ts | 21 ++++------ .../B06_Section_UI_Page_Ford_Controls.ts | 8 ++-- .../B06_Section_UI_Page_Structure_Pick.ts | 13 +++--- .../B06_Section_UI_Style_Cross_Areas.css | 8 ++++ 9 files changed, 110 insertions(+), 62 deletions(-) diff --git a/B06_Section/B06_Section_UI_Adjust_Dock.ts b/B06_Section/B06_Section_UI_Adjust_Dock.ts index 9c1ef254b..fde3e9deb 100644 --- a/B06_Section/B06_Section_UI_Adjust_Dock.ts +++ b/B06_Section/B06_Section_UI_Adjust_Dock.ts @@ -151,6 +151,19 @@ function moveRows(panelRoot: HTMLElement, selector: string, target: HTMLElement) function relocateSideRows(panelRoot: HTMLElement, scroll = true): void { clearSideSlots(); const side = panelRoot.dataset.side; + // 세월교 · BOX 본체 = 옮길 줄 없이 그 명세의 본체 상자만 강조(66-1) — 날개벽 칸이 든 명세 폼에서 찾음 + if (side === "body") { + const body = sideSlots?.wingInlet + .closest(".b05-structure__spec") + ?.querySelector( + 'fieldset[data-spec-container="ford"], fieldset[data-spec-container="body"]', + ); + if (!body || body.closest("[hidden]")) return; + setGroupLabel(body, ""); + body.classList.add("is-active"); + if (scroll) body.scrollIntoView({ block: "nearest" }); + return; + } if (!sideSlots || (side !== "inlet" && side !== "outlet" && side !== "extra")) return; const target = side === "extra" ? sideSlots.extra : slotOf(side); // 추가 기슭막이 칸은 평소 숨어 있다 — 고른 벽이 다단이면 **그 단이 딸린 칸 바로 diff --git a/B06_Section/B06_Section_UI_Cross_Box.ts b/B06_Section/B06_Section_UI_Cross_Box.ts index 1fccfe0b2..5e6e46382 100644 --- a/B06_Section/B06_Section_UI_Cross_Box.ts +++ b/B06_Section/B06_Section_UI_Cross_Box.ts @@ -27,8 +27,11 @@ export type { const SVG_NS = "http://www.w3.org/2000/svg"; +/** 고르는 부재 — 좌 · 우 끝 또는 본체(구체 가운데 1/3 · 좌측 「본체」 상자 · 66-1). */ +export type BoxPick = BoxSideRole | "body"; + /** 선택 강조를 카드 재생성 없이 갈아 끼우는 setter. */ -export type BoxHighlightSetter = (role: BoxSideRole | null) => void; +export type BoxHighlightSetter = (role: BoxPick | null) => void; /** * BOX암거 구체 오버레이 — computeBoxLayout 결과를 그린다. @@ -39,7 +42,7 @@ export function appendBoxOverlay( layout: BoxLayout, x: (offset: number) => number, toDisplayY: (elevation: number) => number, - onSelectSide?: (role: BoxSideRole) => void, + onSelectSide?: (role: BoxPick) => void, ): BoxHighlightSetter { const { box } = layout; const toXY = (point: OffsetPoint): [number, number] => [ @@ -133,21 +136,30 @@ export function appendBoxOverlay( label.textContent = layout.label.text; layer.append(label); - // 좌·우 절반을 덮는 투명 겹면 — 어느 끝을 조정할지 클릭으로 고른다. - const hits = new Map(); + // 투명 겹면 — 구체 가운데 1/3 = 본체, 그 바깥 양쪽 = 그 끝(66-1). 어느 것을 조정할지 클릭으로 고른다. + const hits = new Map(); if (onSelectSide) { const midOffset = (layout.sides[0].offset + layout.sides[1].offset) / 2; + const third = (layout.sides[0].offset - layout.sides[1].offset) / 6; const top = Math.max(...layout.topSlab.map((point) => point.elevation)); const bottom = Math.min(...layout.bottomSlab.map((point) => point.elevation)); - for (const side of layout.sides) { - const outer = side.apron.length ? side.apron[1].offset : side.offset; + const band = (from: number, to: number): OffsetPoint[] => [ + { offset: from, elevation: top }, + { offset: to, elevation: top }, + { offset: to, elevation: bottom }, + { offset: from, elevation: bottom }, + ]; + const parts: Array<[BoxPick, OffsetPoint[]]> = [ + ["body", band(midOffset - third, midOffset + third)], + ...layout.sides.map((side): [BoxPick, OffsetPoint[]] => { + const outer = side.apron.length ? side.apron[1].offset : side.offset; + const inner = midOffset + Math.sign(side.offset - midOffset) * Math.abs(third); + return [side.role, band(inner, outer)]; + }), + ]; + for (const [role, points] of parts) { const hit = polygon( - [ - { offset: midOffset, elevation: top }, - { offset: outer, elevation: top }, - { offset: outer, elevation: bottom }, - { offset: midOffset, elevation: bottom }, - ], + points, // 강조용 클래스를 하나 더 단다 — 고른 끝을 옅게 칠한다(2026-08-30 사용자: // BOX암거는 선택해도 아무 표시가 없었다). 구체 부재는 좌·우가 한 몸이라 // 그쪽을 칠하면 어느 끝을 고른 것인지 되레 흐려진다. @@ -156,14 +168,14 @@ export function appendBoxOverlay( ); hit.addEventListener("click", (event) => { event.stopPropagation(); - onSelectSide(side.role); + onSelectSide(role); }); - hits.set(side.role, hit); + hits.set(role, hit); layer.append(hit); } } - return (role: BoxSideRole | null): void => { + return (role: BoxPick | null): void => { for (const [side, hit] of hits) hit.classList.toggle("is-active", side === role); }; } diff --git a/B06_Section/B06_Section_UI_Cross_Box_Panel.ts b/B06_Section/B06_Section_UI_Cross_Box_Panel.ts index 4aa0acff8..3c77b6975 100644 --- a/B06_Section/B06_Section_UI_Cross_Box_Panel.ts +++ b/B06_Section/B06_Section_UI_Cross_Box_Panel.ts @@ -9,6 +9,7 @@ * ========================================================================== */ import type { BoxSideAdjust, BoxSideRole } from "./B06_Section_UI_Cross_Box_Geom"; +import type { BoxPick } from "./B06_Section_UI_Cross_Box"; import { bindArrowKeys, bindDragHandle, @@ -41,7 +42,8 @@ export interface BoxPanelDeps { export interface BoxPanelHandle { root: HTMLElement; /** null이면 숨긴다. 값이 오면 그 측 기준으로 다시 그린다. */ - show: (role: BoxSideRole | null) => void; + /** 본체는 창 없이 좌측 「본체」 상자만(66-1). */ + show: (role: BoxPick | null) => void; } /** 한 걸음(m) — 사용자 지정 0.1m. */ @@ -133,15 +135,16 @@ export function buildBoxPanel(deps: BoxPanelDeps, opts?: { dock?: boolean }): Bo return { root, show(role) { - current = role; - root.classList.toggle("is-hidden", role === null); + current = role === "body" ? null : role; + root.classList.toggle("is-hidden", current === null); // 좌측 [횡단 조정]에 어느 칸을 세울지 알린다 — 날개벽(유입)/(유출) 칸이다 // (세월교와 같은 규약, 2026-08-30 사용자). - root.dataset.side = role === null ? "" : (deps.wingRoleFor?.(role) ?? ""); + root.dataset.side = + role === null || role === "body" ? (role ?? "") : (deps.wingRoleFor?.(role) ?? ""); root.dataset.panelTitle = role === null ? "" : "BOX암거"; arrows.detach(); drag.detach(); - if (role !== null) { + if (current !== null) { arrows.attach(); drag.attach(); } @@ -163,6 +166,6 @@ export interface BoxControl { role: "inlet" | "outlet", patch: Partial<{ installed: boolean; height_m: number; length_m: number; angle_deg: number }>, ) => void; - selectedFor: (chainageM: number) => BoxSideRole | null; - select: (chainageM: number, role: BoxSideRole | null) => void; + selectedFor: (chainageM: number) => BoxPick | null; + select: (chainageM: number, role: BoxPick | null) => void; } diff --git a/B06_Section/B06_Section_UI_Cross_Ford.ts b/B06_Section/B06_Section_UI_Cross_Ford.ts index 6ed3171b1..81879e0b5 100644 --- a/B06_Section/B06_Section_UI_Cross_Ford.ts +++ b/B06_Section/B06_Section_UI_Cross_Ford.ts @@ -27,8 +27,11 @@ export type { const SVG_NS = "http://www.w3.org/2000/svg"; +/** 고르는 부재 — 측벽(유입 · 유출) 또는 본체(바닥판 · 관 · 좌측 「세월교」 상자 · 66-1). */ +export type FordPick = FordWallRole | "body"; + /** 벽 강조를 카드 재생성 없이 갈아 끼우는 setter. */ -export type FordHighlightSetter = (key: FordWallRole | null) => void; +export type FordHighlightSetter = (key: FordPick | null) => void; /** * 세월교 구체 오버레이 — computeFordLayout 결과를 그린다. @@ -41,7 +44,7 @@ export function appendFordOverlay( layout: FordLayout, x: (offset: number) => number, toDisplayY: (elevation: number) => number, - onSelectWall?: (key: FordWallRole) => void, + onSelectWall?: (key: FordPick) => void, ): FordHighlightSetter { const { ford } = layout; const toXY = (point: OffsetPoint): [number, number] => [ @@ -80,7 +83,7 @@ export function appendFordOverlay( }): string => (wing.installed ? `${wing.length_m ?? 0}m·${wing.angle_deg ?? 0}°` : "없음"); // ① 바닥판 — 두 측벽 사이를 잇는 판. 각 측 바깥 연장은 측벽 부재로 함께 그린다. - layer.append( + const slab = layer.appendChild( polygon( layout.slabBridge, "b06-chart__ford-slab", @@ -115,14 +118,14 @@ export function appendFordOverlay( } // ③ 관 — 바닥판 상면에 안힌다. 단면엔 1개만, 련수는 라벨로 알린다. - layer.append( - polygon( - layout.pipe.outer, - "b06-chart__culvert-pipe b06-chart__culvert-pipe--outer", - `${layout.label.text} — 관 밑이 바닥판 상면`, - ), - polygon(layout.pipe.inner, "b06-chart__culvert-pipe", layout.label.text), + const pipeOuter = polygon( + layout.pipe.outer, + "b06-chart__culvert-pipe b06-chart__culvert-pipe--outer", + `${layout.label.text} — 관 밑이 바닥판 상면`, ); + const pipeInner = polygon(layout.pipe.inner, "b06-chart__culvert-pipe", layout.label.text); + layer.append(pipeOuter, pipeInner); + const bodyShapes = [slab, pipeOuter, pipeInner]; // ④ 계류측 마감선 — 구조물이 원지반 위면 성토부선, 안이면 절토선(집수정과 같은 체계). for (const side of layout.sides) { @@ -142,6 +145,15 @@ export function appendFordOverlay( // 관·채움이 벽 위에 겹쳐 클릭을 가로챈다 — 투명 겹면을 맨 위에 얹어 벽을 고른다 // (배수관 기슭막이 `culvert-revet-hit`와 같은 수법). if (onSelectWall) { + // 본체(바닥판 · 관) 판정면 — 벽 판정면보다 먼저 깔아 겹친 자리는 벽이 먹는다(66-1). + for (const points of [layout.slabBridge, layout.pipe.outer]) { + const hit = polygon(points, "b06-chart__culvert-revet-hit", "세월교 본체 선택"); + hit.addEventListener("click", (event) => { + event.stopPropagation(); + onSelectWall("body"); + }); + layer.append(hit); + } for (const side of layout.sides) { const wall = side.parts.find((part) => part.kind === "wall"); if (!wall) continue; @@ -163,9 +175,10 @@ export function appendFordOverlay( label.textContent = layout.label.text; layer.append(label); - return (key: FordWallRole | null): void => { + return (key: FordPick | null): void => { for (const [role, shapes] of walls) { for (const shape of shapes) shape.classList.toggle("is-active", role === key); } + for (const shape of bodyShapes) shape.classList.toggle("is-active", key === "body"); }; } diff --git a/B06_Section/B06_Section_UI_Cross_Ford_Panel.ts b/B06_Section/B06_Section_UI_Cross_Ford_Panel.ts index dda551ef5..2f924f569 100644 --- a/B06_Section/B06_Section_UI_Cross_Ford_Panel.ts +++ b/B06_Section/B06_Section_UI_Cross_Ford_Panel.ts @@ -12,6 +12,7 @@ * ========================================================================== */ import type { FordAdjust, FordWallAdjust, FordWallRole } from "./B06_Section_UI_Cross_Ford_Geom"; +import type { FordPick } from "./B06_Section_UI_Cross_Ford"; import { bindArrowKeys, bindDragHandle, @@ -44,8 +45,8 @@ export interface FordPanelDeps { export interface FordPanelHandle { root: HTMLElement; - /** null이면 숨긴다. 값이 오면 그 측벽 기준으로 다시 그린다. */ - show: (role: FordWallRole | null) => void; + /** null이면 숨긴다. 값이 오면 그 측벽 기준으로 다시 그린다 — 본체는 창 없이 좌측 「세월교」 상자만(66-1). */ + show: (role: FordPick | null) => void; } /** 한 걸음 — 집수정 9키와 같은 0.1m 눈금. */ @@ -157,8 +158,8 @@ export function buildFordPanel(deps: FordPanelDeps, opts?: { dock?: boolean }): return { root, show(role) { - current = role; - root.classList.toggle("is-hidden", role === null); + current = role === "body" ? null : role; + root.classList.toggle("is-hidden", current === null); // 좌측 폼에 어느 칸을 세울지 알린다 — 세월교는 그 측 날개벽 칸이다 // (배관 조정창이 유입구·유출구 칸을 가리키는 것과 같은 규약, 2026-08-30 지시 1). root.dataset.side = role ?? ""; @@ -166,7 +167,7 @@ export function buildFordPanel(deps: FordPanelDeps, opts?: { dock?: boolean }): root.dataset.panelTitle = role === null ? "" : "세월교"; arrows.detach(); drag.detach(); - if (role !== null) { + if (current !== null) { arrows.attach(); drag.attach(); } @@ -198,6 +199,6 @@ export interface FordControl { patch: Partial<{ installed: boolean; height_m: number; length_m: number; angle_deg: number }>, ) => void; /** 지금 선택된 측벽(측점별). */ - selectedFor: (chainageM: number) => FordWallRole | null; - select: (chainageM: number, role: FordWallRole | null) => void; + selectedFor: (chainageM: number) => FordPick | null; + select: (chainageM: number, role: FordPick | null) => void; } diff --git a/B06_Section/B06_Section_UI_Cross_View_Bodies.ts b/B06_Section/B06_Section_UI_Cross_View_Bodies.ts index d8ab44c67..86d662ab2 100644 --- a/B06_Section/B06_Section_UI_Cross_View_Bodies.ts +++ b/B06_Section/B06_Section_UI_Cross_View_Bodies.ts @@ -10,17 +10,13 @@ import type { FordAdjust, FordHighlightSetter, FordLayout, + FordPick, FordWallRole, } from "./B06_Section_UI_Cross_Ford"; import { buildFordPanel } from "./B06_Section_UI_Cross_Ford_Panel"; import type { FordControl, FordPanelHandle } from "./B06_Section_UI_Cross_Ford_Panel"; import { fordCardState, fordPanelDeps } from "./B06_Section_UI_Cross_View_Ford"; -import type { - BoxAdjust, - BoxHighlightSetter, - BoxLayout, - BoxSideRole, -} from "./B06_Section_UI_Cross_Box"; +import type { BoxAdjust, BoxHighlightSetter, BoxLayout, BoxPick } from "./B06_Section_UI_Cross_Box"; import { buildBoxPanel } from "./B06_Section_UI_Cross_Box_Panel"; import type { BoxControl, BoxPanelHandle } from "./B06_Section_UI_Cross_Box_Panel"; import { boxPanelDeps, structureToggle } from "./B06_Section_UI_Cross_View_Box"; @@ -40,8 +36,9 @@ export interface BodyWiringDeps { export interface BodyWiring { fordAdjust: () => FordAdjust | undefined; boxAdjust: () => BoxAdjust | undefined; - toggleFord: (role: FordWallRole) => void; - toggleBox: (role: BoxSideRole) => void; + /** 본체(`body`)는 조정창 없이 좌측 본체 상자만 고름(66-1). */ + toggleFord: (role: FordPick) => void; + toggleBox: (role: BoxPick) => void; /** 오버레이가 만들어 준 강조 setter를 등록하고 현재 선택을 다시 칠한다. */ attachFord: (setter: FordHighlightSetter, layout: FordLayout) => void; attachBox: (setter: BoxHighlightSetter, layout: BoxLayout) => void; @@ -93,15 +90,15 @@ export function createBodyWiring(deps: BodyWiringDeps): BodyWiring { const boxDock = boxDeps ? buildBoxPanel(boxDeps, { dock: true }) : null; const syncDock = ( dock: FordPanelHandle | BoxPanelHandle | null, - role: FordWallRole | BoxSideRole | null, + role: FordPick | BoxPick | null, ): void => { if (!dock) return; - (dock as { show: (role: FordWallRole | BoxSideRole | null) => void }).show(role); + (dock as { show: (role: FordPick | BoxPick | null) => void }).show(role); if (role) adoptAdjustPanel(dock.root); else releaseAdjustPanel(dock.root); }; - const toggleFord = structureToggle({ + const toggleFord = structureToggle({ current: () => fordRole, setCurrent: (value) => (fordRole = value), setActive: (value) => setFordActive(value), @@ -114,7 +111,7 @@ export function createBodyWiring(deps: BodyWiringDeps): BodyWiring { clearArea: deps.clearArea, selectCard: deps.selectCard, }); - const toggleBox = structureToggle({ + const toggleBox = structureToggle({ current: () => boxRole, setCurrent: (value) => (boxRole = value), setActive: (value) => setBoxActive(value), diff --git a/B06_Section/B06_Section_UI_Page_Ford_Controls.ts b/B06_Section/B06_Section_UI_Page_Ford_Controls.ts index a94fd89b5..687a1fd31 100644 --- a/B06_Section/B06_Section_UI_Page_Ford_Controls.ts +++ b/B06_Section/B06_Section_UI_Page_Ford_Controls.ts @@ -16,10 +16,10 @@ import { } from "@util/common_util_culvert_sets"; import type { CrossDesign, CrossSection } from "./B06_Section_Api_Fetch"; import { DEFAULT_FORD_WALL_ADJUST } from "./B06_Section_UI_Cross_Ford"; -import type { FordAdjust, FordWallAdjust, FordWallRole } from "./B06_Section_UI_Cross_Ford"; +import type { FordAdjust, FordPick, FordWallAdjust } from "./B06_Section_UI_Cross_Ford"; import type { FordControl } from "./B06_Section_UI_Cross_Ford_Panel"; import { DEFAULT_BOX_SIDE_ADJUST } from "./B06_Section_UI_Cross_Box"; -import type { BoxAdjust, BoxSideAdjust, BoxSideRole } from "./B06_Section_UI_Cross_Box"; +import type { BoxAdjust, BoxPick, BoxSideAdjust } from "./B06_Section_UI_Cross_Box"; import type { BoxControl } from "./B06_Section_UI_Cross_Box_Panel"; /** 날개벽 한 벌의 저장 키 — 세월교·BOX암거가 같은 옵션 이름을 쓴다(`wing_in*`/`wing_out*`). */ @@ -125,7 +125,7 @@ export function createFordControls(deps: FordControlDeps): FordControls { * 실어 3D가 같은 값으로 다시 그리게 한다. 관경·수량은 B05 정본이 원천이라 * 배수관 구간값과 같은 저장기(`pipe_points` 되쓰기)로 보낸다. */ const fordAdjustments = new Map(); - const fordSelections = new Map(); + const fordSelections = new Map(); const fordSessionKey = (): string | null => deps.sessionKey(); function loadFordAdjustments(): void { @@ -322,7 +322,7 @@ export function createBoxControls(deps: FordControlDeps): { } { const { round1, clampMove, sectionAt, patchCachedDesign } = deps; const adjustments = new Map(); - const selections = new Map(); + const selections = new Map(); function load(): void { adjustments.clear(); diff --git a/B06_Section/B06_Section_UI_Page_Structure_Pick.ts b/B06_Section/B06_Section_UI_Page_Structure_Pick.ts index bbeef09bd..79037c928 100644 --- a/B06_Section/B06_Section_UI_Page_Structure_Pick.ts +++ b/B06_Section/B06_Section_UI_Page_Structure_Pick.ts @@ -6,7 +6,8 @@ * 부재키는 **횡단도가 그 부재를 부르는 이름 그대로**다. 이름이 겹쳐도(배수관 유입 ↔ * 세월교 유입) 한 측점에는 시설이 하나뿐이라 헷갈리지 않는다 — 그 측점이 세월교면 * 세월교 조정창, BOX암거면 BOX 조정창, 아니면 기슭막이 조정창으로 보낸다. - * 본체(`body` — 세월교 월류부 상판·BOX 구체)는 고르는 부재가 아니라 카드까지만 연다. + * 본체(`body` — 세월교 월류부 상판·BOX 구체)는 세월교 · BOX 에서 좌측 본체 상자를 고른다(66-1) · + * 그 밖 시설은 카드까지만 연다. * * 세월교·BOX는 조정창 하나가 그 측 부재 여럿(벽·바닥·날개벽·에이프런)을 함께 다루므로 * 부재키가 `측이름:부재`(예 `inlet:wall`) 꼴이다 — **앞칸이 조정창 이름**이다. 3D 강조는 @@ -29,8 +30,8 @@ interface PickTargets { focusStation: (stationId: string) => void; refreshCard: (chainageM: number) => void; revetSelect: (chainageM: number, key: RevetKey) => void; - fordSelect: (chainageM: number, role: "inlet" | "outlet") => void; - boxSelect: (chainageM: number, role: "left" | "right") => void; + fordSelect: (chainageM: number, role: "inlet" | "outlet" | "body") => void; + boxSelect: (chainageM: number, role: "left" | "right" | "body") => void; } /** @@ -63,12 +64,12 @@ export function applyStructurePick( const key = handoff.key?.split(":")[0]; requestAnimationFrame(() => { targets.focusStation(target.station_id); - if (!key || key === "body") return; + if (!key) return; if (target.ford) { - if (key !== "inlet" && key !== "outlet") return; + if (key !== "inlet" && key !== "outlet" && key !== "body") return; targets.fordSelect(target.chainage_m, key); } else if (target.box) { - if (key !== "left" && key !== "right") return; + if (key !== "left" && key !== "right" && key !== "body") return; targets.boxSelect(target.chainage_m, key); } else { if (!REVET_KEYS.test(key)) return; diff --git a/B06_Section/B06_Section_UI_Style_Cross_Areas.css b/B06_Section/B06_Section_UI_Style_Cross_Areas.css index baca7195d..c07ccae0e 100644 --- a/B06_Section/B06_Section_UI_Style_Cross_Areas.css +++ b/B06_Section/B06_Section_UI_Style_Cross_Areas.css @@ -374,6 +374,14 @@ stroke-width: 1; stroke-dasharray: 4 3; stroke-linejoin: round; +/* 세월교 본체(바닥판 · 관) 선택 강조(66-1) — 측벽 강조와 같은 색. */ +.b06-chart__ford-slab.is-active, +.b06-chart__culvert-pipe.is-active { + fill: color-mix(in srgb, var(--color-danger) 30%, transparent); + stroke: var(--color-danger); + stroke-width: 2.2; +} + } /* 터파기 선(2026-09-09 사용자 확정 ④) — **파선**으로 그린다. 구조물 실체가 아니라