흐름 강도 계산은 이미 trace_flow()가 원본 1m 격자에서 하고 있었고 03_road_routing.npz에
저장까지 되어 있었다. 이번 작업은 그 원본값을 밖으로 꺼내 화면에 그리는 것이다.
- 강도 곡선 출력 간격을 5m -> 1m로 바꿔 계산 원본을 그대로 내보낸다(구간 합, 평균 아님).
구간 기준을 round -> floor로 바로잡았다. 도로 셀 누가거리가 전부 0.5 배수라
numpy의 짝수 반올림이 짝수 칸에 3배를 몰아 2m 주기 빗살을 만들고 있었다
(도로가 격자축과 나란한 구간은 홀수 칸이 전부 0이라 색이 점선으로 나왔다).
- find_inflow_hotspots(): 도로를 시점·기본 관(세류 교차)·종점으로 잘라 구역을 만들고
구역마다 floor(길이 / 관 최대간격) + 3개를 뽑는다. 강도 최대점부터 고르되 고른 지점
양 편측으로 관 최소간격만큼을 후보에서 빼 한쪽 쏠림을 막는다. 관 쪽 경계에서도 같은
거리만큼 물러난다 - 그러지 않으면 그 관이 이미 받는 물 전부가 관 옆 칸에서 다시
최대값으로 잡혀, 정작 관이 없어 보충이 필요한 자리가 뽑히지 못한다.
- GET /api/projects/{id}/drainage/road-inflow 신설(B04_wf1_Surface_Router_Inflow.py).
저장된 road_slot으로 그 1m 구간에 귀속된 셀 마스크를 만들어 외곽선만 돌려준다.
새 그래프 탐색 없음. npz는 mtime 키로 프로세스 캐시에 둔다.
- 응답에 schema_version을 넣어 형식이 바뀌면 옛 저장분을 무시하고 다시 계산하게 했다.
- 프론트: B04_wf1_Surface_UI_FlowStrength.ts 신설. 계획선 위에 1m 구간 로그 레인보우와
유입 집중점 마커(크기=강도, 번호)를 얹고, 마커를 고르면 기여 셀 외곽선을 겹쳐 그린다.
마커 안쪽만 선택 대상이며 팬은 가운데 버튼 전용이라는 규칙은 그대로 둔다.
좌표 변환은 MapRender에 모았다(normalizedToScreen / lonLatToScreen / metricToScreen).
- 사이드 패널: 지면 필터·서피스·스무딩을 "지표면 분석" 한 컨테이너로 모으고 스무딩을
드롭다운(적용/미적용)으로 바꿨다. 포인트·모델 표시 옵션은 "모델 표시 옵션" 하나로
합치고 맨 아래에 점 크기·밀도를 [값][게이지] 형태로 놓았다.
- DRAINAGE_ROAD_WIDTH_M 주석에 설계 도로폭이 아니라 D8 대각 통과를 막는 해석용 굽기
폭임을 명시했다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
480 lines
18 KiB
CSS
480 lines
18 KiB
CSS
/* =============================================================================
|
|
* ui_template_theme.css
|
|
* 글로벌 디자인 테마 및 CSS 변수 (라이트/다크)
|
|
*
|
|
* 출처: .agent/design.md — "Wiza" 스타일 레퍼런스
|
|
* 원칙:
|
|
* - 모든 색상/간격/폰트는 이 파일의 CSS 변수(var(--...))로만 참조.
|
|
* - 하드코딩된 Hex/px 값을 컴포넌트에 직접 입력 금지 (frontend.md §1).
|
|
* - 8px radius가 시그니처. pill/tag만 --radius-pills 사용.
|
|
* ========================================================================== */
|
|
|
|
:root {
|
|
/* ---------------------------------------------------------------------------
|
|
* 1. 색상 토큰 (Colors) — 바이올렛 단색 팔레트
|
|
* ------------------------------------------------------------------------ */
|
|
--color-deep-iris: #26114a; /* 헤드라인, filled 버튼 배경 (24px 이하) */
|
|
--color-plum-velvet: #312749; /* 네비 텍스트, 보조 제목, 카드 타이틀 */
|
|
--color-royal-amethyst: #3e0079; /* 링크, 포커스 링, 아이콘 하이라이트 */
|
|
--color-mist-violet: #edecff; /* 소프트 하이라이트 배경, 태그 배경 */
|
|
--color-lavender-wash: #b99aff; /* 그라디언트 스톱, 히어로 분위기 */
|
|
--color-twilight-beam: #cf8aff; /* 멀티스톱 장식 그라디언트 시작색 */
|
|
|
|
/* 중립 (Neutrals) */
|
|
--color-canvas: #ffffff; /* 페이지 배경, 카드 표면, 입력 필드 */
|
|
--color-paper: #f6f7fa; /* 미묘한 표면 리프트, 테이블 교차행 */
|
|
--color-mist: #e6e2e3; /* 헤어라인 보더, 구분선 */
|
|
--color-smoke: #c1c7cf; /* 비활성 상태, 스켈레톤 플레이스홀더 */
|
|
--color-ash: #9491a1; /* 뮤트 헬퍼 텍스트, placeholder */
|
|
--color-slate: #615e6e; /* 보조 본문 텍스트, 설명 */
|
|
--color-charcoal: #333333; /* 본문 텍스트, 링크, 아이콘 스트로크 */
|
|
--color-carbon: #222222; /* 다크 UI 요소, 니어블랙 액센트 */
|
|
--color-ink: #000000; /* 최대 대비 텍스트/보더 */
|
|
|
|
/* 상태 색상 (Status) — 바이올렛 계열 유지, 필수 기능색만 최소 추가 */
|
|
--color-success: #1f8a4c; /* 성공/승인 */
|
|
--color-warning: #b8860b; /* 경고 (design.md 별색 #f5b800 계열) */
|
|
--color-danger: #c0392b; /* 에러/삭제 */
|
|
--color-info: var(--color-royal-amethyst);
|
|
|
|
/* 그라디언트 (Gradient System) — 항상 흰 표면 뒤에만 배치, 텍스트 직상단 금지 */
|
|
--gradient-lavender-wash: linear-gradient(
|
|
90deg,
|
|
rgb(185, 154, 255),
|
|
rgb(125, 67, 255) 10%,
|
|
rgba(125, 67, 255, 0)
|
|
);
|
|
--gradient-twilight-beam: linear-gradient(
|
|
to right,
|
|
rgb(207, 138, 255),
|
|
rgb(255, 102, 193),
|
|
rgb(255, 173, 116),
|
|
rgb(170, 129, 255)
|
|
);
|
|
--gradient-section-tint: linear-gradient(
|
|
to bottom,
|
|
var(--color-canvas),
|
|
var(--color-mist-violet)
|
|
);
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 2. 의미 기반 별칭 (Semantic Aliases)
|
|
* 컴포넌트는 가급적 아래 별칭을 사용해 라이트/다크 전환에 대응.
|
|
* ------------------------------------------------------------------------ */
|
|
--color-bg: var(--color-canvas); /* 페이지 배경 */
|
|
--color-surface: var(--color-paper); /* 카드/패널 표면 */
|
|
--color-surface-raised: var(--color-canvas); /* 떠 있는 표면 */
|
|
--color-border: var(--color-mist); /* 기본 보더 */
|
|
--color-text: var(--color-deep-iris); /* 기본 본문 (제목 강조) */
|
|
--color-text-body: var(--color-charcoal); /* 일반 본문 */
|
|
--color-text-secondary: var(--color-slate); /* 보조 텍스트 */
|
|
--color-text-muted: var(--color-ash); /* 뮤트/placeholder */
|
|
--color-primary: var(--color-deep-iris); /* 주 액션 배경 */
|
|
--color-primary-text: var(--color-canvas); /* 주 액션 위 텍스트 */
|
|
--color-accent: var(--color-royal-amethyst); /* 링크/액센트 */
|
|
--color-focus-ring: var(--color-royal-amethyst);
|
|
|
|
/* 차트 시리즈 색상 (CPU/메모리/디스크 등 구분용) */
|
|
--color-chart-0: #5b8def; /* 파랑 — CPU */
|
|
--color-chart-1: #34c38f; /* 초록 — 메모리 */
|
|
--color-chart-2: #f1963b; /* 주황 — 디스크 */
|
|
--color-chart-3: #9b6dde; /* 보라 — 예비 */
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 3. 타이포그래피 (Typography)
|
|
* ------------------------------------------------------------------------ */
|
|
/* 폰트 패밀리 — 한글은 Noto Sans KR 우선 (resources/fonts) */
|
|
--font-display:
|
|
"Britti Sans", "Plus Jakarta Sans", "Noto Sans KR", ui-sans-serif, system-ui, -apple-system,
|
|
"Segoe UI", Roboto, sans-serif;
|
|
--font-body:
|
|
"Inter", "Noto Sans KR", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
--font-mono: "JetBrains Mono", "Consolas", ui-monospace, monospace;
|
|
|
|
/* 스케일 (px 고정 — design.md 명세) */
|
|
--text-caption: 12px;
|
|
--leading-caption: 1.3;
|
|
--text-body-sm: 14px;
|
|
--leading-body-sm: 1.4;
|
|
--text-body: 16px;
|
|
--leading-body: 1.5;
|
|
--text-subheading: 24px;
|
|
--leading-subheading: 1;
|
|
--text-heading-sm: 32px;
|
|
--leading-heading-sm: 1;
|
|
--text-heading: 40px;
|
|
--leading-heading: 1;
|
|
--text-heading-lg: 56px;
|
|
--leading-heading-lg: 1;
|
|
--text-display: 64px;
|
|
--leading-display: 1;
|
|
|
|
/* 굵기 */
|
|
--font-weight-regular: 400;
|
|
--font-weight-medium: 500;
|
|
--font-weight-bold: 700;
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 4. 간격 (Spacing) — 8px 기반, compact density
|
|
* ------------------------------------------------------------------------ */
|
|
--spacing-unit: 8px;
|
|
--spacing-4: 4px; /* pill/tag 세로 패딩용 하프 유닛 */
|
|
--spacing-8: 8px;
|
|
--spacing-16: 16px;
|
|
--spacing-24: 24px;
|
|
--spacing-32: 32px;
|
|
--spacing-40: 40px;
|
|
--spacing-48: 48px;
|
|
--spacing-56: 56px;
|
|
--spacing-64: 64px;
|
|
--spacing-96: 96px;
|
|
--spacing-104: 104px;
|
|
--spacing-216: 216px;
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 5. 보더 반경 (Border Radius) — 8px 시그니처
|
|
* ------------------------------------------------------------------------ */
|
|
--radius-sm: 2px;
|
|
--radius-lg: 8px; /* 카드/버튼/입력/아이콘 = 시그니처 */
|
|
--radius-xl: 12px;
|
|
--radius-2xl: 16px;
|
|
--radius-3xl: 24px; /* large 컨테이너 */
|
|
--radius-pills: 1440px; /* pill/tag/캡슐 네비 전용 */
|
|
|
|
--radius-cards: var(--radius-lg);
|
|
--radius-buttons: var(--radius-lg);
|
|
--radius-inputs: var(--radius-lg);
|
|
--radius-icons: var(--radius-lg);
|
|
--radius-large: var(--radius-3xl);
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 6. 그림자 (Shadows) — 블루틴트, 서브틀 (최대 32px blur / 6% opacity)
|
|
* ------------------------------------------------------------------------ */
|
|
--shadow-sm:
|
|
rgba(18, 55, 105, 0.08) 0px 2px 4px 0px, rgba(18, 55, 105, 0.04) 0px 1px 1px 0px,
|
|
rgba(18, 55, 105, 0.08) 0px 0px 0px 1px;
|
|
--shadow-lg:
|
|
rgba(14, 59, 101, 0.06) 0px 32px 24px -12px, rgba(14, 59, 101, 0.01) 0px 11px 4px 0px,
|
|
rgba(14, 59, 101, 0.02) 0px 6px 4px 0px, rgba(14, 59, 101, 0.03) 0px 3px 3px 0px,
|
|
rgba(14, 59, 101, 0.04) 0px 1px 1px 0px;
|
|
--shadow-feature:
|
|
rgba(114, 49, 255, 0.32) 0px -6px 20px 0px inset, rgba(47, 1, 151, 0.12) 0px 11px 12px 0px,
|
|
rgba(47, 1, 151, 0.12) 0px 3px 3px 0px, rgba(47, 1, 151, 0.12) 0px 1px 1px 0px,
|
|
rgba(47, 1, 151, 0.08) 0px 0px 0px 1px;
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 7. 레이아웃 (Layout)
|
|
* ------------------------------------------------------------------------ */
|
|
--page-max-width: 1200px;
|
|
--section-gap: 64px;
|
|
--card-padding: 24px;
|
|
--element-gap: 8px;
|
|
|
|
/* Scrollbar */
|
|
--color-scrollbar-track: transparent;
|
|
--color-scrollbar-thumb: color-mix(in srgb, var(--color-text) 12%, transparent);
|
|
--color-scrollbar-thumb-hover: color-mix(in srgb, var(--color-text) 20%, transparent);
|
|
--color-scrollbar-thumb-active: color-mix(in srgb, var(--color-text) 28%, transparent);
|
|
|
|
/* 워크플로우 3단 레이아웃 (frontend.md §2) */
|
|
--wf-header-height: 56px; /* 상단: 타이틀 + 진행 단계 */
|
|
--wf-left-panel-width: 320px; /* 좌측: 입력 폼 (너비 고정) */
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 8. 상호작용 (Motion & Z-index)
|
|
* ------------------------------------------------------------------------ */
|
|
--transition-fast: 120ms ease;
|
|
--transition-base: 200ms ease;
|
|
|
|
--z-header: 100;
|
|
--z-dropdown: 200;
|
|
--z-overlay: 900;
|
|
--z-modal: 1000;
|
|
--z-toast: 1100;
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* 9. 2D 지도 벡터 팔레트 (B04 배경지도 · B05 배수유역도 공용)
|
|
* 캔버스에 그리는 색이라 CSS로 직접 칠할 수 없다 — TS가 이 변수를 읽어 쓴다
|
|
* (`ui_template_palette.ts`). 여기가 유일한 정의처이며 화면별 복제 금지.
|
|
* 배경이 위성사진이라 라이트/다크 공통으로 같은 색을 쓴다.
|
|
* ------------------------------------------------------------------------ */
|
|
--map-route: #f97316; /* 계획선 (B04 지도·B05 배수유역도 공통) */
|
|
--map-cadastral: #f97316;
|
|
--map-sigungu: #7c3aed;
|
|
--map-eupmyeondong: #22c55e;
|
|
--map-contour: #fdba74;
|
|
--map-sheet-contour: #a5b4fc;
|
|
--map-sheet-stream: #2563eb;
|
|
--map-sheet-elev-point: #f9a8d4;
|
|
--map-sheet-cutfill: #f43f5e;
|
|
--map-sheet-wall: #0f766e;
|
|
--map-flow-arrow: #7c3aed;
|
|
--map-upstream: rgba(29, 78, 216, 0.95); /* 상류 세류망 강조선 */
|
|
--map-upstream-toggle: #1d4ed8; /* 토글 버튼 색띠 */
|
|
--map-satellite-toggle: #64748b; /* 배경사진은 선 색이 없어 중립 회색 */
|
|
--map-pipe-orphan: #e5e7eb; /* 유역이 없는 배관 마커 */
|
|
--map-pipe-marker: rgba(249, 115, 22, 0.95); /* B04 기본 관 마커 */
|
|
|
|
/* 배수유역 오버레이(B04 지도) */
|
|
--map-halo: rgba(255, 255, 255, 0.9); /* 선·글자 뒤에 까는 흰 테두리 */
|
|
--map-label-text: #1f2937; /* 지도 위 라벨 글자 */
|
|
--map-marker-text: #111827; /* 관 마커 번호 글자·선택된 마커 테두리 */
|
|
--map-marker-outline: #374151; /* 선택되지 않은 마커 테두리 */
|
|
--map-basin-outline: #92400e; /* 2차 유역 외곽선(분수령) */
|
|
--map-basin-ring: rgba(146, 64, 14, 0.95);
|
|
--map-boundary-handle: rgba(146, 64, 14, 0.95); /* 유역선 편집 핸들 */
|
|
--map-boundary-handle-moved: rgba(220, 38, 38, 0.95); /* 사용자가 옮긴 핸들 */
|
|
--map-primary-region: #059669; /* 1차 유역 */
|
|
--map-flow-region: #2563eb; /* 유역 방향 토글 */
|
|
--map-grid-line: rgba(255, 255, 255, 0.55); /* 해석 격자 셀 선 */
|
|
--map-flow-to-road-fill: rgba(220, 38, 38, 0.28);
|
|
--map-flow-to-road-line: rgba(153, 27, 27, 0.95);
|
|
--map-flow-away-fill: rgba(37, 99, 235, 0.22);
|
|
--map-flow-away-line: rgba(255, 255, 255, 0.95);
|
|
--map-flow-away-arrow: rgba(30, 64, 175, 0.95);
|
|
--map-flow-unknown-fill: rgba(120, 113, 108, 0.18); /* 표고가 없어 판정 못한 셀 */
|
|
|
|
/* 도로 유입 흐름 강도 색띠 — 적음(파랑) → 많음(빨강). 로그 스케일로 보간한다.
|
|
보간을 하려면 hex여야 한다(rgba/색이름 금지). */
|
|
--map-flow-ramp-0: #2563eb;
|
|
--map-flow-ramp-1: #06b6d4;
|
|
--map-flow-ramp-2: #22c55e;
|
|
--map-flow-ramp-3: #eab308;
|
|
--map-flow-ramp-4: #f97316;
|
|
--map-flow-ramp-5: #dc2626;
|
|
--map-inflow-outline: #dc2626; /* 선택한 지점으로 들어오는 셀들의 외곽선 */
|
|
|
|
/* 유역 채움 파스텔 8종 — 유역 번호 순으로 돌려쓴다(사용자 지시: 파스텔톤).
|
|
알파 0.45는 비선택 유역을 0.18로 낮출 때 문자열로 치환하므로 형식을 바꾸지 말 것. */
|
|
--map-basin-1: rgba(167, 216, 199, 0.45);
|
|
--map-basin-2: rgba(247, 208, 168, 0.45);
|
|
--map-basin-3: rgba(186, 199, 240, 0.45);
|
|
--map-basin-4: rgba(241, 183, 199, 0.45);
|
|
--map-basin-5: rgba(214, 226, 168, 0.45);
|
|
--map-basin-6: rgba(202, 186, 227, 0.45);
|
|
--map-basin-7: rgba(168, 214, 232, 0.45);
|
|
--map-basin-8: rgba(240, 219, 168, 0.45);
|
|
}
|
|
|
|
/* =============================================================================
|
|
* 다크 모드 (Dark) — 라이트 우선 브랜드이나 CAD 뷰어 야간 작업 대응
|
|
* design.md는 light 브랜드이므로, 다크는 중립 표면을 어둡게 반전하고
|
|
* 바이올렛 액센트는 명도를 올려 대비 확보.
|
|
* ========================================================================== */
|
|
:root[data-theme="dark"] {
|
|
--color-canvas: #16121f;
|
|
--color-paper: #1e1930;
|
|
--color-mist: #322a45;
|
|
--color-smoke: #4a4160;
|
|
--color-ash: #8b86a0;
|
|
--color-slate: #b3aec6;
|
|
--color-charcoal: #e4e0f0;
|
|
--color-carbon: #f0edf8;
|
|
--color-ink: #ffffff;
|
|
|
|
--color-deep-iris: #d8ccff;
|
|
--color-plum-velvet: #c4b8e6;
|
|
--color-royal-amethyst: #b99aff;
|
|
--color-mist-violet: #2a2140;
|
|
|
|
--color-bg: var(--color-canvas);
|
|
--color-surface: var(--color-paper);
|
|
--color-surface-raised: #251f38;
|
|
--color-border: var(--color-mist);
|
|
--color-text: var(--color-deep-iris);
|
|
--color-text-body: var(--color-charcoal);
|
|
--color-text-secondary: var(--color-slate);
|
|
--color-text-muted: var(--color-ash);
|
|
--color-primary: var(--color-royal-amethyst);
|
|
--color-primary-text: #16121f;
|
|
--color-accent: var(--color-lavender-wash);
|
|
--color-focus-ring: var(--color-lavender-wash);
|
|
|
|
--color-success: #3fbb6f;
|
|
--color-warning: #e0b64a;
|
|
--color-danger: #e8695a;
|
|
|
|
--shadow-sm: rgba(0, 0, 0, 0.4) 0px 2px 4px 0px, rgba(0, 0, 0, 0.2) 0px 0px 0px 1px;
|
|
--shadow-lg: rgba(0, 0, 0, 0.5) 0px 32px 24px -12px, rgba(0, 0, 0, 0.3) 0px 3px 3px 0px;
|
|
}
|
|
|
|
/* 시스템 설정 기반 자동 다크 (사용자가 명시적으로 data-theme를 안 준 경우) */
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme="light"]) {
|
|
--color-canvas: #16121f;
|
|
--color-paper: #1e1930;
|
|
--color-mist: #322a45;
|
|
--color-smoke: #4a4160;
|
|
--color-ash: #8b86a0;
|
|
--color-slate: #b3aec6;
|
|
--color-charcoal: #e4e0f0;
|
|
--color-carbon: #f0edf8;
|
|
--color-ink: #ffffff;
|
|
|
|
--color-deep-iris: #d8ccff;
|
|
--color-plum-velvet: #c4b8e6;
|
|
--color-royal-amethyst: #b99aff;
|
|
--color-mist-violet: #2a2140;
|
|
|
|
--color-bg: var(--color-canvas);
|
|
--color-surface: var(--color-paper);
|
|
--color-surface-raised: #251f38;
|
|
--color-border: var(--color-mist);
|
|
--color-text: var(--color-deep-iris);
|
|
--color-text-body: var(--color-charcoal);
|
|
--color-text-secondary: var(--color-slate);
|
|
--color-text-muted: var(--color-ash);
|
|
--color-primary: var(--color-royal-amethyst);
|
|
--color-primary-text: #16121f;
|
|
--color-accent: var(--color-lavender-wash);
|
|
--color-focus-ring: var(--color-lavender-wash);
|
|
}
|
|
}
|
|
|
|
/* =============================================================================
|
|
* 기본 리셋 및 문서 스타일
|
|
* ========================================================================== */
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* 일반 페이지의 가로·세로 스크롤바를 동일한 얇은 테마로 표시한다.
|
|
* B07 CAD iframe은 별도 문서이므로 이 전역 스타일의 영향을 받지 않는다. */
|
|
* {
|
|
scrollbar-color: var(--color-scrollbar-thumb) var(--color-scrollbar-track);
|
|
scrollbar-width: thin;
|
|
}
|
|
|
|
@supports selector(::-webkit-scrollbar) {
|
|
* {
|
|
scrollbar-color: auto;
|
|
scrollbar-width: auto;
|
|
}
|
|
|
|
*::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
*::-webkit-scrollbar-track {
|
|
background-color: transparent;
|
|
}
|
|
|
|
*::-webkit-scrollbar-thumb {
|
|
border: 2px solid transparent;
|
|
border-radius: var(--radius-pills);
|
|
background-color: var(--color-scrollbar-thumb);
|
|
background-clip: padding-box;
|
|
}
|
|
|
|
*::-webkit-scrollbar-thumb:hover {
|
|
background-color: var(--color-scrollbar-thumb-hover);
|
|
}
|
|
|
|
*::-webkit-scrollbar-thumb:active {
|
|
background-color: var(--color-scrollbar-thumb-active);
|
|
}
|
|
|
|
*::-webkit-scrollbar-button {
|
|
display: none;
|
|
width: 0;
|
|
height: 0;
|
|
}
|
|
|
|
*::-webkit-scrollbar-corner {
|
|
background-color: transparent;
|
|
}
|
|
}
|
|
|
|
@media (forced-colors: active) {
|
|
* {
|
|
scrollbar-color: auto;
|
|
}
|
|
}
|
|
|
|
/* ─── 공용 접기 컨테이너 (ui_template_collapsible.ts) ─────────────────────────
|
|
컨테이너에 `ui-collapsible`, 제목에 `ui-collapsible__title`을 주면 제목 행 전체가
|
|
클릭 영역이 되고, 접히면 제목을 뺀 직속 자식이 숨겨진다. 펼침 ▾ / 접힘 ▸ 캐럿 표시. */
|
|
.ui-collapsible__title {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--spacing-8, 8px);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
|
|
.ui-collapsible__title::after {
|
|
content: "▾";
|
|
flex: 0 0 auto;
|
|
margin-block: -0.4em;
|
|
color: var(--color-text-muted);
|
|
/* 레이아웃 허용 범위 내에서 최대한 크게(제목 글자의 약 1.7배). 음수 margin으로 행 높이는 유지. */
|
|
font-size: 1.7em;
|
|
line-height: 1;
|
|
}
|
|
|
|
.ui-collapsible.is-collapsed > .ui-collapsible__title::after {
|
|
content: "▸";
|
|
}
|
|
|
|
.ui-collapsible.is-collapsed > :not(.ui-collapsible__title) {
|
|
display: none;
|
|
}
|
|
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
body {
|
|
background-color: var(--color-bg);
|
|
color: var(--color-text-body);
|
|
font-family: var(--font-body);
|
|
font-size: var(--text-body);
|
|
line-height: var(--leading-body);
|
|
font-weight: var(--font-weight-regular);
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
margin: 0;
|
|
font-family: var(--font-display);
|
|
font-weight: var(--font-weight-medium);
|
|
color: var(--color-text);
|
|
line-height: 1;
|
|
}
|
|
|
|
h1 {
|
|
font-size: var(--text-heading);
|
|
}
|
|
h2 {
|
|
font-size: var(--text-heading-sm);
|
|
}
|
|
h3 {
|
|
font-size: var(--text-subheading);
|
|
}
|
|
|
|
a {
|
|
color: var(--color-accent);
|
|
text-decoration: none;
|
|
transition: color var(--transition-fast);
|
|
}
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
:focus-visible {
|
|
outline: 2px solid var(--color-focus-ring);
|
|
outline-offset: 2px;
|
|
}
|