/* === pp-00-fonts.css === */
/* JetBrains Mono — 로컬 호스팅 (woff2 5 weights) — 코드/모노스페이스 표시용 */
@import url('/static/font/pretendard/static/pretendard.css');

/* Noto Sans KR — 로컬 호스팅 (variable woff2, weight 100-900 단일 파일) */
@font-face { font-family: 'Noto Sans KR'; src: url(/static/fonts/noto-sans-kr/noto-sans-kr.woff2) format("woff2-variations"); font-display: swap; font-weight: 100 900; font-style: normal; }

/* SUIT — 로컬 호스팅 (variable woff2, weight 100-900 단일 파일) — 고딕3 (SIL OFL, 임베딩 허용) */
@font-face { font-family: 'SUIT'; src: url(/static/fonts/suit/suit-variable.woff2) format("woff2-variations"); font-display: swap; font-weight: 100 900; font-style: normal; }

@font-face { font-family: jetbrainsMono; src: url(/static/fonts/jetbrains-mono/jetbrains-mono-300.woff2) format("woff2"); font-display: swap; font-weight: 300; font-style: normal; }
@font-face { font-family: jetbrainsMono; src: url(/static/fonts/jetbrains-mono/jetbrains-mono-400.woff2) format("woff2"); font-display: swap; font-weight: 400; font-style: normal; }
@font-face { font-family: jetbrainsMono; src: url(/static/fonts/jetbrains-mono/jetbrains-mono-500.woff2) format("woff2"); font-display: swap; font-weight: 500; font-style: normal; }
@font-face { font-family: jetbrainsMono; src: url(/static/fonts/jetbrains-mono/jetbrains-mono-600.woff2) format("woff2"); font-display: swap; font-weight: 600; font-style: normal; }
@font-face { font-family: jetbrainsMono; src: url(/static/fonts/jetbrains-mono/jetbrains-mono-700.woff2) format("woff2"); font-display: swap; font-weight: 700; font-style: normal; }
@font-face { font-family: jetbrainsMono Fallback; src: local("Arial"); ascent-override: 77.57%; descent-override: 22.82%; line-gap-override: 0%; size-adjust: 131.49%; }

:root,
html.pp-font-noto {
    --pp-ui-font-family: "Noto Sans KR", -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", sans-serif;
    --pp-ui-font-feature-settings: normal;
}
html.pp-font-jetbrains {
    --pp-ui-font-family: jetbrainsMono, jetbrainsMono Fallback, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    --pp-ui-font-feature-settings: 'liga' off, 'calt' off;
}
html.pp-font-suit {
    --pp-ui-font-family: 'SUIT', -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo", sans-serif;
    --pp-ui-font-feature-settings: normal;
}
html.pp-font-pretendard {
    --pp-ui-font-family: Pretendard, -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo", sans-serif;
    --pp-ui-font-feature-settings: normal;
}

/* ============================================================
 * Base Typography — Signal 테마 토큰 기준
 *  - body / 헤딩 / 단락 / 링크 / 보조 텍스트
 *  - 모든 색상은 :root 토큰 (var(--xxx)) 사용 → 테마 교체 가능
 *  - cascade base (pp-fonts 가 가장 먼저 로드) → 페이지/컴포넌트 룰이 override 가능
 * ============================================================ */
body {
    color: var(--foreground);
    background: var(--background);
    font-family: var(--pp-ui-font-family);
    font-feature-settings: var(--pp-ui-font-feature-settings);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}
h1, h2, h3, h4, h5, h6 {
    color: var(--foreground);
    font-weight: 600;
    line-height: 1.3;
}
p {
    color: var(--foreground);
    line-height: 1.55;
}
small {
    color: var(--muted-foreground);
    font-size: 0.875em;
}
strong, b {
    color: var(--foreground);
    font-weight: 600;
}
code:not([class]), kbd, samp {
    color: var(--accent-foreground);
    background: var(--accent);
    padding: 1px 4px;
    border-radius: 4px;
    font-family: jetbrainsMono, jetbrainsMono Fallback, ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
    font-size: 0.92em;
}

/* ============================================================
 * Link — Signal primary 톤
 *  - 기본: primary 컬러 (navy)
 *  - hover/focus: primary-strong (있으면) 또는 동일 톤 약간 진하게
 *  - visited: muted-foreground (방문 표시 약하게)
 *  - underline 정책: 전역 제거 (사용자 정책 — pp-04a/pp-09i 와 일관)
 * ============================================================ */
a {
    /* primary 톤 살짝 연하게 (가독성 유지 + 진한 네이비 톤다운) */
    color: color-mix(in oklch, var(--primary) 75%, white 25%);
    text-decoration: none;
    transition: color 0.15s ease;
}
a:link {
    color: color-mix(in oklch, var(--primary) 75%, white 25%);
}
a:visited {
    color: var(--muted-foreground);
}
a:hover,
a:focus {
    color: var(--pp-primary-strong, var(--primary));
    text-decoration: none;
}
a:active {
    color: var(--primary);
}

/* === pp-01-tokens.css === */
/* ====================================================================== */
/* PlantPulse — Signal Dashboard 디자인 시스템 클론                          */
/* 출처: https://signal-devops.dashboardpack.com/kubernetes                 */
/* 토큰/타이포/컴포넌트를 Signal 과 동일한 스펙으로 정렬한다.                  */
/* ====================================================================== */

/* 폰트: 에어갭/CSP 대응 — Google Fonts CDN @import 제거.
 * JetBrains Mono 는 pp-fonts.css 의 로컬 @font-face(/static/fonts/jetbrains-mono/)로 호스팅. */

:root {
    --radius: 0.5rem;

    /* 라이트 모드 base — Signal/shadcn 톤 정렬 (가독성 강화) */
    --background: oklch(97.5% 0.005 260);
    --foreground: oklch(14% 0.008 260);                  /* 본문 — 진한 navy-dark, 강한 contrast */
    --card: oklch(99.5% 0.002 260);
    --card-foreground: oklch(14% 0.008 260);
    --popover: oklch(99.5% 0.002 260);
    --popover-foreground: oklch(14% 0.008 260);
    --primary: var(--pp-primary-strong, #003d8f);
    --primary-foreground: var(--pp-white, #ffffff);
    --secondary: oklch(95.5% 0.008 260);
    --secondary-foreground: oklch(20% 0.012 260);
    --muted: oklch(95.5% 0.008 260);
    --muted-foreground: oklch(48% 0.01 260);             /* 보조 — 명확한 회색 톤 (라벨/메타 정보용) */
    --muted-strong-foreground: oklch(44.6% 0.043 257.3); /* 진한 중립(slate-600 상당) — disconnected 뱃지·CM 브래킷 등 흰텍스트 대비(AA)용 */
    --subtle-foreground: oklch(60% 0.008 260);           /* 약한 보조 — 시간 / 경량 hint 용 (신규) */
    --accent: oklch(95.5% 0.008 260);
    --accent-foreground: oklch(20.5% 0.02 260);
    --destructive: oklch(57.7% 0.245 27);
    --destructive-foreground: oklch(98.5% 0 0);
    --success: oklch(62% 0.2 145);
    --success-foreground: oklch(98.5% 0 0);
    --warning: oklch(75% 0.18 75);
    --warning-foreground: oklch(20.5% 0.02 260);
    --border: oklch(91% 0.008 260);
    --input: oklch(91% 0.008 260);   /* 폼 인풋 보더 — 연회색. (WCAG 1.4.11 위해 65%로 진하게 했으나 시각상 너무 검게 보여 원복 — 사용자 지시 2026-06-28) */
    --ring: var(--pp-primary-strong, #003d8f);

    --chart-1: var(--pp-primary-strong, #003d8f);
    --chart-2: oklch(60% 0.15 200);
    --chart-3: oklch(65% 0.16 280);
    --chart-4: oklch(70% 0.16 60);
    --chart-5: oklch(58% 0.18 340);

    /* 다크 사이드바 */
    /* shadcn-inspired refined dark palette — zinc 톤에 미세한 navy tint */
    --sidebar: oklch(14% 0.012 265);                  /* 깊은 zinc + 살짝 navy */
    --sidebar-surface: oklch(16% 0.012 265);          /* 카드/액티브 표면 */
    --sidebar-foreground: oklch(92% 0.005 260);
    --sidebar-accent: oklch(20% 0.015 265);           /* hover 표면 */
    --sidebar-accent-foreground: oklch(96% 0.003 260);
    --sidebar-border: oklch(22% 0.012 265);
    --sidebar-ring: var(--pp-primary-strong, #003d8f);
    --sidebar-primary: #60a5fa;                       /* 차분한 sky blue (active text) */
    --sidebar-primary-foreground: var(--pp-white, #ffffff);

    /* opacity helpers (browsers without color-mix fallback) */
    --sidebar-fg-30: rgba(231, 234, 232, 0.30);
    --sidebar-fg-50: rgba(231, 234, 232, 0.50);
    --sidebar-fg-70: rgba(231, 234, 232, 0.70);
    --sidebar-accent-50: rgba(28, 36, 33, 0.50);

    /* 사이드바 폭 */
    --pp-sidebar-w: 200px;
    --pp-topbar-h: 64px;

    /* 사이드바 토글 (접힘 = 아이콘만) — 원래 pp-02-layout-shell.css 정의, Phase 1 통합 */
    --pp-sidebar-w-collapsed: 64px;

    /* 토큰 재정의 — pp-bg-muted/border 가 hue 165(teal) 였던 걸 zinc 중립으로 */
    /* (원래 pp-04a-tables.css 정의, Phase 1 통합) */
    --pp-bg-muted:        oklch(0.97 0.005 286);    /* zinc-50 (중립) */
    --pp-bg:              var(--pp-white, #ffffff);
    --pp-border-strong:   oklch(0.85 0.008 286);    /* zinc-300 */
    --pp-text:            oklch(0.21 0.006 286);
    --pp-text-soft:       oklch(0.30 0.006 286);
    --pp-text-muted:      oklch(0.55 0.016 286);
    --pp-text-faint:      oklch(0.70 0.012 286);

    /* 이전 teal 기반 토큰 → navy primary 로 재매핑 (전역) */
    /* (원래 pp-04a-tables.css 정의, Phase 1 통합) */
    --pp-primary-dark:   oklch(28% 0.12 260);
    --pp-primary-light:  oklch(75% 0.08 260);
    --pp-primary-pale:   oklch(96% 0.01 260);
    --pp-primary-soft:   oklch(82% 0.05 260);
    --pp-second:         oklch(0.45 0.02 260);

    /* Phase 5a: frequent 색상 변수화 (사용 빈도 top 5 hex) */
    --pp-white:          #ffffff;
    --pp-muted-fg:       #6b7280;
    --pp-primary-strong: #003d8f;
    --pp-primary:        #1d4ed8;
    --pp-info:           #2563eb;   /* info 상태 전용 blue (브랜드 primary 와 분리 — 뱃지 톤) */
    --pp-border:         #e5e7eb;

    /* 디자인 토큰 — 그라데이션 (현대 다중 stop, navy → cyan/teal/purple) */
    /* (원래 pp-05a-badges.css 정의, Phase 1 통합) */
    --gradient-primary:        linear-gradient(135deg, oklch(0.30 0.12 260) 0%, var(--primary, #003d8f) 50%, oklch(0.45 0.18 230) 100%);
    --gradient-primary-soft:   linear-gradient(135deg, oklch(0.96 0.02 260) 0%, oklch(0.93 0.05 230) 100%);
    --gradient-success:        linear-gradient(135deg, var(--pp-tone-success-bg) 0%, var(--pp-tone-success-bg) 50%, #4ade80 100%);
    --gradient-warning:        linear-gradient(135deg, #b45309 0%, #f59e0b 50%, #fbbf24 100%);
    --gradient-danger:         linear-gradient(135deg, #991b1b 0%, var(--pp-tone-danger-bg) 50%, #ef4444 100%);
    --gradient-dark:           linear-gradient(135deg, oklch(0.13 0.006 286) 0%, oklch(0.21 0.006 286) 100%);
    --gradient-mesh:           radial-gradient(circle at 20% 30%, rgba(0,61,143,0.08) 0%, transparent 40%),
                               radial-gradient(circle at 80% 70%, rgba(86, 108, 180, 0.06) 0%, transparent 40%);
    --gradient-aurora:         linear-gradient(135deg, oklch(0.65 0.20 260) 0%, oklch(0.55 0.22 280) 50%, oklch(0.65 0.20 200) 100%);
}

/* === pp-02-bs5-overrides.css === */

/* ====================================================================== */
/* 타이포그래피                                                            */
/* ====================================================================== */
body:not(.pp-login-page),
body:not(.pp-login-page) .pp-shell,
body:not(.pp-login-page) #wrapper,
body:not(.pp-login-page) #page-wrapper,
body:not(.pp-login-page) #navigation,
body:not(.pp-login-page) .navbar,
body:not(.pp-login-page) .card,
body:not(.pp-login-page) .modal,
body:not(.pp-login-page) .btn,
body:not(.pp-login-page) table,
body:not(.pp-login-page) input,
body:not(.pp-login-page) select,
body:not(.pp-login-page) textarea,
body:not(.pp-login-page) .form-control,
body:not(.pp-login-page) .nav,
body:not(.pp-login-page) .dropdown-menu {
    font-family: var(--pp-ui-font-family) !important;
    font-feature-settings: var(--pp-ui-font-feature-settings) !important;
}
body:not(.pp-login-page) code:not([class]),
body:not(.pp-login-page) kbd,
body:not(.pp-login-page) samp,
body:not(.pp-login-page) pre,
body:not(.pp-login-page) .CodeMirror,
body:not(.pp-login-page) .CodeMirror * {
    font-family: jetbrainsMono, jetbrainsMono Fallback, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace !important;
    font-feature-settings: 'liga' off, 'calt' off !important;
}

/* body 의 background/color/font 는 pp-fonts.css 의 base typography 가 담당 (강제 오버라이드 제거) */
body {
    font-size: 13px;
    line-height: 1.55;
    letter-spacing: 0;
}

body .bootstrap-dialog.pp-settings-dialog .pp-settings-font-control {
    min-width: 224px;
}
body .bootstrap-dialog.pp-settings-dialog .pp-font-choice {
    display: flex;
    gap: 0;
    width: 100%;
}
body .bootstrap-dialog.pp-settings-dialog .pp-font-choice .btn {
    flex: 1 1 0;
    min-width: 0;
    height: 32px;
    line-height: 20px;
}
body .bootstrap-dialog.pp-settings-dialog .pp-font-choice .btn + .btn {
    margin-left: -1px !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-font-choice .btn.active,
body .bootstrap-dialog.pp-settings-dialog .pp-font-choice .btn:active {
    background: var(--primary) !important;
    border-color: var(--primary) !important;
    color: var(--primary-foreground) !important;
}
/* 페이지 본문 색은 pp-fonts.css 의 base typography 가 담당 (이 룰 제거) */
/* 회색 보조 — fieldset legend, hint, "[조회 건수]" 등 */
#page-wrapper .text-muted,
#page-wrapper small,
#page-wrapper .form-text,
#page-wrapper legend small {
    color: var(--muted-foreground) !important;
}
/* 인라인 hex 색상 자동 매핑 — 톤 통일 */
/* 짙은 회색 #555 #333 #222 → 본문 (foreground) */
#page-wrapper [style*="color: #555"],
#page-wrapper [style*="color:#555"],
#page-wrapper [style*="color: #444"],
#page-wrapper [style*="color:#444"],
#page-wrapper [style*="color: #333"],
#page-wrapper [style*="color:#333"],
#page-wrapper [style*="color: #222"],
#page-wrapper [style*="color:#222"],
#page-wrapper [style*="color: #111"],
#page-wrapper [style*="color:#111"],
#page-wrapper [style*="color: #000"],
#page-wrapper [style*="color:#000"],
#page-wrapper [style*="color: black"],
#page-wrapper [style*="color:black"],
#page-wrapper [style*="color: #1a4a7a"],
#page-wrapper [style*="color:#1a4a7a"] {
    color: var(--foreground) !important;
}
/* 중간 회색 #666 #777 #888 → muted */
#page-wrapper [style*="color: #666"],
#page-wrapper [style*="color:#666"],
#page-wrapper [style*="color: #777"],
#page-wrapper [style*="color:#777"],
#page-wrapper [style*="color: #888"],
#page-wrapper [style*="color:#888"],
#page-wrapper [style*="color: #628197"],
#page-wrapper [style*="color:#628197"] {
    color: var(--muted-foreground) !important;
}
/* 옅은 회색 #999 #aaa #bbb #ccc → subtle (한 단계 더 옅음) */
#page-wrapper [style*="color: #999"],
#page-wrapper [style*="color:#999"],
#page-wrapper [style*="color: #aaa"],
#page-wrapper [style*="color:#aaa"],
#page-wrapper [style*="color: #bbb"],
#page-wrapper [style*="color:#bbb"],
#page-wrapper [style*="color: #ccc"],
#page-wrapper [style*="color:#ccc"] {
    color: var(--subtle-foreground) !important;
}
/* 헤딩 톤 — h1-h6 (medium gray, 본문 톤보다 약간 옅게) */
#page-wrapper h1, #page-wrapper h2, #page-wrapper h3,
#page-wrapper h4, #page-wrapper h5, #page-wrapper h6 {
    color: oklch(0.36 0 0) !important;
}
/* 입력 폼 텍스트 — 본문 톤 */
#page-wrapper input.form-control, #page-wrapper select.form-control,
#page-wrapper textarea.form-control {
    color: var(--foreground) !important;
}
/* placeholder — subtle */
#page-wrapper .form-control::placeholder {
    color: var(--subtle-foreground) !important;
    opacity: 1 !important;
}
/* fieldset legend — 보조 강조 톤 */
#page-wrapper fieldset legend {
    color: var(--secondary-foreground) !important;
    font-weight: 600 !important;
}
/* link 톤 — pp-fonts.css 의 base typography 가 담당 (이 룰 제거) */

/* ====================================================================== */
/* 텍스트 색상 강제 오버라이드 — 다른 CSS 파일의 하드코딩 색 무력화        */
/* (pp-override-layout.css, pp-calendar.css, pp-daterange-picker.css 등)   */
/* ====================================================================== */
/* panel-body 본문 색은 pp-fonts.css 의 base typography 가 담당 (이 광범위 강제 룰 제거) */
/* 외부 CSS 의 회색 텍스트 (#888, #aaa, #ccc, #999 등) — 모두 muted 로 매핑 */
body .text-muted, body .text-info, body .text-secondary {
    color: var(--muted-foreground) !important;
}
/* state-badge 색상은 pp-12-status-tones.css 가 정본 (tone bg + on-solid). 여기 중복 색상 룰 제거 */
/* b/strong 강제 색/굵기 룰 제거 — base typography 가 담당 */
/* 라벨 톤 — uppercase muted */
body #page-wrapper label.form-label,
body #page-wrapper label.form-label {
    color: oklch(0.5 0.01 0) !important;
    font-size: 12px !important;
    border-right: 0 !important;
}
/* 데이터 테이블 td/th — 본문 톤 */
body #page-wrapper table.table td,
body #page-wrapper table.table tbody tr td {
    color: var(--foreground) !important;
}
/* table thead 색은 공통 패널 테이블 룰 (.card table.table thead, body .card .table thead) 이 담당 */

/* ====================================================================== */
/* 외부 CSS 클래스의 하드코딩 텍스트 색상 오버라이드 (pp-override-layout 등)*/
/* ====================================================================== */
/* select2 위젯 텍스트 — 본문 톤 */
body .select2-container--bootstrap .select2-selection__rendered,
body .select2-container--bootstrap .select2-selection__choice {
    color: var(--foreground) !important;
}
body .select2-container--bootstrap .select2-selection__placeholder,
body .select2-container--bootstrap .select2-selection__clear {
    color: var(--subtle-foreground) !important;
}
body .select2-container--bootstrap .select2-selection__choice__remove {
    color: var(--muted-foreground) !important;
}
/* dropdown menu 텍스트 — 본문 톤 */
body .dropdown-menu > li > a {
    color: var(--foreground) !important;
}
body .dropdown-menu > li > a:hover,
body .dropdown-menu > li > a:focus {
    color: var(--foreground) !important;
    background: var(--muted) !important;
}
body .dropdown-menu .divider {
    background-color: var(--border) !important;
}
/* 알람 / 알림 패널 ".cap-empty" "데이터 없음" */
body .cap-empty,
body .nodata,
body .empty-state,
body #stream-content > li {
    color: var(--muted-foreground) !important;
}
/* 콘솔 hint, code 톤 — signal 토큰 */
body code:not([class]) {
    color: var(--primary) !important;
    background: var(--muted) !important;
    padding: 2px 6px !important;
    border-radius: 4px !important;
    font-size: 10px !important;
    font-family: jetbrainsMono, jetbrainsMono Fallback, ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
}
/* 모달 헤더 / 푸터 톤 */
body .modal-header, body .modal-title {
    color: var(--foreground) !important;
}
body .modal-body {
    color: var(--foreground) !important;
}
body .modal-body label {
    color: var(--secondary-foreground) !important;
}
/* checkbox / radio 텍스트 */
body input[type="checkbox"] + label,
body input[type="radio"] + label {
    color: var(--foreground) !important;
}
/* 탭 / 네비게이션 톤 (본문 영역) */
body #page-wrapper .nav-tabs > li > a {
    color: var(--muted-foreground) !important;
}
body #page-wrapper .nav-tabs > li.active > a,
body #page-wrapper .nav-tabs > li > a.active {
    color: var(--foreground) !important;
}

/* ====================================================================== */
/* 인라인 패딩/마진 정리 — 패널 일관성 강제                                */
/* JSP 의 style="margin-bottom:0" / "padding:0" 등을 토큰으로 강제 통일    */
/* ====================================================================== */
/* 패널 자체 — margin-bottom 16px 강제 (인라인 0 무력화) */
/* ====================================================================== */
/* 전역 input-group-addon — 중립 zinc 톤 (이전 teal hue 제거)             */
/* ====================================================================== */
body .input-group-text {
    background: oklch(0.97 0.005 286) !important;          /* zinc-50 */
    border-color: var(--border) !important;                /* zinc-200 */
    color: oklch(0.45 0.01 286) !important;                /* zinc-500 */
    font-weight: 500 !important;
}
body .input-group-text i {
    color: oklch(0.45 0.01 286) !important;
}

/* ====================================================================== */
/* 전역 input-group — addon 과 인접 input/select 자동 연결 (코너 0)       */
/* ====================================================================== */
body .input-group {
    display: flex;           /* BS5: addon + control 가로 정렬 (BS3 display:table 제거) */
    flex-wrap: wrap;
    align-items: stretch;
}
/* 인접 모서리 각짐 — BS5 input-group 의 모든 자식 일괄(.form-control/.form-select/.btn/.input-group-text).
   우리 .form-control/.form-select 의 border-radius !important 를 보정. BS3 .input-group-btn 잔재 제거.
   첫 자식 아니면 왼쪽 모서리 0, 마지막 자식 아니면 오른쪽 모서리 0 → addon/버튼과 선이 이어진다.
   (BS5 처럼 검증 피드백/드롭다운 메뉴는 제외) */
body .input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.invalid-tooltip):not(.valid-feedback):not(.invalid-feedback) {
    border-top-left-radius: 0 !important;
    border-bottom-left-radius: 0 !important;
}
body .input-group > :not(:last-child):not(.dropdown-toggle):not(.valid-tooltip):not(.invalid-tooltip):not(.valid-feedback):not(.invalid-feedback) {
    border-top-right-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
}
/* 중간에 addon 이 끼는 경우 (form-control + addon + form-control) */
body .input-group > .input-group-text:not(:first-child):not(:last-child) {
    border-radius: 0 !important;
}

/* ====================================================================== */
/* 전역 btn-group — 외곽만 라운드, 내부 보더 공유 (갭 방지)              */
/* ====================================================================== */
body .btn-group { display: inline-flex; align-items: center; }
body .btn-group > .btn {
    border-radius: 0 !important;
    margin-left: -1px !important;
    box-shadow: none !important;
}
body .btn-group > .btn:first-child {
    border-top-left-radius: 6px !important;
    border-bottom-left-radius: 6px !important;
    margin-left: 0 !important;
}
body .btn-group > .btn:last-child {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
}
/* 드롭다운 토글 버튼은 뒤따르는 ul.dropdown-menu 때문에 :last-child 가 안 먹어 우측 라운드가 빠진다 →
   버튼 중 마지막(:last-of-type)인 토글에 우측 라운드 부여 (split-button 도 caret 가 last-of-type 라 정상). */
body .btn-group > .btn.dropdown-toggle:last-of-type {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
}
/* 드롭다운 구분선 — BS5 기본 rgba(0,0,0,.175) 가 너무 진해 라이트 보더 토큰으로 연하게 */
body .dropdown-menu {
    --bs-dropdown-divider-bg: var(--pp-border);
}
body .btn-group > .btn:hover,
body .btn-group > .btn:focus,
body .btn-group > .btn.active {
    z-index: 2;
    position: relative;
}

body #page-wrapper .card,
body #page-wrapper .card.card,
body #page-wrapper .card.card-primary,
body #page-wrapper .card.card-second,
body #page-wrapper .card.card-info,
body #page-wrapper .card.card-warning,
body #page-wrapper .card.card-danger,
body #page-wrapper .card.card-success,
body #page-wrapper .card.card-dark,
body #page-wrapper .card.card-impo {
    margin-bottom: 16px !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    margin-top: 0 !important;
    border-radius: 12px !important;
    overflow: hidden;                      /* 컬러 헤더 그라데이션을 라운드 안으로 클립 */
}
/* 마지막 패널 — 추가 bottom margin 없음 */
body #page-wrapper > .row:last-child .card:last-child,
body #page-wrapper .row:last-of-type .card:last-of-type {
    /* 마지막 row 의 row-padding-bottom 24px 가 처리 */
}
/* row 자체의 인라인 margin-bottom 무력화 */
body #page-wrapper > .row,
body #page-wrapper > .row[style*="margin-bottom"] {
    margin-bottom: 0 !important;
}
/* alert 박스 — 표준 spacing */
body #page-wrapper .alert {
    margin-bottom: 16px !important;
    margin-top: 0 !important;
}
/* col 안 form 들의 안쪽 spacing 표준화 — 인라인 margin 무력화 */
body #page-wrapper .form-inline,
body #page-wrapper form.form-inline,
body #page-wrapper .pp-form-row,
body #page-wrapper form.pp-form-row {
    margin-top: 0 !important;
}
/* 안내 박스 (alert, hint) 의 자식 들 — 인라인 padding-bottom 0 무력화 */
body #page-wrapper .alert h4 {
    margin-top: 0 !important;
    margin-bottom: 8px !important;
}
body #page-wrapper .alert > div,
body #page-wrapper .alert > ul {
    margin-bottom: 0 !important;
}
/* 인라인 margin-top 음수 (-10px, -2px 등) — 패널 정렬 깨짐 방지 */
body #page-wrapper .card-header > div[style*="margin-top: -2px"],
body #page-wrapper .card-header > div[style*="margin-top:-2px"] {
    margin-top: 0 !important;
}
/* legend / fieldset spacing 표준 — fieldset 좌우 패딩 + legend 는 100% 블록 정상화 */
body #page-wrapper fieldset {
    border: 0 !important;
    display: block;
    margin: 0 0 24px 0 !important;
    padding: 0 16px !important;
}
body #page-wrapper fieldset > legend {
    display: block;
    width: calc(100% + 32px);
    margin-left: -16px !important;
    margin-right: -16px !important;
    float: none;
    clear: both;
    position: static;
}
/* legend 뒤 콘텐츠는 새 줄에서 시작 */
body #page-wrapper fieldset > legend + * {
    clear: both;
    margin-top: 0 !important;
}
body #page-wrapper fieldset legend {
    border: 0 !important;
    border-bottom: 1px solid var(--border) !important;
    padding: 0 0 8px 0 !important;
    margin-bottom: 12px !important;
    font-size: 14px !important;
    font-weight: 600 !important;
    color: var(--secondary-foreground) !important;
}
/* form-inline 내부 form-inline (중첩) 마진 정리 */
body #page-wrapper .form-inline .form-inline,
body #page-wrapper .pp-form-row .pp-form-row {
    margin: 0 !important;
}
/* 인라인 padding-top 0px / margin-bottom 0px / 0 패턴 — panel-body 인 경우 무력화 */
body #page-wrapper .card-body[style*="padding-bottom: 0"],
body #page-wrapper .card-body[style*="padding-bottom:0"] {
    padding-bottom: 22px !important;
}
body #page-wrapper .card-body[style*="margin-bottom: 0"],
body #page-wrapper .card-body[style*="margin-bottom:0"] {
    margin-bottom: 0 !important;  /* panel-body 자체는 margin 없음 */
}

/* ====================================================================== */
/* 다이얼로그 / 모달 — Signal 톤 정리 (rounded-xl + shadow-lg)             */
/* ====================================================================== */
.modal {
    z-index: 9999;
}
.modal-backdrop {
    background: oklch(85% 0.02 260) !important;       /* 옅은 회색 — 어둡게 깔지 않음 */
    opacity: 0.55 !important;
    backdrop-filter: blur(2px);
}
.modal-dialog {
    margin: 60px auto !important;
}
.modal-content {
    background: var(--card) !important;
    border: 1px solid var(--border) !important;
    border-radius: 14px !important;                         /* rounded-2xl */
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25),
                0 10px 20px -5px rgba(0, 0, 0, 0.04) !important;
    overflow: hidden;
}
.modal-header {
    background: transparent !important;
    border-bottom: 1px solid var(--border) !important;
    padding: 18px 24px !important;
    border-radius: 14px 14px 0 0 !important;
    display: flex !important;
    align-items: center !important;
    gap: 12px;
}
.modal-header .modal-title,
.modal-header h4.modal-title {
    margin: 0 !important;
    padding: 0 !important;
    font-size: 18px !important;
    font-weight: 700 !important;
    color: var(--foreground) !important;
    line-height: 1.4 !important;
    flex: 1;
}
.modal-header .btn-close,
.modal-header button.btn-close {
    margin: 0 0 0 auto !important;        /* flex 우측 정렬 — DOM 순서 무시 */
    order: 99 !important;
    padding: 4px 10px !important;
    font-size: 20px !important;
    font-weight: 400 !important;
    color: var(--muted-foreground) !important;
    opacity: 1 !important;
    background: transparent !important;
    border: 0 !important;
    border-radius: 6px !important;
    line-height: 1 !important;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
    flex-shrink: 0;
}
.modal-header .btn-close:hover {
    color: var(--foreground) !important;
    background: var(--muted) !important;
}
.modal-body {
    padding: 22px 24px !important;
    background: var(--card) !important;
    color: var(--foreground) !important;
    max-height: calc(100vh - 220px);
    overflow-y: auto;
}
.modal-body label {
    color: var(--secondary-foreground) !important;
    font-weight: 500 !important;
    margin-bottom: 6px !important;
}
.modal-body fieldset {
    margin-bottom: 18px !important;
}
/* .form-group 간격은 pp-48 정본(SSOT)에서 일괄 12px — 여기선 form-inline 만. */
.modal-body .form-inline,
.modal-body .pp-form-row {
    margin-bottom: 12px !important;
}
.modal-body input.form-control,
.modal-body select.form-control,
.modal-body textarea.form-control {
    background: var(--background) !important;
    border: 1px solid var(--border) !important;
    border-radius: 6px !important;
    padding: 8px 12px !important;
    font-size: 13px !important;
}
.modal-body input.form-control:focus,
.modal-body select.form-control:focus,
.modal-body textarea.form-control:focus {
    outline: 0 !important;
    border-color: var(--primary) !important;
    box-shadow: 0 0 0 3px rgba(0, 61, 143, 0.12) !important;
}
.modal-footer {
    background: transparent !important;
    border-top: 1px solid var(--border) !important;
    padding: 14px 24px !important;
    border-radius: 0 0 14px 14px !important;
    display: flex !important;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
.modal-footer > .btn,
.modal-footer button.btn {
    margin: 0 !important;
    padding: 8px 16px !important;
    height: 36px !important;
    min-width: 90px !important;            /* 다이얼로그 내 버튼 최소 너비 — 일관성 */
    border-radius: 6px !important;
    font-size: 13px !important;
    font-weight: 500 !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 6px;
}
.modal-footer > .btn > i,
.modal-footer button.btn > i {
    font-size: 14px !important;
}
/* BootstrapDialog 호환 — kind 별 톤 */
.bootstrap-dialog .modal-header {
    background: transparent !important;
    color: var(--foreground) !important;
}
.bootstrap-dialog.type-primary .modal-header,
.bootstrap-dialog.type-info .modal-header,
.bootstrap-dialog.type-warning .modal-header,
.bootstrap-dialog.type-danger .modal-header,
.bootstrap-dialog.type-success .modal-header {
    background: transparent !important;
    color: var(--foreground) !important;
}
.bootstrap-dialog .bootstrap-dialog-title,
.bootstrap-dialog .modal-header .bootstrap-dialog-title {
    color: var(--foreground) !important;
    font-size: 16px !important;
    font-weight: 600 !important;
    flex: 1;
}
.bootstrap-dialog .bootstrap-dialog-close-button {
    margin-left: auto !important;
}
.bootstrap-dialog .bootstrap-dialog-close-button .btn-close {
    color: var(--muted-foreground) !important;
    opacity: 1 !important;
    background: transparent !important;
    border: 0 !important;
    font-size: 22px !important;
    padding: 4px 8px !important;
    border-radius: 6px !important;
    line-height: 1 !important;
}
.bootstrap-dialog .bootstrap-dialog-close-button .btn-close:hover {
    color: var(--foreground) !important;
    background: var(--muted) !important;
}
/* BootstrapDialog footer 버튼 — 표준 크기 */
.bootstrap-dialog .bootstrap-dialog-footer-buttons,
.bootstrap-dialog .modal-footer {
    display: flex !important;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
.bootstrap-dialog .bootstrap-dialog-footer-buttons .btn,
.bootstrap-dialog .modal-footer .btn {
    height: auto !important;
    padding: 8px 16px !important;
    font-size: 13px !important;
    border-radius: 6px !important;
    margin: 0 !important;
}
/* 취소 / 닫기 버튼 (icon only) — 평평한 default */
.bootstrap-dialog .bootstrap-dialog-footer-buttons button[data-button-id="cancel"],
.bootstrap-dialog .bootstrap-dialog-footer-buttons button.btn-secondary {
    background: var(--background) !important;
    color: var(--foreground) !important;
    border: 1px solid var(--border) !important;
}
.bootstrap-dialog .bootstrap-dialog-footer-buttons button[data-button-id="cancel"]:hover {
    background: var(--secondary) !important;
}
/* 모달 안 패널 — 자체 border 줄임 */
.modal-body .card {
    border: 1px solid var(--border) !important;
    box-shadow: none !important;
    margin-bottom: 12px !important;
}

/* ====================================================================== */
/* 텍스트 톤 추가 보강 — 누락된 영역 일괄 적용                              */
/* ====================================================================== */
/* KPI 카드 큰 숫자 — 본문 톤 (강조) */
body #page-wrapper .announcement-heading {
    color: var(--foreground) !important;
}
/* KPI 카드 라벨 — muted */
body #page-wrapper .announcement-bottom > div > div:first-child {
    color: var(--muted-foreground) !important;
}
/* KPI 카드 보조 (작은 글자 / 부가 설명) — subtle */
body #page-wrapper .announcement-bottom > div > div:last-child:not(:first-child) {
    color: var(--subtle-foreground) !important;
}
/* fieldset 내 input 라벨 — 보조 톤 */
body #page-wrapper fieldset .form-inline label.form-label,
body #page-wrapper fieldset .pp-form-row label.form-label {
    color: var(--secondary-foreground) !important;
    font-weight: 500 !important;
}

/* ====================================================================== */
/* 입력/수정 폼 (fieldset > form-inline) — flex 레이아웃 강제              */
/* 좁은 컨테이너 (col-lg-6) 안에서 인라인 width 큰 input 이 wrap 되어      */
/* label / input 이 두 줄로 어색하게 보이는 깨짐 보정.                    */
/* ====================================================================== */
body #page-wrapper fieldset .form-inline,
body #page-wrapper fieldset .pp-form-row {
    display: flex !important;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px !important;
    flex-wrap: nowrap;
    width: 100%;
}
body #page-wrapper fieldset .form-inline > label.form-label,
body #page-wrapper fieldset .form-inline > label.form-label,
body #page-wrapper fieldset .pp-form-row > label.form-label {
    flex: 0 0 140px;
    width: 140px !important;
    text-align: right !important;
    margin: 0 !important;
    line-height: 1.4 !important;
    font-weight: 600 !important;
    font-size: 12px !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    letter-spacing: 0.01em !important;
}
/* form-inline 안 input/select/textarea — 인라인 width 무력화 (가용 폭 채움) */
body #page-wrapper fieldset .form-inline > input.form-control,
body #page-wrapper fieldset .form-inline > select.form-control,
body #page-wrapper fieldset .form-inline > textarea.form-control,
body #page-wrapper fieldset .form-inline > .form-control,
body #page-wrapper fieldset .pp-form-row > input.form-control,
body #page-wrapper fieldset .pp-form-row > select.form-control,
body #page-wrapper fieldset .pp-form-row > textarea.form-control,
body #page-wrapper fieldset .pp-form-row > .form-control {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
    width: auto !important;
    margin: 0 !important;
}
/* fa-question-circle 가 라벨 안에 있을 때 — 라벨 너비 변경 안 됨 */
body #page-wrapper fieldset .form-inline > label.form-label > i.fa-question-circle,
body #page-wrapper fieldset .form-inline > label.form-label > i.fa-question-circle,
body #page-wrapper fieldset .pp-form-row > label.form-label > i.fa-question-circle {
    margin-right: 4px !important;
    color: var(--muted-foreground) !important;
}
/* 테이블 안 첫 컬럼 (id/name 등) — 본문 톤 (Bold) */
body #page-wrapper table.table tbody td:first-child:not(.action) {
    font-weight: 500 !important;
}
/* 패널 안에 있는 hint 텍스트 */
body #page-wrapper .card .input-comment {
    color: var(--subtle-foreground) !important;
    font-size: 11px !important;
    margin-top: 2px !important;
}
/* "이상적인 실행 속도" "현재 단위 생산 시간" 등 보조 라벨 */
body #page-wrapper [style*="font-size: 12px"][style*="color"],
body #page-wrapper small.text-muted {
    color: var(--muted-foreground) !important;
}
/* default badge 강제 룰 제거 — pp-09i 의 단일 badge 룰이 담당 */
/* 알람 우선순위 badge — info / warn / error 색 명시 */
body #page-wrapper .alarm-priority-badge.info {
    background: rgba(34, 139, 70, 0.10) !important;
    color: oklch(45% 0.18 145) !important;
}
body #page-wrapper .alarm-priority-badge.warn {
    background: rgba(217, 119, 6, 0.10) !important;
    color: oklch(50% 0.18 75) !important;
}
body #page-wrapper .alarm-priority-badge.error {
    background: rgba(220, 38, 38, 0.10) !important;
    color: oklch(50% 0.20 27) !important;
}
/* 시간 / 날짜 디스플레이 — subtle (보조 정보) */
body #page-wrapper .card-body .time,
body #page-wrapper .card-body .timestamp,
body #page-wrapper time {
    color: var(--subtle-foreground) !important;
}
/* 패널 footer "오브젝트 ID :" 스타일 */
body #page-wrapper .card-footer {
    background: transparent !important;
    border-top: 1px solid var(--border) !important;
    color: var(--muted-foreground) !important;
    border-radius: 0 0 12px 12px !important;
}

/* 패널 푸터 액션 영역 (검색/저장 등 버튼 묶음) — 살짝 채워진 배경 */
body #page-wrapper .card-footer.card-footer-actions {
    background: var(--muted, #f8fafc) !important;
    padding: 10px 12px !important;
}
body #page-wrapper .card-footer B,
body #page-wrapper .card-footer b,
body #page-wrapper .card-footer strong {
    color: var(--secondary-foreground) !important;
    font-weight: 600 !important;
}
/* Status indicator (정상/경고/심각) — 색 명시 (OK 룰 삭제, WARN/ERROR 만 유지) */
body #page-wrapper [data-status="WARN"] * {
    color: var(--warning) !important;
}
body #page-wrapper [data-status="ERROR"] * {
    color: var(--destructive) !important;
}
/* 페이지 헤더 액션 영역 input/select placeholder */
body #page-wrapper .pp-page-header-right .form-control::placeholder {
    color: var(--subtle-foreground) !important;
    opacity: 0.85 !important;
}
/* 사이드바 카테고리 헤더 (Overview / Connectivity 등) — 시각적 강조 */
body .pp-nav-section-header span:first-child {
    color: oklch(60% 0.02 260) !important;                          /* 사이드바 dark 위 가독 */
}
/* 카드 안 progress bar 텍스트 — 본문 */
body #page-wrapper .progress-bar {
    color: var(--primary-foreground) !important;
}

/* ====================================================================== */
/* 페이지 헤더 / 패널 헤더 우측 버튼 — 사이즈 표준화                       */
/* 모든 액션 버튼의 height/padding/font-size 통일 (시각적 일관성)          */
/* ====================================================================== */
/* 페이지 헤더 우측 액션 영역 — 표준 36px height */
body #page-wrapper .pp-page-header-right > .btn,
body #page-wrapper .pp-page-header .btn-group > .btn,
body #page-wrapper .pp-page-header-right form .btn,
body #page-wrapper .pp-page-header-right input.form-control,
body #page-wrapper .pp-page-header-right select.form-control {
    height: 36px !important;
    padding: 0 14px !important;
    font-size: 13px !important;
    line-height: 1.4 !important;
    font-weight: 500 !important;
    border-radius: 6px !important;
    margin: 0 !important;
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
/* btn-group 내부 — 외곽만 라운드, 내부 0 / 보더 1px 겹침 */
body #page-wrapper .pp-page-header .btn-group {
    display: inline-flex;
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
    border-radius: 6px !important;
}
body #page-wrapper .pp-page-header .btn-group > .btn {
    border-radius: 0 !important;
    margin-left: -1px !important;
    box-shadow: none;
}
body #page-wrapper .pp-page-header .btn-group > .btn:first-child {
    border-top-left-radius: 6px !important;
    border-bottom-left-radius: 6px !important;
    margin-left: 0 !important;
}
body #page-wrapper .pp-page-header .btn-group > .btn:last-child {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
}
/* 헤더 드롭다운 토글 우측 라운드 — ul.dropdown-menu 가 :last-child 라 토글이 빠지는 문제 보정 */
body #page-wrapper .pp-page-header .btn-group > .btn.dropdown-toggle:last-of-type {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
}
body #page-wrapper .pp-page-header .btn-group > .btn:hover,
body #page-wrapper .pp-page-header .btn-group > .btn:focus {
    z-index: 2;
}
/* 페이지 헤더 버튼 포커스-블러 이펙트 — 폼 버튼(.btn:focus 룰)과 동일한 링 적용.
   :focus/:active/:focus-visible 선택자가 기본 셀렉터보다 specificity 가 높으므로
   포커스 링이 자연스럽게 우선 적용된다(specificity 기반, 마커 없음). */
body #page-wrapper .pp-page-header-right > .btn:focus,
body #page-wrapper .pp-page-header-right > .btn:active,
body #page-wrapper .pp-page-header-right > .btn.active,
body #page-wrapper .pp-page-header-right > .btn:active:focus,
body #page-wrapper .pp-page-header-right > .btn:focus-visible,
body #page-wrapper .pp-page-header .btn-group > .btn:focus,
body #page-wrapper .pp-page-header .btn-group > .btn:active,
body #page-wrapper .pp-page-header .btn-group > .btn.active,
body #page-wrapper .pp-page-header .btn-group > .btn:active:focus,
body #page-wrapper .pp-page-header .btn-group > .btn:focus-visible,
body #page-wrapper .pp-page-header-right form .btn:focus,
body #page-wrapper .pp-page-header-right form .btn:active,
body #page-wrapper .pp-page-header-right form .btn.active,
body #page-wrapper .pp-page-header-right form .btn:active:focus,
body #page-wrapper .pp-page-header-right form .btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px oklch(55% 0.22 165 / 0.20);
}
/* 페이지 헤더 select — text padding 화살표 공간 확보 */
body #page-wrapper .pp-page-header-right select.form-control {
    padding: 0 32px 0 14px !important;
}
/* 페이지 헤더 input form-control */
body #page-wrapper .pp-page-header-right input.form-control {
    padding: 0 14px !important;
}
/* ----- 패널 헤더 우측 액션 영역 — 표준 30px height (텍스트 wrap 방지) ----- */
body #page-wrapper .card-head-actions > .btn,
body #page-wrapper .card-head-actions .btn-group > .btn,
body #page-wrapper .card-head-actions > input.form-control,
body #page-wrapper .card-head-actions > select.form-control,
body #page-wrapper .card-head-actions .input-group input,
body #page-wrapper .card-head-actions .input-group .input-group-text {
    height: 30px !important;
    padding: 0 12px !important;
    font-size: 12px !important;
    line-height: 1.4 !important;
    font-weight: 500 !important;
    border-radius: 6px !important;
    margin: 0 !important;
    box-shadow: none;
    white-space: nowrap !important;
}
/* 패널 헤더 버튼 포커스-블러 이펙트 — 페이지 헤더와 동일한 포커스 링 복원
   :focus/:active/.active specificity 가 기본 셀렉터보다 높아 자연스럽게 우선 적용 */
body #page-wrapper .card-head-actions > .btn:focus,
body #page-wrapper .card-head-actions > .btn:active,
body #page-wrapper .card-head-actions > .btn.active,
body #page-wrapper .card-head-actions > .btn:active:focus,
body #page-wrapper .card-head-actions > .btn:focus-visible,
body #page-wrapper .card-head-actions .btn-group > .btn:focus,
body #page-wrapper .card-head-actions .btn-group > .btn:active,
body #page-wrapper .card-head-actions .btn-group > .btn.active,
body #page-wrapper .card-head-actions .btn-group > .btn:active:focus,
body #page-wrapper .card-head-actions .btn-group > .btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px oklch(55% 0.22 165 / 0.20);
}
/* 패널 헤더 input-group — 일체화 (30px 높이 통일).
   Bootstrap 3 의 display:table / table-cell 구조를 flex 로 완전 덮어쓴다. */
body #page-wrapper .card-head-actions .input-group {
    height: 30px !important;
    display: inline-flex !important;
    flex-wrap: nowrap;
    align-items: stretch;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 6px !important;
    overflow: hidden;
    background: var(--pp-white) !important;
    width: auto;
    min-width: 200px;
    max-width: 320px;
    vertical-align: middle;
}
body #page-wrapper .card-head-actions .input-group-text {
    background: var(--muted, #f4f4f5) !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    border: 0 !important;
    border-right: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 0 !important;
    font-size: 13px !important;
    height: auto;
    min-width: 32px;
    padding: 0 10px !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    line-height: 1 !important;
    flex: 0 0 auto;
}
body #page-wrapper .card-head-actions .input-group-text > i,
body #page-wrapper .card-head-actions .input-group-text > .fa,
body #page-wrapper .card-head-actions .input-group-text > .fa-light,
body #page-wrapper .card-head-actions .input-group-text > .fa-light,
body #page-wrapper .card-head-actions .input-group-text > .fa-light {
    line-height: 1 !important;
    font-size: 13px !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    height: auto;
    margin: 0 !important;
}
body #page-wrapper .card-head-actions .input-group input.form-control {
    border: 0 !important;
    border-radius: 0 !important;
    height: 28px !important;
    line-height: 1.4 !important;
    padding: 0 10px !important;
    flex: 1 1 auto;
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    background: transparent !important;
    box-shadow: none !important;
}
body #page-wrapper .card-head-actions .input-group input.form-control:focus {
    box-shadow: none !important;
    outline: 0 !important;
}
/* 패널 헤더 아이콘 only 버튼 — 정사각 30×30 (명시 클래스로만 적용) */
body #page-wrapper .card-head-actions > .btn.btn-icon-only,
body #page-wrapper .card-head-actions > button.btn-icon-only,
body #page-wrapper .card-head-actions > .btn-group > .btn.btn-icon-only {
    width: 30px !important;
    padding: 0 !important;
    justify-content: center;
    font-size: 12px !important;
}
/* 패널 헤더 segmented 탭 (timeline 기간 등) — 30px */
body #page-wrapper .card-head-actions #timeline-range-btns .btn,
body #page-wrapper .card-head-actions .btn-group .tl-range-btn {
    height: 30px !important;
    padding: 0 12px !important;
    font-size: 11px !important;
}

/* ----- 패널 헤더 우측 액션 영역 — flex 정렬 (multi-control) -----
 * 표준: 카드 헤더 타이틀 우측 액션바(버튼·입력·셀렉트)는 항상 한 줄(nowrap).
 * .pp-header-search(페이지 헤더)와 동일 원칙 — 행바꿈 금지. 좁은 화면은 pp-99 모바일이 가로 스크롤 처리. */
body #page-wrapper .card-head-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: nowrap;
    justify-content: flex-end;
}

/* select 박스도 input/btn 과 같은 30px 높이로 통일 + 가로 auto/명시 너비 */
body #page-wrapper .card-head-actions select.form-control {
    height: 30px !important;
    width: auto !important;
    min-width: 130px;
    max-width: 240px;
    padding: 0 28px 0 10px !important;
    font-size: 12px !important;
    line-height: 1.4 !important;
    border-radius: 6px !important;
    background-position: right 8px center !important;
    background-size: 14px !important;
    display: inline-block !important;
}

body #page-wrapper .card-head-actions input[type="text"].form-control,
body #page-wrapper .card-head-actions input[type="search"].form-control,
body #page-wrapper .card-head-actions input[type="number"].form-control {
    height: 30px !important;
    width: auto !important;
    min-width: 140px;
    max-width: 260px;
    padding: 0 10px !important;
    font-size: 12px !important;
    line-height: 1.4 !important;
    border-radius: 6px !important;
    display: inline-block !important;
}

/* input-group 안 input 은 input-group 의 폭을 따른다 (덮어쓰기) */
body #page-wrapper .card-head-actions .input-group input.form-control {
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    flex: 1 1 auto;
}

/* ph-field 안 select/input 은 ph-field 의 정렬을 따른다 */
body #page-wrapper .card-head-actions .ph-field > select.form-control,
body #page-wrapper .card-head-actions .ph-field > input.form-control {
    min-width: 100px;
    max-width: 220px;
}

/* 라벨+컨트롤 페어 — 헤더 안에서 form-inline 같은 inline 라벨링.
 *  ph-field 자체가 30px 높이를 가지도록 강제해 옆의 .btn / select 와 baseline 일치. */
body #page-wrapper .card-head-actions .ph-field {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    line-height: 30px !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
    vertical-align: middle;
}

body #page-wrapper .card-head-actions .ph-field > label {
    margin: 0 !important;
    padding: 0 !important;
    height: 30px;
    line-height: 30px !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    white-space: nowrap !important;
    display: inline-flex;
    align-items: center;
}

body #page-wrapper .card-head-actions .ph-field > select.form-control,
body #page-wrapper .card-head-actions .ph-field > input.form-control {
    height: 30px !important;
    line-height: 1.4 !important;
    margin: 0 !important;
    vertical-align: middle;
}

/* 헤더 안 vertical separator — 30px 높이 안에서 18px 중앙 정렬 */
body #page-wrapper .card-head-actions .ph-sep {
    display: inline-flex;
    width: 1px;
    height: 18px;
    background: var(--pp-border) !important;
    margin: 0 4px !important;
    align-self: center;
}

/* card-head-actions 안의 모든 직속 자식 — 동일 높이 보장 (botton / select / input / btn-group) */
body #page-wrapper .card-head-actions > .btn,
body #page-wrapper .card-head-actions > .btn-group,
body #page-wrapper .card-head-actions > select.form-control,
body #page-wrapper .card-head-actions > input.form-control,
body #page-wrapper .card-head-actions > .input-group,
body #page-wrapper .card-head-actions > .ph-field,
body #page-wrapper .card-head-actions > .ph-sep {
    vertical-align: middle;
    align-self: center;
}

body #page-wrapper .card-head-actions > .btn-group > .btn {
    vertical-align: middle;
}
/* 페이지 헤더 라벨 (조회 결과 표기 등) — 작은 보조 텍스트 */
body #page-wrapper .pp-page-header-right .form-inline > label {
    font-size: 12px !important;
    color: var(--muted-foreground) !important;
}

/* ====================================================================== */
/* 타임라인 차트 공통 오버라이드 — vis-timeline 등 라이브러리                 */
/* timeline-axis-grid 가 좌측 세로선만 표시되게 (right/top/bottom 제거)        */
/* ====================================================================== */
body div.timeline-axis-grid {
    -moz-box-sizing: border-box !important;
    border: 0 !important;
    border-left-style: solid !important;
    border-left-color: #f0f0f0 !important;   /* 연한 회색 — 시각 노이즈 줄임 */
    border-width: 1px !important;
    box-sizing: border-box !important;
}

/* === pp-03-utilities.css === */
/* ============================================================
 * 텍스트 정렬 유틸리티 — 인라인 style="text-align:..." 제거 후 사용
 * ============================================================ */
.text-center { text-align: center !important; }
.text-end,
.text-right  { text-align: right !important; }
.text-start,
.text-left   { text-align: left !important; }


/* ============================================================
 * Spacing / Display 유틸리티 — 인라인 style 제거 후 사용
 * 4px scale: 0,1=4,2=8,3=12,4=16,5=20,6=24,8=32
 * ============================================================ */
.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: 4px !important; }
.mb-2 { margin-bottom: 8px !important; }
.mb-3 { margin-bottom: 12px !important; }
.mb-4 { margin-bottom: 16px !important; }
.mb-5 { margin-bottom: 20px !important; }
.mb-6 { margin-bottom: 24px !important; }

.mt-0 { margin-top: 0 !important; }
.mt-1 { margin-top: 4px !important; }
.mt-2 { margin-top: 8px !important; }
.mt-3 { margin-top: 12px !important; }
.mt-4 { margin-top: 16px !important; }
.mt-5 { margin-top: 20px !important; }
.mt-6 { margin-top: 24px !important; }

.ml-0 { margin-left: 0 !important; }
.ml-1 { margin-left: 4px !important; }
.ml-2 { margin-left: 8px !important; }
.ml-3 { margin-left: 12px !important; }
.ml-4 { margin-left: 16px !important; }
.ml-auto { margin-left: auto !important; }

.mr-0 { margin-right: 0 !important; }
.mr-1 { margin-right: 4px !important; }
.mr-2 { margin-right: 8px !important; }
.mr-3 { margin-right: 12px !important; }
.mr-4 { margin-right: 16px !important; }

.p-0 { padding: 0 !important; }
.p-1 { padding: 4px !important; }
.p-2 { padding: 8px !important; }
.p-3 { padding: 12px !important; }
.p-4 { padding: 16px !important; }

.pt-0 { padding-top: 0 !important; }
.pt-2 { padding-top: 8px !important; }
.pt-3 { padding-top: 12px !important; }
.pb-0 { padding-bottom: 0 !important; }
.pb-2 { padding-bottom: 8px !important; }
.pb-3 { padding-bottom: 12px !important; }

.gap-1 { gap: 4px !important; }
.gap-2 { gap: 8px !important; }
.gap-3 { gap: 12px !important; }
.gap-4 { gap: 16px !important; }

.d-flex   { display: flex !important; }
.d-iflex  { display: inline-flex !important; }
.d-block  { display: block !important; }
.d-iblock { display: inline-block !important; }
.d-none   { display: none !important; }
/* 초기 hidden — JS 가 toggle 하려는 element 용. !important 없어서 inline style/script 가 override 가능. */
.is-hidden-init { display: none; }

/* Tailwind 네이밍 유틸 제거(BS5 등가 사용): flex-col→flex-column, items-center→align-items-center,
   justify-*→justify-content-*, flex-1→flex-fill. 위 클래스는 미사용이라 정의 삭제. */

.opacity-50 { opacity: 0.5 !important; }
.opacity-70 { opacity: 0.7 !important; }

/* 폰트 weight 보조 */
.fw-bold   { font-weight: 600 !important; }
.fw-normal { font-weight: 400 !important; }

/* 표준 mono 폰트 유틸 — 인라인 style="font-family:monospace" 제거 후 사용.
   토큰 정본은 .pp-data-value.pp-mono(pp-25-cards.css) 와 동일한 var(--pp-font-mono, …). */
.pp-mono { font-family: var(--pp-font-mono, ui-monospace, monospace); }

/* 폰트 색 보조 (토큰 기반) */
.text-muted-fg   { color: var(--muted-foreground) !important; }
.text-subtle     { color: var(--subtle-foreground, #9ca3af) !important; }
.text-primary-fg { color: var(--primary, var(--pp-primary-strong)) !important; }

/* 추가 유틸리티 */
.text-decoration-none { text-decoration: none !important; }
.text-nowrap          { white-space: nowrap !important; }
.cursor-pointer       { cursor: pointer !important; }
.overflow-hidden      { overflow: hidden !important; }


/* ============================================================
 * 폭 유틸리티 (col-w-*) — 인라인 width 제거 후 사용
 * 기존 .table > thead > tr > th.col-w-* 정의를 일반 요소까지 확장
 * ============================================================ */
.col-w-30  { width: 30px !important; }
.col-w-40  { width: 40px !important; }
.col-w-50  { width: 50px !important; }
.col-w-60  { width: 60px !important; }
.col-w-70  { width: 70px !important; }
.col-w-80  { width: 80px !important; }
.col-w-90  { width: 90px !important; }
.col-w-100 { width: 100px !important; }
.col-w-110 { width: 110px !important; }
.col-w-120 { width: 120px !important; }
.col-w-130 { width: 130px !important; }
.col-w-140 { width: 140px !important; }
.col-w-150 { width: 150px !important; }
.col-w-160 { width: 160px !important; }
.col-w-170 { width: 170px !important; }
.col-w-180 { width: 180px !important; }
.col-w-190 { width: 190px !important; }
.col-w-200 { width: 200px !important; }
.col-w-210 { width: 210px !important; }
.col-w-220 { width: 220px !important; }
.col-w-230 { width: 230px !important; }
.col-w-240 { width: 240px !important; }
.col-w-250 { width: 250px !important; }
.col-w-260 { width: 260px !important; }
.col-w-280 { width: 280px !important; }
.col-w-300 { width: 300px !important; }
.col-w-320 { width: 320px !important; }
.col-w-340 { width: 340px !important; }
.col-w-350 { width: 350px !important; }
.col-w-380 { width: 380px !important; }
.col-w-400 { width: 400px !important; }
.col-w-450 { width: 450px !important; }
.col-w-500 { width: 500px !important; }
.col-w-600 { width: 600px !important; }

/* 퍼센트 폭 */
.w-100 { width: 100% !important; }
.w-75  { width: 75% !important; }
.w-50  { width: 50% !important; }
.w-25  { width: 25% !important; }

/* 흰색 텍스트 */
.text-white { color: var(--pp-white) !important; }
.w-20  { width: 20% !important; }
.w-40  { width: 40% !important; }
.w-60  { width: 60% !important; }
.w-80  { width: 80% !important; }
.w-90  { width: 90% !important; }


/* ============================================================
 * Padding / 폰트 사이즈 / 보더 유틸리티 — 추가 batch
 * ============================================================ */
.pl-1 { padding-left: 4px !important; }
.pl-2 { padding-left: 8px !important; }
.pl-3 { padding-left: 12px !important; }
.pl-4 { padding-left: 16px !important; }
.pl-5 { padding-left: 20px !important; }
.pr-1 { padding-right: 4px !important; }
.pr-2 { padding-right: 8px !important; }
.pr-3 { padding-right: 12px !important; }
.pr-4 { padding-right: 16px !important; }
.pr-5 { padding-right: 20px !important; }
.px-2 { padding-left: 8px !important; padding-right: 8px !important; }
.px-3 { padding-left: 12px !important; padding-right: 12px !important; }
.px-4 { padding-left: 16px !important; padding-right: 16px !important; }
.py-1 { padding-top: 4px !important; padding-bottom: 4px !important; }
.py-2 { padding-top: 8px !important; padding-bottom: 8px !important; }
.py-3 { padding-top: 12px !important; padding-bottom: 12px !important; }

.fs-12 { font-size: 12px !important; }
.fs-14 { font-size: 14px !important; }
.fs-15 { font-size: 15px !important; }
.fs-18 { font-size: 18px !important; }
.fs-24 { font-size: 24px !important; }

.h-100   { height: 100% !important; }
.mh-30   { min-height: 30px !important; }
.text-truncate { overflow: hidden !important; white-space: nowrap !important; text-overflow: ellipsis !important; }

/* 보더 */
.border-bottom-dashed-light { border-bottom: 1px dotted var(--pp-border) !important; }
.border-bottom-light        { border-bottom: 1px solid var(--pp-border) !important; }
.border-right-0             { border-right: 0 !important; }
.border-0                   { border: 0 !important; }

/* 텍스트 메타 (작은 회색) */
.text-meta-sm { font-size: 12px !important; color: var(--muted-foreground, var(--pp-muted-fg)) !important; }

/* 패널 헤딩 컴팩트 표시값 (중앙 큰 숫자) */

/* 차트 컨테이너 폭 100% + 고정 높이 */
.chart-200 { width: 100% !important; height: 200px !important; }
.chart-250 { width: 100% !important; height: 250px !important; }
.chart-280 { width: 100% !important; height: 280px !important; }
.chart-300 { width: 100% !important; height: 300px !important; }

/* input-group 코너 제거 (addon 연결용) */
.rounded-r-0 { border-top-right-radius: 0 !important; border-bottom-right-radius: 0 !important; }
.rounded-l-0 { border-top-left-radius:  0 !important; border-bottom-left-radius:  0 !important; }

/* 작은 메타 텍스트 */
.text-meta-xs { font-size: 11px !important; color: var(--muted-foreground, var(--pp-muted-fg)) !important; }

/* 폼 라벨 캡 (전체 폭 라벨) */

/* 보조 메타 (90% size + small top padding) — 라벨 옆 부속 텍스트 */
.label-meta-sm { font-size: 90% !important; padding-top: 3px !important; }

.fs-11   { font-size: 11px !important; }
.text-ddd { color: #ddd !important; }

.mt-neg-10 { margin-top: -10px !important; }

/* 패널 안 헤더 더블라인 (padding-bottom + thin border)
 * NOTE: 동일 selector .section-divider 가 pp-09a 에도 정의 — 현재 어디서도 미사용 (dead).
 *       남겨도 문제 없으나 cascade 상 pp-09a 가 이김. */
.section-divider {
    margin-bottom: 10px !important;
    padding-bottom: 3px !important;
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
}

/* 차트 컨테이너 100x100 + thin border-top */

/* 폼 라벨 인덴트 (8 column gap) */
.ml-form-indent { margin-left: 168px !important; }


/* 추가 batch utility */
.text-danger-c { color: var(--pp-tone-danger-bg) !important; }
.text-foreground-c { color: var(--foreground, #111827) !important; }
.fs-10 { font-size: 10px !important; }

/* 페이지 헤더 조회 시간 인풋 (320px + center + bold) */
.search-time-input {
    width: 320px !important;
    text-align: center !important;
    font-weight: 600 !important;
}

/* 상태 칩 (회색 배경 + 흰 텍스트 + 작은 라운드) */
.chip-status-mute {
    background: #888 !important;
    color: var(--pp-white) !important;
    font-size: 11px !important;
    padding: 3px !important;
    border-radius: 3px !important;
    margin-top: 3px !important;
    text-align: center !important;
}

/* 인포 칩 (진한 파란 배경 + 흰 텍스트 — 라이트 테마 정책) */
.chip-info-pale {
    padding: 2px 8px !important;
    border-radius: 6px !important;
    background: var(--pp-primary) !important;
    color: var(--pp-white) !important;
}

/* 라벨 캡 (50px 폭 작은 회색 배경) */
.label-cap-50 {
    background: #f4f4f4 !important;
    width: 50px !important;
    line-height: 15px !important;
    font-size: 11px !important;
}

/* subtle hint (10px ccc with left pad) */


/* 추가 batch (이번 라운드) */

/* 텍스트 정렬 + 색상 */
.text-muted-c { color: #888 !important; }

/* 폼 라벨 (라인 높이 45 + 일반 폰트 + 중간 사이즈) */
.label-line-45 {
    line-height: 45px !important;
    font-weight: 400 !important;
    font-size: 16px !important;
}

/* 컬럼 라벨 (100px 폭 + 중앙 + 회색 + 하단 보더) */
.col-label-100 {
    width: 100px !important;
    text-align: center !important;
    color: #555 !important;
    border-bottom: 1px solid #ddd !important;
}

/* 제목 핫 탭 (15px 흰 + 진하게 + 30/24 라인) */
.title-hot-30 {
    font-size: 15px !important;
    color: var(--pp-white) !important;
    font-weight: 700 !important;
    line-height: 30px !important;
}


/* clear */
.clear-both { clear: both !important; }

/* 빈 영역 표기 (margin + 회색 + 중앙) */
.placeholder-empty {
    margin-top: 20px !important;
    margin-bottom: 20px !important;
    color: #ddd !important;
    text-align: center !important;
}

/* 패널 본문 차트 영역 표준 (relative + min-height) */
.chart-container-280 {
    position: relative !important;
    min-height: 280px !important;
}

/* 패널 헤더 보조 (large title + bottom border) */

/* 12px 회색 + 작은 라인 */
.text-meta-tight {
    font-size: 12px !important;
    color: #888 !important;
    line-height: 12px !important;
}

/* 작은 회색 한 줄 */
.text-cap-12 {
    font-size: 12px !important;
    color: #ccc !important;
}

/* 작은 차트 placeholder (절대 위치 중앙) */
.chart-no-data-overlay {
    display: none;
    position: absolute !important;
    left: 50% !important;
    top: 50% !important;
    transform: translate(-50%, -50%) !important;
    z-index: 100 !important;
    font-size: 13px !important;
    color: #888 !important;
}

/* OEE/RAM/EMS 토글 차트 폭+높이 */

/* order/view 패널 헤더 (18px + bottom border) */

/* order/view 작은 sub-info (10px + ddd border) */

/* float 좌측 + margin + 40% 폭 */

/* 정사각 sticker (150x150) */

/* text-right + bold */
.text-end-bold {
    text-align: right !important;
    font-weight: 700 !important;
}


/* Round 4 batch */

.text-white-xs {
    font-size: 10px !important;
    color: var(--pp-white) !important;
}

.section-tab-meta {
    font-size: 12px !important;
    border-bottom: 0 !important;
    padding: 2px !important;
}

.text-start-auto {
    width: auto !important;
    text-align: left !important;
}

.h-min-120 { min-height: 120px !important; }

.form-readme-block {
    max-width: 400px !important;
    margin-bottom: 14px !important;
}


.ml-90 { margin-left: 90px !important; }
.ml-30 { margin-left: 30px !important; }

.text-tab-meta-bold {
    font-size: 12px !important;
    color: #888 !important;
    font-weight: 700 !important;
}

/* 차트 영역 100x100 (상단 보더 제거 — margin-top 으로 분리) */
.chart-100-bt {
    width: 100% !important;
    height: 100px !important;
    margin-top: 10px !important;
}
/* 차트 영역 — 고정 높이 변형 (monitoring Tier 1 차트) */
.chart-h-220 { width: 100% !important; height: 220px !important; }
.chart-h-280 { width: 100% !important; height: 280px !important; }
/* monitoring 사이드 차트 — border-top 제거 + margin-top */
.mon-side-chart-220,
.mon-side-chart-150 {
    width: 100% !important;
    margin-top: 10px !important;
}
.mon-side-chart-220 { height: 220px !important; }
.mon-side-chart-150 { height: 150px !important; }
.text-success-c { color: var(--pp-tone-success-bg) !important; }


/* Round 5 batch */

/* font-size variants */
.fs-32 { font-size: 32px !important; }

/* text-meta-xs variants (이미 정의된 것 외) */
.text-hint-aaa-xs {
    color: #aaa !important;
    font-size: 10px !important;
}

.text-hint-aaa-11 {
    color: #aaa !important;
    font-size: 11px !important;
}

/* === pp-10-layout-shell.css === */

/* ============================================================
 * 전역 스크롤바 — 얇고 깔끔하게 (OS 기본 두꺼운 스크롤바 대체)
 *   - 8px 트랙에 content-box + 2px 투명 보더로 실제 thumb ~4px (slim)
 *   - hover 시에만 진해짐. Firefox 는 scrollbar-width:thin.
 *   컴포넌트별 전용 스크롤바(map/alarm-dropdown 등)는 더 구체적이라 그대로 우선. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--pp-border, var(--pp-text-soft)) transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: var(--pp-border, var(--pp-text-soft));
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover {
    background: var(--muted-foreground, var(--pp-text-muted));
    background-clip: content-box;
}
*::-webkit-scrollbar-corner { background: transparent; }

/* 흰색 텍스트 + 가운데 정렬 */
.text-white-center {
    text-align: center !important;
    color: var(--pp-white) !important;
}

/* 회색 텍스트 + 일반 굵기 */
.text-meta-normal {
    color: #888 !important;
    font-weight: 400 !important;
}

/* Hint label — 작은 옅은 회색 */
.text-eee-sm {
    font-size: 10px !important;
    color: #eee !important;
    padding-left: 10px !important;
}

/* 패딩 padding 10/5 */
.p-10-5 {
    padding: 10px !important;
    padding-bottom: 5px !important;
}

/* 작은 우측 마진 */
.mr-4-2 { margin-right: 16px !important; }

/* 표 안 사용 — 카드형 컨테이너 (3px 라운드 + ddd 보더 + 위쪽 음수 마진) */
.card-floater-3 {
    border: 0 solid #ddd !important;
    border-radius: 3px !important;
    margin-top: -10px !important;
    margin-left: 10px !important;
}

/* 흰 카드 박스 */
.card-tile-white {
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 6px !important;
    padding: 10px 12px !important;
}

/* 가운데 + 회색 + padding 5 */
.empty-center-5 {
    text-align: center !important;
    color: #ddd !important;
    padding: 5px !important;
}

/* 카운트 박스 (chart 100% × 25px) */
.chart-25-w100 {
    width: 100% !important;
    height: 25px !important;
}

/* 검색 인풋 와이드 (280px) */
.search-input-280 {
    width: 280px !important;
    text-align: center !important;
    font-weight: 700 !important;
}

/* 폼 selector 크기 강조 */

/* form indent + 작은 폰트 */
.form-help-indent-12 {
    margin-left: 168px !important;
    font-size: 12px !important;
}

/* 패딩 좌우 20 */
.px-20 {
    padding-left: 20px !important;
    padding-right: 20px !important;
}


/* Round 6 batch */
.h-46  { height: 46px !important; }
.h-80  { height: 80px !important; }
.h-160 { height: 160px !important; }
.h-115 { height: 115px !important; }


.text-hint-9-999 {
    font-size: 9px !important;
    color: #999 !important;
}

.text-fs-16-normal {
    font-size: 16px !important;
    font-weight: 400 !important;
}

.text-11-333 {
    font-size: 11px !important;
    color: #333 !important;
}

.text-cap-bold {
    color: #888 !important;
    font-size: 11px !important;
    text-align: center !important;
    font-weight: 700 !important;
}

.border-top-light {
    border-top: 1px solid #eee !important;
}


.border-2-ccc { border: 2px solid #ccc !important; }

/* ====================================================================== */
/* 사이드바 (좌측 네비게이션) — Signal 클론                                  */
/* ====================================================================== */

body #navigation.navbar-static-side,
body #navigation {
    position: fixed !important;
    left: 0 !important;
    top: var(--pp-topbar-h) !important;        /* #brand 아래로 */
    width: var(--pp-sidebar-w) !important;
    /* PPZoom 의 --pp-zoom (기본 1) 로 역보정 — zoom < 1 일 때 vh 가 시각적으로 줄어드는 것을
       보정해 사이드바가 항상 뷰포트 전체 높이를 채움. */
    height: calc((100vh - var(--pp-topbar-h)) / var(--pp-zoom, 1)) !important;
    /* 사이드바 배경 — collapsed 툴팁과 동일 단색 (.pp-nav-tip @ pp-02a-topbar-headers.css:437) */
    background: linear-gradient(135deg, #1a1a1a 0%, #2c3e50 100%) !important;
    color: var(--sidebar-foreground) !important;
    border-right: 0 !important;
    /* 외부 그림자만 (우측 inset highlight 제거) */
    box-shadow: 2px 0 8px rgba(15, 23, 42, 0.24) !important;
    z-index: 40 !important;
    /* collapsed 상태에서 ::after 툴팁이 사이드바 폭 밖으로 나가야 하므로 visible 필요 */
    overflow: visible;
    padding: 0 !important;
    margin: 0 !important;
    display: flex !important;
    flex-direction: column;
    box-sizing: border-box !important;
}
* { box-sizing: border-box; }
/* 스크롤은 내부 sidebar-collapse 에서 처리 + 스크롤바 숨김 */
#navigation .sidebar-collapse {
    overflow-y: auto;
    overflow-x: visible;        /* collapsed 툴팁이 사이드바 밖으로 나갈 수 있게 */
    scrollbar-width: none;     /* Firefox */
    -ms-overflow-style: none;  /* IE/Edge */
}
#navigation .sidebar-collapse::-webkit-scrollbar {
    display: none;             /* Chrome/Safari */
    width: 0; height: 0;
}

/* 사이드바 로고 블록 — #brand 를 좌측 사이드바 헤더로 사용 */
body #brand.pp-nav-header,
body .navbar #brand.pp-nav-header {
    position: fixed !important;
    left: 0 !important;
    top: 0 !important;
    width: var(--pp-sidebar-w) !important;
    height: var(--pp-topbar-h) !important;
    /* 로고 배경 — 단색 (그라디언트 금지) */
    background: #1a1a1a !important;
    border-right: 0 !important;
    border-bottom: 0px solid rgba(255, 255, 255, 0.06) !important;
    margin: 0 !important;
    padding: 0 !important;
    z-index: 41 !important;
    display: flex !important;
    align-items: center !important;
    float: none !important;
}
body #brand .navbar-brand.pp-brand-link {
    display: flex !important;
    align-items: center;
    gap: 12px;
    width: 100%;
    height: 100%;
    padding: 0 16px !important;
    text-decoration: none !important;
    /* 로고 배경 — 단색 (그라디언트 금지) */
    background: #1a1a1a !important;
}
body #brand img#logo { display: none !important; }

/* 사이드바 다크 배경용 로고 이미지 — 회색 톤 원본을 흰색 실루엣으로 변환 */
body #brand .pp-brand-logo {
    display: block;
    max-height: 32px;
    max-width: calc(var(--pp-sidebar-w) - 32px);
    width: auto;
    height: auto;
    object-fit: contain;
    filter: brightness(0) invert(1);
    opacity: 0.95 !important;
    transform-origin: center center;
}
html.pp-sidebar-collapsed body #brand .pp-brand-logo {
    max-width: calc(var(--pp-sidebar-w-collapsed) - 16px);
    max-height: 28px;
}

/* 로고 호버 시 3바퀴 스핀 (1080deg, 0.9s ease-in-out) */
@keyframes pp-brand-logo-spin-3 {
    from { transform: rotate(0deg); }
    to   { transform: rotate(1080deg); }
}
body #brand:hover .pp-brand-logo,
body #brand .pp-brand-link:hover .pp-brand-logo {
    animation: pp-brand-logo-spin-3 0.9s ease-in-out;
}

/* 사이드바 본문 */
.sidebar-collapse {
    flex: 1;
    overflow-y: auto;
    padding: 16px 12px !important;
    background: transparent !important;
}

/* 카테고리 섹션 헤더 */
/* BS5 .nav { display:flex; flex-wrap:wrap } 가 세로 사이드바 메뉴(#side-menu.nav)를 가로 flex 로 깨뜨림
   → block 복원(li 풀폭 세로 스택). 안 그러면 섹션이 105px 로 줄고 좌측 클리핑·캐럿 위치 오류 발생. */
body #side-menu.nav,
body #side-menu {
    display: block !important;
}
.pp-nav-section {
    margin-bottom: 12px !important;
}
.pp-nav-section-header {
    display: flex; align-items: center;
    width: 100%;
    padding: 6px 12px !important;
    background: transparent !important;
    border: 0 !important;
    color: var(--sidebar-fg-30) !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.18em !important;
    transition: color .15s ease;
    cursor: pointer;
    text-align: left !important;
}
.pp-nav-section-header:hover {
    color: var(--sidebar-fg-50) !important;
}
.pp-nav-section-header .caret {
    margin-left: auto !important;
    font-size: 10px !important;
    transition: transform .2s ease;
    /* Bootstrap 3 의 .caret 은 border 로 삼각형 그림 — FA 아이콘과 중복 → 제거 */
    border: 0 !important;
    width: auto !important;
    height: auto !important;
    vertical-align: baseline !important;
}
.pp-nav-section.collapsed .pp-nav-section-header .caret {
    transform: rotate(-90deg);
}
.pp-nav-section-items {
    margin-top: 4px !important;
    display: flex;
    flex-direction: column;
    gap: 2px;
    transition: max-height .25s ease, opacity .2s ease;
    overflow: hidden;
}
.pp-nav-section.collapsed .pp-nav-section-items {
    max-height: 0;
    opacity: 0 !important;
}

/* 사이드바 메뉴 아이템 */
#side-menu, .nav.nav-second-level { list-style: none; padding: 0 !important; margin: 0 !important; }

#side-menu > li > a,
.pp-nav-section-items a {
    display: flex !important;
    align-items: center;
    gap: 12px;
    padding: 8px 12px !important;
    border-radius: 8px !important;
    font-size: 13px !important;
    font-weight: 500 !important;
    /* 다크 배경 대비 75% 흰 텍스트 — 가독성 + 위계 분리 */
    color: rgba(255, 255, 255, 0.72) !important;
    text-decoration: none !important;
    line-height: 1.3 !important;
    transition: background .15s ease, color .15s ease;
    background: transparent !important;
    border: 0 !important;
}
#side-menu > li > a:hover,
.pp-nav-section-items a:hover {
    /* 호버 배경 — 더 잘 보이도록 0.04 → 0.08 */
    background: rgba(255, 255, 255, 0.08) !important;
    color: var(--pp-white) !important;
}
/* active — primary tint 배경 + 좌측 stripe (border-left) + 흰 텍스트, 우측 모든 boder/shadow 제거 */
#side-menu > li > a.m_selected,
#side-menu > li.active > a,
.pp-nav-section-items a.m_selected,
.pp-nav-section-items a.active {
    background: rgba(96, 165, 250, 0.16) !important;
    color: var(--pp-white) !important;
    font-weight: 600 !important;
    border-left: 0 !important;
    border-right: 0 !important;
    border-top: 0 !important;
    border-bottom: 0 !important;
    box-shadow: none !important;
}
#side-menu > li > a > i,
.pp-nav-section-items a > i {
    width: 18px;
    font-size: 14px !important;
    color: rgba(255, 255, 255, 0.45) !important;
    flex-shrink: 0;
    text-align: center !important;
}
#side-menu > li > a:hover > i,
.pp-nav-section-items a:hover > i {
    color: rgba(255, 255, 255, 0.85) !important;
}
#side-menu > li > a.m_selected > i,
.pp-nav-section-items a.m_selected > i,
.pp-nav-section-items a.active > i {
    color: #60a5fa !important;
}

/* 두 번째 레벨 들여쓰기 (기존 admin.jsp 호환) */
.nav-second-level li a {
    padding-left: 36px !important;
}

/* 사이드바 알람 배지 */
#side-menu .badge {
    margin-left: auto !important;
    padding: 2px 6px !important;
    border-radius: 10px !important;
    font-size: 9px !important;
    font-weight: 600 !important;
    line-height: 1 !important;
    background: var(--sidebar-accent) !important;
    color: var(--sidebar-foreground) !important;
    border: none !important;
}

/* CPU/메모리 박스는 카테고리 위로 안 가게 */
#nav-performance-box {
    border-top: 1px solid var(--sidebar-border) !important;
    background: transparent !important;
    padding: 8px 0 !important;
    margin-top: auto !important;
    flex-shrink: 0;
}
#nav-performance-box * { color: var(--sidebar-fg-50) !important; }
#nav-performance-box b { color: var(--sidebar-foreground) !important; }
#nav-help { display: none; }


/* ============================================================
 * include/footer.jsp — 카피라이트 영역
 * 인라인 style (color:#000) 제거 + 시맨틱 클래스
 * ============================================================ */
.pp-footer-copy {
    display: none !important;
}
.pp-footer-copy-text {
    color: var(--muted-foreground) !important;
    font-size: 11px !important;
}


/* sb-admin.css 의 .row { margin-left: -10px; margin-right: -10px } 음수 마진 override → 0 으로.
   col padding 은 디폴트 (10px) 유지 → row 안 col 좌우 10px 균일 패딩. */
body .row {
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* a11y(WCAG 2.4.1) — 스킵 링크. pp-a11y.js 가 body 최상단에 주입. 포커스 전엔 화면 밖, 포커스 시 노출. */
.pp-skip-link {
    position: absolute;
    top: -200px;
    left: 8px;
    z-index: 20000;
    padding: 8px 16px;
    background: var(--primary, var(--pp-primary-strong));
    color: var(--primary-foreground, var(--pp-white));
    border-radius: 0 0 8px 8px;
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: top 0.12s ease;
}
.pp-skip-link:focus {
    top: 0;
    outline: 2px solid var(--ring, var(--pp-primary-strong));
    outline-offset: 2px;
}
/* main 포커스 타깃은 포커스 아웃라인을 숨김(스킵 후 도착점 — 시각 노이즈 방지) */
.pp-page-content[tabindex="-1"]:focus, #pp-main[tabindex="-1"]:focus { outline: none; }

/* === pp-11-topbar.css === */
/* ====================================================================== */
/* 상단 바 — 페이지 배경 (--pp-primary-pale) 과 동일 hue/lightness 로 통일.   */
/*           backdrop blur 효과 위해 alpha 0.92 유지.                         */
/* ====================================================================== */
.navbar.pp-topnav,
.pp-topnav-static {
    background: oklch(1 0 0 / 0.92) !important;               /* 흰색 + alpha — 페이지(primary-pale) 위 layer 분리 */
    /* backdrop-filter 제거: 이 navbar 가 fixed 사이드바(#navigation)의 DOM 조상이라
       backdrop-filter 가 containing block 을 만들어 사이드바를 우측으로 200px 밀어냄.
       bg alpha 0.92(거의 불투명)라 blur 효과는 미미 → 제거해 레이아웃 정상화. */
    border-bottom: 1px solid var(--border) !important;
    box-shadow: none !important;
    margin-bottom: 0 !important;
    min-height: var(--pp-topbar-h) !important;
    height: var(--pp-topbar-h) !important;
}
#brand { display: none !important; }  /* 사이드바 로고로 대체 */

/* 상단 바 컨테이너 — flex 로 수직 정렬, 사이드바 폭만큼 좌측 패딩.
 * 좌/우 24px 은 페이지 컨텐츠 (#page-wrapper > .row { padding: 0 24px }) 와 정렬. */
nav.navbar.pp-topnav {
    padding-left: 16px !important;   /* #wrapper margin 이 사이드바 클리어 — navbar 는 16px 만(콘텐츠 정렬) */
    padding-right: 24px !important;
    /* BS5 기본 .navbar padding-block(0.5rem=8px) 제거 — 안 그러면 툴바 항목이 8px 아래로 밀려 수직정렬 깨짐 */
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    display: flex !important;
    flex-direction: row;
    align-items: center !important;
    gap: 0;
}
nav.navbar.pp-topnav > * { float: none !important; }
#nav.navbar-top-links.pp-nav-left {
    margin: 0 !important;
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    flex-wrap: nowrap !important;   /* BS5 .nav 기본 flex-wrap:wrap 무력화 — 상단바 링크/검색 줄바꿈 방지 */
    min-height: var(--pp-topbar-h);
}
#nav.navbar-top-links.pp-nav-left > li {
    float: none !important;
    display: inline-flex;
    align-items: center;
    height: var(--pp-topbar-h);
    padding: 0 !important;
}
#nav.navbar-top-links.pp-nav-left > li#nav-eql {
    flex: 1 1 auto;
    max-width: 520px;
    padding: 0 8px !important;
}
#nav-toolbar.navbar-top-links.pp-nav-right {
    margin: 0 !important;
    display: flex;
    align-items: center;
    height: var(--pp-topbar-h);
    flex-shrink: 0;
}
#nav-toolbar > li {
    float: none !important;
    display: inline-flex;
    align-items: center;
    height: var(--pp-topbar-h);
}
#nav-eql-form { width: 100%; margin: 0 !important; }
#loadingbar-frame { display: none !important; }

/* health-badge — 색깔 배경 위 흰색 텍스트 (정상/비정상/경고 등) */
.health-badge,
.health-badge * {
    color: var(--pp-white) !important;
}

/* ─── 페이지 로딩 프로그레스 (NProgress) ───────────────────────── */
#nprogress {
    pointer-events: none;
}
#nprogress .bar {
    /* 주황 그라디언트 — amber 500 → orange 500 → orange 600 */
    background: linear-gradient(90deg, #f59e0b 0%, #f97316 60%, #ea580c 100%) !important;
    height: 3px !important;
    position: fixed;
    z-index: 10500;
    top: 0;
    left: 0;
    width: 100%;
}
#nprogress .peg {
    box-shadow: 0 0 12px #f97316, 0 0 6px #f59e0b !important;
    opacity: 0.9 !important;
}
#nprogress .spinner {
    display: none !important;        /* 우측 스피너 비활성 — 상단 바만 사용 */
}

/* EQL 검색 바 — Signal dashboard 의 Search 박스 톤 (single rounded pill) */
body #nav-eql,
body li#nav-eql {
    padding: 0 !important;
    margin: 0 !important;
}
/* 좌측 search 아이콘 */
/* CodeMirror placeholder/표시영역 정리 */

/* ====================================================================== */
/* 컨텐츠 헤더 — Bootstrap .page-header (h3.page-header) 또는 페이지 최상위 h3  */
/* ====================================================================== */
#page-wrapper h3.page-header,
#page-wrapper > h3:first-child,
#page-wrapper > .container-fluid > h3:first-child,
#page-wrapper > .row:first-child h3.page-header {
    margin: 0 !important;
    padding: 20px 24px 16px !important;
    font-size: 22px !important;
    font-weight: 700 !important;
    color: var(--foreground) !important;
    letter-spacing: -0.01em !important;
    border: 0 !important;        /* 컨텐츠 타이틀 보더 제거 */
    background: transparent !important;
    display: flex !important;
    align-items: center !important;
    gap: 12px;
    line-height: 1.2 !important;
}
#page-wrapper h3.page-header > i {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 38px !important;
    height: 38px !important;
    border-radius: 10px !important;
    background: rgba(0, 61, 143, 0.10) !important;
    color: var(--primary) !important;
    font-size: 16px !important;
    flex-shrink: 0;
    margin-right: 6px !important;
}
/* 우측 검색/액션 영역 — float:right 가 flex 안에서 안 먹으므로 margin-left:auto 강제 */
#page-wrapper h3.page-header > div[style*="float: right"],
#page-wrapper h3.page-header > .float-end,
#page-wrapper h3.page-header > form {
    margin-left: auto !important;
    float: none !important;
    display: flex !important;
    align-items: center;
    gap: 8px;
}
#page-wrapper h3.page-header form .form-inline,
#page-wrapper h3.page-header form .pp-form-row {
    display: flex !important;
    align-items: center;
    gap: 8px;
}
#page-wrapper h3.page-header form .form-control {
    height: 36px !important;
    padding: 4px 12px !important;
}
#page-wrapper h3.page-header form .btn {
    height: 36px !important;
    padding: 0 14px !important;
}
/* 페이지 서브타이틀 (레거시 호환) */
#page-wrapper .page-subtitle,
#page-wrapper p.page-subtitle {
    margin: -8px 0 16px !important;
    padding: 0 24px 16px !important;
    font-size: 13px !important;
    color: var(--muted-foreground) !important;
    line-height: 1.5 !important;
    border: 0 !important;
}

/* ====================================================================== */
/* 공통 페이지 헤더 컴포넌트 (.pp-page-header) — 태그파일 page-header.tag    */
/* 왼쪽: 아이콘+타이틀+서브타이틀 / 오른쪽: 검색·액션 영역                   */
/* ====================================================================== */
.pp-page-header {
    padding: 12px 16px 8px !important;
    background: transparent !important;
    border: 0 !important;
    margin: 0 !important;
}
.pp-page-header-row {
    display: flex;
    align-items: center;        /* 좌측 타이틀 블록과 우측 액션 수직 중앙 정렬 */
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    min-height: 38px;
    margin-top: 0 !important;
}
.pp-page-header-left {
    display: flex;
    flex-direction: row;       /* 아이콘 + 텍스트영역(타이틀+서브타이틀) 가로 배치 */
    align-items: flex-start;
    gap: 14px;
    min-width: 0;
    flex: 1 1 auto;
}
.pp-page-title-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 8px;
    /* 페이지 헤더 아이콘 — primary 컬러 단색 */
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    font-size: 18px !important;
    box-shadow: 0 2px 6px rgba(0, 61, 143, 0.20) !important;
}
.pp-page-title-icon > i {
    color: var(--pp-white) !important;
}
.pp-page-title-content {       /* 타이틀 + 서브타이틀 동일 좌측 기준 수직 정렬 */
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.pp-page-title-text {
    margin: 0 !important;
    padding: 0 !important;
    font-size: 24px !important;
    font-weight: 600 !important;                   /* Signal logs — semibold */
    line-height: 1.25 !important;
    color: oklch(0.21 0.006 286) !important;       /* zinc-900 */
    letter-spacing: -0.01em !important;
}
.pp-page-subtitle {
    margin: 0 !important;
    padding: 0 !important;
    font-size: 14px !important;
    color: oklch(0.55 0.016 286) !important;       /* zinc-500 — Signal subtitle 톤 */
    line-height: 1.5 !important;
    font-weight: 400 !important;
}
.pp-page-header-right {
    display: flex;
    align-items: center;
    align-self: center;          /* 행 수직 중앙 */
    gap: 8px;
    flex-shrink: 0;
    flex-wrap: nowrap;           /* 우측 액션(검색/버튼)은 같은 행 유지 — 줄바꿈 금지 */
}
/* BS5 .input-group 기본 width:100% 가 헤더 우측에서 공간을 다 먹어
   인접 버튼이 다음 행으로 밀리는 문제 보정 — 헤더 안에서는 내용폭(auto)로. */
.pp-page-header-right .input-group {
    width: auto;
    flex: 0 0 auto;
    flex-wrap: nowrap;
}
/* 페이지 헤더 우측 버튼에 부드러운 box-shadow (Signal: shadow-sm) */
.pp-page-header-right .btn,
.pp-page-header-right .btn-group > .btn {
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.pp-page-header-right .btn:hover {
    box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.08) !important;
}
/* ============================================================
 * 표준: 페이지 헤더 우측 검색바·버튼바 (레이아웃 공통) — 항상 한 줄
 *   <pp:page-header> actions 안의 검색폼/툴바. 신규는 .pp-header-search 사용,
 *   레거시 .form-inline / 직속 <form> 도 동일 규칙으로 수렴.
 *   ※ !important 미사용 — 벤더(BS5)는 @layer(vendor) 하위라 normal 규칙으로 이긴다.
 * ============================================================ */
.pp-page-header-right > form,
.pp-page-header-right .pp-header-search,
.pp-page-header-right .form-inline {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;      /* 검색바·버튼은 같은 줄 유지(줄바꿈 금지) */
    gap: 8px;
    min-width: 0;
}
/* 헤더 우측 컨트롤 높이 통일 = 36px (인풋·셀렉트·addon·버튼 동일).
   input-group 은 .form-select / .input-group-text 도 쓰므로 함께 36px 로 맞춰 버튼과 정렬. */
.pp-page-header-right .form-control,
.pp-page-header-right .form-select,
.pp-page-header-right .input-group-text,
.pp-page-header-right .btn {
    height: 36px !important;
    font-size: 13px !important;
}
.pp-page-header-right .input-group-text { display: flex; align-items: center; }
.pp-page-header-right .form-control { padding: 0 12px !important; }
.pp-page-header-right .btn { padding: 0 14px !important; }
/* 헤더 우측 form-control(특히 select)은 content 폭 — 기본 form-control width:100% 가
   같은 줄 버튼을 다음 행으로 밀어내는 것 방지(connect/status 등). 특이성으로 BS5 .form-control 이김. */
.pp-page-header-right input.form-control,
.pp-page-header-right select {
    width: auto;
    max-width: 360px;
}
/* 데스크톱: 헤더 행 줄바꿈 금지 → 검색바가 타이틀 아래로 안 내려간다.
   타이틀 블록(.pp-page-header-left)은 min-width:0/flex 라 부족하면 말줄임으로 축소되어 검색바 자리 확보. */
@media (min-width: 768px) {
    .pp-page-header-row { flex-wrap: nowrap; }
}
/* 좁은 화면: 검색바는 줄바꿈 대신 가로 스크롤(컨트롤이 잘게 쪼개지지 않게). */
@media (max-width: 767.98px) {
    .pp-page-header-right { max-width: 100%; overflow-x: auto; }
}

@media (max-width: 575.98px) {
    .pp-page-header {
        padding: 18px 16px 12px !important;
    }
    .pp-page-header-row {
        align-items: flex-start;
        gap: 12px;
    }
    .pp-page-header-left {
        flex: 1 1 100%;
        max-width: 100%;
    }
    .pp-page-title-text {
        font-size: 20px !important;
    }
    .pp-page-header-right {
        flex: 1 1 100%;
        max-width: 100%;
        min-width: 0;
        justify-content: flex-start;
        flex-wrap: wrap;
    }
    .pp-page-header-right .form-inline {
        display: flex !important;
        width: 100%;
        max-width: 100%;
        min-width: 0;
        flex-wrap: wrap;
    }
    .pp-page-header-right .form-inline > * {
        min-width: 0;
    }
    .pp-page-header-right input.form-control,
    .pp-page-header-right select {
        width: auto;
        max-width: 100%;
        min-width: 0;
        flex: 1 1 160px;
    }
    .pp-page-header-right .btn-group {
        max-width: 100%;
        flex: 0 1 auto;
    }
}

/* ====================================================================== */
/* 버튼 그룹 (.btn-group) — 인접 버튼 borderless 연결                       */
/* ====================================================================== */
.btn-group {
    display: inline-flex !important;
    align-items: center;
    border-radius: 6px !important;
}
/* 분절 버튼 모서리 클립(overflow) + 인접버튼 호버 z-index 격리(isolation) — 단, 드롭다운(.dropdown-menu)을
   품은 .btn-group 은 메뉴가 그룹 박스 밖으로 펼쳐지고(overflow 시 잘림) 별도 스태킹 컨텍스트(isolation)에
   갇히면 패널 뒤로 깔리므로, 두 속성 모두 클리핑/격리 대상에서 제외해야 BS5 드롭다운이 정상 표시된다. */
.btn-group:not(:has(.dropdown-menu)) {
    overflow: hidden;
    isolation: isolate;
}
.btn-group > .btn {
    border-radius: 0 !important;
    margin: 0 !important;
    position: relative;
}
.btn-group > .btn:first-child {
    border-top-left-radius: 6px !important;
    border-bottom-left-radius: 6px !important;
}
.btn-group > .btn:last-child {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
}
.btn-group > .btn + .btn {
    margin-left: -1px !important;
}
.btn-group > .btn:hover,
.btn-group > .btn:focus {
    z-index: 2;
}

#page-wrapper { padding: 0 !important; }
#page-wrapper > .container-fluid,
#page-wrapper > .row:not(:first-child) {
    padding: 0px 0px !important;
    margin-left: 16px !important;
    margin-right: 16px !important;
}
#page-wrapper > .row:first-child {
    padding: 0 !important;
    margin: 0 !important;
}
/* 마지막 row 는 하단 padding 24px 추가 — viewport 끝과 충돌 방지 */
#page-wrapper > .row:last-child {
    padding-bottom: 24px !important;
}
/* :only-child col padding 0 룰 제거 — Bootstrap 표준 (.row -10 마진 + col +10 패딩 짝) 보존 */
/* 멀티 col row 의 강제 gutter 룰 제거 — Bootstrap 기본값 또는 페이지 자체 룰에 위임 */
/* 그리드 col 간격(가로) 을 16px 로 통일 — stacked card 세로 간격(16px)과 동일 리듬.
   BS5 기본 --bs-gutter-x(1.5rem=24px) 대신 1rem. */
#page-wrapper .row {
    --bs-gutter-x: 1rem !important;
}
/* ───────────────────────────────────────────────────────────────────────
   .pp-page-content — pp:page-header 아래 본문 영역 (태그파일 pp:page-content).
   좌우 16px inset 으로 pp-page-header(좌우 16px)와 정확히 같은 수직선에 정렬한다.
   내부 .row 는 BS5 표준 음수 거터마진(-gutter/2)을 써서
   col 콘텐츠 좌측선 = 16 - gutter/2 + gutter/2 = 16px → 헤더와 일치.
   (row 직속에 row 를 두는 것은 안티패턴 — pp:row 안에는 pp:col 만.)
   ─────────────────────────────────────────────────────────────────────── */
.pp-page-content {
    padding: 0 16px 16px !important;
}
/* pp-page-content 안의 모든 .row(직속 + 카드/칼럼 내부 중첩)에 BS5 표준 음수 거터마진 복원.
   (pp-02-layout-shell 의 `body .row{margin:0}` BS3 잔재가 음수마진을 죽여 중첩 row 의 col 콘텐츠가
   6px 안쪽으로 밀려 형제 콘텐츠와 좌측선이 어긋나는 문제 — 컨테이너 패딩이 음수마진을 흡수하므로 표준 복원이 정답.) */
#page-wrapper .pp-page-content .row:not(.dt-row):not([class*="dataTable"]) {
    --bs-gutter-x: 1rem !important;
    margin-left: calc(var(--bs-gutter-x) * -0.5) !important;
    margin-right: calc(var(--bs-gutter-x) * -0.5) !important;
}
.pp-page-content > .row + .row {
    margin-top: 0 !important;
}

/* 패널 자체 vertical margin 표준 (16px) — row 끼리 간격 + row 내 여러 stacked panel 간격 */
#page-wrapper .card,
#page-wrapper .card.card {
    margin-bottom: 12px !important;
}
/* 패널(card) 좌우 패딩 전역 통일 — header/body/footer 모두 20px 로 정렬.
   (기존: header 20 / body 22 / footer 16 제각각 → 헤더·본문·푸터 좌측선 어긋남 해소) */
#page-wrapper .card > .card-header,
#page-wrapper .card > .card-body,
#page-wrapper .card > .card-footer {
    padding-left: 16px !important;
    padding-right: 16px !important;
}
/* row 사이 vertical 간격 표준 — row 자체에 margin-bottom 적용 */
#page-wrapper > .row + .row {
    margin-top: 0 !important;
}

/* 패널 헤딩은 페이지 헤더 스타일 적용 안 함 (충돌 방지) */
#page-wrapper .card .card-header,
#page-wrapper .card .card-header h3 {
    border-bottom: 0 !important;                           /* 헤더 하단 보더 제거 (전역) */
    background: transparent !important;
    padding: 12px 16px 8px !important;
    font-size: 14px !important;
    font-weight: 600 !important;
    color: var(--card-foreground) !important;
    display: flex;
    align-items: center;
    gap: 8px;
    border-radius: 0 !important;
}

/* 도메인 검색 버튼 */

/* 우측 상단 아이콘 버튼 — Signal 톤 (round 36, hover bg) */
#nav-toolbar > li { padding: 0 !important; margin: 0 4px !important; }
#nav-toolbar > li > a {
    width: 36px; height: 36px;
    display: inline-flex !important;
    align-items: center; justify-content: center;
    border-radius: 8px !important;
    color: var(--muted-foreground) !important;
    border: 0 !important;
    padding: 0 !important;
    transition: background .15s ease, color .15s ease;
}
#nav-toolbar > li > a:hover {
    background: var(--secondary) !important;
    color: var(--foreground) !important;
}
#nav-toolbar > li > a > i { font-size: 16px !important; }
#nav-toolbar .badge {
    border: none !important;
    background: var(--destructive) !important;
    color: var(--destructive-foreground) !important;
    border-radius: 10px !important;
    font-size: 9px !important;
    padding: 1px 6px !important;
    position: absolute;
    top: 4px; right: 4px;
}

/* 메인 콘텐츠 사이드바 옆으로 밀기 — wrapper 만 적용 (page-wrapper 는 wrapper 내부) */
#wrapper {
    margin-left: var(--pp-sidebar-w) !important;
    width: calc(100% - var(--pp-sidebar-w)) !important;
    max-width: calc(100% - var(--pp-sidebar-w)) !important;
    transition: margin-left .25s ease, width .25s ease;
}
#wrapper #page-wrapper {
    margin-left: 0 !important;
    width: 100% !important;
}

/* nav="false" 풀스크린/새창 페이지 (pp:html nav 속성) — 네비 없으니 사이드바 클리어 마진 제거.
   #wrapper 의 좌측 팬텀 빈칸(=var(--pp-sidebar-w)) 을 0 으로 되돌려 콘텐츠가 화면 전체 폭을 쓴다. */
#wrapper.pp-nonav {
    margin-left: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
}

/* ====================================================================== */
/* 사이드바 토글 (접힘 = 아이콘만) — html.pp-sidebar-collapsed body                */
/* width 260 → 64 으로 축소, 텍스트 숨김, 아이콘만 표시. Signal logs 패턴.    */
/* (--pp-sidebar-w-collapsed 토큰은 pp-01-tokens-base.css 에서 정의됨)       */
/* ====================================================================== */
#navigation, #brand.pp-nav-header {
    transition: width .25s ease, transform .25s ease;
}
html.pp-sidebar-collapsed body #navigation {
    width: var(--pp-sidebar-w-collapsed) !important;
}
html.pp-sidebar-collapsed body #brand.pp-nav-header {
    width: var(--pp-sidebar-w-collapsed) !important;
}
html.pp-sidebar-collapsed body #brand .navbar-brand.pp-brand-link {
    padding: 0 !important;
    justify-content: center;
}
/* 카테고리 섹션 헤더 (Overview/Connectivity 등) 숨김 */
html.pp-sidebar-collapsed body .pp-nav-section-header { display: none !important; }
/* 메뉴 아이템 텍스트/배지 숨김 — 아이콘만 표시 */
html.pp-sidebar-collapsed body #side-menu > li > a > span,
html.pp-sidebar-collapsed body .pp-nav-section-items a > span:not(.pp-icon),
html.pp-sidebar-collapsed body .pp-nav-section-items a > .badge {
    display: none !important;
}
html.pp-sidebar-collapsed body #side-menu > li > a,
html.pp-sidebar-collapsed body .pp-nav-section-items a {
    justify-content: center !important;
    padding: 12px 0 !important;
    gap: 0 !important;
}
html.pp-sidebar-collapsed body #side-menu > li > a > i,
html.pp-sidebar-collapsed body .pp-nav-section-items a > i {
    margin: 0 !important;
    width: 28px !important;
    font-size: 22px !important;
    line-height: 1 !important;
}
html.pp-sidebar-collapsed body .sidebar-collapse {
    padding: 12px 8px !important;
}
html.pp-sidebar-collapsed body #current_ntp_time { display: none !important; }
html.pp-sidebar-collapsed body #nav-performance-box { display: none !important; }

/* 메인 콘텐츠 좌측 마진 / 상단바 좌측 패딩을 새 폭에 맞춰 축소 */
html.pp-sidebar-collapsed body #wrapper {
    margin-left: var(--pp-sidebar-w-collapsed) !important;
    width: calc(100% - var(--pp-sidebar-w-collapsed)) !important;
    max-width: calc(100% - var(--pp-sidebar-w-collapsed)) !important;
}

/* collapsed 사이드바 전용 툴팁 — JS 가 body 에 #pp-nav-tip div 부착 */
.pp-nav-tip {
    display: none;
    position: fixed;
    transform: translateY(-50%);
    background: #1a1a1a !important;
    color: var(--pp-white) !important;
    padding: 6px 12px !important;
    border-radius: 6px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    white-space: nowrap !important;
    pointer-events: none;
    z-index: 10000;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.32) !important;
    letter-spacing: 0.01em !important;
}

/* 사이드바 토글 — 상단 네비 좌측 배치 (Signal devops 스타일) */
#nav-toggle {
    display: inline-flex !important;
    align-items: center;
    height: var(--pp-topbar-h, 64px);
    float: none !important;
    margin-left: -5px !important;
}
#nav-toggle-button {
    cursor: pointer;
    width: 36px; height: 36px;
    display: inline-flex !important; align-items: center; justify-content: center;
    border-radius: 6px !important;
    color: var(--foreground) !important;
    background: transparent !important;
    transition: background .15s ease, color .15s ease;
    margin: 0 8px !important;
    font-size: 16px !important;
}
#nav-toggle-button:hover {
    background: var(--secondary) !important;
    color: var(--primary) !important;
}
/* collapsed 상태일 때 햄버거 아이콘 회전 */
html.pp-sidebar-collapsed body #nav-toggle-button > i {
    transform: rotate(180deg);
    transition: transform .2s ease;
}



/* ============================================================
 * 상단 네비 — 도메인 통합 검색 (EQL 검색 대체)
 * sites / assets / tags / opcs / alarms / edges / events 통합 검색
 * 네비 배경: 흰색/라이트 톤 — 옅은 회색 배경 + 1px 보더
 * ============================================================ */
#nav-domain-search {
    padding: 14px 0 14px 8px !important;
    flex: 1 1 auto !important;
    max-width: 720px !important;
    height: var(--pp-topbar-h);
    display: inline-flex !important;
    align-items: center !important;
}

#nav-domain-search .nav-domain-search-input {
    display: inline-flex !important;
    align-items: center !important;
    line-height: 1 !important;
    gap: 10px;
    height: 40px;
    padding: 0 14px !important;
    background: #fff !important;
    border: 1px solid var(--pp-text-soft) !important;
    border-radius: 8px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 13px !important;
    font-weight: 400 !important;
    text-decoration: none !important;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
    width: 100%;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05) !important;
}

#nav-domain-search .nav-domain-search-input:hover,
#nav-domain-search .nav-domain-search-input:focus {
    background: var(--pp-white) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--foreground, #111827) !important;
    box-shadow: 0 0 0 3px rgba(0, 61, 143, 0.10) !important;
}

#nav-domain-search .nav-domain-search-input > i,
#nav-domain-search .nav-domain-search-label,
#nav-domain-search .nav-domain-search-hint,
#nav-domain-search .nav-domain-search-kbd {
    display: inline-flex !important;
    align-items: center !important;
    line-height: 1 !important;
}

#nav-domain-search .nav-domain-search-input > i {
    font-size: 14px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    justify-content: center;
    flex-shrink: 0;
    height: 1em;
    line-height: 1 !important;
}

.nav-domain-search-label {
    font-weight: 600 !important;
    color: var(--foreground, #111827) !important;
    flex-shrink: 0;
}

.nav-domain-search-hint {
    flex: 1 1 auto;
    color: var(--subtle-foreground, #9ca3af) !important;
    font-size: 12px !important;
    overflow: hidden;
    white-space: nowrap !important;
    text-overflow: ellipsis;
}

.nav-domain-search-kbd {
    flex-shrink: 0;
    font-size: 10px !important;
    font-weight: 600 !important;
    letter-spacing: 0.3px !important;
    height: 20px;
    line-height: 1 !important;
    padding: 2px 7px !important;
    border-radius: 4px !important;
    background: var(--pp-white) !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    border: 1px solid var(--pp-border) !important;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04) !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
}

/* === pp-12-page-themes.css === */
/* ============================================================
 * 상단 네비 우측 툴바 — 아이콘들 일정 간격, 정렬 깔끔하게
 * (#nav-toolbar > li 들 - WS / 알람 / 사용자 메뉴)
 * ============================================================ */
#nav-toolbar.navbar-top-links.pp-nav-right {
    gap: 4px !important;
    padding-right: 0 !important;
}

#nav-toolbar > li.dropdown {
    padding: 0 !important;
    margin: 0 !important;
    height: var(--pp-topbar-h);
    display: inline-flex !important;
    align-items: center !important;
}

#nav-toolbar > li.dropdown > a.dropdown-toggle {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 4px;
    height: 36px;
    padding: 0 10px !important;
    border-radius: 8px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    background: transparent !important;
    transition: background 0.15s, color 0.15s;
    text-decoration: none !important;
    font-size: 13px !important;
    line-height: 1 !important;
}

#nav-toolbar > li.dropdown > a.dropdown-toggle:hover,
#nav-toolbar > li.dropdown.open > a.dropdown-toggle {
    background: var(--muted, #f3f4f6) !important;
    color: var(--foreground, #111827) !important;
}

#nav-toolbar > li.dropdown > a.dropdown-toggle > i {
    font-size: 16px !important;
    line-height: 1 !important;
}

/* 알람 카운트 뱃지 (상단 nav 우측) */
#alarm_count_top {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    min-width: 18px;
    height: 18px;
    padding: 0 6px !important;
    background: var(--destructive, var(--pp-tone-danger-bg)) !important;
    color: var(--pp-white) !important;
    border: 0 !important;
    border-radius: 10px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1 !important;
    margin-left: 4px !important;
}
/* ====================================================================== */
/* 카드 / 패널 — Signal Dashboard 정확 스펙: rounded-xl + border + shadow-sm */
/* (rounded-xl = 12px / shadow-sm = 0 1px 2px 0 rgb(0 0 0 / 0.05))         */
/* ====================================================================== */
.card, .card, .card,
.card.card, .card.card-info, .card.card-success,
.card.card-warning, .card.card-danger {
    background: var(--card) !important;
    color: var(--card-foreground) !important;
    border: 1px solid var(--border) !important;
    border-radius: 12px !important;                              /* rounded-xl */
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;       /* shadow-sm */
    margin-bottom: 16px !important;
    transition: box-shadow .2s ease;
}
.card:hover, .card:hover, .card:hover {
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.06), 0 2px 4px -2px rgba(0, 0, 0, 0.04) !important;
}
.card-header {
    background: transparent !important;
    border-bottom: 0 !important;                          /* 그라데이션 라인을 ::after 로 대체 */
    padding: 12px 16px !important;
    font-size: 16px !important;
    font-weight: 600 !important;
    color: var(--card-foreground) !important;
    border-top-left-radius: 12px !important;
    border-top-right-radius: 12px !important;
    display: flex !important;
    align-items: center !important;       /* 헤더 영역 모든 자식 수직 중앙 */
    gap: 10px;
    min-height: 44px;                     /* 헤더 최소 높이 — 버튼 정렬 안정 */
    position: relative;
}
/* 패널 헤더 하단 그라데이션 보더 — 좌측 살짝 진함 → 우측 페이드 (옅게) */
.card-header::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    background: linear-gradient(
        to right,
        var(--border) 0%,
        var(--border) 30%,
        transparent 100%
    ) !important;
    opacity: 0.45 !important;
    pointer-events: none;
}

/* 입력/수정 폼 페이지 — 패널 헤더 하단 보더 제거 (사용자 요청) */
body.pp-form-page #page-wrapper .card .card-header,
body.pp-form-page .card-header {
    border-bottom: 0 !important;
}

/* ====================================================================== */
/* 패널 테마 — 통일된 헤더 그라데이션 + 흰색 텍스트 패턴                  */
/* primary / dark / second / info / warning / danger / success / impo     */
/* ====================================================================== */
/* 공통: 컬러 헤더는 ::after 그라데이션 라인 숨김 + 흰 텍스트 */
body #page-wrapper .card.card-primary > .card-header::after,
body #page-wrapper .card.card-dark > .card-header::after,
body #page-wrapper .card.card-second > .card-header::after,
body #page-wrapper .card.card-info > .card-header::after,
body #page-wrapper .card.card-warning > .card-header::after,
body #page-wrapper .card.card-danger > .card-header::after,
body #page-wrapper .card.card-success > .card-header::after,
body #page-wrapper .card.card-impo > .card-header::after {
    display: none;
}
body #page-wrapper .card.card-primary > .card-header,
body #page-wrapper .card.card-primary > .card-header *,
body #page-wrapper .card.card-dark    > .card-header,
body #page-wrapper .card.card-dark    > .card-header *,
body #page-wrapper .card.card-second  > .card-header,
body #page-wrapper .card.card-second  > .card-header *,
body #page-wrapper .card.card-info    > .card-header,
body #page-wrapper .card.card-info    > .card-header *,
body #page-wrapper .card.card-warning > .card-header,
body #page-wrapper .card.card-warning > .card-header *,
body #page-wrapper .card.card-danger  > .card-header,
body #page-wrapper .card.card-danger  > .card-header *,
body #page-wrapper .card.card-success > .card-header,
body #page-wrapper .card.card-success > .card-header *,
body #page-wrapper .card.card-impo    > .card-header,
body #page-wrapper .card.card-impo    > .card-header * {
    color: var(--pp-white) !important;
}
body #page-wrapper .card.card-primary > .card-header .card-head-sub,
body #page-wrapper .card.card-dark    > .card-header .card-head-sub,
body #page-wrapper .card.card-second  > .card-header .card-head-sub,
body #page-wrapper .card.card-info    > .card-header .card-head-sub,
body #page-wrapper .card.card-warning > .card-header .card-head-sub,
body #page-wrapper .card.card-danger  > .card-header .card-head-sub,
body #page-wrapper .card.card-success > .card-header .card-head-sub,
body #page-wrapper .card.card-impo    > .card-header .card-head-sub {
    color: rgba(255, 255, 255, 0.78) !important;
}

/* default — 흰 배경 (기본) */
body #page-wrapper .card.card {
    border-color: var(--border) !important;
    background: var(--pp-white) !important;
}
body #page-wrapper .card.card > .card-header {
    background: var(--pp-white) !important;
    color: oklch(0.21 0.006 286) !important;
    border-bottom: 0 !important;
}
body #page-wrapper .card.card > .card-header > i,
body #page-wrapper .card.card > .card-header .card-head-title,
body #page-wrapper .card.card > .card-header .card-head-title > i {
    color: oklch(0.21 0.006 286) !important;
}
body #page-wrapper .card.card > .card-header .card-head-sub {
    color: var(--muted-foreground) !important;
}

/* primary — 메인 navy */
body #page-wrapper .card.card-primary {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
}
body #page-wrapper .card.card-primary > .card-header {
    background: linear-gradient(135deg, var(--primary, var(--pp-primary-strong)) 0%, oklch(28% 0.12 260) 100%) !important;
    border-bottom: 0 !important;
    color: var(--pp-white) !important;
}

/* dark — zinc-900 */
body #page-wrapper .card.card-dark {
    border-color: oklch(0.21 0.006 286) !important;
}
body #page-wrapper .card.card-dark > .card-header {
    background: linear-gradient(135deg, oklch(0.21 0.006 286) 0%, oklch(0.14 0.006 286) 100%) !important;
    border-bottom: 0 !important;
}

/* second — slate (보조 정보) */
body #page-wrapper .card.card-second {
    border-color: oklch(0.45 0.02 260) !important;
}
body #page-wrapper .card.card-second > .card-header {
    background: linear-gradient(135deg, oklch(0.45 0.02 260) 0%, oklch(0.38 0.02 260) 100%) !important;
    border-bottom: 0 !important;
}

/* info — sky/cyan */
body #page-wrapper .card.card-info {
    border-color: oklch(0.62 0.13 230) !important;
}
body #page-wrapper .card.card-info > .card-header {
    background: linear-gradient(135deg, oklch(0.62 0.13 230) 0%, oklch(0.50 0.13 230) 100%) !important;
    border-bottom: 0 !important;
}

/* warning — amber */
body #page-wrapper .card.card-warning {
    border-color: oklch(0.70 0.15 70) !important;
}
body #page-wrapper .card.card-warning > .card-header {
    background: linear-gradient(135deg, oklch(0.70 0.15 70) 0%, oklch(0.58 0.16 60) 100%) !important;
    border-bottom: 0 !important;
}

/* danger — red */
body #page-wrapper .card.card-danger {
    border-color: oklch(0.62 0.20 27) !important;
}
body #page-wrapper .card.card-danger > .card-header {
    background: linear-gradient(135deg, oklch(0.62 0.20 27) 0%, oklch(0.50 0.20 27) 100%) !important;
    border-bottom: 0 !important;
}

/* success — emerald */
body #page-wrapper .card.card-success {
    border-color: oklch(0.55 0.16 155) !important;
}
body #page-wrapper .card.card-success > .card-header {
    background: linear-gradient(135deg, oklch(0.55 0.16 155) 0%, oklch(0.45 0.16 155) 100%) !important;
    border-bottom: 0 !important;
}

/* impo — 강조 (다크 그레이) */
body #page-wrapper .card.card-impo {
    border-color: oklch(0.35 0.01 260) !important;
}
body #page-wrapper .card.card-impo > .card-header {
    background: linear-gradient(135deg, oklch(0.35 0.01 260) 0%, oklch(0.25 0.01 260) 100%) !important;
    border-bottom: 0 !important;
}

/* ─── 카드 헤더 flex 정렬 — 타이틀 블록(좌) + 액션 버튼(우) 일관 배치 ───
   float-end 유무와 무관하게 card-head-actions 를 항상 우측으로 통일(버튼 위치 오락가락 해소).
   pp:card 는 float 없이, 레거시 raw 카드는 float-end 로 마크업돼 있어도 둘 다 우측 정렬된다. */
#page-wrapper .card > .card-header {
    display: flex !important;
    align-items: center !important;
    gap: 8px;
}
#page-wrapper .card > .card-header > .card-head-actions {
    margin-left: auto !important;
    float: none !important;
}

/* ─── 패널 헤더 타이틀 블록 (제목 + 서브타이틀) — Signal Dashboard 패턴 ─── */
.card-head-block {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    gap: 2px;
}
.card-head-block .card-head-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 15px !important;
    font-weight: 600 !important;
    color: var(--card-foreground) !important;
    line-height: 1.3 !important;
}
.card-head-block .card-head-title i {
    font-size: 15px !important;
    color: var(--card-foreground) !important;
}
.card-head-sub,
.card-head-block .card-head-sub {
    font-size: 12px !important;
    font-weight: 400 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    line-height: 1.4 !important;
    letter-spacing: 0 !important;
    padding-left: 0 !important;        /* 아이콘 좌측 라인과 정렬 */
}
/* KPI 카드는 내부 row/col-xs 그리드 레이아웃 — flex 적용 제외 */
.kpi-card .card-header,
.kpi-card .card-footer,
.analysis-kpi .card-header,
.analysis-kpi .card-footer {
    display: block !important;
    padding: 10px 15px !important;
    min-height: 0 !important;
    border-radius: 0 !important;
    border-bottom: 1px solid var(--border) !important;
}
.analysis-kpi .card-footer,
.kpi-card .card-footer {
    border-bottom: 0 !important;
    border-top: 0 !important;
}
/* KPI 카드 라벨/숫자 — Korean 텍스트 wrapping 방지 */
.kpi-card .card-footer * {
    white-space: nowrap !important;
    word-break: keep-all !important;
}
.kpi-card .card-footer > div {
    overflow: hidden !important;
}
/* KPI 라벨 폰트 사이즈 (좁은 col 안에서 fits) */
.kpi-card .card-footer .announcement-bottom > div > div:first-child,
.kpi-card .card-footer > div > div:first-child {
    font-size: 13px !important;
}
.card-header > * {
    align-self: center !important;
}
.kpi-card .card-header > *,
.kpi-card .card-footer > *,
.analysis-kpi .card-header > *,
.analysis-kpi .card-footer > * {
    align-self: auto !important;
}
/* 패널 헤더 직접 자식 텍스트 — 한글 글자 단위 wrapping 방지 */
.card-header {
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: keep-all;
}
/* ============================================================
 * 패널 헤더 아이콘 위치 — HTML 순서와 무관하게 항상 타이틀 앞 (왼쪽)
 *  1) card-head-title 을 inline-flex 강제 (없는 경우 대비)
 *  2) i 자식에 order -99 → 모든 형제보다 먼저 렌더 (DOM 순서 무관)
 *  3) panel-heading 의 직접 자식 i (block 직접 패턴) 도 동일 처리
 *  card-head-actions / pull-right 안의 i 는 우측 액션 그룹 자식이라 영향 없음.
 * ============================================================ */
body .card-head-title {
    display: inline-flex !important;
    flex-direction: row !important;
    align-items: center !important;
    gap: 8px;
}
body .card-header > i,
body .card-head-title > i,
body .card-head-block .card-head-title > i,
body .card-header > .card-head-title > i {
    order: -99 !important;
}
/* card-head-meta — 타이틀 텍스트 뒤로 (가장 마지막 위치) */
body .card-head-title > .card-head-meta,
body .card-head-block .card-head-title > .card-head-meta,
body .card-header > .card-head-title > .card-head-meta {
    order: 99 !important;
}
.card-header > i:first-child + *,
.card-header {
    word-break: keep-all !important;
}
.card-header .btn,
.card-header .btn-group,
.card-header .btn-sm,
.card-header > .card-head-actions > .btn,
.card-header > .float-end > .btn {
    margin: 0 !important;                 /* 버튼 자체 마진 제거 → flex align-items 가 중앙 정렬 */
    align-self: center !important;
}
/* 패널 헤더 직접 자식 아이콘만 — 텍스트 색 (단조). 버튼 안 아이콘은 제외. */
.card-header > i:first-child,
#page-wrapper .card-header > i:first-child {
    color: var(--card-foreground) !important;       /* 텍스트와 동일 색 (단조) */
    font-size: 16px !important;                      /* 헤더 타이틀과 동일 */
}
/* 버튼 안 아이콘은 버튼 색 따라감 (btn-primary/danger 면 흰색) */
.btn-primary > i, .btn-danger > i, .btn-success > i, .btn-warning > i,
.btn-primary i.fa-light, .btn-primary i.fa-light, .btn-primary i.fa-light,
.btn-danger i.fa-light, .btn-danger i.fa-light, .btn-danger i.fa-light,
.btn-success i.fa-light, .btn-success i.fa-light, .btn-success i.fa-light {
    color: inherit !important;       /* 버튼 색 상속 (white on colored bg) */
}
.btn-primary, .btn-danger, .btn-success {
    color: var(--primary-foreground) !important;
}
.btn-danger { color: var(--destructive-foreground) !important; }
.btn-success { color: var(--success-foreground) !important; }
/* 패널 헤더 우측 액션 버튼 (새로고침/필터/추가 등) — 자동으로 우측 끝 정렬 */
.card-header > .card-head-actions,
.card-header > .float-end {
    margin-left: auto !important;
    float: none !important;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;                         /* 액션 영역은 줄어들지 않음 */
}
/* 패널 헤더 타이틀 — flex item 줄바꿈 방지 + 헤더 폰트 톤 일치 (size/weight 상속) */
.card-header > .card-head-title {
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    flex: 1 1 auto;
    font-size: inherit !important;
    font-weight: inherit !important;
    color: inherit !important;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.card-header > .card-head-title > i {
    color: inherit !important;
    font-size: inherit !important;
}
.card-header > .card-head-actions > .btn,
.card-header > .card-head-actions > .btn-group > .btn,
.card-header > .float-end > .btn,
.card-header > .float-end > .btn-group > .btn,
.card-header > .float-end > .btn-group > a.btn {
    height: 28px !important;
    line-height: 26px !important;
    padding: 0 10px !important;
    font-size: 12px !important;
    box-sizing: border-box !important;
}
/* btn-group 외곽만 라운드, 내부 버튼은 0 — 깔끔히 붙음 */
.card-header > .card-head-actions > .btn-group,
.card-header > .float-end > .btn-group {
    display: inline-flex;
    align-items: center;
}
.card-header > .card-head-actions > .btn-group > .btn,
.card-header > .float-end > .btn-group > .btn {
    border-radius: 0 !important;
    margin-left: -1px !important;
}
.card-header > .card-head-actions > .btn-group > .btn:first-child,
.card-header > .float-end > .btn-group > .btn:first-child {
    border-top-left-radius: 6px !important;
    border-bottom-left-radius: 6px !important;
    margin-left: 0 !important;
}
.card-header > .card-head-actions > .btn-group > .btn:last-child,
.card-header > .float-end > .btn-group > .btn:last-child {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
}
/* 버튼이 단독(btn-group 미사용)일 때는 6px 라운드 유지 */
.card-header > .card-head-actions > .btn,
.card-header > .float-end > .btn {
    border-radius: 6px !important;
}
.card-body, .card-body { padding: 4px 16px 16px !important; }   /* 카드바디: 상단 4, 좌우/하단 16 (사용자 요청, 단일 shorthand) */

/* 패널 안에 테이블이 있을 때는 좌우 마진 0 — 보더에 딱 붙임 */
#page-wrapper .card .card-body:has(> .table-responsive),
#page-wrapper .card .card-body:has(> .dataTables_wrapper),
#page-wrapper .card .card-body:has(.dataTables_wrapper),
#page-wrapper .card .card-body:has(> table.dataTable),
#page-wrapper .card .card-body:has(> table.table) {
    padding: 0 !important;
}
.card .card-body > .table-responsive,
.card .card-body > table.dataTable,
.card .card-body > table.table {
    margin: 0 !important;
    border: 0 !important;
    padding: 0 !important;
    border-radius: 0 !important;
}
.card .card-body > .table-responsive {
    max-width: 100%;
    overflow-x: auto !important;
}
/* equipment 대시보드 우측 — table-responsive 가 .equipment-history-view 래퍼 안에 있어
 * card-body 직속이 아니므로 위 좌우 풀블리드 룰이 적용되지 않는다.
 * 래퍼를 display:contents 로 박스에서 제거해 내부 table-responsive/dataTables_wrapper 가
 * card-body 의 직속처럼 취급되도록 한다 → 표가 카드 가장자리에 딱 붙는다(좌우 풀블리드). */
.card .card-body > .equipment-history-view {
    display: contents;
}
/* dataTables 의 table-responsive / table 컨테이너 — 패널 헤더 거의 붙도록 위로 (-37px 누적) */
.card .card-body .dataTables_wrapper .table-responsive,
.card .card-body .dataTables_wrapper > table.dataTable {
    margin-top: -37px !important;
}
/* 패널 헤더와 테이블 사이 여백 추가 축소 — panel-body 위쪽 패딩 줄임 */
#page-wrapper .card .card-body:has(> .table-responsive),
#page-wrapper .card .card-body:has(> .dataTables_wrapper),
#page-wrapper .card .card-body:has(.dataTables_wrapper),
#page-wrapper .card .card-body:has(> table.dataTable),
#page-wrapper .card .card-body:has(> table.table) {
    padding-top: 0 !important;
}
/* 테이블 첫/마지막 컬럼은 패널 보더에 닿지 않도록 살짝 들여쓰기 */
.card .card-body table.table > thead > tr > th:first-child,
.card .card-body table.table > tbody > tr > td:first-child {
    padding-left: 22px !important;
}
.card .card-body table.table > thead > tr > th:last-child,
.card .card-body table.table > tbody > tr > td:last-child {
    padding-right: 22px !important;
}
/* 테이블 위/아래 dataTables 컨트롤 row — 컨트롤 row 만 패딩, 테이블 row 는 패딩 0 */
.dataTables_wrapper { padding: 0 !important; margin: 0 !important; }
/* BS5 .row 음수 마진(-gutter/2)이 flush card-body 에서 카드 밖으로 삐져나가
   하단 가로 스크롤을 유발 → 컨트롤 row 음수 마진 제거(테이블 flush 유지).
   #page-wrapper prefix 로 pp-11 의 `#page-wrapper .pp-page-content .row:not(...)`
   (특이도 1,4,0) 음수마진 복원 규칙을 이긴다 (여긴 1,5,0). */
#page-wrapper .card .card-body .dataTables_wrapper > .row {
    margin-left: 0 !important;
    margin-right: 0 !important;
}
/* 첫 row (length/filter) 와 마지막 row (info/paginate) 는 별도 패딩 — 아래 규칙으로 부여 */
.dataTables_wrapper > .row > [class*="col-"],
.card .card-body .dataTables_wrapper > .row > [class*="col-"] {
    padding: 0 !important;
    line-height: 1.4 !important;
    min-height: 32px;
    display: flex;
    align-items: center;
}
.card .card-body .dataTables_wrapper .dataTables_length,
.card .card-body .dataTables_wrapper .dataTables_filter,
.card .card-body .dataTables_wrapper .dataTables_info,
.card .card-body .dataTables_wrapper .dataTables_paginate {
    min-height: 32px;
    display: flex;
    align-items: center;
    width: 100%;
}
/* 상단 페이지행수/필터링 row 는 숨김 (사용자 요청) */
.card .card-body .dataTables_wrapper > .row:first-child,
.dataTables_wrapper > .row:first-child {
    display: none !important;
}
.card .card-body .dataTables_wrapper .dataTables_paginate { justify-content: flex-end; }
.card .card-body .dataTables_wrapper .dataTables_filter { justify-content: flex-end; }
/* /index 의 dataTable 패널 전용 — 패널 바디 패딩 5px (slim) */
.card-body-datatable { padding: 5px !important; }
/* dataTables_length / _filter 인라인 폼 정렬 */
.dataTables_wrapper .dataTables_length label,
.dataTables_wrapper .dataTables_filter label {
    margin: 0 !important;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px !important;
    color: var(--muted-foreground) !important;
    font-weight: 500 !important;
}
.card-footer {
    background: transparent !important;
    border-top: 1px solid var(--border) !important;
    padding: 12px 16px !important;
    border-bottom-left-radius: 12px !important;
    border-bottom-right-radius: 12px !important;
}

/* edge/view 좌측 패널 (col-lg-3) — 헤더 하단 보더 제거 (전역 정책 일치) */
#page-wrapper .col-lg-3 .card.card > .card-header,
#page-wrapper .col-lg-3 .card > .card-header {
    border-bottom: 0 !important;
    margin-bottom: 4px !important;
    gap: 6px;
    flex-wrap: wrap;                                  /* 액션 영역 잘리지 않도록 wrap */
    min-height: auto !important;
}

/* === pp-20-panels.css === */
/* 좁은 col 안 card-head-actions 작은 패딩 */
#page-wrapper .col-lg-3 .card-header > .card-head-actions > .btn {
    padding: 0 10px !important;
    font-size: 11px !important;
}

/* edge/view 좌측 정보 패널 — label(상) + value(하) 모던 키/값 레이아웃 */
body .col-lg-3 .card-body .form-inline,
body div.col-lg-3 .card-body .form-inline,
body .col-lg-3 .card-body .pp-form-row,
body div.col-lg-3 .card-body .pp-form-row {
    display: block !important;
    margin: 0 0 14px !important;
    padding: 0 !important;
    border: 0 !important;
    background: transparent !important;
}
body .col-lg-3 .card-body .form-inline:last-child,
body .col-lg-3 .card-body .pp-form-row:last-child {
    margin-bottom: 4px !important;
}
body .col-lg-3 .card-body .form-inline > label,
body .col-lg-3 .card-body .form-inline > .form-label,
body .col-lg-3 .card-body .form-inline > .form-label,
body .col-lg-3 .card-body .pp-form-row > label,
body .col-lg-3 .card-body .pp-form-row > .form-label,
body .col-lg-3 .card-body .pp-form-row > .form-label {
    display: block !important;
    width: auto !important;
    margin: 0 0 4px !important;
    padding: 0 !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.08em !important;
    color: var(--muted-foreground) !important;
    text-align: start !important;
    line-height: 1.2 !important;
}
body .col-lg-3 .card-body .form-inline > input.form-control,
body .col-lg-3 .card-body .pp-form-row > input.form-control {
    display: block !important;
    width: 100% !important;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    background: transparent !important;
    height: auto !important;
    min-height: 22px !important;
    font-size: 14px !important;
    font-weight: 500 !important;
    color: var(--foreground) !important;
    box-shadow: none !important;
    line-height: 1.4 !important;
    text-overflow: ellipsis;
}
body .col-lg-3 .card-body .form-inline > input.form-control[readonly],
body .col-lg-3 .card-body .pp-form-row > input.form-control[readonly] {
    background: transparent !important;
    cursor: default;
}
body .col-lg-3 .card-body .form-inline > input.form-control:focus,
body .col-lg-3 .card-body .pp-form-row > input.form-control:focus {
    outline: 0 !important;
    box-shadow: none !important;
}

/* edge/view.css 의 col-lg-9 패널 보더 제거 룰 무력화 (Signal 톤 강제 복원) */
body .col-lg-9 > .card.card,
body div.col-lg-9 > div.card.card {
    background: var(--card) !important;
    border: 1px solid var(--border) !important;
    border-radius: 12px !important;
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
}
body .col-lg-9 > .card.card > .card-header,
#page-wrapper .col-lg-9 > .card.card > .card-header {
    background: transparent !important;
    border: 0 !important;                                    /* 헤더 하단 보더 제거 (전역 정책) */
    margin-bottom: 4px !important;
    color: var(--card-foreground) !important;
    font-size: 14px !important;
    font-weight: 600 !important;
}
/* .col-lg-9 panel-body 강제 룰 제거 — 패널 자체 스타일 보존 */

/* ====================================================================== */
/* 버튼                                                                    */
/* ====================================================================== */
.btn {
    border-radius: 6px !important;
    font-size: 12px !important; font-weight: 500 !important;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
    /* 모든 버튼 — 텍스트와 아이콘 vertical center 정렬 (FA 아이콘 baseline drift 방지) */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    line-height: 1.2 !important;
    white-space: nowrap !important;
    vertical-align: middle;
}

/* 버튼 안 아이콘 — line-height 통일 */
.btn > i,
.btn > .fa,
.btn > .fa-light,
.btn > .fa-light,
.btn > .fa-light,
.btn > .fa-brands {
    line-height: 1 !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-right: 0 !important;
    flex-shrink: 0;
}

.btn-secondary {
    background: var(--card) !important;
    color: var(--foreground) !important;
    border: 1px solid var(--border) !important;
}
.btn-secondary:hover {
    background: var(--secondary) !important;
    border-color: var(--ring) !important;
}
.btn-primary {
    background: var(--primary) !important;
    color: var(--primary-foreground) !important;
    border: 1px solid var(--primary) !important;
}
.btn-primary:hover {
    filter: brightness(0.95);
}
/* btn-danger 는 전역 --destructive(밝은 57.7%) 대신 무거운(깊은) 빨강 사용 — 버튼 한정.
   뱃지/에러텍스트 등 다른 danger 톤은 --destructive 유지. */
.btn-danger {
    background: oklch(50% 0.19 27) !important;
    color: var(--destructive-foreground) !important;
    border: 1px solid oklch(50% 0.19 27) !important;
}
.btn-dark {
    background: oklch(0.21 0.006 286) !important;             /* 다크 톤 (zinc-900) */
    color: var(--pp-white) !important;
    border: 1px solid oklch(0.21 0.006 286) !important;
}
.btn-success {
    background: var(--success) !important;
    color: var(--success-foreground) !important;
    border: 1px solid var(--success) !important;
}

/* ====================================================================== */
/* 테이블 — Signal Users 페이지 톤 (소프트 보더 only / 헤더 ghost / hover) */
/* ====================================================================== */
.table, .dataTables_wrapper table {
    background: transparent !important;
    color: var(--card-foreground) !important;
    border: 0 !important;
    table-layout: auto !important;          /* 컬럼 글자 세로 깨짐 방지 */
    width: 100% !important;
}
.table.table-bordered, .dataTables_wrapper table.table-bordered {
    border: 0 !important;
}
/* 테이블 상단 보더 — thead 위쪽에 1px (아래쪽 마지막 행과 동일한 톤) */
.table,
.dataTables_wrapper table {
    border-top: 1px solid var(--border) !important;
}
.table > thead > tr:first-child > th,
.dataTables_wrapper table > thead > tr:first-child > th {
    border-top: 1px solid var(--border) !important;
}
.table > thead > tr > th,
.table.table-bordered > thead > tr > th,
.dataTables_wrapper table > thead > tr > th {
    background: var(--card) !important;       /* 흰색 (카드 톤) */
    color: var(--muted-foreground) !important;
    border-top: 0 !important;
    border-left: 0 !important;
    border-right: 0 !important;
    border-bottom: 1px solid var(--border) !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.05em !important;
    padding: 6px 24px 6px 14px !important;     /* 얇게 — 상하 6px / 우측 화살표 24px */
    height: auto !important;
    line-height: 1.2 !important;
    text-align: start !important;
    white-space: nowrap !important;
    vertical-align: middle !important;
    position: relative;                          /* 화살표 absolute anchor */
}
.table > tbody > tr > td,
.table.table-bordered > tbody > tr > td,
.dataTables_wrapper table > tbody > tr > td {
    background: transparent !important;
    border-top: 0 !important;
    border-left: 0 !important;
    border-right: 0 !important;
    border-bottom: 1px solid oklch(91% 0.008 165 / 0.4) !important;
    font-size: 13px !important;
    padding: 10px 14px !important;
    vertical-align: middle !important;
    white-space: nowrap !important;
    line-height: 1.5 !important;
}
/* 셀 안의 뱃지/입력칸 정렬 */
.table > tbody > tr > td .badge,
.table > tbody > tr > td .btn-sm {
    vertical-align: middle;
}
.table > tbody > tr:hover > td {
    background: oklch(95.5% 0.008 165 / 0.5) !important;
}
/* 마지막 행은 closing 보더 (테이블 하단 라인 명시).
   ⚠️ 보더색은 캐노니컬 --border(oklch 연회색, 전 테이블 보더 SSOT)로 통일.
   기존 var(--pp-border) 는 status/통계 등 다크 컨텍스트에서 슬레이트(slate-700)로 override 되어
   테이블 하단만 검정처럼 진하게 보이던 불일치 발생 → --border 로 톤 통일. */
body .table > tbody > tr:last-child > td,
body table.table > tbody > tr:last-child > td,
body .table-responsive > .table > tbody > tr:last-child > td {
    border-bottom: 1px solid var(--border, var(--pp-border)) !important;
}
/* 줄무늬 비활성화 (Signal 톤) — BS5.3 box-shadow inset 줄무늬도 함께 제거.
   DataTables(table.dataTable.table-striped)는 nth-of-type(2n+1) > * 셀렉터 사용 → 함께 커버. */
.table.table-striped > tbody > tr:nth-of-type(odd) > td,
table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
    background: transparent !important;
    box-shadow: none !important;
}
/* 정렬 화살표 — th 우측 가운데 absolute 위치 (텍스트 wrap 와 무관) */
.table > thead th[class*="sorting"] {
    cursor: pointer;
    background-image: none !important;
    /* absolute ::before/::after 화살표의 기준 컨테이너 — 없으면 화살표가
       엉뚱한 조상 기준으로 떠서 정렬 시 위치가 오락가락한다. */
    position: relative !important;
    padding-right: 20px !important;
}
.table > thead th[class*="sorting"]::before,
.table > thead th[class*="sorting"]::after {
    position: absolute !important;
    right: 10px !important;
    width: 8px;
    height: 5px;
    text-align: center !important;
    color: var(--muted-foreground) !important;
    font-family: sans-serif !important;
    font-size: 6px !important;
    line-height: 5px !important;
    margin: 0 !important;
    opacity: 0.55 !important;
    pointer-events: none;
}
.table > thead th[class*="sorting"]::before {
    content: "\25B2"; /* up triangle */
    top: calc(50% - 6px);
}
.table > thead th[class*="sorting"]::after {
    content: "\25BC"; /* down triangle */
    top: calc(50% + 1px);
}
.table > thead th.sorting_asc::before  { color: var(--primary) !important; opacity: 1 !important; }
.table > thead th.sorting_asc::after   { opacity: 0.25 !important; }
.table > thead th.sorting_desc::before { opacity: 0.25 !important; }
.table > thead th.sorting_desc::after  { color: var(--primary) !important; opacity: 1 !important; }
.table > thead th.sorting_disabled::before,
.table > thead th.sorting_disabled::after { display: none; }
/* DataTables 영역 정리 */
.dataTables_wrapper .dataTables_filter input,
.dataTables_wrapper .dataTables_length select {
    height: 32px !important;
    border-radius: 6px !important;
    border: 1px solid var(--border) !important;
    padding: 0 10px !important;
}
/* DataTables 페이지네이션 — Signal 스타일 (round 6px, hover bg, active primary)
   기존 Bootstrap .pagination 과 중복 스타일 모두 reset */
.dataTables_wrapper .dataTables_paginate,
.dataTables_paginate {
    text-align: end !important;
    padding: 14px 22px !important;
    margin: 0 !important;
    float: none !important;
}
.dataTables_paginate ul.pagination,
.dataTables_paginate .pagination,
.dataTables_wrapper .dataTables_paginate ul {
    display: inline-flex !important;
    margin: 0 !important;
    padding: 0 !important;
    list-style: none !important;
    border: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
    gap: 4px;
}
.dataTables_paginate ul.pagination > li,
.dataTables_paginate .pagination > li,
.pagination > li {
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
    outline: 0 !important;
    border-radius: 0 !important;
    list-style: none !important;
    display: inline-block !important;
}
/* 인접한 li 사이 안 보이는 보더 분리 */
.dataTables_paginate ul.pagination > li::before,
.dataTables_paginate ul.pagination > li::after,
.pagination > li::before,
.pagination > li::after {
    display: none !important;
    content: none !important;
}
/* li.paginate_button 자체는 wrapper — 보더 없음, 안의 <a>/<span> 만 클릭 영역 */
li.paginate_button,
li.paginate_button.previous,
li.paginate_button.next,
li.paginate_button.active,
li.paginate_button.disabled,
li.paginate_button.disabled:hover,
.dataTables_wrapper .dataTables_paginate li.paginate_button,
.dataTables_wrapper .dataTables_paginate li.paginate_button.disabled {
    border: 0 !important;
    background: transparent !important;
    padding: 0 !important;
    margin: 0 4px 0 0 !important;        /* 버튼 사이 4px 간격 (li 마진) */
    box-shadow: none !important;
    color: inherit !important;
}
li.paginate_button:last-child { margin-right: 0 !important; }
/* 클릭 가능한 a / span 만 버튼 스타일 */
.dataTables_paginate ul.pagination > li > a,
.dataTables_paginate ul.pagination > li > span,
.dataTables_paginate .pagination > li > a,
.dataTables_paginate .pagination > li > span,
.dataTables_wrapper .dataTables_paginate li.paginate_button > a,
.dataTables_wrapper .dataTables_paginate li.paginate_button > span {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 32px;
    padding: 0 10px !important;
    margin: 0 !important;
    border: 1px solid var(--border) !important;
    border-radius: 6px !important;
    background: var(--card) !important;
    color: var(--foreground) !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    line-height: 1 !important;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
    box-shadow: none !important;
    text-decoration: none !important;
}
/* DataTables 가 추가한 .paginate_button div 형태 (no a 자식) — 그 자체에 버튼 스타일 */
.dataTables_wrapper .dataTables_paginate > .paginate_button,
.dataTables_wrapper .dataTables_paginate > span > .paginate_button {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 32px;
    padding: 0 10px !important;
    margin: 0 0 0 4px !important;
    border: 1px solid var(--border) !important;
    border-radius: 6px !important;
    background: var(--card) !important;
    color: var(--foreground) !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button:hover,
.dataTables_wrapper .dataTables_paginate .paginate_button:focus {
    background: var(--secondary) !important;
    border-color: var(--ring) !important;
    color: var(--foreground) !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.current,
.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
    background: var(--primary) !important;
    color: var(--primary-foreground) !important;
    border-color: var(--primary) !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,
.dataTables_paginate ul.pagination > li.disabled > a,
.dataTables_paginate ul.pagination > li.disabled > span {
    color: var(--muted-foreground) !important;
    background: transparent !important;
    border-color: var(--border) !important;
    opacity: 0.55 !important;
    cursor: not-allowed;
}
.dataTables_paginate ul.pagination > li.active > a,
.dataTables_paginate ul.pagination > li.active > span,
.dataTables_paginate li.paginate_button.active > a {
    background: var(--primary) !important;
    color: var(--primary-foreground) !important;
    border-color: var(--primary) !important;
}
.dataTables_paginate ul.pagination > li > a:hover,
.dataTables_paginate li.paginate_button:not(.disabled):not(.active) > a:hover {
    background: var(--secondary) !important;
    border-color: var(--ring) !important;
}
/* 페이지네이션 좌측 info 텍스트 */
.dataTables_wrapper .dataTables_info {
    color: var(--muted-foreground) !important;
    font-size: 12px !important;
    padding: 14px 22px !important;
}

/* table-fixed 의 td 가 word-break: break-all 이라 text-truncate (ellipsis) 가 깨짐 — table 내 truncate cell 만 강제 */
.table.table-fixed > tbody > tr > td .text-truncate {
    word-break: normal !important;
    display: block;
    max-width: 100%;
}



/* === pp-21-forms-tabs.css === */

/* ====================================================================== */
/* Alert 패널 (alert-warning/info/danger/success) — 신규 테마 톤            */
/* ====================================================================== */
.alert {
    border-radius: 12px !important;
    padding: 14px 20px !important;
    font-size: 13px !important;
    line-height: 1.5 !important;
    border: 1px solid var(--border) !important;
    box-shadow: none !important;
    margin-bottom: 16px !important;
}
.alert-info {
    background: rgba(0, 61, 143, 0.06) !important;
    border-color: rgba(0, 61, 143, 0.20) !important;
    color: var(--primary) !important;
}
.alert-warning {
    background: oklch(96% 0.04 75 / 1) !important;
    border-color: oklch(82% 0.12 75 / 1) !important;
    color: oklch(35% 0.12 75) !important;
}
.alert-danger, .alert-error {
    background: oklch(96% 0.04 27 / 1) !important;
    border-color: oklch(82% 0.12 27 / 1) !important;
    color: oklch(40% 0.18 27) !important;
}
.alert-success {
    background: oklch(96% 0.04 145 / 1) !important;
    border-color: oklch(82% 0.12 145 / 1) !important;
    color: oklch(35% 0.12 145) !important;
}
.alert > i, .alert > .fa-light, .alert > .fa-light, .alert > .fa-light {
    margin-right: 8px !important;
}


/* ====================================================================== */
/* shadcn 스타일 Segmented Tabs                                            */
/* Bootstrap 3 .nav-tabs 마크업을 자동 리스타일                              */
/* ====================================================================== */

/* 컨테이너 — 회색 muted 배경, 라운드, 작은 패딩 */
.nav-tabs {
    display: inline-flex !important;
    align-items: center !important;
    gap: 4px !important;
    padding: 2px !important;
    margin: 0 0 16px !important;
    background: var(--muted) !important;
    border: 0 !important;
    border-bottom: 0 !important;
    border-radius: 8px !important;
    width: -moz-fit-content !important;
    width: fit-content !important;
    list-style: none !important;
}

/* li wrapper — 보더/배경 제거 */
.nav-tabs > li {
    float: none !important;
    margin: 0 !important;
    border: 0 !important;
    background: transparent !important;
}

/* 탭 버튼 — 비활성 상태 */
.nav-tabs > li > a {
    display: inline-flex !important;
    align-items: center !important;
    gap: 6px !important;
    padding: 6px 12px !important;
    margin: 0 !important;
    border: 0 !important;
    border-radius: 6px !important;
    background: transparent !important;
    color: var(--muted-foreground) !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    line-height: 1.2 !important;
    white-space: nowrap !important;
    cursor: pointer !important;
    transition: color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease !important;
}

/* 비활성 탭 hover */
.nav-tabs > li > a:hover,
.nav-tabs > li > a:focus {
    background: transparent !important;
    color: var(--foreground) !important;
    border: 0 !important;
}

/* 활성 탭 — 흰색 배경, 그림자 */
.nav-tabs > li.active > a, .nav-tabs > li > a.active,
.nav-tabs > li.active > a:hover, .nav-tabs > li > a.active:hover,
.nav-tabs > li.active > a:focus, .nav-tabs > li > a.active:focus {
    background: var(--background) !important;
    color: var(--foreground) !important;
    border: 0 !important;
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
}

/* 컨텐츠 영역 — Bootstrap tab-content */
.tab-content {
    border: 0 !important;
    background: transparent !important;
    padding: 0 !important;
}

/* ====================================================================== */
/* KPI Stat Cards — Signal Deployments 스타일 메트릭 카드                  */
/* ====================================================================== */
@media (max-width: 992px) {
    .pp-stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.pp-stat-label > i {
    font-size: 14px !important;
    color: var(--muted-foreground) !important;
}
.pp-stat-trend.up    { color: var(--success) !important; }
.pp-stat-trend.down  { color: var(--destructive) !important; }
.pp-stat-trend.flat  { color: var(--muted-foreground) !important; }

/* 카드 색상 변형 — 좌측에 4px 액센트 보더 */

/* === pp-22-spacing.css === */

/* ====================================================================== */
/* 인라인 spacing 정규화 — 167+ JSP에 흩뿌려진 인라인 padding/margin 통일  */
/* 표준: 패널/섹션 마진 16px, 컬럼 거터 8px, 빈 spacer div 16px           */
/* ====================================================================== */

/* 빈 spacer div 표준화 (15px / 10px → 16px / 12px) */
body #page-wrapper div[style*="margin-bottom: 15px"]:empty,
body #page-wrapper div[style*="margin-bottom:15px"]:empty {
    margin-bottom: 16px !important;
}
body #page-wrapper div[style*="margin-bottom: 10px"]:empty,
body #page-wrapper div[style*="margin-bottom:10px"]:empty {
    margin-bottom: 12px !important;
}

/* nav-tabs 하단 마진 통일 (인라인 15px → 표준 16px) */
body #page-wrapper ul.nav-tabs[style*="margin-bottom"] {
    margin-bottom: 16px !important;
}

/* row.row 가 panel-body 안에 들어있을 때 잉여 padding 제거 (order/view 케이스) */
body #page-wrapper .card-body > .row[style*="padding:5px"],
body #page-wrapper .card-body > .row[style*="padding: 5px"] {
    padding: 0 !important;
}

/* 인덱스 페이지 첫 row 의 margin-top:10px 인라인 → 0 (page-header 와 통일) */
body #page-wrapper > .row:first-of-type[style*="margin-top: 10px"],
body #page-wrapper > .row:first-of-type[style*="margin-top:10px"] {
    margin-top: 0 !important;
}


/* ============================================================
 * 디자인 시스템 — 재사용 위젯 (shadcn 톤)
 * sc-* prefix — 카드, 아바타, 스켈레톤, 브레드크럼, 아코디언 등
 * 모든 페이지에서 사용 가능
 * ============================================================ */


/* ─── Profile Card ─── */
.sc-profile { display: flex; align-items: center; gap: 12px; }
.sc-profile-body { flex: 1; min-width: 0; }
.sc-profile-name {
    font-size: 14px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}
.sc-profile-meta {
    font-size: 12px !important;
    color: oklch(0.55 0.016 286) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}

/* Empty State 표준은 .pp-empty-state(+--lg/--sm) 로 통일됨 — pp-25-cards.css. 구 .sc-empty 제거. */

.pp-empty-state__sub:last-child {
    margin-bottom: 0 !important;
}

/* ─── Action Card (clickable) ─── */
a.sc-action {
    display: flex;
    align-items: center;
    gap: 14px;
    text-decoration: none !important;
    cursor: pointer;
    color: inherit !important;
}
a.sc-action:hover {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: 0 4px 14px rgba(0, 61, 143, 0.10) !important;
    transform: translateY(-1px);
}
.sc-action-icon {
    width: 40px; height: 40px;
    border-radius: 10px !important;
    background: rgba(0, 61, 143, 0.08) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 16px !important;
    flex-shrink: 0;
}
.sc-action-body { flex: 1; min-width: 0; }
.sc-action-title {
    font-size: 14px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
}
.sc-action-desc {
    font-size: 12px !important;
    color: oklch(0.55 0.016 286) !important;
    margin-top: 2px !important;
}
.sc-action-chevron {
    color: oklch(0.55 0.016 286) !important;
    flex-shrink: 0;
}

/* ─── Accordion ─── */
.sc-accordion {
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    overflow: hidden;
}
.sc-acc-item {
    border-bottom: 1px solid var(--pp-border) !important;
}
.sc-acc-item:last-child { border-bottom: 0 !important; }
.sc-acc-trigger {
    width: 100%;
    text-align: left !important;
    background: var(--pp-white) !important;
    border: 0 !important;
    padding: 12px 16px !important;
    font-size: 13px !important;
    font-weight: 500 !important;
    color: oklch(0.21 0.006 286) !important;
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    transition: background 0.12s;
}
.sc-acc-trigger:hover { background: var(--pp-bg-muted, #f9fafb) !important; }
.sc-acc-chevron {
    transition: transform 0.2s ease;
    font-size: 12px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
}
.sc-acc-trigger.sc-acc-open .sc-acc-chevron {
    transform: rotate(180deg);
}
.sc-acc-content {
    padding: 0 16px 14px !important;
    font-size: 13px !important;
    color: var(--pp-text-soft, #374151) !important;
    line-height: 1.6 !important;
    display: none;
}
.sc-acc-content.sc-acc-show { display: block; }

/* ─── Separator ─── */
.sc-separator {
    height: 1px;
    background: var(--pp-border) !important;
    margin: 14px 0 !important;
}
.sc-separator-dashed {
    background: transparent !important;
    border-top: 1px dashed var(--pp-border) !important;
    height: 0;
}

/* ─── Switch ─── */
.sc-switch {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    user-select: none;
}
.sc-switch input { position: absolute; opacity: 0 !important; width: 0; height: 0; }
.sc-switch-slider {
    width: 36px;
    height: 20px;
    background: oklch(0.85 0.01 286) !important;
    border-radius: 999px !important;
    position: relative;
    transition: background 0.18s ease;
    flex-shrink: 0;
}
.sc-switch-slider::before {
    content: '';
    position: absolute;
    width: 16px; height: 16px;
    background: var(--pp-white) !important;
    border-radius: 50% !important;
    top: 2px; left: 2px;
    box-shadow: 0 1px 2px rgba(0,0,0,0.15) !important;
    transition: transform 0.18s ease;
}
.sc-switch input:checked ~ .sc-switch-slider {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}
.sc-switch input:checked ~ .sc-switch-slider::before {
    transform: translateX(16px);
}
.sc-switch input:disabled ~ .sc-switch-slider {
    opacity: 0.5 !important;
    cursor: not-allowed;
}
.sc-switch-label {
    font-size: 13px !important;
    color: oklch(0.30 0.006 286) !important;
}

/* ─── Keyboard Shortcut (kbd) ─── */
.sc-kbd, kbd.sc-kbd {
    display: inline-block;
    padding: 2px 8px !important;
    background: oklch(0.97 0.005 260) !important;
    border: 1px solid var(--pp-border) !important;
    border-bottom-width: 2px !important;
    border-radius: 4px !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 11px !important;
    color: oklch(0.30 0.006 286) !important;
    box-shadow: 0 1px 0 rgba(0,0,0,0.04) !important;
}

/* ─── Stat Row (label + value) ─── */
.sc-stat-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0 !important;
    border-bottom: 1px solid var(--pp-border) !important;
    font-size: 13px !important;
}
.sc-stat-row:last-child { border-bottom: 0 !important; }
.sc-stat-row > span:first-child {
    color: oklch(0.55 0.016 286) !important;
}
.sc-stat-val {
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}


/* ============================================================
 * 디자인 시스템 — 추가 위젯
 * ds-* prefix — 툴바·검색·필터칩·드로어·커맨드팔레트·드롭존·타임라인·
 * 위저드·히어로·배너·사용자메뉴·알림센터·로딩·트렌드 등
 * 모든 페이지에서 사용 가능
 * ============================================================ */

 * ============================================================ */

/* ─── Description List ──────────────────────────────────── */
.ds-dl { margin: 0 !important; }
.ds-dl dt {
    font-size: 11px !important;
    font-weight: 500 !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 8px !important;
    letter-spacing: 0.2px !important;
}
.ds-dl dd {
    font-size: 13px !important;
    color: oklch(0.21 0.006 286) !important;
    margin: 2px 0 0 0 !important;
    padding-bottom: 8px !important;
    border-bottom: 1px dashed var(--pp-border) !important;
}
.ds-dl dd:last-child { border-bottom: 0 !important; }
.ds-dl code {
    background: var(--pp-bg-muted, #f4f4f5) !important;
    padding: 1px 6px !important;
    border-radius: 4px !important;
    font-size: 12px !important;
}

/* ─── Status Dots ───────────────────────────────────────── */
.ds-dot {
    display: inline-block;
    width: 8px; height: 8px;
    border-radius: 50% !important;
    background: oklch(0.75 0.01 286) !important;
    margin-right: 4px !important;
    vertical-align: middle;
}
.ds-dot-ok   { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.ds-dot-warn { background: #f59e0b !important; }
.ds-dot-err  { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
.ds-dot-mute { background: var(--pp-text-muted) !important; }
.ds-dot-pulse {
    box-shadow: 0 0 0 0 currentColor !important;
    animation: ds-dot-pulse 1.6s ease-out infinite;
}
@keyframes ds-dot-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(22,163,74,0.6); }
    70%  { box-shadow: 0 0 0 8px rgba(22,163,74,0);  }
    100% { box-shadow: 0 0 0 0 rgba(22,163,74,0);    }
}

/* ─── Status Pills ──────────────────────────────────────── */
.ds-pill {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--pp-border) !important;
    border-radius: 999px !important;
    overflow: hidden;
    font-size: 11px !important;
    font-weight: 500 !important;
}
.ds-pill-l { padding: 3px 10px !important; background: var(--pp-bg-muted, #f9fafb) !important; color: var(--pp-text-muted, var(--pp-muted-fg)) !important; }
.ds-pill-r { padding: 3px 10px !important; background: var(--pp-white) !important; }
.ds-pill-r.ds-pill-ok   { color: var(--pp-tone-success-bg) !important; }
.ds-pill-r.ds-pill-warn { color: var(--pp-tone-warn-bg) !important; }
.ds-pill-r.ds-pill-err  { color: var(--pp-tone-danger-bg) !important; }

/* ─── Trend Arrows ──────────────────────────────────────── */
.ds-trend {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px !important;
    font-weight: 600 !important;
}
.ds-trend-up   { color: var(--pp-tone-success-bg) !important; }
.ds-trend-down { color: var(--pp-tone-danger-bg) !important; }
.ds-trend-flat { color: var(--pp-muted-fg) !important; }

/* ─── Live Indicator ────────────────────────────────────── */
.ds-live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 10px !important;
    font-weight: 700 !important;
    color: var(--pp-tone-danger-bg) !important;
    letter-spacing: 0.5px !important;
}
.ds-live-dot {
    width: 7px; height: 7px;
    border-radius: 50% !important;
    background: var(--pp-tone-danger-bg) !important;
    box-shadow: 0 0 0 0 rgba(220,38,38,0.6) !important;
    animation: ds-live-pulse 1.4s ease-out infinite;
    color: var(--pp-white) !important;
}
.ds-live-paused { color: var(--pp-muted-fg) !important; }
.ds-live-paused .ds-live-dot { background: var(--pp-muted-fg) !important; animation: none; }
@keyframes ds-live-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(220,38,38,0.6); }
    70%  { box-shadow: 0 0 0 6px rgba(220,38,38,0);  }
    100% { box-shadow: 0 0 0 0 rgba(220,38,38,0);    }
}

/* ─── Toolbar ───────────────────────────────────────────── */
.ds-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    margin-bottom: 12px !important;
    flex-wrap: wrap;
}
.ds-toolbar-search {
    position: relative;
    flex: 1;
    max-width: 320px;
    min-width: 200px;
}
.ds-toolbar-search-icon {
    position: absolute;
    left: 10px; top: 50%;
    transform: translateY(-50%);
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    font-size: 12px !important;
}
.ds-toolbar-search input {
    width: 100%;
    height: 32px;
    padding: 0 10px 0 30px !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 6px !important;
    font-size: 13px !important;
    background: var(--pp-bg-muted, #f9fafb) !important;
    transition: border-color 0.12s, background 0.12s;
}
.ds-toolbar-search input:focus {
    outline: 0 !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    background: var(--pp-white) !important;
    box-shadow: 0 0 0 3px rgba(0, 61, 143, 0.10) !important;
}
.ds-toolbar-divider {
    width: 1px;
    height: 22px;
    background: var(--pp-border) !important;
}
.ds-toolbar-spacer { flex: 1; }

/* ─── Search Results Dropdown ───────────────────────────── */
.ds-search-results {
    position: absolute;
    top: 100%;
    left: 0; right: 0;
    margin-top: 6px !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    box-shadow: 0 8px 24px rgba(0,0,0,0.10) !important;
    overflow: hidden;
    z-index: 100;
    max-height: 380px;
    overflow-y: auto;
}
.ds-search-section {
    font-size: 10px !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    padding: 8px 14px 4px !important;
}
.ds-search-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px !important;
    cursor: pointer;
    text-decoration: none !important;
    color: oklch(0.21 0.006 286) !important;
    transition: background 0.1s;
}
.ds-search-item:hover { background: var(--pp-bg-muted, #f9fafb) !important; }
.ds-search-item-body { flex: 1; min-width: 0; }
.ds-search-item-title {
    font-size: 13px !important;
    font-weight: 500 !important;
}
.ds-search-item-title b {
    background: rgba(0, 61, 143, 0.12) !important;
    padding: 0 2px !important;
    border-radius: 2px !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
}
.ds-search-item-meta {
    font-size: 11px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 1px !important;
}
.ds-search-item-chev {
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    font-size: 11px !important;
}

/* ─── Filter Chips ──────────────────────────────────────── */
.ds-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px 4px 12px !important;
    background: rgba(0, 61, 143, 0.08) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    border: 1px solid transparent !important;
    border-radius: 999px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
}
.ds-chip-active { background: rgba(0, 61, 143, 0.10) !important; }
.ds-chip-clear {
    background: transparent !important;
    border: 1px dashed var(--pp-border) !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    cursor: pointer;
}
.ds-chip-remove {
    background: transparent !important;
    border: 0 !important;
    color: inherit !important;
    font-size: 14px !important;
    line-height: 1 !important;
    cursor: pointer;
    padding: 0 0 0 2px !important;
    opacity: 0.6 !important;
}
.ds-chip-remove:hover { opacity: 1 !important; }

/* ─── Bulk Action Bar ───────────────────────────────────── */
.ds-bulk-bar {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 10px 16px !important;
    background: oklch(0.21 0.006 286) !important;
    color: var(--pp-white) !important;
    border-radius: 10px !important;
    margin: 12px 0 !important;
}
.ds-bulk-bar-info { flex: 1; }
.ds-bulk-bar-count { font-size: 13px !important; font-weight: 600 !important; }
.ds-bulk-bar-count b {
    color: oklch(0.85 0.18 200) !important;
    font-size: 14px !important;
    margin-right: 4px !important;
}
.ds-bulk-bar-meta {
    font-size: 11px !important;
    color: rgba(255,255,255,0.6) !important;
    margin-left: 8px !important;
}
.ds-bulk-bar-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* ─── Segmented Control ─────────────────────────────────── */
.ds-segmented {
    display: inline-flex;
    background: var(--pp-bg-muted, #f4f4f5) !important;
    border-radius: 8px !important;
    padding: 3px !important;
    border: 1px solid var(--pp-border) !important;
}
.ds-segmented-item {
    background: transparent !important;
    border: 0 !important;
    padding: 5px 12px !important;
    font-size: 12px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    border-radius: 6px !important;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    transition: background 0.15s, color 0.15s;
}
.ds-segmented-item:hover { color: oklch(0.21 0.006 286) !important; }
.ds-segmented-item.active {
    background: var(--pp-white) !important;
    color: oklch(0.21 0.006 286) !important;
    box-shadow: 0 1px 2px rgba(0,0,0,0.06) !important;
}

/* ─── Vertical Timeline (Activity feed) ─────────────────── */
.ds-timeline {
    list-style: none;
    margin: 0 !important;
    padding: 0 0 0 20px !important;
    border-left: 2px solid var(--pp-border) !important;
}
.ds-tl-item {
    position: relative;
    padding: 4px 0 18px 18px !important;
}
.ds-tl-item:last-child { padding-bottom: 0 !important; }
.ds-tl-dot {
    position: absolute;
    left: -30px; top: 0;
    width: 22px; height: 22px;
    border-radius: 50% !important;
    background: oklch(0.85 0.01 286) !important;
    color: var(--pp-white) !important;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px !important;
    border: 2px solid var(--pp-white) !important;
    box-shadow: 0 0 0 1px var(--pp-border) !important;
}
.ds-tl-ok   .ds-tl-dot { background: var(--pp-tone-success-bg) !important; box-shadow: 0 0 0 1px var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.ds-tl-info .ds-tl-dot { background: var(--primary, var(--pp-primary-strong)) !important; box-shadow: 0 0 0 1px var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important; }
.ds-tl-warn .ds-tl-dot { background: #f59e0b !important; box-shadow: 0 0 0 1px #f59e0b !important; }
.ds-tl-err  .ds-tl-dot { background: var(--pp-tone-danger-bg) !important; box-shadow: 0 0 0 1px var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
.ds-tl-title {
    font-size: 13px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
}
.ds-tl-meta {
    font-size: 11px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 1px !important;
}
.ds-tl-desc {
    font-size: 12px !important;
    color: var(--pp-text-soft, #374151) !important;
    margin-top: 4px !important;
    line-height: 1.5 !important;
}

/* ─── Status Timeline (수평) ────────────────────────────── */
.ds-stl {
    display: flex;
    align-items: flex-start;
    gap: 0;
    padding: 16px 0 !important;
}
.ds-stl-step {
    flex: 0 0 auto;
    text-align: center !important;
    width: 100px;
}
.ds-stl-circle {
    width: 36px; height: 36px;
    border-radius: 50% !important;
    background: var(--pp-bg-muted, #f4f4f5) !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    border: 2px solid var(--pp-border) !important;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px !important;
    font-weight: 600 !important;
    margin: 0 auto 6px !important;
}
.ds-stl-step.ds-stl-done .ds-stl-circle {
    background: var(--pp-tone-success-bg) !important;
    border-color: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important;
}
.ds-stl-step.ds-stl-active .ds-stl-circle {
    background: var(--primary, var(--pp-primary-strong)) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    box-shadow: 0 0 0 4px rgba(0,61,143,0.15) !important;
}
.ds-stl-label {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: oklch(0.21 0.006 286) !important;
}
.ds-stl-time {
    font-size: 10px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 1px !important;
}
.ds-stl-line {
    flex: 1;
    height: 2px;
    background: var(--pp-border) !important;
    margin: 18px -10px 0 !important;
    z-index: -1;
}
.ds-stl-line.ds-stl-done   { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.ds-stl-line.ds-stl-active {
    background: linear-gradient(to right, var(--pp-tone-success-bg) 0%, var(--primary, var(--pp-primary-strong)) 100%) !important;
    color: var(--pp-white) !important;
}

/* ─── Drawer / Slide-over ───────────────────────────────── */
.ds-drawer-overlay {
    position: fixed;
    inset: 0;
    background: oklch(85% 0.02 260 / 0.55) !important;
    backdrop-filter: blur(2px);
    z-index: 1040;
    display: none;
}
.ds-drawer-overlay.show { display: block; }
.ds-drawer {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    width: 420px;
    max-width: 90vw;
    background: var(--pp-white) !important;
    border-left: 1px solid var(--pp-border) !important;
    box-shadow: -8px 0 32px rgba(0,0,0,0.10) !important;
    z-index: 1041;
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.25s cubic-bezier(.4,0,.2,1);
}
.ds-drawer.show { transform: translateX(0); }
.ds-drawer-header {
    padding: 16px 20px !important;
    border-bottom: 1px solid var(--pp-border) !important;
    display: flex;
    align-items: center;
    gap: 12px;
}
.ds-drawer-body {
    flex: 1 1 auto;
    min-height: 0;             /* flex item 의 overflow 가 실제로 동작하게 함 */
    padding: 16px 20px !important;
    overflow-y: auto;
}
.ds-drawer-footer {
    flex-shrink: 0;            /* 콘텐츠가 늘어나도 footer 는 줄지 않음 */
    margin-top: auto !important;          /* 콘텐츠가 짧아도 footer 를 항상 맨 밑으로 밀어냄 */
    padding: 12px 20px !important;
    border-top: 1px solid var(--pp-border) !important;
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    background: var(--pp-bg-muted, #f9fafb) !important;
    /* drawer 가 매우 길어 body 가 스크롤되어도 footer 가 항상 보이도록 보강.
       (flex 구조상 이미 보이지만, 일부 브라우저 차이를 흡수.) */
    position: sticky;
    bottom: 0;
}

/* === pp-23-forms.css === */
/* ============================================================================
 * pp-04-forms.css
 * 영역: ds-cmdk / ds-dropzone / ds-file / ds-hero / ds-banner / ds-welcome
 *        ds-user / ds-notif / ds-stb 타임라인 / range / fieldset / color
 *        select2 / form-stack / control-label
 * 분할: 2026-05-15 (Phase 2) — 원본 pp-04-forms-tables.css 1688라인 분할
 * ============================================================================ */
/* ─── Dropzone ──────────────────────────────────────────── */
.ds-dropzone {
    border: 2px dashed var(--border, var(--pp-border)) !important;
    border-radius: 12px !important;
    padding: 32px 24px !important;
    text-align: center !important;
    background: oklch(0.97 0.005 286) !important;     /* zinc-50 (중립) */
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.ds-dropzone:hover {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    background: rgba(0, 61, 143, 0.04) !important;
}
.ds-dropzone.ds-dropzone-active {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    background: rgba(0, 61, 143, 0.06) !important;
}
.ds-dropzone-icon {
    font-size: 32px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-bottom: 8px !important;
}
.ds-dropzone:hover .ds-dropzone-icon,
.ds-dropzone.ds-dropzone-active .ds-dropzone-icon {
    color: var(--primary, var(--pp-primary-strong)) !important;
}
.ds-dropzone-title {
    font-size: 13px !important;
    font-weight: 500 !important;
    color: oklch(0.21 0.006 286) !important;
    margin-bottom: 4px !important;
}
.ds-dropzone-meta {
    font-size: 11px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
}

/* ─── File List ─────────────────────────────────────────── */
.ds-file-list {
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    overflow: hidden;
    background: var(--pp-white) !important;
}
.ds-file-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px !important;
    border-bottom: 1px solid var(--pp-border) !important;
}
.ds-file-item:last-child { border-bottom: 0 !important; }
.ds-file-icon {
    width: 36px; height: 36px;
    border-radius: 8px !important;
    background: var(--pp-bg-muted, #f4f4f5) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px !important;
    flex-shrink: 0;
}
.ds-file-body { flex: 1; min-width: 0; }
.ds-file-name {
    font-size: 13px !important;
    font-weight: 500 !important;
    color: oklch(0.21 0.006 286) !important;
}
.ds-file-meta {
    font-size: 11px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 1px !important;
}

/* ─── Spinner ───────────────────────────────────────────── */
.ds-spinner {
    display: inline-block;
    width: 18px;
    height: 18px;
    border: 2px solid var(--pp-border) !important;
    border-top-color: var(--primary, var(--pp-primary-strong)) !important;
    border-radius: 50% !important;
    animation: ds-spinner-rotate 0.7s linear infinite;
}
.ds-spinner-sm { width: 12px; height: 12px; border-width: 2px !important; }
.ds-spinner-lg { width: 28px; height: 28px; border-width: 3px !important; }
@keyframes ds-spinner-rotate { to { transform: rotate(360deg); } }

/* ─── Banner ────────────────────────────────────────────── */
.ds-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px !important;
    border-radius: 8px !important;
    font-size: 13px !important;
    margin-bottom: 8px !important;
}
.ds-banner-info   { background: #eff6ff !important; color: #1e40af !important; border: 1px solid #bfdbfe !important; }
.ds-banner-warn   { background: #fffbeb !important; color: #92400e !important; border: 1px solid #fde68a !important; }
.ds-banner-danger { background: #fef2f2 !important; color: #991b1b !important; border: 1px solid #fecaca !important; }
.ds-banner-text { flex: 1; }
.ds-banner-link {
    color: inherit !important;
    font-weight: 600 !important;
    text-decoration: underline !important;
    cursor: pointer;
}
.ds-banner-close {
    background: transparent !important;
    border: 0 !important;
    color: inherit !important;
    font-size: 18px !important;
    line-height: 1 !important;
    cursor: pointer;
    opacity: 0.6 !important;
    padding: 0 4px !important;
}
.ds-banner-close:hover { opacity: 1 !important; }

/* ─── Welcome ───────────────────────────────────────────── */
.ds-welcome {
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 14px !important;
    padding: 24px !important;
    display: flex;
    gap: 20px;
    align-items: center;
    margin-bottom: 16px !important;
}
.ds-welcome-body { flex: 1; }
.ds-welcome-title {
    font-size: 18px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    margin: 0 0 4px !important;
}
.ds-welcome-desc {
    font-size: 13px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin: 0 0 14px !important;
}
.ds-welcome-stats {
    display: flex;
    gap: 24px;
}
.ds-welcome-stat { display: flex; flex-direction: column; }
.ds-welcome-stat-num {
    font-size: 22px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    line-height: 1 !important;
}
.ds-welcome-stat-lbl {
    font-size: 11px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 4px !important;
}


/* ─── Notification Center ───────────────────────────────── */
.ds-notif-wrap { position: relative; display: inline-block; }
.ds-notif-trigger {
    width: 36px;
    height: 36px;
    border-radius: 8px !important;
    background: transparent !important;
    border: 1px solid var(--pp-border) !important;
    cursor: pointer;
    position: relative;
    color: oklch(0.30 0.006 286) !important;
}
.ds-notif-trigger:hover { background: var(--pp-bg-muted, #f9fafb) !important; }
.ds-notif-dot {
    position: absolute;
    top: 6px; right: 7px;
    width: 8px; height: 8px;
    border-radius: 50% !important;
    background: var(--pp-tone-danger-bg) !important;
    border: 2px solid var(--pp-white) !important;
    color: var(--pp-white) !important;
}
.ds-notif-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    width: 360px;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    box-shadow: 0 8px 24px rgba(0,0,0,0.10) !important;
    z-index: 100;
    overflow: hidden;
    display: none;
}
.ds-notif-wrap:hover .ds-notif-panel,
.ds-notif-wrap.show .ds-notif-panel { display: block; }
.ds-notif-header {
    padding: 12px 14px !important;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--pp-border) !important;
}
.ds-notif-header h4 {
    margin: 0 !important;
    font-size: 14px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
}
.ds-notif-header a {
    font-size: 11px !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    cursor: pointer;
    text-decoration: none !important;
}
.ds-notif-list { max-height: 380px; overflow-y: auto; }
.ds-notif-item {
    display: flex;
    gap: 10px;
    padding: 10px 14px !important;
    border-bottom: 1px solid var(--pp-border) !important;
    text-decoration: none !important;
    color: inherit !important;
}
.ds-notif-item:hover { background: var(--pp-bg-muted, #f9fafb) !important; }
.ds-notif-item:last-child { border-bottom: 0 !important; }
.ds-notif-unread { background: rgba(0, 61, 143, 0.03) !important; }
.ds-notif-unread .ds-notif-title { font-weight: 600 !important; }
.ds-notif-icon {
    width: 28px; height: 28px;
    border-radius: 50% !important;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--pp-white) !important;
    font-size: 11px !important;
    flex-shrink: 0;
}
.ds-notif-icon.ds-notif-ok   { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.ds-notif-icon.ds-notif-warn { background: #f59e0b !important; }
.ds-notif-icon.ds-notif-err  { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
.ds-notif-icon.ds-notif-info { background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important; }
.ds-notif-body { flex: 1; min-width: 0; }
.ds-notif-title {
    font-size: 12px !important;
    color: oklch(0.21 0.006 286) !important;
}
.ds-notif-desc {
    font-size: 11px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 1px !important;
}
.ds-notif-time {
    font-size: 10px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin-top: 4px !important;
}
.ds-notif-footer {
    padding: 10px 14px !important;
    text-align: center !important;
    border-top: 1px solid var(--pp-border) !important;
    background: var(--pp-bg-muted, #f9fafb) !important;
}
.ds-notif-footer a {
    font-size: 12px !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    text-decoration: none !important;
    font-weight: 500 !important;
}

/* view-inline 라벨/값 */
.view-inline { display: flex; align-items: center; gap: 12px; padding: 6px 0 !important; }
.view-label  { font-size: 12px !important; color: var(--pp-text-muted, var(--pp-muted-fg)) !important; width: 110px; flex-shrink: 0; margin-bottom: 0 !important; }
.view-content { flex: 1; }


/* ============================================================
 * 설비 연결 / 건강 status-bar 타임라인 (gantt 스타일)
 * 디자인 시스템 카탈로그 + 일반 페이지에서도 사용 가능
 * ============================================================ */
.ds-stb-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 0 !important;
    border-bottom: 1px solid var(--pp-border) !important;
}
.ds-stb-row:last-of-type { border-bottom: 0 !important; }
.ds-stb-label {
    width: 160px;
    flex-shrink: 0;
    font-size: 11px !important;
    color: oklch(0.30 0.006 286) !important;
    font-weight: 500 !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}
.ds-stb-track {
    flex: 1;
    height: 18px;
    background: var(--pp-bg-muted, #f4f4f5) !important;
    border-radius: 4px !important;
    display: flex;
    overflow: hidden;
    border: 1px solid var(--pp-border) !important;
}
.ds-stb-seg {
    height: 100%;
    transition: opacity 0.15s, transform 0.15s;
    cursor: pointer;
    position: relative;
}
.ds-stb-seg:hover {
    opacity: 0.85 !important;
    z-index: 2;
}
.ds-stb-axis {
    display: flex;
    justify-content: space-between;
    padding: 6px 0 0 172px !important;        /* label width + gap */
    font-size: 10px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
}
.ds-stb-legend {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11px !important;
    color: var(--pp-text-soft, #374151) !important;
    margin-right: 16px !important;
}
.ds-stb-swatch {
    display: inline-block;
    width: 10px; height: 10px;
    border-radius: 2px !important;
    flex-shrink: 0;
}
.ds-stb-track-tooltip { overflow: visible; }
.ds-stb-seg-active {
    box-shadow: 0 0 0 2px var(--pp-white), 0 0 0 3px currentColor !important;
    z-index: 3;
}
.ds-stb-tip {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: oklch(0.18 0.01 286) !important;
    color: var(--pp-white) !important;
    padding: 8px 12px !important;
    border-radius: 6px !important;
    font-size: 11px !important;
    white-space: nowrap !important;
    z-index: 10;
    box-shadow: 0 4px 12px rgba(0,0,0,0.18) !important;
}
.ds-stb-tip::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent !important;
    border-top-color: oklch(0.18 0.01 286) !important;
}
.ds-stb-tip-period {
    display: block;
    font-weight: 600 !important;
    margin-bottom: 4px !important;
}
.ds-stb-tip-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px !important;
}


/* ====================================================================== */
/* 범위 슬라이더 (input[type=range]) — primary navy 톤                    */
/* ====================================================================== */
input[type="range"].form-control,
body input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    height: 6px !important;
    padding: 0 !important;
    background: oklch(0.91 0.008 286) !important;
    border-radius: 999px !important;
    outline: 0 !important;
    border: 0 !important;
    box-shadow: none !important;
    cursor: pointer;
}
body input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px; height: 16px;
    border-radius: 50% !important;
    background: var(--primary, var(--pp-primary-strong)) !important;
    border: 2px solid var(--pp-white) !important;
    box-shadow: 0 1px 3px rgba(0, 61, 143, 0.3) !important;
    cursor: pointer;
    transition: transform 0.12s, box-shadow 0.12s;
    color: var(--pp-white) !important;
}
body input[type="range"]::-webkit-slider-thumb:hover {
    transform: scale(1.15);
    box-shadow: 0 2px 6px rgba(0, 61, 143, 0.4) !important;
}
body input[type="range"]::-moz-range-thumb {
    width: 16px; height: 16px;
    border-radius: 50% !important;
    background: var(--primary, var(--pp-primary-strong)) !important;
    border: 2px solid var(--pp-white) !important;
    box-shadow: 0 1px 3px rgba(0, 61, 143, 0.3) !important;
    cursor: pointer;
    color: var(--pp-white) !important;
}
body input[type="range"]::-moz-range-track {
    height: 6px;
    background: oklch(0.91 0.008 286) !important;
    border-radius: 999px !important;
}
body input[type="range"]:focus {
    box-shadow: 0 0 0 3px rgba(0, 61, 143, 0.15) !important;
}
body input[type="range"]:disabled {
    opacity: 0.5 !important;
    cursor: not-allowed;
}

/* ====================================================================== */
/* fieldset / legend — 아이콘 색상 정렬 + 톤 통일                          */
/* ====================================================================== */
body fieldset > legend {
    color: oklch(0.30 0.006 286) !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    border-bottom: 1px solid var(--border) !important;
    padding-bottom: 6px !important;
    margin-bottom: 12px !important;
}
body fieldset > legend > i {
    color: var(--primary, var(--pp-primary-strong)) !important;
    margin-right: 6px !important;
    font-size: 11px !important;
}


/* ====================================================================== */
/* 컬러 피커 (input[type=color]) — 내부 패딩 제거, 보더 안쪽까지 색 채움 */
/* ====================================================================== */
body input[type="color"] {
    -webkit-appearance: none;
    appearance: none;
    padding: 0 !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 6px !important;
    background-clip: padding-box !important;
    cursor: pointer;
    overflow: hidden;
    height: 36px;
    width: 48px;
}
body input[type="color"]::-webkit-color-swatch-wrapper {
    padding: 0 !important;
    border: 0 !important;
    border-radius: 5px !important;
}
body input[type="color"]::-webkit-color-swatch {
    border: 0 !important;
    border-radius: 5px !important;
}
body input[type="color"]::-moz-color-swatch {
    border: 0 !important;
    border-radius: 5px !important;
}
body input[type="color"]:focus {
    outline: 0 !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: 0 0 0 3px rgba(0, 61, 143, 0.12) !important;
}


/* ====================================================================== */
/* Select2 — 테마 정렬 (zinc/navy 톤)                                    */
/* ====================================================================== */
body .select2-container--default .select2-selection--single,
body .select2-container--default .select2-selection--multiple {
    height: 36px !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 6px !important;
    background: var(--pp-white) !important;
    transition: border-color 0.12s, box-shadow 0.12s;
}
body .select2-container--default.select2-container--focus .select2-selection--single,
body .select2-container--default.select2-container--focus .select2-selection--multiple,
body .select2-container--default.select2-container--open .select2-selection--single,
body .select2-container--default.select2-container--open .select2-selection--multiple {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: 0 0 0 3px rgba(0, 61, 143, 0.12) !important;
    outline: 0 !important;
}
body .select2-container--default .select2-selection--single .select2-selection__rendered {
    line-height: 34px !important;
    padding-left: 12px !important;
    padding-right: 28px !important;
    color: oklch(0.21 0.006 286) !important;
    font-size: 13px !important;
}
body .select2-container--default .select2-selection--single .select2-selection__placeholder {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}
body .select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 34px !important;
    right: 8px !important;
}
body .select2-container--default .select2-selection--single .select2-selection__arrow b {
    border-color: var(--muted-foreground, var(--pp-muted-fg)) transparent transparent transparent !important;
}
body .select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
    border-color: transparent transparent var(--primary, var(--pp-primary-strong)) transparent !important;
}
/* 단일 선택(single) 모드의 우측 ✕ clear 버튼은 표시하지 않음 (드롭다운 화살표만 사용) */
body .select2-container--default .select2-selection--single .select2-selection__clear {
    display: none !important;
}

/* Select2 multi-select — chip 들 */
body .select2-container--default .select2-selection--multiple {
    min-height: 36px !important;
    padding: 2px 6px !important;
}
body .select2-container--default .select2-selection--multiple .select2-selection__choice {
    /* 닫기 버튼을 라벨 오른쪽으로 — 기본 마크업 [×, LABEL] 을 시각적으로 [LABEL, ×] 로 뒤집음.
       배경/보더는 primary 톤 옅은 tint — --muted 토큰이 환경별로 녹색 oklch 로 정의될 수 있어 직접 rgba 로 명시. */
    display: inline-flex !important;
    flex-direction: row-reverse !important;
    align-items: center !important;
    gap: 10px;
    background: rgba(29, 78, 216, 0.08) !important;
    color: var(--primary, var(--pp-primary)) !important;
    border: 1px solid rgba(29, 78, 216, 0.22) !important;
    border-radius: 999px !important;
    padding: 2px 10px 2px 14px !important;       /* 라벨 좌측 14px + 닫기 우측 10px */
    font-size: 12px !important;
    font-weight: 500 !important;
    margin-top: 3px !important;
    margin-right: 4px !important;
    line-height: 1.6 !important;
    transition: background 0.12s, border-color 0.12s;
}
body .select2-container--default .select2-selection--multiple .select2-selection__choice:hover {
    background: rgba(29, 78, 216, 0.14) !important;
    border-color: rgba(29, 78, 216, 0.38) !important;
}
/* row-reverse 안에서 text node 가 라벨 — text 와 × 사이 분리 보강. text 는 margin 불가하므로 × 에 좌측 margin */
body .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
    margin-left: 4px !important;
    color: var(--primary, var(--pp-primary)) !important;
}
/* 라벨 텍스트 span (select2 4.x) — 시각적 왼쪽 여백 + primary 본문색 */
body .select2-container--default .select2-selection--multiple .select2-selection__choice__display {
    margin-left: 10px !important;
    color: var(--primary, var(--pp-primary)) !important;
}
body .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 18px;
    height: 23px;
    margin: 0 !important;
    padding: 0 !important;
    border-radius: 50% !important;
    color: var(--primary, var(--pp-primary)) !important;
    opacity: 0.65 !important;
    font-size: 13px !important;
    line-height: 1 !important;
    transition: background 0.12s, color 0.12s, opacity 0.12s;
}
body .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
    color: var(--destructive, var(--pp-tone-danger-bg)) !important;
    background: rgba(220, 38, 38, 0.10) !important;
    opacity: 1 !important;
}
body .select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
    margin-top: 8px !important;
    font-size: 13px !important;
    color: oklch(0.21 0.006 286) !important;
}

/* PPReceiverSelect — 라벨 다음 줄로 떨어지도록 block 강제 */
body .pp-receiver-select.select2-container {
    display: block !important;
    width: 100% !important;
    max-width: 500px;
    margin-top: 4px !important;
}
body .form-stack > .form-group > label.form-label,
body .form-group > label.form-label[for="recieve_others"],
body .form-group > label.form-label[for="tag_name"] {
    display: block !important;
}

/* jQuery-validate 가 input-group 내부에 주입하는 에러 라벨이 addon(단위 'min' 등) 정렬을 미세하게 틀어뜨리는 문제:
   에러 메시지는 input-group 다음 줄로 분리(입력+addon 은 한 덩어리로 라운드 유지). 빈(유효) 상태는 자리 차지 안 함. */
.input-group > label.error {
    flex-basis: 100%;
    order: 99;
    margin-top: 4px;
}
.input-group > label.error:empty {
    flex-basis: 0;
    width: 0;
    margin: 0;
    padding: 0;
}

/* PPReceiverSelect — chip 과 입력칸을 한 줄에 인라인 배치(세로 중앙), wrap 시 자연 줄바꿈 */
body .pp-receiver-select .select2-selection--multiple {
    display: block !important;
    min-height: 36px;
}
body .pp-receiver-select .select2-selection__rendered {
    display: flex !important;
    flex-wrap: wrap !important;
    align-items: center !important;
    padding-right: 6px !important;
}
body .pp-receiver-select .select2-selection__rendered .select2-selection__choice {
    margin: 2px 4px 2px 0 !important;
}
body .pp-receiver-select .select2-selection__rendered > .select2-search--inline {
    flex: 0 1 auto !important;
    margin: 0 !important;
    padding: 0 !important;
}
/* 태그 선택 입력 — 칩 옆 인라인, 텍스트 커서(캐럿) 숨김(드롭다운 선택 방식) */
body .pp-receiver-select .select2-selection__rendered > .select2-search--inline .select2-search__field {
    margin: 0 !important;
    padding: 4px 6px !important;
    box-sizing: border-box !important;
    caret-color: transparent !important;
    cursor: pointer !important;
}

/* select2 멀티셀렉트 chip 제거(x) 버튼 — 원형 pill, primary 톤 (default 테마) */
body .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 24px;
    height: 23px;
    margin: 0 !important;
    padding: 0 !important;
    border-radius: 50% !important;
    color: var(--primary, var(--pp-primary)) !important;
    opacity: 0.65 !important;
    font-size: 13px !important;
    line-height: 1 !important;
    transition: background 0.12s, color 0.12s, opacity 0.12s;
}

/* select2 inline search 인풋 — 보더/배경/포커스 ring 모두 제거 (chip 안에서 떠보이지 않게) */
body .select2-search--inline .select2-search__field,
body .select2-container .select2-search--inline .select2-search__field {
    border: 0 !important;
    outline: 0 !important;
    box-shadow: none !important;
    background: transparent !important;
}
body .select2-search--inline .select2-search__field:focus,
body .select2-container .select2-search--inline .select2-search__field:focus {
    border: 0 !important;
    outline: 0 !important;
    box-shadow: none !important;
}

/* Select2 dropdown — typeahead 와 동일 시그널 (라운드 10px + 그림자 + primary 액센트) */
body .select2-container--default .select2-dropdown {
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.16), 0 4px 10px rgba(15, 23, 42, 0.06) !important;
    overflow: hidden;
    margin-top: 4px !important;
    padding: 4px !important;
}
body .select2-container--default .select2-search--dropdown {
    padding: 4px 4px 6px !important;
}
body .select2-container--default .select2-search--dropdown .select2-search__field {
    border: 1px solid var(--pp-border) !important;
    border-radius: 6px !important;
    padding: 7px 10px !important;
    font-size: 13px !important;
    background: var(--muted, #f4f4f5) !important;
    transition: border-color 0.15s, box-shadow 0.15s;
}
body .select2-container--default .select2-search--dropdown .select2-search__field:focus {
    outline: 0 !important;
    border-color: var(--primary, var(--pp-primary)) !important;
    background: var(--pp-white) !important;
    box-shadow: 0 0 0 3px rgba(29, 78, 216, 0.15) !important;
}
body .select2-container--default .select2-results__option {
    padding: 8px 12px !important;
    font-size: 13px !important;
    color: var(--foreground, #111827) !important;
    border-radius: 6px !important;
    margin: 1px 0 !important;
    transition: background 0.12s, color 0.12s;
    position: relative;
}
body .select2-container--default .select2-results__option--highlighted[aria-selected],
body .select2-container--default .select2-results__option--highlighted {
    background: rgba(29, 78, 216, 0.08) !important;
    color: var(--foreground, #111827) !important;
}
body .select2-container--default .select2-results__option--highlighted::before {
    content: '';
    position: absolute;
    left: 0;
    top: 4px;
    bottom: 4px;
    width: 3px;
    border-radius: 2px !important;
    background: var(--primary, var(--pp-primary)) !important;
    color: var(--pp-white) !important;
}
body .select2-container--default .select2-results__option[aria-selected=true] {
    background: rgba(29, 78, 216, 0.04) !important;
    color: var(--primary, var(--pp-primary)) !important;
    font-weight: 600 !important;
}
body .select2-container--default .select2-results__option--disabled {
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    cursor: not-allowed;
}



/* ============================================================================
 * 폼 입력 표준 (SSOT) — BS5.3 form-control / form-select 단일 기준.
 * 기존 pp-21(폼 블록)·pp-override-form(중복 블록) 에서 이관·통합. 흩어진 충돌 제거.
 * canonical: height 36 · padding 4/12(컴팩트) · bg var(--card) · border 1px var(--input) ·
 *            radius 6 · color var(--foreground) · focus ring(--ring) · select 화살표(form-control+form-select).
 * 컨텍스트 한정(모달 padding, range/color/select2, 로그인, readonly/disabled[pp-50])은 각 part 유지.
 * 정본 문서: BS5.3 https://getbootstrap.com/docs/5.3/forms/form-control/
 * ============================================================================ */
.form-control, .form-select:not(.form-select-sm),
input[type="text"], input[type="number"], input[type="search"], input[type="password"],
input[type="email"], input[type="tel"], input[type="url"], input[type="datetime-local"],
input[type="date"], input[type="time"], select:not(.form-select-sm), textarea {
    height: 36px !important;            /* 표준 통일: select2/버튼/input-group/헤더와 동일 36px. form-select-sm 은 제외(28px 별도 표준) */
    padding: 6px 12px !important;

    background-color: var(--card) !important;  /* ⚠️ background 단축 금지 — 단축은 background-image 를 none 으로 리셋해 아래 select chevron(.form-select 매칭 시 specificity (0,2,0) > chevron (0,1,1))을 짓밟는다. longhand 로 background-image 보존. */
    border: 1px solid var(--input) !important;
    border-radius: 6px !important;
    color: var(--foreground) !important;
    box-shadow: none !important;
    font-size: 13px !important;
    line-height: 1.5 !important;
}
textarea.form-control, textarea { height: auto !important; min-height: 72px !important; }
/* form-select-sm — 작은 select 표준 높이 28px(카드헤더 우측 툴바 btn-sm 과 동일 높이로 통일, 오락가락 해소).
   위 36px 강제 규칙에서 .form-select-sm/select.form-select-sm 는 제외됨 → 여기서 28px 표준(강제선언 불필요). */
.form-select-sm, select.form-select-sm {
    height: 28px;
    padding: 2px 26px 2px 8px;
    font-size: 12px;
    line-height: 1.4;
    background-position: right 8px center;
}
.form-control:focus, .form-select:focus,
input[type="text"]:focus, input[type="number"]:focus, input[type="search"]:focus,
input[type="password"]:focus, input[type="email"]:focus, select:focus, textarea:focus {
    border-color: var(--ring) !important;
    box-shadow: 0 0 0 2px rgba(0, 61, 143, 0.18) !important;
    outline: 0 !important;
}
.form-control::placeholder, .form-select::placeholder, input::placeholder, textarea::placeholder {
    color: var(--muted-foreground) !important;
    opacity: 1 !important;
}
/* select 화살표 — form-control / form-select / native select 공통(SVG chevron) */
select.form-control, select.form-select, .form-select, select {
    -webkit-appearance: none !important;
    -moz-appearance: none !important;
    appearance: none !important;
    /* 화살표 chevron — base64 SVG. URL인코딩형(%3c/;utf8)이 일부 브라우저에서 invalid로 드롭돼 화살표 소실 → base64(A-Za-z0-9+/=만)로 파싱 100% 보장. 디코드: <svg ...><polyline points="6 9 12 15 18 9"/></svg> */
    background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiM2YjcyODAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cG9seWxpbmUgcG9pbnRzPSI2IDkgMTIgMTUgMTggOSIvPjwvc3ZnPg==") !important;
    background-repeat: no-repeat !important;
    background-position: right 12px center !important;
    background-size: 12px 12px !important;
    padding-right: 32px !important;
}
/* 화살표 자리 확보 — 위 `.form-select:not(.form-select-sm){padding:6px 12px}`(specificity 0,2,0) 가
   chevron 의 padding-right:32px(0,1,1) 을 이겨 텍스트가 화살표와 겹치므로, 더 높은 specificity 로 보정. */
body .form-select:not(.form-select-sm),
body select:not(.form-select-sm):not([multiple]) {
    padding-right: 32px !important;
}
select[multiple], select.form-control[multiple], select.form-select[multiple] {
    background-image: none !important;
    padding-right: 12px !important;
    height: auto !important;
}

/* ── 입력 도움말 표준: .form-text 단일 (BS5 네이티브) ──
 *    스택드 폼에서 입력 바로 아래 블록 — muted, 컴팩트. 레거시 .form-help-inline
 *    (수평폼 152px 들여쓰기 전용)을 스택드 폼에서 대체하는 표준. site/add 정본 정합. */
body #page-wrapper .form-group > .form-text {
    display: block;
    margin-top: 4px;
    font-size: 12px;
    color: var(--muted-foreground);
    line-height: 1.5;
}
body #page-wrapper .form-group > .form-text > i {
    margin-right: 4px;
}

/* ─────────────────────────────────────────────────────────────────────
 * PPTagInput — 경량 멀티 태그/수신자 선택(select2 대체). 칩 인박스 인라인 +
 * 드롭다운(상단 검색) 선택 + 박스 캐럿 없음.
 * ───────────────────────────────────────────────────────────────────── */
.pp-tag-input { position: relative; width: 100%; max-width: 500px; }
.pp-tag-input-box {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
    min-height: 36px; padding: 4px 8px;
    border: 1px solid var(--pp-border); border-radius: 6px;
    background: var(--pp-white); cursor: pointer;
}
.pp-tag-input.is-open .pp-tag-input-box {
    border-color: var(--primary, var(--pp-primary));
    box-shadow: 0 0 0 2px rgba(29, 78, 216, 0.12);
}
.pp-tag-input-placeholder { color: var(--muted-foreground, var(--pp-muted-fg)); font-size: 13px; }
.pp-tag-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 2px 6px 2px 10px; border-radius: 14px;
    /* 프라이머리(#1d4ed8)는 칩에 과하게 진해, 한 톤 낮춘 중간 프라이머리 블루(흰 텍스트 가독 유지) */
    background: oklch(0.52 0.13 260); color: var(--pp-white); font-size: 12px; line-height: 18px;
}
.pp-tag-chip-x {
    display: inline-flex; align-items: center; justify-content: center;
    width: 16px; height: 16px; border-radius: 50%;
    font-size: 11px; cursor: pointer; opacity: 0.8;
}
.pp-tag-chip-x:hover { background: rgba(255, 255, 255, 0.22); opacity: 1; }
.pp-tag-input-dropdown {
    position: absolute; z-index: 1000; left: 0; right: 0; top: calc(100% + 4px);
    max-width: 500px; padding: 6px;
    background: var(--pp-white); border: 1px solid var(--pp-border); border-radius: 8px;
    box-shadow: 0 6px 18px rgba(15, 23, 42, 0.12);
}
/* 검색 input 래퍼 — 좌측 돋보기 아이콘(장식) */
.pp-tag-input-search { position: relative; }
.pp-tag-input-search::before {
    content: '\f002';                                /* fa-magnifying-glass */
    font-family: 'Font Awesome 7 Pro', sans-serif; font-weight: 300;
    position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
    color: var(--pp-text-muted); font-size: 13px; pointer-events: none;
}
.pp-tag-input-filter {
    width: 100%; box-sizing: border-box; padding: 6px 10px 6px 30px; margin-bottom: 4px;
    border: 1px solid var(--pp-border); border-radius: 6px; font-size: 13px;
}
.pp-tag-input-options { max-height: 220px; overflow-y: auto; }
.pp-tag-option { padding: 6px 10px; border-radius: 6px; font-size: 13px; cursor: pointer; }
.pp-tag-option:hover { background: var(--pp-bg-muted); }   /* 진한 info 블루 → 테마 중립 연한 배경 */
.pp-tag-input-empty { padding: 8px 10px; text-align: center; font-size: 12px; color: var(--muted-foreground, var(--pp-muted-fg)); }

/* === pp-24-tables.css === */
/* ============================================================================
 * pp-04a-tables.css
 * 영역: 토큰 재정의(pp-bg-muted/border, primary 재매핑) / 전역 링크 / sc-switch
 *        KPI Card v2 / OPC Chip v2 / Site Card / Alarm Summary v2
 *        panel·table override / input-group / pagination / ds-tree / ds-code-block
 * 분할: 2026-05-15 (Phase 2) — 원본 pp-04-forms-tables.css 1688라인 분할
 * ============================================================================ */
/* ====================================================================== */
/* 토큰 재정의 — pp-bg-muted/border / pp-text-* (Phase 1 통합 → pp-01)    */
/* ====================================================================== */

/* ====================================================================== */
/* 전역 링크 — hover 시 underline 제거 (사용자 요청)                     */
/* ====================================================================== */
body a,
body a:link,
body a:visited {
    text-decoration: none !important;
}
body a:hover,
body a:focus,
body a:active {
    text-decoration: none !important;
}

/* ====================================================================== */
/* sc-switch 와 일반 체크박스 충돌 방지 — switch 내부 input 만 absolute 고정 */
/* ====================================================================== */
body label.sc-switch {
    position: relative;
}
body label.sc-switch > input[type="checkbox"] {
    position: absolute !important;
    opacity: 0 !important;
    width: 1px !important;
    height: 1px !important;
    margin: 0 !important;
    pointer-events: none;
}
body label.sc-switch > .sc-switch-slider {
    pointer-events: auto;
}


/* ====================================================================== */
/* 테이블 보더 톤 — BS5 .table / .table-bordered 의 셀·상하 보더 색을 부드러운 회색(--border)으로 고정. */
/* (--bs-table-border-color 를 지정하지 않으면 vendor 기본 보더가 진하게(검정 톤) 보이던 문제 — 회색 톤 통일) */
/* ====================================================================== */
.table,
.dataTables_wrapper table {
    --bs-table-border-color: var(--border) !important;
    --bs-border-color: var(--border) !important;
}

/* ====================================================================== */
/* KPI Card v2 — 대시보드 KPI 카드 (아이콘 + 추세 + 값 + 라벨)            */
/* ====================================================================== */
.kpi-card-v2 {
    background: var(--pp-white) !important;
    border: 1px solid var(--border) !important;
    border-radius: 12px !important;
    padding: 16px 18px !important;
    transition: box-shadow 0.15s, border-color 0.15s, transform 0.15s;
    margin-bottom: 16px !important;
}
.kpi-card-v2:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.06) !important;
    border-color: oklch(0.85 0.01 286) !important;
}
.kpi-card-v2-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px !important;
}
.kpi-card-v2-icon {
    width: 36px; height: 36px;
    border-radius: 10px !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 16px !important;
    flex-shrink: 0;
}
.kpi-card-v2-trend {
    font-size: 11px !important;
    font-weight: 600 !important;
}
.kpi-card-v2-value {
    font-size: 28px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    line-height: 1.05 !important;
    letter-spacing: -0.02em !important;
}
.kpi-card-v2-unit {
    font-size: 14px !important;
    color: oklch(0.55 0.016 286) !important;
    font-weight: 500 !important;
    margin-left: 3px !important;
}
.kpi-card-v2-label {
    margin-top: 8px !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    color: oklch(0.30 0.006 286) !important;
}
.kpi-card-v2-sub {
    margin-top: 2px !important;
    font-size: 11px !important;
    color: oklch(0.55 0.016 286) !important;
}

/* ====================================================================== */
/* OPC Summary Chip v2 — 카드 행 형식 (아이콘 + 라벨 + 값)               */
/* ====================================================================== */
.opc-chip-v2 {
    display: inline-flex;
    align-items: stretch;
    background: var(--pp-white) !important;
    border: 1px solid var(--border) !important;
    border-radius: 10px !important;
    overflow: hidden;
    font-size: 12px !important;
    margin-right: 8px !important;
    margin-bottom: 6px !important;
    transition: box-shadow 0.12s, border-color 0.12s;
}
.opc-chip-v2:hover {
    box-shadow: 0 2px 6px rgba(0,0,0,0.06) !important;
    border-color: oklch(0.85 0.01 286) !important;
}
.opc-chip-v2-icon {
    width: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: oklch(0.97 0.005 286) !important;
    color: oklch(0.55 0.016 286) !important;
    border-right: 1px solid var(--border) !important;
    font-size: 11px !important;
}
.opc-chip-v2-body {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 0 12px !important;
}
.opc-chip-v2-num {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: oklch(0.21 0.006 286) !important;
    line-height: 1 !important;
}
.opc-chip-v2-label {
    font-size: 11px !important;
    color: oklch(0.55 0.016 286) !important;
    font-weight: 500 !important;
}
/* 의미별 컬러 변형 */
.opc-chip-v2-ok    .opc-chip-v2-icon { background: rgba(22,163,74,0.10) !important; color: var(--pp-tone-success-bg) !important; }
.opc-chip-v2-ok    .opc-chip-v2-num  { color: var(--pp-tone-success-bg) !important; }
.opc-chip-v2-warn  .opc-chip-v2-icon { background: rgba(245,158,11,0.10) !important; color: #f59e0b !important; }
.opc-chip-v2-warn  .opc-chip-v2-num  { color: #f59e0b !important; }
.opc-chip-v2-err   .opc-chip-v2-icon { background: rgba(220,38,38,0.10) !important; color: var(--pp-tone-danger-bg) !important; }
.opc-chip-v2-err   .opc-chip-v2-num  { color: var(--pp-tone-danger-bg) !important; }
.opc-chip-v2-mute  .opc-chip-v2-icon { background: oklch(0.95 0.005 286) !important; color: oklch(0.55 0.016 286) !important; }

/* ====================================================================== */
/* Site Card — model/index 사이트 카드 (panel 스타일 X, 가벼운 카드 톤)
 *  구역 구분(top header bar + bottom footer bar) 없이 단일 카드 면.
 *  - 우상단 floating site_id 뱃지
 *  - 중앙 아이콘 + 이름 + 설명
 *  - 우하단 floating action chips (hover 에서만 노출)
 * ====================================================================== */
.model-site-card {
    position: relative;
    background: var(--pp-white) !important;
    border: 1px solid var(--border) !important;
    border-radius: 14px !important;
    overflow: hidden;
    padding: 22px 16px 18px !important;
    transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04) !important;
    cursor: pointer;
    text-align: center !important;
}
.model-site-card:hover {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: 0 8px 24px rgba(0, 61, 143, 0.10) !important;
    transform: translateY(-2px) !important;
}
.model-site-card.selected {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: 0 0 0 3px rgba(0, 61, 143, 0.12), 0 4px 12px rgba(0, 61, 143, 0.08) !important;
    transform: none !important;
}

/* site_id — 우상단 작은 뱃지 (panel header 가 아니라 floating chip) */
.model-site-title {
    position: absolute;
    top: 10px;
    left: 12px;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    background: var(--muted, #f4f4f5) !important;
    border: none !important;
    padding: 3px 8px !important;
    border-radius: 10px !important;
    letter-spacing: 0.3px !important;
    text-align: left !important;
    transition: background 0.18s, color 0.18s;
}
.model-site-card.selected .model-site-title {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}

.model-site-body {
    padding: 18px 4px 8px !important;
    text-align: center !important;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}
.model-site-body img {
    width: 56px !important;
    height: 56px !important;
    transition: transform 0.18s;
}
.model-site-card:hover .model-site-body img {
    transform: scale(1.06);
}
/* NOTE: .model-site-icon 의 기본/hover 정의는 pp-05-cards.css 로 이전 (gradient + box-shadow). 여기는 .selected 상태만 유지. */
.model-site-card.selected .model-site-icon {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}
.model-site-name {
    font-size: 14px !important;
    font-weight: 600 !important;
    color: var(--foreground, #1f2937) !important;
}
.model-site-desc {
    font-size: 12px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-top: 0 !important;
}

/* footer — 카드 하단 floating action 영역.  hover 시에만 노출 */
.model-site-footer {
    background: transparent !important;
    border-top: 0 !important;
    padding: 10px 0 0 !important;
    display: flex;
    justify-content: center;
    gap: 14px !important;
    opacity: 0.55 !important;
    transition: opacity 0.18s;
}
.model-site-card:hover .model-site-footer {
    opacity: 1 !important;
}
.model-site-footer a {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    cursor: pointer;
    transition: color 0.12s, transform 0.12s;
    font-size: 14px !important;
}
.model-site-footer a:hover {
    color: var(--primary, var(--pp-primary-strong)) !important;
    transform: scale(1.15);
}


/* ====================================================================== */
/* 이전 teal 기반 토큰 → navy primary 재매핑 (Phase 1 통합 → pp-01)       */
/* ====================================================================== */

/* ====================================================================== */
/* Alarm Summary Bar v2 — 카드 분할 형식                                  */
/* ====================================================================== */
.alarm-summary-v2 {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 8px;
}
.alarm-summary-v2-cell {
    background: var(--pp-white) !important;
    border: 1px solid var(--border) !important;
    border-left-width: 3px !important;
    border-radius: 8px !important;
    padding: 10px 14px !important;
    display: flex;
    flex-direction: column;
    gap: 2px;
    transition: box-shadow 0.12s, border-color 0.12s;
    position: relative;
}
.alarm-summary-v2-cell:hover {
    box-shadow: 0 2px 8px rgba(0,0,0,0.06) !important;
}
.alarm-summary-v2-cell > i {
    position: absolute;
    top: 10px;
    right: 12px;
    font-size: 16px !important;
    opacity: 0.45 !important;
}
.alarm-summary-v2-num {
    font-size: 22px !important;
    font-weight: 700 !important;
    line-height: 1.1 !important;
    letter-spacing: -0.01em !important;
}
.alarm-summary-v2-label {
    font-size: 11px !important;
    color: oklch(0.55 0.016 286) !important;
    font-weight: 500 !important;
}
.alarm-summary-v2-info { border-left-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; }
.alarm-summary-v2-info .alarm-summary-v2-num,
.alarm-summary-v2-info > i { color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; }
.alarm-summary-v2-warn { border-left-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; }
.alarm-summary-v2-warn .alarm-summary-v2-num,
.alarm-summary-v2-warn > i { color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; }
.alarm-summary-v2-err  { border-left-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; }
.alarm-summary-v2-err  .alarm-summary-v2-num,
.alarm-summary-v2-err  > i { color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; }


/* ============================================================
 * 사용자 요청·런타임 보정 룰 (이전 index.css 에서 이전)
 * 모든 override 는 이 파일 한곳에만 — pp-signal-theme.css 가 단일 source of truth
 * ============================================================ */


/* ─── panel 라운드 — overflow:hidden 제거 + heading/body/footer 명시 ─── */
body #page-wrapper .card,
body #page-wrapper .card.card,
body #page-wrapper .card.card-primary,
body #page-wrapper .card.card-second,
body #page-wrapper .card.card-info,
body #page-wrapper .card.card-warning,
body #page-wrapper .card.card-danger,
body #page-wrapper .card.card-success,
body #page-wrapper .card.card-dark,
body #page-wrapper .card.card-impo {
    overflow: visible !important;             /* 툴팁/드롭다운 가림 해소 */
}
body #page-wrapper .card > .card-header,
body #page-wrapper .card > .card-header:first-child {
    border-top-left-radius: 12px !important;
    border-top-right-radius: 12px !important;
}
body #page-wrapper .card > .card-body:last-child,
body #page-wrapper .card > .card-footer:last-child,
body #page-wrapper .card > .form-content-footer:last-child {
    border-bottom-left-radius: 12px !important;
    border-bottom-right-radius: 12px !important;
}
/* 컬러 헤더 — 그라데이션이 라운드 밖으로 안 새도록 자체 클립 */
body #page-wrapper .card.card-primary > .card-header,
body #page-wrapper .card.card-dark > .card-header,
body #page-wrapper .card.card-second > .card-header,
body #page-wrapper .card.card-info > .card-header,
body #page-wrapper .card.card-warning > .card-header,
body #page-wrapper .card.card-danger > .card-header,
body #page-wrapper .card.card-success > .card-header,
body #page-wrapper .card.card-impo > .card-header {
    overflow: hidden;
}

/* 패널 안 테이블 — 상단 보더 중첩 제거 */
body #page-wrapper .card > .card-body > table.table:first-child,
body #page-wrapper .card > .card-body > .table-responsive:first-child > table.table {
    margin-top: 0 !important;
}
/* 첫 thead border-top 강제 제거 룰 삭제 — 공통 패널 테이블 thead 룰이 border-top 1px 적용 */

/* 페이지네이션 — 활성 상태 톤 보정 */
body .pagination > li > a,
body .pagination > li > span {
    color: oklch(0.30 0.006 286) !important;
    background: var(--pp-white) !important;
    border-color: var(--border) !important;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
body .pagination > li > a:hover,
body .pagination > li > span:hover {
    background: var(--pp-bg-muted, oklch(0.97 0.005 286)) !important;
    border-color: var(--border) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
}
body .pagination > li.active > a,
body .pagination > li.active > span,
body .pagination > li.active > a:hover,
body .pagination > li.active > span:hover,
body .pagination > li.active > a:focus,
body .pagination > li.active > span:focus {
    background: var(--primary, var(--pp-primary-strong)) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    z-index: 2;
}
body .pagination > li.disabled > a,
body .pagination > li.disabled > span {
    color: var(--pp-text-faint, oklch(0.70 0.012 286)) !important;
    background: var(--pp-white) !important;
}

/* ─── form-content-footer — 좌/우 버튼 정렬 + margin 리셋 ─── */
body .form-content-footer {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 12px !important;
    padding: 14px 22px !important;
    background: oklch(0.97 0.005 286) !important;
    border-top: 1px solid var(--border) !important;
    margin: 0 !important;                            /* 이전 negative margin 무력화 */
    border-bottom-left-radius: 12px !important;
    border-bottom-right-radius: 12px !important;
}
/* form-content-footer 가 panel-body 안에 있을 때 — body 패딩만큼 확장 */
body .card > .card-body > .form-content-footer:last-child,
body .card-body > .form-content-footer {
    margin: 14px -22px -14px !important;
}
/* form-content-footer 가 panel 직접 자식이면 margin 0 — panel 끝까지 자연스럽게 */
body .card > .form-content-footer {
    margin: 0 !important;
}
body .form-content-footer-left,
body .form-content-footer-right {
    display: inline-flex !important;
    align-items: center !important;
    gap: 8px !important;
}
body .form-content-footer-left { justify-content: flex-start; }
body .form-content-footer-right { justify-content: flex-end; }

/* 변형: 배경/보더 없는 footer (버튼만 노출 — 패널 좌우 정렬과 동일) */
body .form-content-footer.form-content-footer-bare {
    background: transparent !important;
    border-top: 0 !important;
    border-radius: 0 !important;
    padding: 14px 22px !important;
    margin: 0 !important;
}
body .form-content-footer .btn {
    height: 36px !important;
    line-height: 1 !important;
    margin: 0 !important;
}

/* ─── input-group-addon — 모든 인스턴스 zinc 강제 (teal 잔재 완전 제거) ─── */
body .input-group-text,
body span.input-group-text,
body div.input-group-text,
body .input-group > .input-group-text {
    background: oklch(0.97 0.005 286) !important;     /* zinc-50 */
    border-color: oklch(0.91 0.008 286) !important;   /* zinc-200 */
    color: oklch(0.45 0.01 286) !important;
}
body .input-group-text i,
body .input-group-text .fa-light,
body .input-group-text .fa-light,
body .input-group-text .fa-light {
    color: oklch(0.45 0.01 286) !important;
}

/* ─── ds-drawer-footer — position: fixed 로 viewport 하단 고정 ─── */
body .ds-drawer-footer {
    box-shadow: 0 -2px 6px rgba(15, 23, 42, 0.04) !important;
    position: fixed;
    bottom: 0;
    width: 100%;
}

/* ─── ds-pill 좌측 — 명시적 zinc 톤 ─── */
body .ds-pill-l {
    background: oklch(0.97 0.005 286) !important;
}

/* ─── dropdown — 컬러 버튼 위 caret 흰색 ─── */
body .btn-primary .caret,
body .btn-danger .caret,
body .btn-success .caret,
body .btn-info .caret,
body .btn-warning .caret,
body .btn-dark .caret {
    border-top-color: var(--pp-white) !important;
}
body .btn-primary.dropdown-toggle:hover .caret,
body .btn-primary.dropdown-toggle:focus .caret {
    border-top-color: var(--pp-white) !important;
}

/* ─── Badge / Pill — 드롭섀도우 (Signal devops 톤) ─── */
body .badge,
body .health-badge,
body .conn-badge-ok,
body .conn-badge-warn,
body .conn-badge-error,
body .conn-badge-disconnected,
body .conn-badge-unknown {
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.08) !important;
}

/* ─── Progress Bar — 깔끔한 톤 ─── */
body .progress {
    height: 8px !important;
    background: oklch(0.94 0.005 286) !important;
    border-radius: 999px !important;
    overflow: hidden;
    box-shadow: none !important;
    margin-bottom: 0 !important;
}
body .progress-bar {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    line-height: 8px !important;
    border-radius: 999px !important;
    box-shadow: none !important;
    transition: width 0.4s cubic-bezier(.4, 0, .2, 1);
}
body .progress-bar-success { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
body .progress-bar-warning { background: #f59e0b !important; }
body .progress-bar-danger  { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
body .progress-bar-info    { background: #0ea5e9 !important; }
body .progress-bar.progress-bar-striped {
    background-image: linear-gradient(45deg,
        rgba(255,255,255,0.18) 25%, transparent 25%,
        transparent 50%, rgba(255,255,255,0.18) 50%,
        rgba(255,255,255,0.18) 75%, transparent 75%, transparent) !important;
    background-size: 14px 14px !important;
}
body .progress-bar.active,
body .progress-bar.progress-bar-striped.active {
    animation: progress-stripes 1.5s linear infinite;
}
@keyframes progress-stripes {
    from { background-position: 0 0; }
    to   { background-position: 14px 0; }
}

/* ─── Alert (긴 형식: h4 + 본문) — divider 색상 + 상하 패딩 ─── */
body .alert h4 {
    margin: 0 0 8px !important;
    padding-bottom: 8px !important;
    font-size: 14px !important;
    font-weight: 600 !important;
    border-bottom: 1px solid currentColor !important;
    border-bottom-color: rgba(0, 0, 0, 0.08) !important;
}
body .alert-info h4    { border-bottom-color: rgba(2, 132, 199, 0.25) !important; }
body .alert-success h4 { border-bottom-color: rgba(22, 163, 74, 0.25) !important; }
body .alert-warning h4 { border-bottom-color: rgba(217, 119, 6, 0.25) !important; }
body .alert-danger h4  { border-bottom-color: rgba(220, 38, 38, 0.25) !important; }

body .alert .alert-warnning-line {
    display: none !important;            /* h4 의 border-bottom 으로 대체 */
}
body .alert > div:not(.alert-warnning-line) {
    padding-top: 4px !important;
    padding-bottom: 2px !important;
}

/* ─── Badge — 컬러 배경 위 항상 흰 텍스트 ─── */
body .badge {
    color: var(--pp-white) !important;
}
body .badge[style*="background"] {
    color: var(--pp-white) !important;
}
/* ─── Pagination — 좌우 버튼 딱 붙임 (gap 0) ─── */
body .pagination {
    display: inline-flex;
    margin: 0 !important;
    padding: 0 !important;
    border-radius: 6px !important;
    overflow: hidden;
}
body .pagination > li {
    display: inline-block;
    margin: 0 !important;
}
body .pagination > li > a,
body .pagination > li > span {
    margin: 0 !important;
    border-radius: 0 !important;
    border-right: 0 !important;
    padding: 6px 12px !important;
    line-height: 1.4 !important;
}
body .pagination > li:first-child > a,
body .pagination > li:first-child > span {
    border-top-left-radius: 6px !important;
    border-bottom-left-radius: 6px !important;
}
body .pagination > li:last-child > a,
body .pagination > li:last-child > span {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
    border-right: 1px solid var(--border) !important;
}

/* ============================================================
 * Tree View — 들여쓰기 + 토글 + 아이콘
 * ============================================================ */
.ds-tree {
    list-style: none;
    margin: 0 !important;
    padding: 0 !important;
}
.ds-tree-node {
    position: relative;
}
.ds-tree-node > .ds-tree-toggle,
.ds-tree-node > .ds-tree-label {
    display: inline-block;
    vertical-align: middle;
}
.ds-tree-toggle {
    width: 18px;
    text-align: center !important;
    color: oklch(0.55 0.016 286) !important;
    font-size: 10px !important;
    cursor: pointer;
    transition: transform 0.15s;
}
.ds-tree-toggle:hover { color: var(--primary, var(--pp-primary-strong)) !important; }
.ds-tree-label {
    font-size: 13px !important;
    color: oklch(0.30 0.006 286) !important;
    padding: 3px 8px !important;
    border-radius: 4px !important;
    cursor: pointer;
}
.ds-tree-node:hover > .ds-tree-label { background: oklch(0.97 0.005 286) !important; }
.ds-tree-node.ds-tree-selected > .ds-tree-label {
    background: rgba(0, 61, 143, 0.10) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    font-weight: 500 !important;
}

/* ============================================================
 * Code Block (헤더 + 복사 버튼 + 다크 변형)
 * ============================================================ */
.ds-code-block {
    border: 1px solid var(--border) !important;
    border-radius: 8px !important;
    overflow: hidden;
    margin-bottom: 14px !important;
    background: oklch(0.97 0.005 286) !important;
}
.ds-code-block-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 6px 14px !important;
    background: var(--pp-white) !important;
    border-bottom: 1px solid var(--border) !important;
    font-size: 11px !important;
    font-weight: 500 !important;
    color: oklch(0.55 0.016 286) !important;
}
.ds-code-block-lang i { margin-right: 4px !important; }
.ds-code-block-copy {
    background: transparent !important;
    border: 1px solid var(--border) !important;
    color: oklch(0.30 0.006 286) !important;
    padding: 3px 10px !important;
    border-radius: 4px !important;
    font-size: 11px !important;
    cursor: pointer;
    transition: all 0.12s;
}
.ds-code-block-copy:hover {
    background: oklch(0.97 0.005 286) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
}

/* ============================================================
 * 일반 테이블(데이터테이블 제외) 마지막 행 하단 보더 제거
 *   예: <table class="table tag-current-table"> — 카드/영역 바닥에
 *   불필요한 구분선이 남던 문제. DataTables 는 자체 페이징 푸터가 있어 제외.
 * ============================================================ */
.table:not(.dataTable) > tbody > tr:last-child > td,
.table:not(.dataTable) > tbody > tr:last-child > th {
    border-bottom: 0 !important;
}

/* === pp-25-cards.css === */
/* ============================================================================
 * pp-05-cards.css
 * 영역: ds-code-block 후속 / form-validation / toast / id-badge / dialog-form
 *        checkbox·radio / 버튼 변형 / dropdown / fieldset+legend / site-card-grid
 *        jstree 톤 매핑 / panel-table 보더 / 버튼 active / Hero / conn-badge / Hero v2
 * 분할: 2026-05-15 (Phase 2) — 원본 pp-05-cards-badges.css 2120라인 분할
 * ============================================================================ */
.ds-code-block-copy.copied {
    background: var(--pp-tone-success-bg) !important;
    border-color: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important;
}
.ds-code-block-body {
    margin: 0 !important;
    padding: 14px 16px !important;
    background: oklch(0.97 0.005 286) !important;
    color: oklch(0.21 0.006 286) !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 12px !important;
    line-height: 1.6 !important;
    overflow-x: auto;
    white-space: pre !important;
    border: 0 !important;
    border-radius: 0 !important;
}
.ds-code-block-dark .ds-code-block-head {
    background: oklch(0.21 0.006 286) !important;
    color: oklch(0.85 0.005 286) !important;
    border-bottom-color: oklch(0.30 0.006 286) !important;
}
.ds-code-block-dark .ds-code-block-copy {
    background: transparent !important;
    border-color: oklch(0.30 0.006 286) !important;
    color: oklch(0.85 0.005 286) !important;
}
.ds-code-block-dark .ds-code-block-copy:hover {
    border-color: oklch(0.55 0.016 286) !important;
    color: var(--pp-white) !important;
}
.ds-code-block-dark .ds-code-block-body {
    background: oklch(0.18 0.01 286) !important;
    color: oklch(0.92 0.005 286) !important;
}
.ds-diff-add     { background: rgba(22, 163, 74, 0.12) !important; color: #166534 !important; display: block; }
.ds-diff-del     { background: rgba(220, 38, 38, 0.12) !important; color: #991b1b !important; display: block; }
.ds-diff-context { display: block; }

/* ============================================================
 * Form Validation 상태
 * ============================================================ */
body .form-group.has-success .form-control,
body .form-inline.has-success .form-control,
body .pp-form-row.has-success .form-control {
    border-color: var(--pp-tone-success-bg) !important;
    box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.12) !important;
}
body form-control.is-invalid,
body .form-control.is-invalid,
body .form-select.is-invalid,
body select.is-invalid,
body .form-control.error,
body .form-select.error,
body select.error,
body input.form-control.error,
body select.form-control.error,
body textarea.form-control.error {
    border-color: var(--pp-tone-danger-bg) !important;
    background-color: rgba(220, 38, 38, 0.04) !important;
    /* 보더 굵기 / box-sizing 강제 — 검증 실패 시 입력 박스 사이즈 변동 방지 (ring shadow 제거) */
    box-sizing: border-box !important;
    border-width: 1px !important;
    border-style: solid !important;
    box-shadow: none !important;
}
/* 텍스트 인풋/textarea — BS5 기본 is-invalid ! 아이콘(background-image) 제거.
   앱은 PP.validate 가 .pp-error-tip(fa-exclamation-circle, 툴팁) 아이콘을 별도로 우측에 붙이므로
   둘이 겹쳐 ! 가 2개로 보이던 문제(select 은 chevron 이 BS5 ! 를 덮어 1개). select 은 chevron 보존 위해 제외. */
body input.form-control.is-invalid, body textarea.form-control.is-invalid,
body input.form-control.error, body textarea.form-control.error {
    background-image: none;
}
/* 포커스 시에만 옅은 ring (사이즈 영향 적음) */
body form-control.is-invalid:focus,
body .form-control.is-invalid:focus,
body .form-select.is-invalid:focus,
body select.is-invalid:focus,
body .form-control.error:focus {
    box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.18) !important;
}
body .form-group.has-warning .form-control,
body .form-inline.has-warning .form-control,
body .pp-form-row.has-warning .form-control {
    border-color: #f59e0b !important;
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.12) !important;
}

/* jquery.validate 가 부모 컨테이너 미존재시 input 자체에 .error 만 주는 경우 대비 */
body .form-control.error:focus,
body .form-control.is-invalid:focus {
    outline: none !important;
    border-color: var(--pp-tone-danger-bg) !important;
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.18) !important;
}

body .ds-help-success { color: var(--pp-tone-success-bg) !important; font-size: 11px !important; margin-top: 4px !important; }
body .ds-help-error   { color: var(--pp-tone-danger-bg) !important; font-size: 11px !important; margin-top: 4px !important; }
body .ds-help-warning { color: var(--pp-tone-warn-bg) !important; font-size: 11px !important; margin-top: 4px !important; }
body .ds-help-meta    { color: oklch(0.55 0.016 286) !important; font-size: 11px !important; margin-top: 4px !important; }
body .ds-help-required { color: var(--pp-tone-danger-bg) !important; }

/* toastr 라이브러리 톤 통일 */
body .toast {
    border-radius: 8px !important;
    box-shadow: 0 4px 12px rgba(0,0,0,0.10) !important;
    background-image: none !important;
    padding: 12px 16px 12px 50px !important;
    background-position: 14px center !important;
}
body .toast-success { background-color: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
body .toast-info    { background-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important; }
body .toast-warning { background-color: #f59e0b !important; }
body .toast-error   { background-color: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }


/* ============================================================
 * id-badge — 도메인 ID (좌측 5px primary 보더 + 흰 배경 + 모노스페이스)
 * ID 는 도메인 식별의 핵심 — 좌측 컬러 액센트로 시각 강조
 * ============================================================ */
body .id-badge {
    display: inline-flex !important;
    align-items: center;
    padding: 2px 10px !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-left: 3px solid var(--primary, var(--pp-primary-strong)) !important;
    border-radius: 12px !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    line-height: 1.6 !important;
    letter-spacing: 0.3px !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    text-shadow: none !important;
    transition: border-color 0.12s, box-shadow 0.12s, background 0.12s;
    cursor: default;
}
body .id-badge:hover {
    background: oklch(0.99 0.003 286) !important;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08) !important;
}
/* 도메인 리딩 아이콘 (FA7 Pro light) — 도메인 유형 인지용. 기본 tag, 도메인별 override(아래). */
body .id-badge::before {
    font-family: "Font Awesome 7 Pro";
    font-weight: 300;
    font-size: 0.95em;
    margin-right: 5px;
    content: "\f02b";
    color: var(--muted-foreground);
}
body .id-badge[data-domain-type="SITE"]::before  { content: "\f275"; }
body .id-badge[data-domain-type="ASSET"]::before { content: "\f8a4"; }
body .id-badge[data-domain-type="EQUIPMENT"]::before { content: "\f8a4"; }
body .id-badge[data-domain-type="AREA"]::before  { content: "\e009"; }
body .id-badge[data-domain-type="LINE"]::before  { content: "\f46f"; }
body .id-badge[data-domain-type="CUSTOMER"]::before { content: "\f2b5"; }
body .id-badge[data-domain-type="EMPLOYEE"]::before { content: "\f2c2"; }
body .id-badge[data-domain-type="CALENDAR"]::before { content: "\f133"; }
body .id-badge[data-domain-type="OPC"]::before   { content: "\f1b3"; }
body .id-badge[data-domain-type="TAG"]::before   { content: "\f02b"; }
body .id-badge[data-domain-type="EDGE"]::before  { content: "\f8da"; }
body .id-badge[data-domain-type="ALARM"]::before        { content: "\f0f3"; }
body .id-badge[data-domain-type="ALARM_CONFIG"]::before { content: "\f0f3"; }
body .id-badge[data-domain-type="ORDER"]::before   { content: "\f46d"; }
body .id-badge[data-domain-type="PRODUCT"]::before { content: "\f466"; }
body .id-badge[data-domain-type="BLOB"]::before    { content: "\f15b"; }
body .id-badge[data-domain-type="USER"]::before    { content: "\f007"; }
body .id-badge[data-domain-type="FLOW"]::before    { content: "\f542"; }  /* fa-diagram-project (project-diagram) */
/* 도메인별 좌측 보더 컬러 */
body .id-badge[data-domain-type="SITE"]  { border-left-color: var(--pp-tone-success-bg) !important; }
body .id-badge[data-domain-type="ASSET"] { border-left-color: var(--pp-tone-warn-bg) !important; }
body .id-badge[data-domain-type="OPC"]   { border-left-color: var(--primary, var(--pp-primary-strong)) !important; }
body .id-badge[data-domain-type="TAG"]   { border-left-color: #7c3aed !important; }
body .id-badge[data-domain-type="EDGE"]  { border-left-color: #0891b2 !important; }
body .id-badge[data-domain-type="ALARM"] { border-left-color: var(--pp-tone-danger-bg) !important; }
body .id-badge[data-domain-type="USER"]  { border-left-color: oklch(0.30 0.006 286) !important; }
body .id-badge[data-domain-type="ORDER"] { border-left-color: #f59e0b !important; }
body .id-badge[data-domain-type="FLOW"]  { border-left-color: #14b8a6 !important; }
body .id-badge[data-domain-type="BLOB"]  { border-left-color: #8b5cf6 !important; }


/* ============================================================
 * 다이얼로그 내부 폼 — 라벨/입력 상하(vertical) 레이아웃 강제
 * (BootstrapDialog + bootstrap modal 공통)
 * - 적용 범위: .bootstrap-dialog 와 .modal 내부 **만** (페이지 본문 폼 영향 X)
 * - 라벨 상단 (block) + 입력 풀폭
 * - form-inline / form-horizontal 도 dialog 내부에서는 block 동작
 * ============================================================ */

/* form-inline / form-group 컨테이너 — block + 풀폭 */
body .bootstrap-dialog .form-inline,
body .bootstrap-dialog .form-group,
body .modal .form-inline,
body .modal .form-group,
body .bootstrap-dialog .pp-form-row,
body .modal .pp-form-row {
    display: block !important;
    width: 100% !important;
    margin-bottom: 14px !important;
    flex-wrap: nowrap !important;
}

/* 라벨 (control-label / form-label / col-sm-* 라벨) — block + 좌측 정렬 + 표준 크기 */
body .bootstrap-dialog label.form-label,
body .bootstrap-dialog .form-group > label,
body .modal label.form-label,
body .modal .form-group > label {
    display: block !important;
    width: auto !important;
    min-width: 0 !important;
    max-width: 100% !important;
    margin: 0 0 6px 0 !important;
    text-align: left !important;
    line-height: 1.4 !important;
    /* 라벨 표준 크기 — 페이지 내 #page-wrapper 라벨과 동일 시그널 */
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    flex: none !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    float: none !important;
    letter-spacing: 0.01em !important;
}

/* 입력 (input/select/textarea) + Bootstrap form-control — 풀폭 */
body .bootstrap-dialog .form-inline > .form-control,
body .bootstrap-dialog .form-inline > input,
body .bootstrap-dialog .form-inline > select,
body .bootstrap-dialog .form-inline > textarea,
body .bootstrap-dialog .form-group > .form-control,
body .bootstrap-dialog .form-group > input.form-control,
body .bootstrap-dialog .form-group > select.form-control,
body .bootstrap-dialog .form-group > textarea.form-control,
body .modal .form-inline > .form-control,
body .modal .form-group > .form-control,
body .modal .form-group > input.form-control,
body .modal .form-group > select.form-control,
body .modal .form-group > textarea.form-control,
body .bootstrap-dialog .pp-form-row > .form-control,
body .bootstrap-dialog .pp-form-row > input,
body .bootstrap-dialog .pp-form-row > select,
body .bootstrap-dialog .pp-form-row > textarea,
body .modal .pp-form-row > .form-control {
    width: 100% !important;
    max-width: 100% !important;
    display: block !important;
}

/* Bootstrap 3 form-horizontal 의 col-sm-* 래퍼 — 다이얼로그 안에서 풀폭 */
body .bootstrap-dialog .form-group > [class*="col-"],
body .modal .form-group > [class*="col-"] {
    width: 100% !important;
    float: none !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
}

/* 다이얼로그 안 모든 form-group 의 form-control wrapper (col-* 안의 input) */
body .bootstrap-dialog .form-group [class*="col-"] > .form-control,
body .modal .form-group [class*="col-"] > .form-control {
    width: 100% !important;
}

/* form-inline 내부 form-group 도 풀폭 — gap 제거 */
body .bootstrap-dialog .form-inline > .form-group,
body .modal .form-inline > .form-group,
body .bootstrap-dialog .pp-form-row > .form-group,
body .modal .pp-form-row > .form-group {
    display: block !important;
    width: 100% !important;
    margin-right: 0 !important;
    margin-left: 0 !important;
}

/* 체크박스/라디오 줄은 가로 유지 — vertical 강제에서 제외 */
body .bootstrap-dialog .form-group.form-check-inline,
body .bootstrap-dialog .checkbox,
body .bootstrap-dialog .radio,
body .modal .form-group.form-check-inline,
body .modal .checkbox,
body .modal .radio {
    display: flex !important;
    align-items: center;
    width: auto !important;
}
body .bootstrap-dialog .checkbox > label,
body .bootstrap-dialog .radio > label,
body .modal .checkbox > label,
body .modal .radio > label {
    display: inline-flex !important;
    margin: 0 !important;
}


/* ============================================================
 * Checkbox / Radio — shadcn 스타일 네이티브 (iCheck 제거)
 * - accent-color 로 시스템 컨트롤에 디자인 토큰 입힘
 * - 라벨 가로 정렬 + 클릭 가능 영역 확장
 * ============================================================ */
body input[type="checkbox"],
body input[type="radio"] {
    appearance: auto;
    -webkit-appearance: auto;
    accent-color: var(--primary, var(--pp-primary-strong));
    width: 16px;
    height: 16px;
    margin: 0 6px 0 0 !important;
    vertical-align: middle;
    cursor: pointer;
    flex-shrink: 0;
}
body input[type="checkbox"]:focus-visible,
body input[type="radio"]:focus-visible {
    outline: 2px solid var(--ring, var(--primary)) !important;
    outline-offset: 2px !important;
    border-radius: 3px !important;
}
body input[type="checkbox"]:disabled,
body input[type="radio"]:disabled {
    opacity: 0.5 !important;
    cursor: not-allowed;
}

/* 체크박스/라디오 + 라벨 가로 정렬 (label > input + 텍스트 패턴) */
body label > input[type="checkbox"],
body label > input[type="radio"],
body .checkbox label > input[type="checkbox"],
body .radio label > input[type="radio"] {
    position: static !important;
    margin-left: 0 !important;
}
body .checkbox,
body .radio {
    margin: 6px 0 !important;
}
body .checkbox label,
body .radio label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding-left: 0 !important;
    font-weight: 400 !important;
    cursor: pointer;
}
body .checkbox-inline,
body .radio-inline {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding-left: 0 !important;
    margin-right: 12px !important;
    font-weight: 400 !important;
}


/* ============================================================
 * 버튼 — shadcn/ui 추가 변형 + 강화 hover/disabled + 사이즈 일관성
 * (기본 .btn / .btn-primary / .btn-secondary 정의는 pp-03-panels.css)
 * ============================================================ */

/* ---- A) Ghost / Link 변형 ----------------------- */

/* btn-ghost — 투명 + hover 시 muted bg (툴바·아이콘 버튼) */
body .btn-ghost {
    background: transparent !important;
    color: var(--foreground) !important;
    border: 1px solid transparent !important;
}
body .btn-ghost:hover,
body .btn-ghost:focus {
    background: var(--muted) !important;
    color: var(--foreground) !important;
    border-color: transparent !important;
}

/* btn-link — 텍스트 링크 */
body .btn-link {
    background: transparent !important;
    border: 1px solid transparent !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    text-decoration: none !important;
    padding: 4px 6px !important;
    box-shadow: none !important;
}
body .btn-link:hover,
body .btn-link:focus {
    background: transparent !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    text-decoration: underline !important;
}

/* ---- B) Hover/Disabled 강화 ------------------------------- */

/* 명확한 hover — 한 톤 어둡게 */
body .btn-primary:hover,
body .btn-primary:focus {
    background: oklch(28% 0.10 260) !important;     /* primary 한 단계 어둡게 */
    border-color: oklch(28% 0.10 260) !important;
    color: var(--pp-white) !important;
    filter: none !important;
}
body .btn-secondary:hover,
body .btn-secondary:focus {
    background: var(--muted) !important;
    border-color: var(--ring, var(--primary)) !important;
    color: var(--foreground) !important;
}
body .btn-danger:hover,
body .btn-danger:focus {
    background: oklch(43% 0.17 27) !important;
    border-color: oklch(43% 0.17 27) !important;
    color: var(--pp-white) !important;
}
body .btn-success:hover,
body .btn-success:focus {
    background: oklch(52% 0.18 145) !important;
    border-color: oklch(52% 0.18 145) !important;
    color: var(--pp-white) !important;
}
body .btn-warning:hover,
body .btn-warning:focus {
    background: #b45309 !important;
    border-color: #b45309 !important;
    color: var(--pp-white) !important;
}
body .btn-info:hover,
body .btn-info:focus {
    background: #0369a1 !important;
    border-color: #0369a1 !important;
    color: var(--pp-white) !important;
}

/* Disabled — shadcn 스타일 (opacity 0.5 + 클릭 차단) */
body .btn:disabled,
body .btn.disabled,
body .btn[disabled] {
    opacity: 0.5 !important;
    pointer-events: none !important;
    cursor: not-allowed !important;
    filter: none !important;
}

/* ---- C) 사이즈 일관성 ------------------------------------- */
body .btn-lg {
    padding: 10px 18px !important;
    font-size: 14px !important;
    border-radius: 8px !important;
    line-height: 1.2 !important;
}
body .btn-sm {
    padding: 5px 10px !important;
    font-size: 11.5px !important;
    border-radius: 5px !important;
    line-height: 1.2 !important;
}
body .btn-xs {
    padding: 3px 8px !important;
    font-size: 10.5px !important;
    border-radius: 4px !important;
    line-height: 1.2 !important;
}

/* 아이콘 전용 버튼 — 정사각형 */
body .btn.btn-icon-only {
    width: 32px;
    padding-left: 0 !important;
    padding-right: 0 !important;
    justify-content: center;
}
body .btn-sm.btn-icon-only { width: 28px; }
body .btn-xs.btn-icon-only { width: 24px; }
body .btn-lg.btn-icon-only { width: 40px; }


/* ============================================================
 * Dropdown 컨텍스트 메뉴 — shadcn/ui 스타일
 *   - 둥근 모서리(8px) + 미세 보더 + soft shadow
 *   - 내부 4px padding, 아이템 6px 라운드 + hover 시 muted bg
 *   - typeahead / 토픽 dropdown(#nav-toolbar 등) 은 자체 룰로 별도
 * ============================================================ */
body .dropdown-menu {
    min-width: 180px;
    padding: 4px !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 8px !important;
    background: var(--popover, var(--pp-white)) !important;
    box-shadow:
        0 10px 25px -5px rgba(15, 23, 42, 0.12),
        0 4px 10px -3px rgba(15, 23, 42, 0.08),
        0 0 0 1px rgba(15, 23, 42, 0.02) !important;
    font-size: 13px !important;
    color: var(--foreground) !important;
    overflow: hidden;
}
body .dropdown-menu > li > a {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px !important;
    border-radius: 6px !important;
    color: var(--foreground) !important;
    font-size: 13px !important;
    line-height: 1.3 !important;
    transition: background-color 0.12s, color 0.12s;
}
body .dropdown-menu > li > a > i,
body .dropdown-menu > li > a > .fa-light,
body .dropdown-menu > li > a > .fa-brands {
    font-size: 13px !important;
    width: 14px;
    text-align: center !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    flex-shrink: 0;
}
body .dropdown-menu > li > a:hover,
body .dropdown-menu > li > a:focus {
    background: var(--muted, oklch(0.96 0.005 286)) !important;
    color: var(--foreground) !important;
}
body .dropdown-menu > li > a:hover > i,
body .dropdown-menu > li > a:focus > i,
body .dropdown-menu > li > a:hover > .fa-light,
body .dropdown-menu > li > a:focus > .fa-light {
    color: var(--foreground) !important;
}
body .dropdown-menu > li.active > a,
body .dropdown-menu > li.active > a:hover,
body .dropdown-menu > li.active > a:focus {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}
body .dropdown-menu > li.active > a > i {
    color: rgba(255, 255, 255, 0.8) !important;
}
body .dropdown-menu > li.disabled > a,
body .dropdown-menu > li.disabled > a:hover {
    color: var(--muted-foreground, #9ca3af) !important;
    background: transparent !important;
    cursor: not-allowed;
}
body .dropdown-menu .divider {
    height: 1px;
    margin: 4px 2px !important;
    background-color: var(--border, var(--pp-border)) !important;
}
body .dropdown-menu .dropdown-header {
    padding: 6px 10px 4px !important;
    font-size: 10.5px !important;
    font-weight: 700 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.04em !important;
    color: var(--muted-foreground, #9ca3af) !important;
}

/* 등장 애니메이션 — open 시 살짝 아래에서 페이드 인 */
body .open > .dropdown-menu,
body .dropdown.open > .dropdown-menu {
    animation: pp-dropdown-in 120ms ease-out both;
    transform-origin: top left;
}
@keyframes pp-dropdown-in {
    from { opacity: 0; transform: translateY(-4px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0)    scale(1); }
}


/* ============================================================
 * Dropdown 버튼 — caret 좌측에 ::before 분리선 (caret 모양 유지)
 * 좌우 갭 균형: 분리선↔caret = caret↔버튼우측 = 10px
 * ============================================================ */
body .btn.dropdown-toggle {
    padding-right: 14px !important;    /* caret 우측 갭 — 좌측 분리선↔caret 갭(14px) 과 균형 */
}
/* Bootstrap caret 의 보이지 않는 border-right:4px transparent 상쇄 */
body .btn.dropdown-toggle .caret {
    margin-right: -4px !important;
}
body .btn.dropdown-toggle.btn-icon-only,
body .btn-icon-only.dropdown-toggle {
    padding-right: 0 !important;        /* 아이콘 전용 토글은 영향 없음 */
}
body .btn.dropdown-toggle .caret {
    margin-left: 20px !important;        /* 텍스트→caret 갭 — 분리선 좌측 여유 확보 */
    position: relative;
    /* Bootstrap 3 default caret 보더 유지 — 절대 건드리지 않음 */
}
body .btn.dropdown-toggle .caret::before {
    content: '';
    position: absolute;
    left: -12px;       /* 분리선 ↔ caret 가시 삼각형 갭 +2px */
    top: -7px;
    bottom: -7px;
    width: 1px;
    background: rgba(255, 255, 255, 0.30) !important;
}
body .btn-secondary.dropdown-toggle .caret::before,
body .btn-link.dropdown-toggle .caret::before {
    background: rgba(0, 0, 0, 0.12) !important;
}


/* ============================================================
 * fieldset + legend 안 panel-body 정렬 — 좌우 패딩 통일
 * 기본 fieldset 은 보더/패딩 0, legend 는 panel-body 와 좌측 정렬
 * ============================================================ */
body .card-body > fieldset,
body .card > .card-body > fieldset {
    border: 0 !important;
    padding: 0 !important;
    margin: 0 0 14px !important;
    min-width: 0;
}
body .card-body > fieldset + fieldset,
body .card > .card-body > fieldset + fieldset {
    margin-top: 28px !important;
    padding-top: 20px !important;
}
body .card-body > fieldset:last-child,
body .card > .card-body > fieldset:last-child {
    margin-bottom: 0 !important;
}

/* 마지막 fieldset 안의 마지막 form-inline 의 trailing margin 제거 — 패널 바닥 여백 정돈 */
body .card-body > fieldset:last-child .form-inline:last-child,
body .card > .card-body > fieldset:last-child .form-inline:last-child,
body .card-body > fieldset:last-child .pp-form-row:last-child,
body .card > .card-body > fieldset:last-child .pp-form-row:last-child {
    margin-bottom: 0 !important;
}

/* 모든 fieldset 의 마지막 .form-help-inline trailing 도 제거 */
body .card-body > fieldset:last-child > .form-help-inline:last-child,
body .card > .card-body > fieldset:last-child > .form-help-inline:last-child {
    margin-bottom: 0 !important;
}
body .card-body > fieldset > legend,
body .card > .card-body > fieldset > legend {
    width: 100%;
    border-bottom: 1px dashed var(--border, var(--pp-border)) !important;
    padding: 0 0 6px !important;
    margin: 0 0 12px !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    color: oklch(0.30 0.006 286) !important;
    line-height: 1.4 !important;
}
body .card-body > fieldset > legend > i {
    color: var(--primary, var(--pp-primary-strong)) !important;
    margin-right: 6px !important;
    font-size: 12px !important;
}
/* fieldset 내부 form-inline — 좌우 정렬을 panel-body 와 같이 */
body .card-body > fieldset .form-inline,
body .card-body > fieldset .pp-form-row {
    margin-bottom: 8px !important;
}
body .card-body > fieldset .form-inline:last-child,
body .card-body > fieldset .pp-form-row:last-child {
    margin-bottom: 0 !important;
}

/* panel-body 직접 자식 form-inline — fieldset 미사용 시 동일한 행간 보장 */
body .card-body > .form-inline,
body .card-body > .pp-form-row {
    margin-bottom: 8px !important;
}
body .card-body > .form-inline:last-child,
body .card-body > .pp-form-row:last-child {
    margin-bottom: 0 !important;
}


/* ============================================================
 * Site Card Grid — 글로벌 (디자인 시스템 + /model/index 공통)
 * ============================================================ */
.model-site-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
}
@media (max-width: 1199px) {
    .model-site-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 991px) {
    .model-site-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575px) {
    .model-site-grid { grid-template-columns: 1fr; }
}
.model-site-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 14px !important;
    background: linear-gradient(135deg, rgba(0, 61, 143, 0.10), rgba(0, 61, 143, 0.04)) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    font-size: 22px !important;
    margin: 0 auto 10px !important;
    border: 1px solid rgba(0, 61, 143, 0.12) !important;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.model-site-card:hover .model-site-icon {
    transform: scale(1.06);
    box-shadow: 0 4px 12px rgba(0, 61, 143, 0.10) !important;
}


/* ============================================================
 * jstree — ds-tree 톤 매핑 (asset/tree.jsp 등 실제 사용처)
 * ============================================================ */
body .jstree-default,
body .jstree-default-dark {
    font-size: 14px !important;
    color: oklch(0.30 0.006 286) !important;
}
body .jstree-default .jstree-anchor {
    height: 26px !important;
    line-height: 26px !important;
    padding: 0 8px !important;
    border-radius: 4px !important;
    color: oklch(0.30 0.006 286) !important;
    font-weight: 400 !important;
    transition: background 0.1s, color 0.1s;
}
body .jstree-default .jstree-anchor:hover,
body .jstree-default .jstree-hovered {
    background: oklch(0.97 0.005 286) !important;
    color: oklch(0.21 0.006 286) !important;
    box-shadow: none !important;
}
body .jstree-default .jstree-clicked,
body .jstree-default .jstree-anchor.jstree-clicked {
    background: rgba(29, 78, 216, 0.08) !important;
    color: var(--primary, var(--pp-primary)) !important;
    font-weight: 500 !important;
    box-shadow: none !important;
    border: 1px solid #afbaef !important;
    border-radius: 5px !important;
}
/* 마지막 텍스트 오른쪽에만 미세 여백 — 보더와 텍스트가 붙지 않도록 */
body .jstree-default .jstree-clicked::after,
body .jstree-default .jstree-anchor.jstree-clicked::after {
    content: '';
    display: inline-block;
    width: 2px;
}
body .jstree-default .jstree-icon {
    color: oklch(0.55 0.016 286) !important;
}
body .jstree-default .jstree-clicked > .jstree-icon {
    color: var(--primary, var(--pp-primary-strong)) !important;
}
body .jstree-default .jstree-ocl {
    color: oklch(0.55 0.016 286) !important;
    transition: transform 0.15s;
}
body .jstree-default > .jstree-children {
    border-left: 0 !important;
    margin-left: 0 !important;
    padding-left: 0 !important;
}
body .jstree-default .jstree-wholerow {
    height: 26px !important;
}
body .jstree-default .jstree-wholerow-hovered {
    background: oklch(0.97 0.005 286) !important;
}
body .jstree-default .jstree-wholerow-clicked {
    background: rgba(0, 61, 143, 0.10) !important;
}


/* ============================================================
 * 패널 안 테이블 — 보더 정리 (Audit Log 등)
 * ============================================================ */
/* panel-body padding:0 + 테이블 — 좌우 끝까지 + 라운드 매칭 */
body .card > .card-body > table.table {
    margin-bottom: 0 !important;
}
body .card > .card-body[style*="padding:0"] > table.table > thead > tr:first-child > th,
body .card > .card-body[style*="padding: 0"] > table.table > thead > tr:first-child > th {
    border-top: 0 !important;
}
body .card > .card-body[style*="padding:0"] > table.table > tbody > tr:last-child > td,
body .card > .card-body[style*="padding: 0"] > table.table > tbody > tr:last-child > td {
    border-bottom: 0 !important;
}
/* table-striped/bordered 안 보더 톤 통일 — signal 테마 토큰 */
body .card .table > thead > tr > th {
    border-bottom: 1px solid var(--border) !important;
    background: var(--muted) !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.3px !important;
    color: var(--muted-foreground) !important;
    padding: 6px 14px !important;
}
body .card .table > tbody > tr > td {
    border-top: 1px solid var(--border, var(--pp-border)) !important;
    border-bottom: 0 !important;
    padding: 10px 14px !important;
    font-size: 13px !important;
    vertical-align: middle;
}
/* 첫 행 위쪽 보더 제거 (헤더와 중첩 방지) */
body .card .table > tbody > tr:first-child > td {
    border-top: 0 !important;
}
/* table-striped — odd 행 흰색 + BS5 box-shadow 줄무늬 메커니즘 제거.
   BS5.3 .table-striped 은 box-shadow inset(var(--bs-table-bg-type))로 줄무늬를 그려
   background 만으론 안 지워짐 → box-shadow:none 으로 끄고 background 직접 지정.
   DataTables 는 `table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > *` 셀렉터를 써서
   .table.table-striped > td 규칙에 안 잡히므로 함께 커버. */
body .card .table.table-striped > tbody > tr:nth-of-type(odd) > td,
table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
    background: oklch(1 0 0) !important;
    box-shadow: none !important;
}
body .card .table.table-striped > tbody > tr:hover > td {
    background: oklch(0.96 0.005 286) !important;
}
/* 모서리 라운드 매칭 — 마지막 row 의 첫/마지막 셀 (radius 0 = 모서리 각짐) */
body .card > .card-body > table.table > tbody > tr:last-child > td:first-child {
    border-bottom-left-radius: 0 !important;
}
body .card > .card-body > table.table > tbody > tr:last-child > td:last-child {
    border-bottom-right-radius: 0 !important;
}


/* ============================================================
 * 버튼 active/click 상태 — 보다 진한 톤 + 살짝 눌린 느낌
 * ============================================================ */
body .btn:active,
body .btn.active,
body .btn:focus:active {
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12) !important;
    transform: translateY(0.5px);
    outline: 0 !important;
}

body .btn-primary:active,
body .btn-primary.active,
body .btn-primary:active:focus,
body .open > .dropdown-toggle.btn-primary {
    background: oklch(20% 0.10 260) !important;       /* navy-darker */
    border-color: oklch(20% 0.10 260) !important;
    color: var(--pp-white) !important;
}
body .btn-secondary:active,
body .btn-secondary.active,
body .btn-secondary:active:focus,
body .open > .dropdown-toggle.btn-secondary {
    background: oklch(0.92 0.005 286) !important;
    border-color: oklch(0.85 0.008 286) !important;
    color: oklch(0.21 0.006 286) !important;
}
body .btn-danger:active,
body .btn-danger.active,
body .btn-danger:active:focus,
body .open > .dropdown-toggle.btn-danger {
    background: #b91c1c !important;
    border-color: #b91c1c !important;
    color: var(--pp-white) !important;
}
body .btn-success:active,
body .btn-success.active,
body .btn-success:active:focus,
body .open > .dropdown-toggle.btn-success {
    background: var(--pp-tone-success-bg) !important;
    border-color: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important;
}
body .btn-warning:active,
body .btn-warning.active,
body .btn-warning:active:focus {
    background: #b45309 !important;
    border-color: #b45309 !important;
    color: var(--pp-white) !important;
}
body .btn-info:active,
body .btn-info.active,
body .btn-info:active:focus {
    background: #0369a1 !important;
    border-color: #0369a1 !important;
    color: var(--pp-white) !important;
}
body .btn-dark:active,
body .btn-dark.active,
body .btn-dark:active:focus {
    background: oklch(0.13 0.006 286) !important;
    border-color: oklch(0.13 0.006 286) !important;
    color: var(--pp-white) !important;
}

/* 버튼 그룹 active 상태 — 보더 톤 보정 */
body .btn-group > .btn.active {
    background: var(--primary, var(--pp-primary-strong)) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    z-index: 2;
}
body .btn-group > .btn-secondary.active {
    background: rgba(0, 61, 143, 0.10) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
}

/* focus ring — 키보드 접근성만 메인 컬러 ring,
   마우스 클릭 후엔 브라우저 기본 outline(녹색/파랑) 제거 */
body .btn:focus,
body .btn:active:focus,
body .btn.focus {
    outline: 0 !important;
    outline-offset: 0 !important;
    box-shadow: none !important;
}
/* focus-visible ring — BS5 표준 스타일(getbootstrap.com/docs/5.3/components/buttons):
   버튼색 톤의 소프트 반투명 글로우(0.25rem). 키보드 포커스에서만(:focus-visible). */
body .btn:focus-visible {
    outline: 0 !important;
    box-shadow: 0 0 0 0.25rem rgba(0, 61, 143, 0.4) !important;   /* primary/secondary 기본 — navy */
}
body .btn-danger:focus-visible  { box-shadow: 0 0 0 0.25rem rgba(220, 38, 38, 0.4) !important; }
body .btn-success:focus-visible { box-shadow: 0 0 0 0.25rem rgba(22, 163, 74, 0.4) !important; }
body .btn-warning:focus-visible { box-shadow: 0 0 0 0.25rem rgba(217, 119, 6, 0.4) !important; }
/* 클릭 직후(:active) 살짝 눌린 느낌은 유지 */
body .btn:active,
body .btn.active {
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12) !important;
}


/* ============================================================
 * Connection Badge — 더 진한 톤 (식별성 강화)
 * ============================================================ */
body .conn-badge-ok {
    background: var(--pp-tone-success-bg) !important;          /* emerald-700 */
    color: var(--pp-white) !important;
}
body .conn-badge-warn {
    background: var(--pp-tone-warn-bg) !important;          /* amber-600 */
    color: var(--pp-white) !important;
}
body .conn-badge-error {
    background: var(--pp-tone-danger-bg) !important;          /* red-600 */
    color: var(--pp-white) !important;
}
body .conn-badge-disconnected {
    background: var(--pp-tone-muted-strong-bg) !important;          /* slate-600 */
    color: var(--pp-white) !important;
}
body .conn-badge-unknown {
    background: var(--pp-muted-fg) !important;          /* gray-500 */
    color: var(--pp-white) !important;
}


/* ============================================================
 * 데이터 표시 표준 (읽기전용 label:value) — SSOT · 명확 네이밍
 *   <pp:dl> / <pp:di label="…">값</pp:di> 태그가 이 마크업을 생성.
 *   view 카드 · 다이얼로그 · 드로어 공용. 시맨틱 <dl> 그리드(라벨 칼럼 | 값 칼럼).
 *   ⚠️ 레거시 .ds-dl / .pp-detail-meta / .view-label+.view-content / *-meta-table 대체.
 *   ※ 새 표준은 !important 미사용 — 클래스 특이도로 충분(향후 burn-down 모범).
 * ============================================================ */
.pp-data-list {
    --pp-data-label-w: 130px;
    display: grid;
    grid-template-columns: var(--pp-data-label-w) minmax(0, 1fr);
    margin: 0;
    font-size: 12px;
    line-height: 1.45;
    /* 기본으로 테두리 박스 + 라운드(사용자 요청) */
    border: 1px solid var(--pp-border);
    border-radius: 8px;
    overflow: hidden;
    background: var(--pp-white);
}
.pp-data-label,
.pp-data-value {
    padding: 7px 12px;
    margin: 0;
    border-bottom: 1px solid var(--pp-border);
    overflow-wrap: anywhere;
    min-width: 0;
}
.pp-data-label {
    font-weight: 600;
    color: var(--pp-text-muted);
    background: var(--pp-bg-muted);
    border-right: 1px solid var(--pp-border);
}
.pp-data-value { color: var(--pp-text); }
/* 마지막 행 하단 경계 제거 */
.pp-data-list > .pp-data-label:nth-last-of-type(1),
.pp-data-list > .pp-data-value:nth-last-of-type(1) { border-bottom: 0; }
/* --bordered 는 이제 기본과 동일 (하위호환 no-op, 신규는 불필요) */
/* span2 — 값이 전체폭 차지 (긴 텍스트 / 코드 / JSON 블록) */
.pp-data-label--hidden { display: none; }
.pp-data-value--full { grid-column: 1 / -1; }
/* flush — 값 셀 패딩 제거(코드/JSON 블록을 셀에 딱 붙여 표시) */
.pp-data-value--flush { padding: 0; }
/* 값 안의 모노스페이스/코드 */
.pp-data-value > code,
.pp-data-value.pp-mono { font-family: var(--pp-font-mono, ui-monospace, monospace); }


/* ============================================================
 * 빈 상태 표준 — .pp-empty-state (명확 네이밍)
 *   데이터/검색결과 없음. 아이콘 + 문구 중앙정렬. 카드본문·테이블·패널 공용.
 *   ⚠️ 레거시 .empty-state-pad / .ds-chart-empty / .empty-line-30 대체. !important 미사용.
 * ============================================================ */
.pp-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 32px 16px;
    text-align: center;
    color: var(--pp-text-muted);
}
.pp-empty-state__icon { font-size: 28px; line-height: 1; color: var(--pp-text-faint); }
.pp-empty-state__text { font-size: 13px; }
.pp-empty-state__sub  { font-size: 12px; color: var(--pp-text-faint); }
/* 컴팩트(테이블 셀/소형 패널) */
.pp-empty-state--compact { padding: 16px 12px; }
.pp-empty-state--compact .pp-empty-state__icon { font-size: 20px; }
/* 대형(패널/트리 빈상태) — 구 .sc-empty 메트릭 흡수(단일 시스템 통일) */
.pp-empty-state--lg { padding: 60px 24px; gap: 0; }
.pp-empty-state--lg .pp-empty-state__icon { font-size: 42px; margin-bottom: 14px; }
.pp-empty-state--lg .pp-empty-state__text { font-size: 15px; font-weight: 600; color: var(--foreground, var(--pp-text)); margin-bottom: 6px; }
.pp-empty-state--lg .pp-empty-state__sub { font-size: 13px; line-height: 1.6; margin-bottom: 16px; }
/* 소형(좁은 사이드바) — 구 .sc-empty-sm 흡수 */
.pp-empty-state--sm { padding: 18px 12px; gap: 0; }
.pp-empty-state--sm .pp-empty-state__icon { font-size: 32px; margin-bottom: 6px; }
.pp-empty-state--sm .pp-empty-state__text { font-size: 12px; }
.pp-empty-state--sm .pp-empty-state__sub { font-size: 11px; }
/* 설명 내 강조 아이콘 — 구 .sc-empty-desc .fa-light 톤 */
.pp-empty-state__sub .fa-light, .pp-empty-state__sub > b > i { color: var(--primary, var(--pp-primary)); }



/* 카드 본문 세로 스크롤 유틸 — BS5 에 max-height 유틸리티가 없어 생성.
   모델(/model/index) 논리/물리 트리 카드처럼 본문이 길어지는 card-body 에 부여. */
.pp-card-body-scroll-500 {
    max-height: 500px;
    overflow-y: auto;
}

/* === pp-26-badges.css === */
/* ============================================================================
 * pp-05a-badges.css
 * 영역: model-tree-footer / 타임라인 / 테이블 hover / daterangepicker
 *        login·error 페이지 템플릿 / metric-card / panel-body[padding:0] 테이블
 *        status-bar 툴팁 / jstree padding / card-head-actions / card-head-title
 *        Hero v2 타이틀 / 디자인 시스템 카탈로그 페이지 전용
 * 분할: 2026-05-15 (Phase 2) — 원본 pp-05-cards-badges.css 2120라인 분할
 * ============================================================================ */
/* ============================================================
 * 모델 트리 패널 푸터 (오브젝트 ID 표시)
 * ============================================================ */
.model-tree-footer {
    border-top: 1px solid var(--border, var(--pp-border)) !important;
    background: oklch(0.97 0.005 286) !important;
    padding: 10px 14px !important;
    display: flex;
    align-items: center;
    gap: 8px;
    border-bottom-left-radius: 12px !important;
    border-bottom-right-radius: 12px !important;
}
.model-tree-footer-label {
    font-size: 11px !important;
    color: oklch(0.55 0.016 286) !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.3px !important;
}

/* ============================================================
 * 타임라인 패널 — 시간 축 + 멀티 row + now indicator
 * ============================================================ */
.ds-timeline-track {
    position: relative;
    padding: 28px 12px 12px !important;
}
.ds-timeline-x {
    display: flex;
    justify-content: space-between;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 10px !important;
    color: oklch(0.55 0.016 286) !important;
    padding: 0 90px 8px 100px !important;
    border-bottom: 1px dashed var(--border, var(--pp-border)) !important;
    margin-bottom: 12px !important;
}
.ds-timeline-rows {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.ds-timeline-row {
    display: flex;
    align-items: center;
    gap: 10px;
}
.ds-timeline-row-label {
    width: 90px;
    flex-shrink: 0;
    font-size: 11px !important;
    font-weight: 600 !important;
    color: oklch(0.30 0.006 286) !important;
    text-align: right !important;
}
.ds-timeline-row-track {
    position: relative;
    flex: 1;
    height: 22px;
    background: oklch(0.97 0.005 286) !important;
    border-radius: 4px !important;
    overflow: hidden;
}
.ds-timeline-seg {
    position: absolute;
    top: 0; bottom: 0;
    border-radius: 0 !important;
}
.ds-timeline-pip {
    position: absolute;
    top: 50%;
    width: 10px; height: 10px;
    border-radius: 50% !important;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 0 2px var(--pp-white) !important;
    cursor: pointer;
    transition: transform 0.12s;
}
.ds-timeline-pip:hover {
    transform: translate(-50%, -50%) scale(1.3);
    z-index: 5;
}
.ds-timeline-area {
    width: 100%;
    height: 22px;
    display: block;
}
.ds-timeline-now {
    position: absolute;
    top: 4px;
    bottom: 4px;
    width: 2px;
    background: var(--pp-tone-danger-bg) !important;
    box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.18) !important;
    pointer-events: none;
    z-index: 10;
    color: var(--pp-white) !important;
}
.ds-timeline-now-label {
    position: absolute;
    top: -22px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important;
    padding: 2px 8px !important;
    border-radius: 4px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    white-space: nowrap !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
}
.ds-timeline-foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    padding: 12px 22px !important;
    background: oklch(0.97 0.005 286) !important;
    border-top: 1px solid var(--border, var(--pp-border)) !important;
    border-bottom-left-radius: 12px !important;
    border-bottom-right-radius: 12px !important;
    font-size: 11px !important;
}
.ds-timeline-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    color: oklch(0.45 0.01 286) !important;
}
.ds-timeline-legend > span {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.ds-timeline-meta {
    color: oklch(0.55 0.016 286) !important;
    font-weight: 500 !important;
}

/* nav-tabs 톤 정렬 (모델 트리 패널 안) */
body .card .nav-tabs > li > a {
    color: oklch(0.45 0.01 286) !important;
    background: transparent !important;
    border: 0 !important;
    padding: 6px 12px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    border-radius: 0 !important;
    border-bottom: 2px solid transparent !important;
    transition: color 0.12s, border-color 0.12s;
}
body .card .nav-tabs > li > a:hover {
    color: oklch(0.21 0.006 286) !important;
    background: transparent !important;
}
body .card .nav-tabs > li.active > a, body .card .nav-tabs > li > a.active,
body .card .nav-tabs > li.active > a:hover, body .card .nav-tabs > li > a.active:hover,
body .card .nav-tabs > li.active > a:focus, body .card .nav-tabs > li > a.active:focus {
    color: var(--primary, var(--pp-primary-strong)) !important;
    background: transparent !important;
    border-bottom-color: var(--primary, var(--pp-primary-strong)) !important;
    font-weight: 600 !important;
}


/* ============================================================
 * 테이블 hover — 녹색/노랑 잔재 제거, 중립 zinc / navy-pale
 * ============================================================ */
body table.table > tbody > tr:hover > td,
body table.table > tbody > tr:hover,
body table.table-hover > tbody > tr:hover,
body table.table-hover > tbody > tr:hover > td,
body table.table-bordered > tbody > tr:hover > td,
body table.table-bordered > tbody > tr:nth-child(even):hover > td,
body table.table-bordered > tbody > tr:nth-child(odd):hover > td,
body table.dataTable > tbody > tr:hover,
body table.dataTable > tbody > tr:hover > td {
    background: rgba(0, 61, 143, 0.04) !important;       /* navy 4% */
}
body table.table-striped > tbody > tr:hover > td {
    background: rgba(0, 61, 143, 0.06) !important;
}
body table.table > tbody > tr.selected > td,
body table.dataTable > tbody > tr.selected,
body table.dataTable > tbody > tr.selected > td {
    background: rgba(0, 61, 143, 0.10) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
}

/* ============================================================
 * Daterangepicker — 테마 정렬
 * ============================================================ */
body .daterangepicker {
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 12px !important;
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12) !important;
    font-family: inherit !important;
    overflow: hidden;
    padding: 0 !important;
    background: var(--pp-white) !important;
}
body .daterangepicker:before, body .daterangepicker:after { display: none; }
body .daterangepicker .ranges {
    padding: 12px !important;
    border-right: 1px solid var(--border, var(--pp-border)) !important;
}
body .daterangepicker .ranges ul {
    width: 130px;
}
body .daterangepicker .ranges li {
    padding: 7px 12px !important;
    border-radius: 6px !important;
    margin-bottom: 2px !important;
    color: oklch(0.30 0.006 286) !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    transition: background 0.1s, color 0.1s;
}
body .daterangepicker .ranges li:hover {
    background: oklch(0.97 0.005 286) !important;
    color: oklch(0.21 0.006 286) !important;
}
body .daterangepicker .ranges li.active {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}
body .daterangepicker .calendar-table {
    border: 0 !important;
    background: var(--pp-white) !important;
}
body .daterangepicker td.in-range {
    background: rgba(0, 61, 143, 0.08) !important;
    color: oklch(0.21 0.006 286) !important;
    border-radius: 0 !important;
}
body .daterangepicker td.start-date,
body .daterangepicker td.end-date,
body .daterangepicker td.active,
body .daterangepicker td.active:hover {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    border-radius: 50% !important;
}
body .daterangepicker td.start-date.in-range,
body .daterangepicker td.end-date.in-range {
    border-radius: 50% !important;
}
body .daterangepicker td:not(.disabled):not(.off):hover {
    background: oklch(0.97 0.005 286) !important;
    color: oklch(0.21 0.006 286) !important;
    border-radius: 50% !important;
}
body .daterangepicker td.off {
    color: oklch(0.75 0.01 286) !important;
}
body .daterangepicker th.month {
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    font-size: 13px !important;
}
body .daterangepicker th.prev,
body .daterangepicker th.next {
    color: oklch(0.55 0.016 286) !important;
    cursor: pointer;
    transition: color 0.12s;
}
body .daterangepicker th.prev:hover,
body .daterangepicker th.next:hover {
    color: var(--primary, var(--pp-primary-strong)) !important;
}
body .daterangepicker thead tr:first-child th {
    padding: 10px 0 !important;
}
body .daterangepicker .drp-buttons {
    border-top: 1px solid var(--border, var(--pp-border)) !important;
    padding: 12px 16px !important;
    background: oklch(0.97 0.005 286) !important;
}
body .daterangepicker .drp-buttons .btn {
    height: 32px;
    padding: 0 14px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
}
body .daterangepicker .drp-buttons .applyBtn {
    background: var(--primary, var(--pp-primary-strong)) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}
body .daterangepicker .drp-buttons .cancelBtn {
    background: var(--pp-white) !important;
    border-color: var(--border, var(--pp-border)) !important;
    color: oklch(0.30 0.006 286) !important;
}
body .daterangepicker .drp-selected {
    font-size: 12px !important;
    color: oklch(0.45 0.01 286) !important;
    margin-right: 12px !important;
    font-weight: 500 !important;
}

/* ============================================================
 * 페이지 템플릿 — 로그인 / 에러 페이지
 * ============================================================ */
.ds-template-frame {
    border: 1px dashed var(--border, var(--pp-border)) !important;
    border-radius: 12px !important;
    padding: 20px !important;
    background: oklch(0.97 0.005 286) !important;
    margin-bottom: 16px !important;
}

/* Error pages */
.ds-error-page {
    text-align: center !important;
    padding: 48px 24px !important;
    background: var(--pp-white) !important;
    border-radius: 10px !important;
}
.ds-error-code {
    font-size: 80px !important;
    font-weight: 800 !important;
    line-height: 1 !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    letter-spacing: -0.04em !important;
    margin-bottom: 12px !important;
}
.ds-error-code-warn { color: var(--pp-tone-warn-bg) !important; }
.ds-error-code-danger { color: var(--pp-tone-danger-bg) !important; }
.ds-error-icon {
    font-size: 40px !important;
    color: oklch(0.65 0.01 286) !important;
    margin-bottom: 16px !important;
}
.ds-error-icon-warn { color: var(--pp-tone-warn-bg) !important; }
.ds-error-icon-danger { color: var(--pp-tone-danger-bg) !important; }
.ds-error-title {
    font-size: 22px !important;
    font-weight: 700 !important;
    color: oklch(0.21 0.006 286) !important;
    margin: 0 0 8px !important;
}
.ds-error-desc {
    font-size: 14px !important;
    color: oklch(0.55 0.016 286) !important;
    margin: 0 0 24px !important;
    max-width: 480px;
    margin-left: auto !important;
    margin-right: auto !important;
}
.ds-error-actions {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-bottom: 12px !important;
}
.ds-error-trace {
    margin-top: 24px !important;
    text-align: left !important;
    max-width: 600px;
    margin-left: auto !important;
    margin-right: auto !important;
}
.ds-error-trace summary {
    font-size: 12px !important;
    color: oklch(0.55 0.016 286) !important;
    cursor: pointer;
    padding: 8px 12px !important;
    background: oklch(0.97 0.005 286) !important;
    border-radius: 6px !important;
    user-select: none;
}
.ds-error-trace summary:hover {
    color: oklch(0.21 0.006 286) !important;
}
.ds-error-trace pre {
    margin: 8px 0 0 !important;
    padding: 14px !important;
    background: oklch(0.18 0.01 286) !important;
    color: oklch(0.85 0.005 286) !important;
    border-radius: 6px !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 11px !important;
    line-height: 1.6 !important;
    text-align: left !important;
    overflow-x: auto;
}


/* 디자인 토큰 — 그라데이션 (Phase 1 통합 → pp-01-tokens-base.css) */

/* 토큰을 직접 사용할 수 있는 utility 클래스 */
.bg-gradient-primary       { background: var(--gradient-primary) !important; color: var(--pp-white) !important; }
.bg-gradient-primary-soft  { background: var(--gradient-primary-soft) !important; color: oklch(0.21 0.006 286) !important; }
.bg-gradient-success       { background: var(--gradient-success) !important; color: var(--pp-white) !important; }
.bg-gradient-warning       { background: var(--gradient-warning) !important; color: var(--pp-white) !important; }
.bg-gradient-danger        { background: var(--gradient-danger) !important; color: var(--pp-white) !important; }
.bg-gradient-dark          { background: var(--gradient-dark) !important; color: var(--pp-white) !important; }
.bg-gradient-mesh          { background: var(--pp-white) !important; background-image: var(--gradient-mesh) !important; }
.bg-gradient-aurora        { background: var(--gradient-aurora) !important; color: var(--pp-white) !important; }

/* 텍스트 그라데이션 */
.text-gradient-primary {
    background: linear-gradient(90deg, var(--primary, var(--pp-primary-strong)) 0%, oklch(0.55 0.18 230) 100%) !important;
    -webkit-background-clip: text;
    background-clip: text !important;
    -webkit-text-fill-color: transparent;
    color: transparent !important;
    color: var(--pp-white) !important;
}
.text-gradient-aurora {
    background: linear-gradient(90deg, oklch(0.55 0.20 260) 0%, oklch(0.50 0.22 290) 50%, oklch(0.55 0.20 200) 100%) !important;
    -webkit-background-clip: text;
    background-clip: text !important;
    -webkit-text-fill-color: transparent;
    color: transparent !important;
}


/* ============================================================
 * panel-body[padding:0] 안 테이블 — 모서리 라운드 매칭
 * heading 이 없으면 thead 첫 row 가 panel 의 top-radius 를 상속
 * ============================================================ */
body .card > .card-body[style*="padding:0"]:first-child > table.table > thead > tr:first-child > th:first-child,
body .card > .card-body[style*="padding: 0"]:first-child > table.table > thead > tr:first-child > th:first-child {
    border-top-left-radius: 12px !important;
}
body .card > .card-body[style*="padding:0"]:first-child > table.table > thead > tr:first-child > th:last-child,
body .card > .card-body[style*="padding: 0"]:first-child > table.table > thead > tr:first-child > th:last-child {
    border-top-right-radius: 12px !important;
}
body .card > .card-body[style*="padding:0"]:last-child > table.table > tbody > tr:last-child > td:first-child,
body .card > .card-body[style*="padding: 0"]:last-child > table.table > tbody > tr:last-child > td:first-child {
    border-bottom-left-radius: 12px !important;
}
body .card > .card-body[style*="padding:0"]:last-child > table.table > tbody > tr:last-child > td:last-child,
body .card > .card-body[style*="padding: 0"]:last-child > table.table > tbody > tr:last-child > td:last-child {
    border-bottom-right-radius: 12px !important;
}

/* 테이블 thead 좌우 끝 보더 — panel 라운드 영역 안으로 자연스럽게 */
body .card > .card-body[style*="padding:0"]:first-child > table.table > thead > tr:first-child > th:first-child,
body .card > .card-body[style*="padding: 0"]:first-child > table.table > thead > tr:first-child > th:first-child {
    border-left: 0 !important;
}
body .card > .card-body[style*="padding:0"]:first-child > table.table > thead > tr:first-child > th:last-child,
body .card > .card-body[style*="padding: 0"]:first-child > table.table > thead > tr:first-child > th:last-child {
    border-right: 0 !important;
}


/* ============================================================
 * 상태바 타임라인 호버 툴팁 — 어두운 배경 위 강제 흰 텍스트
 * ============================================================ */
body .ds-stb-tip,
body .ds-stb-tip *,
body .ds-stb-tip-period,
body .ds-stb-tip-row,
body .ds-stb-tip span,
body .ds-stb-tip b {
    color: var(--pp-white) !important;
}
body .ds-stb-tip .ds-stb-swatch {
    /* swatch 색은 인라인 그대로 — 보더만 흰색 */
    box-shadow: 0 0 0 1px rgba(255,255,255,0.2) !important;
}


/* ============================================================
 * jstree padding 정상화 — assetTreeDiv 등 트리 아이콘 보존
 * 이전 padding 0 으로 인해 아이콘이 사라지던 문제 해결
 * ============================================================ */
/* anchor padding 은 pp-28-tree.css 의 inline-flex 규칙(좌우 8px)으로 일원화 */
body .jstree-default li,
body .jstree-default-large li,
body .jstree-default ul {
    padding: 0 !important;
    margin: 0 !important;
}

/* ============================================================
 * card-head-actions 안 btn-group — 외곽만 라운드 (이전 6px override 무효화)
 * ============================================================ */
body #page-wrapper .card-head-actions > .btn-group > .btn,
body #page-wrapper .card-head-actions .btn-group > .btn {
    border-radius: 0 !important;
    margin-left: -1px !important;
}
body #page-wrapper .card-head-actions > .btn-group > .btn:first-child,
body #page-wrapper .card-head-actions .btn-group > .btn:first-child {
    border-top-left-radius: 6px !important;
    border-bottom-left-radius: 6px !important;
    margin-left: 0 !important;
}
body #page-wrapper .card-head-actions > .btn-group > .btn:last-child,
body #page-wrapper .card-head-actions .btn-group > .btn:last-child {
    border-top-right-radius: 6px !important;
    border-bottom-right-radius: 6px !important;
}
body #page-wrapper .card-head-actions > .btn-group {
    display: inline-flex;
    align-items: center;
}


/* ============================================================
 * card-head-title — 아이콘 → 텍스트 (정방향)
 * 이전엔 row-reverse 로 텍스트→아이콘 swap 했으나, 사용자 정책 변경: 아이콘 항상 앞.
 * pp-02b-panels-themes.css 의 inline-flex + i { order: -99 } 안전망에 위임.
 * fa-fw 마진은 0 으로 유지 (gap: 8px 로 간격 일관).
 * ============================================================ */
body .card-head-block .card-head-title > i,
body .card-header > .card-head-title > i {
    margin: 0 !important;
}


/* ============================================================
 * 디자인 시스템 카탈로그 페이지 전용 (이전 module/design-system/index.css)
 * ============================================================ */

/* ============================================================
 * 디자인 시스템 카탈로그 — 카탈로그 페이지 전용 스타일
 * (테마 자체는 pp-signal-theme.css 가 담당. 여기는 카탈로그 데모용)
 * ============================================================ */

.ds-row {
    display: flex;
    gap: 24px;
    align-items: flex-start;
}

/* ─── 좌측 인덱스 (sticky) ─────────────────────────────── */
.ds-toc {
    position: sticky;
    top: calc(var(--pp-topbar-h, 64px) + 16px);
    align-self: flex-start;
    max-height: calc(100vh - 100px);
    overflow-y: auto;
    padding: 16px 8px 16px 0 !important;
    border-right: 1px solid var(--pp-border) !important;
    font-size: 12px !important;
}
.ds-toc-section {
    font-size: 11px !important;
    font-weight: 600 !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px !important;
    padding: 12px 12px 4px !important;
}
.ds-toc-list {
    list-style: none;
    padding: 0 0 8px !important;
    margin: 0 !important;
}
.ds-toc-list li a {
    display: block;
    padding: 5px 12px !important;
    color: var(--pp-text-soft, #374151) !important;
    text-decoration: none !important;
    border-radius: 6px !important;
    transition: background 0.12s, color 0.12s;
}
.ds-toc-list li a:hover {
    background: var(--pp-bg-muted, #f4f4f5) !important;
    color: var(--pp-text, #111827) !important;
}
.ds-toc-list li.active > a {
    background: rgba(0, 61, 143, 0.08) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    font-weight: 500 !important;
}

/* ─── 우측 컨텐츠 ──────────────────────────────────────── */
.ds-content {
    padding-bottom: 120px !important;
}

/* 섹션 */
.ds-section {
    padding: 28px 0 8px !important;
    border-bottom: 1px dashed var(--pp-border) !important;
    scroll-margin-top: calc(var(--pp-topbar-h, 64px) + 16px);
}
.ds-section:last-child {
    border-bottom: 0 !important;
}
.ds-h2 {
    font-size: 22px !important;
    font-weight: 600 !important;
    color: oklch(0.21 0.006 286) !important;
    margin: 0 0 6px !important;
    letter-spacing: -0.01em !important;
}
.ds-h3 {
    font-size: 14px !important;
    font-weight: 600 !important;
    color: oklch(0.30 0.006 286) !important;
    margin: 18px 0 10px !important;
}
.ds-lead {
    font-size: 13px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    margin: 0 0 16px !important;
    line-height: 1.5 !important;
}
.ds-note {
    font-size: 12px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    line-height: 1.5 !important;
    padding: 8px 12px !important;
    background: var(--pp-bg-muted, #f9fafb) !important;
    border-left: 3px solid var(--pp-border) !important;
    border-radius: 0 6px 6px 0 !important;
    margin-top: 8px !important;
}

/* 가로 데모 행 */
.ds-row-flex {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    padding: 4px 0 12px !important;
}

/* 코드 블록 */
.ds-code {
    background: oklch(0.18 0.01 286) !important;
    color: oklch(0.92 0.005 286) !important;
    padding: 12px 14px !important;
    border-radius: 8px !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 12px !important;
    line-height: 1.6 !important;
    overflow-x: auto;
    white-space: pre !important;
    margin: 8px 0 12px !important;
}

/* 디자인 시스템 카탈로그 — 폼 유효성 섹션 보조 클래스 */
.ds-bullets {
    margin: 4px 0 12px !important;
    padding-left: 20px !important;
    line-height: 1.8 !important;
}
.ds-bullets > li > code {
    background: oklch(0.95 0.005 286) !important;
    padding: 1px 4px !important;
    border-radius: 3px !important;
    font-size: 11.5px !important;
}

.ds-addon-success {
    background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important;
    border-color: var(--pp-tone-success-bg) !important;
}

.ds-error-summary {
    margin-bottom: 16px !important;
}
.ds-error-summary-list {
    padding-left: 20px !important;
    margin: 6px 0 0 !important;
    line-height: 1.8 !important;
}

.ds-rule-table code {
    background: oklch(0.95 0.005 286) !important;
    padding: 1px 5px !important;
    border-radius: 3px !important;
    font-size: 11.5px !important;
}
.ds-rule-table th {
    background: oklch(0.97 0.003 286) !important;
    font-weight: 600 !important;
}
.ds-rule-deprecated > td {
    color: var(--pp-muted-fg) !important;
    background: oklch(0.98 0.002 286) !important;
}
.ds-rule-deprecated code {
    text-decoration: line-through !important;
    text-decoration-color: rgba(220, 38, 38, 0.4) !important;
}

/* stmt-status-badge: 사용처 0건(미사용) — 블록 전체 삭제 */

/* ============================================================
 * health-level-badge — 헬스 타임라인 레벨 인디케이터 (작은 pill, 레이아웃만)
 *  색상(tone bg + on-solid)은 pp-12-status-tones.css 가 정본 — 여기 중복 색상 룰 제거
 * ============================================================ */
body .health-level-badge {
    display: inline-block;
    padding: 2px 5px !important;
    border-radius: 5px !important;
    font-size: 9px !important;
    color: var(--pp-white) !important;
    margin-left: 4px;
}
body .health-level-badge-ok *,
body .health-level-badge-info *,
body .health-level-badge-warn *,
body .health-level-badge-error * { color: var(--pp-white) !important; }

/* ============================================================
 * ID/오브젝트 뱃지 popover (pp-id-badge.js, .pp-badge-pop)
 *   긴 description 이 popover 폭을 넘던 문제 → 값 셀 ellipsis.
 * ============================================================ */
/* BS5 popover(pp-badge-popover) 기본 max-width(276px) 확대 — 도메인 ID 팝오버 가로 +80px */
.popover.pp-badge-popover { max-width: 360px; }
/* 도메인 ID 팝오버 — overflow:hidden 은 박스 밖 화살표를 클리핑하므로 visible + 헤더/바디 직접 라운딩(seam 제거).
   BS5 popper 화살표는 JS 수직중앙 보정과 어긋나므로 미사용 — 팝오버가 배지에 수직중앙 정렬되는 점을 이용해
   세로중앙 커스텀 화살표를 그린다. 기본 placement=right(팝오버가 배지 오른쪽)이므로 화살표를 왼쪽 모서리
   '밖으로' protrude(left:-8px) 시키는 걸 base 규칙에 둔다(placement 속성 매칭 실패 시 박스 안으로 떨어지던 버그 방지). */
.popover.pp-badge-popover { overflow: visible; }
.popover.pp-badge-popover .popover-header { border-radius: var(--bs-popover-border-radius, 14px) var(--bs-popover-border-radius, 14px) 0 0; }
.popover.pp-badge-popover .popover-body { border-radius: 0 0 var(--bs-popover-border-radius, 14px) var(--bs-popover-border-radius, 14px); }
.popover.pp-badge-popover .popover-arrow { display: none; }
.popover.pp-badge-popover::before,
.popover.pp-badge-popover::after {
    content: ""; position: absolute; top: 50%; margin-top: -8px;
    width: 0; height: 0; border: 8px solid transparent; pointer-events: none;
}
/* base = 왼쪽 모서리 '밖' 화살표(배지를 가리킴) — 삼각형 밑변이 팝오버 좌측 보더에 flush 되고 꼭지가
   바깥(왼쪽)으로 protrude 하도록 left:-16px(=보더 8px 두께 ×2). ::before 보더색 외곽 / ::after 바디배경 내곽(1px 안쪽). */
.popover.pp-badge-popover::before { left: -16px; border-right-color: var(--bs-popover-border-color, var(--border)); }
.popover.pp-badge-popover::after  { left: -15px; border-right-color: var(--bs-popover-bg, var(--card)); }
/* placement=left(팝오버가 배지 왼쪽)일 때만 오른쪽 모서리로 전환 */
.popover.pp-badge-popover[data-popper-placement^="left"]::before { left: auto; right: -16px; border-right-color: transparent; border-left-color: var(--bs-popover-border-color, var(--border)); }
.popover.pp-badge-popover[data-popper-placement^="left"]::after  { left: auto; right: -15px; border-right-color: transparent; border-left-color: var(--bs-popover-bg, var(--card)); }
.pp-badge-pop { max-width: 340px; }
.pp-badge-row {
    display: flex;
    gap: 10px;
    align-items: flex-start;   /* 값이 여러 줄로 wrap 돼도 라벨은 첫 줄에 정렬 */
    line-height: 1.5;
}
.pp-badge-row + .pp-badge-row { margin-top: 4px; }
.pp-badge-label {
    flex: 0 0 auto;
    min-width: 56px;           /* 라벨 폭 정렬 — 값들이 같은 열에서 시작(내용 정돈) */
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-size: 11px;
    font-weight: 600;
    white-space: nowrap;
}
.pp-badge-val {
    flex: 1 1 auto;
    min-width: 0;
    white-space: normal;          /* 긴 텍스트는 다음 행으로 wrap (팝오버 폭 초과 방지) */
    overflow-wrap: anywhere;
    word-break: break-word;
    font-size: 12px;
    color: var(--foreground, #0f172a);
}

/* === pp-27-asset.css === */
/* ============================================================================
 * pp-06-asset.css
 * 영역: DS 카탈로그(swatches/typo/icon-grid/sparkline) / Metric Card / progress
 *        daterangepicker 트리거 / 모델 트리 패널 토글바 / asset/tree.jsp 우측 패널
 *        panel-heading 보더 / model-tree-footer-v2
 * 분할: 2026-05-15 (Phase 2) — 원본 pp-06-asset-tree.css 1696라인 분할
 * ============================================================================ */

/* 컬러 스와치 */
.ds-swatches {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
    margin-bottom: 16px !important;
}
.ds-swatch {
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    overflow: hidden;
    background: var(--pp-white) !important;
}
.ds-swatch-box {
    height: 56px;
    width: 100%;
}
.ds-swatch-name {
    font-size: 12px !important;
    font-weight: 600 !important;
    padding: 6px 10px 0 !important;
    color: oklch(0.21 0.006 286) !important;
}
.ds-swatch-hex {
    font-size: 11px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    padding: 0 10px 8px !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
}

/* 토큰 테이블 */
.ds-table-tokens {
    font-size: 12px !important;
}
.ds-table-tokens th {
    background: var(--pp-bg-muted, #f9fafb) !important;
    font-size: 11px !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
}
.ds-table-tokens code {
    background: var(--pp-bg-muted, #f4f4f5) !important;
    color: oklch(0.30 0.10 260) !important;
    padding: 1px 6px !important;
    border-radius: 4px !important;
    font-size: 11px !important;
}

/* 타이포그래피 데모 행 */
.ds-typo-row {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: 16px;
    align-items: baseline;
    padding: 8px 0 !important;
    border-bottom: 1px dashed var(--pp-border) !important;
}
.ds-typo-row:last-child {
    border-bottom: 0 !important;
}
.ds-typo-spec {
    font-size: 11px !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    color: var(--pp-text-muted, var(--pp-muted-fg)) !important;
    background: var(--pp-bg-muted, #f9fafb) !important;
    padding: 4px 8px !important;
    border-radius: 4px !important;
}

/* 아이콘 그리드 */
.ds-icon-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 8px;
    margin: 8px 0 !important;
}
.ds-icon-cell {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 6px !important;
    background: var(--pp-white) !important;
    font-size: 11px !important;
    color: var(--pp-text-soft, #374151) !important;
}
.ds-icon-cell i {
    font-size: 16px !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    width: 20px;
    text-align: center !important;
}

/* 룰 리스트 */
.ds-rules {
    font-size: 13px !important;
    line-height: 1.7 !important;
    padding-left: 20px !important;
    color: var(--pp-text-soft, #374151) !important;
}
.ds-rules code {
    background: var(--pp-bg-muted, #f4f4f5) !important;
    color: oklch(0.30 0.10 260) !important;
    padding: 1px 6px !important;
    border-radius: 4px !important;
    font-size: 12px !important;
}

/* sparkline 데모 */
.ds-spark {
    display: inline-block;
    width: 80px;
    height: 24px;
    background: var(--pp-bg-muted, #f9fafb) !important;
    border-radius: 4px !important;
}


/* ds-stl-info — PPStatusTimeline 호버 정보바 */
body .ds-stl-host {
    padding-bottom: 10px !important;
}


/* (드롭다운 버튼 caret 룰은 pp-05-cards-badges.css 의 정의로 단일화) */


/* ============================================================
 * progress-bar — 텍스트 보이도록 높이 + 좌우 padding
 * ============================================================ */
body .progress {
    height: 18px !important;          /* 텍스트 들어갈 높이 */
    padding: 0 !important;
}
body .progress-bar {
    line-height: 18px !important;
    padding: 0 10px !important;
    text-align: right !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    min-width: 36px;                  /* 작은 % 값도 텍스트 노출 */
}


/* ============================================================
 * Daterangepicker 트리거 인풋 — 텍스트 중앙 정렬
 * ============================================================ */
body input.form-control[id$="daterange"],
body #ds-daterange,
body input.daterangepicker-input,
body input[data-toggle="daterangepicker"] {
    text-align: center !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    letter-spacing: 0.3px !important;
    font-weight: 500 !important;
}


/* ============================================================
 * 모델 트리 패널 — 사이트 셀렉터 + 세그먼티드 탭 (에셋/연결)
 * ============================================================ */
body .model-tree-toolbar {
    padding: 14px !important;
    display: flex;
    flex-direction: column;
    gap: 0;
    border-bottom: 1px solid var(--border, var(--pp-border)) !important;
    background: oklch(0.985 0.003 286) !important;
}
body .model-tree-tabs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 3px;
    padding: 2px !important;
    background: oklch(0.94 0.005 286) !important;
    border-radius: 6px !important;
    margin-top: 10px;
}
body .model-tree-tab {
    background: transparent !important;
    border: 0 !important;
    padding: 4px 8px !important;
    border-radius: 4px !important;
    font-size: 11.5px !important;
    font-weight: 500 !important;
    color: oklch(0.45 0.01 286) !important;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, box-shadow 0.15s;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    line-height: 1.3 !important;
}
body .model-tree-tab:hover {
    color: oklch(0.21 0.006 286) !important;
}
body .model-tree-tab.active {
    background: var(--pp-white) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    font-weight: 600 !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08) !important;
}
body .model-tree-tab > i {
    font-size: 11px !important;
}

/* 트리 자체 영역 — 패딩 + 높이 캡(트리만 내부 스크롤).
 * BS5/signal 마이그레이션(.panel-body→.card-body) 때 레거시 스크롤 제약이 누락돼
 * jstree 가 card-body 를 벗어나 넘치던 회귀를 복원. toolbar/탭/footer 는 고정,
 * 이 pane 만 세로 스크롤. (모바일 오버플로우 규칙은 pp-z-mobile-overflow.css 별도) */
/* 모델 트리 pane — 탭 중첩 구조(asset/data: card>#tags_nav_tabs>tab-content) 무관하게
   항상 스크롤. 이전 `.card > .tab-content > .tab-pane` 직속 체인은 asset/data 에서 미매칭이었음. */
body .card .card-body.model-tree-pane {
    padding: 10px 14px !important;
    margin: 0 !important;
    max-height: calc(100vh - 320px);
    min-height: 200px;
    overflow-y: auto !important;
    overflow-x: auto !important;
}

/* jstree 좌측 정렬 — 기본 indent 사용 (margin-left 0) */
body .jstree-default,
body .jstree-default-dark {
    margin-left: 0 !important;
}

/* ===========================================================================
 * asset/tree.jsp — 우측 패널 (에셋 정보 / 타임라인)
 * =========================================================================== */
/* 에셋 정보 패널 — 메타 (타입 태그 + 등록/수정일) */
.asset-info-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding-bottom: 12px !important;
    margin-bottom: 16px !important;
    border-bottom: 1px solid var(--pp-border) !important;
}

.asset-info-type-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px !important;
    background: oklch(0.21 0.006 286) !important;
    color: var(--pp-white) !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.3px !important;
}

.asset-info-type-tag > i,
.asset-info-type-tag > span {
    color: var(--pp-white) !important;
}

.asset-info-history {
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.asset-info-history > i {
    color: var(--subtle-foreground, #9ca3af) !important;
}

/* 에셋 정보 행 — 좌측 이미지 + 우측 폼 */
.asset-info-row {
    margin: 0 !important;
}

/* 에셋 이미지 프레임 */
.asset-info-image-frame {
    position: relative;
    width: 100%;
    height: 310px;
    border: 0 !important;
    border-radius: 8px !important;
    background: transparent !important;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}

.asset-info-image-inner {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.asset-info-image-inner > img,
.asset-info-image-inner > svg {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}


.asset-info-image-placeholder > i {
    font-size: 36px !important;
    margin-bottom: 8px !important;
    display: block;
    opacity: 0.5 !important;
}

/* 이미지 위 상태 도트 (연결/건강) — 우상단 오버레이 */


/* 타임라인 fieldset legend 의 범례 영역 */
.asset-tree-tl-range {
    color: var(--subtle-foreground, var(--pp-text-soft)) !important;
    font-weight: 400 !important;
    display: none;
    font-size: 11px !important;
    margin-left: 4px !important;
}

.asset-tree-tl-legend {
    display: flex;
    align-items: center;
    gap: 0;
    margin-top: 12px !important;
    padding-top: 10px !important;
    border-top: 1px dashed var(--pp-border) !important;
    justify-content: flex-end;
}

.asset-tree-tl-help {
    margin-right: 8px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 13px !important;
}

.asset-tree-tl-pill {
    display: inline-flex;
    align-items: center;
    color: var(--pp-white) !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    padding: 2px 6px !important;
    line-height: 1.3 !important;
}
.asset-tree-tl-pill:first-of-type {
    border-top-left-radius: 3px !important;
    border-bottom-left-radius: 3px !important;
}
.asset-tree-tl-pill:last-child {
    border-top-right-radius: 3px !important;
    border-bottom-right-radius: 3px !important;
}
.asset-tree-tl-pill-mute { background: #9ca3af !important; }
.asset-tree-tl-pill-ok   { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.asset-tree-tl-pill-warn { background: var(--pp-tone-warn-bg) !important; }
.asset-tree-tl-pill-err  { background: #b91c1c !important;
    color: var(--pp-white) !important;
}
.asset-tree-tl-pill-disc { background: #4a0e0e !important; }

/* 타임라인 wrap + info pill */
.asset-tree-tl-wrap {
    position: relative;
    margin-top: 4px !important;
    margin-left: 5px !important;
    margin-bottom: 10px !important;
}
.asset-tree-tl-info {
    position: absolute;
    z-index: 1;
    left: 4px;
    top: 2px;
    opacity: 0.85 !important;
    background: var(--muted-foreground, var(--pp-muted-fg)) !important;
    color: var(--pp-white) !important;
    font-size: 11px !important;
    padding: 1px 12px !important;
    border-radius: 3px !important;
}
.asset-tree-tl-bar {
    padding-bottom: 10px !important;
}


/* 폼 인라인 보조 설명 — fieldset 안에서 입력 필드 아래 작은 안내.
 * form-inline 안에 위치하면 flex 자식이 되므로 flex-basis: 100% 로 다음 줄로 wrap,
 * 라벨(140px) + gap(12px) = 152px 왼쪽 들여쓰기 — 입력박스 시작점과 정렬.
 * 톤은 ds-help-meta 와 통일 (font-size 11px + muted-foreground). */
.form-help-inline {
    flex: 1 0 100%;
    margin: 4px 0 0 152px !important;
    padding-left: 0 !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    line-height: 1.5 !important;
}

/* form-inline 부모가 flex-wrap: nowrap 이라도, form-help-inline 이 자기 줄을 갖도록 강제.
 * 입력박스와 도움말 사이 수직 공간 최소화 (margin-top 0) */
.form-inline > .form-help-inline,
.pp-form-row > .form-help-inline {
    flex-basis: calc(100% - 152px) !important;
    max-width: calc(100% - 152px) !important;
    margin-left: 152px !important;
    margin-top: -10px !important;
    margin-bottom: 0 !important;
}

/* form-stack > form-group 패턴 — 라벨이 입력 위, 도움말은 입력 바로 아래 (왼쪽 정렬) */
.form-stack > .form-group > .form-help-inline {
    display: block;
    margin: 4px 0 0 0 !important;
    padding-left: 0 !important;
    max-width: none !important;
    flex-basis: auto !important;
}

/* form-stack > form-group 패턴 — 인풋/셀렉트/텍스트에어리어 모두 부모 폭 채움
 * (col-w-* 명시 인라인 너비는 그대로 적용되지만, 기본은 100%) */
.form-stack > .form-group > .form-control:not([class*="col-w-"]),
.form-stack > .form-group > select.form-control:not([class*="col-w-"]),
.form-stack > .form-group > textarea.form-control:not([class*="col-w-"]) {
    width: 100% !important;
    max-width: 100%;
}

/* fieldset 안의 form-stack 전체를 좌우 14px 들여쓰기 — legend 는 fieldset 왼쪽 끝에 그대로.
 * connect/plc/add 가 기본 정렬. 단일 단 / form-stack--2col / form-grid-2col 모든 변형 일관. */
body #page-wrapper fieldset .form-stack {
    padding-left: 0 !important;
    padding-right: 0 !important;
}
body #page-wrapper fieldset .form-stack > .form-group {
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* fieldset 안의 .row > col 는 bootstrap 음수 마진 정규화 (단일 form-stack 과 우측 정렬 일치) */
body #page-wrapper fieldset > form > .row,
body #page-wrapper fieldset > .row {
    margin-left: 0 !important;
    margin-right: 0 !important;
}
body #page-wrapper fieldset > form > .row > [class*="col-"],
body #page-wrapper fieldset > .row > [class*="col-"] {
    padding-left: 14px !important;
    padding-right: 14px !important;
}
/* col 내부의 form-group 은 자체 마진 제거 (col padding 이 대신 들여쓰기) */
body #page-wrapper fieldset > form > .row > [class*="col-"] .form-stack > .form-group,
body #page-wrapper fieldset > .row > [class*="col-"] .form-stack > .form-group {
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* form-stack--2col — form-stack 의 자식 form-group 들을 좌/우 자동 분배 (홀수=좌, 짝수=우).
 * .form-group--full 은 한 줄 전체 차지 (ID·textarea·긴 설명 등 예외).
 * 768px 미만 1 칼럼 자동 stack. */
.form-stack.form-stack--2col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 24px;
}
.form-stack.form-stack--2col > .form-group {
    min-width: 0;
}
.form-stack.form-stack--2col > .form-group.form-group--full {
    grid-column: 1 / -1;
}
@media (max-width: 767px) {
    .form-stack.form-stack--2col {
        grid-template-columns: 1fr;
    }
}
/* fieldset 안 form-stack--2col 의 form-group 마진 제거 (grid gap 으로 대체).
 * 좌우 14px 패딩은 form-stack 공통 규칙 (위쪽 .form-stack) 에서 적용. */
body #page-wrapper fieldset .form-stack.form-stack--2col > .form-group {
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* fieldset 안의 라벨은 연한 톤 (인풋 강조) */
body #page-wrapper fieldset .form-stack > .form-group > label.form-label {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 500 !important;
}

/* form-inline 의 부모(예: form-stack 또는 col-lg-6)는 wrap 허용 */
.form-inline,
.pp-form-row {
    flex-wrap: wrap !important;
}

.form-help-inline > i {
    margin-right: 4px !important;
    color: var(--subtle-foreground, #9ca3af) !important;
}

.form-help-inline > code {
    background: var(--muted, #f3f4f6) !important;
    color: var(--foreground, #111827) !important;
    padding: 1px 6px !important;
    border-radius: 3px !important;
    font-size: 11px !important;
}

/* 폼 컨트롤 세로 스택 — 자식 (input-group, form-group, fieldset 등) 사이 일정 간격 */
.form-stack {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.form-stack > * {
    margin: 0 !important;
}

/* 온톨로지 좌측 카운트 카드 — 사이트 트리 하단 (구역/라인/설비/태그 카운트) */
.onto-count-stack {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 16px !important;
    padding: 0 8px !important;
}

.onto-count-card {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 40px;
    padding: 0 18px !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-bottom: 2px solid var(--primary, var(--pp-primary)) !important;
    border-radius: 100px !important;
    font-size: 16px !important;
    font-weight: 600 !important;
    color: var(--foreground, #111827) !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04) !important;
}

.onto-count-card .onto-count-icon {
    font-size: 18px !important;
    color: var(--primary, var(--pp-primary)) !important;
}

.onto-count-card .onto-count-value {
    font-size: 16px !important;
    color: var(--foreground, #111827) !important;
}

/* 온톨로지 우측 도메인 패널 — 입력 그룹 좌측 라벨 (MIN/MAX/HI/LO/HI_HI...) 통일 폭 */

.onto-range-addon + .form-control {
    border-left: 0 !important;
}

#tag_alarm .form-group .input-group + .input-group {
    margin-top: 4px !important;
}

/* 공통 fieldset 폼 레이아웃 — 패널 내부 시맨틱 그룹화 */
.form-fieldset {
    border: 0 !important;
    margin: 0 0 14px 0 !important;
    padding: 0 !important;
}

.form-fieldset:last-child {
    margin-bottom: 0 !important;
}

.form-fieldset > legend {
    display: block;
    width: 100%;
    margin-bottom: 8px !important;
    padding: 0 0 4px 0 !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--foreground, #111827) !important;
    border: 0 !important;
    border-bottom: 1px solid var(--pp-border) !important;
    line-height: 1.4 !important;
}

.form-fieldset > legend > i {
    color: var(--primary, var(--pp-primary)) !important;
    margin-right: 4px !important;
}

/* fieldset legend 의 기본 정보 [TYPE] tag */


.asset-tree-meta > i {
    margin-right: 4px !important;
    color: var(--subtle-foreground, #9ca3af) !important;
}

/* health-badge 시맨틱 modifier (배경 + pill 형태) — 디자인 시스템에서 인라인 style 대신 사용 */
body .health-badge.health-badge-ok {
    display: inline-block;
    padding: 2px 10px !important;
    border-radius: 10px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1.4 !important;
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body .health-badge.health-badge-ok    { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }


/* 카드 헤더 하단 보더 없음(표준, 사용자 요청) — 기존 전역 border-bottom 규칙 제거. */
/* 컬러 헤더 (그라데이션 배경) — 흰색 약 보더 */
body #page-wrapper .card.card-primary > .card-header,
body #page-wrapper .card.card-dark > .card-header,
body #page-wrapper .card.card-second > .card-header,
body #page-wrapper .card.card-info > .card-header,
body #page-wrapper .card.card-warning > .card-header,
body #page-wrapper .card.card-danger > .card-header,
body #page-wrapper .card.card-success > .card-header,
body #page-wrapper .card.card-impo > .card-header {
    border-bottom: 1px solid rgba(255, 255, 255, 0.15) !important;
}
/* 그라데이션 라인 ::after 비활성 (이중선 방지) */
body .card-header::after {
    display: none !important;
}


/* ============================================================
 * 모델 트리 패널 footer v2 — 다중 행 메타 표시
 * ============================================================ */
body .model-tree-footer-v2 {
    background: oklch(0.97 0.005 286) !important;
    border-top: 1px solid var(--border, var(--pp-border)) !important;
    padding: 10px 14px !important;
    display: flex;
    flex-direction: column;
    gap: 6px;
    border-bottom-left-radius: 12px !important;
    border-bottom-right-radius: 12px !important;
}
body .model-tree-foot-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px !important;
    flex-wrap: wrap;
}
body .model-tree-foot-label {
    color: oklch(0.55 0.016 286) !important;
    font-weight: 600 !important;
    width: 100px;
    flex-shrink: 0;
}
body .model-tree-foot-label > i {
    margin-right: 4px !important;
    font-size: 10px !important;
}
body .model-tree-foot-path {
    color: oklch(0.21 0.006 286) !important;
    font-weight: 500 !important;
    font-size: 11px !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    min-width: 0;
    flex: 1;
}
body .model-tree-foot-count {
    font-weight: 700 !important;
    color: oklch(0.21 0.006 286) !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
}
body .model-tree-foot-meta {
    color: oklch(0.55 0.016 286) !important;
    font-size: 10px !important;
    margin-left: auto !important;
}


/* model-tree-toolbar 상단 보더 추가 */
body .model-tree-toolbar {
    border-top: 1px solid var(--border, var(--pp-border)) !important;
}



/* asset/plugin/index.jsp — 좁은 KPI 헤더 (col-w-55/60/70) 영문 텍스트 ellipsis */
#oee_data_table > thead > tr > th,
#ram_data_table > thead > tr > th,
#ems_data_table > thead > tr > th {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* === pp-28-tree.css === */
/* ============================================================================
 * pp-06a-tree.css
 * 영역: jstree 전반 (기본 dotted 라인 유지, 톤 매핑, 들여쓰기 축소, padding 정상화)
 *        ds-search-toolbar / 데이터 테이블 컬럼 폭(col-w-NN) / ds-chart-empty
 * 분할: 2026-05-15 (Phase 2) — 원본 pp-06-asset-tree.css 1696라인 분할
 * ============================================================================ */
/* ============================================================
 * jstree — 아이콘은 정상 유지하면서 우리 톤만 가볍게 적용
 * ============================================================ */
/* anchor 톤 — 호버/선택 navy */
body .jstree-default .jstree-anchor,
body .jstree-default-large .jstree-anchor {
    color: oklch(0.30 0.006 286) !important;
    transition: background 0.1s, color 0.1s;
}
body .jstree-default .jstree-icon {
    margin-right: 0px !important;
    /* 아이콘(themeicon·ocl 공통 .jstree-icon)을 anchor(line-height 26px) 수직 중앙에 — 기본 vertical-align:top 이라 위로 떠 보이던 문제 보정 */
    vertical-align: middle !important;
    /* @layer 격리로 벤더 jstree(line-height:24px) 가 layer(vendor) 로 내려가, unlayered FontAwesome 의 line-height:1 이 이김 →
       FA 테마아이콘 글리프가 24px 박스 상단에 붙어 위로 떠 보였다. 박스 높이로 line-height 복원(unlayered, 특정성 0,2,1 로 FA 를 이김 — 강제선언 불필요). */
    line-height: 24px;
}
/* 트리 텍스트 13px + 아이콘·텍스트 수직 중앙(inline-flex) — baseline 어긋남으로 텍스트가 위로 떠 보이던 문제 제거.
   gap 으로 아이콘↔텍스트 간격 복원(inline-flex 전환으로 사라졌던 좌우 여백), padding 으로 행 양옆 여백. */
body .jstree-default .jstree-anchor {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0 8px !important;
    font-size: 13px;
    margin-left: -6px;
}
/* 텍스트 12px 로 줄여도 노드 아이콘(FA themeicon) 글리프 크기는 유지 */
body .jstree-default .jstree-themeicon {
    font-size: 14px;
}
/* body .jstree-default .jstree-anchor:hover/.jstree-hovered, .jstree-wholerow-hovered
   정의는 pp-05-cards.css (763, 803 라인) 룰 재사용 */
body .jstree-default .jstree-clicked,
body .jstree-default .jstree-anchor.jstree-clicked,
body .jstree-default .jstree-wholerow-clicked {
    background: rgba(0, 61, 143, 0.10) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: none !important;
    border: 0 !important;
    padding-right: 3px !important;
}


/* 다이얼로그 footer — zinc-50 배경 (form-content-footer 와 통일) */
body .modal-footer {
    background: oklch(0.97 0.005 286) !important;
    border-top: 1px solid var(--border, var(--pp-border)) !important;
    border-bottom-left-radius: 14px !important;
    border-bottom-right-radius: 14px !important;
}


/* 다이얼로그 header — title/icon/close 모두 수직 중앙 정렬 */
body .modal-header {
    display: flex !important;
    align-items: center !important;
    gap: 12px;
}
body .modal-header .modal-title,
body .modal-header h4.modal-title,
body .modal-header h3.modal-title,
body .modal-header h2.modal-title {
    display: inline-flex !important;
    align-items: center !important;
    gap: 8px;
    margin: 0 !important;
    padding: 0 !important;
    line-height: 1.4 !important;
    flex: 1 1 auto !important;
    min-width: 0;
}
body .modal-header .modal-title > i,
body .modal-header h4.modal-title > i,
body .modal-header h3.modal-title > i,
body .modal-header h2.modal-title > i {
    font-size: 18px !important;
    line-height: 1 !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
}

/* 닫기 버튼 — 정사각 + 중앙 정렬, 타이틀과 동일 baseline */
body .modal-header .btn-close,
body .modal-header button.btn-close {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    align-self: center !important;
    margin: 0 0 0 auto !important;
    padding: 0 !important;
    width: 32px !important;
    height: 32px !important;
    flex: 0 0 32px !important;
    line-height: 1 !important;
    font-size: 14px !important;
    background: transparent !important;
    border: 0 !important;
    border-radius: 6px !important;
    color: var(--muted-foreground) !important;
    opacity: 1 !important;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    text-shadow: none !important;
}
body .modal-header .btn-close > i,
body .modal-header button.btn-close > i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1 !important;
    font-size: 14px !important;
    width: auto;
    height: auto;
}
body .modal-header .btn-close:hover,
body .modal-header button.btn-close:hover {
    background: var(--muted, #f3f4f6) !important;
    color: var(--foreground) !important;
}


/* PPStatusTimeline 호스트 — SVG 위 여백 최소화 */
body .ds-stl-host,
body .card-body > .ds-stl-host {
    padding: 0 !important;
    margin: 0 !important;
}
body .pp-status-timeline svg {
    display: block;
    margin: 0 !important;
}
/* 자산 패밀리 타임라인 행 라벨을 FontAwesome 글리프(연결=wifi \f1eb, 건강=heart \f004)로 렌더.
 * 라벨은 SVG <text> 라 <i> 태그가 안 먹어, asset/index·dashboard-{site,area,line,equipment}.js
 * 가 라벨값을 FA 유니코드로 넣고 여기서 FA Pro Light 폰트를 입힌다. 자산 패밀리 컨테이너 5종으로
 * 스코프(connect/map/order/monitoring/design-system 등 빈/텍스트 라벨 타임라인엔 무관 — 빈 라벨은 no-op).
 * pp-33-dashboards.css 의 .timeline-label{font-family:sans-serif !important} 를 이겨야 해 ID+!important. */
#health_timeline .timeline-label,
#connection_timeline .timeline-label,
#info_connection_timeline .timeline-label,
#asset_connection_timeline .timeline-label,
#alarm_timeline .timeline-label {
    font-family: "Font Awesome 7 Pro" !important;
    font-weight: 300 !important;
    font-size: 18px !important;
}
/* asset/tree 전용 — 타임라인 행 아이콘(wifi/heart) 미표시. 트리만 .asset-tree-tl-bar 스코프. */
#health_timeline.asset-tree-tl-bar .timeline-label {
    display: none;
}
/* panel-body 안 ds-stl-host 만 들고 있을 때 — 기본 panel-body 패딩 유지 (이전 4px 축소 시도는 되돌림) */
body .card-body:has(> .ds-stl-host) {
    padding-top: 14px !important;
    padding-bottom: 22px !important;
}

/* ============================================================
 * jstree — 하위 노드 들여쓰기 축소 (기본 24px → 14px)
 * 좁은 패널 안에서 깊은 트리도 잘 보이도록
 * ============================================================ */
body .jstree-default .jstree-children,
body .jstree-default-large .jstree-children {
    margin-left: 14px !important;
    padding-left: 0 !important;
}

/* 1depth(root) 자식은 들여쓰기 0 — 좌측 끝 정렬 */
body .jstree-default > .jstree-container-ul,
body .jstree-default > ul.jstree-children,
body .jstree-default > .jstree-children,
body .jstree-default-large > .jstree-container-ul,
body .jstree-default-large > ul.jstree-children,
body .jstree-default-large > .jstree-children {
    margin-left: 0 !important;
    padding-left: 0 !important;
}

/* asset/tree 모델 패널 — jstree 노드 margin-left 를 24px(기본) → 10px 로 축소.
 * 점선(.jstree-node 배경)이 노드와 함께 이동하면서 연결선 정렬이 유지된다 (라인 깨지지 않음).
 * jstree 기본 `.jstree-default .jstree-node{margin-left:24px}` 를 id 우선순위 + !important 로 덮어씀. */
body #assetTreeDiv .jstree-node,
body #opcTreeDiv .jstree-node {
    margin-left: 10px !important;
}

/* ===========================================================================
 * 디자인 마이그레이션 — 다이얼로그 폼 + 캔버스 에디터 공통 정규화
 * (DESIGN-MIGRATION.md 2026-05-10 적용)
 * =========================================================================== */

/* ── ds-dialog-form: 다이얼로그 안에서 사용하는 폼 래퍼.
 *    profile/application 같은 모달 내부 컨텐츠가 인라인 padding 으로 정렬되던
 *    것을 단일 클래스로 통합. */
.ds-dialog-form {
    padding: 12px 14px 6px 14px !important;
}

.ds-dialog-form fieldset {
    margin-bottom: 0 !important;
}

.ds-dialog-form .form-inline .form-control,
.ds-dialog-form .pp-form-row .form-control {
    min-width: 220px;
}

/* fieldset 사이 간격 — 명시적 spacer */

/* ── ds-dialog-footer: 모달 폼 하단 액션 영역.
 *    좌측 = 취소/보조, 우측 = 주요 액션. form-content-footer 와 시맨틱 동일하나
 *    모달 안쪽의 마진/구분선 톤은 약하게. */
.ds-dialog-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 16px !important;
    padding-top: 12px !important;
    border-top: 1px solid var(--pp-border) !important;
}

.ds-dialog-footer .ds-dialog-footer-left,
.ds-dialog-footer .ds-dialog-footer-right {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* ── canvas-edit-panel: 캔버스 에디터 좌측 패널의 컴팩트 톤.
 *    margin-bottom: 10px 인라인 스타일을 클래스로 이전. */
.canvas-edit-panel {
    margin-bottom: 10px !important;
}

/* 위젯 팔레트 헤더는 컴팩트 padding */
.canvas-edit-heading-compact {
    padding: 8px 10px !important;
}

/* 캔버스 에디터 저장/목록 액션 영역 (form-content-footer 미사용 변형) */
.canvas-edit-actions {
    margin-bottom: 20px !important;
    display: flex;
    align-items: center;
    gap: 8px;
}

.canvas-edit-actions .float-end {
    margin-left: auto !important;
}

/* ── card-flush: 패널을 다른 패널과 시각적으로 붙여 배치할 때.
 *    map index 의 KPI/side-panel 처럼 sticky 또는 grid cell 안에 들어가
 *    bottom margin 이 불필요한 경우. */
body #page-wrapper .card.card.card-flush {
    margin-bottom: 0 !important;
}

/* ===========================================================================
 * 검색 툴바 (ds-search-toolbar) — 검색이 복잡한 화면(태그 등)이 페이지
 *  헤더 직하단에 별도 검색 패널을 올릴 때 사용. panel-default 위에
 *  덧붙는 시맨틱 modifier.
 * =========================================================================== */
body #page-wrapper .card.card.ds-search-toolbar > .card-body {
    
}

/* tag/index 검색 폼 — 일관된 간격
 *   row gap: 12px (수직), 24px (필드 사이)
 *   field 내부: label 자연 폭 + 8px → input
 */
.tag-search-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.tag-search-row {
    display: flex;
    flex-wrap: wrap;
    column-gap: 24px;
    row-gap: 12px;
    align-items: center;
}

.tag-search-row .tag-search-field {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}

.tag-search-row .tag-search-field > label.form-label.form-label {
    width: 70px;
    margin: 0 !important;
    padding: 0 10px 0 0 !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 12px !important;
    white-space: nowrap !important;
    text-align: right !important;
    flex: 0 0 70px;
}

.tag-search-row .tag-search-field > .form-control {
    width: 180px;
}

.tag-search-row .tag-search-field-wide > .form-control {
    width: 220px;
}

.tag-search-row .tag-search-actions {
    margin-left: auto !important;
    display: flex;
    align-items: center;
    gap: 6px;
}

.tag-search-row .tag-search-actions .btn {
    min-width: 110px;
}

/* ===========================================================================
 * 데이터 테이블 컬럼 가로폭 표준 — 인라인 style="width:NNpx" 제거 후 사용
 * =========================================================================== */
.table > thead > tr > th.col-w-40 { width: 40px; }
.table > thead > tr > th.col-w-50 { width: 50px; }
.table > thead > tr > th.col-w-60 { width: 60px; }
.table > thead > tr > th.col-w-70 { width: 70px; }
.table > thead > tr > th.col-w-80 { width: 80px; }
.table > thead > tr > th.col-w-90 { width: 90px; }
.table > thead > tr > th.col-w-110 { width: 110px; }

/* edge/index — O/S 호스트명 컬럼은 가변 폭이지만 최소 200px */
.table > thead > tr > th.edge-host-col {
    min-width: 200px;
}
.table > thead > tr > th.col-w-100 { width: 100px; }
.table > thead > tr > th.col-w-120 { width: 120px; }
.table > thead > tr > th.col-w-140 { width: 140px; }
.table > thead > tr > th.col-w-150 { width: 150px; }
.table > thead > tr > th.col-w-160 { width: 160px; }
.table > thead > tr > th.col-w-180 { width: 180px; }
.table > thead > tr > th.col-w-200 { width: 200px; }
.table > thead > tr > th.col-w-220 { width: 220px; }
.table > thead > tr > th.col-w-250 { width: 250px; }
.table > thead > tr > th.col-w-280 { width: 280px; }
.table > thead > tr > th.col-w-300 { width: 300px; }
.table > thead > tr > th.col-w-380 { width: 380px; }
.table > thead > tr > th.col-w-400 { width: 400px; }
.table > thead > tr > th.col-w-450 { width: 450px; }
.table > thead > tr > th.col-w-500 { width: 500px; }

/* 고정 레이아웃 + word-break 표준 */
.table.table-fixed {
    table-layout: fixed;
}

.table.table-fixed > tbody > tr > td {
    word-break: break-all;
}

/* 클릭 가능한 행 / id-badge */
.table > tbody > tr.row-clickable {
    cursor: pointer;
}

.id-badge.id-badge-clickable {
    cursor: pointer;
}

/* order/index — 타임라인 패널 body */
.card.card > .card-body.order-timeline-body #data_timeline {
    background: var(--background, var(--pp-white)) !important;
    height: 100%;
}

/* order/index — 데이터 테이블 헤더가 2-row 인 경우 중간/하단 보더 톤 */


/* 패널 헤딩 보조 메타 (count, last-updated 같은 작은 정보) */
.card-head-title .card-head-meta,
.card-head-meta {
    font-weight: 400 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 12px !important;
    margin-left: 4px !important;
}

/* 빈 메타는 좌측 마진 제거 — 헤더 우측 phantom 공간 방지 */
.card-head-meta:empty {
    margin: 0 !important;
    display: none;
}

/* nav-tabs + tab-content 강제 룰 제거 — 부모/페이지 룰이 자유롭게 정의 */

/* tab-content 가 panel-body 도 겸하는 경우 — 중복 패딩 방지 */
body .nav-tabs + .tab-content.card-body {
    padding: 16px !important;
}

/* 좌측 사이드 네비게이션 — 알람 메뉴 옆 info/warn/error 카운트 뱃지 (3개 붙여서 segmented bar) */
.nav-alarm-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px !important;
    border: 0 !important;
    border-radius: 0 !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1 !important;
    color: var(--pp-white) !important;
}

/* 3개가 한 segmented pill 처럼 붙어 보이도록 — 부모 a 의 gap:12px 를 음수 마진으로 상쇄 */
.pp-nav-section-items > a > .nav-alarm-count + .nav-alarm-count {
    margin-left: -12px !important;
}

/* segmented pill 의 좌/우 라운드는 클래스로 직접 지정 (부모 a 안에 다른 span 이 섞여 있어 :first-of-type 미동작) */
.pp-nav-section-items > a > .nav-alarm-count.nav-alarm-count-info {
    margin-left: auto !important;
    border-top-left-radius: 8px !important;
    border-bottom-left-radius: 8px !important;
}
.pp-nav-section-items > a > .nav-alarm-count.nav-alarm-count-error {
    border-top-right-radius: 8px !important;
    border-bottom-right-radius: 8px !important;
}

.nav-alarm-count-info  { background: var(--pp-tone-info-bg) !important; }
.nav-alarm-count-warn  { background: var(--pp-tone-warn-bg) !important; }
.nav-alarm-count-error { background: var(--pp-tone-danger-bg) !important; }

/* 좌측 사이드 네비게이션 — 플로우 메뉴 옆 에러 카운트 뱃지 (단일, 오른쪽 끝 정렬) */
.pp-nav-section-items > a > .nav-flow-count {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    margin-left: auto !important;
    min-width: 16px !important;
    height: 16px !important;
    padding: 0 6px !important;
    border: 0 !important;
    border-radius: 8px !important;
    background: oklch(0.55 0.22 27) !important;
    color: var(--pp-white) !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1 !important;
}

/* 패널 헤더 카운트 뱃지 (타이틀 바로 뒤 — [N] 패턴 대체) */
.card-head-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    height: 20px;
    padding: 0 7px !important;
    background: var(--muted, #f3f4f6) !important;
    color: var(--foreground, #111827) !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    line-height: 1 !important;
}

/* ===========================================================================
 * 차트 비어 있을 때 안내 — pill 스타일 (panel-body 안에서 사용)
 * =========================================================================== */
.ds-chart-empty {
    text-align: center !important;
    padding: 40px 0 !important;
}

/* NOTE: .ds-chart-empty-pill 의 단일 정의는 pp-07-canvas.css 로 이전.  여기는 .ds-chart-empty 만 보유. */

/* asset/data — 시간대별 차트 패널 body */
body #page-wrapper .card.card > .card-body.asset-data-chart-body {
    padding: 5px !important;
}

.asset-data-chart {
    width: 100%;
    height: 140px;
    display: none;
}

.alarm-timeline-canvas {
    background: var(--pp-white) !important;
    height: 100%;
    display: none;
}

.alarm-count-strip {
    height: 50px;
    text-align: center !important;
    border-bottom: 1px solid var(--pp-border) !important;
    display: flex;
    align-items: center;
    justify-content: center;
}

.alarm-count-label {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 26px !important;
    font-weight: 700 !important;
}

.alarm-charts-area {
    display: none;
}

.alarm-trend-row {
    margin-top: 10px !important;
}

.alarm-trend-spark {
    width: 100%;
    height: 150px;
}

.alarm-pie-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-top: 24px !important;
    margin-bottom: -10px !important;
}

.alarm-pie {
    height: 150px;
    text-align: center !important;
    color: var(--subtle-foreground, #ddd) !important;
    opacity: 0.7 !important;
}

body #page-wrapper .card.card > .card-body.alarm-list-body {
    min-height: 500px;
}

body #page-wrapper .card.card > .card-body.alarm-rank-body {
    min-height: 375px;
}

.alarm-rank-tabs {
    padding: 0 !important;
    margin: 0 !important;
}

.alarm-rank-pane {
    min-height: 231px;
}

/* diagnostic/index 통계 패널 헬퍼 */
.diag-total-strip {
    height: 50px;
    text-align: center !important;
    border-bottom: 1px solid var(--pp-border) !important;
    line-height: 50px !important;
    margin-bottom: 15px !important;
}

.diag-total-label {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 22px !important;
    font-weight: 700 !important;
}

.diag-level-chart {
    width: 100%;
    height: 150px;
    margin-top: 50px;   /* 상단 뱃지와 간격 확보 */
}
/* 데이터 없음 빈상태 — 차트 영역만큼 높이를 차지해 아이콘/문구를 세로 중앙에 배치 */
#diag_stats_empty {
    min-height: 200px;
    justify-content: center;
}

.diag-hourly-chart {
    width: 100%;
    height: 170px;
}

.diag-app-chart {
    width: 100%;
    height: 140px;
}

body #page-wrapper .card.card > .card-body.diag-chart-body {
    padding: 5px !important;
}

/* diagnostic/index — 타임라인 캔버스 + 패널 body 컴팩트 (하단 빈 공간 제거) */
body .diag-timeline-body #alarm_timeline.alarm-timeline-canvas {
    min-height: 130px !important;
    height: 130px !important;
}
body .card.card > .card-body.diag-timeline-body {
    padding-top: 8px !important;
    padding-bottom: 8px !important;
}
body .diag-timeline-body #alarm_timeline_cover {
    min-height: 0 !important;
    height: auto !important;
}

.diagnostic-ai-summary {
    border-left: 3px solid var(--pp-accent, #2f80ed) !important;
}

.diagnostic-ai-empty {
    min-height: 54px;
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-size: 13px;
}

.diagnostic-ai-content {
    display: block;
}

.diagnostic-ai-headline {
    display: flex;
    align-items: center;
    gap: 10px;
    padding-bottom: 12px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--pp-border, #dcdfe6);
}

.diagnostic-ai-headline strong {
    flex: 1;
    min-width: 0;
    font-size: 15px;
    color: var(--foreground, #333);
    overflow-wrap: anywhere;
}

.diagnostic-ai-context {
    color: var(--muted-foreground, #777);
    font-size: 12px;
    white-space: nowrap;
}

.diagnostic-ai-severity {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 72px;
    height: 26px;
    padding: 0 10px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 700;
    color: #fff;
    background: #8a93a3;
}

.diagnostic-ai-severity.is-info {
    background: var(--pp-tone-info-bg);
}

.diagnostic-ai-severity.is-warn {
    background: var(--pp-tone-warn-bg);
}

.diagnostic-ai-severity.is-error {
    background: #c93c37;
}

.diagnostic-ai-summary-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
}

.diagnostic-ai-column,
.diagnostic-ai-evidence {
    min-width: 0;
}

.diagnostic-ai-column h4,
.diagnostic-ai-evidence h4 {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 700;
    color: var(--foreground, #333);
}

.diagnostic-ai-column ul,
.diagnostic-ai-evidence ul {
    margin: 0;
    padding-left: 18px;
}

.diagnostic-ai-column li,
.diagnostic-ai-evidence li {
    margin-bottom: 5px;
    color: var(--foreground, #333);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.diagnostic-ai-column li.is-empty,
.diagnostic-ai-evidence li.is-empty {
    color: var(--muted-foreground, #777);
}

.diagnostic-ai-evidence {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px dashed var(--pp-border, #dcdfe6);
}

.diagnostic-ai-report {
    border-color: var(--pp-border, #dcdfe6);
}

.diagnostic-ai-report-grid {
    margin-top: 12px;
}

.diagnostic-ai-report-handover {
    margin: 0;
    line-height: 1.55;
    color: var(--foreground, #333);
    overflow-wrap: anywhere;
}

@media (max-width: 991px) {
    .diagnostic-ai-summary-grid {
        grid-template-columns: 1fr;
    }

    .diagnostic-ai-headline {
        align-items: flex-start;
        flex-direction: column;
    }

    .diagnostic-ai-context {
        white-space: normal;
    }
}

/* performance/index 차트 패널 헬퍼 */
body #page-wrapper .card.card > .card-body.perf-stream-body {
    position: relative;
}

.perf-stream-current {
    position: absolute;
    left: 80px;
    top: 45px;
    z-index: 1;
    font-size: 20px !important;
    background: var(--pp-white) !important;
    color: var(--foreground, #555) !important;
    border: 2px solid var(--pp-border, #ddd) !important;
    border-radius: 5px !important;
    width: 150px;
    text-align: center !important;
    padding: 4px 0 !important;
    font-style: italic !important;
}

.perf-stream-current-unit {
    font-size: 12px !important;
    margin-left: 4px !important;
}

.perf-stream-min {
    position: absolute;
    right: 60px;
    top: 45px;
    z-index: 1;
    font-size: 20px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-style: italic !important;
}

.perf-stream-chart {
    width: 100%;
    height: 250px;
}

.perf-stat-strip {
    height: 50px;
    text-align: center !important;
    border-bottom: 1px solid var(--pp-border) !important;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
}

.perf-stat-num {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 26px !important;
    font-weight: 700 !important;
}

.perf-stat-unit {
    font-size: 16px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
}

.perf-queue-chart {
    width: 100%;
    height: 200px;
}

.perf-cpu-chart {
    width: 100%;
    height: 160px;
}

.perf-cpu-spark {
    width: 100%;
    height: 40px;
}

.perf-large-chart {
    width: 100%;
    height: 200px;
    padding: 10px !important;
}

body #page-wrapper .card.card > .card-body.perf-overlay-body {
    position: relative;
}

.perf-overlay-pill {
    position: absolute;
    right: 20px;
    bottom: 30px;
    z-index: 1;
    font-size: 14px !important;
    background: var(--pp-white) !important;
    color: var(--foreground, #555) !important;
    border: 2px solid var(--pp-border, #ddd) !important;
    border-radius: 5px !important;
    width: 150px;
    text-align: center !important;
    padding: 4px 0 !important;
    font-style: italic !important;
}

.perf-overlay-pill-wide {
    width: 250px;
}

.perf-overlay-pill-unit {
    font-size: 12px !important;
    margin-left: 4px !important;
}

/* monitoring/index — 컴팩트 패널 헤딩 (밀도 높은 타일) */
body #page-wrapper .card.card > .card-header.card-head-compact {
    padding: 8px 12px !important;
}

/* monitoring 패널 헤딩 안 보조 inline 메타 (예: PPS 라벨 옆 작은 텍스트) */
.card-head-compact .card-head-meta {
    color: var(--subtle-foreground, #bbb) !important;
}

/* monitoring panel-body padding 제거 (차트/heatmap 그리드가 외곽까지 가득) */
body #page-wrapper .card.card > .card-body.mon-flush-body {
    padding: 0 !important;
    overflow: hidden;
}

/* connect/index — 프로토콜 그리드 */



/* security/form — 제어 자산 스코프 피커 트리 (보안정책 스코프 S3).
 * 새 클래스 사유: BS5 유틸리티에는 고정 max-height 가 없어 스크롤 상한을 잡을 수 없다
 * (overflow-auto 는 JSP 쪽 BS5 유틸로 처리, 여기는 높이 상한만). */
.pp-scope-tree {
    max-height: 340px;
    min-height: 120px;
}

/* === pp-29-canvas.css === */
body #page-wrapper .card.card > .card-body.connect-protocol-grid .col-lg-12 {
    padding-left: 0 !important;
    padding-right: 0 !important;
    margin-bottom: 0 !important;
}

/* connect/index — 프로토콜 카드 모던 재디자인 */
body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part {
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 12px !important;
    padding: 18px 14px 0 !important;
    margin: 0 !important;
    height: auto !important;
    min-height: 150px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04) !important;
    transition: border-color 0.18s, box-shadow 0.18s, transform 0.18s;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part:hover {
    border-color: var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: 0 8px 20px rgba(0, 61, 143, 0.10) !important;
    transform: translateY(-2px);
}

/* 이미지 영역 — 카드 상단 중앙 */
body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part .text {
    min-height: 76px;
    margin: 0 !important;
    padding: 0 0 14px 0 !important;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 auto;
    height: auto !important;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part img,
body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part .text img {
    height: 50px !important;
    width: auto !important;
    max-width: 100%;
    margin: 0 !important;
    object-fit: contain;
    display: inline-block;
    transition: transform 0.18s;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part:hover img {
    transform: scale(1.06);
}

/* 하단 링크 영역 — 버튼 톤의 "연결하기" */
body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part .con-link-box {
    margin: 0 -14px !important;
    padding: 10px 12px !important;
    border-top: 1px solid var(--pp-border, #f3f4f6) !important;
    background: var(--muted, #fafafa) !important;
    text-align: center !important;
    transition: background 0.18s;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part:hover .con-link-box {
    background: rgba(0, 61, 143, 0.06) !important;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part .con-link-box a {
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    text-decoration: none !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    transition: color 0.12s;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part:hover .con-link-box a {
    color: var(--primary, var(--pp-primary-strong)) !important;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part .con-link-box a::after {
    content: "\f105";
    font-family: "Font Awesome 7 Pro" !important;
    font-weight: 100 !important;
    font-size: 11px !important;
    margin-left: 2px !important;
    transition: transform 0.18s;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid .box-part:hover .con-link-box a::after {
    transform: translateX(3px);
}

/* 프로토콜 카드 박스 — 횡렬 배치. col-* 박스가 .row 없이 card-body 직속이라
   BS5 flex-grid 에선 flex 부모가 없어 세로로 쌓인다 → 컨테이너를 flex 로(BS3 float 대체). */
body #page-wrapper .card.card > .card-body.connect-protocol-grid {
    display: flex !important;
    flex-wrap: wrap !important;
}
/* col-lg-2 등 컬럼 간격 — 카드 사이 가로/세로 균일 거터(좌우 6px → 카드간 12px) */
body #page-wrapper .card.card > .card-body.connect-protocol-grid .col-lg-2,
body #page-wrapper .card.card > .card-body.connect-protocol-grid .col-md-2,
body #page-wrapper .card.card > .card-body.connect-protocol-grid .col-12 {
    padding-left: 6px !important;
    padding-right: 6px !important;
    padding-bottom: 12px !important;
}

.connect-footer-help {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-align: right !important;
    font-size: 12px !important;
    margin-top: 12px !important;
}

/* order/view ISO 패널 (OEE/RAM/EMS) */
body #page-wrapper .card.card > .card-body.order-iso-body {
    position: relative;
    min-height: 250px;
}

.order-iso-empty {
    display: none;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 100;
    font-size: 13px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}

/* 차트 비어있을 때 안내 pill (단일 정의 — 이전 pp-06a 의 padding/font-size 보존) */
.ds-chart-empty-pill {
    display: inline-block;
    padding: 5px 15px !important;
    border: 1px solid var(--pp-border) !important;
    background: var(--pp-white) !important;
    border-radius: 32px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 14px !important;
}

.order-iso-chart {
    width: 100%;
    height: 200px;
}

.order-iso-stats {
    font-size: 11px !important;
    margin-bottom: 0 !important;
    margin-top: 10px !important;
}

/* order/view 우측 사이드 차트들 */
body #page-wrapper .card.card > .card-body.order-side-chart-body {
    padding: 10px !important;
    position: relative;
    min-height: 220px;
}
/* 설비 상태 타임라인은 단일 행 d3 타임라인(~70px)이라 220px 패널이면 상하 공백 과다 →
   해당 카드만 콘텐츠 높이로(나머지 echarts 사이드차트 220px 는 유지). */
body #page-wrapper .card.card > .card-body.order-side-chart-body:has(#equip_status_timeline) {
    min-height: 0 !important;
}

.order-side-chart {
    width: 100%;
    height: 220px;
}

/* tall 변형 — 좌측 메인 영역으로 옮긴 후 동일 높이로 통일 */
.order-side-chart.order-side-chart-tall {
    height: 220px;
}

/* asset/dashboard 트렌드 행 + 테이블 로딩 */
.row.ov-trend-row {
    padding: 0 15px !important;
}

.ov-data-table > tbody > tr > td.ov-table-loading {
    text-align: center !important;
    color: var(--subtle-foreground, #ccc) !important;
}

/* line.jsp 하위 설비 카드 컨테이너 */
body #page-wrapper .card.card > .card-body.line-child-body {
    padding: 0 0 10px 0 !important;
}

.line-child-loading {
    text-align: center !important;
    color: var(--subtle-foreground, #ccc) !important;
    padding: 30px !important;
}

/* statistics — 날짜 미선택 안내 (히트맵 placeholder)
 * 페이지 컨텐츠 좌우 24px 와 정렬되도록 자체 padding 사용 */
.stat-detail-placeholder {
    display: none;
    padding: 60px 24px !important;
}

/* connection-tag-list 헤더 안 전체선택 링크 */
.conn-check-all-link {
    cursor: pointer;
    color: inherit !important;
    text-decoration: none !important;
}

/* analysis/oee, ram, ems 차트 패널 표준 사이즈 */
body #page-wrapper .card.card > .card-body.analysis-chart-body {
    padding: 5px !important;
}

.analysis-chart-280 {
    width: 100%;
    height: 280px;
}

.analysis-chart-300 {
    width: 100%;
    height: 300px;
}

/* map/include sub-panels — 모니터링 사이드바 패널 (기본 1px 보더 사용) */
body #page-wrapper .card.card.mon-side-panel {
    border-width: 1px !important;
}

/* ===========================================================================
 * map/index — 우측 인프라/엔진 사이드 패널
 *  - 글로벌 사이트 맵 패널과 같은 총 높이 (heading + body = map-board-panel)
 *  - body 는 차트 + 메트릭 테이블 스크롤
 * =========================================================================== */
body #page-wrapper .card.card.map-side-panel > .card-body.map-side-body {
    padding: 0 !important;
    height: 530px;
    overflow-y: auto;
    overflow-x: hidden;
    border-top: 1px solid var(--pp-border) !important;
}

.map-side-chart-wrap {
    padding: 4px !important;
}


.map-side-chart {
    width: 100%;
    height: 80px;
}

/* PPS 차트 ↔ 메트릭 테이블 사이 구분 라인 — 시각 노이즈 줄이려고 제거 */
.map-side-divider {
    display: none;
}

/* 실시간 수신 차트 row — 인프라 카테고리 다음에 삽입된 차트 셀.
   td:last-child 의 우측 정렬/굵은 글꼴 룰을 무력화하고 패딩만 지정. */
.map-side-table > tbody > tr.map-side-chart-row > td {
    padding: 0 !important;
    text-align: left !important;
    font-weight: normal !important;
    background: transparent !important;
    border: 0 !important;
    border-top: 1px solid var(--pp-border, #f3f4f6) !important;
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
}

.map-side-table {
    margin: 0 !important;
    font-size: 11px !important;
}

/* 인프라/엔진 사이드 테이블 — 라벨(좌) + 값(우측 정렬) */
.map-side-table > tbody > tr > td {
    padding: 4px 8px !important;
    border-color: var(--pp-border, #f3f4f6) !important;
}
.map-side-table > tbody > tr > td:first-child {
    text-align: left !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    white-space: nowrap !important;
}
.map-side-table > tbody > tr > td:last-child {
    text-align: right !important;
    font-weight: 600 !important;
    color: var(--foreground, #1f2937) !important;
    white-space: nowrap !important;
}
.map-side-table > tbody > tr.side-section-row > td {
    text-align: left !important;
    background: var(--muted, #f8fafc) !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    font-weight: 700 !important;
    padding: 3px 10px 2px 10px !important;
    font-size: 9.5px !important;
    line-height: 1.4 !important;
    text-transform: uppercase !important;
    letter-spacing: 1px !important;
    border: 0 !important;
    border-top: 1px solid var(--pp-border) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    box-shadow: none !important;
    position: sticky;
    top: 0;
    z-index: 1;
}
.map-side-table > tbody > tr.side-section-row > td > i {
    color: var(--primary, var(--pp-primary-strong)) !important;
    margin-right: 5px !important;
}
/* 첫 카테고리(인프라) 위 보더 — 하단 보더와 동일 색상으로 일관성 유지.
   side-section-row 의 border-bottom 과 같은 var(--pp-border) 색상 사용. */
.map-side-table {
    border-top: 1px solid var(--pp-border) !important;
    margin-top: 8px !important;
}
.map-side-table > tbody > tr.side-section-row:first-child > td {
    border-top: 0 !important;
}

/* 인프라 헬스 상태 뱃지 (정상/에러/미상) */
.side-h-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 7px !important;
    border-radius: 10px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1.4 !important;
    letter-spacing: 0.2px !important;
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
.side-h-badge > i {
    font-size: 10px !important;
    line-height: 1 !important;
    color: inherit !important;
}
.side-h-badge-ok   { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.side-h-badge-err  { background: #b91c1c !important;
    color: var(--pp-white) !important;
}
.side-h-badge-mute { background: var(--muted-foreground, #9ca3af) !important; }

/* ===========================================================================
 * 뱃지 텍스트 컬러 일괄 보장 — 화이트 테마에서 진한 배경 위 텍스트는 흰색.
 *  (id-badge 처럼 흰 배경 + 컬러 보더 패턴은 제외)
 * =========================================================================== */
/* ===========================================================================
 * .on-dark — 다크/진한 배경 위의 모든 텍스트 흰색 강제 유틸리티.
 *  - 자체 + 모든 자손 element/link 가 #fff 로 강제됨.
 *  - 라이트 테마에서 진한 배경(navy 600~800, green 700, red 700, orange 700 등)
 *    위 텍스트가 잘 보이도록 보장.
 *  - 사용: <div class="alarm-info on-dark">..</div>, <span class="health-badge on-dark">..</span>
 *  - 컬러 뱃지 패밀리(conn-badge-*, health-badge, alarm-info/warn/error,
 *    alarm-count-cell, diag-level-cell, side-h-badge, opc_obj, cs-agent-cell)는
 *    묵시적으로 .on-dark 와 동일하게 동작 (backward compat).
 * =========================================================================== */
body .on-dark,
body .on-dark *,
body .on-dark a,
body .on-dark a:hover,
body .on-dark a:focus,
body .badge,
body .badge *,
body .conn-badge-ok,
body .conn-badge-ok *,
body .conn-badge-warn,
body .conn-badge-warn *,
body .conn-badge-error,
body .conn-badge-error *,
body .conn-badge-disconnected,
body .conn-badge-disconnected *,
body .conn-badge-unknown,
body .conn-badge-unknown *,
body .health-badge,
body .health-badge *,
body .health-badge-ok,
body .health-badge-ok *,
body .alarm-info,
body .alarm-info *,
body .alarm-warn,
body .alarm-warn *,
body .alarm-error,
body .alarm-error *,
body .alarm-count-cell,
body .alarm-count-cell *,
body .alarm-count-cell-info,
body .alarm-count-cell-info *,
body .alarm-count-cell-warn,
body .alarm-count-cell-warn *,
body .alarm-count-cell-error,
body .alarm-count-cell-error *,
body .diag-level-cell,
body .diag-level-cell *,
body .diag-level-info,
body .diag-level-info *,
body .diag-level-warn,
body .diag-level-warn *,
body .diag-level-error,
body .diag-level-error *,
body .side-h-badge,
body .side-h-badge *,
body .side-h-badge-ok,
body .side-h-badge-ok *,
body .side-h-badge-err,
body .side-h-badge-err *,
body .side-h-badge-mute,
body .side-h-badge-mute *,
body .opc_obj,
body .opc_obj *,
body .cs-agent-cell,
body .cs-agent-cell * {
    color: var(--pp-white) !important;
}

/* 뱃지 안 링크 / hover — 흰색 유지 */
body .conn-badge-ok a,
body .conn-badge-warn a,
body .conn-badge-error a,
body .conn-badge-disconnected a,
body .conn-badge-unknown a,
body .health-badge a,
body .alarm-info a,
body .alarm-warn a,
body .alarm-error a,
body .alarm-count-cell:hover,
body .alarm-count-cell:focus,
body .diag-level-cell a,
body .side-h-badge a {
    color: var(--pp-white) !important;
    text-decoration: none !important;
}
.map-side-table .side-unit {
    font-size: 9px !important;
    color: var(--subtle-foreground, #9ca3af) !important;
    font-weight: 500 !important;
    margin-left: 2px !important;
}


/* === pp-30-diag-kpi.css === */
/* ===========================================================================
 * 진단 레벨 바 (정보/경고/심각) — diagnostic-sidebar.jsp
 *  - 3분할 가로 바 카드, 컬러 배경 + 흰 텍스트
 * =========================================================================== */
.diag-level-bar-wrap {
    padding: 10px 10px 0 10px !important;
}

.diag-level-bar {
    display: flex;
    gap: 0;
    border-radius: 6px !important;
    overflow: hidden;
    opacity: 0.92 !important;
}

.diag-level-cell {
    flex: 1;
    text-align: center !important;
    padding: 6px 4px !important;
    color: var(--pp-white) !important;
}

.diag-level-cell .diag-level-label,
.diag-level-cell .diag-level-label > i {
    font-size: 11px !important;
    color: var(--pp-white) !important;
    font-weight: 600 !important;
    line-height: 1.2 !important;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.diag-level-cell .diag-level-num,
.diag-level-cell .diag-level-num > span {
    font-size: 18px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    margin-top: 2px !important;
}

.diag-level-info  { background: var(--pp-tone-info-bg) !important; }
.diag-level-warn  { background: var(--pp-tone-warn-bg) !important; }
.diag-level-error { background: var(--pp-tone-danger-bg) !important; }

/* ===========================================================================
 * 알람 건수 셀 (정보·경고·심각) — 사이트 카드 / 패널 안 3분할 카운트
 * =========================================================================== */
.alarm-count-cells {
    display: flex;
    gap: 4px;
    align-items: stretch;
}

.alarm-count-cell {
    flex: 1;
    display: inline-flex !important;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center !important;
    padding: 4px 6px !important;
    border-radius: 5px !important;
    text-decoration: none !important;
    color: var(--pp-white) !important;
    font-weight: 700 !important;
    line-height: 1.2 !important;
    transition: filter 0.12s, transform 0.12s;
    min-width: 36px;
}

.alarm-count-cell:hover,
.alarm-count-cell:focus {
    color: var(--pp-white) !important;
    filter: brightness(1.08);
    transform: translateY(-1px);
}

.alarm-count-cell-label {
    font-size: 10px !important;
    font-weight: 600 !important;
    color: rgba(255, 255, 255, 0.85) !important;
    padding-bottom: 2px !important;
    border-bottom: 1px solid rgba(255, 255, 255, 0.18) !important;
    margin-bottom: 2px !important;
    width: 100%;
    letter-spacing: 0.3px !important;
}

.alarm-count-cell-num {
    font-size: 13px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
}

.alarm-count-cell-info  { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; }
.alarm-count-cell-warn  { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; }
.alarm-count-cell-error { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; }

/* ===========================================================================
 * kpi-stat-card — 운영 핵심 지표 6종을 표현하는 카드 컴포넌트.
 *  - 기본 = 아이콘 + 큰 값 + unit + 라벨 + 서브 한 줄
 *  - 모달리티: --gauge (우측 미니 게이지) / --alarms (하단 알람 요약 바)
 *               / --simple (서브 한 줄만)
 *  - 클릭 가능: --clickable
 * 디자인 시스템 카탈로그: /design-system/index — KPI Stat Card 섹션
 * =========================================================================== */

/* 그리드 — 6개 카드를 한 줄에 (반응형 6/3/2/1) */
.kpi-stat-grid {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 10px;
}

@media (max-width: 1400px) {
    .kpi-stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 991px) {
    .kpi-stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 575px) {
    .kpi-stat-grid { grid-template-columns: 1fr; }
}

/* 카드 본체 */
.kpi-stat-card,
a.kpi-stat-card {
    display: flex;
    flex-direction: column;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    padding: 0 !important;
    overflow: hidden;
    text-decoration: none !important;
    color: inherit !important;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04) !important;
}

a.kpi-stat-card:hover,
a.kpi-stat-card:focus,
a.kpi-stat-card:active {
    color: inherit !important;
    text-decoration: none !important;
}

.kpi-stat-card.kpi-stat-card--clickable {
    cursor: pointer;
}

.kpi-stat-card.kpi-stat-card--clickable:hover,
a.kpi-stat-card.kpi-stat-card--clickable:hover {
    border: 1px solid var(--primary, var(--pp-primary-strong)) !important;
    box-shadow: 0 2px 8px rgba(0, 61, 143, 0.10) !important;
    transform: translateY(-1px);
}

/* 비-clickable 카드 hover 시 보더 유지 (버그 가드) */
.kpi-stat-card:not(.kpi-stat-card--clickable):hover {
    border: 1px solid var(--pp-border) !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04) !important;
    transform: none;
}

/* 상단 헤드 — 아이콘 + 값 */
.kpi-stat-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px 8px 14px !important;
    gap: 10px;
}

.kpi-stat-card-icon {
    width: 38px;
    height: 38px;
    border-radius: 8px !important;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 61, 143, 0.08);
    color: var(--primary, var(--pp-primary-strong));
    font-size: 18px !important;
    flex-shrink: 0;
}

.kpi-stat-card-value {
    font-size: 26px !important;
    font-weight: 700 !important;
    color: var(--foreground, #1f2937);
    line-height: 1 !important;
    text-align: right !important;
    white-space: nowrap !important;
}

.kpi-stat-card-unit {
    font-size: 11px !important;
    font-weight: 500 !important;
    color: var(--subtle-foreground, #9ca3af) !important;
    padding-left: 3px !important;
}

/* ── 상태 톤 변형 — 아이콘 배경에 상태 색상 부여(가독성/상태 강조).
 *    사용자 요청: 요약 지표 카드(정상/주의/위험 등)가 한눈에 구분되도록 색상 부여.
 *    success(정상)·warning(주의)·danger(위험)·info(정보) — 상태 토큰 재사용, 신규 색 없음. */
.kpi-stat-card--success .kpi-stat-card-icon { background: var(--pp-tone-success-bg); color: white; }
.kpi-stat-card--warning .kpi-stat-card-icon { background: var(--pp-tone-warn-bg); color: white; }
.kpi-stat-card--danger  .kpi-stat-card-icon { background: var(--pp-tone-danger-bg); color: white; }
.kpi-stat-card--info    .kpi-stat-card-icon { background: var(--pp-tone-info-bg); color: white; }
/* 위험/주의는 값 숫자도 톤 색으로 강조 — 즉시 가독 */
.kpi-stat-card--danger  .kpi-stat-card-value { color: var(--pp-tone-danger-bg); }
.kpi-stat-card--warning .kpi-stat-card-value { color: var(--pp-tone-warn-bg); }

/* 하단 바디 — 라벨 + 서브 */
.kpi-stat-card-body {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px 14px 12px 14px !important;
    border-top: 1px solid var(--pp-border, #f3f4f6) !important;
}

.kpi-stat-card-meta {
    flex: 1;
    min-width: 0;
}

.kpi-stat-card-label {
    font-size: 13px !important;
    font-weight: 600 !important;
    color: var(--foreground, #1f2937) !important;
    margin-bottom: 2px !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

.kpi-stat-card-sub {
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    line-height: 1.3 !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* --gauge: 우측 미니 게이지 */
.kpi-stat-card-gauge {
    width: 56px;
    height: 56px;
    flex-shrink: 0;
}

/* --alarms: 하단 알람 요약 바 */
.kpi-stat-card.kpi-stat-card--alarms .kpi-stat-card-body {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
}

/* 금일 알람 카드 하단 바 — 디자인 시스템 health-badge 패턴 (pill + 흰 텍스트) */
.kpi-stat-card-alarms-bar {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 5px;
}

.kpi-stat-card-alarms-bar > span {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1.5 !important;
    letter-spacing: 0.3px !important;
    color: var(--pp-white) !important;
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.10) !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06) !important;
    transition: filter 0.12s, transform 0.12s;
}

.kpi-stat-card-alarms-bar > span > span {
    font-size: 12px !important;
    font-weight: 800 !important;
    color: var(--pp-white) !important;
    line-height: 1.2 !important;
}

/* 우선순위 톤 — alarm severity 토큰과 동일하게 background/border 고정 */
.kpi-stat-card-alarms-bar > span.alarm-info {
    background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important;
    border: 1px solid var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important;
    color: var(--pp-white) !important;
}
.kpi-stat-card-alarms-bar > span.alarm-warn {
    background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important;
    border: 1px solid var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important;
    color: var(--pp-white) !important;
}
.kpi-stat-card-alarms-bar > span.alarm-error {
    background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important;
    border: 1px solid var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important;
    color: var(--pp-white) !important;
}

.kpi-stat-card-alarms-bar > span:hover {
    filter: brightness(1.08);
    transform: translateY(-1px);
}

/* ===========================================================================
 * 진행 다이얼로그 (pp-progress-dialog) — 모던 컴팩트 로딩 카드
 *  showProgress(msg) 호출 시 표시. dim backdrop + frosted card.
 *  z-index: typeahead/select2/datepicker(보통 10000~) 위로 강제 — 항상 최상위.
 * =========================================================================== */
body .modal.pp-progress-dialog {
    background: rgba(15, 23, 42, 0.45) !important;
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    z-index: 99999 !important;
    display: flex !important;        /* 뷰포트 정중앙 */
    align-items: center;
    justify-content: center;
}

/* pp-progress-dialog 띄워질 때 같이 나오는 마지막 backdrop 도 위로 끌어올림.
 * (typeahead/select2 dropdown z-index 10000~ 위에 backdrop 이 있어야 가려짐) */
body.pp-progress-open .modal-backdrop {
    z-index: 99998 !important;
}

/* 로딩 중에는 페이지 컨텐츠에 새 stacking context 강제 (z-index: 0).
 * 그 안에서 어떤 z-index 가 설정되어도 modal/backdrop 위로 못 올라옴. */
body.pp-progress-open #wrapper {
    z-index: 0;
    isolation: isolate;
    position: relative;
}

/* twitter typeahead 의 wrapper (.twitter-typeahead) 도 잠재적 stacking — 강제 */
body.pp-progress-open .twitter-typeahead,
body.pp-progress-open .typeahead.dropdown-menu,
body.pp-progress-open .tt-menu,
body.pp-progress-open .ui-autocomplete,
body.pp-progress-open .select2-container--open,
body.pp-progress-open .ui-datepicker {
    z-index: 1 !important;
}

body .modal.pp-progress-dialog .modal-dialog {
    width: auto !important;
    max-width: 92%;
    margin: 0 !important;
}

body .modal.pp-progress-dialog .modal-content {
    border-radius: 12px !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12) !important;
    overflow: hidden;
    background: var(--pp-white) !important;
}

body .modal.pp-progress-dialog .modal-header,
body .modal.pp-progress-dialog .modal-footer { display: none !important; }
body .modal.pp-progress-dialog .modal-body { padding: 0 !important; background: var(--pp-white) !important; }
body .modal.pp-progress-dialog .bootstrap-dialog-message { padding: 0 !important; }

/* 카드 본체 */
.pp-progress-card {
    position: relative;
    background: var(--pp-white) !important;
}
.pp-progress-body {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 14px;
    padding: 18px 24px !important;
}

/* ─── Ring spinner (회전 호) ────────────────── */
.pp-progress-ring {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    position: relative;
}
.pp-progress-ring-svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
    overflow: visible;
}
.pp-progress-ring-track,
.pp-progress-ring-arc {
    fill: none;
    stroke-width: 3;
    stroke-linecap: round;
}
.pp-progress-ring-track {
    stroke: var(--muted, var(--pp-border));
}
.pp-progress-ring-arc {
    stroke: url(#pp-progress-ring-grad);
    stroke: var(--primary, var(--pp-primary));
    stroke-dasharray: 26 68;        /* 약 28% arc */
    stroke-dashoffset: 0;
    transform-origin: 18px 18px;
    animation: pp-progress-ring-spin 1.0s linear infinite;
}
@keyframes pp-progress-ring-spin {
    0%   { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* ─── 텍스트 영역 (스피너 우측, 한 줄) ──────── */
.pp-progress-text {
    flex: 0 1 auto;
    min-width: 0;
}
.pp-progress-title {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--foreground, #0f172a) !important;
    line-height: 1.4 !important;
    margin-bottom: 0 !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    letter-spacing: -0.01em !important;
}

/* === pp-31-mapflow-share.css === */
/* ===========================================================================
 * connect/status.jsp — 연결 상태 모니터링
 * =========================================================================== */
.cs-trend-chart {
    width: 100%;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    position: relative;
}
.cs-trend-chart-200 {
    height: 200px;
    opacity: 0.85 !important;
}
.cs-trend-chart-150 {
    height: 150px;
}

.cs-loading {
    text-align: center !important;
    color: var(--subtle-foreground, #ccc) !important;
    padding: 30px 5px !important;
    font-size: 12px !important;
}

/* NOTE: .cs-history / .cs-history-body 는 pp-09-recent-additions.css 에서 컴팩트 모드로 재정의됨.
   스크롤 박스(overflow-y:auto + 고정 height) 제거 — 테이블이 페이지네이션으로 자연스럽게 펼쳐지도록(스크롤 div 미사용). */
.cs-history {
    overflow-y: visible;
    height: auto;
}
.cs-history.cs-history-tall {
    height: auto;
}

/* 우측 에이전트 그리드 — panel-body.cs-agent-body 의 padding 강제 룰 제거 */

.cs-agent-grid {
    list-style: none;
    margin: 0 !important;
    padding: 0 !important;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
    gap: 6px;
}

.cs-agent-grid > li {
    display: block;
}

.cs-agent-cell {
    width: auto !important;
    min-height: 64px;
    padding: 4px 5px !important;
    color: var(--pp-white) !important;
    border-radius: 6px !important;
    text-align: center !important;
    cursor: pointer;
    transition: filter 0.12s, transform 0.12s;
    margin: 0 !important;
    float: none !important;
}

.cs-agent-cell:hover {
    filter: brightness(1.1);
    transform: translateY(-1px);
}

.cs-agent-cell .cs-agent-sub {
    font-size: 8px !important;
    line-height: 10px !important;
    color: rgba(255, 255, 255, 0.7) !important;
}

.cs-agent-cell .cs-agent-id {
    font-size: 10px !important;
    line-height: 14px !important;
    padding: 0 10px !important;
    white-space: nowrap !important;
    text-overflow: ellipsis;
    overflow: hidden;
    color: var(--pp-white) !important;
    font-weight: 600 !important;
}

.cs-agent-cell .cs-agent-mm {
    border-top: 1px solid rgba(255, 255, 255, 0.2) !important;
    padding-top: 4px !important;
    margin-top: 3px !important;
    font-size: 13px !important;
    color: var(--pp-white) !important;
    font-weight: 700 !important;
}

.cs-agent-empty {
    color: var(--subtle-foreground, #ccc) !important;
    text-align: center !important;
    padding: 20px !important;
    font-size: 12px !important;
}

/* --simple: gauge / alarm 모두 없음. 라벨 + 서브 한 줄만 */
.kpi-stat-card.kpi-stat-card--simple .kpi-stat-card-body {
    /* 기본 레이아웃 그대로 — 다만 우측 게이지 자리가 비므로 라벨 영역만 차지 */
}

/* ===========================================================================
 * map/index 전용 패널 패딩 정규화 (인라인 style 제거)
 * =========================================================================== */

.row.map-kpi-row {
    margin-bottom: 12px !important;
}

body #page-wrapper .card.card.map-kpi-panel {
    margin-bottom: 12px !important;
}

body #page-wrapper .card.card.map-kpi-panel > .card-header.map-kpi-heading {
    padding: 10px 16px !important;
}

body #page-wrapper .card.card.map-kpi-panel > .card-body.map-kpi-body {
    padding: 14px 14px 12px 14px !important;
}

body #page-wrapper .card.card.map-board-panel > #map-wrapper.map-board-wrapper {
    position: relative;
    height: 530px;
    border-bottom-left-radius: 12px !important;
    border-bottom-right-radius: 12px !important;
    overflow: hidden;
}

body #page-wrapper .card.card.map-board-panel > #map-wrapper.map-board-wrapper > #mapid {
    width: 100%;
    height: 100%;
}











/* ============================================================
 * map/include/map-overlays — 지도 위 오버레이 박스 시맨틱 정렬
 * 인라인 style 제거 후 사용
 * ============================================================ */
.map-ov-bar {
    width: calc(100% + 2px);
    height: 22px;
    margin: 1px -1px 0 !important;
}

.map-ov-pad     { padding: 4px 2px 0 !important; }
.map-ov-row-spc { margin-top: 1px !important; margin-bottom: 2px !important; }
.map-ov-text-md { line-height: 20px !important; font-size: 13px !important; }
.map-ov-chip-xs {
    font-size: 9px !important;
    padding: 2px 10px !important;
    border-radius: 12px !important;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    line-height: 1.2 !important;
}

.map-ov-heading {
    font-size: 15px !important;
    font-weight: 700 !important;
    color: #222 !important;
    line-height: 1.4 !important;
}

.map-ov-section-divider {
    font-size: 11px !important;
    color: #666 !important;
    font-weight: 600 !important;
    border-bottom: 1px solid #ddd !important;
    padding-bottom: 2px !important;
    margin: 0 -2px !important;
}

.map-ov-text-sm-dark { font-size: 12px !important; color: #333 !important; }

/* 위도/경도 오버레이(우하단 어두운 칩) — 인라인 style 제거 + 시맨틱 클래스
   #8: <div class="map-overlay map-ov-latlng-bar"> + B.map-ov-latlng-label + span.map-ov-latlng-value */
body .map-ov-latlng-bar {
    position: absolute !important;
    z-index: 450 !important;
    right: 10px !important;
    bottom: 10px !important;
    width: 360px !important;
    height: 20px !important;
    line-height: 20px !important;
    text-align: center !important;
    background: #3d3d3d !important;
    color: var(--pp-white) !important;
    border-radius: 20px !important;
    font-size: 12px !important;
    opacity: 0.9 !important;
    margin-right: 15px !important;
    pointer-events: auto !important;
}
body .map-ov-latlng-bar,
body .map-ov-latlng-bar *,
body .map-ov-latlng-bar B,
body .map-ov-latlng-bar .map-ov-latlng-label,
body .map-ov-latlng-bar .map-ov-latlng-value,
body .map-ov-latlng-bar #current-lat-lng,
.map-ov-latlng-label,
.map-ov-latlng-value { color: var(--pp-white) !important; }
/* kpi-stat-card-alarms-bar — 알람바 안 모든 텍스트 흰색 */
body .kpi-stat-card-alarms-bar,
body .kpi-stat-card-alarms-bar * { color: var(--pp-white) !important; }

.map-ov-tile {
    flex: 1;
    background: #f8f9fa !important;
    border: 1px solid #ddd !important;
    border-radius: 4px !important;
    text-align: center !important;
    overflow: hidden;
}

.map-ov-hint-xs { font-size: 9px !important; color: #bbb !important; }


/* 12px 작은 메타 + 회색 + 두꺼운 + 밑여백 */
.text-meta-sm-bold {
    font-size: 12px !important;
    color: #888 !important;
    font-weight: 600 !important;
    margin-bottom: 4px !important;
}


/* ============================================================
 * map/include/bottom-content — 차트 빈 상태 + 범례 칩
 * ============================================================ */
.map-bc-empty {
    text-align: center !important;
    color: #ddd !important;
    padding: 20px !important;
}

.map-bc-chart  { height: 180px; }
.map-bc-h-min  { min-height: 120px; }

.map-bc-legend-dot {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 2px !important;
    vertical-align: middle;
    margin-right: 3px !important;
}

.map-bc-legend-dot.legend-extra { margin-left: 10px !important; }

.map-bc-legend-dot.legend-ok    { background: #2e7d32 !important; }
.map-bc-legend-dot.legend-warn  { background: #e65100 !important; }
.map-bc-legend-dot.legend-err   { background: #b71c1c !important; }
.map-bc-legend-dot.legend-mute  { background: #ccc !important; }

.map-bc-footer {
    border-top: 1px solid #eee !important;
    margin-top: 10px !important;
    padding-top: 8px !important;
    font-size: 11px !important;
    color: #888 !important;
}


/* ============================================================
 * map/include/bottom-content — 설비 연결/건강 상태 히트맵 (eq-block)
 * 각 설비 1개당 작은 색상 셀 + 설비명 prefix
 * ============================================================ */
#equipment_heatmap_container,
#equipment_health_container,
#opc_connection_heatmap_container,
#opc_latency_heatmap_container {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 4px 0 !important;
    align-content: flex-start;
}

.eq-block {
    flex: 0 0 auto;
    width: 36px;
    height: 26px;
    border-radius: 4px !important;
    color: var(--pp-white) !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    line-height: 26px !important;
    text-align: center !important;
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18) !important;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.eq-block:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.18), inset 0 0 0 1px rgba(255, 255, 255, 0.32) !important;
}
/* ============================================================================
 * 페이지 전용 CSS — 모듈 CSS 폐지 후 디자인 시스템 part 로 통합
 * 각 페이지는 body 클래스 또는 컨테이너 클래스로 스코프 부여.
 * ============================================================================ */

/* ━━━ share/index — 공유 캔버스 목록 페이지 ━━━ */
/* =============================================
 * 공유 캔버스 목록 페이지
 * ============================================= */

.share-page {
    margin: 0 !important;
    padding: 0 !important;
    background: #f5f6fa !important;
    /* PPZoom 역보정 — body 에 zoom < 1 일 때 100vh 가 시각적으로 줄어 하단 잘림 방지 */
    min-height: calc(100vh / var(--pp-zoom, 1));
}

/* ─── 상단 네비게이션 ─── */
.share-nav {
    margin-bottom: 0 !important;
}

.share-nav .navbar-brand {
    float: left;
    padding: 6.5px 15px !important;
    font-size: 15px !important;
    line-height: 17px !important;
    height: 52px;
    min-width: 200px;
}

.share-nav-title-text {
    font-size: 18px !important;
    font-weight: bold !important;
    color: #777 !important;
    margin-left: 8px !important;
    vertical-align: middle;
}

.share-nav-toolbar {
    margin-top: 0 !important;
}

.share-nav-toolbar > li > a {
    display: flex;
    align-items: center;
    height: 52px;
    padding: 0 12px !important;
}

.share-nav-toolbar > li > a:hover,
.share-nav-toolbar > li > a:focus {
    background-color: transparent !important;
}

.share-nav-icon {
    font-size: 16px !important;
}

/* ─── 본문 ─── */
.share-body {
    max-width: 1400px;
    margin: 0 auto !important;
    padding: 30px !important;
    padding-top: 80px !important;
}

.share-count {
    font-size: 13px !important;
    color: #888 !important;
    margin-bottom: 15px !important;
    font-weight: 600 !important;
}

/* ─── 빈 상태 ─── */
.share-empty {
    text-align: center !important;
    padding: 80px !important;
    color: #ccc !important;
    font-size: 15px !important;
}

/* ─── 카드 크기 조정 (share 페이지용) ─── */
.share-page .canvas-card-box {
    width: 23%;
    margin: 8px !important;
}

@media (max-width: 1200px) {
    .share-page .canvas-card-box {
        width: 31%;
    }
}

@media (max-width: 768px) {
    .share-page .canvas-card-box {
        width: 47%;
    }
}

/* ━━━ canvas/canvas-widgets — 캔버스 위젯 (canvas/edit + screen + dashboard/screen 공용) ━━━ */
/* ═══════════════════════════════════════════════
 * Canvas 위젯 공통 스타일 (뷰 페이지)
 * ═══════════════════════════════════════════════ */

/* ─── 위젯 헤더 드래그 커서 ─── */
.canvas-tag-label .sw-title-bar { cursor: move; }

/* ─── 위젯 헤더 설명 텍스트 ─── */
.sw-tag-desc {
    font-size: 9px !important;
    color: #aaa !important;
    margin-left: 4px !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 80px;
    display: inline-block;
    vertical-align: middle;
}

/* ─── 위젯 선택 하이라이트 ─── */
.canvas-tag-label.cw-selected {
    outline: 2px solid #337ab7 !important;
    outline-offset: 1px !important;
    z-index: 10;
}
.canvas-anchor-dot.cw-anchor-selected {
    box-shadow: 0 0 0 4px rgba(51,122,183,0.4) !important;
    z-index: 10;
}

/* ─── 리사이즈 핸들 ─── */
.canvas-tag-label .ui-resizable-handle {
    background: rgba(51,122,183,0.3) !important;
    border-radius: 2px !important;
}
.canvas-tag-label .ui-resizable-se {
    width: 10px;
    height: 10px;
    right: 1px;
    bottom: 1px;
    cursor: se-resize;
}

/* ─── 앵커 dot 타입별 색상 ─── */
.anchor-type-tag_value    { background: #337ab7 !important; }
.anchor-type-timeseries   { background: #5b9bd5 !important; }
.anchor-type-asset_health { background: #e74c3c !important; }
.anchor-type-document     { background: #8e44ad !important; }
.anchor-type-gauge        { background: #e67e22 !important; }
.anchor-type-kpi          { background: #27ae60 !important; }
.anchor-type-memo         { background: #95a5a6 !important; }
.anchor-type-oee          { background: #2c3e50 !important; }
.anchor-type-ram          { background: #16a085 !important; }
.anchor-type-ems          { background: #f39c12 !important; }
.anchor-type-data_table   { background: #34495e !important; }
.anchor-type-image        { background: #9b59b6 !important; }

/* ─── 위젯 라벨 컨테이너 사이즈 (타입별) ─── */
.cw-label-tag_value    { min-width: 140px; }
.cw-label-timeseries   { width: 260px; height: 190px; }
.cw-label-asset_health { width: 260px; min-height: 80px; }
.cw-label-document     { width: 220px; min-height: 60px; }
.cw-label-asset_timeline { width: 400px; height: 200px; }
.cw-label-gauge        { width: 160px; height: 170px; }
.cw-label-kpi          { width: 130px; height: 140px; }
.cw-label-memo         { min-width: 60px; }
.cw-label-oee,
.cw-label-oee_chart    { width: 280px; height: 200px; }
.cw-label-ram,
.cw-label-ram_chart    { width: 280px; height: 200px; }
.cw-label-ems,
.cw-label-ems_chart    { width: 280px; height: 200px; }
.cw-label-data_table   { width: 260px; height: 200px; }
.cw-label-image        { width: 300px; height: 220px; }

/* ─── 타임시리즈 위젯 ─── */
.cw-timeseries {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    overflow: hidden;
    width: 100%;
    height: 100%;
}
.cw-ts-chart-area {
    width: 100%;
    height: calc(100% - 28px);
    padding: 5px 0 !important;
}

/* ─── 에셋 건강 위젯 ─── */
.cw-asset-health {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    overflow: hidden;
    width: 100%;
    height: 100%;
}
.cw-ah-body {
    padding: 4px 6px !important;
}
.cw-ah-row {
    display: flex;
    align-items: center;
    margin-bottom: 4px !important;
}
.cw-ah-row:first-child {
    margin-top: 5px !important;
}
.cw-ah-row-label {
    font-size: 9px !important;
    color: #888 !important;
    width: 28px;
    flex-shrink: 0;
    font-weight: 600 !important;
}
.cw-ah-row-bar {
    flex: 1;
    height: 18px;
    background: #f5f5f5 !important;
    border-radius: 2px !important;
    position: relative;
    overflow: hidden;
}
.cw-ah-seg {
    position: absolute;
    top: 0;
    height: 100%;
    min-width: 1px;
}
.cw-ah-empty {
    text-align: center !important;
    color: #ccc !important;
    font-size: 9px !important;
    line-height: 18px !important;
}
.cw-ah-time-axis {
    display: flex;
    justify-content: space-between;
    font-size: 8px !important;
    color: #bbb !important;
    padding-left: 28px !important;
    margin-top: 2px !important;
}

/* ─── 문서 위젯 ─── */
.cw-document {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    overflow: hidden;
}
.cw-doc-item {
    display: flex;
    align-items: center;
    font-size: 10px !important;
    padding: 3px 6px !important;
    border-bottom: 1px solid #f0f0f0 !important;
    overflow: hidden;
    cursor: pointer;
    color: #333 !important;
    text-decoration: none !important;
}
.cw-doc-item:hover { background: #f5f5f5 !important; color: #337ab7 !important; text-decoration: none !important; }
.cw-doc-item i { color: #888 !important; margin-right: 5px !important; font-size: 10px !important; flex-shrink: 0; }
.cw-doc-name { white-space: nowrap !important; flex-shrink: 0; }
.cw-doc-desc { margin-left: auto !important; color: #aaa !important; font-size: 9px !important; overflow: hidden; text-overflow: ellipsis; white-space: nowrap !important; padding-left: 6px !important; }
.cw-doc-more {
    font-size: 9px !important;
    color: #999 !important;
    text-align: center !important;
    padding-top: 3px !important;
}

/* ─── 게이지 위젯 ─── */
.cw-gauge {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    width: 100%;
    height: 100%;
    overflow: hidden;
}
.cw-gauge-area {
    width: 100%;
    height: calc(100% - 28px);
    min-height: 120px;
}

/* ─── KPI 카드 위젯 ─── */
.cw-kpi {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 6px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    overflow: hidden;
    width: 100%;
    height: 100%;
}
.cw-kpi-card {
    width: 100%;
    height: calc(100% - 28px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #f5f5f5 !important;
    color: #999 !important;
    transition: background 0.3s, color 0.3s;
    border-radius: 0 0 5px 5px !important;
}
.cw-kpi-value {
    font-size: 28px !important;
    font-weight: 700 !important;
    line-height: 1.1 !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
}
.cw-kpi-unit {
    font-size: 10px !important;
    opacity: 0.8 !important;
    margin-top: 2px !important;
}
.cw-kpi-trend {
    font-size: 12px !important;
    opacity: 0.7 !important;
    margin-top: 2px !important;
}

/* ─── 메모 위젯 ─── */
.cw-memo {
    line-height: 1.4 !important;
    word-break: break-word;
}

/* ─── ISO 차트 위젯 (OEE, RAM, EMS 공통) ─── */
.cw-iso-chart {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    width: 100%;
    height: 100%;
    overflow: hidden;
}
/* ─── 에셋 타임라인 위젯 ─── */
.cw-timeline {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    overflow: hidden;
    width: 100%;
    height: 100%;
    position: relative;
}

/* === pp-32-toolbar.css === */
.cw-tl-body {
    width: 100%;
    height: calc(100% - 28px);
    overflow: hidden;
}
.cw-tl-nav {
    position: absolute;
    right: 4px;
    bottom: 4px;
    display: flex;
    gap: 2px;
    z-index: 5;
}
.cw-tl-btn {
    width: 22px;
    height: 22px;
    border: 1px solid #bbb !important;
    border-radius: 3px !important;
    background: rgba(255,255,255,0.9) !important;
    color: #666 !important;
    font-size: 10px !important;
    cursor: pointer;
    padding: 0 !important;
    line-height: 20px !important;
    text-align: center !important;
}
.cw-tl-btn:hover {
    background: #337ab7 !important;
    color: var(--pp-white) !important;
    border-color: #337ab7 !important;
}
/* ─── 데이터 테이블 위젯 ─── */
.cw-data-table {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    overflow: hidden;
    width: 100%;
    height: 100%;
}
.cw-tbl-body {
    width: 100%;
    height: calc(100% - 28px);
    overflow-y: auto;
    overflow-x: hidden;
}
.cw-tbl-loading {
    text-align: center !important;
    color: #ccc !important;
    font-size: 10px !important;
    padding: 20px !important;
}
.cw-tbl {
    width: 100%;
    border-collapse: collapse;
    font-size: 10px !important;
}
.cw-tbl thead th {
    background: #f8f8f8 !important;
    padding: 3px 5px !important;
    font-weight: 600 !important;
    color: #888 !important;
    border-bottom: 1px solid #eee !important;
    position: sticky;
    top: 0;
    font-size: 9px !important;
}
.cw-tbl tbody tr:hover { background: #f9f9f9 !important; }
.cw-tbl-name {
    padding: 2px 5px !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 120px;
    color: #555 !important;
}
.cw-tbl-val {
    padding: 2px 5px !important;
    font-weight: bold !important;
    text-align: right !important;
    color: #333 !important;
    font-family: 'Consolas', monospace !important;
}
.cw-tbl-unit {
    padding: 2px 5px !important;
    color: #999 !important;
    font-size: 9px !important;
}

/* ─── 이미지 위젯 ─── */
.cw-image {
    background: var(--pp-white) !important;
    border: 1px solid #bbb !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08) !important;
    overflow: hidden;
    width: 100%;
    height: 100%;
}
.cw-img-body {
    width: 100%;
    height: calc(100% - 28px);
    overflow: hidden;
    background: #111 !important;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ─── ISO 차트 공통 ─── */
.cw-iso-chart-area {
    width: 100%;
    height: calc(100% - 28px);
    padding: 5px !important;
}

/* ─── 미니맵 ─── */
.canvas-minimap {
    position: fixed;
    left: 15px;
    top: 110px;
    z-index: 900;
    width: 200px;
    background: rgba(30,30,30,0.92) !important;
    border-radius: 6px !important;
    box-shadow: 0 2px 12px rgba(0,0,0,0.3) !important;
    overflow: hidden;
    user-select: none;
}
.canvas-minimap .cmm-header {
    font-size: 10px !important;
    color: #ccc !important;
    padding: 4px 8px !important;
    border-bottom: 1px solid rgba(255,255,255,0.1) !important;
    cursor: pointer;
}
.canvas-minimap .cmm-body {
    position: relative;
    width: 100%;
    height: 140px;
    background: #222 !important;
    overflow: hidden;
}
.canvas-minimap #minimap_canvas {
    width: 100%;
    height: 100%;
    display: block;
}
.canvas-minimap .cmm-viewport {
    position: absolute;
    border: 2px solid rgba(51,122,183,0.8) !important;
    background: rgba(51,122,183,0.12) !important;
    pointer-events: none;
    transition: none;
}

/* ━━━ canvas/edit ━━━ */
/* ─── 상위 탭 (기본 정보 / 편집) ─── */
.edit-top-tabs {
    margin-bottom: 0 !important;
    border-bottom: 1px solid #ccc !important;
}
.edit-top-tabs > li > a {
    font-size: 13px !important;
    font-weight: 600 !important;
    color: #666 !important;
    padding: 8px 16px !important;
    border-radius: 4px 4px 0 0 !important;
}
.edit-top-tabs > li.active > a,
.edit-top-tabs > li.active > a:focus,
.edit-top-tabs > li.active > a:hover {
    color: #337ab7 !important;
    border: 1px solid #ccc !important;
    border-bottom: 1px solid var(--pp-white) !important;
    border-radius: 4px 4px 0 0 !important;
    margin-bottom: -1px !important;
}
.edit-top-tabs > li > a:hover {
    border: none !important;
}
.edit-top-content {
    border: none !important;
    padding: 10px 0 !important;
    background: var(--pp-white) !important;
    margin-bottom: 10px !important;
}
.edit-top-content .card {
    box-shadow: none !important;
}

/* ─── 캔버스 편집 페이지: 위젯 팔레트 탭 ─── */

.widget-palette-tabs {
    display: flex;
    flex-wrap: wrap;
    border-bottom: 2px solid #337ab7 !important;
    margin: 0 !important;
    padding: 0 !important;
    background: #f8f8f8 !important;
    overflow: hidden;
}
.widget-palette-tabs .wpt-tab {
    padding: 5px 0 !important;
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: 10px !important;
    color: #666 !important;
    cursor: pointer;
    border: 1px solid transparent !important;
    border-bottom: none !important;
    margin-bottom: -2px !important;
    white-space: nowrap !important;
    text-align: center !important;
}
.widget-palette-tabs .wpt-tab:hover {
    color: #337ab7 !important;
    background: #eef5fb !important;
}
.widget-palette-tabs .wpt-tab.active {
    color: #337ab7 !important;
    background: var(--pp-white) !important;
    border-color: #337ab7 #337ab7 var(--pp-white) !important;
    font-weight: bold !important;
}
.widget-palette-tabs .wpt-tab i {
    display: block;
    font-size: 14px !important;
    margin-bottom: 2px !important;
}

/* ─── 탭 컨텐츠 ─── */
.wpt-content {
    display: none;
    padding: 10px 0 !important;
}
.wpt-content.active {
    display: block;
}

/* ─── 위젯 입력 폼 공통 ─── */
.wpt-form-group {
    margin-bottom: 8px !important;
}
.wpt-form-group label {
    font-size: 11px !important;
    color: #888 !important;
    margin-bottom: 2px !important;
    display: block;
}
.wpt-form-group .form-control {
    font-size: 12px !important;
    height: 30px;
    padding: 4px 8px !important;
}
.wpt-form-group textarea.form-control {
    height: auto;
}

/* ─── 배치된 위젯 목록 ─── */
.widget-list-item {
    padding: 6px 8px !important;
    border-bottom: 1px solid #eee !important;
    font-size: 11px !important;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
}
.widget-list-item:hover {
    background: #f5f5f5 !important;
}
.widget-list-item.selected {
    background: #eef5fb !important;
    border-left: 3px solid #337ab7 !important;
}
.widget-list-item .wli-icon {
    color: #337ab7 !important;
    width: 16px;
    text-align: center !important;
}
.widget-list-item .wli-label {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}
.widget-list-item .wli-type {
    font-size: 9px !important;
    color: #999 !important;
    background: #f0f0f0 !important;
    padding: 1px 4px !important;
    border-radius: 3px !important;
}
.widget-list-item .wli-remove {
    color: #d9534f !important;
    cursor: pointer;
    padding: 0 2px !important;
}

/* ─── 편집 모드 마커 (위젯 유형별 아이콘) ─── */
.canvas-tag-label.editable .widget-type-badge {
    position: absolute;
    top: -8px;
    right: -8px;
    width: 16px;
    height: 16px;
    border-radius: 50% !important;
    background: #337ab7 !important;
    color: var(--pp-white) !important;
    font-size: 8px !important;
    line-height: 16px !important;
    text-align: center !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* ─── 위젯 유형별 앵커 색상 ─── */
.canvas-anchor-dot.type-tag_value { background: #337ab7 !important; }
.canvas-anchor-dot.type-timeseries { background: #5cb85c !important; }
.canvas-anchor-dot.type-asset_health { background: #f0ad4e !important; }
.canvas-anchor-dot.type-document { background: #5bc0de !important; }
.canvas-anchor-dot.type-gauge { background: #d9534f !important; }
.canvas-anchor-dot.type-kpi { background: #8e44ad !important; }
.canvas-anchor-dot.type-memo { background: #95a5a6 !important; }
.canvas-anchor-dot.type-oee_chart { background: #e67e22 !important; }
.canvas-anchor-dot.type-ram_chart { background: #2ecc71 !important; }
.canvas-anchor-dot.type-ems_chart { background: #3498db !important; }

/* ─── ISO 서브탭 ─── */
.iso-sub-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 8px !important;
}
.iso-sub-tabs .iso-sub-tab {
    flex: 1;
    padding: 4px !important;
    text-align: center !important;
    font-size: 10px !important;
    font-weight: bold !important;
    border: 1px solid #ddd !important;
    border-radius: 3px !important;
    cursor: pointer;
    color: #666 !important;
}
.iso-sub-tabs .iso-sub-tab:hover {
    background: #f5f5f5 !important;
}
.iso-sub-tabs .iso-sub-tab.active {
    background: #337ab7 !important;
    color: var(--pp-white) !important;
    border-color: #337ab7 !important;
}


/* === pp-33-dashboards.css === */
/* ━━━ asset/dashboard-equipment — flex 기반 깔끔한 헤더 ━━━ */
.dashboard-title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
    padding: 10px 20px !important;
    background: oklch(14% 0.012 265) !important;              /* 사이드바와 동일 다크 톤 */
    color: oklch(92% 0.005 260) !important;
    border-bottom: 1px solid oklch(22% 0.012 265) !important;
    font-size: 14px !important;
}


.dashboard-title .dashboard-name-block {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 1 1 auto;
    min-width: 0;
    padding-left: 14px !important;
    border-left: 1px solid oklch(0.52 0 0) !important;
    height: 32px;
}
.dashboard-title .dashboard-name {
    font-size: 15px !important;
    font-weight: 600 !important;
    color: var(--pp-white) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}
.dashboard-title .dashboard-name-switcher {
    position: relative;
}
.dashboard-title .dashboard-name-switcher .btn-ghost {
    color: rgba(255, 255, 255, 0.65) !important;
    border-color: transparent !important;
}
.dashboard-title .dashboard-name-switcher .btn-ghost:hover {
    color: var(--pp-white) !important;
    background: rgba(255, 255, 255, 0.08) !important;
}
/* 명시적 <i fa-chevron-down> 아이콘을 쓰므로 BS5 dropdown-toggle 의 ::after 캐럿 제거(화살표 2개 방지). */
.dashboard-title .dashboard-name-switcher .dropdown-toggle::after {
    display: none;
}
.dashboard-title .dashboard-name-switcher .dropdown-menu {
    z-index: 1100 !important;
    max-height: 60vh;
    overflow-y: auto !important;
    overflow-x: hidden;
    min-width: 260px;
}

.dashboard-title .dashboard-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    flex: 0 0 auto;
    justify-content: flex-end;
}
.dashboard-title .dashboard-realtime {
    display: inline-flex;
    align-items: center;
    color: #4ade80 !important;
    margin-right: 4px !important;
}
.dashboard-title .dashboard-realtime-icon {
    color: #4ade80 !important;
}
.dashboard-title .dashboard-toolbar-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 6px !important;
    color: rgba(255, 255, 255, 0.78) !important;
    text-decoration: none !important;
    transition: background 0.15s, color 0.15s;
}
.dashboard-title .dashboard-toolbar-btn:hover {
    background: rgba(255, 255, 255, 0.10) !important;
    color: var(--pp-white) !important;
}
.dashboard-title .dashboard-toolbar-divider {
    width: 1px;
    height: 18px;
    background: oklch(28% 0.012 265) !important;
    display: inline-block;
    margin: 0 4px !important;
}
/* 헤더 우측 끝 로고 — 타이틀/툴바 다음에 배치, 높이만 제한 */
.dashboard-title .dashboard-title-logo {
    height: 28px;
    width: auto;
    flex: 0 0 auto;
    margin-right: 4px;
}
.dashboard-title .dashboard-datepicker {
    width: 150px;
    height: 30px;
    border-radius: 6px !important;
    text-align: center !important;
    color: var(--pp-white) !important;
    background: rgba(255, 255, 255, 0.08) !important;
    border: 1px solid oklch(28% 0.012 265) !important;
    font-size: 13px !important;
    font-weight: 500 !important;
    padding: 0 8px !important;
}
.dashboard-title .dashboard-datepicker:focus {
    outline: 0 !important;
    border-color: #60a5fa !important;
    background: rgba(255, 255, 255, 0.12) !important;
}
/* native date 입력의 달력 아이콘(picker indicator)은 기본 검정이라 다크 툴바에서 안 보임 → invert 로 흰색화. */
.dashboard-title .dashboard-datepicker::-webkit-calendar-picker-indicator {
    filter: invert(1) brightness(1.7);
    opacity: 0.8;
    cursor: pointer;
    margin-left: 4px;
}
.dashboard-title .dashboard-datepicker::-webkit-calendar-picker-indicator:hover {
    opacity: 1;
}

@media (max-width: 767px) {
    .dashboard-title {
        align-items: flex-start;
        gap: 8px;
        padding: 10px 12px !important;
    }
    .dashboard-title .dashboard-name-block {
        flex-basis: 100%;
        height: auto;
        padding-left: 0 !important;
        border-left: 0 !important;
    }
    .dashboard-title .dashboard-toolbar {
        width: 100%;
        justify-content: flex-end;
    }
    .dashboard-title .dashboard-datepicker {
        flex: 1 1 128px;
        max-width: 150px;
    }
}

.dashboard-breadcrumb {
    background: oklch(96% 0.005 260) !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 11px !important;
    line-height: 18px !important;
    padding: 6px 20px !important;
    margin-bottom: 14px !important;
    border-bottom: 1px solid var(--border, var(--pp-border)) !important;
}

div.timeline-event-content {
            margin: 2px !important;
            overflow: hidden;
            white-space: nowrap !important;
            font-weight: normal !important;
            color: #666 !important;
            max-width: none;
        }

        /* jQuery UI .ui-state-default 오버라이드 — 기본/hover/focus/active 모두 투명 배경 */
        .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
            background: transparent !important;
            border: 1px solid transparent !important;
            color: #333 !important;
            font-weight: normal !important;
        }
        .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover,
        .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus,
        .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
            background: transparent !important;
            border: 1px solid transparent !important;
        }
        .timeline-event .timeline-event-range .ui-widget .ui-state-default .timeline-event-selected .ui-state-active {
            border: 0px !important;
        }

        div.no-box {
            border: 0px !important;
            padding: 0px !important;
        }

        /* 타임라인 아이템 노드(.t-box) 는 pp-57-timeline-node.css 의 .pp-tl-node 로 이관 */


        .asset_box {
            width: 120px;
            min-height: 60px;
            min-width: 120px;
            max-width: 120px;
            text-align: center !important;
        }

        .asset_box_text {
            width: 120px;
            min-height: 20px;
            min-width: 120px;
            max-width: 120px;
            text-align: center !important;
            border-top: 1px dotted #eee !important;
            font-size: 11px !important;
            padding-top: 5px !important;
        }

.ui-datepicker {
            margin-left: -158px !important;
            margin-top: 2px !important;
            z-index: 9999;
        }
        .ui-datepicker-div {
            border: 2px solid #ccc !important;
        }

        .ui-datepicker-month {
            color: var(--pp-white) !important;
        }

        .ui-datepicker-month option {
            color: #1c94c4 !important;
        }

        select.ui-datepicker-month {
            background: #1c94c4 !important;
            border-raidus: 2px !important;
            border: 0px !important;
        }

        select.ui-datepicker-month option {
            background: var(--pp-white) !important;
        }

        .ui-widget-header {
            background: #1c94c4 !important;
            border: 1px solid var(--pp-white) !important;
        }
        .ui-widget-header .ui-state-default {
            border: 1px solid #ccc !important;
            background: #f6f6f6 !important;
            font-weight: bold !important;
            color: #888 !important;
        }

.axis path, .axis line {
            fill: none;
            stroke: black;
            shape-rendering: crispEdges;
        }

        .axis text {
            font-family: sans-serif !important;
            font-size: 10px !important;
        }

        .timeline-label {
            font-family: sans-serif !important;
            font-size: 12px !important;
        }

        
        .coloredDiv {
            height: 20px;
            width: 20px;
            float: left;
        }

.asset_status {
            position: absolute;
            z-index: 9;
            left: 20px;
            top: auto;
            bottom: 58px;            /* 이미지 좌하단으로 이동 (건강 뱃지 — 연결상태 위) */
            width: 100px;
            height: 40px;
            border-radius: 100px !important;
            background: var(--pp-white) !important;
            border: 2px solid #ccc;
            color: #ccc;
            text-align: center !important;
            font-size: 24px !important;
            font-weight: bold !important;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 4px;
        }

        .connection_status {
            position: absolute;
            z-index: 2;
            left: 20px;
            top: auto;
            bottom: 12px;            /* 이미지 좌하단 (건강 뱃지 아래) */
            width: 100px;
            height: 40px;
            border-radius: 100px !important;
            background: var(--pp-white) !important;
            border: 2px solid #ccc;        /* 건강 뱃지(asset_status) 와 동일 보더 */
            color: #ccc;
            text-align: center !important;
            font-size: 24px !important;
            font-weight: bold !important;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 4px;
        }

.oee_header {
                                        padding: 3px !important;
                                        margin-right: 1px !important;
                                        border-bottom: 1px solid #ddd !important;
                                        border-rigiht: 1px solid var(--pp-white) !important;
                                        color: #555 !important;
                                        text-align: center !important;
                                        background: #eee !important;
                                    }

                                    .oee_value {
                                        padding: 3px !important;
                                        margin-right: 1px !important;
                                        border-bottom: 0px solid #ddd !important;
                                        border-right: 1px solid var(--pp-white) !important;
                                        color: #333 !important;
                                        font-size: 12px !important;
                                        font-weight: bold !important;
                                        text-align: center !important;
                                    }

/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 * asset/dashboard-equipment — 본문 재디자인 (equipment 전용 클래스)
 * 이전엔 view-sub-title/eq-tag-*/equipment-kpi-tabs/ds-tab-meta 가
 * CSS 없이 브라우저 기본으로 떠 어수선했다. 인라인 style 도 제거(이유:
 * 디자인시스템 위생 + check-frontend inline-style ratchet 하향).
 * 모두 equipment 전용 셀렉터라 line/area/site 대시보드에 영향 없음.
 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */

/* 카드 안 섹션 소제목(연결상태/기본정보 등). 이전 .view-sub-title 무 CSS 보정.
 * 신규 equipment 전용 셀렉터라 경합 규칙이 없어 important 우선순위 불필요(ratchet 유지). */
.eq-card-legend {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 0 0 8px 0;
    margin-bottom: 10px;
    border-bottom: 1px solid var(--border, var(--pp-border));
    line-height: 22px;
}
.eq-card-legend .eq-card-legend-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--foreground, var(--pp-text));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.eq-card-legend .eq-card-legend-meta {
    font-size: 11px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    white-space: nowrap;
}

/* 데이터 표시 섹션 제목 표준과 통일 (.pp-data-title 와 동일 룩). */
.view-sub-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    font-size: 12px;
    font-weight: 700;
    color: var(--foreground);
    padding: 8px 0 6px 0;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--pp-border);
}
.view-sub-title > .float-end { font-weight: 400; }

/* 좌/우 컬럼 사이 여백(이전 인라인 .pl-4 대용 — 그리드 gutter 보강) */
.equipment-info-grid { row-gap: 16px; }

/* 태그 선택 리스트(트렌드 차트 좌측) — 이전 .eq-tag-* 무 CSS */
.eq-tag-scroll {
    min-height: 320px;
    max-height: 320px;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 0px;
    border: 2px solid var(--border, var(--pp-border));
    border-radius: 8px;
}
.eq-tag-item {
    padding: 6px 8px;
    /* border-bottom 제거 (사용자 요청) */
}
.eq-tag-item:last-child { border-bottom: 0; }
.eq-tag-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 2px;
}
.eq-tag-label {
    font-size: 12px;
    color: var(--foreground, var(--pp-text));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding-left: 2px;
}
.eq-tag-label .eq-tag-icon { color: var(--pp-muted-fg); }
.eq-tag-label .eq-tag-desc { color: var(--pp-muted-fg); }

/* 트렌드 차트 캔버스/빈상태/실행바 (이전 인라인 style 제거) */
.eq-trend-col { position: relative; }
.eq-trend-chart { height: 320px; min-width: 600px; }
/* 트렌드 차트 빈상태 — 차트 영역(높이 320px) 전체에 오버레이, 가로/세로 중앙정렬 */
.eq-trend-col > .eq-chart-no-data {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 320px;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    line-height: 16px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    pointer-events: none;
}
.eq-chart-no-data-pill {
    padding: 5px 15px;
    border: 1px solid var(--border, var(--pp-border));
    background: var(--pp-white);
    border-radius: 64px;
}
.eq-exec-bar {
    padding: 3px;
    line-height: 24px;
    font-size: 11px;
    text-align: right;
    border-top: 1px solid var(--border, var(--pp-border));
    color: var(--muted-foreground, var(--pp-muted-fg));
}

/* KPI 탭(OEE/RAM/EMS) 헤더 — 이전 .equipment-kpi-tabs/.ds-tab-meta 무 CSS */
.equipment-kpi-tabs { margin-bottom: -1px; }
.equipment-kpi-tabs .nav-tabs { border-bottom: 0; }
.equipment-kpi-tabs .ds-tab-meta {
    font-size: 11px;
    font-weight: 400;
    color: var(--muted-foreground, var(--pp-muted-fg));
    margin-left: 2px;
}

/* 타임라인 상세 팝업 — 이전 인라인 style 제거 */
.eq-popup-loc {
    padding: 5px;
    line-height: 30px;
    color: var(--pp-white);
    text-align: center;
    font-weight: bold;
    background: var(--pp-muted-fg);
    border-radius: 12px;
}
.eq-popup-json-scroll {
    max-height: 260px;
    min-width: 400px;
    overflow-y: auto;
    overflow-x: hidden;
}

/* ━━━ asset/dashboard-overview ━━━ */
/* ───────────────────────────────────────────────
 * SITE / AREA / LINE 대시보드 공통 스타일
 * ─────────────────────────────────────────────── */

/* 상단 타이틀 바 */
.ov-screen-title {
    padding: 8px 20px !important;
    background: #222 !important;
    color: #ddd !important;
    font-size: 14px !important;
}
.ov-screen-title a { color: var(--pp-white) !important; }
.ov-screen-title a:hover { color: #ccc !important; text-decoration: none !important; }

/* 형제 에셋 드롭다운 */
.ov-screen-title select {
    background: #444 !important;
    color: var(--pp-white) !important;
    border: 1px solid #666 !important;
    border-radius: 3px !important;
    font-size: 12px !important;
    padding: 2px 5px !important;
    max-width: 200px;
}

/* 실시간 갱신 아이콘 */
@keyframes ov-blink {
    0%   { opacity: 1; }
    50%  { opacity: 0.3; }
    100% { opacity: 1; }
}

/* 브레드크럼 */
.ov-breadcrumb {
    background: #ddd !important;
    font-size: 10px !important;
    line-height: 16px !important;
    padding-left: 20px !important;
    margin-bottom: 10px !important;
    box-shadow: 0 1px 1px -1px #333 !important;
}
.ov-breadcrumb a { color: #555 !important; }
.ov-breadcrumb a:hover { text-decoration: underline !important; }

/* 기본 정보 뷰 */
/* view 스타일은 글로벌(pp-override-layout.css)을 그대로 사용 — 설비 대시보드와 동일 */

/* 에셋 이미지 영역 */
.ov-asset-image-wrap {
    position: relative;
    text-align: center !important;
    padding: 5px !important;
    height: 320px;
    border: 0 !important;
    border-radius: 0 !important;
    background: transparent !important;
    margin-bottom: 10px !important;
    overflow: hidden;
}
.ov-health-badge, .ov-conn-badge {
    position: absolute;
    z-index: 1;
    left: 20px;
    width: 100px;
    height: 40px;
    border-radius: 100px !important;
    background: var(--pp-white) !important;
    border: 2px solid #ccc !important;
    color: #ccc !important;
    text-align: center !important;
    font-family: sans-serif !important;
    font-size: 24px !important;
    font-weight: bold !important;
    opacity: 0.6 !important;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
}
.ov-health-badge {
    top: 0px;
}
.ov-conn-badge {
    top: 50px;
    border: 0 !important;
    font-size: 24px !important;
}
.ov-asset-image-wrap img {
    max-width: 100%;
    max-height: 320px;
}
.ov-asset-image-placeholder {
    color: #ccc !important;
    font-size: 80px !important;
    line-height: 320px !important;
}

/* OEE 요약 pill 테이블 (설비 대시보드 스타일) */
.ov-oee-pill-wrap {
    border: 0px solid #888 !important;
    border-radius: 0px !important;
    margin-top: 10px !important;
}
.ov-oee-pill-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid #ccc !important;
    border-radius: 32px !important;
    overflow: hidden;
}
.ov-oee-pill-table .oee_header {
    padding: 3px !important;
    margin-right: 1px !important;
    border-bottom: 1px solid #ddd !important;
    border-right: 1px solid var(--pp-white) !important;
    color: #555 !important;
    text-align: center !important;
    background: #eee !important;
}
.ov-oee-pill-table .oee_header:last-child {
    border-right: 0px !important;
}
.ov-oee-pill-table .oee_value {
    padding: 3px !important;
    margin-right: 1px !important;
    border-bottom: 0px solid #ddd !important;
    border-right: 1px solid var(--pp-white) !important;
    color: #333 !important;
    font-size: 12px !important;
    font-weight: bold !important;
    text-align: center !important;
}
.ov-oee-pill-table .oee_value:last-child {
    border-right: 0px !important;
}

/* 하위 에셋 / OPC 테이블 (customer/index 스타일) */
.ov-data-table {
    table-layout: fixed;
}
.ov-data-table thead th {
    text-align: center !important;
}
.ov-data-table tbody td {
    word-break: break-all;
    vertical-align: middle;
}

/* 알람 요약 카드 */
.ov-alarm-summary table { width: 100%; }
.ov-alarm-summary td { padding-right: 10px !important; }
.ov-alarm-summary td:last-child { padding-right: 0 !important; }



/* 차트 컨테이너 */
.ov-status-donut {
    height: 180px;
}
.ov-trend-chart {
    height: 200px;
    width: 100%;
}


/* 최근 알람 목록 */
.ov-alarm-item {
    padding: 6px 8px !important;
    border-bottom: 1px solid #eee !important;
    font-size: 11px !important;
}
.ov-alarm-item:hover {
    background: #f9f9f9 !important;
}
.ov-alarm-item .alarm-time {
    color: #999 !important;
    font-size: 10px !important;
}
.ov-alarm-item .alarm-priority {
    display: inline-block;
    padding: 1px 6px !important;
    border: 1px solid transparent !important;
    border-radius: 3px !important;
    color: var(--pp-white) !important;
    font-size: 10px !important;
    font-weight: bold !important;
    margin-right: 5px !important;
}
.ov-alarm-item .alarm-priority.info  { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; }
.ov-alarm-item .alarm-priority.warn  { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; }
.ov-alarm-item .alarm-priority.error { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; }
/* 컬러 배경 위 텍스트는 흰색 (info=녹/warn=주황/error=빨강 모두 진한 톤) */
.ov-alarm-item .alarm-priority.info,
.ov-alarm-item .alarm-priority.warn,
.ov-alarm-item .alarm-priority.error { color: var(--pp-white) !important; }

/* vis 타임라인 컬러 아이템 텍스트·아이콘 흰색 강제는 pp-57-timeline-node.css(.pp-tl-node *) 로 이관 */
.ov-alarm-item .alarm-desc {
    color: #333 !important;
    margin-top: 2px !important;
}

/* 날짜 선택 입력 */
.ov-date-input {
    width: 200px;
    border-radius: 24px !important;
    text-align: center !important;
    color: var(--pp-white) !important;
    background: #888 !important;
    border: 1px solid #ddd !important;
    font-size: 14px !important;
    font-weight: bold !important;
}

/* 날짜 피커 위치 조정 — .ui-datepicker 정의는 위 194~198 라인 룰 재사용 */

/* ID 배지 */
#id-badge, .id-badge {
    font-family: monospace !important;
    font-size: 11px !important;
    color: #888 !important;
}

/* 섹션 타이틀 공통 */
.ov-section-title {
    padding: 3px !important;
    border-bottom: 1px solid #ccc !important;
    font-size: 14px !important;
    margin-bottom: 5px !important;
}
.ov-section-title b {
    color: #333 !important;
}

/* 빈 데이터 메시지 */
.ov-empty {
    text-align: center !important;
    color: #ccc !important;
    padding: 30px 10px !important;
    font-size: 14px !important;
}
.ov-empty i {
    font-size: 32px !important;
    display: block;
    margin-bottom: 10px !important;
}

/* 우측 소형 트렌드 차트 */

/* 통계 테이블 */
.ov-stats-table td {
    padding: 2px 6px !important;
    border-bottom: 1px solid #f0f0f0 !important;
}
.ov-stats-label {
    color: #888 !important;
    width: 100px;
}
.ov-stats-value {
    font-weight: bold !important;
    text-align: right !important;
}

/* 패널 간격 */
.ov-card-gap {
    margin-bottom: 15px !important;
}

/* 하위 설비 카드 */
.equip-card {
    display: flex;
    background: var(--pp-white) !important;
    border: none !important;
    border-bottom: 2px solid #e0e3e8 !important;
    border-left: none !important;
    border-radius: 0 !important;
    margin-bottom: 0 !important;
    padding: 12px 14px !important;
    cursor: pointer;
    transition: all 0.2s ease;
}
.equip-card:hover {
    background: #f8fbff !important;
}
.equip-card-left {
    flex: 0 0 108px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.equip-card-img {
    width: 96px;
    height: 96px;
    border: 2px solid #eef2f5 !important;
    border-radius: 8px !important;
    overflow: hidden;
    text-align: center !important;
    background: linear-gradient(135deg, #f8f9fa 0%, #eef1f4 100%) !important;
}
.equip-card-img img {
    width: 96px;
    height: 96px;
    object-fit: cover;
}
.equip-card-body {
    flex: 1;
    min-width: 0;
    padding-left: 12px !important;
}
.equip-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 3px !important;
}
.equip-card-name {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: #1a2a3a !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: -0.2px !important;
}
.equip-card-badges {
    white-space: nowrap !important;
    flex-shrink: 0;
    margin-left: 8px !important;
    display: flex;
    gap: 4px;
    align-items: center;
}
.equip-card-badges span {
    border-radius: 10px !important;
    padding: 2px 8px !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    letter-spacing: 0.2px !important;
}
.equip-card-id {
    font-size: 11px !important;
    color: #7a8a9a !important;
    margin-bottom: 6px !important;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px;
}
.equip-card-alarm-counts {
    display: inline-flex;
    gap: 3px;
    margin-left: 4px !important;
}
.equip-card-alarm-counts span {
    border-radius: 10px !important;
    padding: 1px 7px !important;
    font-size: 9px !important;
    font-weight: 600 !important;
    letter-spacing: 0.3px !important;
}
.equip-card-oee {
    margin-top: 4px !important;
}
.equip-card-oee-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid #e0e3e8 !important;
    border-radius: 6px !important;
    overflow: hidden;
}
.equip-card-oee-table .oee_header {
    padding: 3px 6px !important;
    border-bottom: 1px solid #ddd !important;
    border-right: 1px solid #ddd !important;
    color: #666 !important;
    text-align: center !important;
    background: #f0f0f0 !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    letter-spacing: 0.3px !important;
}
.equip-card-oee-table .oee_value {
    padding: 4px 6px !important;
    border-right: 1px solid #eef1f4 !important;
    color: #2a3a4a !important;
    font-size: 13px !important;
    font-weight: 700 !important;
    text-align: center !important;
}

/* d3 타임라인 축 스타일 (설비 대시보드와 동일) — .axis/.timeline-label 정의는 위 232~245 라인 룰 재사용 */

/* === pp-34-mobile-pages.css === */
/* ━━━ m/connect — 모바일 connect 페이지 ━━━ */



/* OPC 마커 카운트 칩 (지도 좌측 하단 5개 segmented 칩) */
.opc_obj {
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
    padding: 4px 0 !important;
    color: var(--pp-white) !important;
    border-radius: 4px !important;
    text-align: center !important;
    font-size: 11px !important;
    cursor: pointer;
    line-height: 1.2 !important;
    transition: transform 0.12s, box-shadow 0.12s, opacity 0.12s;
}

.opc_obj:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25) !important;
}

.opc_obj > * { color: var(--pp-white) !important; }

/* 5개 칩을 한 행에 균등 배분 */
.map-overlay-keep:has(> .opc_obj) {
    display: inline-flex !important;
    gap: 4px;
    background: transparent !important;
    width: 360px;
    height: auto !important;
    padding: 0 !important;
}

.opc_obj > .border-bottom-light {
    border-bottom-color: rgba(255, 255, 255, 0.35) !important;
    margin: 2px 8px !important;
}

@media (max-width: 575.98px) {
    .map-overlay-keep:has(> .opc_obj) {
        width: min(360px, calc(100vw - 128px)) !important;
        gap: 3px;
    }

    .map-overlay-keep:has(> .opc_obj) .opc_obj {
        min-height: 40px;
        font-size: 10px !important;
    }

    .map-overlay-keep:has(> .opc_obj) .opc_obj > .border-bottom-light {
        margin: 1px 5px !important;
    }
}


/* ━━━ m/site — 모바일 site 페이지 (.pp-msite 스코프) ━━━ */
/**
 * 모바일 사이트 페이지 스타일.
 *
 * m/site.jsp 의 인라인 CSS를 외부화한 파일이다.
 * .someOtherTheme 정의는 위 61~73 라인 룰 재사용.
 */

/* ━━━ forecast/index — page-scoped label.form-label (전역 누수 방지) ━━━ */
/* forecast 본문 폼은 .pp-form-row 가로폼(라벨 좌측 고정폭)이 정당 용도다.
 * 다만 BootstrapDialog/모달은 body 직속(#page-wrapper 밖)에 append 되므로,
 * 이 규칙을 #page-wrapper 본문으로 스코프해 다이얼로그 라벨 누수를 구조적으로 차단한다.
 * (edge/view 사례처럼 우측정렬+고정폭이 다이얼로그 stacked 표준을 깨는 것을 방지) */
body.pp-page-forecast #page-wrapper label.form-label {
            width: 80px;
            text-align: right !important;
            margin-right: 10px !important;
            line-height: 45px !important;
        }

        #contents div {
            float: left;
        }

        .columns {
            padding: 10px !important;
        }


/* ============================================================
 * /equipment/index — 설비 목록 카드 (모던 디자인)
 * ============================================================ */
.eq-card-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 14px;
    padding: 0 !important;
    margin: 0 !important;
    list-style: none;
}

.eq-card {
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    overflow: hidden;
    text-align: left !important;
    transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
    display: flex;
    flex-direction: column;
}

.eq-card:hover {
    box-shadow: 0 6px 18px rgba(15, 23, 42, 0.08) !important;
    transform: translateY(-1px);
    border-color: var(--primary, var(--pp-primary)) !important;
}

.eq-card-header {
    padding: 10px 14px 4px 14px !important;
    background: var(--pp-white) !important;
}

.eq-card-header > b {
    display: block;
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

.eq-card-desc {
    padding: 0 14px 8px 14px !important;
    background: var(--pp-white) !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.4 !important;
    min-height: 18px;
}

.eq-card-status {
    padding: 8px 12px !important;
    background: var(--muted, #f8fafc) !important;
    border-top: 1px solid var(--pp-border) !important;
    border-bottom: 1px solid var(--pp-border) !important;
}

.eq-card-status table {
    width: 100%;
    margin: 0 !important;
    border-collapse: separate;
    border-spacing: 4px 0;
}

.eq-card-status td {
    padding: 0 !important;
    text-align: center !important;
    vertical-align: middle;
}

.eq-status-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--pp-text-soft);
    color: var(--pp-white);
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25) !important;
}

.eq-status-dot > i {
    font-size: 10px !important;
}

.eq-card-thumb {
    padding: 14px !important;
    background: var(--pp-white) !important;
    text-align: center !important;
}

.eq-card-thumb a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 110px;
    text-decoration: none !important;
}

.eq-card-thumb img {
    display: block;
    margin: 0 auto !important;
    max-width: 100%;
    width: auto;
    height: 110px;
    object-fit: contain;
    transition: transform 0.2s ease;
}

.eq-card-thumb a:hover img {
    transform: scale(1.03);
}

.eq-card-image-fallback {
    display: none;
    align-items: center;
    justify-content: center;
    width: 110px;
    height: 110px;
    border-radius: 8px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 42px;
    line-height: 1;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.eq-card-thumb-empty .eq-card-image-fallback {
    display: inline-flex;
}

.eq-card-image-hidden {
    display: none !important;
}

.eq-card-thumb a:hover .eq-card-image-fallback {
    background: rgba(21, 128, 61, 0.08) !important;
    border-color: var(--primary, var(--pp-primary)) !important;
    color: var(--primary, var(--pp-primary)) !important;
}

.eq-oee-area {
    padding: 0 14px 12px 14px !important;
    background: var(--pp-white) !important;
    text-align: center !important;
    min-height: 26px;
}

.eq-status-badge-wrap {
    text-align: center !important;
}

.eq-card-footer {
    margin-top: auto !important;
    padding: 8px 14px !important;
    background: var(--muted, #f8fafc) !important;
    border-top: 1px solid var(--pp-border) !important;
    font-size: 12px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.eq-card-footer > span:first-child {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 500 !important;
    color: var(--foreground, #111827) !important;
}

.eq-card-footer > span:first-child > i {
    color: var(--primary, var(--pp-primary)) !important;
}

.eq-card-footer a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 5px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-decoration: none !important;
    transition: background 0.15s, color 0.15s;
}

.eq-card-footer a:hover {
    background: var(--primary, var(--pp-primary)) !important;
    color: var(--pp-white) !important;
}

/* 좌측 필터링 패널 (id="tags") — 패딩/마진 정돈 */
#page-wrapper #tags > .card-body {
    padding: 12px !important;
}

#page-wrapper #tags > .card-header {
    padding: 10px 12px !important;
}

/* 좌측 필터링 패널 푸터 액션 (검색 버튼) — 살짝 채워진 배경 */
#page-wrapper .card-footer.card-footer-actions {
    background: var(--muted, #f8fafc) !important;
    padding: 10px 12px !important;
}


/* ============================================================
 * /canvas/index — 캔버스 카드 (eq-card 패턴 매칭)
 * ============================================================ */
.canvas-card-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 14px;
    margin: 0 !important;
    padding: 0 !important;
}

.canvas-card {
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    overflow: hidden;
    text-align: left !important;
    cursor: pointer;
    transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
    display: flex;
    flex-direction: column;
}

.canvas-card:hover {
    box-shadow: 0 6px 18px rgba(15, 23, 42, 0.08) !important;
    transform: translateY(-1px);
    border-color: var(--primary, var(--pp-primary)) !important;
}

/* 헤더 (제목) — eq-card-header 와 동일 */
.canvas-card-header {
    padding: 10px 14px 4px 14px !important;
    background: var(--pp-white) !important;
}

.canvas-card-header > b {
    display: block;
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* 설명 */
.canvas-card-desc {
    padding: 0 14px 8px 14px !important;
    background: var(--pp-white) !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.4 !important;
    min-height: 18px;
}

/* 타입 배지 row (eq-card-status 위치) */
.canvas-card-status {
    padding: 8px 14px !important;
    background: var(--muted, #f8fafc) !important;
    border-top: 1px solid var(--pp-border) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    min-height: 36px;
}

.canvas-card-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px !important;
    border-radius: 12px !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    flex-shrink: 0;
    line-height: 1.4 !important;
    background: var(--pp-muted-fg) !important;
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

.canvas-card-badge > i {
    color: var(--pp-white) !important;
}

.canvas-card-badge-mine {
    background: var(--pp-primary) !important;
    color: var(--pp-white) !important;
}

.canvas-card-badge-shared {
    background: #8b5cf6 !important;
    color: var(--pp-white) !important;
}

/* SVG 썸네일 (중앙) — eq-card-thumb 와 동일 */
.canvas-card-thumb {
    padding: 14px !important;
    background: var(--pp-white) !important;
    text-align: center !important;
    height: 140px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.canvas-card-svg {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.canvas-card-svg > svg {
    max-width: 100%;
    max-height: 100%;
}

/* 빈 썸네일 — 큰 아이콘 */
.canvas-card-svg > i {
    font-size: 48px !important;
    color: oklch(0.85 0.01 286) !important;
    opacity: 0.55 !important;
}

/* 푸터 (위젯 카운트 + 액션) — eq-card-footer 와 동일 */
.canvas-card-footer {
    margin-top: auto !important;
    padding: 8px 14px !important;
    background: var(--muted, #f8fafc) !important;
    border-top: 1px solid var(--pp-border) !important;
    font-size: 12px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* === pp-40-recent-additions.css === */
/* ============================================================================
 * pp-09-recent-additions.css
 * SCOPE  : CANVAS CARD / MAP MARKER / CONNECT STATUS
 * 영역   : canvas-card 메타·액션, /map/index 사이트 마커 팝업, 데이터 파이프라인 오버레이, 우측 정보 패널, PlantPulse Hero, /connect/status 사이드 Activity Feed
 * 주의   : 본 파일은 9개 part(pp-09a ~ pp-09i)로 분할됨. ant concat-css 빌드.
 * ============================================================================ */

.canvas-card-meta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 500 !important;
    color: var(--foreground, #111827) !important;
}

.canvas-card-meta > i {
    color: var(--primary, var(--pp-primary)) !important;
}

.canvas-card-actions {
    display: inline-flex;
    gap: 4px;
}

.canvas-card-action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 5px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-decoration: none !important;
    transition: background 0.15s, color 0.15s;
}

.canvas-card-action-btn:hover {
    background: var(--primary, var(--pp-primary)) !important;
    color: var(--pp-white) !important;
}

.canvas-card-action-btn.canvas-card-action-danger:hover {
    background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important;
}


/* ============================================================
 * /map/index — 사이트 마커 클릭 팝업 (Leaflet popup 안 콘텐츠)
 * ============================================================ */
.site-popup { width: 320px; font-family: 'Noto Sans Korean', sans-serif !important; }
.site-popup-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 8px 12px !important; background: #75848f !important; border-radius: 6px 6px 0 0 !important; color: var(--pp-white) !important;
}
.site-popup-header .site-name { font-size: 14px !important; font-weight: 700 !important; cursor: pointer; }
.site-popup-header .site-name:hover { text-decoration: underline !important; }
.site-popup-header .site-id-badge {
    font-size: 10px !important; background: rgba(255,255,255,0.2) !important; border-radius: 10px !important;
    padding: 0px 8px !important; cursor: pointer; margin-right: 24px !important; line-height: 16px !important;
}
.site-popup-desc {
    text-align: center !important; font-size: 11px !important; color: #888 !important; padding: 4px 10px !important;
    background: #f3f4f6 !important; border-bottom: 1px solid var(--pp-border) !important;
}
.site-popup-body { background: var(--pp-white) !important; border-radius: 0 0 6px 6px !important; border: 1px solid var(--pp-border) !important; border-top: 0 !important; max-height: 400px; overflow-y: auto; }
.site-popup-stats {
    display: grid; grid-template-columns: 1fr 1fr 1fr 1fr;
    gap: 0; padding: 8px 6px !important; border-bottom: 1px solid #f0f0f0 !important;
}
.site-popup-stat {
    text-align: center !important; padding: 4px 2px !important;
}
.site-popup-stat .stat-value { font-size: 16px !important; font-weight: 700 !important; color: #333 !important; }
.site-popup-stat .stat-value a { color: #333 !important; text-decoration: none !important; }
.site-popup-stat .stat-value a:hover { color: #1976d2 !important; }
.site-popup-stat .stat-label { font-size: 9px !important; color: #999 !important; margin-top: 1px !important; }
.site-popup-section { padding: 8px 10px !important; border-bottom: 1px solid #f0f0f0 !important; }
.site-popup-section:last-child { border-bottom: 0 !important; }
.site-popup-section-title { font-size: 10px !important; color: #aaa !important; font-weight: 600 !important; margin-bottom: 4px !important; }
.site-popup-conn-item b { color: #333 !important; }
.site-popup-alarm-row .alarm-info,
.site-popup-alarm-row .alarm-warn,
.site-popup-alarm-row .alarm-error { flex: 1; font-size: 11px !important; text-align: center !important; }
.site-popup-oee { display: flex; align-items: center; justify-content: space-around; padding: 4px 0 !important; }
.site-popup-oee-item { text-align: center !important; }
.site-popup-oee-item:first-child { border-right: 1px solid #ddd !important; }
.site-popup-oee-label { font-size: 9px !important; color: #888 !important; margin-top: -2px !important; }
.eq-status-badge {
    display: inline-block; font-size: 10px !important; color: var(--pp-white) !important; border-radius: 8px !important;
    padding: 0px 6px !important; margin-left: 2px !important; font-weight: 600 !important; line-height: 16px !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* ============================================================
 * /map/index — 데이터 파이프라인 오버레이 (좌측 상단)
 * 5개 stage 카드 + 4개 화살표 = 총 컨테이너 폭 610px (각 카드 +20px)
 * ============================================================ */
.map-pipeline-overlay {
    position: absolute;
    z-index: 450;
    left: 55px;
    top: 10px;
    width: 640px;
    background: var(--pp-white) !important;
    border: 0 !important;
    border-radius: 8px !important;
    padding: 10px 12px !important;
    opacity: 0.97 !important;
    pointer-events: auto;
    /* 플랫폼 헬스 타임라인 패널과 동일 drop-shadow 톤 */
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 6px 18px rgba(15, 23, 42, 0.08) !important;
}

.map-pipeline-flow {
    display: flex;
    align-items: stretch;
    gap: 4px;
}


.map-pipeline-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--muted-foreground, var(--pp-text-soft)) !important;
    font-size: 14px !important;
    flex: 0 0 auto;
    width: 14px;
}

/* tile 톤 — shadcn stat card 패턴 (기본 = 정상 그린 톤, JS 가 inline 으로 지연/이상 색 토글) */
.map-pipeline-overlay .map-ov-tile {
    background: var(--pp-white) !important;
    border: 2px solid #5aa86a !important;
    border-radius: 8px !important;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: box-shadow 0.15s, border-color 0.15s, transform 0.15s;
}
.map-pipeline-overlay .map-ov-tile:hover {
    box-shadow: 0 4px 12px rgba(90, 168, 106, 0.18) !important;
    transform: translateY(-1px);
}

/* 상단 헤더 — 정상시 녹색 / 지연·이상시 주황·빨강 (JS inline 으로 토글, 카드 border 와 동일 톤). 텍스트·아이콘 항상 흰색 */
.map-pipeline-overlay .map-ov-section-divider {
    font-size: 10.5px !important;
    color: var(--pp-white) !important;
    font-weight: 600 !important;
    background: linear-gradient(135deg, #2e7d32 0%, #43a047 100%) !important;   /* 기본 = 진한→밝은 그린 그라데이션 */
    padding: 5px 6px !important;
    border-bottom: 0 !important;
    text-align: center !important;
    letter-spacing: 0.04em !important;
    margin: 0 !important;
}
.map-pipeline-overlay .map-ov-section-divider > i,
.map-pipeline-overlay .map-ov-section-divider > span,
.map-pipeline-overlay .map-ov-section-divider .map-ov-stage-icon,
.map-pipeline-overlay .map-ov-section-divider .map-ov-stage-icon > i {
    color: var(--pp-white) !important;
    margin-right: 2px !important;
}
.map-ov-stage-icon { color: var(--pp-white) !important; }

/* 중앙 값 — 굵고 큼지막하게 */
.map-pipeline-overlay .map-ov-pad { padding: 0 !important; }
.map-pipeline-overlay .map-ov-heading {
    font-size: 17px !important;
    font-weight: 800 !important;
    color: var(--foreground, #0f172a) !important;
    line-height: 1.15 !important;
    text-align: center !important;
    padding: 7px 4px 2px !important;
    letter-spacing: -0.01em !important;
}
.map-pipeline-overlay .map-ov-heading .map-ov-hint-xs {
    font-size: 9.5px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    font-weight: 500 !important;
    margin-left: 1px !important;
}

/* 하단 health badge — pill (정상=green 기본, JS 가 inline 으로 지연=orange / 이상=red 토글) */
.map-pipeline-overlay .map-ov-row-spc {
    display: flex;
    justify-content: center;
    margin: 0 !important;
    padding: 0 4px 5px !important;
}
.map-pipeline-overlay .health-badge.map-ov-chip-xs {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 9px !important;
    border-radius: 999px !important;
    font-size: 9.5px !important;
    font-weight: 600 !important;
    line-height: 1.4 !important;
    background: #2e7d32 !important;       /* 기본 = 정상 (JS 동적 색이 inline 으로 우선 적용됨) */
    color: var(--pp-white) !important;
    border: 0 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
.map-pipeline-overlay .health-badge.map-ov-chip-xs > i { font-size: 8.5px !important; }
.map-pipeline-overlay .health-badge.map-ov-chip-xs > span { color: var(--pp-white) !important; }

/* 차트 bar 영역 — 카드 바닥 */
.map-pipeline-overlay .map-ov-bar {
    width: 100%;
    height: 22px;
    margin: auto 0 0 !important;
    background: transparent !important;
    border-top: 0 !important;
}


/* ============================================================
 * /map/index — 우측 정보 패널 스택 (헬스 타임라인 / 시스템 성능 / 클러스터)
 * 3개 패널을 flex column 으로 stack + gap 으로 자동 간격
 * ============================================================ */
.map-info-stack {
    position: absolute;
    z-index: 450;
    top: 10px;
    right: 15px;
    width: 420px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    pointer-events: none;
}
.map-info-overlay {
    position: static;
    width: 100%;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    padding: 10px 12px !important;
    opacity: 0.97 !important;
    pointer-events: auto;
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 6px 18px rgba(15, 23, 42, 0.08) !important;
}

.map-info-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 6px !important;
    padding-bottom: 6px !important;
    border-bottom: 1px solid var(--pp-border) !important;
}
.map-info-title {
    font-size: 12px !important;
    font-weight: 700 !important;
    color: var(--foreground, #0f172a) !important;
    letter-spacing: -0.005em !important;
}
.map-info-title > i {
    margin-right: 2px !important;
}
.map-info-sub {
    font-size: 10.5px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    letter-spacing: 0.02em !important;
}
/* 패널 헤더 우측 정보 아이콘 (마우스 오버 시 bootstrap tooltip) */
.map-info-help {
    margin-left: auto !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    cursor: help;
    font-size: 13px !important;
    transition: color 0.15s;
}
.map-info-help:hover { color: var(--primary, var(--pp-primary)) !important; }

/* ============================================================
 * /map/index — PlantPulse Hero (시스템 진단 사이드바 하단)
 * ============================================================ */
.pp-hero-panel {
    margin-top: 16px !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    overflow: hidden;
    background:
        radial-gradient(ellipse at top right, rgba(96, 165, 250, 0.10) 0%, transparent 55%),
        radial-gradient(ellipse at bottom left, rgba(29, 78, 216, 0.06) 0%, transparent 55%),
        linear-gradient(135deg, var(--pp-white) 0%, #f8fafc 100%) !important;
    color: var(--foreground, #0f172a) !important;
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 6px 18px rgba(15, 23, 42, 0.06) !important;
}
.pp-hero-body {
    padding: 20px 20px 16px !important;
}
.pp-hero-content {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px !important;
    padding-bottom: 12px !important;
    border-bottom: 1px solid var(--pp-border) !important;
}
.pp-hero-icon {
    width: 44px; height: 44px;
    border-radius: 10px !important;
    background: linear-gradient(135deg, rgba(29, 78, 216, 0.10) 0%, rgba(96, 165, 250, 0.16) 100%) !important;
    border: 1px solid rgba(29, 78, 216, 0.18) !important;
    display: flex; align-items: center; justify-content: center;
    color: var(--primary, var(--pp-primary)) !important;
    font-size: 20px !important;
    flex-shrink: 0;
}
.pp-hero-text { min-width: 0; }
.pp-hero-title {
    font-size: 16px !important;
    font-weight: 800 !important;
    color: var(--foreground, #0f172a) !important;
    letter-spacing: -0.01em !important;
    line-height: 1.2 !important;
}
.pp-hero-sub {
    margin-top: 2px !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    letter-spacing: 0.02em !important;
}
.pp-hero-features {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.pp-hero-feature {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 12px !important;
    color: var(--foreground, #334155) !important;
    letter-spacing: 0.01em !important;
}
.pp-hero-feature > i {
    width: 20px;
    color: var(--primary, var(--pp-primary)) !important;
    font-size: 12.5px !important;
    flex-shrink: 0;
    text-align: center !important;
}
.pp-hero-footer {
    margin-top: 14px !important;
    padding-top: 10px !important;
    border-top: 1px solid var(--pp-border) !important;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 10.5px !important;
    letter-spacing: 0.04em !important;
}
.pp-hero-tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--primary, var(--pp-primary)) !important;
    font-weight: 600 !important;
}
.pp-hero-tag > i { font-size: 11px !important; }
.pp-hero-version {
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
}

/* ============================================================
 * /connect/status — 사이드 Activity Feed (cs-timeline) 컴팩트
 * ============================================================ */
body #page-wrapper .card.card > .card-body.cs-history-body {
    padding: 8px 0 0 !important;          /* 좌우 0 — 데이터테이블이 카드 보더에 좌우 피팅(다른 화면과 동일) */
}
.cs-history { padding: 0 !important; min-height: 0; }
/* 히스토리 DataTable — 카드 좌우 끝까지 피팅, 가로 스크롤바 미발생(table-responsive 제거됨) */
.cs-history .opc-history-table { margin: 0; }
.cs-history .dataTables_wrapper { overflow-x: hidden; }

.cs-timeline.ds-timeline {
    list-style: none;
    margin: 0 !important;
    padding: 4px 10px 4px 22px !important;       /* 좌(dot+라인 공간) 22 + 우(여백) 10 + 상하 4 */
    position: relative;
    border-left: 0 !important;        /* 기본 ds-timeline 의 2px border 무력화 — ::before 라인만 사용 */
}
.cs-timeline.ds-timeline::before {
    content: '';
    position: absolute;
    left: 14px; top: 12px; bottom: 12px;
    width: 1px;
    background: var(--pp-border) !important;
}
.cs-timeline .ds-tl-dot {
    left: -12px;                       /* 패딩 22 + dot left -12 = container 좌단에서 10 위치 */
}
.cs-timeline .ds-tl-item {
    position: relative;
    padding: 4px 4px 4px 10px !important;
    margin: 0 !important;
    border-radius: 4px !important;
    cursor: pointer;
    transition: background 0.12s;
}
.cs-timeline .ds-tl-item + .ds-tl-item { margin-top: 2px !important; }
.cs-timeline .ds-tl-item:hover { background: var(--muted, #f4f6fa) !important; }
.cs-timeline .ds-tl-dot {
    position: absolute;
    left: -12px; top: 50%;
    width: 10px; height: 10px;
    margin-top: -5px !important;
    border-radius: 50% !important;
    background: var(--pp-white) !important;
    border: 2px solid var(--pp-border, var(--pp-text-soft)) !important;
    display: flex; align-items: center; justify-content: center;
    font-size: 0 !important;
}
.cs-timeline .ds-tl-err  .ds-tl-dot { border-color: #ef4444 !important; }
.cs-timeline .ds-tl-warn .ds-tl-dot { border-color: #f59e0b !important; }
.cs-timeline .ds-tl-info .ds-tl-dot { border-color: var(--pp-info) !important; }
.cs-timeline .ds-tl-ok   .ds-tl-dot { border-color: var(--pp-tone-success-bg) !important; }

.cs-timeline .ds-tl-body { display: flex; flex-direction: column; gap: 2px; }
.cs-timeline .cs-tl-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    line-height: 1.4 !important;
}
.cs-timeline .cs-tl-line .id-badge {
    font-size: 10.5px !important;
    padding: 1px 6px !important;
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 70%;
}
.cs-timeline .cs-tl-time {
    font-size: 10px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    letter-spacing: 0.02em !important;
    flex-shrink: 0;
    display: inline-flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.25 !important;
    cursor: help;
}
.cs-timeline .cs-tl-ago {
    color: var(--foreground, var(--pp-border-strong)) !important;
    font-weight: 600 !important;
    font-size: 10.5px !important;
}
.cs-timeline .cs-tl-time-abs {
    font-family: 'Consolas', 'Menlo', monospace !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    font-size: 9.5px !important;
}
.cs-timeline .cs-tl-sub {
    font-size: 10.5px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    line-height: 1.4 !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    width: 100%;
}

.cs-tl-empty {
    text-align: center !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    padding: 20px 8px !important;
    font-size: 11.5px !important;
}
.cs-tl-empty > i {
    font-size: 32px !important;
    display: block;
    margin: 0 auto 8px !important;
    color: var(--pp-tone-success-bg) !important;
    opacity: 0.6 !important;
    line-height: 1 !important;
    text-align: center !important;
}


/* === pp-41-stats-edge-dialog.css === */
/* ============================================================================
 * pp-09a-stats-edge-dialog.css
 * SCOPE  : STATISTICS / EDGE / DIALOG
 * 영역   : /alarm/view 알람 설정 패널, /statistics/index 통계, /connect/view 통계, /edge/view 엣지 상세, BootstrapDialog
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /alarm/view — 알람 설정 패널 (메타 grid + 전송 플래그 + EQL)
 * ============================================================ */
.alarm-config-panel .card-head-actions .priority-badge-unknown {
    margin-right: 6px !important;
    vertical-align: middle;
}
.alarm-config-body { padding: 16px 18px !important; }

/* 알람 설정 메타 — table 형식 */
.alarm-config-meta-table {
    margin: 0 0 14px !important;
    font-size: 12.5px !important;
    table-layout: fixed;
}
.alarm-config-meta-table thead th {
    background: linear-gradient(180deg, #f8fafc 0%, var(--pp-white) 100%) !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
    font-size: 11px !important;
    letter-spacing: 0.02em !important;
    border-bottom: 1px solid var(--pp-border) !important;
    padding: 8px 12px !important;
    white-space: nowrap !important;
}
.alarm-config-meta-table thead th > i { color: var(--primary, var(--pp-primary)) !important; margin-right: 4px !important; }
.alarm-config-meta-table tbody td {
    color: var(--foreground, #0f172a) !important;
    padding: 10px 12px !important;
    line-height: 1.5 !important;
    word-break: break-word;
    vertical-align: middle;
    border-top: 0 !important;
}
.alarm-config-meta-table tbody tr { background: var(--pp-white) !important; }
.alarm-config-meta-date {
    font-size: 11.5px !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    white-space: nowrap !important;
}
.alarm-config-meta-sep { color: var(--muted-foreground, var(--pp-text-soft)) !important; margin: 0 4px !important; }

.alarm-config-flags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 12px 0 14px !important;
    padding: 10px 12px !important;
    background: var(--muted, #f8fafc) !important;
    border-radius: 12px;
}
.alarm-config-flag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px !important;
    font-size: 11.5px !important;
    font-weight: 500 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 999px !important;
    letter-spacing: 0.01em !important;
}
.alarm-config-flag.is-on {
    color: var(--pp-tone-success-bg) !important;
    background: rgba(34, 197, 94, 0.08) !important;
    border-color: rgba(34, 197, 94, 0.30) !important;
}
.alarm-config-flag > i { color: inherit !important; opacity: 0.7 !important; }
.alarm-config-flag-val {
    font-weight: 700 !important;
    margin-left: 2px !important;
    padding: 1px 7px !important;
    border-radius: 4px !important;
    background: rgba(15, 23, 42, 0.06) !important;
    color: var(--foreground, #0f172a) !important;
    font-size: 10.5px !important;
    letter-spacing: 0.04em !important;
}
.alarm-config-flag.is-on .alarm-config-flag-val {
    background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important;
}

/* alarm-config-eql — 커버(보더/배경/헤더) 제거, 내부 CodeMirror 만 글로벌 보더 사용 */
.alarm-config-eql {
    border: 0 !important;
    border-radius: 0 !important;
    background: transparent !important;
    overflow: visible;
}
.alarm-config-eql-head { display: none; }
.alarm-config-eql-title,
.alarm-config-eql-hint { display: none; }
.alarm-config-eql .alarm-view-eql-textarea {
    border: 0 !important;
    background: #fafafa !important;
    font-family: 'Consolas', 'Menlo', 'Source Code Pro', monospace !important;
    font-size: 12px !important;
    color: #0f172a !important;
    padding: 12px 14px !important;
    min-height: 330px;
    box-shadow: none !important;
    resize: vertical;
}
/* ============================================================
 * CodeMirror — signal 라이트 테마 단일 소스 (xq-dark 테마 override)
 *  컨테이너: 라이트 배경 + 보더 + 라운드
 *  토큰: SQL/EQL 구문 강조 (keyword/string/number/comment 등)
 *  특정 컨테이너 (.alarm-config-eql, .query-eql-panel 등) 는 size/padding 만 별도
 * ============================================================ */
body .CodeMirror {
    background: var(--pp-white) !important;
    color: var(--foreground) !important;
    font-family: jetbrainsMono, 'Consolas', 'Menlo', monospace !important;
    border: 1px solid var(--border) !important;
    border-radius: 8px !important;
    overflow: hidden;
}
body .CodeMirror-gutters {
    background: var(--muted) !important;
    border-right: 1px solid var(--border) !important;
}
body .CodeMirror-linenumber { color: var(--muted-foreground) !important; }
body .CodeMirror pre,
body .CodeMirror-line { color: var(--foreground) !important; }
/* anonymous span 만 다크 텍스트 — cm-* 토큰은 자체 색 유지 */
body .CodeMirror-line > span:not([class]) { color: var(--foreground) !important; }
body .CodeMirror-cursor { border-left-color: var(--primary) !important; }
body .CodeMirror-selected { background: rgba(29, 78, 216, 0.14) !important; }
body .CodeMirror-activeline-background { background: rgba(29, 78, 216, 0.04) !important; }
body .CodeMirror-matchingbracket { color: var(--primary) !important; font-weight: 600 !important; }
body .CodeMirror-nonmatchingbracket { color: var(--destructive) !important; }

/* SQL/EQL 토큰 컬러 — 라이트 테마 */
body .cm-keyword   { color: var(--primary) !important; font-weight: 600 !important; }
body .cm-string    { color: var(--success, var(--pp-tone-success-bg)) !important; }
body .cm-number    { color: var(--warning, #b45309) !important; }
body .cm-comment   { color: var(--muted-foreground) !important; font-style: italic !important; }
body .cm-operator  { color: #6b21a8 !important; }
body .cm-variable,
body .cm-variable-2,
body .cm-variable-3 { color: var(--foreground) !important; }
body .cm-property  { color: #0891b2 !important; }
body .cm-bracket   { color: var(--muted-strong-foreground) !important; }
body .cm-tag       { color: var(--primary) !important; font-weight: 600 !important; }
body .cm-attribute { color: #6b21a8 !important; }
body .cm-def       { color: var(--foreground) !important; font-weight: 600 !important; }
body .cm-builtin   { color: #be123c !important; }
body .cm-meta      { color: var(--muted-foreground) !important; }
body .cm-qualifier { color: var(--success, var(--pp-tone-success-bg)) !important; }
body .cm-atom      { color: var(--warning, #b45309) !important; }
body .cm-error     { color: var(--pp-white) !important; background: var(--destructive) !important; }

/* 컨테이너별 size/padding 만 (색은 글로벌 룰이 담당) */
.alarm-config-eql .CodeMirror,
.query-eql-panel .CodeMirror {
    font-size: 12px !important;
    height: auto !important;
    min-height: 60px;
    padding: 0 !important;
    width: 100% !important;
}
/* statement/view·alarm EQL 뷰어 — CodeMirror 박스 높이 ~200px (한 줄로 보이지 않게) */
.alarm-config-eql .CodeMirror { min-height: 200px !important; }
.alarm-config-eql .CodeMirror-scroll { min-height: 200px; padding: 8px 12px !important; }

.map-info-loading {
    color: var(--muted-foreground, var(--pp-text-soft)) !important;
    font-size: 12px !important;
    line-height: 30px !important;
    text-align: center !important;
    padding: 6px !important;
}

/* ─── 헬스 타임라인 ─────────────────────────── */
.map-info-body--timeline { position: relative; padding: 2px 0 0 !important; }
.map-info-timeline { margin: 0 !important; }
.map-info-timeline-stamp {
    position: absolute;
    z-index: 1;
    left: 0;
    top: 4px;
    border-radius: 3px !important;
    background: var(--muted-foreground, var(--pp-muted-fg)) !important;
    color: var(--pp-white) !important;
    font-size: 10px !important;
    padding: 1px 8px !important;
    letter-spacing: 0.01em !important;
}
.map-info-timeline-stamp * { color: var(--pp-white) !important; }

/* ─── 시스템 성능 ───────────────────────────── */
.map-info-perf-table { margin: 0 !important; }
.map-info-perf-chart { height: 80px; }

/* ─── 클러스터 상태 ─────────────────────────── */
.map-info-cluster-table {
    width: 100%;
    font-size: 10.5px !important;
    border-collapse: collapse;
}
.map-info-cluster-table thead td {
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    font-weight: 600 !important;
    border-bottom: 1px solid var(--pp-border) !important;
    padding: 4px 4px !important;
    letter-spacing: 0.02em !important;
}
.map-info-cluster-table tbody td {
    color: var(--foreground, #0f172a) !important;
    padding: 4px 4px !important;
    border-bottom: 1px solid rgba(228, 228, 231, 0.5) !important;
}
.map-info-cluster-foot {
    border-top: 1px solid var(--pp-border) !important;
    margin-top: 4px !important;
    padding-top: 3px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    font-size: 10px !important;
    text-align: right !important;
}


/* ============================================================
 * 공통 운영 화면 정보 흐름 — summary -> filter -> main -> drawer
 * ============================================================ */
.pp-ops-summary-strip {
    display: grid;
    grid-template-columns: repeat(4, minmax(140px, 1fr));
    gap: 8px;
    margin: 0 0 12px !important;
}

.pp-ops-summary-card {
    min-height: 74px;
    padding: 10px 12px !important;
    text-align: left;
    background: var(--pp-white, #fff) !important;
    border: 1px solid var(--pp-border) !important;
    border-left-width: 4px !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04) !important;
}

.pp-ops-summary-card > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 11px !important;
    font-weight: 600 !important;
}

.pp-ops-summary-card > span > i {
    color: inherit !important;
}

.pp-ops-summary-card > strong {
    display: block;
    overflow: hidden;
    margin-top: 6px;
    color: var(--foreground, #0f172a) !important;
    font-size: 21px !important;
    line-height: 1.12 !important;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pp-ops-summary-card-total { border-left-color: var(--muted-foreground, var(--pp-muted-fg)) !important; }
.pp-ops-summary-card-info { border-left-color: var(--primary, var(--pp-primary)) !important; }
.pp-ops-summary-card-warning { border-left-color: var(--warning, #b45309) !important; }
.pp-ops-summary-card-critical { border-left-color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
.pp-ops-summary-card-total > strong { color: var(--muted-foreground, var(--pp-muted-fg)) !important; }
.pp-ops-summary-card-info > strong { color: var(--primary, var(--pp-primary)) !important; }
.pp-ops-summary-card-warning > strong { color: var(--warning, #b45309) !important; }
.pp-ops-summary-card-critical > strong { color: var(--destructive, var(--pp-tone-danger-bg)) !important; }

.pp-ops-summary-card > small {
    display: block;
    overflow: hidden;
    margin-top: 3px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    line-height: 1.25 !important;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pp-ops-filter-panel .card-body {
    padding-top: 14px !important;
    padding-bottom: 14px !important;
}

.pp-ops-filter-grid {
    display: flex !important;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
    margin: 0 !important;
}

.pp-ops-filter-field {
    display: inline-flex;
    flex-direction: column;
    gap: 6px;
    min-width: 220px;
}

.pp-ops-filter-field > .form-label {
    margin: 0 !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}

.pp-ops-filter-field > .form-label > i {
    color: var(--primary, var(--pp-primary)) !important;
}

.pp-ops-filter-actions {
    display: inline-flex;
    align-items: flex-end;
    gap: 8px;
    margin-left: auto !important;
}

.pp-ops-main-panel,
.pp-ops-detail-drawer {
    min-width: 0;
}

.pp-ops-detail-drawer > .card:first-child {
    margin-top: 0 !important;
}

@media (max-width: 767px) {
    .pp-ops-summary-strip {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .pp-ops-filter-grid {
        align-items: stretch;
        flex-direction: column;
    }

    .pp-ops-filter-field {
        width: 100%;
    }

    .pp-ops-filter-field .form-control {
        width: 100% !important;
    }

    .pp-ops-filter-actions {
        justify-content: stretch;
        margin-left: 0 !important;
        width: 100%;
    }

    .pp-ops-filter-actions .btn {
        width: 100%;
    }
}

/* ============================================================
 * /edge/index — reliability summary
 * ============================================================ */
.edge-reliability-summary {
    display: grid;
    grid-template-columns: repeat(4, minmax(120px, 1fr));
    gap: 8px;
    margin: 0 0 12px !important;
}
.edge-reliability-panel .edge-reliability-summary {
    margin: 0 !important;
}
.edge-reliability-card {
    min-height: 78px;
    padding: 10px 12px !important;
    text-align: left;
    background: var(--pp-white, #fff) !important;
    border: 1px solid var(--pp-border) !important;
    border-left-width: 4px !important;
    border-radius: 4px !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04) !important;
}
.edge-reliability-card-total { border-left-color: var(--muted-foreground, var(--pp-muted-fg)) !important; }
.edge-reliability-card-healthy { border-left-color: var(--success, var(--pp-tone-success-bg)) !important; }
.edge-reliability-card-warning { border-left-color: var(--warning, #b45309) !important; }
.edge-reliability-card-critical { border-left-color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
.edge-reliability-card-total strong { color: var(--muted-foreground, var(--pp-muted-fg)) !important; }
.edge-reliability-card-healthy strong { color: var(--success, var(--pp-tone-success-bg)) !important; }
.edge-reliability-card-warning strong { color: var(--warning, #b45309) !important; }
.edge-reliability-card-critical strong { color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
.edge-reliability-card strong {
    display: block;
    margin-top: 4px;
    font-size: 22px !important;
    line-height: 1.1 !important;
}
.edge-reliability-label {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 11px !important;
    font-weight: 600 !important;
}
.edge-reliability-desc {
    display: block;
    margin-top: 3px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    line-height: 1.25 !important;
}
.edge-operational-strip {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(220px, 280px);
    gap: 10px;
    align-items: stretch;
    margin-top: 10px !important;
    padding-top: 10px !important;
    border-top: 1px solid var(--pp-border) !important;
}
.edge-operational-metrics {
    display: grid;
    grid-template-columns: repeat(6, minmax(82px, 1fr));
    gap: 6px;
}
.edge-operational-item {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 42px;
    padding: 6px 8px !important;
    background: #f8fafc !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 4px !important;
}
.edge-operational-item span {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    line-height: 1.2 !important;
}
.edge-operational-item strong {
    margin-top: 3px;
    color: var(--foreground, #0f172a) !important;
    font-size: 14px !important;
    line-height: 1.15 !important;
}
.edge-operational-item-critical strong { color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
.edge-operational-item-warning strong { color: var(--warning, #b45309) !important; }
.edge-worst-edge-cta {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 42px;
    padding: 7px 10px !important;
    text-align: left;
    background: #fff !important;
    border: 1px solid var(--pp-border) !important;
    border-left: 4px solid var(--muted-foreground, var(--pp-muted-fg)) !important;
    border-radius: 4px !important;
}
.edge-worst-edge-cta:not(:disabled) {
    cursor: pointer;
}
.edge-worst-edge-cta:disabled {
    opacity: 0.72;
    cursor: default;
}
.edge-worst-edge-critical { border-left-color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
.edge-worst-edge-warning { border-left-color: var(--warning, #b45309) !important; }
.edge-worst-edge-label {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1.2 !important;
}
.edge-worst-edge-cta strong {
    margin-top: 3px;
    color: var(--foreground, #0f172a) !important;
    font-size: 13px !important;
    line-height: 1.2 !important;
}
.edge-worst-edge-detail {
    margin-top: 2px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    line-height: 1.25 !important;
}
.edge-reliability-action { color: var(--primary, var(--pp-info)) !important; }
.edge-rel-finding {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 8px !important;
    border-bottom: 1px solid rgba(228, 228, 231, 0.65) !important;
}
.edge-rel-finding:last-child { border-bottom: 0 !important; }
.edge-rel-finding strong { white-space: nowrap; }
.edge-rel-finding-healthy strong { color: var(--success, var(--pp-tone-success-bg)) !important; }
.edge-rel-finding-warning strong { color: var(--warning, #b45309) !important; }
.edge-rel-finding-critical strong { color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
@media (max-width: 767px) {
    .edge-reliability-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .edge-operational-strip { grid-template-columns: 1fr; }
    .edge-operational-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* ============================================================
 * /flow/index — execution summary
 * ============================================================ */
.flow-summary-panel .flow-summary-strip {
    margin: 0 !important;
}
.flow-operational-strip {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(220px, 280px);
    gap: 10px;
    align-items: stretch;
    margin-top: 10px !important;
    padding-top: 10px !important;
    border-top: 1px solid var(--pp-border) !important;
}
.flow-operational-metrics {
    display: grid;
    grid-template-columns: repeat(6, minmax(82px, 1fr));
    gap: 6px;
}
.flow-operational-item {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 42px;
    padding: 6px 8px !important;
    background: #f8fafc !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 4px !important;
}
.flow-operational-item span {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    line-height: 1.2 !important;
}
.flow-operational-item strong {
    margin-top: 3px;
    color: var(--foreground, #0f172a) !important;
    font-size: 14px !important;
    line-height: 1.15 !important;
}
.flow-operational-item-critical strong { color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
.flow-operational-item-warning strong { color: var(--warning, #b45309) !important; }
.flow-worst-flow-cta {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 42px;
    padding: 7px 10px !important;
    text-align: left;
    background: #fff !important;
    border: 1px solid var(--pp-border) !important;
    border-left: 4px solid var(--muted-foreground, var(--pp-muted-fg)) !important;
    border-radius: 4px !important;
}
.flow-worst-flow-cta:not(:disabled) {
    cursor: pointer;
}
.flow-worst-flow-cta:disabled {
    opacity: 0.72;
    cursor: default;
}
.flow-worst-flow-critical { border-left-color: var(--destructive, var(--pp-tone-danger-bg)) !important; }
.flow-worst-flow-warning { border-left-color: var(--warning, #b45309) !important; }
.flow-worst-flow-label {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1.2 !important;
}
.flow-worst-flow-cta strong {
    overflow: hidden;
    margin-top: 3px;
    color: var(--foreground, #0f172a) !important;
    font-size: 13px !important;
    line-height: 1.2 !important;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.flow-worst-flow-detail {
    margin-top: 2px;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10px !important;
    line-height: 1.25 !important;
}
@media (max-width: 767px) {
    .flow-operational-strip { grid-template-columns: 1fr; }
    .flow-operational-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* ============================================================
 * /statistics/index — 통계 페이지 (stat-card, opc-status-badge)
 * ============================================================ */
.stat-card {
    background: var(--pp-white) !important;
    border: 0px !important;
    border-left: 3px solid var(--pp-border) !important;
    border-radius: 3px !important;
    padding: 12px 14px !important;
    margin-bottom: 10px !important;
}
.stat-card .stat-value {
    font-size: 22px !important;
    font-weight: 700 !important;
    line-height: 1.3 !important;
}
.stat-card .stat-label {
    font-size: 11px !important;
    color: #999 !important;
    margin-top: 2px !important;
    font-weight: 600 !important;
}
.stat-delta { font-size: 11px !important; font-weight: 600 !important; margin-left: 4px !important; }
.stat-delta-up { color: var(--pp-tone-success-bg) !important; }
.stat-delta-down { color: var(--pp-tone-danger-bg) !important; }
.stat-delta-flat { color: #9ca3af !important; }
.stat-card-green .stat-value  { color: #555 !important; }
.stat-card-blue .stat-value   { color: #555 !important; }
.stat-card-orange .stat-value { color: #555 !important; }
.stat-card-red .stat-value    { color: #555 !important; }
.stat-card-purple .stat-value { color: #555 !important; }
.stat-card-cyan .stat-value   { color: #555 !important; }

.opc-status-badge {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50% !important;
    margin-right: 5px !important;
}
.opc-status-ok { background-color: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.opc-status-warn { background-color: var(--pp-tone-warn-bg) !important; }
.opc-status-error { background-color: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
.opc-status-unknown { background-color: #9ca3af !important; }

#heatmap_chart { width: 100%; height: 170px; }
#alarm_chart, #health_chart { width: 100%; height: 240px; }
#opc_status_chart, #opc_latency_chart { width: 100%; height: 240px; }
#trend_trigger_chart, #trend_job_chart, #trend_log_chart, #trend_blob_chart,
#trend_diag_chart, #trend_pipeline_ex_chart,
#pipeline_ex_type_chart, #pipeline_ex_code_chart { width: 100%; height: 240px; }
#trend_opc_conn_chart, #trend_opc_latency_chart { width: 100%; height: 240px; }
#trend_point_fail_chart { width: 100%; height: 240px; }
#site_data_chart, #site_alarm_chart { width: 100%; height: 240px; }
#asset_health_chart, #asset_connection_chart { width: 100%; height: 240px; }
#report_point_chart, #report_datatype_chart, #report_datatype_pie_chart,
#report_alarm_chart, #report_latency_chart { width: 100%; height: 240px; }
#report_opc_point_chart, #report_opc_latency_chart { width: 100%; height: 240px; }
#report_asset_top_chart, #report_asset_top_alarm_chart { width: 100%; height: 240px; }
#report_asset_health_chart, #report_asset_conn_chart { width: 100%; height: 240px; }
#report_area_point_chart, #report_area_status_chart { width: 100%; height: 240px; }
#report_line_point_chart, #report_line_status_chart { width: 100%; height: 240px; }
#report_tag_point_chart, #report_tag_alarm_chart { width: 100%; height: 240px; }
#hist_opc_latency_chart, #hist_opc_count_chart { width: 100%; height: 240px; }

.selected-date-label {
    display: inline-block;
    color: #888 !important;
    font-size: 16px !important;
    font-weight: bold !important;
}

.section-divider {
    border-radius: 40px !important;
    color: #888 !important;
    font-weight: bold !important;
    text-align: left !important;
    padding: 5px !important;
    padding-left: 0px !important;
    margin-top: 0px !important;
    margin-bottom: 0px !important;
    font-size: 16px !important;
}
.section-divider i { margin-right: 6px !important; }


/* ============================================================
 * /connect/view/{id} — 연결 통계 패널 시맨틱 스타일
 * ============================================================ */
.conn-stats-block {
    padding: 4px 0 12px 0 !important;
}

.conn-latency-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin-top: 10px !important;
}

/* 카드형 — 최저/평균/최고 */
.conn-latency-cell {
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    padding: 10px 8px !important;
    text-align: center !important;
    font-size: 18px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
    line-height: 1.2 !important;
    display: flex;
    flex-direction: column;
    gap: 6px;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.conn-latency-cell:hover {
    border-color: var(--primary, var(--pp-primary)) !important;
    box-shadow: 0 2px 6px rgba(15, 23, 42, 0.06) !important;
}

.conn-latency-cell .text-meta-sm {
    display: block;
    font-size: 10px !important;
    font-weight: 600 !important;
    letter-spacing: 0.4px !important;
    text-transform: uppercase !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin: 0 !important;
}

.conn-latency-cell .text-cap-12 {
    font-size: 10px !important;
    font-weight: 500 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-left: 2px !important;
}

/* 의미별 강조 — 첫(최저)/마지막(최고) 색상 differentiation */
.conn-latency-cell:first-child {
    color: oklch(0.45 0.16 145) !important;
}
.conn-latency-cell:last-child {
    color: oklch(0.55 0.20 25) !important;
}

.conn-latency-chart {
    width: 100%;
    height: 60px;
    margin-top: 4px !important;
}

/* 5개 상태 카운트 셀 */
.conn-status-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 4px;
    flex: 1;
}

.conn-status-cell {
    font-size: 13px !important;
    color: var(--pp-white) !important;
    font-weight: 700 !important;
    line-height: 24px !important;
    text-align: center !important;
    border-radius: 3px !important;
    padding: 0 6px !important;
}

.conn-status-ok    { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.conn-status-warn  { background: var(--pp-tone-warn-bg) !important; }
.conn-status-err   { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
.conn-status-disc  { background: #7f1d1d !important; }
.conn-status-mute  { background: var(--pp-muted-fg) !important; }

.conn-priority-chart {
    height: 150px;
    text-align: center !important;
    color: #ddd !important;
}

/* ── connect/view 연결된 태그 목록(#currTagList) — 카드 폭에 정확히 피팅 ──
 * 전역 pp-20-panels.css 가 table-layout:auto·width:100% 를 !important 로 강제하지만,
 * auto 레이아웃에서는 nowrap 셀 내용이 컨테이너보다 넓어지면 width:100% 가 무시되어
 * 테이블이 카드를 넘쳐 .table-responsive 가 가로 스크롤로 잘려 보였다.
 * 이 화면 한정으로 table-layout:fixed 를 강제해 컬럼이 카드 폭(100%) 안에서
 * 비율(JSP th width %)대로 분배되도록 하고, 넘치는 셀 내용은 ellipsis 로 처리한다. */
#currTagList.dataTable {
    table-layout: fixed !important;
    width: 100% !important;
}
#currTagList.dataTable > thead > tr > th,
#currTagList.dataTable > tbody > tr > td {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}


/* ============================================================
 * /edge/view/{id} — 엣지 상세 페이지 (gauge-grid, stat-box, dot, opc-summary)
 * ============================================================ */
/* =========================================================================
 * edge/view.css — 엣지 상세 화면 전용 스타일.
 * connect/view.css 와 동일 톤 (form-label / screen-title) + 본 화면 전용 위젯.
 * ========================================================================= */

/* (제거) 과거 connect/view 모방 가로폼 라벨 규칙 `body.pp-page-edge-view label.form-label`
 * — edge/view 페이지엔 이 스타일을 쓰는 페이지 폼이 없고, body 에 붙는 BootstrapDialog(신규 배포
 *   다이얼로그) 라벨에만 우측정렬+border-right 로 잘못 누수돼 표준을 깨뜨렸다. 정당 용도 0 → 삭제.
 *   다이얼로그 라벨은 공용 `.bootstrap-dialog label.form-label{text-align:left}` 표준으로 복귀. */

/* 검은 섹션 타이틀 — connect/view 와 동일 ──────────────────────────────── */
.screen-title {
    padding-left: 20px !important;
    padding-top: 5px !important;
    padding-bottom: 5px !important;
    margin-bottom: 0 !important;
    background: #222 !important;
    color: #ddd !important;
    font-size: 14px !important;
}

/* ── 시스템 자원 진행바 ────────────────────────────────────────────── */
.edge-bar-fill.warn { background:#f0ad4e !important; }
.edge-bar-fill.err  { background:#d9534f !important; }

/* ── 상태 알약/배지 ───────────────────────────────────────────────── */

/* ── 우측 패널 panel-heading 톤 통일 ───────────────────────────────── */
.col-lg-9 .card > .card-header {
    background: #fafbfc !important; border-bottom:1px solid var(--pp-border) !important;
    font-weight:600 !important; color:#374151 !important;
}
.col-lg-9 .card > .card-header .btn-group .btn-sm {
    margin-top:-2px !important;
}

/* ── stat 카드 격자 — 시스템 자원 + PLC 통계 ───────────────────────── */
.stat-grid     { display:grid; grid-template-columns:repeat(4, 1fr); gap:10px; }
.stat-box      {
    padding:12px 14px !important; border:1px solid var(--pp-border) !important; border-radius:6px !important;
    background:var(--pp-white) !important; min-height:74px;
}
.stat-box .stat-lbl { font-size:11px !important; color:var(--pp-muted-fg) !important; margin-bottom:4px !important; }
.stat-box .stat-num { font-size:22px !important; font-weight:600 !important; color:#111827 !important; line-height:1.1 !important; }
.stat-box .stat-num .unit { font-size:12px !important; color:#9ca3af !important; margin-left:2px !important; }
.stat-box.ok    .stat-num { color:#198754 !important; }
.stat-box.err   .stat-num { color:#bf2b30 !important; }
.stat-box.warn  .stat-num { color:#bf8700 !important; }

/* legacy fallback (격자 밖에서도 사용) */
.stat-num   { font-size:22px !important; font-weight:bold !important; color:#555 !important; line-height:1.1 !important; }
.stat-lbl   { font-size:11px !important; color:#888 !important; }

/* 패널 내 공통 표 헤더 룰은 pp-05-cards.css 의 body .card .table > thead > tr > th 가 담당 (이 룰 제거) */

/* ── OPC 상태 dot ─────────────────────────────────────────────────── */
.dot        { display:inline-block; width:10px; height:10px; border-radius:50% !important; vertical-align:middle; }
.dot-ok     { background:#5cb85c !important; box-shadow:0 0 0 2px rgba(92,184,92,0.18) !important; }
.dot-err    { background:#d9534f !important; box-shadow:0 0 0 2px rgba(217,83,79,0.18) !important; }
.dot-mute   { background:#a8a8a8 !important; box-shadow:0 0 0 2px rgba(168,168,168,0.18) !important; }
.dot-warn   { background:#f0ad4e !important; box-shadow:0 0 0 2px rgba(240,173,78,0.18) !important; }

/* ── OPC 카운터 요약 ──────────────────────────────────────────────── */
.opc-summary    { display:flex; gap:14px; flex-wrap:wrap; font-size:11px !important; color:#888 !important; margin-left:20px; }
.opc-summary b  { font-size:14px !important; color:#555 !important; margin-right:3px !important; }

/* gauge-grid (시스템 자원 게이지 3개 — 미정의분 보강) */
.gauge-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.gauge-cell { background: var(--pp-white) !important; border: 1px solid var(--pp-border) !important; border-radius: 6px !important; padding: 8px 12px 4px !important; text-align: center !important; }
.gauge-lbl  { font-size: 11px !important; color: var(--pp-muted-fg) !important; margin-bottom: 2px !important; font-weight: 600 !important; }

/* state-row (엣지 상태 표시) */
.state-row { padding: 8px 12px !important; border-radius: 6px !important; font-size: 13px !important; font-weight: 600 !important; margin-bottom: 12px !important; display: flex; align-items: center; gap: 8px; }
.state-row.state-row-init { background: var(--muted-strong-foreground) !important; color: var(--pp-white) !important; }
.state-row.state-ok   { background: var(--pp-tone-success-bg) !important; color: var(--pp-white) !important; }
.state-row.state-warn { background: #b45309 !important; color: var(--pp-white) !important; }
.state-row.state-down { background: #991b1b !important; color: var(--pp-white) !important; }
.state-row > i { font-size: 16px !important; }

/* row-mono / row-chip — 테이블 셀 보조 */
.row-mono { font-family: 'Consolas', 'Menlo', monospace !important; font-size: 11px !important; color: #374151 !important; }
.row-chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px !important; border-radius: 10px !important; font-size: 11px !important; font-weight: 600 !important; color: var(--pp-white) !important; box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important; }
.row-chip.ok  { background: var(--pp-tone-success-bg) !important; color: var(--pp-white) !important; }
.row-chip.err { background: #991b1b !important; color: var(--pp-white) !important; }

/* opc-summary 칩 색상 (4종) — 진한 단색 + 흰 텍스트 */
.opc-chip.total { background: #3730a3 !important; color: var(--pp-white) !important; }
.opc-chip.ok    { background: var(--pp-tone-success-bg) !important; color: var(--pp-white) !important; }
.opc-chip.col   { background: var(--pp-primary) !important; color: var(--pp-white) !important; }
.opc-chip.stop  { background: var(--muted-strong-foreground) !important; color: var(--pp-white) !important; }
.opc-chip.err   { background: #991b1b !important; color: var(--pp-white) !important; }
.opc-chip > b   { font-size: 13px !important; font-weight: 700 !important; color: inherit !important; }


/* /edge/view 타입 뱃지 — 다크 배경 + 흰 텍스트 (식별성 강화). pp-badge 기반(.badge 의존 제거) */
body .badge-edge-type {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 3px 10px !important;
    background: oklch(0.21 0.006 286) !important;
    color: var(--pp-white) !important;
    border-radius: 4px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.4px !important;
    text-transform: uppercase !important;
    line-height: 1.2 !important;
    min-width: 56px;
}


/* /edge/index 버전 뱃지 — 다크 톤 (badge-edge-type 과 통일) — signal 토큰 */
body .badge.badge-edge-version,
body .badge-edge-version {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 3px 10px !important;
    background: var(--foreground) !important;
    color: var(--pp-white) !important;
    border-radius: 4px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.4px !important;
    line-height: 1.2 !important;
    min-width: 56px;
    font-family: 'Consolas', 'Menlo', monospace !important;
}

/* /edge/index 엣지 상태 뱃지 — 디자인 시스템 (shadow 포함) */
body .state-badge-ok,
body .state-badge-warn,
body .state-badge-error,
body .state-badge-wait {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px 10px !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    line-height: 1.1 !important;
    min-width: 36px;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    transition: transform 0.12s, box-shadow 0.12s;
}

/* state-badge 색상(tone bg + on-solid)은 pp-12-status-tones.css 가 정본 — 여기 중복 색상 룰 제거. 레이아웃/hover 만 유지 */

body .state-badge-ok:hover,
body .state-badge-warn:hover,
body .state-badge-error:hover,
body .state-badge-wait:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.14), 0 2px 4px rgba(0, 0, 0, 0.08) !important;
}


/* ============================================================
 * BootstrapDialog 안 다이얼로그 메시지 스타일 (디자인 시스템)
 * ============================================================ */

/* 위험 강조 텍스트 (붉은) */
.dlg-warn-text {
    color: var(--pp-tone-danger-bg) !important;
    font-weight: 500 !important;
}

/* 주의 강조 텍스트 (앰버) */
.dlg-amber-text {
    color: var(--pp-tone-warn-bg) !important;
    font-weight: 500 !important;
}

/* 다이얼로그 안 로그 출력용 dark code block */
.dlg-log-pre {
    max-height: 480px;
    overflow: auto;
    font-size: 11px !important;
    background: oklch(0.16 0.01 286) !important;
    color: oklch(0.85 0.012 286) !important;
    padding: 12px !important;
    border-radius: 6px !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    white-space: pre !important;
    margin: 0 !important;
}

body .bootstrap-dialog .form-group > label.form-label {
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-bottom: 4px !important;
    display: block;
}

body .bootstrap-dialog .form-group > input.form-control {
    width: 100%;
}

/* 다이얼로그 헤더 아이콘 — 타이틀 텍스트와 동일 색 (강조 색상 제거) */
body .bootstrap-dialog .modal-title > i,
body .bootstrap-dialog .modal-header h4.modal-title > i {
    color: inherit !important;
    margin-right: 6px !important;
}


/* ============================================================
 * BootstrapDialog plugin 헤더 — title + close 정렬 (modal-header 안의 wrapper)
 * 구조: .modal-header > .bootstrap-dialog-header > [.bootstrap-dialog-title, .bootstrap-dialog-close-button]
 * ============================================================ */
body .bootstrap-dialog .modal-header {
    padding: 14px 18px !important;
}

body .bootstrap-dialog .bootstrap-dialog-header {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 12px;
    width: 100%;
}

body .bootstrap-dialog .bootstrap-dialog-title {
    display: inline-flex !important;
    align-items: center !important;
    gap: 8px;
    flex: 1 1 auto;
    min-width: 0;
    font-size: 18px !important;
    font-weight: 700 !important;
    color: var(--foreground) !important;
    line-height: 1.4 !important;
    margin: 0 !important;
}

body .bootstrap-dialog .bootstrap-dialog-title > i {
    font-size: 18px !important;
    line-height: 1 !important;
    color: inherit !important;
}

body .bootstrap-dialog .bootstrap-dialog-close-button {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    flex: 0 0 32px;
    margin: 0 !important;
}

/* close 버튼 — 32x32 정사각, FA 아이콘으로 표시 */
body .bootstrap-dialog .bootstrap-dialog-close-button .btn-close {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 32px !important;
    height: 32px !important;
    padding: 0 !important;
    margin: 0 !important;
    background: transparent !important;
    border: 0 !important;
    border-radius: 6px !important;
    color: var(--muted-foreground) !important;
    opacity: 1 !important;
    cursor: pointer;
    line-height: 1 !important;
    font-size: 0 !important;             /* 기존 × 텍스트 숨김 */
    text-shadow: none !important;
    transition: background 0.15s, color 0.15s;
}

/* 닫기 X 아이콘은 pp-dialog.js 가 직접 <i class="fa-light fa-times"> 로 emit 한다.
   ::before 로 또 주입하면 X 가 2개가 되므로 제거. (아이콘 없는 레거시 close 는
   pp-09b 의 :not(:has(> i...))::before 가드 규칙이 fallback 처리한다.) */

body .bootstrap-dialog .bootstrap-dialog-close-button .btn-close:hover {
    background: var(--muted, #f3f4f6) !important;
    color: var(--foreground) !important;
}


/* ============================================================
 * /asset/tree/index — 에셋 정보 패널
 * 설비 이미지 위 상태 카드 (연결/건강) + 이미지 업로더
 * ============================================================ */

/* 상태 카드 row — 이미지 위에 배치 (오버랩 없음) */
.asset-info-status-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-bottom: 10px !important;
}

/* 온다크 컴팩트 뱃지 — 솔리드 컬러, 가로 1줄 (아이콘 + 라벨 + 값), 높이 ~30px */
.asset-info-status-card {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: center !important;
    justify-content: flex-start !important;
    gap: 8px;
    height: 30px;
    min-height: 30px;
    padding: 0 12px !important;
    background: oklch(0.40 0.02 286) !important;
    color: var(--pp-white) !important;
    border: 1px solid rgba(255, 255, 255, 0.10) !important;
    border-radius: 6px !important;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.14), inset 0 0 0 1px rgba(255, 255, 255, 0.06) !important;
    transition: filter 0.15s, box-shadow 0.15s;
    position: relative;
    overflow: hidden;
    text-align: left !important;
    white-space: nowrap !important;
}

.asset-info-status-card:hover {
    filter: brightness(1.05);
    box-shadow: 0 2px 6px rgba(15, 23, 42, 0.18), inset 0 0 0 1px rgba(255, 255, 255, 0.10) !important;
}

.asset-info-status-card-icon {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: auto;
    height: auto;
    background: transparent !important;
    border: 0 !important;
    border-radius: 0 !important;
    color: var(--pp-white) !important;
    font-size: 14px !important;
    line-height: 1 !important;
    flex: 0 0 auto !important;
    box-shadow: none !important;
    margin: 0 !important;
}

.asset-info-status-card-meta {
    display: inline-flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
    white-space: nowrap !important;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}

.asset-info-status-card-icon > i {
    line-height: 1 !important;
    display: block;
    color: var(--pp-white) !important;
}

.asset-info-status-card-label {
    font-size: 10px !important;
    font-weight: 700 !important;
    color: rgba(255, 255, 255, 0.75) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px !important;
    line-height: 1 !important;
    white-space: nowrap !important;
    flex-shrink: 0;
}

.asset-info-status-card-value {
    white-space: nowrap !important;
    font-size: 12px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    line-height: 1 !important;
    letter-spacing: 0.2px !important;
}

/* 상태별 풀컬러 단색 배경 — 흰 텍스트 가독성 보장 */
.asset-info-status-card.is-ok    { background: var(--pp-tone-success-bg) !important; color: var(--pp-white) !important; }
.asset-info-status-card.is-warn  { background: #b45309 !important; color: var(--pp-white) !important; }
.asset-info-status-card.is-error { background: #991b1b !important; color: var(--pp-white) !important; }
.asset-info-status-card.is-disc  { background: #7f1d1d !important; color: var(--pp-white) !important; }
.asset-info-status-card.is-mute  { background: oklch(0.40 0 0) !important; color: var(--pp-white) !important; }

/* alarm 활성 상태 — 우상단 미니 펄스 도트 (흰색) */
.asset-info-status-card.is-warn::before,
.asset-info-status-card.is-error::before {
    content: "";
    position: absolute;
    top: 10px;
    right: 10px;
    width: 8px;
    height: 8px;
    border-radius: 50% !important;
    background: var(--pp-white) !important;
    box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.6) !important;
    z-index: 2;
    animation: asset-status-pulse 1.8s ease-in-out infinite;
}

@keyframes asset-status-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.55); transform: scale(1); }
    50%      { box-shadow: 0 0 0 8px rgba(255, 255, 255, 0);  transform: scale(1.15); }
}

/* 이미지 업로더 — 버튼 + 도움말을 한 행에 정돈 */

.asset-image-uploader > .form-help-inline {
    margin: 0 !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}


/* ============================================================
 * /asset/tree/index — 스테이트먼트 추가 다이얼로그 EQL 입력
 * 우측 상단에 실행 버튼 (FAB) 배치
 * ============================================================ */
.asset-stmt-eql-row {
    display: block !important;
    width: 100%;
}

.asset-stmt-eql-row > label.form-label {
    display: block;
    margin: 0 0 6px 0 !important;
}

.asset-stmt-eql-wrap {
    position: relative;
    width: 100%;
    min-width: 0;
    max-width: none !important;
}

/* 에셋 스테이트먼트 다이얼로그 — 라벨/입력 상하 레이아웃 */
.asset-stmt-form-stack > .form-group {
    display: block;
    width: 100%;
    /* 간격은 pp-48 정본(12px) — 이전 14px 제거 */
}

.asset-stmt-form-stack > .form-group > label.form-label {
    display: block;
    margin: 0 0 6px 0 !important;
    text-align: left !important;
    width: auto;
    line-height: 1.4 !important;
}

.asset-stmt-form-stack > .form-group > .form-control,
.asset-stmt-form-stack > .form-group > select.form-control {
    width: 100%;
    max-width: 100%;
}

.asset-stmt-eql-wrap > textarea.form-control,
.asset-stmt-eql-wrap > .CodeMirror {
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box;
}

.asset-stmt-eql-wrap > textarea.form-control {
    width: 100% !important;
    font-family: 'Consolas', 'Menlo', monospace !important;
    font-size: 12px !important;
}

.asset-stmt-eql-run {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 36px;
    height: 36px;
    border-radius: 50% !important;
    border: 0 !important;
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    font-size: 18px !important;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.20) !important;
    transition: transform 0.12s, box-shadow 0.12s, background 0.12s;
    z-index: 2;
}

.asset-stmt-eql-run:hover {
    background: oklch(0.32 0.10 260) !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25) !important;
}

.asset-stmt-eql-run > i {
    line-height: 1 !important;
}

/* === pp-42-asset-toolbar.css === */
/* ============================================================================
 * pp-09b-asset-toolbar.css
 * SCOPE  : ASSET TREE / TOOLBAR
 * 영역   : /asset/tree/index 다이얼로그·EQL·상태도트, 헤더 알람 드롭다운, 글로벌 close 버튼, 상단 우측 툴바·popover
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /asset/tree/index 다이얼로그 — 도큐먼트 / 스테이트먼트 / 플러그인
 * ============================================================ */

/* (asset-doc / asset-stmt 다이얼로그 form-inline 의 110px 좌측 라벨 룰 제거
 *  — pp-05 의 글로벌 다이얼로그 vertical 룰이 적용되도록 양보) */

/* 도큐먼트 추가 — 파일 선택 input + 폴더 버튼 한 row (vertical 폼 안에서 풀폭) */
.asset-doc-file-picker {
    position: relative;
    display: flex !important;
    align-items: stretch;
    gap: 6px;
    width: 100% !important;
    min-width: 0;
}

.asset-doc-file-picker > input.form-control {
    flex: 1 1 auto;
    width: auto !important;
    cursor: pointer;
}

.asset-doc-file-picker > .btn {
    flex: 0 0 auto;
}

/* PP.dialog.confirm 메시지 — 가운데 + 패딩 */
.dialog-message-cover {
    text-align: center !important;
    padding: 8px 4px !important;
    font-size: 14px !important;
    color: var(--foreground, #111827) !important;
    line-height: 1.5 !important;
}

/* 에셋 다이얼로그 — 패널과 동일한 톤 (헤더 그라데이션 X, 흰 바디) */
body .bootstrap-dialog.asset-doc-dialog .modal-dialog {
    width: 600px !important;
    max-width: 92vw !important;
}

body .bootstrap-dialog.asset-stmt-dialog .modal-body,
body .bootstrap-dialog.asset-doc-dialog .modal-body {
    padding: 18px 22px !important;
}

/* 다이얼로그 안 fieldset:last-child margin-bottom 0 (footer 와 자연스럽게) */
body .bootstrap-dialog .modal-body > fieldset:last-child {
    margin-bottom: 0 !important;
}

/* form-content-footer — 다이얼로그 안에서 좌우 정렬 + 적정 패딩 */
body .bootstrap-dialog .modal-body > .form-content-footer {
    margin: 18px -22px -18px !important;
    padding: 14px 22px !important;
    border-top: 1px solid var(--pp-border) !important;
    background: var(--muted, #f8fafc) !important;
}


/* ============================================================
 * 디자인 시스템 카탈로그 데모용 — 상태 도트 배경 색상 modifier
 * eq-status-dot 위에서 사용 (실제 페이지는 JS 로 인라인 background 부여)
 * ============================================================ */
.eq-status-dot.ds-bg-success { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.eq-status-dot.ds-bg-warning { background: var(--pp-tone-warn-bg) !important; }
.eq-status-dot.ds-bg-danger  { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
.eq-status-dot.ds-bg-mute    { background: #9ca3af !important; }


/* WS / 사용자 dropdown-menu 들 — 동일 스타일 적용 */
#nav-toolbar > li.dropdown > .dropdown-menu {
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    box-shadow: 0 12px 28px rgba(15, 23, 42, 0.14), 0 4px 8px rgba(15, 23, 42, 0.06) !important;
    margin-top: 6px !important;
    padding: 6px !important;
    min-width: 220px;
}

#nav-toolbar > li.dropdown > .dropdown-menu > li > a {
    padding: 8px 12px !important;
    border-radius: 6px !important;
    font-size: 12px !important;
    color: var(--foreground, #111827) !important;
    transition: background 0.12s;
    display: flex;
    align-items: center;
    gap: 8px;
}

#nav-toolbar > li.dropdown > .dropdown-menu > li > a:hover,
#nav-toolbar > li.dropdown > .dropdown-menu > li > a:focus {
    background: var(--muted, #f8fafc) !important;
}

#nav-toolbar > li.dropdown > .dropdown-menu > li.divider {
    margin: 4px 0 !important;
    background: var(--pp-border) !important;
}

#nav-toolbar > li.dropdown > .dropdown-menu > li.dropdown-header {
    padding: 6px 12px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px !important;
}


/* ============================================================
 * 글로벌 close 버튼 — 텍스트(×/X/&times;) → FA 아이콘 일괄 변환
 * 모달, 알람 alert, 다이얼로그 어디든 적용
 * <button class="close">×</button> 또는 <span aria-hidden>&times;</span>
 * ============================================================ */

/* 텍스트 노드 자체를 숨기고 ::before 로 FA 아이콘 표시 */
body .modal-header .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands)),
body .alert .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands)),
body .bootstrap-dialog .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands)),
body .modal .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands)) {
    font-size: 0 !important;
    line-height: 0 !important;
}

body .modal-header .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands))::before,
body .alert .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands))::before,
body .bootstrap-dialog .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands))::before,
body .modal .btn-close:not(:has(> i.fa-light, > i.fa-light, > i.fa-light, > i.fa-brands))::before {
    content: "\f00d";
    font-family: "Font Awesome 7 Pro" !important;
    font-weight: 100 !important;
    font-size: 14px !important;
    line-height: 1 !important;
    color: inherit !important;
    display: inline-block;
}

/* 안에 <span aria-hidden="true">&times;</span> 가 있을 때 텍스트 숨기고 ::before 사용 */
body .btn-close > span[aria-hidden="true"]:only-child {
    font-size: 0 !important;
    line-height: 0 !important;
    visibility: hidden;
    width: 0;
    overflow: hidden;
}
body .btn-close:has(> span[aria-hidden="true"]:only-child)::before {
    content: "\f00d";
    font-family: "Font Awesome 7 Pro" !important;
    font-weight: 100 !important;
    font-size: 14px !important;
    line-height: 1 !important;
    color: inherit !important;
    display: inline-block;
    visibility: visible;
}


/* ============================================================
 * 상단 우측 커스텀 툴바 (.pp-top-toolbar)
 * Bootstrap navbar-top-links 대체 — 깔끔한 정렬·간격·hover
 * ============================================================ */
.pp-top-toolbar {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: var(--pp-topbar-h);
    margin: 0 !important;
    padding: 0 !important;
    flex-shrink: 0;
}

.pp-top-toolbar .pp-tb-item {
    position: relative;
    display: inline-flex;
    align-items: center;
}

/* 툴바 버튼 — 둥근 사각, 36×36, 호버 muted */
.pp-top-toolbar .pp-tb-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0 !important;
    background: transparent;
    border: 0 !important;
    border-radius: 8px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
    text-decoration: none !important;
}

.pp-top-toolbar .pp-tb-btn:hover,
.pp-top-toolbar .pp-tb-btn:focus,
.pp-top-toolbar .dropdown.open .pp-tb-btn {
    background: var(--muted, #f3f4f6) !important;
    color: var(--foreground, #111827) !important;
    text-decoration: none !important;
    outline: none !important;
}


.pp-top-toolbar .pp-tb-btn::after { display: none !important; }   /* BS dropdown caret 숨김 */

.pp-top-toolbar .pp-tb-icon {
    font-size: 16px !important;
    line-height: 1 !important;
}

/* 알람 카운트 뱃지 — 버튼 우상단 */
.pp-top-toolbar .pp-tb-badge {
    position: absolute;
    top: 4px;
    right: 4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px !important;
    background: var(--destructive, var(--pp-tone-danger-bg)) !important;
    color: var(--pp-white) !important;
    border: 2px solid var(--pp-white) !important;
    border-radius: 10px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    line-height: 1 !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    transform: translate(40%, -40%);
}

.pp-top-toolbar .pp-tb-badge:empty,
.pp-top-toolbar .pp-tb-badge[data-count="0"] {
    display: none;
}

/* 사용자 아바타 (dropdown 트리거 안 + popover 헤더) */
.pp-top-toolbar .pp-tb-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50% !important;
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
    font-size: 13px !important;
}

.pp-top-toolbar .pp-tb-avatar.pp-tb-avatar-lg {
    width: 36px;
    height: 36px;
    font-size: 15px !important;
}

/* ============================================================
 * 툴바 popover (dropdown-menu 대체)
 * ============================================================ */
.pp-top-toolbar .pp-tb-popover.dropdown-menu {
    position: absolute;
    top: 100% !important;
    right: 0 !important;
    left: auto !important;
    min-width: 380px;
    margin-top: 8px !important;
    padding: 0 !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    box-shadow: 0 12px 28px rgba(15, 23, 42, 0.14), 0 4px 8px rgba(15, 23, 42, 0.06) !important;
    overflow: hidden;
    z-index: 1050;
}

.pp-top-toolbar .pp-tb-popover-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px !important;
    background: var(--muted, #f8fafc) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    color: var(--foreground, #111827) !important;
}

.pp-top-toolbar .pp-tb-popover-header > i {
    color: var(--primary, var(--pp-primary-strong)) !important;
    font-size: 14px !important;
}

.pp-top-toolbar .pp-tb-popover-body {
    padding: 6px !important;
    max-height: 360px;
    overflow-y: auto;
}

.pp-top-toolbar .pp-tb-popover-link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px !important;
    border-radius: 6px !important;
    color: var(--foreground, #111827) !important;
    font-size: 13px !important;
    text-decoration: none !important;
    transition: background 0.12s;
}

.pp-top-toolbar .pp-tb-popover-link > i {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    width: 16px;
    text-align: center !important;
}

.pp-top-toolbar .pp-tb-popover-link:hover,
.pp-top-toolbar .pp-tb-popover-link:focus {
    background: var(--muted, #f8fafc) !important;
    color: var(--foreground, #111827) !important;
    text-decoration: none !important;
}

.pp-top-toolbar .pp-tb-popover-link-danger {
    color: var(--destructive, var(--pp-tone-danger-bg)) !important;
}

.pp-top-toolbar .pp-tb-popover-link-danger > i {
    color: var(--destructive, var(--pp-tone-danger-bg)) !important;
}

.pp-top-toolbar .pp-tb-popover-link-danger:hover {
    background: rgba(220, 38, 38, 0.08) !important;
    color: var(--destructive, var(--pp-tone-danger-bg)) !important;
}

.pp-top-toolbar .pp-tb-popover-divider {
    height: 1px;
    margin: 4px 0 !important;
    background: var(--pp-border) !important;
}

.pp-top-toolbar .pp-tb-popover-footer {
    display: block;
    padding: 12px 16px !important;
    background: var(--pp-white) !important;
    border-top: 1px solid var(--pp-border) !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    text-align: center !important;
    text-decoration: none !important;
    transition: background 0.12s;
}

.pp-top-toolbar .pp-tb-popover-footer:hover {
    background: var(--muted, #f8fafc) !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
}

.pp-top-toolbar .pp-tb-popover-footer > strong {
    margin-right: 6px !important;
}

/* WS / 사용자 popover 의 row (라벨 + 값) */
.pp-top-toolbar .pp-tb-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px !important;
    border-radius: 6px !important;
    font-size: 12px !important;
}

.pp-top-toolbar .pp-tb-row-icon {
    color: var(--subtle-foreground, #9ca3af) !important;
    width: 14px;
    text-align: center !important;
}

.pp-top-toolbar .pp-tb-row-label {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    flex-shrink: 0;
    font-weight: 500 !important;
}

.pp-top-toolbar .pp-tb-row-val {
    color: var(--foreground, #111827) !important;
    font-weight: 600 !important;
    word-break: break-all;
}

.pp-top-toolbar .pp-tb-user-name {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
}

/* 알람 popover 폭 + 본문 */
.pp-top-toolbar .pp-tb-popover-alarm {
    width: 380px;
    min-width: 380px;
}

.pp-top-toolbar .pp-tb-popover-alarm .pp-tb-popover-body {
    padding: 0 !important;
    max-height: 360px;
}

/* 알람 항목 (JS 가 동적 생성하는 <a>) */
.pp-top-toolbar .pp-tb-popover-alarm .pp-tb-popover-body > a {
    display: block;
    padding: 10px 14px !important;
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
    color: var(--foreground, #111827) !important;
    font-size: 12px !important;
    line-height: 1.5 !important;
    text-decoration: none !important;
    transition: background 0.12s;
}

.pp-top-toolbar .pp-tb-popover-alarm .pp-tb-popover-body > a:hover {
    background: var(--muted, #f8fafc) !important;
}

/* 알람 항목 — 헤드(레벨 + 날짜 + ago) / 설명 2-row */
.pp-tb-popover-item-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px !important;
    font-size: 11px !important;
}
.pp-tb-popover-item-date {
    color: var(--secondary-foreground, var(--pp-muted-fg)) !important;
}
.pp-tb-popover-item-ago {
    margin-left: auto !important;
    color: var(--pp-text-soft) !important;
    font-size: 10px !important;
}
.pp-tb-popover-item-desc {
    color: var(--foreground, #1f2937) !important;
    font-size: 12px !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    padding-top: 4px !important;
    border-top: 1px solid var(--pp-border, #f3f4f6) !important;
}
.pp-tb-popover-empty {
    padding: 16px 14px !important;
    text-align: center !important;
    color: #9ca3af !important;
    font-size: 12px !important;
}
.pp-tb-popover-empty.pp-tb-popover-error {
    color: var(--pp-tone-danger-bg) !important;
}


/* ============================================================
 * 상단 툴바 — LIVE 버튼 (WebSocket 연결 상태)
 * 초록 깜빡임 (정상) / 빨강 깜빡임 (끊김)
 * ============================================================ */
.pp-top-toolbar .pp-tb-btn-live {
    width: auto;
    padding: 0 12px !important;
    gap: 7px;
}

.pp-top-toolbar .pp-tb-live-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50% !important;
    background: var(--pp-tone-success-bg) !important;
    box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.6) !important;
    animation: pp-tb-live-pulse-ok 1.6s ease-in-out infinite;
    flex-shrink: 0;
    color: var(--pp-white) !important;
}

.pp-top-toolbar .pp-tb-live-text {
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.6px !important;
    color: var(--pp-tone-success-bg) !important;
    line-height: 1 !important;
}

@keyframes pp-tb-live-pulse-ok {
    0%, 100% { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.55); transform: scale(1); }
    50%      { box-shadow: 0 0 0 6px rgba(22, 163, 74, 0); transform: scale(1.18); }
}

/* JS 가 #ws-signal 에 fa-times / fa-warning 등 부여하면 끊김 처리 */
.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-times) .pp-tb-live-dot,
.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-exclamation-triangle) .pp-tb-live-dot {
    background: var(--pp-tone-danger-bg) !important;
    animation-name: pp-tb-live-pulse-err;
    color: var(--pp-white) !important;
}

.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-times) .pp-tb-live-text,
.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-exclamation-triangle) .pp-tb-live-text {
    color: var(--pp-tone-danger-bg) !important;
}

/* 끊김 상태에서는 LIVE → DOWN 텍스트로 (CSS-only 변환) */
.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-times) .pp-tb-live-text,
.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-exclamation-triangle) .pp-tb-live-text {
    font-size: 0 !important;
}

.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-times) .pp-tb-live-text::before,
.pp-top-toolbar .pp-tb-btn-live:has(#ws-signal.fa-exclamation-triangle) .pp-tb-live-text::before {
    content: "DOWN";
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.6px !important;
}

@keyframes pp-tb-live-pulse-err {
    0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.55); transform: scale(1); }
    50%      { box-shadow: 0 0 0 6px rgba(220, 38, 38, 0); transform: scale(1.25); }
}


/* ============================================================
 * /statistics/index — 통계 페이지 패널 마진/패딩 정렬
 * ============================================================ */

.page-statistics .stat-summary-body > .row + .row {
    margin-top: 12px !important;
}

.page-statistics .stat-summary-body > .row-divider {
    margin: 12px 0 4px 0 !important;
}

/* day_detail_area / tab-content 내부의 row 들도
 * #page-wrapper 직속 row 와 동일하게 좌/우 24px 페이지 거터 적용. */
.page-statistics #day_detail_area > .row,
.page-statistics #day_detail_area .tab-content > .tab-pane > .row {
    padding: 0 !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* tab-pane 내부 nav-tabs row 도 동일 */
.page-statistics #day_detail_area > .tab-content {
    padding: 0 !important;
}


/* ============================================================
 * /canvas/edit — 배치된 위젯 목록 영역
 * ============================================================ */
.canvas-edit-placed-list {
    max-height: 330px;
    overflow-y: auto;
    margin-right: 3px !important;
}

/* 소형 빈상태는 .pp-empty-state--sm 으로 통일됨 (pp-25-cards.css). */


/* ============================================================
 * 데이터 타입 뱃지 (.dt-badge) + 현재값 뱃지 (.value-q-badge)
 * — 라이트테마 표준: 진한 배경 + 흰 텍스트 (온다크)
 *   pp-override-status.css 의 기본 정의를 단일 source 인 이 파일에서 오버라이드
 * ============================================================ */

/* 데이터 타입 뱃지 — 다크 무채색 + 흰 텍스트, 폰트 굵게 */
.dt-badge {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: auto !important;
    min-width: 80px;
    padding: 0 !important;
    border: 0px !important;
    border-radius: 12px !important;
    background: oklch(0.30 0.01 286) !important;
    color: var(--pp-white) !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    line-height: 1.4 !important;
    letter-spacing: 0.2px !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

.dt-badge > i {
    font-size: 10px !important;
    color: oklch(0.85 0.02 286) !important;
}

/* 현재값 뱃지 — 품질별 다크 톤 + 흰 텍스트 */
.value-q-badge {
    display: inline-block !important;
    width: auto !important;
    min-width: 56px;
    padding: 3px 10px !important;
    border-radius: 6px !important;
    color: var(--pp-white) !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    text-align: center !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

.value-q-good {
    background: oklch(0.45 0.16 145) !important;   /* 진한 그린 */
}

.value-q-uncertain {
    background: oklch(0.55 0.18 65) !important;    /* 진한 앰버 */
}

.value-q-bad {
    background: oklch(0.50 0.22 25) !important;    /* 진한 레드 */
}

/* 테이블 셀 안에서도 정렬 안정 */
td .value-q-badge,
td .dt-badge {
    vertical-align: middle;
}


/* ============================================================
 * /connect/index — 카드 자체를 링크로 (.box-part-link)
 * 카드가 <a> 태그가 되었으므로 link 데코·색상 정리
 * ============================================================ */
body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link {
    text-decoration: none !important;
    color: inherit !important;
    display: flex !important;
    flex-direction: column !important;
    cursor: pointer;
}

/* con-link-box 가 카드의 마지막 row 가 되도록 — text 영역이 flex-grow */
body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link .text {
    flex: 1 1 auto;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link:hover,
body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link:focus {
    text-decoration: none !important;
    color: inherit !important;
}

/* con-link-box 가 이제 텍스트만 담음 → 텍스트에 직접 typography */
body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link .con-link-box {
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    transition: color 0.12s, background 0.18s;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link:hover .con-link-box {
    color: var(--primary, var(--pp-primary-strong)) !important;
}

/* chevron — con-link-box 끝에 직접 */
body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link .con-link-box::after {
    content: "\f105";
    font-family: "Font Awesome 7 Pro" !important;
    font-weight: 100 !important;
    font-size: 11px !important;
    margin-left: 4px !important;
    transition: transform 0.18s;
    display: inline-block;
}

body #page-wrapper .card.card > .card-body.connect-protocol-grid a.box-part-link:hover .con-link-box::after {
    transform: translateX(2px);
}


/* ============================================================
 * /connect/index — alert info 본문 (인라인 padding 대체)
 * ============================================================ */
.alert.alert-info > .connect-alert-body {
    padding-left: 25px !important;
    line-height: 1.55 !important;
}


/* /connect/opc/add — OPC 서버 연결 (테스트) 버튼은 card-head-actions 로 이동.
 * 별도 마진 불필요 — card-head-actions 가 정렬 책임. */


/* ── btn-close (구 BS3 .close → BS5 .btn-close 개명) ──
   본 앱의 닫기버튼은 자식 <i class="fa-light fa-times"> 아이콘을 쓴다.
   BS5 .btn-close 는 배경 X 이미지를 그리므로(FA 아이콘과 겹쳐 이중 X) 배경 이미지를 제거한다. */
body .btn-close {
    background-image: none !important;
    -webkit-mask: none !important;
    mask: none !important;
}

/* === pp-43-connect-typeahead.css === */
/* ============================================================================
 * pp-09c-connect-typeahead.css
 * SCOPE  : CONNECT / TYPEAHEAD
 * 영역   : /connect/opc/index 프로토콜 뱃지, /connect/view 통계·타임라인, ds-dl 그룹, /site/form, asset/tree 빈 상태, card-nested, ISO plugin, typeahead, /ontology/index, 태그 검색 패널
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /connect/opc/index — 프로토콜 타입 뱃지 + 명/설명 셀
 * ============================================================ */

/* OPC DA — navy */

/* OPC UA — teal */

/* OPC 명 + 설명 셀 */

.opc-name-cell > a {
    color: var(--foreground, #111827) !important;
}




/* ============================================================
 * /connect/view — 페이지 헤더 날짜 선택 컴포넌트 (input-group)
 * 캘린더 아이콘 addon + 날짜 input + "날짜 이동" 버튼을 하나의
 * 연결된 컨트롤로. 헤더 우측 36px 컨트롤 규격에 맞춤.
 * ============================================================ */
body.page-connect-view .pp-page-header-right .conn-date-group {
    display: flex;
    align-items: stretch;
    width: auto;
    flex: 0 0 auto;
}

/* addon / input / 버튼 — 헤더 표준 36px 높이로 통일 */
body.page-connect-view #page-wrapper .pp-page-header-right .conn-date-group > .input-group-text,
body.page-connect-view #page-wrapper .pp-page-header-right .conn-date-group > .form-control,
body.page-connect-view #page-wrapper .pp-page-header-right .conn-date-group > .btn {
    height: 36px !important;
    font-size: 13px !important;
    box-shadow: none !important;
}

/* 좌측 캘린더 아이콘 addon */
body.page-connect-view #page-wrapper .pp-page-header-right .conn-date-group > .input-group-text {
    background: var(--muted, #f8fafc) !important;
    border: 1px solid var(--pp-border) !important;
    border-right: 0 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    padding: 0 10px !important;
    border-radius: 6px 0 0 6px !important;
}

/* 날짜 input — 가운데 영역, 좌우 보더 0 (addon·버튼과 연결) */
body.page-connect-view #page-wrapper .pp-page-header-right .conn-date-group > .form-control {
    width: 150px !important;
    border-radius: 0 !important;
    border-left: 0 !important;
    border-right: 0 !important;
    padding: 0 10px !important;
}

/* 우측 "날짜 이동" 버튼 — 그룹 끝, 우측만 라운드 */
body.page-connect-view #page-wrapper .pp-page-header-right .conn-date-group > .btn {
    border-radius: 0 6px 6px 0 !important;
    white-space: nowrap;
}


/* ============================================================
 * /connect/view — 통계/타임라인/차트 추가 스타일
 * ============================================================ */
.conn-stats-block + .conn-stats-block {
    margin-top: 14px !important;
    padding-top: 14px !important;
    border-top: 1px dashed var(--pp-border) !important;
}

.conn-stats-label {
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--foreground, #374151) !important;
    margin-bottom: 10px !important;
    padding-bottom: 8px !important;
    border-bottom: 1px solid var(--pp-border) !important;
}

.conn-stats-label > i {
    color: var(--primary, var(--pp-primary)) !important;
    margin-right: 4px !important;
}

/* 연결 상태 타임라인 — 좌(현재상태) + 우(타임라인 트랙) flex */
.conn-timeline-row {
    display: flex;
    gap: 12px;
    align-items: stretch;
}

.conn-timeline-status {
    flex: 0 0 140px;
    color: var(--pp-white) !important;
    border-radius: 8px !important;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center !important;
    padding: 10px 8px !important;
    transition: background 0.18s;
}

/* 아이콘 위 / 라벨 아래 — column flex */
.conn-timeline-icon {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    line-height: 1.1 !important;
}

.conn-timeline-icon > i {
    font-size: 32px !important;
    line-height: 1 !important;
}

.conn-timeline-label {
    font-size: 11px !important;
    font-weight: 600 !important;
    letter-spacing: 0.3px !important;
}

/* 상태별 배경 — JS 가 클래스로 토글 */
.conn-timeline-status.is-ok    { background: oklch(0.45 0.16 145) !important; }
.conn-timeline-status.is-warn  { background: oklch(0.62 0.18 65) !important;  }
.conn-timeline-status.is-err   { background: oklch(0.55 0.22 25) !important;  }
.conn-timeline-status.is-disc  { background: oklch(0.40 0.14 25) !important;  }
.conn-timeline-status.is-mute  { background: oklch(0.55 0 0) !important;      }

.conn-timeline-track {
    flex: 1 1 auto;
    min-width: 0;
}

#opc_connection_timeline {
    padding-bottom: 8px !important;
}

/* 포인트 수신 차트 */
.conn-point-trend-chart {
    height: 160px;
    opacity: 0.95 !important;
}


/* ============================================================
 * 데이터 디스플레이 — 섹션 타이틀 (ds-dl 그룹 헤더)
 * ============================================================ */
/* 데이터 표시 섹션 제목 표준 — .pp-data-title (<pp:dl title> 가 생성).
   레거시 .view-section-title / .view-sub-title 통일. !important 제거(벤더 @layer vendor 하위 → normal 로 충분). */
.pp-data-title,
.view-section-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 700;
    color: var(--foreground);
    border-bottom: 1px solid var(--pp-border);
    padding: 8px 0 6px 0;
    margin-bottom: 6px;
}
/* 우측 메타(등록/수정 시각 등)는 자동 오른쪽 정렬 + 약한 강조 */
.pp-data-title > .float-end,
.pp-data-title > .pp-data-title__meta,
.view-section-title > .float-end { margin-left: auto; font-weight: 400; }
/* danger 톤 섹션 제목(예: 비정상 종료) */
.pp-data-title--danger,
.pp-data-title--danger > i { color: var(--pp-tone-danger-bg); }
.pp-data-title--danger { border-bottom-color: rgba(220, 38, 38, 0.25); }

.view-section-meta {
    margin-left: 4px !important;
    font-size: 11px !important;
    font-weight: 500 !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    letter-spacing: 0 !important;
}
.view-section-title > i {
    color: var(--primary, var(--pp-primary)) !important;
}

/* 두 번째 이상 view-section-title 은 위 간격 추가 */
.ds-dl + .view-section-title {
    margin-top: 14px !important;
}

/* hidden 영역 펼침 후 view-section-title 도 동일 */
#opc_detail .view-section-title {
    margin-top: 14px !important;
}


/* ============================================================
 * /site/form — 지도 입력 박스 (라벨 위 / 지도 아래)
 * ============================================================ */
.form-inline-block {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
}

.form-inline-block > .form-label {
    margin: 0 !important;
}


.site-form-map {
    width: 100%;
    max-width: 800px;
    height: 500px;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    overflow: hidden;
}


/* ============================================================
 * /asset/tree — 이미지 영역 빈 상태 (sc-empty 변형)
 * ============================================================ */
.asset-info-image-empty {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 24px !important;
}

.asset-info-image-empty .pp-empty-state__icon {
    font-size: 56px !important;
    color: oklch(0.85 0.01 286) !important;
    opacity: 0.6 !important;
    margin-bottom: 8px !important;
}

.asset-info-image-empty .pp-empty-state__text {
    font-size: 14px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}

.asset-info-image-empty .pp-empty-state__sub {
    font-size: 11px !important;
    color: var(--muted-foreground, #9ca3af) !important;
    margin-top: 4px !important;
}


/* ============================================================
 * 패널 안에 중첩된 보조 패널 (card-nested)
 * — 에셋 정보 패널 안의 "기본 정보" / "에셋 이미지" 같이
 *   섹션 분리 용도로 사용. 외곽보다 톤 약간 가볍게.
 * ============================================================ */
body #page-wrapper .card.card-nested {
    margin-bottom: 12px !important;
    box-shadow: none !important;
}

body #page-wrapper .card.card-nested:last-child {
    margin-bottom: 0 !important;
}

body #page-wrapper .card.card-nested > .card-header {
    background: var(--muted, #f8fafc) !important;
    padding: 8px 12px !important;
}

body #page-wrapper .card.card-nested > .card-header .card-head-title {
    font-size: 12px !important;
}

body #page-wrapper .card.card-nested > .card-header .card-head-sub {
    font-size: 10px !important;
}

body #page-wrapper .card.card-nested > .card-body {
    padding: 12px !important;
}


/* ============================================================
 * 트리 노드 상태 인디케이터 (.tree-status-icon)
 * — pp-override-status.css 의 opacity:0.5 를 무력화하고,
 *   온다크 (어두운 컬러 배경 + 흰 아이콘) 스타일 강제.
 * ============================================================ */
.tree-status-icon {
    opacity: 0.7;
}
.tree-status-icon .pp-status-dot {
    opacity: 1 !important;
    color: var(--pp-white) !important;
}

.tree-status-icon .pp-status-dot > i {
    color: var(--pp-white) !important;
    line-height: 14px !important;
    font-size: 8px !important;
}


/* ============================================================
 * 에셋 스테이트먼트 추가 모달 (statement_dialog) — 가로 800px
 * BootstrapDialog SIZE_WIDE override
 * ============================================================ */
body .bootstrap-dialog.asset-stmt-dialog .modal-dialog {
    width: 1000px !important;
    max-width: 96vw !important;
}

body .bootstrap-dialog.asset-plugin-stmt-dialog .modal-dialog {
    width: 800px !important;
    max-width: 92vw !important;
}

/* ============================================================
 * ISO 플러그인 카드 그리드 (.plugin-card-grid)
 * — 기존 인라인 스타일을 시맨틱 클래스로 이전
 * ============================================================ */
.plugin-card-grid {
    display: flex;
    gap: 12px;
    justify-content: center;
    margin-bottom: 16px !important;
    flex-wrap: wrap;
}

.plugin-card {
    width: 160px;
    height: 160px;
    cursor: pointer;
    border: 2px solid var(--pp-border) !important;
    border-radius: 10px !important;
    padding: 14px 12px !important;
    text-align: center !important;
    background: var(--pp-white) !important;
    transition: border-color 0.18s, background 0.18s, transform 0.12s, box-shadow 0.18s;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.plugin-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 14px rgba(15, 23, 42, 0.08) !important;
}

.plugin-card-icon {
    font-size: 32px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-bottom: 6px !important;
    line-height: 1 !important;
}

.plugin-card-name {
    font-size: 16px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
    letter-spacing: 0.4px !important;
}

.plugin-card-std {
    font-size: 10px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-top: 4px !important;
    font-weight: 600 !important;
}

.plugin-card-desc {
    font-size: 10px !important;
    color: var(--muted-foreground, #9ca3af) !important;
    margin-top: 6px !important;
    line-height: 1.35 !important;
}

/* 선택 상태 — 플러그인별 컬러 */
.plugin-card.is-oee.selected {
    border-color: var(--pp-tone-success-bg) !important;
    background: oklch(0.97 0.04 145) !important;
}
.plugin-card.is-oee.selected .plugin-card-icon { color: var(--pp-tone-success-bg) !important; }
.plugin-card.is-oee.selected .plugin-card-name { color: #166534 !important; }

.plugin-card.is-ram.selected {
    border-color: var(--pp-primary) !important;
    background: oklch(0.97 0.03 260) !important;
}
.plugin-card.is-ram.selected .plugin-card-icon { color: var(--pp-primary) !important; }
.plugin-card.is-ram.selected .plugin-card-name { color: #1e40af !important; }

.plugin-card.is-ems.selected {
    border-color: var(--pp-tone-warn-bg) !important;
    background: oklch(0.97 0.04 80) !important;
}
.plugin-card.is-ems.selected .plugin-card-icon { color: var(--pp-tone-warn-bg) !important; }
.plugin-card.is-ems.selected .plugin-card-name { color: #b45309 !important; }

/* 안내 alert — 모서리·패딩 정돈 */
.plugin-card-hint {
    font-size: 12px !important;
    padding: 10px 14px !important;
    margin-bottom: 0 !important;
    line-height: 1.5 !important;
}


/* ============================================================
 * asset-stmt-dialog 내부 CodeMirror — 다이얼로그 폭 안에 가두기
 * pp-07 의 global .CodeMirror { width: 1000px } 오버라이드
 * ============================================================ */
.bootstrap-dialog.asset-stmt-dialog .asset-stmt-eql-wrap .CodeMirror {
    width: 100% !important;
    max-width: 100% !important;
    min-width: 0 !important;
    padding-right: 48px !important;     /* 우측 실행 버튼 자리만 */
    box-sizing: border-box;
    font-size: 12px !important;
}

.bootstrap-dialog.asset-stmt-dialog .asset-stmt-eql-wrap .CodeMirror-scroll {
    max-height: 280px;
    min-height: 180px;
}

/* 실행 버튼이 CodeMirror 위에 떠야 함 */
.bootstrap-dialog.asset-stmt-dialog .asset-stmt-eql-run {
    z-index: 5;
}


/* ============================================================
 * typeahead 검색 드롭다운 — 단일 source (단정 / 깔끔)
 * 컨테이너: 8px radius · 옅은 보더 · 부드러운 그림자 · 6px 내부 padding
 * 헤더(pp-ta-header): sticky · 일반 굵은 라벨 + 우측 카운트
 * 아이템(a): 6px radius · 호버 / 활성 시 옅은 tint (액센트 바 없음)
 * 내부(pp-ta-item): [id-badge] [name] [desc] — 단색, 그라데이션 없음
 * ============================================================ */

/* ─── Container — Command Palette 톤 ────────────────────── */
body .typeahead.dropdown-menu,
body ul.typeahead.dropdown-menu,
body .dropdown-menu.typeahead {
    max-height: 480px;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 6px !important;
    margin-top: 4px !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 14px !important;
    box-shadow:
        0 0 0 1px rgba(15, 23, 42, 0.02),
        0 2px 4px rgba(15, 23, 42, 0.04),
        0 20px 48px rgba(15, 23, 42, 0.16) !important;
    outline: 0 !important;
    min-width: 720px;
    max-width: 95vw;
    /* Bootstrap modal z-index 1050 보다 높게 설정 — 다이얼로그 안 typeahead 도 위로 떠야 함 */
    z-index: 1060 !important;
}

/* ─── Scrollbar — 라운드 코너 안쪽으로 들어오게 ─────── */
body .typeahead.dropdown-menu::-webkit-scrollbar {
    width: 12px;
    background: #f1f5f9 !important;
}
/* 위/아래 라운드 코너(14px) 영역을 트랙에서 비워서 사각 모서리 안 보이게 */
body .typeahead.dropdown-menu::-webkit-scrollbar-track {
    background: #f1f5f9 !important;
    margin-top: 14px !important;
    margin-bottom: 14px !important;
    border-radius: 999px !important;
    border-left: 1px solid var(--pp-border) !important;
}
body .typeahead.dropdown-menu::-webkit-scrollbar-thumb {
    background: var(--pp-text-soft) !important;
    border-radius: 999px !important;
    border: 3px solid var(--pp-white) !important;
    background-clip: padding-box !important;
    min-height: 30px;
}
body .typeahead.dropdown-menu::-webkit-scrollbar-thumb:hover {
    background: var(--pp-text-muted) !important;
    background-clip: padding-box !important;
    border: 3px solid var(--pp-white) !important;
}
body .typeahead.dropdown-menu::-webkit-scrollbar-corner {
    background: transparent !important;
    border-radius: 14px !important;
}
/* Firefox */
body .typeahead.dropdown-menu {
    scrollbar-width: thin;
    scrollbar-color: var(--pp-text-soft) transparent;
}

/* ─── <li> 기본 리셋 ───────────────────────────── */
body .typeahead.dropdown-menu > li {
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    list-style: none;
}

/* ─── 카테고리 헤더 — 미니 라벨 + 하단 구분선 ─────────────────── */
body .typeahead.dropdown-menu > li.pp-ta-header {
    position: sticky;
    top: -6px;
    z-index: 2;
    padding: 8px 10px 8px !important;
    margin: 0 -6px 6px -6px !important;
    background: var(--pp-white) !important;
    color: var(--pp-text-muted) !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    letter-spacing: 0 !important;
    text-transform: none !important;
    border-top: 0 !important;
    border-bottom: 1px solid var(--pp-border) !important;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    cursor: default;
}
body .typeahead.dropdown-menu > li.pp-ta-header:first-child {
    margin-top: -2px !important;
}

body .pp-ta-count {
    flex-shrink: 0;
    font-size: 10.5px !important;
    font-weight: 600 !important;
    color: var(--primary, var(--pp-primary)) !important;
    background: rgba(29, 78, 216, 0.08) !important;
    border: 1px solid rgba(29, 78, 216, 0.20) !important;
    padding: 2px 10px !important;
    border-radius: 999px !important;
    letter-spacing: 0.02em !important;
    text-transform: none !important;
}

/* ─── 아이템 행 (a) — 미니멀, 둥근 호버 + 하단 구분선 ──── */
body .typeahead.dropdown-menu > li > a {
    display: block;
    position: relative;
    padding: 8px 12px !important;         /* 아이템 내부 콘텐츠 패딩(유지) — 외부 여백은 컨테이너에서 0 처리 */
    margin: 0 !important;
    border: 0 !important;
    border-bottom: 1px solid #eef2f6 !important;
    border-radius: 12px !important;       /* 아이템(hover/active 하이라이트) 모서리 라운드 */
    color: #0f172a !important;
    background: transparent !important;
    transition: background 0.12s;
    text-decoration: none !important;
}
/* 마지막 항목은 하단 구분선 제거 */
body .typeahead.dropdown-menu > li:last-child > a { border-bottom: 0 !important; }
/* 카테고리 헤더 위 항목은 카테고리 헤더 구분선과 겹치지 않게 */
body .typeahead.dropdown-menu > li.pp-ta-header + li > a { border-top: 0 !important; }

body .typeahead.dropdown-menu > li.active > a,
body .typeahead.dropdown-menu > li > a:hover,
body .typeahead.dropdown-menu > li > a:focus {
    background: var(--pp-bg-muted) !important;       /* 테마 중립 연한 배경(zinc-50) — 기존 진한 톤 대체 */
    color: #0f172a !important;
}
/* 좌측 액센트 바 제거 */
body .typeahead.dropdown-menu > li > a::before,
body .typeahead.dropdown-menu > li.active > a::before,
body .typeahead.dropdown-menu > li > a:hover::before {
    content: none !important;
    display: none !important;
}
/* 우측 chevron — hover 시 fade-in */
body .typeahead.dropdown-menu > li > a::after {
    content: '\f105';                /* fa-chevron-right */
    font-family: 'Font Awesome 7 Pro', sans-serif !important;
    font-weight: 100 !important;
    position: absolute;
    right: 14px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--pp-text-muted) !important;
    font-size: 12px !important;
    opacity: 0 !important;
    transition: opacity 0.12s, transform 0.12s;
}
body .typeahead.dropdown-menu > li.active > a::after,
body .typeahead.dropdown-menu > li > a:hover::after {
    opacity: 1 !important;
    transform: translateY(-50%) translateX(2px);
}

/* ─── 아이템 내부 레이아웃 — 세로 2단 (위: 이름 / 아래: 설명), ID 뱃지 미표시 ─── */
body .pp-ta-item {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    row-gap: 2px;
    min-width: 0;
    line-height: 1.35 !important;
    width: 100%;
    padding: 0 !important;                   /* 외곽 패딩 제거 — 항목이 메뉴 가장자리에 밀착 (chevron 은 absolute) */
}
/* dropdown-menu 폭을 콘텐츠에 맞춰 늘려 표 정렬이 깔끔하도록 */
body .typeahead.dropdown-menu > li > a { width: 100%; box-sizing: border-box; }

/* ID 뱃지/칩 미표시 — renderItem 이 더이상 생성하지 않음. 잔여 마크업도 숨김 */
body .pp-ta-id,
body .pp-ta-id.id-badge,
body .typeahead.dropdown-menu .pp-ta-id.id-badge { display: none !important; }

/* ── vanilla 자동완성 메뉴(현대화) — PPTypeahead 가 생성하는 .pp-ta-menu ── */
body .pp-ta-wrap { position: relative; display: block; }
/* typeahead 입력박스 우측 돋보기 아이콘 (장식 — pointer-events none, input 우측 패딩으로 텍스트 겹침 방지) */
body .pp-ta-wrap::after {
    content: '\f002';                                /* fa-magnifying-glass */
    font-family: 'Font Awesome 7 Pro', sans-serif;
    font-weight: 300;
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--pp-text-muted);
    font-size: 13px;
    pointer-events: none;
}
body .pp-ta-wrap > input { padding-right: 32px; }
body .pp-ta-menu.typeahead.dropdown-menu {
    position: absolute; top: calc(100% + 4px); left: 0; right: auto;
    display: none; float: none; min-width: 100%; max-width: 540px;
    margin: 0; padding: 0; list-style: none;
    max-height: 320px; overflow-y: auto; overflow-x: hidden;
    background: var(--pp-white); border: 1px solid var(--pp-border);
    border-radius: 8px; box-shadow: 0 6px 18px rgba(15, 23, 42, 0.12); z-index: 1050;
    scrollbar-width: thin;                                   /* 스크롤바 연하게 (Firefox) */
    scrollbar-color: var(--pp-border) transparent;
}
/* 스크롤바 연하게 (WebKit) — 기본 다크 스크롤바 대체 */
body .pp-ta-menu.typeahead.dropdown-menu::-webkit-scrollbar { width: 8px; }
body .pp-ta-menu.typeahead.dropdown-menu::-webkit-scrollbar-track { background: transparent; }
body .pp-ta-menu.typeahead.dropdown-menu::-webkit-scrollbar-thumb {
    background: var(--pp-border); border-radius: 4px; border: 2px solid transparent; background-clip: padding-box;
}
body .pp-ta-menu.typeahead.dropdown-menu::-webkit-scrollbar-thumb:hover { background: var(--pp-text-muted); background-clip: padding-box; }
body .pp-ta-menu > li { list-style: none; }
body .pp-ta-menu > li > a {
    display: block; padding: 0; border-radius: 0;   /* 아이템을 메뉴(커버) 보더에 밀착 — 여백 없음 */
    text-decoration: none; color: inherit;
}
body .pp-ta-menu > li.active > a,
body .pp-ta-menu > li > a:hover { background: var(--pp-bg-muted); }
body .pp-ta-menu > li.pp-ta-header {
    padding: 4px 8px 6px; margin-bottom: 0;          /* 헤더 하단 여백 제거 — 첫 아이템 밀착 */
    font-size: 11px; color: var(--muted-foreground, var(--pp-muted-fg));
    border-bottom: 1px solid var(--pp-border);
}

/* 우상 끝 — ID 모노 칩 (옅은 회색) */
body .pp-ta-id {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
    font-family: 'SFMono-Regular', 'Menlo', 'Consolas', monospace !important;
    font-size: 10.5px !important;
    font-weight: 600 !important;
    color: var(--pp-muted-fg) !important;
    background: #f8fafc !important;
    padding: 2px 8px !important;
    border-radius: 4px !important;
    border: 1px solid var(--pp-border) !important;
    letter-spacing: 0.02em !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 280px;
    margin-left: 12px !important;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}

/* 우하 — 설명 (이름 바로 밑 — 이름과 동일한 grid col 2, row 2 좌측 정렬, 부드러운 슬레이트 톤) */
body .pp-ta-desc {
    grid-column: 2;
    grid-row: 2;
    justify-self: start;
    align-self: start;
    margin: 0 !important;
    padding: 0 !important;
    color: var(--pp-muted-fg) !important;
    font-size: 12px !important;
    font-weight: 400 !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    text-align: left !important;
    letter-spacing: -0.005em !important;
    min-width: 0;
    max-width: 100%;
}

/* 이름 — 진하게, 타이트한 자간 */
body .pp-ta-name {
    min-width: 0;
    font-weight: 600 !important;
    font-size: 13.5px !important;
    color: var(--foreground, #0f172a) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    text-align: left !important;
    letter-spacing: -0.01em !important;
}

/* 활성/호버 — ID 태그는 흰 배경 + primary 텍스트 (subtle) */
body .typeahead.dropdown-menu > li.active .pp-ta-id,
body .typeahead.dropdown-menu > li > a:hover .pp-ta-id,
body .typeahead.dropdown-menu > li > a:focus .pp-ta-id {
    background: var(--pp-white) !important;
    color: var(--pp-primary) !important;
    border-color: var(--pp-text-soft) !important;
    box-shadow: none !important;
}
body .typeahead.dropdown-menu > li.active .pp-ta-desc,
body .typeahead.dropdown-menu > li > a:hover .pp-ta-desc {
    color: var(--pp-border-strong) !important;
}

/* 빈 결과 */
body .typeahead.dropdown-menu > li.disabled > a {
    padding: 16px 12px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    text-align: center !important;
    font-size: 12px !important;
    cursor: default;
    background: transparent !important;
}
body .typeahead.dropdown-menu > li.disabled > a::before { display: none !important; }


/* ============================================================
 * /ontology/index — 인라인 스타일을 시맨틱 클래스로 이전
 * ============================================================ */

/* 사이트 명 배너 (페이지 헤더 아래 floating) */
.onto-site-banner {
    position: absolute;
    z-index: 1;
    width: 800px;
    margin-left: 300px !important;
}

.onto-site-banner-inner {
    font-size: 14px !important;
    padding: 6px 14px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    border-radius: 999px !important;
    text-align: left !important;
    background: transparent !important;
}

.onto-site-banner-inner > i {
    color: var(--primary, var(--pp-primary)) !important;
}

.onto-site-banner-inner > strong {
    color: var(--foreground, #111827) !important;
    font-weight: 700 !important;
}

.onto-site-banner-inner .fs-12 {
    font-size: 11px !important;
    color: var(--muted-foreground, #9ca3af) !important;
}

/* 좌측 사이드 floater (사이트 선택 + 도메인 패널) */
.onto-side-floater {
    position: absolute;
    z-index: 1;
    width: 280px;
    margin-left: 10px !important;
}

/* 사이트 선택 패널 body — 가운데 정렬 + 흰 하단 보더 (overlap 방지) */
.onto-tags-body {
    border-bottom: 1px solid var(--pp-white) !important;
    text-align: center !important;
}

/* 트리 캔버스 영역 */
.onto-tree-canvas {
    padding-left: 50px !important;
}

.onto-site-tree {
    width: 100%;
    height: 9000px;
}


/* ============================================================
 * 오토컴플릿 타입어헤드 — 더 부드럽고 모던하게
 * (위 typeahead 룰 보완: 애니메이션 / 빈 상태 / focus 스타일)
 * ============================================================ */
body .typeahead.dropdown-menu {
    animation: typeahead-fade-in 0.16s ease-out;
}

@keyframes typeahead-fade-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* 입력박스 focus 시 살짝 ring */
.form-control.typeahead:focus,
input.typeahead:focus {
    border-color: var(--primary, var(--pp-primary)) !important;
    box-shadow: 0 0 0 3px rgba(29, 78, 216, 0.12) !important;
    outline: 0 !important;
}

/* 빈 결과 메시지 */
body .typeahead.dropdown-menu > li.disabled {
    padding: 18px 16px !important;
    color: var(--muted-foreground, #9ca3af) !important;
    text-align: center !important;
    font-size: 12px !important;
}

/* 아이템 행 마이크로 인터랙션 — 호버 시 살짝 슬라이드 */
body .typeahead.dropdown-menu > li > a {
    position: relative;
    transition: background 0.12s, color 0.12s, padding-left 0.12s;
}

body .typeahead.dropdown-menu > li.active > a,
body .typeahead.dropdown-menu > li > a:hover,
body .typeahead.dropdown-menu > li > a:focus {
    padding-left: 14px !important;
}

/* hover/active 좌측에 primary 색 인디케이터 */
body .typeahead.dropdown-menu > li > a::before {
    content: "";
    position: absolute;
    left: 4px;
    top: 50%;
    width: 3px;
    height: 0;
    border-radius: 2px !important;
    background: var(--primary, var(--pp-primary)) !important;
    transform: translateY(-50%);
    transition: height 0.16s ease;
    color: var(--pp-white) !important;
}

body .typeahead.dropdown-menu > li.active > a::before,
body .typeahead.dropdown-menu > li > a:hover::before,
body .typeahead.dropdown-menu > li > a:focus::before {
    height: 60%;
}


/* ============================================================
 * 타입어헤드 — 더 모던한 폴리시 (최종 오버라이드)
 * 행을 2-line 적응형 레이아웃: Name(큰 텍스트) + ID 뱃지 우측,
 * 설명은 다음 줄. 좁아도 깨지지 않게.
 * ============================================================ */

/* 컨테이너 — 살짝 더 부드러운 그림자 + 얇은 보더 */
body .typeahead.dropdown-menu {
    border: 1px solid rgba(15, 23, 42, 0.06) !important;
    box-shadow: 0 16px 40px rgba(15, 23, 42, 0.18), 0 4px 10px rgba(15, 23, 42, 0.06) !important;
    padding: 0 !important;                /* 외부(메뉴 컨테이너) 패딩 제거 — 아이템이 커버 보더에 밀착 */
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    background: rgba(255, 255, 255, 0.98) !important;
}

/* (옛 typeahead override 룰 제거 — 최신 grid 디자인이 위쪽 룰에서 단일 source) */


/* ============================================================
 * 태그 검색 패널 (#tags) — input-group-addon 우측 보더 제거
 * 라벨(addon)과 input/select 사이 경계 무지향
 * ============================================================ */
body #tags .input-group > .input-group-text,
body #tags .input-group .input-group-text {
    border-right: 0 !important;
}


/* ============================================================
 * 태그 검색 패널 (#tags) — control-label / addon 텍스트 옆 패딩
 * 라벨/addon 의 텍스트가 다음 input 의 왼쪽 보더와 너무 붙음 → 우측 패딩 보강
 * ============================================================ */
body #tags .form-inline > label.form-label,
body #tags .form-inline > label.form-label,
body #tags .pp-form-row > label.form-label,
body #tags .form-group > label.form-label,
body #tags .form-group > label.form-label {
    padding-right: 12px !important;
}

body #tags .input-group > .input-group-text,
body #tags .input-group .input-group-text {
    padding-right: 12px !important;
}



/* === pp-44-tag-form-band.css === */
/* ============================================================================
 * pp-09d-tag-form-band.css
 * SCOPE  : TAG VIEW / FORM / ALARM BAND
 * 영역   : /tag/view 통계 카드, Toastr, EQL 알람 뱃지, /tag/form 패널·footer·저장 버튼·알람 밴드, 알람 밴드 수직 임계치, ontology 툴팁, /calendar 상태 뱃지
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /tag/view — 통계 카드 / 데이터·알람 영역
 * ============================================================ */

/* 통계 블록 (포인트/알람) — 배경/보더 제거 (사용자 정책) */



.tag-stat-value > .text-cap-12 {
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-left: 4px !important;
}

.tag-stat-spark {
    width: 100%;
    height: 60px;
    margin-top: 8px !important;
}


/* 통계 카드 — 오늘/전체 2 컬럼 + 24h spark (포인트·알람 공통) — 배경/보더 제거 */
.tag-stat-card {
    background: transparent !important;
    border: 0 !important;
    border-radius: 0 !important;
    padding: 4px 0 8px !important;
    margin-bottom: 14px !important;
}

.tag-stat-card-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
}

.tag-stat-cell {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.tag-stat-cell-today {
    flex: 1 1 auto;
    text-align: left !important;
}

.tag-stat-cell-total {
    flex: 0 0 auto;
    text-align: right !important;
    border-left: 1px solid var(--pp-border) !important;
    padding-left: 14px !important;
}

.tag-stat-cell-label {
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
    margin-bottom: 4px !important;
    letter-spacing: 0.01em !important;
}

.tag-stat-cell-today .tag-stat-cell-value {
    font-size: 28px !important;
    font-weight: 800 !important;
    color: var(--foreground, #111827) !important;
    line-height: 1.05 !important;
    letter-spacing: 0.3px !important;
}

.tag-stat-cell-total .tag-stat-cell-value {
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 15px !important;
    font-weight: 700 !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    line-height: 1.15 !important;
}

.tag-stat-cell-unit {
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-left: 4px !important;
}

.tag-stat-card .tag-stat-spark {
    margin-top: 6px !important;
}

/* 중요도별 알람 그리드 (정보/경고/심각) */
.tag-priority-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin-bottom: 8px !important;
}

.tag-priority-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 8px !important;
    border-radius: 10px !important;
    color: var(--pp-white) !important;
    text-align: center !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

.tag-priority-cell.alarm-info  { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; color: var(--pp-white) !important; }
.tag-priority-cell.alarm-warn  { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; color: var(--pp-white) !important; }
.tag-priority-cell.alarm-error { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; color: var(--pp-white) !important; }

.tag-priority-label {
    font-size: 10px !important;
    font-weight: 700 !important;
    color: rgba(255, 255, 255, 0.85) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.6px !important;
}

.tag-priority-value {
    font-size: 16px !important;
    font-weight: 800 !important;
    color: var(--pp-white) !important;
    line-height: 1.1 !important;
}

.tag-priority-chart {
    height: 160px;
    text-align: center !important;
    color: var(--muted-foreground, #d4d4d8) !important;
    margin-top: 8px !important;
}

/* 현재 값 row 표 */
.tag-current-table {
    margin: 0 !important;
    border-bottom: 2px solid var(--pp-border, #d1d5db) !important;
    border-top: 2px solid var(--pp-border, #d1d5db) !important;
    table-layout: fixed;
}

.tag-current-table > thead > tr > th {
    color: var(--foreground, #374151) !important;
    font-weight: 600 !important;
    border-bottom: 1px solid var(--pp-border) !important;
}

.tag-current-th-value { width: 300px; text-align: left !important; }
.tag-current-th-meta  { width: 150px; text-align: center !important; }

/* 현재값 단위 — 인라인 style 제거 표준화(tag/view.js) */
.tag-current-unit { font-size: 14px; font-weight: 500; }
.tag-current-value {
    display: inline-block;
    min-width: 230px;
    width: 100%;
    font-size: 22px !important;
    font-weight: 700 !important;
    line-height: 45px !important;
    border-radius: 8px !important;
}

/* 탭 컨텐츠 — 보더 박스 */


/* 타입어헤드 dropdown z-index 강제 (Bootstrap default 1000 → 5) */
body .typeahead.dropdown-menu,
body .tt-menu {
    z-index: 5 !important;
}


/* 타입어헤드 input 박스 자체도 z-index 낮춤 (auto/0) — 어떤 컨테이너가 stacking 만들어도 위로 못 올라감.
 * `.twitter-typeahead` 는 bootstrap3-typeahead lib 가 input 을 감싸는 wrapper. */
body input.typeahead,
body input.form-control.typeahead,
body .twitter-typeahead,
body .twitter-typeahead .tt-input,
body .twitter-typeahead .tt-hint {
    z-index: auto !important;
    position: relative;
}


/* ============================================================
 * Toastr 토스트 닫기 버튼 — 수직 중앙 정렬
 * pp-app.css 의 top:11px right:8px 절대 위치를 50% 로 이동
 * ============================================================ */
body #toast-container .toast .toast-close-button,
body #toast-container > div .toast-close-button {
    position: absolute !important;
    top: 50% !important;
    right: 10px !important;
    transform: translateY(-50%);
    margin: 0 !important;
    line-height: 1 !important;
}

/* 닫기 텍스트(×) 자체 폰트 크기·정렬 */
body #toast-container .toast-close-button {
    font-size: 18px !important;
    font-weight: 700 !important;
    opacity: 0.7 !important;
}

body #toast-container .toast-close-button:hover {
    opacity: 1 !important;
}


/* ============================================================
 * EQL 알람 / 알람 목록 — 중요도 뱃지 온다크 강화
 * pp-override-status.css 의 기본 컬러를 dark oklch 톤 + inset shadow 로 오버라이드
 * ============================================================ */
body #page-wrapper .priority-badge-band,
body .priority-badge-band {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 60px;
    padding: 3px 10px !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* BAND — 동적 중요도(태그 설정 기반). violet 톤으로 INFO/WARN/ERROR 와 구분 */
body #page-wrapper .priority-badge-band,
body .priority-badge-band {
    background: oklch(0.48 0.18 290) !important;
    color: var(--pp-white) !important;
}

/* 자손 (i / span / *) 까지 흰 텍스트 강제 — 기존 priority-badge dark color rule 무력화 */
body #page-wrapper .priority-badge-band *,
body .priority-badge-band * {
    color: var(--pp-white) !important;
}

body #page-wrapper .priority-badge-band > i,
body .priority-badge-band > i {
    font-size: 10px !important;
    color: rgba(255,255,255,0.85) !important;
}


/* ============================================================
 * /tag/form — 탭 컨텐츠를 패널처럼 표시
 * 각 .tab-pane 이 panel-default 처럼 흰 배경·보더·둥근 모서리·그림자
 * ============================================================ */
body #page-wrapper .tab-content-as-panels {
    background: transparent !important;
    padding: 0 !important;
    border: 0 !important;
}

/* tab-pane 자체는 투명 — 내부 .card 이 시각 보더·배경 담당 (디자인 시스템 표준) */
body #page-wrapper .tab-content-as-panels > .tab-pane {
    background: transparent !important;
    border: 0 !important;
    border-radius: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    margin: 0 !important;
}

/* tab-pane 안 panel — 표준 panel-default 라디우스 유지 (4모서리 모두 round).
 * nav-tabs 와 분리, 패널 간 12px 위쪽 마진. */
body #page-wrapper .tab-content-as-panels > .tab-pane > .card.card {
    margin-top: 12px !important;
}

/* 탭 nav 자체 스타일 — 탭 컨텐츠와 시각적으로 연결되어 보이도록 */
body #page-wrapper .nav-tabs + .tab-content-as-panels > .tab-pane.active,
body #page-wrapper .nav-tabs + * .tab-content-as-panels > .tab-pane.active {
    /* 활성 탭 컨텐츠와 nav 가 이어진 효과 */
}

/* 탭 컨텐츠 안 fieldset 마진 정리 */
body #page-wrapper .tab-content-as-panels > .tab-pane > fieldset {
    margin-bottom: 16px !important;
}

body #page-wrapper .tab-content-as-panels > .tab-pane > fieldset:last-child {
    margin-bottom: 0 !important;
}

body #page-wrapper .tab-content-as-panels > .tab-pane > .mb-4:first-child {
    display: none;     /* 옛 padding spacer 제거 */
}


/* ============================================================
 * /tag/form — <form> 내부의 row/footer 도 페이지 24px 거터 적용
 * #page-wrapper > .row 룰이 직속 자식만 잡으므로, form 안에 row 가 있으면
 * 별도 룰로 동일 padding 적용.
 * ============================================================ */
body #page-wrapper > form > .row,
body #page-wrapper > form > div > .row {
    padding: 0 24px !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
}

body #page-wrapper > form > .row > [class*="col-"]:only-child,
body #page-wrapper > form > div > .row > [class*="col-"]:only-child {
    padding-left: 0 !important;
    padding-right: 0 !important;
}

body #page-wrapper > form > .form-content-footer {
    margin-left: 24px !important;
    margin-right: 24px !important;
}

body #page-wrapper > form > .row:last-of-type {
    padding-bottom: 0 !important;
}


/* ============================================================
 * /tag/form — 저장 버튼 별도 row (맨 아래 강조)
 * ============================================================ */




/* ============================================================
 * /tag/form 알람 밴드 — 이미지 제거 + CSS 시각 밴드 + 임계치 그리드
 * ============================================================ */

/* 시각 밴드 차트 — 7 세그먼트 (TRIP_HI ─ HI_HI ─ HI ─ 정상 ─ LO ─ LO_LO ─ TRIP_LO) */
.alarm-band-chart {
    display: flex;
    align-items: stretch;
    height: 36px;
    border-radius: 8px !important;
    overflow: hidden;
    margin-bottom: 18px !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05) !important;
}

.alarm-band-segment {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--pp-white) !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    letter-spacing: 0.4px !important;
    text-transform: uppercase !important;
    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.08) !important;
}

.alarm-band-trip   { background: oklch(0.50 0.22 25) !important; }      /* 심각 */
.alarm-band-warn   { background: oklch(0.62 0.18 65) !important; }      /* 경고 */
.alarm-band-info   { background: oklch(0.55 0.16 145) !important; }     /* 정보 */
.alarm-band-normal { background: oklch(0.85 0.01 286) !important; color: var(--foreground, #374151) !important; }

/* 임계치 3 그룹 (정보/경고/심각) — grid 3-column */
.alarm-band-thresholds {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
    margin-bottom: 18px !important;
}

.alarm-band-group {
    background: var(--muted, #f8fafc) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    padding: 12px 14px !important;
}

.alarm-band-group-label {
    display: inline-block;
    padding: 3px 10px !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    margin-bottom: 10px !important;
    text-transform: uppercase !important;
    letter-spacing: 0.4px !important;
}

.alarm-band-group-label.alarm-info  { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; }
.alarm-band-group-label.alarm-warn  { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; }
.alarm-band-group-label.alarm-error { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; }

/* 불린 알람 그리드 */
.alarm-bool-grid {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.alarm-bool-row {
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    padding: 12px 14px !important;
    background: var(--pp-white) !important;
}

.alarm-bool-row-head {
    font-size: 13px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
    margin-bottom: 10px !important;
}

.alarm-bool-row-head > i {
    color: var(--primary, var(--pp-primary)) !important;
    margin-right: 6px !important;
}

.alarm-bool-row-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 18px;
    align-items: center;
}

.alarm-bool-row-fields .form-inline-grow {
    flex: 1 1 300px;
    min-width: 0;
}

/* form-help-inline-text — input 옆 짧은 설명 */
.form-help-inline-text {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 12px !important;
    margin-left: 8px !important;
}

/* form-help-block — 패널/섹션 하단 일반 안내 (margin-left 없음) */
.form-help-block {
    margin: 8px 0 0 0 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 12px !important;
}


/* /tag/form > 인공지능 탭 — 안내 alert 정리 */
.ai-intro-alert > h4 {
    margin: 0 0 8px 0 !important;
    font-size: 14px !important;
}



.ai-intro-list > li {
    margin-bottom: 2px !important;
}


/* select2 multiple — search inline input 보더 제거 (디자인 시스템 강제 오버라이드) */
body .select2-container--bootstrap .select2-selection--multiple .select2-search--inline .select2-search__field {
    background: 0 0 !important;
    padding: 0 12px !important;
    height: 32px;
    line-height: 1.42857143 !important;
    margin-top: 0 !important;
    min-width: 5em;
    border: 0px !important;
}


/* select2 multiple — 선택된 choice 칩 (디자인 시스템 컬러) */
body .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
    background-color: #446582 !important;
    border: 1px solid #2e6da4 !important;
    color: var(--pp-white) !important;
    border-radius: 5px !important;
    padding: 2px 8px !important;
    margin: 0 3px 0 0 !important;
    font-size: 12px !important;
    flex-shrink: 0;
    line-height: 18px !important;
}

body .select2-container--bootstrap .select2-selection--multiple .select2-selection__choice__remove {
    color: var(--pp-white) !important;
    margin-right: 4px !important;
}


/* ============================================================
 * 알람 밴드 — 수직 임계치 리스트 (위→아래 = 큰값→작은값)
 * 디자인 시스템 깔끔한 톤
 * ============================================================ */
.alarm-band-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 4px !important;
}

/* 2-column 그리드 (좌: HIGH 측, 우: LOW 측) */
.alarm-band-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 14px;
    margin-bottom: 4px !important;
}

.alarm-band-grid .alarm-band-row-span {
    grid-column: 1 / -1;
}

/* 알람 메세지 input — 라벨 없이 전체 너비 */
.alarm-band-message-input {
    width: 100% !important;
    max-width: 100% !important;
}

.alarm-band-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 14px !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-left: 4px solid transparent !important;
    border-radius: 8px !important;
    transition: border-color 0.15s, background 0.15s;
}

.alarm-band-row:hover {
    background: var(--muted, #f8fafc) !important;
}

.alarm-band-dot {
    flex: 0 0 10px;
    width: 10px;
    height: 10px;
    border-radius: 50% !important;
    background: var(--pp-border) !important;
}

.alarm-band-name {
    flex: 0 0 140px;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 12px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
    letter-spacing: 0.3px !important;
}

.alarm-band-zone {
    flex: 0 0 64px;
    text-align: center !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    padding: 3px 8px !important;
    border-radius: 12px !important;
    background: oklch(0.55 0 0) !important;
    letter-spacing: 0.4px !important;
}

.alarm-band-input {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 300px;
}

/* 상태별 컬러 */
.alarm-band-row.is-error {
    border-left-color: oklch(0.50 0.22 25) !important;
}
.alarm-band-row.is-error .alarm-band-dot { background: oklch(0.50 0.22 25) !important; }
.alarm-band-row.is-error .alarm-band-zone { background: oklch(0.50 0.22 25) !important; }

.alarm-band-row.is-warn {
    border-left-color: oklch(0.62 0.18 65) !important;
}
.alarm-band-row.is-warn .alarm-band-dot { background: oklch(0.62 0.18 65) !important; }
.alarm-band-row.is-warn .alarm-band-zone { background: oklch(0.62 0.18 65) !important; }

.alarm-band-row.is-info {
    border-left-color: var(--pp-tone-info-bg) !important;
}
.alarm-band-row.is-info .alarm-band-dot { background: var(--pp-tone-info-bg) !important; }
.alarm-band-row.is-info .alarm-band-zone { background: var(--pp-tone-info-bg) !important; }

.alarm-band-row.is-normal {
    border: 1px dashed var(--pp-border, #d1d5db) !important;
    background: var(--muted, #f8fafc) !important;
    justify-content: center;
    padding: 6px 14px !important;
}
.alarm-band-row.is-normal .alarm-band-dot { display: none; }
.alarm-band-row.is-normal .alarm-band-name {
    flex: 0 0 auto;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-family: inherit !important;
    font-weight: 600 !important;
    text-align: center !important;
}

/* 불린 알람 — 임계치 행과 동일 패턴, 위/아래 2행 (1열 grid) */
.alarm-band-grid--boolean {
    grid-template-columns: 1fr;
    margin-top: 10px !important;
}
.alarm-band-row--boolean {
    border-left-color: oklch(0.62 0.18 250) !important;
}
.alarm-band-row--boolean .alarm-band-dot { background: oklch(0.62 0.18 250) !important; }
.alarm-band-row--boolean .alarm-band-zone { background: oklch(0.55 0.06 250) !important; }
.alarm-band-row--boolean .alarm-band-input { max-width: 220px; }

/* 중요도 선택값에 따라 dot/zone 컬러 동기화 (JS 가 data-priority 부여) */
.alarm-band-row--boolean[data-priority="hi"] .alarm-band-dot,
.alarm-band-row--boolean[data-priority="hi"] .alarm-band-zone   { background: oklch(0.55 0.16 145) !important; }
.alarm-band-row--boolean[data-priority="hi"]                    { border-left-color: oklch(0.55 0.16 145) !important; }
.alarm-band-row--boolean[data-priority="hi_hi"] .alarm-band-dot,
.alarm-band-row--boolean[data-priority="hi_hi"] .alarm-band-zone { background: oklch(0.62 0.18 65) !important; }
.alarm-band-row--boolean[data-priority="hi_hi"]                  { border-left-color: oklch(0.62 0.18 65) !important; }
.alarm-band-row--boolean[data-priority="trip_hi"] .alarm-band-dot,
.alarm-band-row--boolean[data-priority="trip_hi"] .alarm-band-zone { background: oklch(0.50 0.22 25) !important; }
.alarm-band-row--boolean[data-priority="trip_hi"]                  { border-left-color: oklch(0.50 0.22 25) !important; }
/* 비활성 (NONE) — 흐릿하게 */
.alarm-band-row--boolean[data-active="false"] {
    opacity: 0.55 !important;
    background: var(--muted, #f8fafc) !important;
}


/* ============================================================
 * /ontology/index — 마우스 오버 tooltip (ECharts)
 * ============================================================ */
.onto-tip {
    width: 280px;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    overflow: hidden;
    font-family: 'Noto Sans Korean', sans-serif !important;
    color: var(--foreground, #111827) !important;
}

.onto-tip-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 12px !important;
    background: var(--muted, #f8fafc) !important;
    border-bottom: 1px solid var(--pp-border) !important;
}

.onto-tip-id-badge {
    display: inline-block;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    background: oklch(0.30 0.01 286) !important;                /* 기본 — 다크 무채 */
    padding: 4px 10px !important;
    border-radius: 12px !important;
    letter-spacing: 0.3px !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* 도메인 타입별 컬러 — 모두 진한 dark 톤 + 흰 텍스트 (온다크) */
.onto-tip-id-badge[data-domain-type="SITE"]  { background: oklch(0.45 0.16 145) !important; color: var(--pp-white) !important; }
.onto-tip-id-badge[data-domain-type="AREA"]  { background: oklch(0.48 0.16 65) !important;  color: var(--pp-white) !important; }
.onto-tip-id-badge[data-domain-type="LINE"]  { background: oklch(0.48 0.16 65) !important;  color: var(--pp-white) !important; }
.onto-tip-id-badge[data-domain-type="ASSET"] { background: oklch(0.48 0.16 65) !important;  color: var(--pp-white) !important; }
.onto-tip-id-badge[data-domain-type="OPC"]   { background: oklch(0.40 0.12 260) !important; color: var(--pp-white) !important; }
.onto-tip-id-badge[data-domain-type="TAG"]   { background: oklch(0.42 0.20 290) !important; color: var(--pp-white) !important; }
.onto-tip-id-badge[data-domain-type="EDGE"]  { background: oklch(0.45 0.12 220) !important; color: var(--pp-white) !important; }

.onto-tip-type {
    font-size: 10px !important;
    font-weight: 700 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px !important;
}

.onto-tip-body {
    padding: 8px 12px !important;
}

.onto-tip-dl {
    margin: 0 !important;
    font-size: 12px !important;
    line-height: 1.5 !important;
}

.onto-tip-dl > dt {
    float: left;
    clear: left;
    width: 80px;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}

.onto-tip-dl > dd {
    margin: 0 0 4px 80px !important;
    color: var(--foreground, #111827) !important;
    /* 길어도 다음 줄로 넘기지 않고 한 줄 ellipsis (tooltip 폭 280px 고정) */
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

.onto-tip-section {
    padding: 8px 12px !important;
    border-top: 1px solid var(--pp-border) !important;
}

.onto-tip-section-event {
    background: linear-gradient(90deg, var(--ev-bg, var(--pp-muted-fg)), color-mix(in srgb, var(--ev-bg, var(--pp-muted-fg)) 70%, black)) !important;
    color: var(--pp-white) !important;
    border-top: 0 !important;
}

.onto-tip-section-state {
    background: linear-gradient(90deg, oklch(0.50 0.02 260), oklch(0.40 0.02 260)) !important;
    color: var(--pp-white) !important;
    border-top: 0 !important;
}

.onto-tip-section-stats {
    background: linear-gradient(90deg, oklch(0.48 0.04 220), oklch(0.40 0.04 220)) !important;
    color: var(--pp-white) !important;
    border-top: 0 !important;
}

.onto-tip-section-tag-value.onto-tip-value-good {
    background: linear-gradient(90deg, oklch(0.50 0.16 145), oklch(0.42 0.14 145)) !important;
    color: var(--pp-white) !important;
    border-top: 0 !important;
}

.onto-tip-section-tag-value.onto-tip-value-other {
    background: linear-gradient(90deg, oklch(0.55 0.18 65), oklch(0.45 0.16 65)) !important;
    color: var(--pp-white) !important;
    border-top: 0 !important;
}

.onto-tip-section-label {
    font-size: 9px !important;
    font-weight: 700 !important;
    color: rgba(255, 255, 255, 0.85) !important;
    letter-spacing: 0.6px !important;
    text-transform: uppercase !important;
    margin-bottom: 2px !important;
}

.onto-tip-section-value {
    font-size: 13px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    line-height: 1.3 !important;
}

.onto-tip-section-key {
    font-size: 10px !important;
    color: rgba(255, 255, 255, 0.80) !important;
    margin-top: 2px !important;
    word-wrap: break-word;
    white-space: normal !important;
}

.onto-tip-section-meta {
    font-size: 9px !important;
    color: rgba(255, 255, 255, 0.65) !important;
    margin-top: 3px !important;
}

.onto-tip-tag-value {
    font-size: 22px !important;
    font-weight: 800 !important;
    color: var(--pp-white) !important;
    line-height: 1.2 !important;
    margin: 2px 0 !important;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.16) !important;
}


/* ============================================================
 * /calendar/index — 상태 뱃지 온다크 (예정 / 진행중 / 완료)
 * ============================================================ */
body #page-wrapper .cal-status-upcoming,
body #page-wrapper .cal-status-progress,
body #page-wrapper .cal-status-done,
.cal-status-upcoming,
.cal-status-progress,
.cal-status-done {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 64px;
    padding: 3px 10px !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

.cal-status-upcoming { background: oklch(0.45 0.12 220) !important; }    /* 예정 — 다크 teal */
.cal-status-progress { background: oklch(0.55 0.18 65) !important; }     /* 진행중 — 다크 앰버 */
.cal-status-done     { background: oklch(0.45 0.16 145) !important; }    /* 완료 — 다크 그린 */

.cal-status-upcoming > i,
.cal-status-progress > i,
.cal-status-done > i {
    font-size: 9px !important;
    color: rgba(255,255,255,0.85) !important;
}


/* === pp-45-order-equipment.css === */
/* ============================================================================
 * pp-09e-order-equipment.css
 * SCOPE  : ORDER / TIMELINE / EQUIPMENT / STORAGE
 * 영역   : 워크오더 상태 뱃지, /order/index 타임라인, /timeline/index 노드, asset stmt-type 뱃지, /basedata 모달, /asset/dashboard/equipment, /storage/index, /alarm/index 타임라인, PPSettings 다이얼로그
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * 워크오더 상태 뱃지 — 디자인 시스템 (온다크, 12px 라운드, inset shadow)
 * pp-override-status.css 기본 룰 오버라이드
 * ============================================================ */
body #page-wrapper .wo-status-start,
body #page-wrapper .wo-status-paused,
body #page-wrapper .wo-status-end,
body #page-wrapper .wo-status-wait,
body #page-wrapper .wo-status-delay,
body #page-wrapper .wo-status-cancel,
body #page-wrapper .wo-status-aborted,
.wo-status-start,
.wo-status-paused,
.wo-status-end,
.wo-status-wait,
.wo-status-delay,
.wo-status-cancel,
.wo-status-aborted {
    display: inline-flex !important;
    align-items: center;
    gap: 4px;
    min-width: 70px;
    padding: 3px 10px !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

body #page-wrapper .wo-status-start,    .wo-status-start    { background: oklch(0.55 0.18 65)  !important; } /* 진행중 — 앰버 */
body #page-wrapper .wo-status-paused,   .wo-status-paused   { background: oklch(0.50 0.10 75)  !important; } /* 일시중지 — 차분한 옐로/브론즈 */
body #page-wrapper .wo-status-end,      .wo-status-end      { background: oklch(0.45 0.16 145) !important; } /* 완료 — 진한 그린 */
body #page-wrapper .wo-status-wait,     .wo-status-wait     { background: oklch(0.50 0.04 260) !important; } /* 대기 — 차분한 다크 그레이/네이비 */
body #page-wrapper .wo-status-delay,    .wo-status-delay    { background: oklch(0.55 0.18 35)  !important; } /* 지연 — 다크 오렌지/레드 */
body #page-wrapper .wo-status-cancel,   .wo-status-cancel   { background: oklch(0.40 0.01 286) !important; } /* 취소 — 다크 무채 */
body #page-wrapper .wo-status-aborted,  .wo-status-aborted  { background: oklch(0.45 0.22 25)  !important; } /* 비정상종료 — 다크 레드 */

body #page-wrapper .wo-status-start > i,
body #page-wrapper .wo-status-paused > i,
body #page-wrapper .wo-status-end > i,
body #page-wrapper .wo-status-wait > i,
body #page-wrapper .wo-status-delay > i,
body #page-wrapper .wo-status-cancel > i,
body #page-wrapper .wo-status-aborted > i {
    font-size: 9px !important;
    color: rgba(255,255,255,0.85) !important;
}


/* /order/view — OEE 차트 + 설비 상태 타임라인 패널 헬퍼 */
.order-timeline-empty {
    text-align: center !important;
    padding: 20px !important;
    color: var(--muted-foreground, #aaa) !important;
}


/* 타임라인 아이템 노드(.t-box-2*, .tl-node*) 는 pp-57-timeline-node.css 로 이관 */

/* vis-item 안에서 자연스럽게 적용되도록 — 링크 색상 안 끊김 */
.vis-item .vis-item-content a {
    text-decoration: none !important;
    color: inherit !important;
}

/* /order/index 데이터 테이블 — 상태 뱃지 가로 중앙 정렬 강제 */
body #page-wrapper #data_table td:first-child {
    text-align: center !important;
    vertical-align: middle !important;
}
body #page-wrapper #data_table td:first-child > div {
    display: flex;
    justify-content: center;
    align-items: center;
}


/* /order/view — 비정상종료 정보 view-section-title danger 변형 */
.view-section-title.view-section-title-danger {
    color: var(--pp-tone-danger-bg) !important;
    border-bottom-color: rgba(220, 38, 38, 0.25) !important;
}
.view-section-title.view-section-title-danger > i {
    color: var(--pp-tone-danger-bg) !important;
}
.abort-code-text {
    color: var(--pp-tone-danger-bg) !important;
    font-weight: 700 !important;
}


/* /model/index — 선택된 사이트 카드 아이콘 온다크 (흰 아이콘) */
body #page-wrapper .model-site-card.selected .model-site-icon,
body #page-wrapper .model-site-card.selected .model-site-icon > i,
body #page-wrapper .model-site-card.selected .model-site-icon * {
    color: var(--pp-white) !important;
    background: var(--primary, var(--pp-primary-strong)) !important;
    border-color: var(--primary, var(--pp-primary-strong)) !important;
}

body #page-wrapper .model-site-card.selected .model-site-icon > i {
    background: transparent !important;
}


/* ============================================================
 * 에셋 스테이트먼트 유형 뱃지 (.stmt-type-*) — 온다크 (oklch dark + 흰 텍스트)
 * pp-override-status.css 기본 룰 오버라이드
 * ============================================================ */
body #page-wrapper .stmt-type-event,
body #page-wrapper .stmt-type-context,
body #page-wrapper .stmt-type-aggregation,
body #page-wrapper .stmt-type-command,
.stmt-type-event,
.stmt-type-context,
.stmt-type-aggregation,
.stmt-type-command {
    display: inline-flex !important;
    align-items: center;
    gap: 4px;
    min-width: 60px;
    padding: 3px 10px !important;
    border-radius: 8px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

body #page-wrapper .stmt-type-event,       .stmt-type-event       { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }  /* 이벤트 — red-600 */
body #page-wrapper .stmt-type-context,     .stmt-type-context     { background: var(--pp-primary) !important;
    color: var(--pp-white) !important; }  /* 상태 — blue-700 */
body #page-wrapper .stmt-type-aggregation, .stmt-type-aggregation { background: var(--pp-tone-warn-bg) !important; }  /* 집계 — amber-600 */
body #page-wrapper .stmt-type-command,     .stmt-type-command     { background: #8b5cf6 !important;
    color: var(--pp-white) !important; }  /* 명령 — violet-500 */

body #page-wrapper .stmt-type-event > i,
body #page-wrapper .stmt-type-context > i,
body #page-wrapper .stmt-type-aggregation > i,
body #page-wrapper .stmt-type-command > i {
    font-size: 9px !important;
    color: rgba(255, 255, 255, 0.85) !important;
}


/* ============================================================
 * /basedata/index — 추가/수정 모달 (기준정보 표준 폼)
 * 라벨 상단 + 입력 풀폭 + 컬러 피커 행
 * ============================================================ */
body .basedata-form-dialog .modal-dialog {
    width: 600px !important;
    max-width: 92vw !important;
}

.basedata-form-stack > .form-group {
    display: block;
    width: 100%;
    /* 간격은 pp-48 정본(12px) — 이전 14px 제거 */
}

.basedata-form-stack > .form-group > label.form-label {
    display: block;
    margin: 0 0 6px 0 !important;
    text-align: left !important;
    width: auto;
    line-height: 1.4 !important;
}

.basedata-form-stack > .form-group > .form-control,
.basedata-form-stack > .form-group > select.form-control,
.basedata-form-stack > .form-group > textarea.form-control {
    width: 100%;
    max-width: 100%;
}

.basedata-form-stack .form-control.is-uppercase {
    text-transform: uppercase !important;
}

.basedata-color-row {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
}

.basedata-color-row > .basedata-color-picker {
    width: 60px;
    height: 34px;
    padding: 2px !important;
    flex: 0 0 60px;
}

.basedata-color-row > .basedata-color-text {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
}


/* ============================================================
 * /asset/dashboard/equipment — 설비 이미지 프레임 (중앙 정렬)
 * ============================================================ */
.equipment-image-frame {
    width: 100%;
    height: 320px;
    padding: 8px !important;
    border-radius: 10px !important;
    background: transparent !important;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    position: relative;
}
.equipment-image-inner {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.equipment-image-inner > img,
.equipment-image-inner > svg {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
    display: block;
    margin: 0 auto !important;
    position: relative;
    z-index: 1;
}
.equipment-image-placeholder {
    position: absolute;
    font-size: 120px;
    color: #ccc;
    opacity: 0.4;
    z-index: 0;
}

/* 워크오더 요약 stats — 이미지 아래 가로 패턴 */
.equipment-stats {
    margin-top: 10px !important;
    padding: 0 !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 10px !important;
    overflow: hidden;
    background: var(--card, var(--pp-white)) !important;
}
.equipment-stats-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 11px !important;
    table-layout: fixed;
}
.equipment-stats-table > tbody > tr > td.oee_header {
    background: oklch(0.97 0.005 286) !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 10.5px !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.04em !important;
    padding: 6px 4px !important;
    text-align: center !important;
    border-right: 1px solid var(--border, var(--pp-border)) !important;
    border-bottom: 1px solid var(--border, var(--pp-border)) !important;
}
.equipment-stats-table > tbody > tr > td.oee_value {
    padding: 8px 4px !important;
    text-align: center !important;
    background: transparent !important;
    color: var(--foreground) !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    border-right: 1px solid var(--border, var(--pp-border)) !important;
}
.equipment-stats-table > tbody > tr > td.oee_header:last-child,
.equipment-stats-table > tbody > tr > td.oee_value:last-child {
    border-right: 0 !important;
}

/* 에셋 타임라인 캔버스 — pp-06 의 `display:none` 기본값 오버라이드 + 통일 높이 (180px) */
#asset_timeline.alarm-timeline-canvas {
    display: block !important;
    min-height: 180px;
    height: 180px;
}

/* 설비 연결 상태 타임라인 — 풀폭 + 명시 높이 (PPStatusTimeline width 계산 안전) */
.connection-timeline-wrap {
    width: 100%;
    margin-top: 6px !important;
}
.connection-timeline-canvas {
    width: 100%;
    min-height: 48px;
}


/* ============================================================
 * /storage/index — 데이터 패널 헤더 차트 툴바
 * 컴보박스 컴팩트 (절반 폭)
 * ============================================================ */
.storage-chart-toolbar {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: nowrap;
}
.storage-chart-toolbar > .form-control,
.storage-chart-toolbar > select.form-control,
.storage-chart-toolbar > .form-select,
.storage-chart-toolbar > select.form-select {
    width: auto !important;
    min-width: 0;
    max-width: 80px !important;
    font-size: 11.5px !important;
    padding: 4px 24px 4px 8px !important;
    height: 28px;
}
.storage-chart-toolbar > .input-group {
    width: auto !important;
}
.storage-chart-toolbar > .input-group > .form-control,
.storage-chart-toolbar > .input-group > select.form-control {
    width: auto !important;
    max-width: 70px !important;
    font-size: 11.5px !important;
    padding: 4px 24px 4px 8px !important;
    height: 28px;
}
.storage-chart-toolbar .input-group-text {
    font-size: 11px !important;
    padding: 4px 8px !important;
}

/* storage/index — 차트 컨테이너 + empty 오버레이 중앙 배치 */
.storage-chart-cover {
    position: relative;
    min-height: 280px;
    display: flex;
    flex-direction: column;
}
.storage-chart {
    flex: 1 1 auto;
    width: 100%;
    min-height: 240px;
}
.storage-chart-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    margin: 0 !important;
    padding: 0 !important;
    pointer-events: none;
}
.storage-chart-overlay .pp-empty-state__text {
    margin-top: 8px;
}
.storage-chart-overlay .pp-empty-state__sub {
    margin-top: 4px;
}
.storage-chart-loading-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid var(--pp-border);
    border-radius: 999px;
    font-size: 12px;
    color: var(--pp-muted-fg);
}


/* ============================================================
 * /alarm/index — 타임라인 패널 높이 + 노드 아이콘 디자인
 * ============================================================ */
body #alarm_timeline.alarm-timeline-canvas {
    display: block !important;
    min-height: 160px;
    height: 160px;
}
.order-timeline-body #alarm_timeline_cover {
    min-height: 160px;
}

/* 알람 타임라인 노드 — round chip + priority 컬러 */
body .alarm-tbox-info,
body .alarm-tbox-warn,
body .alarm-tbox-error {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 1px solid transparent !important;
    border-radius: 50% !important;
    color: var(--pp-white) !important;
    font-size: 11px !important;
    line-height: 1 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    cursor: pointer;
    transition: transform 0.12s, box-shadow 0.12s;
}
body .alarm-tbox-info  { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; color: var(--pp-white) !important; }
body .alarm-tbox-warn  { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; color: var(--pp-white) !important; }
body .alarm-tbox-error { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; color: var(--pp-white) !important; }
body .alarm-tbox-info:hover,
body .alarm-tbox-warn:hover,
body .alarm-tbox-error:hover {
    transform: translateY(-1px) scale(1.08);
    box-shadow: 0 3px 8px rgba(15, 23, 42, 0.26), inset 0 0 0 1px rgba(255,255,255,0.16) !important;
}
body .alarm-tbox-info > i,
body .alarm-tbox-warn > i,
body .alarm-tbox-error > i {
    color: var(--pp-white) !important;
    font-size: 11px !important;
}
/* off 상태(꺼짐) — 반투명 */
body .alarm-tbox-info > .fa-bell-slash,
body .alarm-tbox-warn > .fa-bell-slash,
body .alarm-tbox-error > .fa-bell-slash { opacity: 0.55 !important; }

/* 최근 알람 — 태그 | 위치 셀 (250px 고정 + ellipsis) */
.alarm-tag-cell {
    max-width: 250px;
    min-width: 0;
}
.alarm-tag-cell .alarm-tag-name {
    display: block;
    color: var(--foreground) !important;
    text-decoration: none !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 100%;
}
.alarm-tag-cell .alarm-tag-name:hover {
    color: var(--primary, var(--pp-primary-strong)) !important;
    text-decoration: underline !important;
}
.alarm-tag-cell .alarm-tag-loc {
    font-size: 11px !important;
    color: var(--muted-foreground, #9ca3af) !important;
    margin-top: 3px !important;
    padding-top: 3px !important;
    border-top: 1px dashed var(--border, var(--pp-border)) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 100%;
}

/* 최근 알람 — 내용 셀 priority 컬러 (공통 td-ellipsis-cell 위에 색만 덧입힘)
   ellipsis 처리는 .td-ellipsis-cell + td.td-ellipsis 공통 패턴이 담당. */
body a.td-ellipsis-cell {
    font-weight: 600 !important;
    color: var(--foreground) !important;
    text-decoration: none !important;
}
body a.td-ellipsis-cell:hover { text-decoration: underline !important; }
body .td-ellipsis-cell.alarm-desc-info  { color: var(--pp-tone-info-bg) !important; }
body .td-ellipsis-cell.alarm-desc-warn  { color: var(--pp-tone-warn-bg) !important; }
body .td-ellipsis-cell.alarm-desc-error { color: var(--pp-tone-danger-bg) !important; }

/* ===========================================================================
 * 환경설정 다이얼로그 (PPSettings) — 화면 배율 슬라이더 + 토글 스위치
 * 모든 selector 에 body .bootstrap-dialog.pp-settings-dialog 프리픽스 부여
 * (BootstrapDialog .modal-body 와의 specificity 경쟁에서 이기도록)
 * =========================================================================== */
body .bootstrap-dialog.pp-settings-dialog .modal-body { padding: 12px 18px !important; }
body .bootstrap-dialog.pp-settings-dialog .pp-settings-body { padding: 0 !important; }
body .bootstrap-dialog.pp-settings-dialog .pp-settings-row {
    display: flex !important;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 16px;
    padding: 14px 4px !important;
    border-bottom: 1px solid var(--pp-border) !important;
    margin: 0 !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-settings-row:last-child { border-bottom: 0 !important; }
body .bootstrap-dialog.pp-settings-dialog .pp-settings-label {
    flex: 1 1 220px;
    min-width: 180px;
    font-size: 13px !important;
    font-weight: 600 !important;
    color: var(--foreground, #0f172a) !important;
    line-height: 1.4 !important;
    margin: 0 !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-settings-label > i {
    color: var(--primary, var(--pp-primary-strong)) !important;
    margin-right: 6px !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-settings-sub {
    font-size: 11px !important;
    font-weight: 400 !important;
    color: var(--secondary-foreground, var(--pp-muted-fg)) !important;
    margin-top: 3px !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-settings-control {
    display: inline-flex !important;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
}

/* 화면 배율 슬라이더 */
body .bootstrap-dialog.pp-settings-dialog .pp-settings-slider {
    -webkit-appearance: none;
    appearance: none;
    width: 280px;
    height: 6px;
    background: var(--pp-border) !important;
    border-radius: 999px !important;
    outline: none !important;
    cursor: pointer;
    padding: 0 !important;
    margin: 0 !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-settings-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 18px;
    height: 18px;
    background: var(--primary, var(--pp-primary-strong)) !important;
    border: 2px solid var(--pp-white) !important;
    border-radius: 50% !important;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(0, 61, 143, 0.4) !important;
    color: var(--pp-white) !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-settings-slider::-moz-range-thumb {
    width: 18px;
    height: 18px;
    background: var(--primary, var(--pp-primary-strong)) !important;
    border: 2px solid var(--pp-white) !important;
    border-radius: 50% !important;
    cursor: pointer;
    color: var(--pp-white) !important;
}
body .bootstrap-dialog.pp-settings-dialog .pp-settings-value {
    font-size: 13px !important;
    font-weight: 700 !important;
    color: var(--primary, var(--pp-primary-strong)) !important;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    min-width: 48px;
    text-align: right !important;
}
/* pp-settings-marks 는 다이얼로그에서 제거되어 더 이상 사용 안 함 (text 라벨 80~100% 표기 불필요).
   레거시 호환을 위해 selector 만 유지하되 display:none. */

/* 토글 스위치 — iOS 스타일 (PPSettings + 디자인 시스템 카탈로그 공통) */
.pp-toggle {
    position: relative;
    display: inline-block;
    width: 44px;
    height: 24px;
    margin: 0 !important;
    vertical-align: middle;
}
.pp-toggle input { opacity: 0 !important; width: 0; height: 0; }
.pp-toggle-slider {
    position: absolute;
    cursor: pointer;
    inset: 0;
    background: var(--pp-text-soft) !important;
    border-radius: 999px !important;
    transition: background 0.2s;
}
.pp-toggle-slider::before {
    content: '';
    position: absolute;
    height: 18px; width: 18px;
    left: 3px; top: 3px;
    background: var(--pp-white) !important;
    border-radius: 50% !important;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2) !important;
    transition: transform 0.2s;
}
.pp-toggle input:checked + .pp-toggle-slider {
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}
.pp-toggle input:checked + .pp-toggle-slider::before {
    transform: translateX(20px);
}

/* 하위 호환 — 이전 .alarm-desc-cell 참조하던 곳도 동작 유지 */
body .alarm-desc-cell {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    text-align: left !important;
    font-weight: 600 !important;
    color: var(--foreground) !important;
    text-decoration: none !important;
}
body .alarm-desc-cell:hover { text-decoration: underline !important; }
body .alarm-desc-cell.alarm-desc-info  { color: var(--pp-tone-info-bg) !important; }
body .alarm-desc-cell.alarm-desc-warn  { color: var(--pp-tone-warn-bg) !important; }
body .alarm-desc-cell.alarm-desc-error { color: var(--pp-tone-danger-bg) !important; }

/* analysis 알람 기간 input 폭 +60px (search-input-280 → 340) */
.search-input-340 {
    width: 340px !important;
    max-width: 340px;
}

/* /diagnostic/index — 타임라인 캔버스 적정 높이 (180px) */
body .diagnostic-timeline #alarm_timeline.alarm-timeline-canvas {
    display: block !important;
    height: 180px !important;
    min-height: 180px !important;
}

/* /log/index — 타임라인 패널 높이 적정 (콘텐츠 ≈ 차트 높이 맞춤) */
body #alarm_timeline {
    display: block !important;
    min-height: 180px;
}
body .order-timeline-body #alarm_timeline_cover {
    min-height: 180px;
}

/* /log/index — 로그 레벨 뱃지 (on-dark, 표준 단색 + 표준 box-shadow) */
body .log-level-info,
body .log-level-warn,
body .log-level-error,
body #page-wrapper .log-level-info,
body #page-wrapper .log-level-warn,
body #page-wrapper .log-level-error {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 64px;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    font-size: 10.5px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    justify-content: center;
}
body .log-level-info,  body #page-wrapper .log-level-info  { background: var(--pp-tone-info-bg) !important; color: var(--pp-white) !important; }
body .log-level-warn,  body #page-wrapper .log-level-warn  { background: var(--pp-tone-warn-bg) !important; color: var(--pp-white) !important; }
body .log-level-error, body #page-wrapper .log-level-error { background: var(--pp-tone-danger-bg) !important; color: var(--pp-white) !important; }
body .log-level-info > i,
body .log-level-warn > i,
body .log-level-error > i {
    color: rgba(255, 255, 255, 0.95) !important;
    font-size: 9.5px !important;
}
body .log-level-info > b,
body .log-level-warn > b,
body .log-level-error > b { color: var(--pp-white) !important; }

/* /log/index — 애플리케이션 뱃지 (on-dark, gray-500) */
body .log-app-badge,
body #page-wrapper .log-app-badge {
    display: inline-flex !important;
    align-items: center;
    gap: 4px;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    font-size: 10.5px !important;
    font-weight: 700 !important;
    background: var(--pp-muted-fg) !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    justify-content: center;
}
body .log-app-badge > i,
body #page-wrapper .log-app-badge > i {
    color: rgba(255, 255, 255, 0.95) !important;
    font-size: 9.5px !important;
}

/* /config/index — config_value 셀 ellipsis (description 은 공통 td-ellipsis-cell 사용)
   .config-desc-cell 은 [DEPRECATED]: 공통 td-ellipsis-cell 로 통일. alias 만 남김. */
.config-value-cell {
    max-width: 360px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}
.config-value-cell {
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    font-size: 12px !important;
}

/* /diagnostic/index — 레벨 뱃지 (on-dark) */
body .level-badge-info,
body .level-badge-warn,
body .level-badge-error,
body #page-wrapper .level-badge-info,
body #page-wrapper .level-badge-warn,
body #page-wrapper .level-badge-error {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 64px;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    font-size: 10.5px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: none !important;
    justify-content: center;
}
body .level-badge-info,  body #page-wrapper .level-badge-info  { background: var(--pp-tone-info-bg) !important; color: var(--pp-white) !important; }
body .level-badge-warn,  body #page-wrapper .level-badge-warn  { background: var(--pp-tone-warn-bg) !important; color: var(--pp-white) !important; }
body .level-badge-error, body #page-wrapper .level-badge-error { background: var(--pp-tone-danger-bg) !important; color: var(--pp-white) !important; }
body .level-badge-info > i,
body .level-badge-warn > i,
body .level-badge-error > i { font-size: 9px !important; color: rgba(255,255,255,0.9) !important; }

/* /user/index — 역할 뱃지 (on-dark) */
body .role-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    font-size: 10.5px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    text-transform: uppercase !important;
}
body .role-badge.role-ADMIN   { background: #991b1b !important; color: var(--pp-white) !important; }
body .role-badge.role-MANAGER { background: var(--pp-primary-strong) !important; color: var(--pp-white) !important; }
body .role-badge.role-USER    { background: oklch(0.35 0.04 260) !important; color: var(--pp-white) !important; }
body .role-badge.role-GUEST   { background: oklch(0.45 0.02 286) !important; color: var(--pp-white) !important; }


/* ============================================================
 * /order/view — 요약 정보 패널 (alarm-view-summary-table 패턴)
 * ============================================================ */
.order-view-summary-table {
    margin: 0 !important;
    table-layout: fixed;
}
.order-view-summary-table thead th {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
    background: var(--muted, #f8fafc) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    padding: 8px 10px !important;
    vertical-align: middle;
}
.order-view-summary-table tbody td {
    vertical-align: middle;
    padding: 12px 10px !important;
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
}
.order-view-th-status { width: 280px; text-align: left; }
.order-view-th-rate   { width: 110px; }
.order-view-th-good   { width: 110px; }
.order-view-th-bad    { width: 110px; }
.order-view-th-target { width: 110px; }

.order-view-cell-status {
    text-align: center !important;
}
.order-view-stat {
    font-weight: 700 !important;
    font-size: 15px !important;
    color: var(--foreground, #111827) !important;
}
.order-view-stat-unit {
    margin-left: 2px !important;
    font-size: 12px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 500 !important;
}
.order-view-stat-good { color: var(--pp-tone-success-bg) !important; }
.order-view-stat-bad  { color: var(--pp-tone-danger-bg) !important; }

/* === pp-46-flow-snapshot-stream.css === */
/* ============================================================================
 * pp-09f-flow-snapshot-stream.css
 * SCOPE  : FLOW / ERROR / SNAPSHOT / STREAM / TOAST
 * 영역   : /flow/index 셀, 에러 페이지 (400/403/404/500), /storage 카운트 뱃지, /snapshot/index 알람 캔버스, /stream/index 실시간 카드, PP.alarmToast / PP.diagToast
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /flow/index — 이름·설명 셀 (250px 고정 + ellipsis)
 * ============================================================ */
.flow-col-name-desc {
    max-width: 250px;
    width: 250px;
}
.flow-name-cell {
    max-width: 250px;
    min-width: 0;
}
.flow-name-cell .flow-name {
    display: block;
    font-weight: 600 !important;
    color: var(--foreground) !important;
    text-decoration: none !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 100%;
}
.flow-name-cell .flow-name:hover {
    color: var(--primary, var(--pp-primary-strong)) !important;
    text-decoration: underline !important;
}
.flow-name-cell .flow-desc {
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-top: 3px !important;
    padding-top: 3px !important;
    border-top: 1px dashed var(--border, var(--pp-border)) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 100%;
}


/* ============================================================
 * 에러 페이지 (400 / 403 / 404 / 500) — 디자인 시스템 통일
 * ============================================================ */
.pp-error-card {
    width: 100%;
    max-width: 480px;
    background: var(--card, var(--pp-white)) !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 16px !important;
    box-shadow:
        0 20px 50px -12px rgba(15, 23, 42, 0.18),
        0 8px 20px -6px rgba(15, 23, 42, 0.08) !important;
    padding: 36px 40px 32px !important;
    text-align: center !important;
    position: relative;
    overflow: hidden;
}
/* 상단 컬러 stripe */
.pp-error-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 4px;
    background: var(--primary, var(--pp-primary-strong)) !important;
    color: var(--pp-white) !important;
}

.pp-error-logo > img {
    max-height: 36px;
    width: auto;
}




.pp-error-actions .btn-lg {
    min-width: 130px;
}


/* ============================================================
 * /storage/index — 전체 데이터 카운트 뱃지 (온다크)
 * ============================================================ */
.storage-total-badge {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px !important;
    /* deep navy → teal 그라디언트 — 시계열 데이터를 연상시키는 cool 톤 */
    background: linear-gradient(135deg, #0f3460 0%, #16537e 50%, #1a7a8a 100%) !important;
    color: var(--pp-white) !important;
    border: 1px solid rgba(255, 255, 255, 0.10) !important;
    border-radius: 10px !important;
    font-size: 12.5px !important;
    font-weight: 600 !important;
    letter-spacing: 0.01em !important;
    line-height: 1.4 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    margin-bottom: 12px !important;
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
}
.storage-total-badge > i {
    font-size: 14px !important;
    color: #5eead4 !important;             /* teal-300, 강조 아이콘 */
    flex-shrink: 0;
}
.storage-total-badge > span,
.storage-total-badge > span * {
    color: var(--pp-white) !important;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}

/* /storage/index — 헤더 우측 끝 시계열 분석기 외부 링크 버튼 */
.storage-analyzer-btn {
    margin-left: 6px !important;
    border-left: 1px solid var(--pp-border) !important;
    padding-left: 16px !important;
}
.storage-analyzer-btn > i {
    color: #1a7a8a !important;
}


/* ============================================================
 * /snapshot/index — 알람 타임라인 캔버스 표시 + 심각 알람 범례
 * 타임라인 차트 통일 높이: 180px (PPTimeline.init height 와 일치)
 * ============================================================ */
#alarm_timeline.alarm-timeline-canvas,
#control_timeline,
#data_timeline {
    display: block !important;
    min-height: 180px;
    height: 180px;
}

/* 패널 헤더 우측 심각 알람 범례 (segmented pill) */
.snapshot-legend {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px !important;
    font-weight: 500 !important;
}
.snapshot-legend-label {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    margin-right: 6px !important;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.snapshot-legend-label > i {
    color: oklch(0.55 0.22 25) !important;
}
.snapshot-legend-cell {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    height: 22px;
    padding: 0 8px !important;
    color: #7f1d1d !important;
    font-weight: 600 !important;
    border: 1px solid rgba(220, 38, 38, 0.18) !important;
}
.snapshot-legend-cell + .snapshot-legend-cell {
    border-left: 0 !important;
}
.snapshot-legend-cell:first-of-type {
    border-top-left-radius: 999px !important;
    border-bottom-left-radius: 999px !important;
    padding-left: 12px !important;
}
.snapshot-legend-cell:last-of-type {
    border-top-right-radius: 999px !important;
    border-bottom-right-radius: 999px !important;
    padding-right: 12px !important;
}
.snapshot-legend-l1 { background: #FFE5E5 !important; }
.snapshot-legend-l2 { background: #FFC2C2 !important; }
.snapshot-legend-l3 { background: #FF9999 !important; color: #5a0000 !important; }
.snapshot-legend-l4 { background: #FF6666 !important; color: var(--pp-white) !important; }
.snapshot-legend-l5 { background: var(--pp-tone-danger-bg) !important; color: var(--pp-white) !important; border-color: var(--pp-tone-danger-bg) !important; }

/* 스냅샷 데이터 셀 (인라인 style 대체) */
.snapshot-dt > tbody > tr > td.snapshot-cell {
    text-align: center !important;
    max-width: 100px;
    min-width: 50px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 12px !important;
}
.snapshot-dt > tbody > tr > td.snapshot-l1 { background: #FFCCCC !important; }
.snapshot-dt > tbody > tr > td.snapshot-l2 { background: #FF9999 !important; }
.snapshot-dt > tbody > tr > td.snapshot-l3 { background: #FF6666 !important; color: var(--pp-white) !important; }
.snapshot-dt > tbody > tr > td.snapshot-l4 { background: #FF3333 !important; color: var(--pp-white) !important; }
.snapshot-dt > tbody > tr > td.snapshot-l5 { background: #FF0000 !important; color: var(--pp-white) !important; }
.snapshot-dt > tbody > tr > th.row-header {
    border-left: 3px solid var(--pp-border) !important;
    max-width: 160px;
    min-width: 160px;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 12px !important;
    font-weight: 600 !important;
}

/* 스냅샷 테이블 — 외곽 보더 0, 가로 스크롤 (컬럼 많을 때 우측으로 드래그) */
.snapshot-panel-body {
    padding: 0 !important;
}
.snapshot-table-wrap {
    overflow-x: auto;
    overflow-y: hidden;
    border: 0 !important;
    border-radius: 0 !important;
}
.snapshot-empty {
    padding: 32px !important;
    text-align: center !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    font-size: 13px !important;
}
.snapshot-empty > i { margin-right: 6px !important; }

/* 래퍼 스코프로 특이도(0,2,0)를 올려 표준 패널 룰
   `.dataTables_wrapper table`(0,1,1)의 border-top 을 이겨 보더리스 의도를 관철.
   기존 보더리스 선언을 더 구체적인 선택자로 옮긴 것(룰 추가 아님). */
.snapshot-table-wrap .snapshot-dt {
    margin-bottom: 0 !important;
    width: auto !important;
    min-width: 100%;
    border: 0 !important;
}
/* 헤더 첫 행 th 의 상단 1px(pp-20-panels 표준 룰)을 스냅샷에서만 제거 —
   스냅샷 테이블은 보더리스라 헤더 상단 보더가 고립되어 보임. */
.snapshot-table-wrap .snapshot-dt > thead > tr:first-child > th {
    border-top: 0 !important;
}
/* thead th / tbody td 의 일반 스타일(배경·보더·패딩·폰트)은 표준 패널 DataTable
   룰(pp-20-panels.css)을 그대로 상속 — 스냅샷 전용 분기 제거(표준과 일관). */
.snapshot-dt tbody td.snapshot-time {
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 12px !important;
    color: var(--foreground, #0f172a) !important;
    font-weight: 600 !important;
    background: var(--muted, #f8fafc) !important;
    position: sticky;
    left: 0;
    z-index: 1;
}
.snapshot-dt tbody tr:hover td.snapshot-time { background: #eef2f6 !important; }

/* DataTable wrapper — 좌우 패딩 0 으로 카드바디 폭에 꽉 채움(표준 알람 목록과 동일 정렬).
   상하 패딩만 유지(필터/길이/페이징 컨트롤 간격). */
#snapshot_dt_wrapper {
    padding: 8px 0 4px !important;
}
#snapshot_dt_wrapper .dataTables_filter input,
#snapshot_dt_wrapper .dataTables_length select {
    border-radius: 6px !important;
}

/* 하단 — 심각 알람 합계 (panel-body 끝, DataTable 페이징 아래) */
#snapshot_table .table-header-rotated thead th {
    background: oklch(97% 0.005 286) !important;
    border-bottom: 1px solid var(--border, var(--pp-border)) !important;
}
#snapshot_table .table-header-rotated tbody td {
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    font-size: 11.5px !important;
    text-align: center !important;
}
#snapshot_table .row-header.headcol {
    background: oklch(99% 0.002 286) !important;
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    font-size: 11.5px !important;
    font-weight: 500 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    border-left: 0 !important;
}


/* ============================================================
 * /stream/index — 실시간 태그 카드 (stream-box)
 * 한 태그 = 한 카드. 헤더(태그ID/명) + chart 영역 + 현재값/알람
 * ============================================================ */
.stream-content {
    list-style: none;
    padding: 0 !important;
    margin: 0 !important;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.stream-box {
    background: var(--card, var(--pp-white)) !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 10px !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04) !important;
    overflow: hidden;
    transition: box-shadow 0.15s;
}
.stream-box:hover {
    box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06) !important;
}
.stream-box-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px !important;
    background: oklch(98% 0.003 286) !important;
    border-bottom: 1px solid var(--border, var(--pp-border)) !important;
}
.stream-box-header > i {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 14px !important;
    flex-shrink: 0;
}
.stream-box-header > a {
    color: var(--foreground) !important;
    text-decoration: none !important;
    font-weight: 600 !important;
}
.stream-box-header > a:hover { text-decoration: underline !important; }
.stream-box-header .stream-box-desc {
    flex: 1 1 auto;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 12px !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    margin-left: 4px !important;
}
.stream-box-header .float-end {
    flex: 0 0 auto;
    margin-left: auto !important;
}
.stream-box-divider { display: none; }

/* 카드 본문 — 차트(좌) + 현재값(우). 태그 패널 전체 높이 240px */
.stream-body {
    display: flex;
    align-items: stretch;
    min-height: 200px;          /* 본문 200px + 헤더 ~40px = 240px */
}
.stream-chart-col {
    flex: 1 1 auto;
    min-width: 0;
    padding: 10px 14px !important;
    border-right: 1px solid var(--border, var(--pp-border)) !important;
    display: flex;
    align-items: stretch;
}
.stream-chart-area,
.stream-chart-boolean,
.stream-box-content-boolean {
    width: 100%;
    height: 100%;
    min-height: 180px;
}
.stream-value-col {
    flex: 0 0 220px;
    padding: 10px 14px 10px 16px !important;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: stretch;
    position: relative;
    background: linear-gradient(135deg, oklch(99% 0.002 286) 0%, oklch(97% 0.005 286) 100%) !important;
}
.stream-alarm-pos {
    position: absolute;
    top: 8px;
    right: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50% !important;
    background: rgba(15, 23, 42, 0.04) !important;
}
.stream-alarm-icon {
    font-size: 12px !important;
}
.stream-alarm-icon.alarm-off { color: var(--muted-foreground, #9ca3af) !important; }
.stream-value-inner {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
}
.stream-value-txt {
    font-size: 26px !important;
    font-weight: 700 !important;
    color: var(--foreground) !important;
    line-height: 1.1 !important;
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    letter-spacing: -0.02em !important;
    display: inline-flex;
    align-items: baseline;
    justify-content: flex-end;
    flex-wrap: wrap;
}

/* 수신 대기중 pill — 칩 스타일 */
.stream-value-txt .stream-waiting,
.stream-waiting {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px !important;
    border-radius: 999px !important;
    background: rgba(15, 23, 42, 0.05) !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    font-size: 11px !important;
    font-weight: 500 !important;
    letter-spacing: 0 !important;
    line-height: 1 !important;
}
.stream-waiting > i {
    font-size: 10px !important;
    color: oklch(0.55 0.10 240) !important;
}

.stream-last-updated {
    font-size: 10px !important;
    color: var(--muted-foreground, #9ca3af) !important;
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    letter-spacing: 0.02em !important;
}

/* 좁은 화면 — 본문 세로 스택 */
@media (max-width: 1100px) {
    .stream-body { flex-direction: column; min-height: 0; }
    .stream-chart-col { border-right: 0 !important; border-bottom: 1px solid var(--border, var(--pp-border)) !important; }
    .stream-value-col {
        flex: 0 0 auto;
        align-items: center;
        background: transparent !important;
    }
    .stream-alarm-pos { position: static; margin-bottom: 4px !important; }
}

/* 설비 기본 정보 블록 — 헬스 타임라인 아래 상단 마진 +24px */
.equipment-basic-info-block {
    margin-top: 24px !important;
}

/* 우측 컬럼 — 최근 알람/상태/집계/명령 히스토리 뷰 공통 크기.
 * DataTables 초기화 후 스크롤바 없음 (overflow:hidden), 높이는 내용에 맞춤. */
.equipment-history-view {
    min-height: 0;
    overflow: hidden;
}

/* 헬스 타임라인 wrap */
.equipment-health-timeline-wrap {
    position: relative;
    margin-top: 14px !important;
    border: 1px solid var(--border, var(--pp-border)) !important;
    border-radius: 8px !important;
    padding: 8px !important;
    background: var(--card, var(--pp-white)) !important;
}
.equipment-health-timeline-canvas {
    min-height: 70px;
}

/* 에셋 타임라인 빈 상태 — 데이터 없을 때 캔버스 위에 오버레이 */
.asset-timeline-cover {
    position: relative;
    min-height: 280px;
}
.asset-timeline-empty {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: transparent !important;
    pointer-events: none;
}
.asset-timeline-empty .pp-empty-state__icon {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-size: 28px !important;
    margin-bottom: 8px !important;
}
.asset-timeline-empty .pp-empty-state__text {
    font-size: 13px !important;
    font-weight: 600 !important;
    color: var(--foreground) !important;
    margin-bottom: 4px !important;
}
.asset-timeline-empty .pp-empty-state__sub {
    font-size: 11.5px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-align: center !important;
}
.alarm-timeline-canvas.is-empty {
    opacity: 0.5 !important;
}

/* ============================================================
 * PP.alarmToast — 하단 알람 토스트 (디자인 시스템 신설)
 * 우하단 카드 스택, 우선순위별 컬러, progress bar, 클릭 시 알람 상세
 * ============================================================ */
.pp-alarm-toast-container {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: 99999;
    width: 380px;
    max-width: calc(100vw - 32px);
    display: flex;
    flex-direction: column-reverse;
    gap: 10px;
    pointer-events: none;        /* 컨테이너는 클릭 통과, 카드만 받음 */
}

.pp-alarm-toast {
    pointer-events: auto;
    position: relative;
    display: flex;
    align-items: stretch;
    /* 사이드바 로고 영역과 동일한 진한 다크 네이비 + 살짝 투명도 (배경이 비치도록) */
    background: oklch(0.11 0.08 260 / 0.92) !important;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--pp-white) !important;
    border: 1px solid rgba(255, 255, 255, 0.10) !important;
    border-radius: 12px !important;
    overflow: hidden;
    box-shadow: 0 14px 38px rgba(0, 0, 0, 0.45), 0 4px 10px rgba(0, 0, 0, 0.25) !important;
    cursor: pointer;
    transform: translate(20px, 8px);
    opacity: 0 !important;
    transition: transform 0.25s cubic-bezier(.2,.7,.3,1.1), opacity 0.2s, box-shadow 0.2s;
    isolation: isolate;
}
.pp-alarm-toast.is-shown {
    transform: translate(0, 0);
    opacity: 1 !important;
}
.pp-alarm-toast.is-leaving {
    transform: translate(20px, 0);
    opacity: 0 !important;
}
.pp-alarm-toast:hover {
    box-shadow: 0 18px 44px rgba(15, 23, 42, 0.40), 0 6px 14px rgba(15, 23, 42, 0.20) !important;
}

/* 좌측 컬러 stripe 제거 — 알람 토스트 좌측 색상 보더 미표시 (우선순위는 priority pill 로 충분).
 * 마크업(.pp-alarm-toast-stripe 요소)은 pp-util.js 가 계속 생성하므로 표시만 끈다. */
.pp-alarm-toast-stripe {
    display: none !important;
}

.pp-alarm-toast-body {
    flex: 1 1 auto;
    padding: 12px 14px 14px !important;
    min-width: 0;
}

.pp-alarm-toast-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px !important;
}

.pp-alarm-toast-priority {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.3px !important;
    text-transform: uppercase !important;
    padding: 3px 8px !important;
    border-radius: 999px !important;
    border: 1px solid transparent !important;
    background: rgba(255, 255, 255, 0.10) !important;
    flex-shrink: 0;
}
.pp-alarm-toast.is-info  .pp-alarm-toast-priority { color: var(--pp-white) !important; background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; }
.pp-alarm-toast.is-warn  .pp-alarm-toast-priority { color: var(--pp-white) !important; background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; }
.pp-alarm-toast.is-error .pp-alarm-toast-priority { color: var(--pp-white) !important; background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; }

.pp-alarm-toast-seq {
    font-size: 11px !important;
    color: rgba(255, 255, 255, 0.55) !important;
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    letter-spacing: 0.2px !important;
    flex-shrink: 0;
}

.pp-alarm-toast-tag {
    font-size: 11.5px !important;
    font-weight: 600 !important;
    color: rgba(255, 255, 255, 0.85) !important;
    background: rgba(255, 255, 255, 0.06) !important;
    padding: 2px 8px !important;
    border-radius: 4px !important;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}

.pp-alarm-toast-close {
    flex: 0 0 26px;
    width: 26px;
    height: 26px;
    border-radius: 50% !important;
    border: 0 !important;
    background: rgba(255, 255, 255, 0.06) !important;
    color: rgba(255, 255, 255, 0.65) !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px !important;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    padding: 0 !important;
}
.pp-alarm-toast-close:hover {
    background: rgba(255, 255, 255, 0.16) !important;
    color: var(--pp-white) !important;
}

.pp-alarm-toast-desc {
    font-size: 13px !important;
    line-height: 1.5 !important;
    color: var(--pp-white) !important;
    word-break: break-word;
    margin-bottom: 6px !important;
}

.pp-alarm-toast-loc {
    font-size: 11px !important;
    color: rgba(255, 255, 255, 0.60) !important;
    display: flex;
    align-items: center;
    gap: 4px;
    padding-top: 6px !important;
    border-top: 1px dashed rgba(255, 255, 255, 0.10) !important;
}
.pp-alarm-toast-loc > i {
    font-size: 10px !important;
    opacity: 0.7 !important;
}

/* 하단 progress bar — 자동 dismiss 까지 남은 시간 시각화 */
.pp-alarm-toast-progress {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: rgba(255, 255, 255, 0.06) !important;
    overflow: hidden;
}
.pp-alarm-toast-progress::after {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(255, 255, 255, 0.40) !important;
    transform-origin: left center;
    animation-name: pp-alarm-toast-progress;
    animation-timing-function: linear;
    animation-fill-mode: forwards;
}
.pp-alarm-toast.is-info  .pp-alarm-toast-progress::after { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; }
.pp-alarm-toast.is-warn  .pp-alarm-toast-progress::after { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; }
.pp-alarm-toast.is-error .pp-alarm-toast-progress::after { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; }

@keyframes pp-alarm-toast-progress {
    0%   { transform: scaleX(1); }
    100% { transform: scaleX(0); }
}


/* ============================================================
 * PP.diagToast — ADMIN 진단 알림 ($.notify 래핑, 우상단 on-dark 카드)
 * 일반 알람(PP.alarmToast) 과 시각/위치 분리
 * ============================================================ */
.notifyjs-pp-diag-base {
    background: transparent !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 8px 0 !important;
    min-width: 320px;
    max-width: 420px;
}

.pp-diag-notify {
    /* 사이드바 로고 영역과 동일한 진한 다크 네이비 + 살짝 투명도 */
    background: oklch(0.11 0.08 260 / 0.92) !important;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--pp-white) !important;
    border: 1px solid rgba(255, 255, 255, 0.10) !important;
    border-radius: 10px !important;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.40), 0 3px 8px rgba(0, 0, 0, 0.22) !important;
    padding: 10px 14px !important;
    font-size: 13px !important;
    line-height: 1.5 !important;
    cursor: pointer;
    transition: filter 0.15s, box-shadow 0.15s;
}
.pp-diag-notify:hover {
    filter: brightness(1.08);
    box-shadow: 0 14px 32px rgba(0, 61, 143, 0.40), 0 4px 10px rgba(0, 61, 143, 0.22) !important;
}

/* 좌측 컬러 보더(level 별 border-left) 제거 — 진단 토스트 좌측 색상 보더 미표시.
 * level 구분은 아래 head 컬러로 유지. */

.pp-diag-notify-head {
    font-size: 10px !important;
    font-weight: 700 !important;
    letter-spacing: 0.5px !important;
    text-transform: uppercase !important;
    color: rgba(255, 255, 255, 0.62) !important;
    margin-bottom: 4px !important;
}
.pp-diag-notify-head > i {
    font-size: 11px !important;
    margin-right: 3px !important;
}
.pp-diag-notify-host {
    color: rgba(255, 255, 255, 0.78) !important;
    font-family: 'JetBrains Mono', 'Consolas', monospace !important;
    font-size: 10.5px !important;
    text-transform: none !important;
}

.pp-diag-notify-msg {
    color: rgba(255, 255, 255, 0.95) !important;
    word-break: break-word;
}

/* level 별 head 컬러 (좌측 stripe 는 제거됨) */
.pp-diag-notify-info    .pp-diag-notify-head { color: #93c5fd !important; }
.pp-diag-notify-success .pp-diag-notify-head { color: #86efac !important; }
.pp-diag-notify-warn    .pp-diag-notify-head { color: #fde68a !important; }
.pp-diag-notify-error   .pp-diag-notify-head { color: #fecaca !important; }


/* === pp-47-alarmview.css === */
/* ============================================================================
 * pp-09g-alarmview.css
 * SCOPE  : ALARM VIEW / TIMELINE / BLOB STORE / ALARM CONFIG
 * 영역   : /alarm/view 디자인 시스템 표준, 사이드바 닫힘 툴팁, /timeline/index, /blob/store, /alarm/advsearch, /alarm/config/form
 * 주의   : 본 파일은 pp-09g-alarmview-mapflow.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /alarm/view — 디자인 시스템 표준 (섹션별 패널 분할)
 * ============================================================ */
.alarm-view-summary-table {
    margin: 0 !important;
}
.alarm-view-summary-table thead th {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
    background: var(--muted, #f8fafc) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    padding: 8px 10px !important;
    vertical-align: middle;
}
.alarm-view-summary-table tbody td {
    vertical-align: middle;
    padding: 12px 10px !important;
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
}
.alarm-view-th-priority { width: 180px; }
.alarm-view-th-on { width: 60px; }
.alarm-view-th-start, .alarm-view-th-end { width: 140px; }
.alarm-view-th-tag { width: 28%; }
.alarm-view-th-msg { width: auto; }
.alarm-view-th-read { width: 60px; }

.alarm-view-cell-date {
    line-height: 1.4 !important;
    color: var(--foreground, #111827) !important;
}
.alarm-view-cell-tag a {
    color: var(--primary, var(--pp-primary)) !important;
    font-weight: 600 !important;
}
.alarm-view-tag-divider {
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
    margin: 4px 0 !important;
}
.alarm-view-cell-msg {
    line-height: 1.5 !important;
}
.alarm-view-msg {
    text-align: left !important;
    font-weight: 500 !important;
}
.alarm-view-msg-info  { color: var(--pp-tone-info-bg) !important; }
.alarm-view-msg-warn  { color: var(--pp-tone-warn-bg) !important; }
.alarm-view-msg-error { color: var(--pp-tone-danger-bg) !important; }

/* ============================================================
 * /statement/view — alarm-view-summary-table 패턴 재사용
 * 컬럼: 상태 / 스테이트먼트명 / 적용된 에셋 / 유형 / 등록일
 * ============================================================ */
.statement-view-summary-table {
    margin: 0 !important;
}
.statement-view-summary-table thead th {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
    background: var(--muted, #f8fafc) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    padding: 8px 10px !important;
    vertical-align: middle;
}
.statement-view-summary-table tbody td {
    vertical-align: middle;
    padding: 12px 10px !important;
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
}
.statement-view-th-status { width: 130px; }
.statement-view-th-name   { width: auto; }
.statement-view-th-asset  { width: 200px; }
.statement-view-th-type   { width: 140px; }
.statement-view-th-date   { width: 160px; }

.statement-view-cell-name {
    line-height: 1.5 !important;
    color: var(--foreground, #111827) !important;
}
.statement-view-name-link {
    color: var(--primary, var(--pp-primary)) !important;
    font-weight: 600 !important;
}
.statement-view-name-divider {
    border-bottom: 1px solid var(--pp-border, #f3f4f6) !important;
    margin: 4px 0 !important;
}
.statement-view-cell-date {
    line-height: 1.4 !important;
    color: var(--foreground, #111827) !important;
}

/* 마지막 실행 정보 카드 — 에러 메시지 래퍼 상단 마진 (지표 목록(pp:dl)과 간격 분리) */
.stmt-view-error-msg-wrap {
    margin-top: 12px;
}

.alarm-view-chart {
    width: 100%;
    height: 280px;
    margin-bottom: 16px !important;
}

.alarm-view-eql-textarea {
    height: 300px;
    font-family: 'Menlo', 'Monaco', monospace !important;
    font-size: 12px !important;
    background: #fafafa !important;
    resize: vertical;
}

.alarm-view-priority-chart {
    height: 150px;
    text-align: center !important;
    color: var(--muted-foreground, #9ca3af) !important;
}

.alarm-view-tag-meta {
    margin-top: 12px !important;
    padding-top: 10px !important;
    border-top: 1px dashed var(--pp-border) !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}

.form-section-label {
    margin: 14px 0 6px 0 !important;
    padding-bottom: 4px !important;
    border-bottom: 1px dashed var(--pp-border) !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.04em !important;
}
.form-section-label:first-child { margin-top: 0 !important; }
.form-section-label > i { color: var(--primary, var(--pp-primary)) !important; margin-right: 4px !important; }

body .priority-badge-unknown,
body .priority-badge-unknown * {
    display: inline-block;
    padding: 2px 14px !important;
    color: var(--pp-white) !important;
    background: var(--muted-foreground, #9ca3af) !important;
    border-radius: 4px !important;
    font-weight: 600 !important;
}

/* panel-heading 의 보조 안내 텍스트 — sub 옆 더 옅은 보조 정보 */
.card-head-note {
    margin-left: 4px !important;
    font-size: 11px !important;
    font-weight: 500 !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    letter-spacing: 0.01em !important;
}

/* 다이얼로그/모달 내부 폼 그룹 — 1열 풀폭 (사용자 정책).
 * 간격(margin-bottom)은 pp-48 정본(SSOT)에서 12px 로 일괄 부여 — 여기서 중복 지정 금지. */
body .bootstrap-dialog .form-inline,
body .bootstrap-dialog .form-group,
body .modal .form-inline,
body .modal .form-group,
body .bootstrap-dialog .pp-form-row,
body .modal .pp-form-row {
    display: block !important;
    width: 100% !important;
    flex-wrap: nowrap !important;
}

/* 폼 다이얼로그 — 검증 메시지 숨김, 빨간 input border 로만 표시 (사용자 정책) */
.pp-dialog-form-modal label.error,
.pp-dialog-form-modal .form-text.error {
    display: none !important;
}
.pp-dialog-form-modal form-control.is-invalid,
.pp-dialog-form-modal select.is-invalid,
.pp-dialog-form-modal textarea.form-control.is-invalid {
    border-color: #ef4444 !important;
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.14) !important;
}

/* 폼 다이얼로그 공통 — form-help 도움말 + ds-form-error.
 * form-group 간격은 pp-48 정본(12px)에서 일괄 — 여기서 재정의 금지(이전 10px 제거). */
.pp-dialog-form-modal .form-group label.form-label {
    display: block;
    margin-bottom: 3px !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
}
.pp-dialog-form-modal .form-group .form-control { width: 100%; }
.pp-dialog-form-modal .form-help {
    display: block;
    margin: 3px 0 0 !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    line-height: 1.35 !important;
    letter-spacing: 0.01em !important;
}
.pp-dialog-form-modal form-control.is-invalid {
    border-color: #ef4444 !important;
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.12) !important;
}

/* 가상 태그 추가 다이얼로그 — 검증 에러 메시지 레이아웃 (행 안 밀리게).
 * form-group 간격은 pp-48 정본(12px) — 여기서 재정의 금지. */
.vtag-dialog .form-group label.form-label {
    display: block;
    margin-bottom: 4px !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
}
.vtag-dialog .form-group .form-control { width: 100%; }
.vtag-dialog form-control.is-invalid {
    border-color: #ef4444 !important;
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.12) !important;
}
.vtag-dialog .form-group .form-control.checked { border-color: var(--pp-border, var(--pp-text-soft)) !important; }

/* /equipment/index 필터 패널 — 설명 input 과 검색 버튼 사이 빈 공간 축소 */
.page-equipment .card-body,
body.page-equipment .card.card > .card-body {
    padding-bottom: 10px !important;
}
.page-equipment .form-fieldset:last-of-type {
    margin-bottom: 0 !important;
}
.page-equipment .card-footer.card-footer-actions {
    padding: 10px 14px !important;
}


/* ============================================================
 * 사이드바 닫힘 모드 — 메뉴 아이콘 호버 시 오른쪽 툴팁
 * (#navigation overflow:hidden 을 닫힘 모드에서 visible 로 풀어
 *  ::after 가 사이드바 바깥으로 빠져나올 수 있게 함.)
 * ============================================================ */
html.pp-sidebar-collapsed body #navigation { overflow: visible; }
html.pp-sidebar-collapsed body #navigation .sidebar-collapse {
    overflow-y: auto;
    overflow-x: visible;
}
html.pp-sidebar-collapsed body #side-menu,
html.pp-sidebar-collapsed body .pp-nav-section,
html.pp-sidebar-collapsed body .pp-nav-section-items { overflow: visible; }

html.pp-sidebar-collapsed body .pp-nav-section-items a,
html.pp-sidebar-collapsed body #side-menu > li > a {
    position: relative;
}
html.pp-sidebar-collapsed body .pp-nav-section-items a:hover::after,
html.pp-sidebar-collapsed body #side-menu > li > a:hover::after {
    content: attr(data-nav-label);
    position: absolute;
    left: calc(100% + 12px);
    top: 50%;
    transform: translateY(-50%);
    padding: 6px 10px !important;
    background: #0f172a !important;
    color: var(--pp-white) !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    white-space: nowrap !important;
    border-radius: 4px !important;
    box-shadow: 0 4px 10px rgba(0,0,0,0.18) !important;
    z-index: 1080;
    pointer-events: none;
}
html.pp-sidebar-collapsed body .pp-nav-section-items a:hover::before,
html.pp-sidebar-collapsed body #side-menu > li > a:hover::before {
    content: '';
    position: absolute;
    left: calc(100% + 6px);
    top: 50%;
    transform: translateY(-50%);
    border: 6px solid transparent !important;
    border-right-color: #0f172a !important;
    z-index: 1080;
    pointer-events: none;
}


/* ============================================================
 * /timeline/index — 표준화
 * ============================================================ */
.timeline-condition-input {
    width: 350px;
    display: none;
}
.timeline-condition-btn {
    display: none;
}
.timeline-move-input {
    border-top-left-radius: 3px !important;
    border-bottom-left-radius: 3px !important;
}
.timeline-canvas-frame {
    border: 1px solid var(--pp-border) !important;
    border-radius: 12px !important;
    background: var(--pp-white) !important;
    overflow: hidden;
}
.order-timeline-body .timeline-canvas-frame {
    margin: 0 !important;
}

/* 타임라인 상세 모달 */
.timeline-detail-ts-badge {
    padding: 6px 12px !important;
    line-height: 1.4 !important;
    color: var(--pp-white) !important;
    text-align: center !important;
    font-weight: 700 !important;
    background: var(--foreground, #0f172a) !important;
    border-radius: 4px !important;
    margin-bottom: 6px !important;
    letter-spacing: 0.02em !important;
}
.timeline-detail-payload {
    max-height: 260px;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 10px !important;
    background: #fafafa !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    font-family: 'Menlo', 'Monaco', monospace !important;
    font-size: 12px !important;
}


/* ============================================================
 * /blob/store — 버켓 카드 + 푸터 디자인 시스템
 * ============================================================ */
.blob-search-row {
    margin-top: 8px !important;
}
.blob-list-body {
    padding: 8px 10px !important;
}
.blob-loading {
    margin-top: 10px !important;
    text-align: center !important;
    color: var(--muted-foreground, #9ca3af) !important;
    font-size: 12px !important;
}
.blob-list-scroll {
    overflow-y: auto;
    overflow-x: hidden;
    width: 100%;
    max-height: 600px;
    padding-right: 4px !important;
    padding-top: 6px !important;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* 버켓 카드 (shadcn-card 스타일) */
.blob-bucket-card {
    display: flex;
    gap: 10px;
    padding: 10px 12px !important;
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    cursor: pointer;
    transition: border-color 0.12s, box-shadow 0.12s, transform 0.06s;
}
.blob-bucket-card:hover {
    border-color: var(--primary, #3b82f6) !important;
    box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08) !important;
}
.blob-bucket-card.selected,
.blob-bucket-card.blob-box-selected {
    border-color: var(--primary, var(--pp-primary)) !important;
    box-shadow: 0 0 0 2px rgba(29, 78, 216, 0.18) !important;
    background: linear-gradient(180deg, #f0f7ff 0%, var(--pp-white) 60%) !important;
}
.blob-bucket-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #6366f1 0%, #4338ca 100%) !important;
    color: var(--pp-white) !important;
    border-radius: 6px !important;
    font-size: 18px !important;
    box-shadow: 0 2px 6px rgba(67, 56, 202, 0.25) !important;
}
.blob-bucket-body {
    flex: 1;
    min-width: 0;
}
.blob-bucket-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
}
.blob-bucket-actions {
    display: inline-flex;
    gap: 8px;
    color: var(--muted-foreground, #9ca3af) !important;
    font-size: 12px !important;
}
.blob-bucket-actions i {
    cursor: pointer;
    transition: color 0.12s;
}
.blob-bucket-actions i:hover {
    color: var(--primary, var(--pp-primary)) !important;
}
.blob-bucket-name {
    margin-top: 6px !important;
    font-weight: 600 !important;
    font-size: 13px !important;
    color: var(--foreground, #111827) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}
.blob-bucket-desc {
    margin-top: 2px !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}
.blob-bucket-stats {
    margin-top: 8px !important;
    display: inline-flex;
    gap: 6px;
    flex-wrap: wrap;
}
.blob-stat-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px !important;
    background: var(--muted, #f3f4f6) !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 500 !important;
}
.blob-stat-chip i {
    color: var(--primary, var(--pp-primary)) !important;
}

/* 푸터 — model-tree-foot 와 유사한 시각 톤 */
.blob-store-footer {
    padding: 10px 12px !important;
    background: var(--muted, #f8fafc) !important;
    border-top: 1px solid var(--pp-border) !important;
}
.blob-foot-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.blob-foot-label {
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.04em !important;
}
.blob-foot-label i {
    color: var(--primary, var(--pp-primary)) !important;
    margin-right: 2px !important;
}
.blob-foot-meta {
    font-size: 12px !important;
    font-weight: 700 !important;
    color: var(--foreground, #111827) !important;
}


/* ============================================================
 * /alarm/advsearch — 내용 입력칸 (description) 폭 600px
 * ============================================================ */
.alarm-advsearch-desc-input {
    width: 600px !important;
    max-width: 100%;
}


/* ============================================================
 * /alarm/config/form — 디자인 시스템 표준화
 * ============================================================ */
.text-required,
.text-required > i {
    color: var(--pp-tone-danger-bg) !important;
    font-weight: 600 !important;
}
.text-required {
    margin-right: 2px !important;
}
.text-required > i {
    font-size: 0.75em !important;
    /* fa-asterisk 는 x-height 기준이라 라벨(대문자 포함) 대비 살짝 낮음 → 1px 올려 광학 중앙 정렬 */
    vertical-align: middle;
    position: relative;
    top: -1px;
}

/* PP.validate 에러 아이콘 — 입력박스 세로 중앙 (top/right 은 JS 에서 동적 계산) */
.form-group,
.form-inline,
.pp-form-row {
    position: relative;
}
.pp-error-tip {
    position: absolute;
    right: 10px;
    color: var(--pp-tone-danger-bg) !important;
    cursor: help;
    font-size: 14px !important;
    line-height: 1 !important;
    z-index: 2;
}
.pp-error-tip:hover,
.pp-error-tip:focus {
    color: #b91c1c !important;
    outline: none !important;
}
.form-help-text {
    margin-top: 4px !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}
.form-help-text > i {
    margin-right: 2px !important;
    color: var(--primary, var(--pp-primary)) !important;
}

/* 우선순위 라디오 — 칩 스타일 */
.priority-radio-group {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 4px !important;
}
.priority-radio {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 6px !important;
    background: var(--pp-white) !important;
    cursor: pointer;
    font-weight: 500 !important;
    transition: all 0.12s;
    margin: 0 !important;
}
.priority-radio input[type="radio"] {
    margin: 0 4px 0 0 !important;
}
.priority-radio:hover {
    border-color: var(--primary, #3b82f6) !important;
}
.priority-radio i {
    font-size: 13px !important;
}
.priority-radio-info i  { color: var(--pp-tone-info-bg) !important; }
.priority-radio-warn i  { color: var(--pp-tone-warn-bg) !important; }
.priority-radio-error i { color: var(--pp-tone-danger-bg) !important; }

.alarm-config-eql-textarea {
    width: 100%;
    min-height: 220px;
    font-family: 'Menlo', 'Monaco', monospace !important;
    font-size: 12px !important;
    background: #fafafa !important;
    resize: vertical;
}
.alarm-config-message-textarea {
    width: 100%;
    min-height: 230px;
    resize: vertical;
}
.alarm-config-duration-input {
    width: 200px;
}
/* '분' addon 이 기본 16px/24px 라 자연높이 38px → input(13px/36px)보다 2px 높음.
 * addon 폰트를 input 과 동일하게 맞춰 stretch 시 36px 로 정렬. */
.alarm-config-duration-input .input-group-text {
    font-size: 13px;
    line-height: 19.5px;
}

.alarm-ai-eql {
    margin-top: 14px;
    border: 1px solid var(--pp-border, #dcdfe6);
    border-radius: 6px;
    background: var(--pp-white, #fff);
    padding: 12px;
}

.alarm-ai-eql-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
}

.alarm-ai-eql h4 {
    margin: 0 0 8px;
    font-size: 13px !important;
    font-weight: 700 !important;
}

.alarm-ai-eql-review {
    margin: 0;
    padding-left: 18px;
}

.alarm-ai-eql-review li {
    margin-bottom: 5px;
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.alarm-ai-eql-code {
    min-height: 80px;
    max-height: 260px;
    overflow: auto;
    white-space: pre-wrap;
    border-radius: 5px;
    border: 1px solid var(--pp-border, #dcdfe6);
    background: #111827;
    color: #f9fafb;
    padding: 10px;
    font-size: 12px !important;
}

.alarm-ai-eql-message,
.alarm-ai-eql-explanation {
    margin-top: 8px;
    color: var(--foreground, #333);
    overflow-wrap: anywhere;
}

.alert .alert-example {
    margin-top: 6px !important;
    padding-top: 6px !important;
    border-top: 1px dashed rgba(0,0,0,0.1) !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}
.alert .alert-example code {
    background: rgba(255,255,255,0.5) !important;
    padding: 1px 4px !important;
    border-radius: 3px !important;
    font-size: 11px !important;
}

/* ============================================================
 * /tag/view — EQL 알람 설정 테이블 엘립스 레이아웃
 * (inline style → CSS 클래스 전환, inline-style ratchet 준수)
 * ============================================================ */
.eql-alarm-table {
    table-layout: fixed;
    width: 100%;
}
.eql-alarm-col-name {
    width: 22%;
}
.eql-alarm-col-desc {
    width: 18%;
}
.eql-alarm-cell-trunc {
    max-width: 0;
}

/* === pp-48-dialog.css === */
/* ============================================================================
 * pp-09g-dialog.css
 * SCOPE  : FORM PANEL FOOTER / BOOTSTRAPDIALOG FORM / CONNECT EDGE BADGES
 * 영역   : 공용 폼 패널 푸터, BootstrapDialog 폼 다이얼로그, /connect/view 뱃지·KPI·통계, /edge/view 상태·온도, /tag/form 집계, /monitoring 클러스터 도트, /env/view 탭, /trigger/edit, Flow 코드 에디터, 확인 다이얼로그 메시지
 * 주의   : 본 파일은 pp-09g-alarmview-mapflow.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * 공용: 폼 패널 푸터 액션 (목록·저장 등 폼 액션 버튼 영역)
 * ============================================================ */
.card-footer.card-footer-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 16px !important;
    background: var(--muted, #f8fafc) !important;
    border-top: 1px solid var(--pp-border) !important;
}
.card-footer.card-footer-actions .btn + .btn {
    margin-left: 6px !important;
}
/* 좌측은 보조 버튼(목록), 우측은 주요 액션 (저장) */
.card-footer.card-footer-actions > .btn:last-child {
    margin-left: auto !important;
}

/* 폼 텍스트영역 사이즈 프리셋 */
.form-textarea-md { min-height: 100px; resize: vertical; }
.form-textarea-lg { min-height: 150px; resize: vertical; }

/* alert 안 ul 리스트 */
.alert .alert-list {
    margin: 6px 0 0 0 !important;
    padding-left: 18px !important;
    font-size: 12px !important;
    line-height: 1.6 !important;
}
.alert .alert-list code {
    background: rgba(255,255,255,0.5) !important;
    padding: 1px 5px !important;
    border-radius: 3px !important;
    font-size: 11px !important;
}


/* ============================================================
 * BootstrapDialog — 폼 다이얼로그 표준 (pp-dialog-form-modal)
 * 메타 편집 / 스크립트 편집 / 테스트 발행 다이얼로그 공통 패턴.
 * ============================================================ */
.pp-dialog-form-modal .modal-body {
    padding: 16px 18px 12px !important;
}
.pp-dialog-form-modal .modal-footer {
    padding: 10px 14px !important;
    background: var(--muted, #f8fafc) !important;
    border-top: 1px solid var(--pp-border) !important;
    display: flex;
    align-items: center;
    gap: 6px;
    justify-content: flex-end;
}
.pp-dialog-form-modal .modal-footer .btn + .btn { margin-left: 0 !important; }

/* asset-doc-dialog — footer 를 modal-body 좌우 패딩만큼 확장 (인라인 style 대체) */
.asset-doc-dialog .modal-footer {
    margin-left: -10px !important;
    margin-right: -10px !important;
}

/* ============================================================
 * pp-detail-meta — drawer/dialog 공용 메타 그리드 (label 130px + value flex)
 * 사용: tag/index, order/index 의 행 선택 drawer, flow-log 상세 다이얼로그 등.
 * ============================================================ */
.pp-detail-meta {
    display: grid;
    grid-template-columns: 130px 1fr;
    border: 1px solid var(--pp-border);
    border-radius: 6px;
    overflow: hidden;
    font-size: 12px;
    background: var(--pp-white, #fff);
}
.pp-detail-meta__row { display: contents; }
.pp-detail-meta__row > .pp-detail-meta__label,
.pp-detail-meta__row > .pp-detail-meta__value {
    padding: 8px 12px;
    border-bottom: 1px solid var(--pp-border, #eef0f3);
}
.pp-detail-meta__row:last-child > .pp-detail-meta__label,
.pp-detail-meta__row:last-child > .pp-detail-meta__value { border-bottom: none; }
.pp-detail-meta__label {
    background: var(--muted, #f7f9fc);
    font-weight: 600;
    color: var(--pp-text-secondary, var(--pp-border-strong));
    border-right: 1px solid var(--pp-border, #eef0f3);
}
.pp-detail-meta__value {
    color: var(--pp-text, #1e293b);
    word-break: break-all;
}

/* pp-detail-drawer — 행 선택 상세 패널 (DataTable row → 우측 slide-over) */
#pp-detail-drawer .ds-drawer-body { padding: 16px; }


/* ============================================================
 * flow-log-detail-dialog — 플로우 로그 상세 다이얼로그
 *   • 가로 800px (JSON pre-block 가독성)
 *   • 메타 그리드 (라벨 130px + 값 flex)
 *   • 레벨 뱃지 INFO/WARN/ERROR modifier
 *   • JSON pre-block (max-height 420px, mono, wrap)
 * ============================================================ */
.flow-log-detail-dialog .modal-dialog {
    width: 800px !important;
    max-width: 800px !important;
}

.flow-log-detail {
    padding: 2px;
}

.flow-log-detail__meta {
    display: grid;
    grid-template-columns: 130px 1fr;
    border: 1px solid var(--pp-border);
    border-radius: 6px;
    overflow: hidden;
    margin-bottom: 14px;
    font-size: 12px;
    background: var(--pp-white, #fff);
}
.flow-log-detail__row {
    display: contents;
}
.flow-log-detail__row > .flow-log-detail__label,
.flow-log-detail__row > .flow-log-detail__value {
    padding: 8px 12px;
    border-bottom: 1px solid var(--pp-border, #eef0f3);
}
.flow-log-detail__row:last-child > .flow-log-detail__label,
.flow-log-detail__row:last-child > .flow-log-detail__value {
    border-bottom: none;
}
.flow-log-detail__label {
    background: var(--muted, #f7f9fc);
    font-weight: 600;
    color: var(--pp-text-secondary, var(--pp-border-strong));
    border-right: 1px solid var(--pp-border, #eef0f3);
}
.flow-log-detail__value {
    color: var(--pp-text, #1e293b);
    word-break: break-all;
}

.flow-log-detail__mono {
    font-family: 'SFMono-Regular', 'Menlo', 'Consolas', monospace;
    font-size: 11.5px;
}
.flow-log-detail__hint {
    color: var(--pp-text-muted);
    font-size: 11px;
    margin-left: 2px;
}
.flow-log-detail__error {
    color: var(--pp-danger, #d9534f);
    font-weight: 500;
}

.flow-log-detail__section {
    font-weight: 600;
    color: var(--pp-text-secondary, var(--pp-border-strong));
    font-size: 12px;
    margin-bottom: 6px;
    padding-left: 2px;
    display: flex;
    align-items: center;
    gap: 6px;
}
.flow-log-detail__section::before {
    content: '';
    display: inline-block;
    width: 3px;
    height: 12px;
    background: var(--pp-primary, var(--pp-info));
    border-radius: 2px;
}

.flow-log-detail__pre {
    background: var(--muted, #f7f9fc);
    border: 1px solid var(--pp-border, #d8dee9);
    border-radius: 6px;
    padding: 12px 14px;
    max-height: 420px;
    overflow: auto;
    font-size: 11.5px;
    line-height: 1.5;
    font-family: 'SFMono-Regular', 'Menlo', 'Consolas', monospace;
    white-space: pre-wrap;
    word-break: break-all;
    margin: 0;
    color: var(--pp-text, #1e293b);
}

/* lvl-badge: 사용처 0건(미사용) — 블록 전체 삭제 (정본은 pp-12 톤 시스템) */

/* ============================================================
 * 다이얼로그 폼 필드 간격 — 단일 정본(SSOT). 모든 다이얼로그/모달의
 * stacked form-group 은 여기서만 간격을 받는다(12px, 마지막 0).
 * 이전에 pp-02/pp-47/pp-45/pp-41 에 흩어져 4/10/14px 로 어긋나던 것을
 * 12px 한 값으로 일원화. margin 기반이라 래퍼(form-stack) 유무와 무관.
 * ============================================================ */
body .bootstrap-dialog .form-group,
body .modal-body .form-group {
    margin-bottom: 12px !important;
}
body .bootstrap-dialog .form-group:last-child,
body .modal-body .form-group:last-child {
    margin-bottom: 0 !important;
}
/* 다이얼로그 안에서는 form-stack 의 flex gap 을 끈다 — 위 margin 과 이중 간격(24px) 방지.
 * 다이얼로그 밖 .form-stack(페이지 폼)은 gap:12px 유지(pp-27). */
body .bootstrap-dialog .form-stack,
body .modal-body .form-stack {
    gap: 0 !important;
}

.pp-dialog-form .form-inline, .pp-dialog-form .pp-form-row { margin-bottom: 12px !important; }
.pp-dialog-form .form-inline:last-child, .pp-dialog-form .pp-form-row:last-child { margin-bottom: 0 !important; }

.flow-meta-desc-textarea { min-height: 240px; resize: vertical; }

/* /connect/view — 연결 타입 / 하위 타입 뱃지 */
.conn-type-badge,
.conn-subtype-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    letter-spacing: 0.04em !important;
    line-height: 1.4 !important;
    border: 1px solid transparent !important;
    white-space: nowrap !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
/* 연결 타입 — solid 톤 */
.conn-type-badge { color: var(--pp-white) !important; background: var(--pp-border-strong) !important; }
.conn-type-opc      { background: var(--pp-primary) !important;
    color: var(--pp-white) !important; }
.conn-type-plc      { background: #7c3aed !important; }
.conn-type-modbus   { background: #0891b2 !important; }
.conn-type-database { background: #0d9488 !important; }
.conn-type-file     { background: var(--pp-tone-warn-bg) !important; }
.conn-type-mqtt     { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.conn-type-kafka    { background: #be123c !important; }
.conn-type-rest     { background: #6b21a8 !important; }

/* 하위 타입 — 진한 배경 + 흰 텍스트 (라이트 테마 정책) */
.conn-subtype-badge { color: var(--pp-white) !important; background: var(--pp-border-strong) !important; border-color: transparent !important; }
.conn-subtype-edge        { color: var(--pp-white) !important; background: #0e7490 !important; border-color: transparent !important; }
.conn-subtype-server      { color: var(--pp-white) !important; background: var(--pp-primary) !important; border-color: transparent !important; }
.conn-subtype-client      { color: var(--pp-white) !important; background: var(--pp-tone-success-bg) !important; border-color: transparent !important; }
.conn-subtype-csv         { color: var(--pp-white) !important; background: #b45309 !important; border-color: transparent !important; }
.conn-subtype-json        { color: var(--pp-white) !important; background: #6b21a8 !important; border-color: transparent !important; }
.conn-subtype-xml         { color: var(--pp-white) !important; background: #be123c !important; border-color: transparent !important; }
.conn-subtype-postgresql  { color: var(--pp-white) !important; background: var(--pp-primary) !important; border-color: transparent !important; }
.conn-subtype-mysql       { color: var(--pp-white) !important; background: #b45309 !important; border-color: transparent !important; }
.conn-subtype-mssql       { color: var(--pp-white) !important; background: #be123c !important; border-color: transparent !important; }
.conn-subtype-oracle      { color: var(--pp-white) !important; background: #b91c1c !important; border-color: transparent !important; }
.conn-subtype-tcp         { color: var(--pp-white) !important; background: var(--pp-border-strong) !important; border-color: transparent !important; }
.conn-subtype-rtu         { color: var(--pp-white) !important; background: #334155 !important; border-color: transparent !important; }

/* /edge/view — 엣지 상태 뱃지 (온다크: 흰 텍스트 + 진한 배경) */
body .edge-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    letter-spacing: 0.04em !important;
    line-height: 1.4 !important;
    border: 1px solid transparent !important;
    white-space: nowrap !important;
    color: var(--pp-white) !important;
    background: var(--pp-border-strong) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body .edge-status-active       { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
body .edge-status-normal       { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
body .edge-status-inactive     { background: var(--pp-muted-fg) !important; }
body .edge-status-offline      { background: #b91c1c !important;
    color: var(--pp-white) !important;
}
body .edge-status-disconnected { background: #b91c1c !important;
    color: var(--pp-white) !important;
}
body .edge-status-warn         { background: #b45309 !important;
    color: var(--pp-white) !important; }
body .edge-status-warning      { background: #b45309 !important;
    color: var(--pp-white) !important; }
body .edge-status-unknown      { background: var(--pp-muted-fg) !important; }

/* /connect/view — 연결이상 건수 KPI 카드 */
.conn-err-kpi {
    background: linear-gradient(135deg, #fff5f5 0%, #fef2f2 100%) !important;
    border: 1px solid #fecaca !important;
    border-radius: 10px !important;
    padding: 12px 16px !important;
    margin-bottom: 14px !important;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.conn-err-kpi-head {
    font-size: 12px !important;
    font-weight: 600 !important;
    color: #b91c1c !important;
    letter-spacing: 0.01em !important;
}
.conn-err-kpi-head > i { margin-right: 4px !important; }
.conn-err-kpi-body {
    display: flex;
    align-items: baseline;
    gap: 6px;
}
.conn-err-kpi-value {
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 28px !important;
    font-weight: 800 !important;
    color: var(--pp-tone-danger-bg) !important;
    line-height: 1.05 !important;
}
.conn-err-kpi-unit {
    font-size: 12px !important;
    font-weight: 600 !important;
    color: #b91c1c !important;
}
.conn-err-kpi-sub {
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
}

/* /connect/view — 상태 통계 좌우 레이아웃 (좌: 카운트 그리드 / 우: 범례) */
.conn-stats-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
    gap: 14px;
    align-items: start;
}
.conn-stats-legend {
    list-style: none;
    margin: 0 !important;
    padding: 0 !important;
    font-size: 11.5px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    line-height: 1.6 !important;
}
.conn-stats-legend li {
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}
.conn-stats-legend b {
    color: var(--foreground, #0f172a) !important;
    font-weight: 600 !important;
    margin-right: 2px !important;
}
.conn-legend-dot {
    width: 8px;
    height: 8px;
    border-radius: 50% !important;
    flex-shrink: 0;
}
.conn-legend-dot.is-ok   { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.conn-legend-dot.is-warn { background: #f59e0b !important; }
.conn-legend-dot.is-err  { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }
.conn-legend-dot.is-disc { background: #7c2d12 !important; }
.conn-legend-dot.is-mute { background: var(--pp-text-muted) !important; }

/* 필수 입력 라벨 앞 빨간 * 마크 — PP.validate 가 자동 prepend */
.pp-required-mark {
    color: var(--pp-tone-danger-bg) !important;
    font-weight: 700 !important;
    font-size: 1em !important;
    margin-right: 4px !important;
    user-select: none;
}

/* 입력 박스 사이즈 변동 방지 — has-error 시에도 동일 크기 유지 (전역 강제) */
body .form-control,
body input.form-control,
body input[type="text"].form-control,
body input[type="number"].form-control,
body input[type="password"].form-control,
body input[type="email"].form-control,
body input[type="search"].form-control,
body select.form-control,
body textarea.form-control {
    box-sizing: border-box !important;
    border-width: 1px !important;
    border-style: solid !important;
    -webkit-appearance: none !important;
    -moz-appearance: textfield !important;
    appearance: none !important;
}
/* type=number spinner 제거 — 사이즈 변동·우측 화살표 노출 방지 */
body input[type="number"].form-control::-webkit-outer-spin-button,
body input[type="number"].form-control::-webkit-inner-spin-button {
    -webkit-appearance: none !important;
    margin: 0 !important;
    display: none !important;
}
/* jquery.validate 가 input 뒤에 label.error 를 끼워넣어도 인접 입력 위치 영향 없게 */
body .form-inline label.error,
body .pp-form-row label.error,
body .form-group label.error,
body label.error {
    margin: 0 !important;
    padding: 0 !important;
    line-height: 0 !important;
    height: 0 !important;
    width: 0 !important;
    overflow: hidden !important;
    display: none !important;
    visibility: hidden !important;
}

/* /edge/view — 온도 게이지 패널 */
.edge-temp-body { padding: 4px 6px 0 !important; }
.edge-temp-gauge { width: 100%; height: 220px; }
.edge-temp-legend {
    list-style: none;
    margin: 4px 0 8px !important;
    padding: 0 4px !important;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    font-size: 11px !important;
    color: var(--pp-border-strong) !important;
}
.edge-temp-legend li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.edge-temp-legend .dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50% !important;
    background: var(--pp-text-muted) !important;
}
.edge-temp-legend .dot-ok     { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }
.edge-temp-legend .dot-warn   { background: #f59e0b !important; }
.edge-temp-legend .dot-danger { background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-white) !important; }

/* [DEPRECATED] log-msg-td / log-msg-cell — 공통 td-ellipsis / td-ellipsis-cell 로 통일.
   기존 코드 호환을 위해 alias 만 남김. 신규 코드는 공통 클래스를 직접 사용. */

/* 데이터 테이블 — 한 줄 ellipsis 셀 (범용)
   설명(description) 같은 긴 텍스트 컬럼을 한 줄로 자르고 title 로 전체 텍스트 노출. */
body .table > tbody > tr > td.td-ellipsis {
    max-width: 0;
    overflow: hidden !important;
    white-space: nowrap !important;
    text-overflow: ellipsis !important;
    word-break: normal !important;
}
.td-ellipsis-cell {
    text-align: left !important;
    font-size: 12px !important;
    width: 100%;
    max-width: 100%;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: normal !important;
    display: block;
}

/* 타임라인 '현재' 마커 — 모든 화면 공통 (검정 배경 + 흰 텍스트 + 노란 펄스 도트) */
.pp-now-marker {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px !important;
    border-radius: 999px !important;
    background: #0f172a !important;
    color: var(--pp-white) !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    letter-spacing: 0.02em !important;
    line-height: 1.2 !important;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.35) !important;
    white-space: nowrap !important;
}
.pp-now-marker * { color: var(--pp-white) !important; }
.pp-now-marker::before {
    content: '';
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50% !important;
    background: #fde047 !important;
    box-shadow: 0 0 0 2px rgba(253, 224, 71, 0.35) !important;
    animation: pp-now-marker-pulse 1.6s ease-in-out infinite;
}
@keyframes pp-now-marker-pulse {
    0%, 100% { box-shadow: 0 0 0 2px rgba(253, 224, 71, 0.35); }
    50%      { box-shadow: 0 0 0 5px rgba(253, 224, 71, 0.18); }
}

/* /diagnostic/index — 타임라인 뱃지(아이콘 only, 데이터 테이블 priority-badge 와 통일) */
.diag-tl-badge {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 22px;
    height: 22px;
    padding: 0 !important;
    border-radius: 50% !important;
    font-size: 11px !important;
    line-height: 1 !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
.diag-tl-badge > i { margin: 0 !important; }
/* 타임라인 아이템 클릭 영역 — 상세 다이얼로그 트리거 */
.diag-tl-click { cursor: pointer; }

/* /tag/form — 집계 주기 체크박스 묶음 (표준 체크박스 + inline label) */
.aggr-period-list {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 14px;
    align-items: center;
}
.aggr-period-list .form-check {
    margin: 0 !important;
    padding-left: 0 !important;
    min-height: 0;
    font-size: 13px !important;
    color: #334155 !important;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.aggr-period-list .form-check-input {
    float: none;
    margin: 0;
    width: 14px;
    height: 14px;
    accent-color: var(--primary, var(--pp-primary-strong));
    cursor: pointer;
}
.aggr-period-list .form-check-label {
    margin: 0;
    cursor: pointer;
}

/* /monitoring/index — 클러스터 상태 도트 */
.cluster-status-cell {
    width: 30px;
    text-align: center !important;
    line-height: 28px !important;
}
.cluster-status-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50% !important;
    background: var(--pp-text-muted) !important;
    box-shadow: 0 0 0 2px rgba(148, 163, 184, 0.2) !important;
}
.cluster-status-dot.cluster-status-up {
    background: var(--pp-tone-success-bg) !important;
    box-shadow: 0 0 0 2px rgba(22, 163, 74, 0.25), 0 0 6px rgba(22, 163, 74, 0.55) !important;
    animation: cluster-status-pulse 2s ease-in-out infinite;
    color: var(--pp-white) !important;
}
.cluster-status-dot.cluster-status-down {
    background: var(--pp-tone-danger-bg) !important;
    box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.25), 0 0 6px rgba(220, 38, 38, 0.55) !important;
    color: var(--pp-white) !important;
}
@keyframes cluster-status-pulse {
    0%, 100% { box-shadow: 0 0 0 2px rgba(22, 163, 74, 0.25), 0 0 6px rgba(22, 163, 74, 0.55); }
    50%      { box-shadow: 0 0 0 4px rgba(22, 163, 74, 0.18), 0 0 10px rgba(22, 163, 74, 0.65); }
}

/* /tag/view — String/Date 카테고리컬 스텝 차트 */
.tag-string-chart {
    width: 100%;
    min-height: 360px;
    margin-bottom: 12px !important;
}

/* 다크 톤 badge — /query/run 행수 등 */
.badge.badge-dark {
    background: #0f172a !important;
    color: var(--pp-white) !important;
    font-weight: 600 !important;
    padding: 3px 8px !important;
    border-radius: 999px !important;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 11px !important;
    letter-spacing: 0.02em !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* /env/view — 탭을 패널 외부 상단, 각 탭 pane 안에 단일 패널 */
.env-view-tabs { margin-bottom: 12px !important; }
.env-view-tab-content > .tab-pane { padding: 0 !important; }
.env-view-panel-body { padding: 0 !important; }
.env-view-table {
    margin-bottom: 0 !important;
    font-size: 13px !important;
}
.env-view-table thead th {
    background: var(--muted, #f8fafc) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    font-size: 12px !important;
    letter-spacing: 0.02em !important;
}
.env-view-table td:first-child {
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 12px !important;
    color: var(--primary, var(--pp-primary)) !important;
    width: 320px;
    word-break: break-all;
}
.env-view-table td:last-child {
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 12px !important;
    color: var(--foreground, #0f172a) !important;
    word-break: break-all;
}

/* /trigger/edit — 폼 전용 보조 클래스 */
.trigger-form-desc {
    min-height: 90px;
    resize: vertical;
}
.trigger-form-check {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 500 !important;
    color: var(--foreground, #0f172a) !important;
    cursor: pointer;
    margin: 0 !important;
}
.trigger-form-check input[type="checkbox"] {
    margin: 0 !important;
}
.trigger-form-result-table {
    table-layout: fixed;
    width: 100% !important;
}
.trigger-form-result-table > tbody > tr > td:last-child {
    max-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}

/* Flow 코드 에디터 영역 — 자식 .CodeMirror 가 글로벌 보더(12px radius, 1px) 가지므로 부모 wrap 은 투명 */
.flow-code-editor-wrap {
    overflow: hidden;
}
.flow-code-editor-wrap .CodeMirror {
    height: 360px;
    font-size: 12px !important;
}
.flow-code-editor-wrap .CodeMirror-lines { padding: 8px 0 !important; }

.flow-dialog-meta {
    margin-bottom: 8px !important;
    font-size: 12px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}
.flow-dialog-meta code {
    background: var(--muted, #f3f4f6) !important;
    color: var(--primary, var(--pp-primary)) !important;
    padding: 1px 6px !important;
    border-radius: 3px !important;
}
.pp-dialog-form-status {
    margin-top: 8px !important;
    min-height: 16px;
}
.flow-dialog-validate-msg {
    font-size: 12px !important;
    font-weight: 500 !important;
}

/* 확인 다이얼로그 메시지 표준 (PP.dialog.confirm) */
.pp-dialog-confirm-message {
    padding: 8px 4px !important;
    font-size: 13px !important;
    line-height: 1.6 !important;
    color: var(--foreground, #111827) !important;
}
.pp-dialog-confirm-message code {
    background: var(--muted, #f3f4f6) !important;
    color: var(--primary, var(--pp-primary)) !important;
    padding: 1px 5px !important;
    border-radius: 3px !important;
    font-size: 11px !important;
}
.pp-dialog-confirm-message .pp-dialog-confirm-question {
    margin-top: 10px !important;
    padding-top: 8px !important;
    border-top: 1px dashed var(--pp-border) !important;
    font-weight: 600 !important;
    color: var(--foreground, #111827) !important;
}


/* 다이얼로그 닫기(X) 버튼 우측 정렬 + FA 아이콘 */
.bootstrap-dialog .modal-header { display: flex !important; align-items: center !important; }
.bootstrap-dialog .modal-header .bootstrap-dialog-title { flex: 1 1 auto !important; }
.bootstrap-dialog .modal-header .bootstrap-dialog-close-button { margin-left: auto !important; order: 9 !important; }
.bootstrap-dialog .bootstrap-dialog-close-button .btn-close { background: transparent !important; border: 0 !important; opacity: .65; cursor: pointer; }
.bootstrap-dialog .bootstrap-dialog-close-button .btn-close:hover { opacity: 1; }

/* === pp-49-mapflow.css === */
/* ============================================================================
 * pp-09g-mapflow.css
 * SCOPE  : MAP / FLOW LOG / QUERY / MY PROFILE
 * 영역   : /map/index 패널 헤더·페이지 톤, BootstrapDialog.confirm 버튼 순서·본문 가시성, /flow/log 메시지 셀, /query/index EQL 패널, btn-group 동색 구분선, /my/profile 다이얼로그
 * 주의   : 본 파일은 pp-09g-alarmview-mapflow.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /map/index — 글로벌 사이트 맵 패널 헤더
 * 다른 패널과 살짝 구분되도록 옅은 슬레이트 배경 (좌측 액센트 없이 풀폭)
 * ============================================================ */
.card.map-board-panel > .card-header {
    background: linear-gradient(180deg, #f1f5f9 0%, var(--pp-border) 100%) !important;
    border-bottom: 1px solid var(--pp-text-soft) !important;
    box-shadow: inset 0 -1px 0 rgba(255,255,255,0.6) !important;
}
.card.map-board-panel > .card-header .card-head-title {
    color: #0f172a !important;
    font-weight: 700 !important;
}
.card.map-board-panel > .card-header .card-head-sub {
    color: var(--pp-border-strong) !important;
}
.card.map-board-panel > .card-header .card-head-title > i {
    color: var(--primary, var(--pp-primary)) !important;
}

/* ============================================================
 * 전역 페이지 배경 + 패널 톤 정돈 (로그인/에러 페이지 제외)
 *
 * 흰 페이지 + 흰 패널이 융합되어 깊이감 부족하던 문제 해결:
 * - 페이지 배경: primary hue 의 아주 연한 톤 (--pp-primary-pale) — 패널(흰색) 과 분리감
 * - 패널: 흰색 유지 + 더 또렷한 보더 + 미세 그림자
 * - 텍스트: foreground/secondary 토큰 톤 유지
 * - `body:not(.pp-login-page)` 셀렉터로 모든 일반 페이지에 자동 적용. 로그인 / 에러 페이지는
 *   `body.pp-login-page` 클래스를 가지므로 자연스럽게 제외.
 * ============================================================ */
body:not(.pp-login-page) {
    /* 무채 밝은 톤 — 일반 화면 기본 바탕을 차분하게 고정. */
    background: oklch(0.98 0 0) !important;
}
body:not(.pp-login-page) #page-wrapper {
    background: transparent !important;
}
body:not(.pp-login-page) .card.card {
    background: var(--pp-white) !important;
    border: 1px solid oklch(0.92 0.005 286) !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 3px rgba(15, 23, 42, 0.06) !important;
}
body:not(.pp-login-page) .card.card > .card-header .card-head-title {
    color: oklch(0.21 0.006 286) !important;
    font-weight: 700 !important;
}
body:not(.pp-login-page) .card.card > .card-header .card-head-sub {
    color: oklch(0.50 0.01 286) !important;
}
body:not(.pp-login-page) .card.card > .card-header .card-head-title > i {
    color: var(--primary, var(--pp-primary-strong)) !important;
}


/* ============================================================
 * BootstrapDialog.confirm — 버튼 순서 표준화
 * BootstrapDialog 의 confirm 은 기본 [OK, Cancel] 순서로 렌더하나,
 * 우리 디자인 시스템 표준은 [취소 ← 왼쪽, 확인/액션 ← 오른쪽].
 * cssClass: 'pp-dialog-confirm' 부여 시 row-reverse 로 표준 순서.
 * ============================================================ */
.bootstrap-dialog.pp-dialog-confirm .modal-footer {
    display: flex;
    flex-direction: row-reverse;
    justify-content: flex-start;
    gap: 6px;
}
.bootstrap-dialog.pp-dialog-confirm .modal-footer .btn + .btn {
    margin-left: 0 !important;
}


/* ============================================================
 * /flow/log — 데이터테이블 메시지 셀 ellipsis
 * ============================================================ */
.flow-log-table {
    table-layout: fixed;
    width: 100% !important;
}
.flow-log-table > tbody > tr > td {
    vertical-align: middle;
}
/* 메시지 컬럼 (마지막) — td 자체를 ellipsis 컨테이너로 (table-layout:fixed 와 결합 필수) */
.flow-log-table > tbody > tr > td:last-child {
    max-width: 0;
    overflow: hidden;
}
.flow-log-msg-cell {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    font-size: 12px !important;
    color: var(--foreground, #111827) !important;
}
.flow-log-msg-error {
    color: var(--pp-tone-danger-bg) !important;
    margin-left: 4px !important;
}


/* ============================================================
 * /query/index — EQL 입력 패널 + CodeMirror frame
 * ============================================================ */
.query-eql-panel .query-eql-body {
    padding: 0 !important;
    padding-left: 20px !important;
    padding-right: 20px !important;
    padding-bottom: 15px !important;
}
.query-eql-panel .query-eql-body textarea {
    display: none;       /* CodeMirror 가 hidden textarea 를 wrap */
}
.query-eql-panel .CodeMirror {
    height: auto;
    min-height: 60px;       /* 약 3줄 (line-height ~19px × 3 + padding) */
    font-size: 13px !important;
}
.query-eql-panel .CodeMirror-lines { padding: 10px 0 !important; }


/* ============================================================
 * BootstrapDialog.confirm (.pp-dialog-confirm) 본문 가시성 강제
 * BootstrapDialog 의 TYPE_WARNING / TYPE_DANGER 가 modal-body /
 * .bootstrap-dialog-message 에 어두운 배경 + 흰 텍스트 입혀 본문 안 보임.
 * cssClass 가 .bootstrap-dialog / .modal-dialog / .modal 어디에 붙어도 cover.
 * ============================================================ */
.pp-dialog-confirm .modal-body,
.pp-dialog-confirm .bootstrap-dialog-message,
.bootstrap-dialog.pp-dialog-confirm .modal-body,
.bootstrap-dialog.pp-dialog-confirm .bootstrap-dialog-message {
    background: var(--pp-white) !important;
    background-color: var(--pp-white) !important;
    color: #111827 !important;
}
/* 본문 안 모든 텍스트 (버튼/코드 제외) 다크 톤 강제 */
.pp-dialog-confirm .modal-body,
.pp-dialog-confirm .modal-body *:not(.btn):not(code):not(i),
.pp-dialog-confirm .bootstrap-dialog-message,
.pp-dialog-confirm .bootstrap-dialog-message *:not(.btn):not(code):not(i) {
    color: #111827 !important;
}
.pp-dialog-confirm .modal-body code,
.pp-dialog-confirm .bootstrap-dialog-message code {
    color: var(--primary, var(--pp-primary)) !important;
    background: var(--muted, #f3f4f6) !important;
}
/* BootstrapDialog type 클래스가 입히는 어두운 배경 override */
.bootstrap-dialog.type-warning.pp-dialog-confirm .modal-body,
.bootstrap-dialog.type-danger.pp-dialog-confirm .modal-body,
.bootstrap-dialog.type-info.pp-dialog-confirm .modal-body,
.bootstrap-dialog.type-primary.pp-dialog-confirm .modal-body {
    background: var(--pp-white) !important;
    color: #111827 !important;
}


/* ============================================================
 * btn-group 안 동색 primary 버튼들 사이의 구분선 보강
 * (primary 끼리 인접하면 border-color 가 background 와 같아 사라짐)
 * ============================================================ */
.btn-group .btn-primary + .btn-primary,
.btn-group .btn-danger + .btn-danger,
.btn-group .btn-success + .btn-success,
.btn-group .btn-warning + .btn-warning,
.btn-group .btn-info + .btn-info {
    box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.22) !important;
}


/* ============================================================
 * /my/profile — 프로필 보기 다이얼로그 표준
 * 상단 avatar + 이름/역할/ID summary 카드 + 폼 (fieldset)
 * ============================================================ */
.pp-profile-form .pp-profile-summary {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px !important;
    margin: 0 0 16px !important;
    background: linear-gradient(135deg, #f8fafc 0%, #eef2f7 100%) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
}
.pp-profile-avatar {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--primary, var(--pp-primary)) 0%, #1e40af 100%) !important;
    color: var(--pp-white) !important;
    font-size: 22px !important;
    border-radius: 50% !important;
    box-shadow: 0 2px 6px rgba(29, 78, 216, 0.25) !important;
    /* 사진 업로드 트리거: 클릭 가능 + 카메라 배지 오버레이 (BS 유틸로 표현 불가한 상호작용/원형 클립) */
    position: relative;
    cursor: pointer;
    overflow: hidden;
}
/* 업로드된 사진을 원형 영역에 꽉 채움 */
.pp-profile-avatar .pp-profile-avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* 우하단 카메라 배지(편집 가능 힌트) — hover 시 강조 */
.pp-profile-avatar .pp-profile-avatar-edit {
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--pp-white);
    color: var(--primary, var(--pp-primary));
    font-size: 9px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.pp-profile-avatar:hover .pp-profile-avatar-edit {
    color: var(--pp-primary-strong, var(--pp-primary));
}
/* 상단 툴바 아바타에 사진 반영 시 원형으로 꽉 채움 */
.pp-top-toolbar .pp-tb-avatar {
    overflow: hidden;
}
.pp-top-toolbar .pp-tb-avatar .pp-tb-avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.pp-profile-summary-body { min-width: 0; flex: 1; }
.pp-profile-name {
    font-size: 16px !important;
    font-weight: 700 !important;
    color: var(--foreground, #0f172a) !important;
    line-height: 1.3 !important;
}
.pp-profile-meta {
    margin-top: 4px !important;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
}
.pp-profile-meta-sep { color: var(--pp-text-soft) !important; }
.pp-profile-role-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px !important;
    background: linear-gradient(135deg, #6366f1 0%, #4338ca 100%) !important;
    color: var(--pp-white) !important;
    border-radius: 10px !important;
    font-size: 10px !important;
    font-weight: 700 !important;
    letter-spacing: 0.02em !important;
    text-transform: uppercase !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
.pp-profile-role-badge i { color: var(--pp-white) !important; margin-right: 2px !important; }
.pp-profile-userid {
    font-family: 'Menlo', 'Monaco', monospace !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
}
.pp-profile-userid i { margin-right: 2px !important; color: var(--muted-foreground, var(--pp-text-muted)) !important; }

/* Leaflet 하단 attribution(© 링크) 숨김 — 사용자 요청. zoom(.leaflet-bar)/layers 컨트롤은 기능이라 보존. !important 로 vendor 규칙(specificity 0,2,0) override */
body .leaflet-control-attribution {
    display: none !important;
}


/* === pp-50-cluster-order.css === */
/* ============================================================================
 * pp-09h-cluster-order.css
 * SCOPE  : CLUSTER / DATETIMEPICKER / ORDER OEE
 * 영역   : 폼 readonly/disabled, /cluster/index 모니터링 표준, daterangepicker, /timeline/index 메인 차트, /order/view OEE 패널·우선순위 뱃지·진행률·OEE stat card
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * 폼 인풋 readonly / disabled — shadcn 톤 (전역 표준)
 * - readonly: 클릭 가능하나 편집 불가. 옅은 muted 배경 + 보통 텍스트 + cursor:default
 * - disabled: 상호작용 불가. opacity 낮춤 + cursor:not-allowed + muted 배경
 *
 * 주의: `:read-only` pseudo 는 Firefox 등에서 <select>·<button>·체크/라디오 등
 * 본래 편집할 수 없는 컨트롤에도 항상 매칭된다. 따라서 input/textarea 로
 * 명시적으로 제한해 select·체크/라디오까지 readonly 톤이 입혀지지 않게 한다.
 * ============================================================ */
body input.form-control[readonly],
body textarea.form-control[readonly],
body input[type="text"].form-control:read-only,
body input[type="password"].form-control:read-only,
body input[type="email"].form-control:read-only,
body input[type="number"].form-control:read-only,
body input[type="tel"].form-control:read-only,
body input[type="url"].form-control:read-only,
body input[type="search"].form-control:read-only,
body input[type="date"].form-control:read-only,
body input[type="time"].form-control:read-only,
body input[type="datetime-local"].form-control:read-only,
body textarea.form-control:read-only {
    background: var(--muted, #f4f4f5) !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    border-color: var(--pp-border) !important;
    box-shadow: none !important;
    cursor: default !important;
}
body input.form-control[readonly]:focus,
body textarea.form-control[readonly]:focus,
body input.form-control:read-only:focus,
body textarea.form-control:read-only:focus {
    border-color: var(--pp-border) !important;
    box-shadow: 0 0 0 3px rgba(15, 23, 42, 0.06) !important;
    outline: 0 !important;
}

/* disabled — input·textarea·select 모두 명시. 체크박스/라디오는 별도 룰. */
body input.form-control[disabled],
body input.form-control:disabled,
body textarea.form-control[disabled],
body textarea.form-control:disabled,
body select[disabled],
body select:disabled,
body fieldset[disabled] input.form-control,
body fieldset[disabled] textarea.form-control,
body fieldset[disabled] select {
    background: var(--muted, #f4f4f5) !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    border-color: var(--pp-border) !important;
    opacity: 0.6 !important;
    cursor: not-allowed !important;
    box-shadow: none !important;
}

/* 체크박스 / 라디오 disabled — 박스만 약화 (cursor 는 박스에만, 라벨에는 자체 룰) */
body input[type="checkbox"][disabled],
body input[type="radio"][disabled],
body input[type="checkbox"]:disabled,
body input[type="radio"]:disabled {
    opacity: 0.5 !important;
    cursor: not-allowed !important;
}
body input[type="checkbox"]:disabled + label,
body input[type="radio"]:disabled + label,
body label.disabled,
body label:has(input[type="checkbox"]:disabled),
body label:has(input[type="radio"]:disabled) {
    cursor: not-allowed !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
}
/* 체크박스·라디오 자체에는 form-control readonly 룰이 적용되지 않도록 명시적 reset */
body input[type="checkbox"].form-control,
body input[type="radio"].form-control,
body input[type="checkbox"],
body input[type="radio"] {
    background: initial !important;
    color: initial !important;
}

/* select disabled native arrow 톤 정렬 */
body select[disabled],
body select:disabled {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--muted-foreground, var(--pp-text-muted)) 50%),
                      linear-gradient(135deg, var(--muted-foreground, var(--pp-text-muted)) 50%, transparent 50%) !important;
    background-position: calc(100% - 16px) center, calc(100% - 11px) center !important;
    background-size: 5px 5px, 5px 5px !important;
    background-repeat: no-repeat !important;
}


/* ============================================================
 * /cluster/index — 클러스터 모니터링 표준 레이아웃
 * 좌(3) 노드 목록 · 중(6) 메인 차트 · 우(3) 노드 상세
 * ============================================================ */
.cluster-meta-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px !important;
    font-size: 12px !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    background: var(--muted, #f4f4f5) !important;
    border-radius: 14px !important;
    font-weight: 600 !important;
}
.cluster-meta-chip i { color: var(--primary, var(--pp-primary)) !important; }

/* 노드 카드 컨테이너 */
.cluster-nodes-body { padding: 10px !important; }
.cluster-master-card {
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    padding: 10px 12px !important;
    background: linear-gradient(180deg, #f8fafc 0%, var(--pp-white) 60%) !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04) !important;
}
.cluster-workers-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 10px !important;
}
.cluster-workers-list .node-cover {
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
    padding: 10px 12px !important;
    background: var(--pp-white) !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04) !important;
    transition: border-color 0.12s;
}
.cluster-workers-list .node-cover:hover { border-color: var(--primary, var(--pp-primary)) !important; }

.cluster-node-head {
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--muted-foreground, var(--pp-border-strong)) !important;
    border-bottom: 1px solid var(--pp-border) !important;
    padding-bottom: 5px !important;
    text-transform: uppercase !important;
    letter-spacing: 0.04em !important;
}
.cluster-node-head i { color: var(--primary, var(--pp-primary)) !important; margin-right: 4px !important; }
.cluster-node-badge-row { margin-top: 8px !important; }
.cluster-health-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    background: var(--pp-tone-success-bg) !important;
    border-radius: 12px !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
.cluster-node-ip {
    margin-top: 8px !important;
    font-size: 16px !important;
    font-weight: 700 !important;
    color: var(--foreground, #0f172a) !important;
    font-family: 'Menlo', 'Monaco', monospace !important;
}
.cluster-node-meta {
    margin-top: 2px !important;
    font-size: 11px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
}
.cluster-node-spark {
    margin-top: 10px !important;
    width: 100%;
    height: 22px;
}

/* 메인 차트 영역 */
.cluster-chart-body {
    position: relative;
    padding: 12px !important;
    min-height: 720px;
}
.cluster-chart-main {
    width: 100%;
    height: 700px;
}

/* 노드 상태 라인 — UP / CPU / MEM / DISK 4개 메타 칩 */
.cluster-node-statline {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    margin-top: 4px;
}
.cluster-node-statline > span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    line-height: 1;
    white-space: nowrap;
}
.cluster-node-statline > span > i {
    font-size: 10px;
    color: var(--muted-foreground, var(--pp-text-muted));
}
.cluster-node-statline .node-stat-up   { color: var(--pp-tone-success-bg); font-weight: 600; }
.cluster-node-statline .node-stat-up   > i { color: var(--pp-tone-success-bg); }
.cluster-node-statline .node-stat-down { color: #b91c1c; font-weight: 600; }
.cluster-node-statline .node-stat-down > i { color: #b91c1c; }
.cluster-chart-small {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 220px;
    height: 160px;
    z-index: 1;
}

/* 마스터 노드 카드 — 차트 좌상단 floating 오버레이 */
.cluster-master-overlay {
    position: absolute !important;
    top: 14px !important;
    left: 14px !important;
    width: 280px !important;
    z-index: 2;
    background: var(--pp-white) !important;
    border: 2px solid var(--pp-border) !important;
    border-radius: 8px !important;
    /* box-shadow: 0 6px 18px rgba(15, 23, 42, 0.10), 0 1px 3px rgba(15, 23, 42, 0.06) !important; */
}
/* 워커 카드 리스트 — 마스터 카드 바로 아래 세로 스택 */
.cluster-workers-overlay {
    position: absolute !important;
    top: calc(14px + 170px);   /* 마스터 카드 높이만큼 아래 — 카드 폭/내용 변경 시 조정 */
    left: 14px !important;
    width: 220px !important;
    z-index: 2;
    max-height: calc(100% - 200px);
    overflow-y: auto;
    margin-top: 0 !important;
}
.cluster-workers-overlay .node-cover {
    box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08), 0 1px 3px rgba(15, 23, 42, 0.04) !important;
}
.cluster-chart-database {
    position: absolute;
    bottom: 14px;
    right: 14px;
    width: 200px;
    height: 200px;
    z-index: 1;
}

/* ============================================================
 * daterangepicker 톤 보강 — 기본 룰 위에 shadcn 색상·라운드 일관성
 * ============================================================ */
body .daterangepicker {
    border-radius: 8px !important;
    box-shadow: 0 10px 28px rgba(15, 23, 42, 0.12), 0 2px 6px rgba(15, 23, 42, 0.05) !important;
    border: 1px solid var(--pp-border) !important;
}
body .daterangepicker td.active,
body .daterangepicker td.active:hover {
    background: var(--primary, var(--pp-primary)) !important;
    color: var(--pp-white) !important;
    border-radius: 4px !important;
}
body .daterangepicker td.start-date,
body .daterangepicker td.end-date {
    background: var(--primary, var(--pp-primary)) !important;
    color: var(--pp-white) !important;
}
body .daterangepicker td.in-range {
    background: rgba(29, 78, 216, 0.10) !important;
    color: var(--foreground, #0f172a) !important;
}
body .daterangepicker .ranges li.active {
    background: var(--primary, var(--pp-primary)) !important;
    color: var(--pp-white) !important;
    border-radius: 4px !important;
}
body .daterangepicker .applyBtn {
    background: var(--primary, var(--pp-primary)) !important;
    border-color: var(--primary, var(--pp-primary)) !important;
    color: var(--pp-white) !important;
}


/* ============================================================
 * /timeline/index — 메인 타임라인 차트 (다른 페이지보다 큰 600px)
 * ============================================================ */
body .timeline-canvas-frame > #alarm_timeline.alarm-timeline-canvas {
    min-height: 600px !important;
    height: 600px !important;
}


/* ============================================================
 * /order/view — OEE 패널 레이아웃 (flex/grid 기반, table 제거)
 * ============================================================ */
.order-oee-meta-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 16px;
    padding: 12px !important;
    background: var(--muted, #f8fafc) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 8px !important;
}
.order-oee-meta-item { min-width: 0; }
.order-oee-meta-label {
    font-size: 10px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.04em !important;
    margin-bottom: 2px !important;
}
.order-oee-meta-value {
    font-size: 14px !important;
    font-weight: 700 !important;
    color: var(--foreground, #0f172a) !important;
    line-height: 1.3 !important;
}


/* ============================================================
 * /order/view 우선순위 뱃지 — on-dark (흰 텍스트 + 색상 그라데이션)
 * JS 가 priority-badge priority-badge-{VALUE} 형태로 생성 (VALUE: NORMAL/HIGH/LOW/URGENT/CRITICAL ...)
 * ============================================================ */
body span.priority-badge,
body .priority-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    border-radius: 12px !important;
    letter-spacing: 0.04em !important;
    text-transform: uppercase !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body span.priority-badge *,
body .priority-badge * { color: var(--pp-white) !important; }

/* 기본 (회색) */
body .priority-badge,
body .priority-badge-NORMAL,
body .priority-badge-Normal,
body .priority-badge-normal {
    background: var(--pp-border-strong) !important;
    color: var(--pp-white) !important;
}
/* 우선 (낮음) */
body .priority-badge-LOW,
body .priority-badge-Low,
body .priority-badge-low {
    background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important;
}
/* BAND — 슬레이트 다크 (정보·범위 알람용) */
body .priority-badge-BAND,
body .priority-badge-Band,
body .priority-badge-band {
    background: #1e293b !important;
    color: var(--pp-white) !important;
}
body .priority-badge-BAND i,
body .priority-badge-Band i,
body .priority-badge-band i {
    color: var(--pp-white) !important;
    font-size: 11px !important;
}
/* 높음 */
body .priority-badge-HIGH,
body .priority-badge-High,
body .priority-badge-high {
    background: #b45309 !important;
    color: var(--pp-white) !important;
}
/* 긴급 / 심각 */
body .priority-badge-URGENT,
body .priority-badge-Urgent,
body .priority-badge-urgent,
body .priority-badge-CRITICAL,
body .priority-badge-Critical,
body .priority-badge-critical {
    background: #991b1b !important;
    color: var(--pp-white) !important;
}


/* ============================================================
 * /order/view — 생산 진행률 패널 (좌측 최상단)
 * ============================================================ */
.order-prod-body { padding: 16px 18px !important; }
.order-prod-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: 24px;
    align-items: center;
}
.order-prod-rate {
    text-align: left !important;
    line-height: 1 !important;
}
.order-prod-rate-value {
    font-size: 48px !important;
    font-weight: 800 !important;
    color: var(--foreground, #0f172a) !important;
    letter-spacing: -0.02em !important;
}
.order-prod-rate-unit {
    font-size: 22px !important;
    font-weight: 600 !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    margin-left: 4px !important;
}
.order-prod-bar.progress {
    margin-top: 14px !important;
    margin-bottom: 0 !important;
    height: 8px;
    border-radius: 999px !important;
    background: var(--muted, #f1f5f9) !important;
    box-shadow: none !important;
    overflow: hidden;
}
.order-prod-bar .progress-bar {
    transition: width 0.8s ease;
    background: linear-gradient(90deg, var(--primary, var(--pp-primary)) 0%, #60a5fa 100%) !important;
    line-height: 8px !important;
    font-size: 0 !important;
    color: var(--pp-white) !important;
}
.order-prod-meta-col {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    padding-left: 18px !important;
    border-left: 1px solid var(--pp-border) !important;
}
.order-prod-meta-item { min-width: 0; }
.order-prod-meta-label {
    font-size: 10px !important;
    font-weight: 700 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.05em !important;
    margin-bottom: 4px !important;
}
.order-prod-meta-value {
    font-size: 18px !important;
    font-weight: 700 !important;
    color: var(--foreground, #0f172a) !important;
    line-height: 1.2 !important;
}


/* ============================================================
 * /order/view OEE 패널 — shadcn stat card 4종 (OEE / A / P / Q)
 * ============================================================ */
.oee-stat-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}
.oee-stat-card {
    background: var(--pp-white) !important;
    border: 1px solid var(--pp-border) !important;
    border-radius: 10px !important;
    padding: 14px 14px 10px !important;
    display: flex;
    flex-direction: column;
    gap: 8px;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04) !important;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.oee-stat-card:hover {
    border-color: var(--primary, var(--pp-primary)) !important;
    box-shadow: 0 4px 14px rgba(15, 23, 42, 0.06) !important;
}
.oee-stat-card-primary {
    background: linear-gradient(180deg, #f8fafc 0%, var(--pp-white) 60%) !important;
    border-color: var(--primary, var(--pp-primary)) !important;
}
.oee-stat-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    text-transform: uppercase !important;
    letter-spacing: 0.05em !important;
}
.oee-stat-card-primary .oee-stat-head { color: var(--primary, var(--pp-primary)) !important; }
.oee-stat-label { display: inline-flex; align-items: center; gap: 4px; }
.oee-stat-label i { color: var(--primary, var(--pp-primary)) !important; font-size: 13px !important; }
.oee-stat-value-row {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 120px;
}
.oee-stat-gauge {
    width: 100%;
    height: 120px;
    min-width: 0;
}
.oee-stat-spark {
    width: 100%;
    height: 28px;
}



/* === pp-51-statistics-policy.css === */
/* ============================================================================
 * pp-09i-statistics-policy.css
 * SCOPE  : STATISTICS KPI / FILTER PANEL / BADGE POLICY
 * 영역   : /map/index 사이트 뱃지, /statistics/index KPI 대시보드, alarm popup white, FILTER PANEL, BADGE POLICY ENFORCEMENT, MONITORING KPI, BADGE FORCE, priority/doc-type 뱃지, DASHBOARD CARD, BADGE TEXT WHITE GLOBAL, FLOW LIST 상태 뱃지
 * 주의   : 본 파일은 pp-09-recent-additions.css 분리본. ant concat-css 빌드.
 * ============================================================================ */
/* ============================================================
 * /map/index 사이트 목록 — 연결/건강 상태 뱃지 (디자인 시스템 톤)
 * priority-badge 시리즈와 동일 시그널 (그라데이션 + 흰 텍스트 + 라운드)
 * ============================================================ */
.site-status-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 22px;
    padding: 0 8px !important;
    font-size: 12px !important;
    font-weight: 700 !important;
    line-height: 1 !important;
    color: var(--pp-white) !important;
    border-radius: 11px !important;
    border: 1px solid transparent !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
    transition: transform 0.06s, box-shadow 0.12s;
}
.site-status-badge i {
    color: var(--pp-white) !important;
    font-size: 11px !important;
    line-height: 1 !important;
}
.site-status-badge:hover {
    transform: translateY(-1px);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.14), 0 3px 6px rgba(15, 23, 42, 0.16) !important;
}

.site-status-normal {
    background: var(--pp-tone-success-bg) !important;
    border-color: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important;
}
.site-status-warn {
    background: #b45309 !important;
    border-color: #b45309 !important;
    color: var(--pp-white) !important;
}
.site-status-error {
    background: #991b1b !important;
    border-color: #991b1b !important;
    color: var(--pp-white) !important;
}
.site-status-disconnected {
    background: #1e293b !important;
    border-color: #1e293b !important;
    color: var(--pp-white) !important;
}
.site-status-unknown {
    background: var(--pp-muted-fg) !important;
    border-color: var(--pp-muted-fg) !important;
    opacity: 0.85 !important;
    color: var(--pp-white) !important;
}


/* ============================================================
 * /statistics/index — KPI 대시보드 + 차트 그리드 (표준 컴포넌트)
 * 모든 카드 = 표준 pp:card(.card/.card-body), 모든 행 = 표준 pp:row(.row).
 * 커스텀 카드 chrome(stat-bottom-card / stat-chart-body / stat-main-row) 전부 제거.
 * 이 part 는 (1) 차트 컨테이너 높이, (2) KPI 값/델타/서브 텍스트 톤,
 *           (3) 한 줄 카드 높이 균등화, (4) row 수직 거터만 담당한다.
 * col 폭(col-lg-3/md-6)·좌우 거터·반응형 stacking 은 전부 Bootstrap 표준에 위임. */

/* (1) 차트 컨테이너 — echarts target 고정 높이(인라인 height 금지 → 단일 표준 클래스) */
body.page-statistics .stat-chart {
    width: 100%;
    min-width: 0;
    height: 240px;
}
/* 히트맵 — #heatmap_chart 는 더 낮은 표준 높이(160px). 표준 .card-body 패딩 유지. */
body.page-statistics #heatmap_chart {
    width: 100%;
    height: 160px;
}

/* (2) KPI 카드 값/델타/서브 텍스트 — 표준 .card-body 안에서 타이포만 정의 */
body.page-statistics .stat-kpi-value {
    font-size: 22px;
    font-weight: 700;
    line-height: 1.2;
    color: var(--foreground);
    font-variant-numeric: tabular-nums;
}
body.page-statistics .stat-kpi-value .stat-delta {
    font-size: 11px;
    font-weight: 600;
    color: var(--muted-foreground);
    letter-spacing: 0;
}
body.page-statistics .stat-kpi-sub {
    margin-top: 4px;
    font-size: 11px;
    color: var(--muted-foreground);
}

/* (3) 한 줄 내 카드 높이 균등(flex stretch) — 표준 .card 에 직접 적용.
       col 래퍼(.row > col-*)는 BS5 flex item 이라 카드를 100% 높이로 늘려 정렬 통일. */
body.page-statistics .row > [class*="col-"] > .card {
    height: 100%;
    margin-bottom: 0;
}

/* (4) row 수직 거터 — wrap 줄 간격 + 섹션 간격을 표준 .row margin-bottom 으로 통일.
       좌우 거터(.row 음수마진 + col 패딩)는 BS5 표준 그대로. 마지막 row 의 잉여 여백만 제거. */
body.page-statistics #page-wrapper .row {
    margin-bottom: 16px;
}
body.page-statistics #page-wrapper .row:last-child {
    margin-bottom: 0;
}

/* ============================================================
 * /map/index 사이트 팝업 — 알람 뱃지 배경색 + 흰 텍스트 (info/warn/error)
 * memory: badge_white_text_on_light_theme — 진한 배경 + 흰 텍스트 기본
 * ============================================================ */
.site-popup .alarm-info,
.site-popup .alarm-warn,
.site-popup .alarm-error,
.site-popup .alarm-info *,
.site-popup .alarm-warn *,
.site-popup .alarm-error *,
.site-popup .alarm-info a,
.site-popup .alarm-warn a,
.site-popup .alarm-error a,
.site-popup .alarm-info a *,
.site-popup .alarm-warn a *,
.site-popup .alarm-error a * {
    color: var(--pp-white) !important;
}
/* priority 톤 — alarm severity 토큰과 동일하게 background/border 고정 */
.site-popup .alarm-info  { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)) !important; border-radius: 4px !important; padding: 1px 4px !important; }
.site-popup .alarm-warn  { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)) !important; border-radius: 4px !important; padding: 1px 4px !important; }
.site-popup .alarm-error { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)) !important; border-radius: 4px !important; padding: 1px 4px !important; }
/* site-popup 헤더 — site-name / id 뱃지 흰 텍스트 */
.site-popup .site-popup-header,
.site-popup .site-popup-header *,
.site-popup .site-popup-header .site-name,
.site-popup .site-popup-header .site-name *,
.site-popup .site-popup-header .site-id-badge,
.site-popup .site-popup-header .site-id-badge * {
    color: var(--pp-white) !important;
}
.site-popup .site-popup-header .site-name > i {
    margin-right: 4px !important;
}

/* eq-status-badge — 카운터 뱃지 (정상/주의/위험) 텍스트 항상 흰색 */
.site-popup .eq-status-badge,
.site-popup .eq-status-badge * {
    color: var(--pp-white) !important;
}

/* site-popup 닫기 버튼 — 우상단 흰색 아이콘 */
.site-popup-close {
    position: absolute;
    top: 6px;
    right: 8px;
    background: none !important;
    border: 0 !important;
    color: var(--pp-white) !important;
    font-size: 14px !important;
    cursor: pointer;
    z-index: 2;
    padding: 4px !important;
    line-height: 1 !important;
    border-radius: 4px !important;
    transition: background 0.15s, color 0.15s;
}
.site-popup-close:hover {
    background: rgba(255, 255, 255, 0.18) !important;
    color: var(--pp-white) !important;
}


/* ============================================================
 * FILTER PANEL — 좌측 검색 패널 (panel.card 표준 + 컴팩트 보정)
 * /equipment/index, /canvas/index 등 좌측 col-lg-2 / col-md-3 검색 폼.
 * 외형(헤더/바디/푸터)은 표준 panel 패턴을 그대로 사용하고,
 * 이 add-on 은 (1) 좁은 col 폼 간격 컴팩트화, (2) 본문 안 sub-그룹 구분만 담당.
 * ============================================================ */

/* (1) 컴팩트 — 좁은 패널이므로 form-group 간격 축소 */
.pp-filter-panel .card-body .form-group {
    margin-bottom: 8px;
}
.pp-filter-panel .card-body .form-group:last-child {
    margin-bottom: 0;
}
.pp-filter-panel .card-body .form-label {
    margin-bottom: 4px !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--pp-muted-fg) !important;
}

/* (2) 본문 안 sub-fieldset 구분 (선택) — 시맨틱 아이콘 + 솔리드 보더 */
.pp-filter-fieldset + .pp-filter-fieldset {
    margin-top: 22px !important;
}
.pp-filter-fieldset-title {
    display: flex !important;
    align-items: center !important;
    gap: 6px !important;
    width: 100% !important;
    margin: 0 0 14px 0 !important;
    padding: 0 0 6px 0 !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    color: #57606a !important;
    letter-spacing: 0.04em !important;
    text-transform: uppercase !important;
    border-bottom: 1px solid var(--pp-border) !important;
}
.pp-filter-fieldset-title > i {
    color: var(--card-foreground) !important;
    font-size: 12px;
}


/* ============================================================
 * BADGE POLICY ENFORCEMENT — 진한 배경 + 흰 텍스트 일괄 보정
 * 라이트 테마 정책: 컬러 뱃지는 옅은 tint 가 아니라 진한 단색 + 흰 텍스트.
 *  (1) UNKNOWN 계열 — 회색 진한 톤 (var(--pp-border-strong) slate-600) + 흰 텍스트
 *  (2) .equip-card-badges 카드 안의 인라인-style 뱃지 — UNKNOWN(#ccc) 보강
 *  (3) .pp-type-badge.type-* — 6 종 컴포넌트 유형별 진한 컬러
 * 모든 declaration 은 cascade override 보장을 위해 !important.
 * ============================================================ */

/* (1-a) priority-badge-unknown — 기존 var(--muted-foreground,#9ca3af) 너무 옅음 → slate-600 */
body .priority-badge-unknown,
body .priority-badge-unknown *,
body #page-wrapper .priority-badge-unknown,
body #page-wrapper .priority-badge-unknown * {
    background: var(--pp-border-strong) !important;
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* (1-c) role-badge-unknown / state-badge-unknown — 신규. 슬레이트 진한 톤 */
body .role-badge.role-UNKNOWN,
body .role-badge-unknown {
    background: var(--pp-border-strong) !important;
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* (2) equip-card-badges — JS 가 인라인 background 으로 #ccc(UNKNOWN) 를 주입.
 *     CSS !important 는 인라인 non-important 를 override → 진한 슬레이트로 강제.
 *     정상 톤(#5cb85c/#3d8b40 등)은 substring 미일치라 영향 없음. */
.equip-card-badges span[style*="#ccc"],
.equip-card-badges span[style*="#CCC"],
.equip-card-badges span[style*="background:#ccc"],
.equip-card-badges span[style*="background: #ccc"] {
    background: var(--pp-border-strong) !important;
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* (3) pp-type-badge — 컴포넌트 유형 6 종. 카탈로그 14 번 노출 */
body .pp-type-badge {
    display: inline-block;
    padding: 2px 10px !important;
    border-radius: 10px !important;
    font-size: 10.5px !important;
    font-weight: 700 !important;
    line-height: 1.4 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.04em !important;
    text-transform: uppercase !important;
    border: 1px solid transparent !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body .pp-type-badge.type-server       { background: #7d7e7e !important;
    color: var(--pp-white) !important; }  /* gray — server 톤 다운 */
body .pp-type-badge.type-edge         { background: #6d28d9 !important;
    color: var(--pp-white) !important; }  /* violet-700 */
body .pp-type-badge.type-opc          { background: var(--pp-border-strong) !important;
    color: var(--pp-white) !important; }  /* slate-600 (진주 톤) */
body .pp-type-badge.type-asset_health { background: var(--pp-tone-success-bg) !important;
    color: var(--pp-white) !important; }  /* green-700 */
body .pp-type-badge.type-tag          { background: #c2410c !important;
    color: var(--pp-white) !important; }  /* orange-700 */
body .pp-type-badge.type-tag_value    { background: #0e7490 !important;
    color: var(--pp-white) !important; }  /* cyan-700 */


/* ============================================================
 * DESIGN SYSTEM — PlantPulse 도메인 뱃지 카탈로그 섹션 한정
 * 가독성을 위해 모든 뱃지 텍스트 흰색 강제. 단, id-badge 는 도메인 컬러
 * 보더 + 흰 배경 디자인이라 원래 텍스트 색상 유지.
 * ============================================================ */
#sec-pp-badges .ds-row-flex > *,
#sec-pp-badges .ds-row-flex > * > * {
    color: var(--pp-white) !important;
}
#sec-pp-badges .id-badge,
#sec-pp-badges .id-badge * {
    color: var(--foreground, #111827) !important;
}


/* ============================================================
 * MONITORING — KPI 카드 단위(span.text-hint-9-999) 한 줄 아래
 * 데이터 파이프라인 패널 아래의 PPS / JVM / 파이프라인 / 스토리지 카드
 * ============================================================ */
.mon-metric-body .mon-kv td .text-hint-9-999 {
    display: inline-block !important;
    margin-left: 4px !important;
    margin-top: 0 !important;
    font-size: 10px !important;
    color: var(--muted-foreground, var(--pp-text-muted)) !important;
    font-weight: 400 !important;
    text-transform: lowercase !important;
}
/* mon-kv — 깔끔한 key-value 테이블 (라벨 40% / 값 60%, 작은 글씨, 행 구분선) */
.mon-metric-body .mon-kv {
    table-layout: fixed !important;
    width: 100% !important;
    margin: 0 !important;
    border-collapse: collapse !important;
    font-size: 12px !important;
    line-height: 1.4 !important;
}
.mon-metric-body .mon-kv td {
    padding: 6px 12px !important;
    border-top: 1px solid var(--pp-border, #f1f5f9) !important;
    vertical-align: middle !important;
}
.mon-metric-body .mon-kv tr:first-child td {
    border-top: 0 !important;
}
.mon-metric-body .mon-kv td:first-child {
    width: 40% !important;
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-weight: 500 !important;
    font-size: 11px !important;
    letter-spacing: 0.01em !important;
}
.mon-metric-body .mon-kv td:last-child {
    width: 60% !important;
    color: var(--foreground, #0f172a) !important;
    font-weight: 600 !important;
    font-variant-numeric: tabular-nums !important;
    text-align: right !important;
}


/* ============================================================
 * BADGE FORCE — 진한 단색 + 흰 텍스트 + 표준 그림자 강제
 * 이전 룰들이 oklch 흐릿한 톤으로 override 하던 것을 마지막에 덮어씀.
 * ============================================================ */

/* 2. conn-badge-* — 진한 단색 + 흰 텍스트 강제 (디자인 시스템 표준 톤)
      ok: emerald-700 / warn: amber-600 / error: red-600 / disconnected: slate-600 / unknown: gray-500 */
body .conn-badge-ok           { background: var(--pp-tone-success-bg) !important; color: var(--pp-white) !important; box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important; }
body .conn-badge-warn         { background: var(--pp-tone-warn-bg) !important; color: var(--pp-white) !important; box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important; }
body .conn-badge-error        { background: var(--pp-tone-danger-bg) !important; color: var(--pp-white) !important; box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important; }
body .conn-badge-disconnected { background: var(--pp-border-strong) !important; color: var(--pp-white) !important; box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important; }
body .conn-badge-unknown      { background: var(--pp-muted-fg) !important; color: var(--pp-white) !important; box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important; }
body [class*="conn-badge-"] * { color: var(--pp-white) !important; }
/* conn-badge-* 의 opacity 강제 제거 — 외부 lib 또는 lifecycle 으로 인한 흐림 방지 */
body [class*="conn-badge-"] { opacity: 1 !important; }

/* 9. equip-status-* — 표준 box-shadow 부착 */
body .equip-status-run,
body .equip-status-idle,
body .equip-status-stop,
body .equip-status-fault,
body .equip-status-setup,
body .equip-status-planned,
body .equip-status-down,
body .equip-status-unknown {
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* 9-1. data-status="*" — 표준 box-shadow 부착 */
body div[data-status="RUN"],
body div[data-status="IDLE"],
body div[data-status="FAULT"],
body div[data-status="DOWN"],
body div[data-status="STOP"],
body div[data-status="SETUP"],
body div[data-status="PLANNED_STOP"],
body div[data-status="PLANNED_START"],
body div[data-status="UNKNOWN"] {
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}


/* ============================================================
 * priority-badge-unknown — 다른 priority-badge-* 와 동일 스타일 적용
 * (info/warn/error base 룰에 unknown 이 포함 안 돼 라디어스/패딩/그림자 빠지던 문제)
 * ============================================================ */
body #page-wrapper .priority-badge-unknown,
body .priority-badge-unknown {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 4px !important;
    min-width: 60px !important;
    padding: 3px 10px !important;
    border-radius: 12px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    color: var(--pp-white) !important;
    letter-spacing: 0.3px !important;
    line-height: 1.4 !important;
    background: var(--pp-border-strong) !important;          /* slate-600 — UNKNOWN 표준 회색 */
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}

/* (제거됨) doc-type-badge 스타일 — 표준 .pp-badge .pp-tone-muted 로 통합(죽은 CSS). */

/* ============================================================
 * DASHBOARD CARD — 단위 줄바꿈
 * 카드 내부 숫자(값) 옆에 inline span 으로 붙어 있는 단위 텍스트를
 * 다음 줄(아래 줄)로 떨어뜨려 가독성 확보.
 * 대상 단위: ms / pps / p/s / 작업자 / 대기큐 / 건 등
 * 적용 카드:
 *   - .kpi-stat-card  (map/include/kpi-strip, analysis, statistics)
 *   - .kpi-card-v2    (design-system data-display)
 *   - .mon-metric-body .mon-kv  (monitoring/index — 위쪽 섹션에서 이미 처리)
 * ============================================================ */
body .kpi-stat-card .kpi-stat-card-value .kpi-stat-card-unit,
body .kpi-stat-card-value > .kpi-stat-card-unit {
    display: block !important;
    margin-top: 2px !important;
    margin-left: 0 !important;
    padding-left: 0 !important;
    line-height: 1.2 !important;
}

body .kpi-card-v2 .kpi-card-v2-value .kpi-card-v2-unit,
body .kpi-card-v2-value > .kpi-card-v2-unit {
    display: block !important;
    margin-top: 2px !important;
    margin-left: 0 !important;
    line-height: 1.2 !important;
}


/* ============================================================
 * BADGE TEXT WHITE GLOBAL + A NO UNDERLINE
 * 정책: 라이트 테마 — 컬러 뱃지 = 진한 배경 + 흰 텍스트가 표준.
 *      예외: .id-badge (도메인 ID 뱃지, 흰 배경 + 컬러 보더 디자인).
 * 추가: <a> 태그 underline 전역 제거 (hover 포함).
 * ============================================================ */

/* (1-A) 옅은 tint + 다크 텍스트로 남아있던 alarm-priority-badge — 진한 배경 + 흰 텍스트 강제
 *       (pp-01:747-761 의 rgba 0.10 옅은 tint 룰 무력화) */
body #page-wrapper .alarm-priority-badge.info,
body .alarm-priority-badge.info {
    background: oklch(0.45 0.16 145) !important;      /* green-700 */
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body #page-wrapper .alarm-priority-badge.warn,
body .alarm-priority-badge.warn {
    background: oklch(0.55 0.18 65) !important;       /* amber-600 */
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body #page-wrapper .alarm-priority-badge.error,
body .alarm-priority-badge.error {
    background: oklch(0.50 0.22 25) !important;       /* red-700 */
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body #page-wrapper .alarm-priority-badge.info *,
body #page-wrapper .alarm-priority-badge.warn *,
body #page-wrapper .alarm-priority-badge.error *,
body .alarm-priority-badge.info *,
body .alarm-priority-badge.warn *,
body .alarm-priority-badge.error * {
    color: var(--pp-white) !important;
}

/* default .badge 광범위 강제 룰 제거 — 개별 뱃지 클래스 (.dt-badge, .stmt-status-badge, .health-badge 등) 가 자체 톤 정의 */

/* [class*="-badge"] 광범위 흰 텍스트 강제 룰 제거 — 개별 뱃지 클래스가 자체 톤 정의 */
/* [class*="-status-"] 광범위 흰 텍스트 강제 룰 제거 — 개별 status 클래스가 자체 톤 정의 */
body [class*="priority-badge"]:not(.id-badge),
body [class*="priority-badge"]:not(.id-badge) * {
    color: var(--pp-white) !important;
}
body [class*="level-badge"],
body [class*="level-badge"] *,
body [class*="log-level-"],
body [class*="log-level-"] *,
body [class*="diag-level-"],
body [class*="diag-level-"] * {
    color: var(--pp-white) !important;
}
body .health-badge,
body .health-badge *,
body [class*="health-badge"]:not(.id-badge),
body [class*="health-badge"]:not(.id-badge) * {
    color: var(--pp-white) !important;
}

/* (2-A) 사용자 명시 — side-h-badge / batch-health-badge / role-badge */
body .side-h-badge,
body .side-h-badge *,
body .side-h-badge-ok,
body .side-h-badge-ok *,
body .side-h-badge-err,
body .side-h-badge-err *,
body .side-h-badge-mute,
body .side-h-badge-mute * {
    color: var(--pp-white) !important;
}
body .batch-health-badge *,
body #batch_health_badge,
body #batch_health_badge * {
    color: var(--pp-white) !important;
}
body .role-badge,
body .role-badge * {
    color: var(--pp-white) !important;
}

/* (2-B) wo-* 워크오더 뱃지 — 자손 흰 텍스트 보강 (배경은 이미 진한 oklch) */
body [class*="wo-status-"],
body [class*="wo-status-"] *,
body [class*="wo-priority-"],
body [class*="wo-priority-"] * {
    color: var(--pp-white) !important;
}

/* (3) id-badge 도메인 ID 뱃지 — 흰 배경 + 컬러 보더 디자인 보존 (예외 화이트리스트) */
body .id-badge,
body .id-badge * {
    color: var(--foreground, #111827) !important;
}
body .id-badge.id-badge-clickable,
body .id-badge.id-badge-clickable * {
    color: var(--foreground, #111827) !important;
}
/* (4) <a> 태그 underline 전역 제거 — hover/focus/active 모두 무 underline (사용자 정책) */
body #page-wrapper a,
body a {
    text-decoration: none !important;
}
body #page-wrapper a:hover,
body #page-wrapper a:focus,
body #page-wrapper a:active,
body a:hover,
body a:focus,
body a:active {
    text-decoration: none !important;
}


/* ============================================================
 * FLOW LIST — 상태 뱃지 (활성/비활성) + ID 뱃지 monospace 변형
 * 인라인 스타일 제거 후 시맨틱 클래스로 추출
 * ============================================================ */
body .flow-status-badge {
    display: inline-flex !important;
    align-items: center !important;
    gap: 4px !important;
    padding: 3px 14px !important;
    border-radius: 24px !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    color: var(--pp-white) !important;
    box-shadow: rgba(255, 255, 255, 0.08) 0px 0px 0px 1px inset, rgba(15, 23, 42, 0.15) 0px 1px 3px !important;
}
body .flow-status-badge.flow-status-on  { background: #3d8b40 !important; }   /* green-700 — 배치됨 */
body .flow-status-badge.flow-status-off { background: var(--pp-muted-fg) !important; }   /* gray-500 — 해제됨 */

/* id-badge monospace 변형 — 코드성 ID (FLOW_ABC123 등) 가독성 */
body .id-badge.id-badge-mono {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace !important;
    font-size: 11px !important;
}


/* ============================================================
 * BADGE FORCE WHITE — Playwright 검출 결과 일괄 적용 (oklch 어두운 텍스트 상속 차단)
 * 모든 진한 배경 뱃지의 텍스트색을 흰색으로 강제 (id-badge 제외).
 * ============================================================ */
body .health-badge,
body [class*="conn-badge-"],
body .equip-status-run,
body .equip-status-stop,
body [class*="eq-status-dot"],
body [class*="pp-type-badge"],
body .flow-status-badge,
body .canvas-card-badge,
body [class*="canvas-card-badge-"],
body [class*="site-status-badge"],
body [class*="side-h-badge"],
body .dt-badge,
body .value-q-badge,
body .value-q-good,
body .value-q-uncertain,
body .value-q-bad {
    color: var(--pp-white) !important;
}
body .health-badge *,
body [class*="conn-badge-"] *,
body .flow-status-badge *,
body [class*="canvas-card-badge"] *,
body [class*="pp-type-badge"] *,
body .dt-badge *,
body .value-q-badge * {
    color: var(--pp-white) !important;
}


/* ============================================================
 * BADGE TEXT FIX 7 — 어두운 배경 위 검정 텍스트 일괄 흰색 강제
 * 적용 영역:
 *   #1 /map/index 데이터 파이프라인 health-badge (icon 포함)
 *   #2 echarts tooltip — 어두운 배경 위 검정 텍스트
 *   #3 /monitoring/index .mon-infra-badge — JS 동적 background
 *   #4 site 알람 뱃지 (alarm-info/warn/error) 안전망
 *   #5 /diagnostic/index .diag-badge-info/warn/error 통계 뱃지
 *   #6 .pp-type-badge.type-server 톤 변경 (위 라인 처리)
 *   #7 conn-badge-* 텍스트 흰색 (이미 처리되어 있음)
 * ============================================================ */

/* #1 — map-pipeline-overlay health-badge: icon + span 모두 흰색 강제 */
body .map-pipeline-overlay .health-badge.map-ov-chip-xs,
body .map-pipeline-overlay .health-badge.map-ov-chip-xs * {
    color: var(--pp-white) !important;
}

/* #2 — echarts tooltip 텍스트 흰색 + 어두운 반투명 배경 강제
       (echarts 가 inline style 로 background 적용 → 검정 텍스트 가독성 0) */
body .echarts-tooltip,
body div[id^="echarts-tooltip"],
body div[id*="ecTooltip"] {
    color: var(--pp-white) !important;
    background: rgba(15, 23, 42, 0.92) !important;
    border-color: rgba(255, 255, 255, 0.12) !important;
}
body .echarts-tooltip *,
body div[id^="echarts-tooltip"] *,
body div[id*="ecTooltip"] * {
    color: var(--pp-white) !important;
}

/* #3 — .mon-infra-badge (redis/stomp/mqtt/kafka/cassandra/timeseries)
       JS healthBadge() 가 inline 으로 background 설정. 외부 div 텍스트도 흰색. */
body .mon-infra-badge {
    color: var(--pp-white) !important;
    padding: 2px 9px !important;
    border-radius: 999px !important;
}
body .mon-infra-badge * {
    color: var(--pp-white) !important;
}

/* #4 — site 알람 뱃지 (alarm-info/warn/error) 안전망 — 모든 자손 흰색 */
body .alarm-summary-bar .alarm-info,
body .alarm-summary-bar .alarm-info *,
body .alarm-summary-bar .alarm-warn,
body .alarm-summary-bar .alarm-warn *,
body .alarm-summary-bar .alarm-error,
body .alarm-summary-bar .alarm-error * {
    color: var(--pp-white) !important;
}

/* #5 — /diagnostic/index 통계 뱃지 (.label.diag-badge-*)
 *   형태(8px 소프트라운드)·배경 톤(info/warn/danger)은 카논(pp-74-status-tones.css)이
 *   단독 소유한다. diag-badge-* family 는 pp-74 의 shape canon + 톤 토큰 규칙에 이미 포함됨.
 *   여기서는 .label 부트스트랩 기본형(둥근 알약·중립색) 안전망과 자손 텍스트 흰색만 보강 —
 *   비카논 hex(amber-700/red-800)·radius:12px 는 제거해 레벨 뱃지(table row level-badge-*)와
 *   동일 형태·톤으로 일관화한다. */
body .diag-stats-badges .label.diag-badge-info *,
body .diag-stats-badges .label.diag-badge-warn *,
body .diag-stats-badges .label.diag-badge-error *,
body .diag-badge-info *,
body .diag-badge-warn *,
body .diag-badge-error * {
    color: var(--pp-white) !important;
}

/* #8 — /map/index 위도/경도 오버레이 (어두운 배경 + 흰 텍스트) 안전망
       map-overlays.jsp 인라인 style 제거 후 클래스 화 — 본 파일 + pp-07b 양쪽 cover */
body .map-ov-latlng-bar,
body .map-ov-latlng-bar *,
body .map-ov-latlng-bar B,
body .map-ov-latlng-bar #current-lat-lng {
    color: var(--pp-white) !important;
}

/* #9 — 일반 안전망: map-overlay 류의 어두운 칩 안 텍스트 흰색
       (map-pipeline-overlay 외 어두운 배경 오버레이 자식 텍스트 가드) */
body .map-overlay.map-ov-latlng-bar,
body .map-overlay.map-ov-latlng-bar > B,
body .map-overlay.map-ov-latlng-bar > span {
    color: var(--pp-white) !important;
}


/* ============================================================
 * BADGE TEXT FIX 9 — 모든 뱃지 텍스트 흰색 강제 (id-badge 제외)
 *  - id-badge 는 도메인 컬러 보더 + 흰 배경 디자인 (도메인 컬러 텍스트 유지)
 *  - 그 외 [class*="badge"], [class*="-badge"], .label 모두 var(--pp-white) 강제
 *  - body 안 자손까지 흰색 (i 아이콘 + span 텍스트 모두 포함)
 *  - 색상은 :root 의 --pp-white 토큰 사용 → 테마 교체 가능
 * ============================================================ */
/* BADGE TEXT FIX 9 광범위 흰 텍스트 강제 룰 제거 — 개별 뱃지 클래스가 자체 톤 정의 (popover 부수효과 회피) */

/* ============================================================
 * Bootstrap tooltip — 어두운 배경 + 흰 텍스트 강제 (signal 토큰)
 *  - 일부 부모 룰이 흰 배경으로 덮어 텍스트 안 보이는 케이스 회피
 * ============================================================ */
body .tooltip-inner {
    background-color: var(--foreground) !important;
    color: var(--pp-white) !important;
    /* 전역 툴팁 텍스트 축소 — BS5 기본 0.875rem(14px) → 12px, 패딩 컴팩트 */
    font-size: 12px !important;
    line-height: 1.4 !important;
    padding: 4px 8px !important;
}
body .tooltip.top .tooltip-arrow,
body .tooltip[x-placement^="top"] .tooltip-arrow,
body .tooltip.bs-tooltip-top .tooltip-arrow {
    border-top-color: var(--foreground) !important;
}
body .tooltip.bottom .tooltip-arrow,
body .tooltip[x-placement^="bottom"] .tooltip-arrow,
body .tooltip.bs-tooltip-bottom .tooltip-arrow {
    border-bottom-color: var(--foreground) !important;
}
body .tooltip.left .tooltip-arrow,
body .tooltip[x-placement^="left"] .tooltip-arrow,
body .tooltip.bs-tooltip-left .tooltip-arrow {
    border-left-color: var(--foreground) !important;
}
body .tooltip.right .tooltip-arrow,
body .tooltip[x-placement^="right"] .tooltip-arrow,
body .tooltip.bs-tooltip-right .tooltip-arrow {
    border-right-color: var(--foreground) !important;
}

/* ============================================================
 * Popover (Bootstrap + pp-help-popover) — 라이트 본문 + 다크 헤더 타이틀
 *  - 본문: 흰 배경 + foreground 텍스트
 *  - 타이틀: foreground 다크 배경 + 흰 텍스트
 *  - arrow: 투명 (테두리 보이지 않게)
 * ============================================================ */
body .popover,
body .popover-content,
body .popover-body,
body .pp-help-popover,
body .pp-help-popover-content {
    background: var(--pp-white) !important;
    color: var(--foreground) !important;
    border-color: var(--border) !important;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12), 0 2px 4px rgba(15, 23, 42, 0.06) !important;
}
/* 컨테이너 radius 를 헤더/바디 코너(14px)와 일치 — BS5 기본(8px)과 어긋나 보더/라디우스 이상하던 문제 보정.
   body .popover(0,1,1) 가 BS5 .popover(0,1,0) 를 이겨 강제선언 없이 적용. arrow 는 컨테이너 밖이라 영향 없음. */
body .popover { border-radius: 14px; }
body .popover-content *,
body .popover-body * {
    color: var(--foreground) !important;
    border-color: var(--border) !important;
}
/* pp-help-popover 본문은 universal color 강제에서 제외 — 내부 색상 뱃지(pp-badge pp-tone-*)·범례 색을 살린다.
   본문 기본색은 .pp-help-popover-content(아래)에서 지정, 자식은 상속. */

/* 공통 도움말 컨텐츠 컴포넌트 (PP.help.*) — 합성형 fragment.
   pp-help 본문(.pp-help-popover-content) 안에서 legend/text/note/kv/subtitle 를 자유 조합. */
.pp-help-popover-content > * + * { margin-top: 8px; }   /* 블록 간 간격 */
/* legend — 색상 뱃지 + 설명 2열 정렬 */
.pp-help-legend { display: flex; flex-direction: column; gap: 7px; }
.pp-help-legend-row {
    display: grid;
    grid-template-columns: 112px 1fr;
    gap: 12px;
    align-items: center;
}
.pp-help-legend-row .pp-badge { justify-self: start; }
.pp-help-legend-desc {
    font-size: 12px;
    line-height: 1.45;
    color: var(--muted-foreground);
}
/* text — 설명 문단 */
.pp-help-text { font-size: 12px; line-height: 1.5; color: var(--foreground); }
/* subtitle — 컨텐츠 내 소제목 */
.pp-help-subtitle {
    font-size: 10px; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase;
    color: var(--muted-foreground); margin-bottom: 2px;
}
/* note — 강조 노트 (좌측 보더 tone) */
.pp-help-note {
    font-size: 12px; line-height: 1.45; padding: 7px 10px;
    border-left: 3px solid var(--border);
    background: var(--muted); border-radius: 0 8px 8px 0;
}
.pp-help-note--info    { border-left-color: var(--pp-tone-info-bg); }
.pp-help-note--success { border-left-color: var(--pp-tone-success-bg); }
.pp-help-note--warn    { border-left-color: var(--pp-tone-warn-bg); }
.pp-help-note--danger  { border-left-color: var(--pp-tone-danger-bg); }
/* kv — label:value 행 */
.pp-help-kv { display: flex; flex-direction: column; gap: 4px; }
.pp-help-kv-row { display: grid; grid-template-columns: 88px 1fr; gap: 10px; }
.pp-help-kv-label { font-size: 11px; font-weight: 600; color: var(--muted-foreground); }
.pp-help-kv-value { font-size: 12px; color: var(--foreground); }
/* 타이틀 헤더 — 다크 배경 + 흰 텍스트 + 상단 모서리 라운드(14px, 카드/모달 통일) */
body .popover-title,
body .popover-header,
body .pp-help-popover-title {
    background: var(--foreground) !important;
    color: var(--pp-white) !important;
    border-bottom-color: var(--foreground) !important;
    border-top-left-radius: 14px !important;
    border-top-right-radius: 14px !important;
}
/* 본문(마지막 요소) — 하단 모서리도 라운드 (헤더 상단과 대칭).
   .popover 에 overflow:hidden 은 화살표를 잘라 못 쓰므로 body 에 직접 부여. */
body .popover-body,
body .pp-help-popover-content {
    border-bottom-left-radius: 14px !important;
    border-bottom-right-radius: 14px !important;
}
body .popover-title *,
body .popover-header *,
body .pp-help-popover-title * {
    color: var(--pp-white) !important;
}
/* arrow — 투명 (테두리 색만) */
body .popover .arrow,
body .popover .popover-arrow {
    background: transparent !important;
}
body .popover.left .arrow,
body .popover.left > .arrow,
body .popover[x-placement^="left"] .arrow,
body .popover.bs-tether-element-attached-right .arrow {
    border-left-color: var(--pp-white) !important;
}
body .popover.right .arrow,
body .popover.right > .arrow,
body .popover[x-placement^="right"] .arrow,
body .popover.bs-tether-element-attached-left .arrow {
    border-right-color: var(--pp-white) !important;
}
body .popover.top .arrow,
body .popover.top > .arrow,
body .popover[x-placement^="top"] .arrow,
body .popover.bs-tether-element-attached-bottom .arrow {
    border-top-color: var(--pp-white) !important;
}
body .popover.bottom .arrow,
body .popover.bottom > .arrow,
body .popover[x-placement^="bottom"] .arrow,
body .popover.bs-tether-element-attached-top .arrow {
    border-bottom-color: var(--pp-white) !important;
}

/* ============================================================
 * /statistics/index — 가로 스크롤 차단
 *  - row 음수 마진 / grid gap / ECharts 컨테이너 overflow 안전망
 * ============================================================ */
body.page-statistics #page-wrapper {
    overflow-x: hidden !important;
}

/* 로딩 진행 다이얼로그(showProgress)는 pp-30 의 정본 디자인을 그대로 사용한다.
 * (이전의 body.page-statistics 한정 오버라이드는 정본 승격으로 제거됨) */

/* === pp-52-alarm-dropdown.css === */
/* ============================================================
 * 상단 툴바 — 최근 알람 dropdown (pp-alarmdd-*)
 * 카드형 row + priority left color band + hover lift
 * 컬러 토큰 기반 — dark-mode-ready
 *
 * 마크업: nav.jsp #alarm_recent (.pp-alarmdd) + nav.js loadAlarms()
 * 카탈로그: /design-system/index → "Alarm dropdown"
 * ============================================================ */

/* container — 상단 툴바 우측에 붙는 viewport-safe 알람 패널 */
.pp-top-toolbar .pp-tb-popover-alarm.pp-alarmdd {
    right: 0 !important;
    left: auto !important;
    width: min(calc(100vw - 24px), 420px);
    min-width: min(calc(100vw - 24px), 420px);
    max-width: calc(100vw - 24px);
    padding: 0 !important;
    border: 1px solid rgba(15, 23, 42, 0.12);
    border-radius: 8px;
    background: var(--popover, var(--pp-white));
    box-shadow: 0 18px 48px rgba(15, 23, 42, 0.18), 0 4px 12px rgba(15, 23, 42, 0.08);
    overflow: hidden;
}

/* ---- 헤더: 타이틀 + 우측 View all 링크 ---- */
.pp-alarmdd .pp-alarmdd-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 44px;
    padding: 11px 14px;
    background: #f8fafc;
    border-bottom: 1px solid rgba(148, 163, 184, 0.28);
}

.pp-alarmdd-header-title {
    display: inline-flex;
    align-items: center;
    min-width: 0;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--foreground, #111827);
}

.pp-alarmdd-header-title > i {
    color: var(--primary, var(--pp-primary-strong));
    font-size: 14px;
}

.pp-alarmdd-header-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
    font-size: 12px;
    font-weight: 600;
    color: var(--primary, var(--pp-primary-strong));
    text-decoration: none;
    transition: opacity 0.12s;
}

.pp-alarmdd-header-link:hover,
.pp-alarmdd-header-link:focus {
    color: var(--primary, var(--pp-primary-strong));
    opacity: 0.75;
    text-decoration: none;
}

.pp-alarmdd-header-link > i {
    font-size: 11px;
}

/* ---- body: scrollable list (max 7~8 rows) ---- */
.pp-alarmdd-body {
    display: block;
    padding: 8px;
    max-height: min(432px, calc(100vh - 92px));
    overflow-y: auto;
    background: var(--popover, var(--pp-white));
}

/* 스크롤바 톤 다운 */
.pp-alarmdd-body::-webkit-scrollbar { width: 6px; }
.pp-alarmdd-body::-webkit-scrollbar-thumb {
    background: var(--border, var(--pp-border));
    border-radius: 3px;
}

/* ---- row (card-style) ---- */
.pp-alarmdd-row {
    display: flex !important;
    align-items: flex-start;
    gap: 10px;
    position: relative;
    width: 100%;
    min-height: 58px;
    box-sizing: border-box;
    padding: 10px 12px;
    margin: 0 0 6px;
    border: 1px solid rgba(148, 163, 184, 0.22);
    border-radius: 8px;
    background: #ffffff;
    color: var(--foreground, #111827);
    text-decoration: none;
    transition: background 0.14s ease, border-color 0.14s ease, transform 0.14s ease;
    overflow: hidden;
}

.pp-alarmdd-row:last-child { margin-bottom: 0; }

.pp-alarmdd-row:hover,
.pp-alarmdd-row:focus {
    background: var(--muted, #f8fafc);
    border-color: rgba(100, 116, 139, 0.28);
    color: var(--foreground, #111827);
    text-decoration: none;
    /* hover 시 위치 이동 제거 — 마우스오버해도 row 가 흔들리지 않고 그대로 유지 */
}

/* priority 좌측 색띠 (4px) */
.pp-alarmdd-band {
    position: static;
    flex: 0 0 4px;
    align-self: stretch;
    width: 4px;
    min-height: 38px;
    margin: 2px 0;
    border-radius: 4px;
    background: var(--muted-foreground, var(--pp-muted-fg));
}

.pp-alarmdd-row.is-info    .pp-alarmdd-band { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)); }
.pp-alarmdd-row.is-warn    .pp-alarmdd-band { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)); }
.pp-alarmdd-row.is-error   .pp-alarmdd-band { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)); }

/* row 내부 — title row + msg */
.pp-alarmdd-row-main {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    gap: 5px;
}

.pp-alarmdd-row-top {
    display: flex;
    align-items: center;
    min-width: 0;
    gap: 8px;
}

/* priority badge — 흰 텍스트 on 컬러 배경 (라이트 테마 표준) */
.pp-alarmdd-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;                     /* 우선순위 아이콘 ↔ 라벨 간격 */
    flex: 0 0 auto;
    min-width: 44px;
    height: 18px;
    padding: 0 7px;
    border-radius: 9px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: var(--pp-white, #ffffff);
    background: var(--muted-foreground, var(--pp-muted-fg));
    white-space: nowrap;
}

.pp-alarmdd-badge.is-info  { background: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)); border-color: var(--pp-alarm-info-bg, var(--pp-tone-success-bg)); }
.pp-alarmdd-badge.is-warn  { background: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)); border-color: var(--pp-alarm-warn-bg, var(--pp-tone-warn-bg)); color: var(--pp-white, #ffffff); }
.pp-alarmdd-badge.is-error { background: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)); border-color: var(--pp-alarm-error-bg, var(--pp-tone-danger-bg)); }

/* 상대 시간 (우측) */
.pp-alarmdd-ago {
    margin-left: auto;
    font-size: 11px;
    font-weight: 500;
    color: var(--subtle-foreground, #9ca3af);
    white-space: nowrap;
}

/* 알람 메시지 (한 줄 ellipsis) */
.pp-alarmdd-msg {
    display: -webkit-box;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--foreground, #1f2937);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: normal;
    word-break: keep-all;
    overflow-wrap: anywhere;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

/* ---- 빈/에러 상태 ---- */
.pp-alarmdd-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 36px 16px;
    text-align: center;
}

.pp-alarmdd-state-icon {
    font-size: 28px;
    color: var(--subtle-foreground, var(--pp-text-soft));
}

.pp-alarmdd-state-text {
    font-size: 12.5px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    word-break: keep-all;
}

.pp-alarmdd-error .pp-alarmdd-state-icon {
    color: var(--destructive, var(--pp-tone-danger-bg));
}

.pp-alarmdd-error .pp-alarmdd-state-text {
    color: var(--destructive, var(--pp-tone-danger-bg));
    font-weight: 500;
}

/* === pp-53-map-status-colors.css === */
/* ============================================================
 * Map / Status legend swatch 색상 토큰
 * ------------------------------------------------------------
 * map/include/map-overlays.jsp, map/site.jsp, map/include/diagnostic-sidebar.jsp 등
 * legend swatch 의 인라인 background:#XXX 를 utility class 로 치환.
 *
 * 색상 의미:
 *   ok      = #2e7d32 — 정상 연결
 *   delay   = #e65100 — 연결 지연
 *   anomaly = #b71c1c — 연결 이상
 *   disc    = #7f1d1d — 연결 끊김
 *   none    = #9ca3af — 미사용/없음
 * ============================================================ */
.pp-status-bg-ok      { background: #2e7d32 !important; }
.pp-status-bg-delay   { background: #e65100 !important; }
.pp-status-bg-anomaly { background: #b71c1c !important; }
.pp-status-bg-disc    { background: #7f1d1d !important; }
.pp-status-bg-none    { background: #9ca3af !important; }
.pp-status-bg-muted   { background: #888 !important; }

/* site-popup 내 적용 시 specificity 보강 (`.site-popup .eq-status-badge` 가 specificity 0,2,0
 * 이라 단일 `.pp-status-bg-*` (0,1,0) 의 background 가 일부 환경에서 적용 안 되는 케이스 보정) */
.site-popup .pp-status-bg-ok      { background: #2e7d32 !important; }
.site-popup .pp-status-bg-delay   { background: #e65100 !important; }
.site-popup .pp-status-bg-anomaly { background: #b71c1c !important; }
.site-popup .pp-status-bg-disc    { background: #7f1d1d !important; }
.site-popup .pp-status-bg-none    { background: #9ca3af !important; }
.site-popup .pp-status-bg-muted   { background: #888 !important; }

/* === pp-54-uns.css === */
/* ============================================================================
 * pp-09l-uns.css
 * SCOPE  : UNS namespace tree and topic preview (/uns/tree)
 * ============================================================================ */

.uns-workspace {
    row-gap: 16px;
}

.uns-panel .card-body {
    min-width: 0;
}

.uns-tree-toolbar {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.uns-search {
    margin-top: 0;
}

.uns-tree-pane {
    max-height: 680px;
    overflow: auto;
    padding-top: 0 !important;
}

.uns-tree {
    min-height: 280px;
}

.uns-tree-node {
    margin: 2px 0;
}

.uns-tree-children {
    margin-left: 18px;
    padding-left: 10px;
    border-left: 1px dashed var(--border, var(--pp-border));
}

.uns-node-btn {
    width: 100%;
    min-height: 42px;
    display: grid;
    grid-template-columns: 22px minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: transparent;
    color: var(--foreground, #111827);
    padding: 6px 8px;
    text-align: left;
}

.uns-node-btn:hover,
.uns-node-btn.active {
    background: var(--bg-muted, #f8fafc);
    border-color: var(--border, var(--pp-border));
}

.uns-node-btn.active {
    box-shadow: inset 3px 0 0 var(--primary, var(--pp-primary-strong));
}

.uns-node-btn > i {
    color: var(--primary, var(--pp-primary-strong));
}

.uns-node-main {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.uns-node-main strong,
.uns-node-main small,
.uns-selected-path,
.uns-topic-row code {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap !important;
}

.uns-node-main strong {
    font-size: 13px !important;
    font-weight: 600 !important;
}

.uns-node-main small {
    color: var(--muted-foreground, var(--pp-muted-fg)) !important;
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 11px !important;
}

.uns-node-type,
.uns-type-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 22px;
    border-radius: 999px;
    border: 1px solid var(--border, var(--pp-border));
    background: var(--card, #fff);
    color: var(--muted-foreground, var(--pp-muted-fg));
    padding: 0 8px;
    font-size: 10px !important;
    font-weight: 700 !important;
    letter-spacing: 0;
}

.uns-selected-empty,
.uns-empty {
    min-height: 140px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    text-align: center;
}

.uns-empty.compact {
    min-height: 42px;
    justify-content: flex-start;
    text-align: left;
    padding: 8px 0;
}

.uns-empty.danger {
    color: var(--destructive, var(--pp-tone-danger-bg));
}

.uns-selected-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(160px, 42%);
    gap: 12px;
    align-items: start;
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border, var(--pp-border));
}

.uns-selected-head h3 {
    margin: 8px 0 0;
    font-size: 18px !important;
    font-weight: 700 !important;
}

.uns-selected-path {
    justify-self: end;
    max-width: 100%;
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-family: 'SFMono-Regular', 'Consolas', monospace !important;
    font-size: 12px !important;
}

.uns-route-preview,
.uns-related-links {
    min-width: 0;
    margin-bottom: 14px;
}

.uns-route-title {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 8px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-size: 12px !important;
    font-weight: 700 !important;
}

.uns-route-chip-list,
.uns-related-link-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    min-width: 0;
}

.uns-route-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border: 1px solid var(--border, var(--pp-border));
    border-radius: 6px;
    background: var(--bg-muted, #f8fafc);
    padding: 5px 8px;
    color: var(--foreground, #111827);
    font-size: 11px !important;
}

.uns-route-chip strong {
    flex: 0 0 auto;
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-size: 10px !important;
}

.uns-route-chip span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.uns-related-link-row {
    display: grid;
    grid-template-columns: 18px auto minmax(0, 1fr);
    gap: 7px;
    align-items: center;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border: 1px solid var(--border, var(--pp-border));
    border-radius: 6px;
    background: var(--card, #fff);
    padding: 6px 8px;
    color: var(--foreground, #111827);
    font-size: 11px !important;
}

.uns-related-link-row:hover {
    border-color: var(--primary, var(--pp-primary-strong));
    text-decoration: none;
}

.uns-related-link-row.text-only:hover {
    border-color: var(--border, var(--pp-border));
}

.uns-related-link-row > * {
    min-width: 0;
}

.uns-related-link-row span {
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-weight: 700 !important;
}

.uns-related-link-row code {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    background: transparent;
    border: 0;
    padding: 0;
    color: inherit;
    font-size: 11px !important;
}

.uns-selected-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    min-width: 0;
}

.uns-ai-topic {
    margin: 12px 0 14px;
    border: 1px solid var(--border, var(--pp-border));
    border-radius: 6px;
    background: var(--card, #fff);
    padding: 12px;
}

.uns-ai-topic-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
    min-width: 0;
}

.uns-ai-topic-head span {
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-size: 12px !important;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.uns-ai-topic h4 {
    margin: 8px 0 6px;
    font-size: 12px !important;
    font-weight: 700 !important;
}

.uns-ai-topic ul {
    margin: 0 0 6px;
    padding-left: 18px;
}

.uns-ai-topic li {
    margin-bottom: 4px;
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.uns-topic-section {
    min-width: 0;
}

.uns-topic-section h4 {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 10px;
    font-size: 13px !important;
    font-weight: 700 !important;
}

.uns-topic-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.uns-topic-row {
    display: grid;
    grid-template-columns: 118px minmax(0, 1fr) 28px;
    gap: 8px;
    align-items: center;
    min-height: 34px;
    padding: 5px 6px;
    border: 1px solid var(--border, var(--pp-border));
    border-radius: 6px;
    background: var(--card, #fff);
}

.uns-topic-row > * {
    min-width: 0;
}

.uns-topic-key {
    color: var(--muted-foreground, var(--pp-muted-fg));
    font-size: 11px !important;
    font-weight: 700 !important;
}

.uns-topic-row code {
    display: block;
    width: 100%;
    overflow: hidden !important;
    max-width: 100%;
    box-sizing: border-box;
    color: var(--foreground, #111827);
    background: var(--bg-muted, #f8fafc);
    border: 1px solid var(--border, var(--pp-border));
    border-radius: 5px;
    padding: 4px 6px;
    font-size: 11px !important;
}

.uns-copy-btn {
    width: 28px;
    height: 28px;
    padding: 0 !important;
}

.uns-config-grid {
    row-gap: 12px;
}

.uns-sparkplug {
    display: inline-flex;
    align-items: center;
    width: 100%;
    gap: 8px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border, var(--pp-border));
}

.uns-type-pill.on {
    color: var(--success, var(--pp-tone-success-bg));
    border-color: color-mix(in srgb, var(--success, var(--pp-tone-success-bg)) 32%, white);
}

.uns-type-pill.off {
    color: var(--muted-foreground, var(--pp-muted-fg));
}

@media (max-width: 991px) {
    .uns-selected-head {
        grid-template-columns: 1fr;
    }

    .uns-selected-path {
        justify-self: start;
    }

    .uns-selected-actions {
        align-items: flex-start;
    }

    .uns-topic-row {
        grid-template-columns: minmax(82px, 110px) minmax(0, 1fr) 28px;
    }
}

/* === pp-55-catalog.css === */
/* ============================================================
 * pp-09m-catalog — 데이터 카탈로그 (Metastore / Eventstore 스키마 뷰어)
 * master-detail: 좌측 테이블 목록 + 우측 컬럼/인덱스 상세
 * ============================================================ */

/* 테이블 목록 패널 */
body .catalog-list-panel .card-body {
    padding: 10px;
}

body .catalog-filter {
    margin-bottom: 8px;
}

body .catalog-table-list {
    max-height: calc(100vh - 300px);
    overflow-y: auto;
    padding-right: 10px;
}

body .catalog-list-count {
    font-size: 11px;
    color: #9aa1a8;
    padding: 2px 2px 8px;
    border-bottom: 1px solid #eef0f2;
    margin-bottom: 6px;
}

body .catalog-count-num {
    font-weight: 700;
    color: #4a5560;
}

body .catalog-table-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 10px;
    border: 1px solid #eef0f2;
    border-radius: 6px;
    margin-bottom: 5px;
    text-decoration: none;
    color: #333;
    background: #fff;
    transition: background .12s, border-color .12s;
}

body .catalog-table-item:hover {
    background: #f6f8fa;
    border-color: #d8dde2;
}

body .catalog-table-item.selected {
    background: #eef4ff;
    border-color: #9cc0ff;
}

body .catalog-table-name {
    font-weight: 600;
    font-size: 13px;
    font-family: "JetBrains Mono", "Menlo", "Consolas", monospace;
    word-break: break-all;
}

body .catalog-table-meta {
    font-size: 11px;
    color: #9aa1a8;
}

/* 상세 영역 — 헤더 카드 */
body .catalog-detail-head {
    background: linear-gradient(135deg, #f8fafc 0%, #eef2f8 100%);
    border: 1px solid #e3e8ef;
    border-left: 3px solid var(--pp-tone-info-bg);
    border-radius: 10px;
    padding: 14px 16px;
    margin-bottom: 14px;
    box-shadow: 0 1px 2px rgba(20, 35, 60, 0.04);
}

body .catalog-detail-head-main {
    display: flex;
    align-items: center;
    gap: 10px;
}

body .catalog-detail-icon {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #fff;
    border: 1px solid #e3e8ef;
    border-radius: 9px;
    color: #5b6b7f;
    font-size: 15px;
}

body .catalog-detail-title {
    font-family: "JetBrains Mono", "Menlo", "Consolas", monospace;
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.2px;
    color: #1f2937;
    word-break: break-all;
}

body .pp-badge-store-metastore {
    background: var(--pp-tone-info-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-badge-store-eventstore {
    background: var(--pp-tone-success-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-badge-store-analytics {
    background: var(--pp-tone-warn-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

/* 패널 헤더 우측 DB 총 용량 */
body .catalog-list-panel .card-header {
    position: relative;
}

body .catalog-db-size {
    position: absolute;
    right: 14px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 12px;
    font-weight: 700;
    color: #5b6b7f;
}

body .catalog-db-size i {
    color: #9aa1a8;
    margin-right: 4px;
}

body .catalog-detail-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 16px;
    margin-top: 9px;
    padding-left: 44px;
    font-size: 12px;
    color: #6b7686;
}

body .catalog-detail-meta i {
    color: #9aa1a8;
    margin-right: 4px;
}

body .catalog-detail-comment {
    font-style: italic;
    color: #8a94a3;
}

body .catalog-empty,
body .catalog-loading {
    padding: 40px 20px;
    text-align: center;
    color: #9aa1a8;
    font-size: 13px;
}

body .catalog-col-table code.catalog-type,
body .catalog-col-table code.catalog-default {
    background: #f4f6f8;
    color: #4a5560;
    border: none;
    font-size: 12px;
    padding: 1px 6px;
    word-break: break-all;
    border-radius: 8px;
}

body .catalog-col-name {
    font-weight: 600;
    color: #2a2f34;
}

/* 키 뱃지 — pp-badge 베이스 (진한 배경 + 흰 텍스트, light theme 표준) */
body .pp-badge-pk {
    background: var(--pp-tone-success-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-badge-fk {
    background: var(--pp-tone-info-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-badge-partition {
    background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-badge-clustering {
    background: var(--pp-tone-warn-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-badge-static,
body .pp-badge-regular {
    background: var(--pp-tone-muted-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

/* 컬럼 테이블(.catalog-col-table) — BS5 `tr{border-color:inherit}` 가 .table-bordered 에서
   dark(--foreground)로 상속돼 thead 상단에 검은 보더가 생기던 문제 → 라이트 보더(--pp-border) 강제. */
body .catalog-col-table,
body .catalog-col-table thead,
body .catalog-col-table thead tr,
body .catalog-col-table tbody tr,
body .catalog-col-table th,
body .catalog-col-table td {
    border-color: var(--pp-border) !important;
}

/* === pp-56-token-admin.css === */
/* ──────────────────────────────────────────────────────────────────────────
 * pp-09n-token-admin.css — API 인증 토큰 관리 페이지 (token/index.jsp, form.jsp).
 *
 * 인라인 스타일 0 정책 — token/index.js 가 클래스만 부여하고 컬러/레이아웃은 본 파일.
 * Audit C2 (2026-06-03) — 회수 + 만료 UI 추가.
 * ────────────────────────────────────────────────────────────────────────── */

/* 토큰 아이콘 셀 */
.token-row-icon {
    text-align: center;
}

/* 토큰 값 셀 — 토큰 뱃지 + 복사 아이콘 가로 정렬 */
.token-cell-token {
    text-align: left;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    min-width: 0;
}

/* 토큰 문자열 뱃지 — 라이트 테마: 진한 배경 + 흰 텍스트. 고정폭 셀 안에서 한 줄 ellipsis. */
.token-cell-token .token-badge {
    font-size: 12px;
    background: #CC4400;
    color: #FFFFFF;
    border-radius: 6px;
    padding: 1px 10px;
    text-align: left;
    font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
    letter-spacing: 0.2px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 액션 컬럼 — wrench / ban / trash 정렬 */
.token-actions {
    white-space: nowrap;
}
.token-actions .action-icon {
    margin: 0 2px;
}

/* 회수 버튼 강조 */
.action-icon.action-icon-warning {
    color: #C62828;
}
.action-icon.action-icon-warning:hover {
    color: #8E1B1B;
}

/* 폼 — 만료 기간 select + 직접 입력 input 가로 정렬 */
.token-ttl-row {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}
.token-ttl-row .form-control {
    flex: 1 1 200px;
    min-width: 160px;
}

/* === pp-57-timeline-node.css === */
/* ============================================================
 * pp-57-timeline-node — vis(links.Timeline) 아이템 공통 노드 SSOT
 *
 * 단일 base 클래스 `.pp-tl-node` + 타입/상태 모디파이어로
 * 타임라인 아이템 뱃지를 통일한다. (구 .tl-node*, .t-box-2*, .t-box 흡수)
 *
 * 소비처: timeline/index, order/index, calendar/index,
 *         asset/dashboard-equipment, canvas/canvas-timeline-widget
 * ============================================================ */

/* base — 컬러 배경 위 온다크 뱃지 */
body .pp-tl-node {
    display: inline-block;
    padding: 2px 8px !important;
    border-radius: 6px !important;
    font-size: 10px !important;
    line-height: 1.3 !important;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    text-decoration: none !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12) !important;
}
body .pp-tl-node b { font-weight: 600 !important; }

/* vis(links.Timeline) 외곽 래퍼 — 벤더 기본 border-radius:2px 를 노드 표준(6px)으로 통일.
 * (래퍼는 overflow:hidden 으로 내부 .pp-tl-node 를 클립 → 모서리 일치 필요) */
body div.timeline-event-content {
    border-radius: 6px !important;
}
/* 이벤트 박스 + hover/선택 하이라이트(.timeline-event-selected) 의 모서리도 content(6px)와 통일 — 라운드.
 * (벤더 기본은 box:0px / selected:0px 라 마우스오버 시 사각 보더가 나옴) */
body div.timeline-event-box,
body div.timeline-event-selected {
    border-radius: 6px !important;
}

/* 컬러 배경 위 텍스트·아이콘은 항상 흰색
 * (vis-Timeline `.timeline-event-content { color:#666 }` 상속 차단) */
body .pp-tl-node,
body .pp-tl-node * {
    color: var(--pp-white) !important;
}

/* ── 타입 모디파이어 (구 .tl-node-* 색 이관) ── */
/* event — 배경은 런타임 인라인 데이터색(json.payload.color) 이 담당 → 클래스는 배경 미지정 */
body .pp-tl-node--event { }
body .pp-tl-node--context     { background: var(--pp-primary) !important; }        /* 상태 */
body .pp-tl-node--command     { background: oklch(0.61 0.22 303) !important; }   /* 명령 — violet-500 */
body .pp-tl-node--aggregation { background: var(--pp-tone-warn-bg) !important; }   /* 집계 — amber-600 */

/* 알람 — 우선순위 색 (구 단일 알람 레드는 error 로 흡수) */
body .pp-tl-node--alarm.pp-tl-node--info  { background: var(--pp-tone-info-bg) !important; }
body .pp-tl-node--alarm.pp-tl-node--warn  { background: var(--pp-tone-warn-bg) !important; }
body .pp-tl-node--alarm.pp-tl-node--error { background: var(--pp-tone-danger-bg) !important; }

/* ── 워크오더 / 캘린더 상태 모디파이어 (구 .t-box-2-* oklch 이관) ── */
body .pp-tl-node--wo         { background: oklch(0.50 0.04 260) !important; }   /* 기본 대기 — 차분 그레이 */
body .pp-tl-node--wo-start   { background: oklch(0.55 0.18 65) !important; }    /* 진행중 — 앰버 */
body .pp-tl-node--wo-paused  { background: oklch(0.50 0.10 75) !important; }    /* 일시중지 — 다크 옐로 */
body .pp-tl-node--wo-end     { background: oklch(0.45 0.16 145) !important; }   /* 완료 — 진한 그린 */
body .pp-tl-node--wo-aborted { background: oklch(0.45 0.22 25) !important; }    /* 비정상종료 — 다크 레드 */
body .pp-tl-node--wo-cancel  { background: oklch(0.40 0.01 286) !important; }   /* 취소 — 다크 무채 */
body .pp-tl-node--wo-delay   { background: oklch(0.55 0.18 35) !important; }    /* 지연 — 다크 오렌지 */

/* 지속시간 (구 .tl-node-dur) */
body .pp-tl-dur {
    font-size: 8px !important;
    opacity: 0.85 !important;
    margin-left: 4px !important;
}

/* === pp-58-command-flow.css === */
/* ============================================================
   pp-58-command-flow.css — 커맨드 플로우 캔버스 (command-flow-canvas.js, T4)
   사유: JointJS SVG 캔버스 컨테이너의 스크롤/최소높이/드래그오버 상태 표시와
   팔레트 버튼의 grab 커서는 BS5 유틸리티 클래스로 표현 불가(상태 셀렉터·cursor·
   svg 컨테이너 레이아웃) → 최소 커스텀 CSS. 노드/링크 시각은 SVG attrs(JS)가 담당.
   ============================================================ */

/* 캔버스 컨테이너 — 다이얼로그 내부에서 스크롤 가능한 도화지 */
.pp-cmdflow-canvas {
    position: relative;
    overflow: auto;
    min-height: 260px;
    border: 1px solid var(--pp-border);
    border-radius: 0.375rem;
    background: var(--pp-bg);
}

/* 팔레트 드래그 중 드롭 대상 표시 */
.pp-cmdflow-canvas.pp-cmdflow-dragover {
    outline: 2px dashed var(--pp-primary);
    outline-offset: -2px;
}

/* 읽기 전용 모드 — 편집 불가 시각 구분 */
.pp-cmdflow-canvas.pp-cmdflow-readonly {
    background: var(--pp-bg-muted);
}

/* 팔레트 버튼 — 드래그 삽입 가능함을 커서로 표현 */
.pp-cmdflow-palette-btn {
    cursor: grab;
}
.pp-cmdflow-palette-btn:active {
    cursor: grabbing;
}

/* 커맨드 정의 다이얼로그 확장 (T6) — 캔버스+인스펙터 배치에 modal-lg(800px)가 좁아
   스텝 노드가 즉시 ㄹ자 줄바꿈되는 문제. 사유: BS5 유틸로는 .modal-dialog 폭 지정 불가
   → ds-dialog 선례(width + max-width vw 클램프)를 따른다. */
.asset-command-def-dialog .modal-dialog {
    width: 1140px;
    max-width: 96vw;
}

/* === pp-70-login-auth.css === */
/**
 * PlantPulse 로그인 / 세션 / 에러 화면 — Signal 디자인 시스템 통합.
 * 좌측 사이드바 그라데이션 톤과 통일된 다크 배경 + 라이트 카드.
 * body.pp-login-page scope.
 */

body.pp-login-page {
    margin: 0 !important;
    padding: 0 !important;
    /* 전역 `* { font-family: var(--pp-ui-font-family) }`(pp-font.css)가 body 폰트를 덮으므로,
       로그인/세션/에러 페이지(body.pp-login-page 공유)는 커스텀 속성을 SUIT 로 설정해야 실제 적용된다.
       커스텀 속성은 상속 → 모든 하위요소가 SUIT 로 해석됨. */
    --pp-ui-font-family: 'SUIT', -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo", sans-serif;
    font-family: 'SUIT', -apple-system, "Segoe UI", "Pretendard", "Apple SD Gothic Neo", sans-serif;
    color: var(--pp-border);
    /* 좌측 사이드바 (#navigation) 와 완벽 동일한 그라데이션 +
       카드 뒤쪽으로 spotlight 한 줄 추가 → 일관성·깊이감 */
    background:
        radial-gradient(ellipse 600px 360px at 50% 42%, rgba(96, 165, 250, 0.18) 0%, transparent 65%),
        radial-gradient(circle at 0% 100%, rgba(96, 165, 250, 0.14) 0%, transparent 45%),
        radial-gradient(circle at 100% 0%, rgba(14, 165, 233, 0.10) 0%, transparent 50%),
        linear-gradient(180deg,
            oklch(0.11 0.08 260) 0%,
            oklch(0.18 0.08 260) 55%,
            oklch(0.23 0.08 260) 100%) !important;
    background-attachment: fixed !important;
    overflow-x: hidden;
}

/* ─── 배경 웨이브 SVG (애니메이션) ───────────── */
.pp-login-waves {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 22vh;
    min-height: 180px;
    max-height: 280px;
    z-index: 0;
    pointer-events: none;
    opacity: 0.55;
}
.pp-login-waves .pp-login-waves-parallax > use {
    animation: pp-login-wave-move 25s cubic-bezier(.55,.5,.45,.5) infinite;
}
.pp-login-waves .pp-login-waves-parallax > use:nth-child(1) { animation-duration:  7s; }
.pp-login-waves .pp-login-waves-parallax > use:nth-child(2) { animation-duration: 10s; }
.pp-login-waves .pp-login-waves-parallax > use:nth-child(3) { animation-duration: 13s; }
.pp-login-waves .pp-login-waves-parallax > use:nth-child(4) { animation-duration: 20s; }
@keyframes pp-login-wave-move {
    0%   { transform: translate3d(-90px, 0, 0); }
    100% { transform: translate3d(85px, 0, 0); }
}

/* 카드/카피라이트는 SVG 위로 올라오게 z-index */
.pp-login-shell  { position: relative; z-index: 1; }
.pp-login-version { position: relative; z-index: 1; }

/* ─── Shell ─────────────────────────────────────── */
.pp-login-shell {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 24px;
    gap: 16px;
}

/* ─── Card — panel-default 와 동일 톤 (다크 배경 위라 그림자 좀 더 깊게) ─ */
.pp-login-card {
    width: 100%;
    max-width: 420px;
    background: var(--card, var(--pp-white));
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 10px;
    padding: 32px 28px 24px;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.10),
        0 12px 32px rgba(0, 0, 0, 0.32),
        0 0 0 1px rgba(255, 255, 255, 0.02);
}

/* ─── Brand (logo + title + sub) — panel-heading 톤 ─ */
.pp-login-brand {
    text-align: center;
    margin-bottom: 24px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--pp-border);
}
.pp-login-logo {
    display: block;
    height: 52px;
    width: auto;
    margin: 0 auto 12px;
}

/* ─── Session load (로그인 후 전환 화면) ───────── */
.pp-session-card { text-align: center; }
.pp-session-spinner {
    margin: 4px 0 14px;
    font-size: 38px;
    color: var(--primary, var(--pp-primary));
    line-height: 1;
}
.pp-session-message {
    font-size: 13px;
    color: var(--foreground, #0f172a);
    margin-bottom: 14px;
    letter-spacing: 0.01em;
}
.pp-session-message-error { color: var(--pp-tone-danger-bg); }
.pp-session-progress {
    width: 200px;
    height: 4px;
    margin: 0 auto;
    background: var(--muted, #f1f5f9);
    border-radius: 999px;
    overflow: hidden;
}
.pp-session-progress-bar {
    width: 0;
    height: 100%;
    background: var(--primary, var(--pp-primary));
    transition: width 0.18s linear;
    border-radius: 999px;
    color: var(--pp-white) !important;
}

/* ─── Inline error alert (로그인 실패) ──────────── */
.pp-login-alert.alert {
    margin: -4px 0 14px;
    padding: 9px 12px;
    border-radius: 6px;
    font-size: 12.5px;
    line-height: 1.5;
}
.pp-login-alert > i { margin-right: 4px; }
.pp-login-title {
    font-size: 18px;
    font-weight: 700;
    color: var(--foreground, #0f172a);
    letter-spacing: -0.01em;
}

/* ─── Form — form-stack + form-group + control-label ─ */
.pp-login-form .form-group {
    margin-bottom: 14px;
}
.pp-login-form .form-label {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--muted-foreground, var(--pp-border-strong));
}
.pp-login-form .form-label > i {
    color: var(--primary, var(--pp-primary));
    margin-right: 4px;
}

/* form-control 톤은 디자인 시스템 전역 룰을 따르되 로그인 카드 안에선 살짝 보강.
   전역 .form-control / input[type=text|password] 룰이 height:32px 를 강제 우선순위로
   박아두므로, 로그인 입력칸 40px 가 이기려면 동일 우선순위 플래그가 필요(.pp-login-input
   스코프 한정 → 다른 화면 입력칸엔 영향 없음). border-box 라 padding/line-height 는
   전역값으로도 텍스트가 40px 안에서 수직중앙 정렬되므로 추가 플래그 불필요. */
.pp-login-input.form-control {
    height: 40px !important;
    padding: 8px 12px;
    font-size: 14px;
    border: 1px solid var(--pp-border, var(--pp-text-soft));
    border-radius: 6px;
    background: var(--pp-white);
    color: var(--foreground, #0f172a);
    transition: border-color 0.15s, box-shadow 0.15s;
    box-shadow: none;
}
.pp-login-input.form-control::placeholder { color: var(--muted-foreground, var(--pp-text-muted)); }
.pp-login-input.form-control:focus {
    outline: 0;
    border-color: var(--primary, var(--pp-primary));
    box-shadow: 0 0 0 3px rgba(29, 78, 216, 0.15);
}

/* ─── Auto-login checkbox ───────────────────────── */
.pp-login-options {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    margin: 4px 0 16px;
}
.pp-login-remember {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--muted-foreground, var(--pp-border-strong));
    cursor: pointer;
    margin: 0;
}
.pp-login-remember input[type=checkbox] {
    margin: 0;
    accent-color: var(--primary, var(--pp-primary));
}

/* ─── Submit — 디자인 시스템 btn-primary 그대로 + 너비/높이만 보강 ── */
.pp-login-btn.btn {
    width: 100%;
    padding: 10px 14px;
    font-size: 14px;
    line-height: 1.4;
    margin-top: 4px;
}
.pp-login-btn.btn > i { margin-right: 4px; }

/* ─── Footer link ───────────────────────────────── */
.pp-login-foot {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--pp-border);
    text-align: center;
}
.pp-login-mobile-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--muted-foreground, var(--pp-muted-fg));
    text-decoration: none;
    transition: color 0.15s;
}
.pp-login-mobile-link:hover {
    color: var(--primary, var(--pp-primary));
    text-decoration: none;
}

/* ─── Version line ──────────────────────────────── */
.pp-login-version {
    font-size: 11px;
    color: rgba(226, 232, 240, 0.55);
    letter-spacing: 0.04em;
}

/* ─── Loading overlay ───────────────────────────── */
.pp-login-loading {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(3px);
    z-index: 9999;
    display: none;
}
.pp-login-loading-inner {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
    width: max-content;
}
.pp-login-loading-icon    { font-size: 64px; color: var(--pp-white); opacity: 0.9; }
.pp-login-loading-text    { margin-top: 16px; font-size: 16px; color: var(--pp-white); letter-spacing: 0.02em; }

/* ─── 작은 화면 ─────────────────────────────────── */
@media (max-width: 480px) {
    .pp-login-card { padding: 24px 20px 18px; border-radius: 10px; }
    .pp-login-logo { height: 44px; }
    .pp-login-title { font-size: 16px; }
}

/* === pp-72-mobile.css === */
/* ============================================================
 * pp-11-mobile.css — 모바일(/m/*) 전용 디자인 (라이트 톤, 카드 그리드)
 * 로그인 + 시스템 모니터링 단일 페이지 2종.
 * ============================================================ */

/* ============================================================
 * Login v2 — 풀스크린 그라데이션 + 그리드 패턴 + 글래스카드
 * ============================================================ */
body.pp-mlogin-v2 {
    margin: 0;
    padding: 0;
    min-height: 100vh;
    font-family: 'Pretendard', sans-serif;
    color: #f8fafc;
    background: #0b1220;
    overflow-x: hidden;
}

/* 배경 레이어 — 그라데이션 + 그리드 + blob */
.m2-bg {
    position: fixed; inset: 0; z-index: 0;
    background:
        radial-gradient(120% 80% at 20% 0%, rgba(29, 78, 216, 0.35) 0%, transparent 55%),
        radial-gradient(80% 60% at 100% 100%, rgba(220, 38, 38, 0.18) 0%, transparent 60%),
        linear-gradient(180deg, #0b1220 0%, #0f172a 60%, #1e293b 100%);
    color: var(--pp-white) !important;
}
.m2-bg-grid {
    position: fixed; inset: 0; z-index: 1; pointer-events: none;
    background-image:
        linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
    background-size: 32px 32px;
    mask-image: radial-gradient(ellipse 80% 60% at 50% 30%, black, transparent 80%);
    -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 30%, black, transparent 80%);
}
.m2-bg-blob {
    position: fixed; z-index: 1; pointer-events: none;
    width: 320px; height: 320px;
    border-radius: 50%;
    filter: blur(80px);
    opacity: 0.45;
}
.m2-bg-blob-a {
    background: var(--pp-primary);
    top: -120px; left: -120px;
    animation: m2-float 14s ease-in-out infinite alternate;
    color: var(--pp-white) !important;
}
.m2-bg-blob-b {
    background: var(--pp-tone-danger-bg);
    bottom: -160px; right: -100px;
    animation: m2-float 16s ease-in-out infinite alternate-reverse;
    color: var(--pp-white) !important;
}
@keyframes m2-float {
    from { transform: translate(0, 0) scale(1); }
    to   { transform: translate(30px, 20px) scale(1.05); }
}

/* 본문 컨테이너 */
.m2-shell {
    position: relative;
    z-index: 2;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 36px 18px 24px;
}

/* 상단 브랜드 */
.m2-brand {
    text-align: center;
    margin-bottom: 26px;
}
.m2-brand-logo {
    height: 48px;
    display: inline-block;
    opacity: 0.95;
    /* 다크 배경에 흰 로고로 보이도록 컬러 반전 */
    filter: brightness(0) invert(1);
}

/* 로그인 카드 — 글래스모피즘 */
.m2-card {
    width: 100%;
    max-width: 380px;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 18px;
    padding: 20px 22px 22px;
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.06) inset,
        0 20px 60px rgba(0, 0, 0, 0.45),
        0 4px 14px rgba(0, 0, 0, 0.25);
}

.m2-card-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-bottom: 14px;
    margin-bottom: 14px;
    border-bottom: 1px solid rgba(255,255,255,0.08);
}
.m2-card-head-ico {
    width: 40px; height: 40px;
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 18px;
    color: var(--pp-white);
    background: linear-gradient(135deg, var(--pp-info), var(--pp-primary));
    border-radius: 10px;
    box-shadow: 0 6px 18px rgba(29, 78, 216, 0.45);
}
.m2-card-title {
    font-size: 16px;
    font-weight: 700;
    color: var(--pp-white);
    letter-spacing: 0.01em;
}
.m2-card-sub {
    font-size: 11.5px;
    color: rgba(255,255,255,0.55);
    margin-top: 2px;
}

/* 오류 알림 */
.m2-alert {
    margin-bottom: 12px;
    padding: 10px 12px;
    background: rgba(220, 38, 38, 0.16);
    border: 1px solid rgba(220, 38, 38, 0.35);
    color: #fecaca;
    border-radius: 10px;
    font-size: 12.5px;
    line-height: 1.4;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* 입력 필드 */
.m2-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.m2-field {
    position: relative;
    display: flex;
    align-items: stretch;
    background: rgba(255,255,255,0.04);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 10px;
    transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
    margin: 0;
}
.m2-field:focus-within {
    border-color: rgba(96, 165, 250, 0.7);
    background: rgba(255,255,255,0.08);
    box-shadow: 0 0 0 4px rgba(96, 165, 250, 0.10);
}
.m2-field-ico {
    width: 44px;
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    color: rgba(255,255,255,0.45);
    font-size: 14px;
    border-right: 1px solid rgba(255,255,255,0.06);
}
.m2-field:focus-within .m2-field-ico { color: #60a5fa; }
.m2-input,
body .m2-input,
input.m2-input {
    flex: 1 1 auto;
    height: 48px;
    padding: 0 14px;
    background: transparent !important;
    background-color: transparent !important;
    border: 0 !important;
    color: #f8fafc !important;
    font-size: 15px;
    font-family: 'Pretendard', sans-serif;
    outline: none !important;
    box-shadow: none !important;
    -webkit-appearance: none;
    appearance: none;
    -webkit-text-fill-color: #f8fafc !important;
    caret-color: #60a5fa;
}
.m2-input::placeholder {
    color: rgba(255,255,255,0.35) !important;
    -webkit-text-fill-color: rgba(255,255,255,0.35) !important;
}
.m2-input:-webkit-autofill,
.m2-input:-webkit-autofill:hover,
.m2-input:-webkit-autofill:focus,
.m2-input:-webkit-autofill:active {
    -webkit-text-fill-color: #f8fafc !important;
    caret-color: #60a5fa !important;
    transition: background-color 9999s ease-in-out 0s;
    box-shadow: 0 0 0 1000px rgba(15, 23, 42, 0) inset !important;
}
.m2-field-toggle {
    background: transparent;
    border: 0;
    width: 44px;
    color: rgba(255,255,255,0.4);
    cursor: pointer;
    font-size: 14px;
    transition: color 0.15s;
}
.m2-field-toggle:hover { color: var(--pp-white); }

/* 로그인 버튼 */
.m2-btn {
    margin-top: 6px;
    height: 50px;
    border: 0;
    border-radius: 10px;
    background: linear-gradient(180deg, #d9534f 0%, #c12e2a 100%);
    color: var(--pp-white);
    font-weight: 700;
    font-size: 15px;
    letter-spacing: 0.04em;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    box-shadow: 0 8px 22px rgba(217, 83, 79, 0.32);
    transition: filter 0.15s, transform 0.05s, box-shadow 0.15s;
}
.m2-btn:hover  { filter: brightness(1.08); box-shadow: 0 10px 28px rgba(217, 83, 79, 0.45); }
.m2-btn:active { transform: translateY(1px); }
.m2-btn-ico    { font-size: 15px; }

/* 진행 인디케이터 */
.m2-progress {
    margin-top: 14px;
    padding: 12px 4px 6px;
    text-align: center;
}
.m2-progress-bar {
    height: 6px;
    background: rgba(255,255,255,0.08);
    border-radius: 999px;
    overflow: hidden;
    position: relative;
}
.m2-progress-bar::after {
    content: '';
    position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent 0%, #60a5fa 30%, #f87171 70%, transparent 100%);
    animation: m2-prog 1.1s linear infinite;
}
@keyframes m2-prog {
    from { transform: translateX(-100%); }
    to   { transform: translateX(100%); }
}
.m2-progress-text {
    margin-top: 8px;
    color: rgba(255,255,255,0.6);
    font-size: 12px;
}

/* 풋터 */
@keyframes m2-pulse {
    50% { opacity: 0.35; }
}

/* iOS 안전 영역 */
@supports (padding-bottom: env(safe-area-inset-bottom)) {
    .m2-shell { padding-bottom: calc(24px + env(safe-area-inset-bottom)); }
}


/* ============================================================
 * System v2 — 모바일 시스템 모니터링 (다크 글래스, login 톤 통일)
 * ============================================================ */
body.pp-mpage-v2 {
    margin: 0;
    padding: 0;
    min-height: 100vh;
    font-family: 'Pretendard', sans-serif;
    color: #f8fafc;
    background: #0b1220;
    padding-bottom: 32px;
}

/* 헤더 */
.m2s-header {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    background: rgba(15, 23, 42, 0.78);
    backdrop-filter: blur(14px) saturate(140%);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    border-bottom: 1px solid rgba(255,255,255,0.08);
}
.m2s-header-left {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
.m2s-header-logo {
    height: 34px;
    display: block;
    /* 다크 헤더 배경 — 흰 로고로 반전 */
    filter: brightness(0) invert(1);
}
.m2s-header-right {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
.m2s-header-logout {
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.10);
    border-radius: 8px;
    color: rgba(255,255,255,0.78);
    width: 34px;
    height: 34px;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.m2s-header-logout:hover {
    background: rgba(220, 38, 38, 0.18);
    border-color: rgba(220, 38, 38, 0.45);
    color: #fecaca;
}

.m2s-main {
    position: relative;
    z-index: 2;
    padding: 14px 14px 24px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* ─── KPI 그리드 (2x2) ─── */
.m2s-kpi-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.m2s-kpi {
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(14px) saturate(140%);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255,255,255,0.10);
    border-radius: 14px;
    padding: 12px 14px 10px;
    box-shadow: 0 1px 0 rgba(255,255,255,0.05) inset, 0 8px 24px rgba(0,0,0,0.30);
}
.m2s-kpi-head {
    font-size: 11px;
    font-weight: 600;
    color: rgba(255,255,255,0.55);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin-bottom: 4px;
}
.m2s-kpi-head > i { color: #60a5fa; margin-right: 4px; }
.m2s-kpi-value {
    font-size: 22px;
    font-weight: 800;
    color: #f8fafc;
    line-height: 1.15;
    letter-spacing: 0.01em;
}
.m2s-kpi-unit {
    font-size: 11px;
    color: rgba(255,255,255,0.45);
    margin-left: 4px;
    font-weight: 600;
}
.m2s-kpi-spark {
    margin-top: 6px;
    height: 40px;
}
.m2s-kpi-meta {
    margin-top: 6px;
    font-size: 11px;
    color: rgba(255,255,255,0.55);
}
.m2s-kpi-meta b { color: rgba(255,255,255,0.85); font-weight: 600; }

/* ─── 공통 카드 ─── */
.m2s-card {
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(14px) saturate(140%);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    border: 1px solid rgba(255,255,255,0.10);
    border-radius: 14px;
    overflow: hidden;
    box-shadow: 0 1px 0 rgba(255,255,255,0.05) inset, 0 12px 30px rgba(0,0,0,0.30);
}
.m2s-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.m2s-card-title {
    font-size: 13px;
    font-weight: 700;
    color: rgba(255,255,255,0.95);
}
.m2s-card-title > i { color: #60a5fa; margin-right: 4px; }
.m2s-card-meta {
    font-size: 11px;
    color: rgba(255,255,255,0.55);
}
.m2s-card-meta b { color: #f8fafc; font-weight: 700; }
.m2s-card-body { padding: 12px 14px; }
.m2s-card-body-tight { padding: 6px 6px 4px; }
.m2s-card-body-flush { padding: 0; }

.m2s-empty {
    padding: 22px 12px;
    text-align: center;
    color: rgba(255,255,255,0.45);
    font-size: 12px;
}

/* ─── 헬스 타임라인 ─── */
.m2s-health-legend {
    display: inline-flex;
    gap: 4px;
}
.m2s-chip {
    font-size: 10px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 4px;
    color: var(--pp-white);
}
.m2s-chip.is-normal { background: var(--pp-tone-success-bg);
    color: var(--pp-white) !important; }
.m2s-chip.is-info   { background: var(--pp-info); }
.m2s-chip.is-warn   { background: #ea580c; }
.m2s-chip.is-error  { background: var(--pp-tone-danger-bg);
    color: var(--pp-white) !important; }

.m2s-health-timeline { width: 100%; min-height: 56px; }
.m2s-health-info {
    margin-top: 6px;
    font-size: 11px;
    color: rgba(255,255,255,0.65);
    min-height: 16px;
}

/* 모바일 전용 헬스 타임라인 — DOM 기반 */
.m2s-tl {
    width: 100%;
    user-select: none;
}
.m2s-tl-bar {
    position: relative;
    width: 100%;
    height: 28px;
    background: rgba(255,255,255,0.04);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 8px;
    overflow: hidden;
}
.m2s-tl-seg {
    position: absolute;
    top: 0;
    bottom: 0;
    cursor: pointer;
    transition: filter 0.12s, transform 0.12s;
}
.m2s-tl-seg:hover { filter: brightness(1.15); }
.m2s-tl-seg.is-normal { background: linear-gradient(180deg, #22c55e 0%, var(--pp-tone-success-bg) 100%);
    color: var(--pp-white) !important; }
.m2s-tl-seg.is-info   { background: linear-gradient(180deg, #3b82f6 0%, var(--pp-info) 100%); }
.m2s-tl-seg.is-warn   { background: linear-gradient(180deg, #f59e0b 0%, #ea580c 100%); }
.m2s-tl-seg.is-error  { background: linear-gradient(180deg, #ef4444 0%, var(--pp-tone-danger-bg) 100%);
    color: var(--pp-white) !important; }

/* 현재 시각 표식 */
.m2s-tl-now {
    position: absolute;
    top: -2px;
    bottom: -2px;
    width: 2px;
    background: var(--pp-white);
    box-shadow: 0 0 6px rgba(255,255,255,0.6);
    pointer-events: none;
}
.m2s-tl-now::before {
    content: '';
    position: absolute;
    top: -3px;
    left: -3px;
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--pp-white);
    box-shadow: 0 0 6px rgba(255,255,255,0.7);
}

/* 시간축 */
.m2s-tl-axis {
    position: relative;
    margin-top: 6px;
    height: 16px;
}
.m2s-tl-tick {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    font-size: 10px;
    color: rgba(255,255,255,0.5);
    font-family: 'SFMono-Regular', 'Consolas', monospace;
}
.m2s-tl-tick:first-child { transform: translateX(0); }
.m2s-tl-tick:last-child  { transform: translateX(-100%); }

/* ─── 게이지 ─── */
.m2s-gauges {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px;
}
.m2s-gauge { height: 160px; }

/* ─── 클러스터 노드 카드 리스트 ─── */
.m2s-cluster-list {
    display: flex;
    flex-direction: column;
    gap: 1px;
    background: rgba(255,255,255,0.04);
}
.m2s-node {
    background: rgba(15, 23, 42, 0.4);
    padding: 12px 14px;
    border-left: 3px solid var(--pp-tone-success-bg);
}
.m2s-node.is-down { border-left-color: var(--pp-tone-danger-bg); opacity: 0.78; }

.m2s-node-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}
.m2s-node-state .fa-database               { color: #4ade80; }
.m2s-node-state .fa-exclamation-triangle   { color: #f87171; }
.m2s-node-ip {
    flex: 1 1 auto;
    font-family: 'SFMono-Regular', 'Consolas', monospace;
    font-size: 13px;
    font-weight: 700;
    color: #f8fafc;
}
.m2s-node-mode {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: 2px 6px;
    border-radius: 4px;
    text-transform: uppercase;
}
.m2s-node-mode.is-master { background: rgba(96, 165, 250, 0.18); color: #93c5fd; }
.m2s-node-mode.is-worker { background: rgba(255, 255, 255, 0.08); color: rgba(255,255,255,0.7); }

.m2s-node-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
}
.m2s-node-grid > div {
    display: flex;
    flex-direction: column;
}
.m2s-node-label {
    font-size: 9.5px;
    color: rgba(255,255,255,0.4);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 2px;
}
.m2s-node-val {
    font-family: 'SFMono-Regular', 'Consolas', monospace;
    font-size: 12px;
    color: rgba(255,255,255,0.92);
    font-weight: 600;
}

.m2s-cluster-updated {
    padding: 8px 14px;
    border-top: 1px solid rgba(255,255,255,0.06);
    background: rgba(255,255,255,0.02);
    color: rgba(255,255,255,0.4);
    font-size: 11px;
    text-align: right;
}

/* iOS 안전 영역 */
@supports (padding-bottom: env(safe-area-inset-bottom)) {
    .m2s-main { padding-bottom: calc(24px + env(safe-area-inset-bottom)); }
}


/* ─── 옛 Login (호환 유지, 클래스 변경된 페이지에서는 미적용) ─── */
.m-login-shell {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 24px 16px 32px;
}
.m-login-card {
    width: 100%;
    max-width: 360px;
    background: rgba(255,255,255,0.04);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 14px;
    padding: 24px 22px 22px;
    backdrop-filter: blur(8px);
}
.m-login-brand {
    text-align: center;
    margin-bottom: 18px;
}
.m-login-brand img { height: 28px; }
.m-login-title {
    text-align: center;
    font-size: 17px;
    font-weight: 700;
    color: var(--pp-white);
    letter-spacing: 0.01em;
}
.m-login-sub {
    text-align: center;
    font-size: 11.5px;
    color: rgba(255,255,255,0.55);
    margin-top: 2px;
    margin-bottom: 22px;
}
.m-login-error {
    background: rgba(220, 38, 38, 0.18);
    border: 1px solid rgba(220, 38, 38, 0.35);
    border-radius: 8px;
    padding: 10px 12px;
    color: #fecaca;
    font-size: 13px;
    margin-bottom: 14px;
}
.m-login-error > i { margin-right: 6px; }

.m-login-form { display: flex; flex-direction: column; gap: 10px; }
.m-login-input {
    width: 100%;
    height: 44px;
    padding: 0 14px;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 8px;
    color: var(--pp-white);
    font-size: 15px;
    outline: none;
    transition: border-color 0.15s, background 0.15s;
}
.m-login-input::placeholder { color: rgba(255,255,255,0.4); }
.m-login-input:focus {
    border-color: rgba(96,165,250,0.6);
    background: rgba(255,255,255,0.10);
}
.m-login-btn {
    margin-top: 4px;
    width: 100%;
    height: 46px;
    background: linear-gradient(180deg, #d9534f 0%, #c12e2a 100%);
    border: 0;
    border-radius: 8px;
    color: var(--pp-white);
    font-weight: 700;
    font-size: 15px;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: filter 0.15s, transform 0.05s;
}
.m-login-btn:hover  { filter: brightness(1.08); }
.m-login-btn:active { transform: translateY(1px); }
.m-login-btn > i { margin-right: 6px; }

.m-login-progress {
    margin-top: 14px;
    height: 6px;
    background: rgba(255,255,255,0.08);
    border-radius: 999px;
    position: relative;
    overflow: hidden;
}
.m-login-progress-bar {
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, #60a5fa 0%, #f87171 50%, #60a5fa 100%);
    background-size: 200% 100%;
    animation: m-login-prog 1.2s linear infinite;
}
.m-login-progress-text {
    display: block;
    text-align: center;
    margin-top: 6px;
    font-size: 12px;
    color: rgba(255,255,255,0.6);
}
@keyframes m-login-prog { from { background-position: 200% 0; } to { background-position: 0 0; } }

.m-login-footer {
    margin-top: 18px;
    text-align: center;
    color: rgba(255,255,255,0.45);
    font-size: 11px;
    line-height: 1.6;
}

/* ─── System (모바일 메인) ─────────────────────────────────── */

.m-header {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 10px;
    height: 50px;
    padding: 0 12px;
    background: linear-gradient(180deg, #1e293b 0%, #0f172a 100%);
    border-bottom: 1px solid #0b1220;
    box-shadow: 0 2px 6px rgba(0,0,0,0.15);
    color: #f8fafc;
    color: var(--pp-white) !important;
}
.m-header-brand img { height: 22px; display: block; }
.m-header-title {
    flex: 1 1 auto;
    font-size: 14px;
    font-weight: 600;
    margin-left: 6px;
    color: #f1f5f9;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.m-header-right {
    display: inline-flex;
    align-items: center;
    gap: 12px;
}
.m-header-user {
    font-size: 12px;
    color: rgba(255,255,255,0.7);
}
.m-header-logout {
    color: rgba(255,255,255,0.78) !important;
    text-decoration: none !important;
    font-size: 16px;
}
.m-header-logout:hover { color: var(--pp-white) !important; }

.m-main {
    padding: 12px 12px 24px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* ─── 공통 카드 ─── */
.m-card {
    background: var(--pp-white);
    border: 1px solid var(--pp-border);
    border-radius: 10px;
    box-shadow: 0 1px 2px rgba(15,23,42,0.04);
    overflow: hidden;
}
.m-card-head {
    padding: 10px 14px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #eef2f6;
    background: #f8fafc;
}
.m-card-title {
    font-size: 13px;
    font-weight: 700;
    color: #0f172a;
}
.m-card-title > i { color: var(--pp-primary); margin-right: 4px; }
.m-card-meta {
    font-size: 11px;
    color: var(--pp-muted-fg);
}
.m-card-meta b { color: #0f172a; font-weight: 700; }
.m-card-body { padding: 12px 14px; }
.m-card-body-tight { padding: 8px 8px 4px; }
.m-card-body-flush { padding: 0; }

/* ─── KPI 그리드 ─── */
.m-grid { display: grid; gap: 10px; }
.m-grid-2 { grid-template-columns: 1fr 1fr; }
.m-kpi {
    background: var(--pp-white);
    border: 1px solid var(--pp-border);
    border-radius: 10px;
    padding: 12px 12px 10px;
    box-shadow: 0 1px 2px rgba(15,23,42,0.04);
}
.m-kpi-head {
    font-size: 11.5px;
    color: var(--pp-muted-fg);
    font-weight: 600;
    margin-bottom: 6px;
}
.m-kpi-head > i { color: var(--pp-primary); margin-right: 4px; }
.m-kpi-value {
    font-size: 22px;
    font-weight: 800;
    color: #0f172a;
    letter-spacing: 0.01em;
    line-height: 1.1;
}
.m-kpi-unit {
    font-size: 11px;
    color: var(--pp-text-muted);
    margin-left: 4px;
    font-weight: 600;
}
.m-kpi-spark {
    margin-top: 6px;
    height: 40px;
}
.m-kpi-meta {
    margin-top: 6px;
    font-size: 11px;
    color: var(--pp-muted-fg);
    line-height: 1.5;
}
.m-kpi-meta > span { color: #0f172a; font-weight: 600; }

/* ─── 헬스 타임라인 ─── */
.m-health-legend {
    display: inline-flex;
    gap: 4px;
}
.m-health-chip {
    font-size: 10px;
    padding: 2px 8px;
    border-radius: 4px;
    color: var(--pp-white);
    font-weight: 600;
}
.m-health-chip.is-normal { background: var(--pp-tone-success-bg);
    color: var(--pp-white) !important; }
.m-health-chip.is-info   { background: var(--pp-info); }
.m-health-chip.is-warn   { background: #ea580c; }
.m-health-chip.is-error  { background: var(--pp-tone-danger-bg);
    color: var(--pp-white) !important; }

.m-health-timeline { width: 100%; min-height: 64px; }
.m-health-empty {
    text-align: center;
    color: var(--pp-text-muted);
    font-size: 12px;
    padding: 22px 0;
}
.m-health-info {
    font-size: 11px;
    color: var(--pp-muted-fg);
    margin-top: 4px;
}

/* ─── 게이지 ─── */
.m-gauges { gap: 4px; }
.m-gauge { height: 140px; }

/* ─── 클러스터 테이블 ─── */
.m-cluster-scroll {
    overflow-x: auto;
}
.m-cluster-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
    min-width: 540px;
}
.m-cluster-table thead th {
    background: #f8fafc;
    color: var(--pp-muted-fg);
    font-weight: 600;
    font-size: 11px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--pp-border);
    text-align: left;
    white-space: nowrap;
}
.m-cluster-table tbody td {
    padding: 8px 10px;
    border-bottom: 1px solid #eef2f6;
    white-space: nowrap;
    color: #0f172a;
}
.m-cluster-table tbody tr:last-child td { border-bottom: 0; }
.m-cluster-table .text-right { text-align: right; }
.m-cluster-status   { width: 36px; text-align: center; }
.m-cluster-status .m-cluster-up   { color: var(--pp-tone-success-bg); }
.m-cluster-status .m-cluster-down { color: var(--pp-tone-danger-bg); }
.m-cluster-mode {
    width: 36px;
    text-align: center;
    font-family: 'SFMono-Regular', 'Consolas', monospace;
    color: var(--pp-primary);
}
.m-cluster-ip {
    font-family: 'SFMono-Regular', 'Consolas', monospace;
    color: #0f172a;
}
.m-cluster-empty {
    text-align: center;
    color: var(--pp-text-muted);
    padding: 18px 10px;
}
.m-cluster-updated {
    padding: 6px 14px;
    border-top: 1px solid #eef2f6;
    background: #f8fafc;
    color: var(--pp-text-muted);
    font-size: 11px;
    text-align: right;
}

/* JustGage 게이지 라벨 색 정렬 */
.m-gauge svg text { font-family: 'Pretendard', sans-serif !important; }

/* === pp-74-status-tones.css === */
/* ============================================================
 * Status tone system
 * ------------------------------------------------------------
 * 서버 mm_status.tone 과 JS PP.Badge 가 사용하는 공통 표현 토큰.
 * 기존 badge class 는 alias 로 유지하고 JSP 전체 치환은 화면별 검증 후 진행한다.
 * ============================================================ */

:root {
    --pp-tone-info-bg:    var(--pp-info);
    --pp-tone-success-bg: oklch(52% 0.17 145);   /* a11y(WCAG 1.4.3) — 흰텍스트 대비 ≥4.5(기존 --success 62% 는 3.35:1 미달) */
    --pp-tone-warn-bg:    oklch(52% 0.14 60);     /* a11y — 노랑(75%, 흰텍스트 2.28:1)→앰버 52%(5.7:1). 흰텍스트 AA 통과 */
    --pp-tone-danger-bg:  var(--destructive, #dc2626);
    --pp-tone-muted-bg:   var(--muted-foreground, var(--pp-muted-fg));
    /* 진한 중립(slate-600) — conn/opc 'disconnected' 전용. 일반 muted 와 구분 보존. */
    --pp-tone-muted-strong-bg: var(--muted-strong-foreground, var(--pp-border-strong));
    --pp-tone-on-solid:   var(--pp-white, #ffffff);
    --pp-alarm-info-bg:   var(--pp-tone-info-bg);
    --pp-alarm-warn-bg:   var(--pp-tone-warn-bg);
    --pp-alarm-error-bg:  var(--pp-tone-danger-bg);
}

body .pp-badge {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 5px !important;
    min-height: 20px !important;
    padding: 2px 10px !important;
    border-radius: 8px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    line-height: 1.35 !important;
    white-space: nowrap !important;
    vertical-align: middle !important;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);   /* 표준 드롭섀도우 — 전 뱃지 일관 (!important 불필요: 경쟁규칙 없음) */
}

/* ============================================================
 * Phase 1.5 — 뱃지 형태(shape) 일괄 통일
 * ------------------------------------------------------------
 * 모든 레거시 텍스트 상태 뱃지 family 를 카논 형태(8px 소프트라운드)로
 * 통일한다. 색/배경은 Phase 1 토큰 시스템(위/아래 규칙)이 단독 소유 —
 * 여기서는 형태만 강제하고 background/color 는 절대 건드리지 않는다.
 * pp-74 는 거의 마지막 part(>74 에 형태 규칙 없음)라 레거시(part 02~57·
 * pp-override-status.css·pp-app.css)의 제각각 radius/padding 을 cascade 로
 * 덮는다. body 접두로 specificity 동등+후순위 → !important 최소 사용으로 승리.
 *
 * 예외(의도적 제외 — 형태 통일 미적용):
 *   · *-dot / pp-status-dot / quality-dot / eq-status-dot  → 원형 점 표식
 *   · ov-health-badge / ov-conn-badge                      → map 오버레이 100px 원형칩
 *   · health-badge.map-ov-chip-xs                          → map 오버레이 초소형칩
 *   · 카운트칩(nav-alarm-count/alarm-count-cell/pp-tb-badge[data-count]) → 숫자칩
 *   · ds-timeline-* / timeline-detail-ts-badge / alarm-tbox → 타임라인 세그/호버
 * ============================================================ */
body .conn-badge-ok,
body .conn-badge-warn,
body .conn-badge-error,
body .conn-badge-disconnected,
body .conn-badge-unknown,
body .state-badge-ok,
body .state-badge-warn,
body .state-badge-error,
body .state-badge-wait,
body .level-badge-info,
body .level-badge-warn,
body .level-badge-error,
body .priority-badge,
body .priority-badge-unknown,
body .priority-badge-band,
body .priority-badge-NORMAL,
body .priority-badge-Normal,
body .priority-badge-normal,
body .priority-badge-LOW,
body .priority-badge-Low,
body .priority-badge-low,
body .priority-badge-HIGH,
body .priority-badge-High,
body .priority-badge-high,
body .priority-badge-URGENT,
body .priority-badge-Urgent,
body .priority-badge-urgent,
body .priority-badge-CRITICAL,
body .priority-badge-Critical,
body .priority-badge-critical,
body .priority-badge-BAND,
body .priority-badge-Band,
body .log-level-info,
body .log-level-warn,
body .log-level-error,
body .log-app-badge,
body .opc-badge-connected,
body .opc-badge-disconnected,
body .opc-connection-ok,
body .opc-connection-warn,
body .opc-connection-error,
body .opc-connection-disconnected,
body .opc-connection-unknown,
body .opc-status-ok,
body .opc-status-warn,
body .opc-status-error,
body .opc-status-unknown,
body .quality-badge,
body .quality-good,
body .quality-uncertain,
body .quality-bad,
body .quality-unknown,
body .value-q-badge,
body .value-q-good,
body .value-q-uncertain,
body .value-q-bad,
body .equip-status-run,
body .equip-status-idle,
body .equip-status-stop,
body .equip-status-fault,
body .equip-status-setup,
body .equip-status-planned,
body .equip-status-down,
body .equip-status-unknown,
body .eq-status-badge,
body .wo-status-start,
body .wo-status-paused,
body .wo-status-end,
body .wo-status-wait,
body .wo-status-delay,
body .wo-status-cancel,
body .wo-status-aborted,
body .cal-status-progress,
body .cal-status-done,
body .cal-status-upcoming,
body .health-badge,
body .health-level-badge,
body .health-level-badge-ok,
body .health-level-badge-info,
body .health-level-badge-warn,
body .health-level-badge-error,
body .stmt-type-event,
body .stmt-type-context,
body .stmt-type-aggregation,
body .stmt-type-command,
body .dt-badge,
body .pp-status-bg-ok,
body .pp-status-bg-delay,
body .pp-status-bg-anomaly,
body .pp-status-bg-disc,
body .pp-status-bg-none,
body .pp-status-bg-muted,
body .alarm-info,
body .alarm-warn,
body .alarm-error,
body .side-h-badge-ok,
body .side-h-badge-err,
body .side-h-badge-mute,
body .mon-infra-badge,
body .diag-badge-info,
body .diag-badge-warn,
body .diag-badge-error,
body .pp-type-badge {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 5px !important;
    min-height: 20px !important;
    padding: 2px 10px !important;
    border-radius: 8px !important;
    font-size: 11px !important;
    font-weight: 700 !important;
    line-height: 1.35 !important;
    white-space: nowrap !important;
    vertical-align: middle !important;
}

body .pp-tone-info {
    background: var(--pp-tone-info-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-tone-success {
    background: var(--pp-tone-success-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-tone-warn {
    background: var(--pp-tone-warn-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-tone-danger {
    background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-tone-muted {
    background: var(--pp-tone-muted-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

/* 톤별 기본 아이콘 (FA5 Solid) — 마크업에 <i> 가 없을 때만 자동 부여(:has 가드, 중복 방지) */
body .pp-tone-info:not(:has(> i))::before,
body .pp-tone-success:not(:has(> i))::before,
body .pp-tone-warn:not(:has(> i))::before,
body .pp-tone-danger:not(:has(> i))::before,
body .pp-tone-muted:not(:has(> i))::before {
    font-family: "Font Awesome 7 Pro";
    font-weight: 100;
    font-size: 0.95em;
    line-height: 1;
    margin-right: 1px;
}
body .pp-tone-success:not(:has(> i))::before { content: "\f058"; } /* check-circle */
body .pp-tone-warn:not(:has(> i))::before    { content: "\f071"; } /* exclamation-triangle */
body .pp-tone-danger:not(:has(> i))::before  { content: "\f057"; } /* times-circle */
body .pp-tone-info:not(:has(> i))::before     { content: "\f05a"; } /* info-circle */
body .pp-tone-muted:not(:has(> i))::before    { content: "\f059"; } /* question-circle */

/* 텍스트 상태 도메인 뱃지(conn/priority/level/health-level/diag/side-h)에도 톤 아이콘 자동 부여.
   :not(:has(> i)) 가드로 명시 <i> 있는 경우 중복 방지. 카운트칩(state-badge/nav-alarm-count/alarm-count-cell)·
   타임라인(alarm-tbox)은 제외(숫자 앞 아이콘 방지). 정본 톤 시스템과 아이콘 일관성 확보. */
body .conn-badge-ok:not(:has(> i))::before,
body .opc-badge-connected:not(:has(> i))::before,
body .side-h-badge-ok:not(:has(> i))::before,
body .health-level-badge-ok:not(:has(> i))::before,
body .level-badge-info:not(:has(> i))::before,
body .health-level-badge-info:not(:has(> i))::before,
body .diag-badge-info:not(:has(> i))::before,
body .conn-badge-warn:not(:has(> i))::before,
body .level-badge-warn:not(:has(> i))::before,
body .health-level-badge-warn:not(:has(> i))::before,
body .diag-badge-warn:not(:has(> i))::before,
body .conn-badge-error:not(:has(> i))::before,
body .level-badge-error:not(:has(> i))::before,
body .health-level-badge-error:not(:has(> i))::before,
body .diag-badge-error:not(:has(> i))::before,
body .side-h-badge-err:not(:has(> i))::before,
body .conn-badge-disconnected:not(:has(> i))::before,
body .conn-badge-unknown:not(:has(> i))::before,
body .priority-badge-unknown:not(:has(> i))::before,
body .side-h-badge-mute:not(:has(> i))::before {
    font-family: "Font Awesome 7 Pro";
    font-weight: 100;
    font-size: 0.95em;
    line-height: 1;
    margin-right: 3px;
}
body .conn-badge-ok:not(:has(> i))::before,
body .opc-badge-connected:not(:has(> i))::before,
body .side-h-badge-ok:not(:has(> i))::before,
body .health-level-badge-ok:not(:has(> i))::before { content: "\f058"; } /* check-circle */
body .level-badge-info:not(:has(> i))::before,
body .health-level-badge-info:not(:has(> i))::before,
body .diag-badge-info:not(:has(> i))::before { content: "\f05a"; } /* info-circle */
body .conn-badge-warn:not(:has(> i))::before,
body .level-badge-warn:not(:has(> i))::before,
body .health-level-badge-warn:not(:has(> i))::before,
body .diag-badge-warn:not(:has(> i))::before { content: "\f071"; } /* exclamation-triangle */
body .conn-badge-error:not(:has(> i))::before,
body .level-badge-error:not(:has(> i))::before,
body .health-level-badge-error:not(:has(> i))::before,
body .diag-badge-error:not(:has(> i))::before,
body .side-h-badge-err:not(:has(> i))::before { content: "\f057"; } /* times-circle */
body .conn-badge-disconnected:not(:has(> i))::before,
body .conn-badge-unknown:not(:has(> i))::before,
body .priority-badge-unknown:not(:has(> i))::before,
body .side-h-badge-mute:not(:has(> i))::before { content: "\f059"; } /* question-circle */

body .pp-badge > i,
body .pp-tone-info > i,
body .pp-tone-success > i,
body .pp-tone-warn > i,
body .pp-tone-danger > i,
body .pp-tone-muted > i {
    background: transparent !important;
    color: inherit !important;
}

body .pp-tone-info *,
body .pp-tone-success *,
body .pp-tone-warn *,
body .pp-tone-danger *,
body .pp-tone-muted * {
    color: inherit !important;
}

body .conn-badge-ok,
body .health-level-badge-ok,
body .health-badge-ok,
body .side-h-badge-ok,
body .state-badge-ok,
body .opc-badge-connected,
body .flow-status-badge.pp-tone-success,
body .flow-status-badge.flow-status-on {
    background: var(--pp-tone-success-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-status-bg-ok,
body .site-popup .pp-status-bg-ok {
    background: #2e7d32 !important;
}

body .health-level-badge-info,
body .level-badge-info,
body .diag-badge-info {
    background: var(--pp-tone-info-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .conn-badge-warn,
body .health-level-badge-warn,
body .level-badge-warn,
body .diag-badge-warn,
body .state-badge-warn {
    background: var(--pp-tone-warn-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-status-bg-delay,
body .site-popup .pp-status-bg-delay {
    background: #e65100 !important;
}

body .conn-badge-error,
body .health-level-badge-error,
body .level-badge-error,
body .diag-badge-error,
body .side-h-badge-err,
body .state-badge-error {
    background: var(--pp-tone-danger-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-status-bg-anomaly,
body .site-popup .pp-status-bg-anomaly {
    background: #b71c1c !important;
}

body .pp-status-bg-disc,
body .site-popup .pp-status-bg-disc {
    background: #7f1d1d !important;
}

body .conn-badge-disconnected,
body .conn-badge-unknown,
body .priority-badge-unknown,
body .side-h-badge-mute,
body .state-badge-wait,
body .flow-status-badge.pp-tone-muted,
body .flow-status-badge.flow-status-off {
    background: var(--pp-tone-muted-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-status-bg-none,
body .site-popup .pp-status-bg-none {
    background: #9ca3af !important;
}

body .pp-status-bg-muted,
body .site-popup .pp-status-bg-muted {
    background: #888 !important;
}

body .alarm-info,
body .alarm-count-cell-info,
body .alarm-tbox-info,
body .kpi-stat-card-alarms-bar > span.alarm-info,
body .tag-priority-cell.alarm-info,
body .alarm-band-group-label.alarm-info,
body .pp-alarmdd-badge.is-info,
body .pp-alarm-toast.is-info .pp-alarm-toast-priority,
body .ov-alarm-item .alarm-priority.info,
body .site-popup .alarm-info {
    background: var(--pp-alarm-info-bg) !important;
    border: 1px solid var(--pp-alarm-info-bg) !important;
    border-color: var(--pp-alarm-info-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .alarm-warn,
body .alarm-count-cell-warn,
body .alarm-tbox-warn,
body .kpi-stat-card-alarms-bar > span.alarm-warn,
body .tag-priority-cell.alarm-warn,
body .alarm-band-group-label.alarm-warn,
body .pp-alarmdd-badge.is-warn,
body .pp-alarm-toast.is-warn .pp-alarm-toast-priority,
body .ov-alarm-item .alarm-priority.warn,
body .site-popup .alarm-warn {
    background: var(--pp-alarm-warn-bg) !important;
    border: 1px solid var(--pp-alarm-warn-bg) !important;
    border-color: var(--pp-alarm-warn-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .alarm-error,
body .alarm-count-cell-error,
body .alarm-tbox-error,
body .kpi-stat-card-alarms-bar > span.alarm-error,
body .tag-priority-cell.alarm-error,
body .alarm-band-group-label.alarm-error,
body .pp-alarmdd-badge.is-error,
body .pp-alarm-toast.is-error .pp-alarm-toast-priority,
body .ov-alarm-item .alarm-priority.error,
body .site-popup .alarm-error {
    background: var(--pp-alarm-error-bg) !important;
    border: 1px solid var(--pp-alarm-error-bg) !important;
    border-color: var(--pp-alarm-error-bg) !important;
    color: var(--pp-tone-on-solid) !important;
}

body .pp-alarmdd-row.is-info .pp-alarmdd-band,
body .pp-alarm-toast.is-info .pp-alarm-toast-progress::after {
    background: var(--pp-alarm-info-bg) !important;
}

body .pp-alarmdd-row.is-warn .pp-alarmdd-band,
body .pp-alarm-toast.is-warn .pp-alarm-toast-progress::after {
    background: var(--pp-alarm-warn-bg) !important;
}

body .pp-alarmdd-row.is-error .pp-alarmdd-band,
body .pp-alarm-toast.is-error .pp-alarm-toast-progress::after {
    background: var(--pp-alarm-error-bg) !important;
}

/* flow-log-level-* 커스텀 뱃지 규칙 제거 — flow 로그 레벨 뱃지는 이제 표준
 * pp-badge pp-tone-{info|warn|danger} 외형을 그대로 사용한다(PP.flowLogLevelBadge).
 * 과거 이 규칙들이 폰트/배경/색을 강제 override 하여 표준에서 발산했다. */

/* === pp-76-map-monitoring.css === */
/* pp-27-map-monitoring.css — JSP 인라인 <style> 추출 통합 (signal parts) */

/* === from map/index.jsp === */
#side_panel_body { scrollbar-width: none; -ms-overflow-style: none; }
#side_panel_body::-webkit-scrollbar { width: 4px; }
#side_panel_body::-webkit-scrollbar-thumb { background: transparent; border-radius: 2px; }
#side_panel_body::-webkit-scrollbar-track { background: transparent; }
#side_panel_body:hover { scrollbar-width: thin; }
#side_panel_body:hover::-webkit-scrollbar-thumb { background: #ccc; }

/* === from map/include/diagnostic-sidebar.jsp === */
.edge-block { display:inline-block;width:20px;height:20px;margin:2px;border-radius:3px;cursor:pointer;opacity:0.9; }
.edge-block:hover { opacity:1;box-shadow:0 0 6px rgba(0,0,0,0.25); }

/* === from monitoring/index.jsp === */
.mon-card { border:1px solid #e9ecef;border-radius:6px;padding:10px;margin-bottom:10px;background:#fff; }
.mon-card-title { font-size:11px;font-weight:600;color:#666;margin-bottom:8px;padding-bottom:5px;border-bottom:1px solid #f0f0f0; }
.mon-card-title i { margin-right:3px;color:#999; }
.mon-kv { width:100%;border-collapse:collapse; }
.mon-kv td { padding:5px 10px;font-size:13px;line-height:20px;border-bottom:1px solid #f0f0f0; }
.mon-kv tr:last-child td { border-bottom:none; }
.mon-kv td:first-child { color:#999; }
.mon-kv td:last-child { text-align:right;font-weight:600;color:#333; }
.mon-infra-cell { flex:1;min-width:16.66%;text-align:center;padding:14px 8px;border-right:1px solid #eee;border-top:1px solid #eee; }
.mon-infra-cell:last-child { border-right:none; }
.mon-infra-icon { font-size:18px;color:#888;margin-bottom:6px; }
.mon-infra-label { font-size:11px;color:#999;margin-bottom:6px;letter-spacing:0.3px; }
.mon-infra-badge { font-size:13px;font-weight:600; }
.mon-metric-body { height:220px;overflow:hidden;display:flex;flex-direction:column;justify-content:space-between; }
.eq-block { display:inline-block;width:24px;height:24px;margin:1px;border-radius:3px;cursor:pointer;text-align:center;line-height:24px;font-size:0;color:#fff;opacity:0.9; }
.eq-block:hover { opacity:1;box-shadow:0 0 6px rgba(0,0,0,0.2); }

/* ============================================================
 * 맵 오버레이 연결상태 뱃지 — 형태 원복(8px 통일 예외, 맵 스코프)
 * ------------------------------------------------------------
 * pp-74 Phase 1.5 가 `pp-status-bg-*` / `eq-status-badge` family 를
 * 카논 8px 형태(inline-flex·min-height 20px·padding 2px 10px·11px/700)로
 * 통일했는데, 이 family 는 맵(/map/index) 오버레이의 두 군데에도 쓰여
 * 모양이 바뀐다. 맵 오버레이만 원래 형태로 되돌린다(색/배경은 미변경).
 *
 * 스코프(맵 컨텍스트 한정):
 *   · #map-wrapper .map-overlay-keep .opc_obj  → 좌하단 OPC 연결 legend 5칩
 *     (map-overlays.jsp). 같은 `opc_obj` 가 connect/monitoring 등 타 화면에도
 *     쓰이나 거긴 `pp-status-bg-*` 미부착이라 영향 없음.
 *   · .site-popup .eq-status-badge            → 사이트 팝업 연결/건강 카운트칩
 *     (map/site.jsp). 같은 `eq-status-badge` 가 equipment 표에도 쓰이나
 *     `.site-popup` 스코프라 표는 8px 통일 유지.
 *
 * specificity: #id+2class(1,2,0) / 2class(0,2,0) 모두 pp-74 의
 * `body .pp-status-bg-*`(0,1,1)·`body .eq-status-badge`(0,1,1) 보다 높음 →
 * !important 동급에서 승리. 원래값 출처: pp-34(.opc_obj)·pp-40(.eq-status-badge).
 * ============================================================ */
#map-wrapper .map-overlay-keep .opc_obj.pp-status-bg-ok,
#map-wrapper .map-overlay-keep .opc_obj.pp-status-bg-delay,
#map-wrapper .map-overlay-keep .opc_obj.pp-status-bg-anomaly,
#map-wrapper .map-overlay-keep .opc_obj.pp-status-bg-disc,
#map-wrapper .map-overlay-keep .opc_obj.pp-status-bg-none {
    display: block !important;
    align-items: initial !important;
    justify-content: initial !important;
    gap: 0 !important;
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px !important;
    padding: 4px 0 !important;
    border-radius: 4px !important;
    font-size: 11px !important;
    font-weight: normal !important;
    line-height: 1.2 !important;
    white-space: normal !important;
    vertical-align: baseline !important;
}

.site-popup .eq-status-badge.pp-status-bg-ok,
.site-popup .eq-status-badge.pp-status-bg-delay,
.site-popup .eq-status-badge.pp-status-bg-anomaly,
.site-popup .eq-status-badge.pp-status-bg-disc,
.site-popup .eq-status-badge.pp-status-bg-muted {
    display: inline-block !important;
    align-items: initial !important;
    justify-content: initial !important;
    gap: 0 !important;
    min-height: 0 !important;
    padding: 0px 6px !important;
    border-radius: 8px !important;
    font-size: 10px !important;
    font-weight: 600 !important;
    line-height: 16px !important;
    white-space: nowrap !important;
    vertical-align: baseline !important;
}

/* === pp-78-flow-diag-blob.css === */
/* pp-28-flow-diag-blob.css — JSP 인라인 <style> 추출 통합 (signal parts) */

/* === from flow/index.jsp === */
#data_table td { vertical-align: middle; }
.flow-status-badge {
    display: inline-block; padding: 2px 8px; border-radius: 12px;
    font-size: 11px; font-weight: 600;
}
.flow-status-badge.enabled  { background: #e6f4ea; color: #1e8e3e; border: 1px solid #c8e6c9; }
.flow-status-badge.disabled { background: #f1f3f4; color: #5f6368; border: 1px solid #dadce0; }
.flow-status-badge.root     { background: #fff3e0; color: #e65100; border: 1px solid #ffe0b2; margin-left: 4px; }
/* 도큐먼트 추가 다이얼로그와 동일 폭 */
.flow-create-dialog .modal-dialog,
.flow-import-dialog .modal-dialog { width: 600px; }

/* === from flow/edit.jsp === */
/* 편집 화면 — 3패널 동일 높이 (캔버스 800px 기준 통일) */
.flow-edit-body       { min-height: 600px; }
.flow-canvas-panel    { padding: 0; position: relative; }
/* 플로우 조회(view) 캔버스 — 편집보다 150px 더 높게 (다이어그램 가독성) */
#flow_view_canvas_wrap { height: 900px !important; }
/* 팔레트 = 690px (검색 필드 sticky + 본문 스크롤) */
.flow-palette-panel   { padding: 0;   height: 690px; overflow-y: auto; }
/* 인스펙터(480) + 디버그(320) = 800 */
.flow-inspector-panel { padding: 12px; max-height: 480px; overflow-y: auto; }
/* canvas-wrap 높이는 pp-flow.css에서 단일 정의 (현재 800px) */
/* 메타 편집 다이얼로그 — 텍스트 영역에 맞춰 더 넓게 */
.flow-meta-dialog .modal-dialog { width: 800px; }
/* 스크립트 편집 다이얼로그 — 메타 다이얼로그와 동일 폭 (BootstrapDialog NORMAL) */
.flow-script-dialog .modal-dialog { width: 800px; }
.flow-script-dialog .CodeMirror {
  height: 380px; border-radius: 12px; overflow: hidden; font-size: 14px; line-height: 1.55;
  font-family: 'JetBrains Mono','Cascadia Code','Fira Code','Source Code Pro',Consolas,'D2Coding',ui-monospace,SFMono-Regular,Menlo,monospace;
  font-variant-ligatures: contextual;
}
.flow-script-dialog .CodeMirror-lines { padding: 8px 0; }

/* === from diagnostic/view.jsp === */
.diag-header {
    display:flex; align-items:center; justify-content:space-between;
    padding:6px 0; margin-bottom:8px; border-bottom:1px solid #e9ecef;
}
.diag-header-title { font-size:13px; font-weight:600; color:#555; }
.diag-header-title i { margin-right:4px; color:#999; }
.diag-header-count { font-size:13px; color:#aaa; }
.diag-list { list-style:none; margin:0; padding:0; }
.diag-item {
    display:flex; align-items:stretch; margin-bottom:5px;
    border-radius:4px; background:#fff; border:1px solid #eee;
    overflow:hidden; transition:box-shadow 0.15s;
}
.diag-item:hover { box-shadow:0 1px 4px rgba(0,0,0,0.08); }
.diag-bar { width:3px; flex-shrink:0; }
.diag-icon { display:flex; align-items:center; justify-content:center; width:30px; flex-shrink:0; font-size:13px; }
.diag-body { flex:1; padding:6px 8px 6px 0; min-width:0; }
.diag-msg { font-size:12px; line-height:1.4; color:#333; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.diag-meta { font-size:12px; color:#aaa; margin-top:3px; display:flex; align-items:center; gap:8px; }
.diag-meta i { margin-right:2px; }
.diag-empty { padding:40px; text-align:center; font-size:13px; color:#ccc; }

/* timeline-event-content 모서리는 pp-57 정본(6px)으로 통일 — 기존 32px 제거 */

/* === pp-80-misc-extracted.css === */
/* pp-29-misc-extracted.css — JSP 인라인 <style> 추출 통합 (signal parts) */

/* === from statement/index.jsp === */
#data_table td { vertical-align: middle; }

/* === from analysis/index.jsp === */
/* (.analysis-kpi 룰 제거 — kpi-stat-card 디자인 시스템 표준으로 교체) */
.tab-pane > .row { padding:0 10px; }

/* === from include/domain-search-dialog.jsp === */
/* dialog 본체 — z-index 는 BootstrapDialog 의 modal 위로 */
/* 도메인 검색 다이얼로그 — 고정폭(가변 92% 제거)으로 테이블/컬럼 폭 고정. 1200→1300(+100px). 작은 화면만 96vw 로 클램프. */
.ds-dialog .modal-dialog { width: 1300px; max-width: 96vw; }
.ds-dialog .modal-content {
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0,0,0,0.18);
  overflow: hidden;
  border: 1px solid var(--pp-border);
}
/* 헤더 — 패널 헤딩과 동일 톤 (흰 배경 + 아이콘 + 타이틀 + 닫기) */
.ds-dialog .modal-header {
  background: #fff !important;
  color: var(--foreground, #1f2937) !important;
  border-bottom: 1px solid var(--pp-border) !important;
  padding: 14px 20px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: space-between !important;
  min-height: 56px !important;
  gap: 10px !important;
}
.ds-dialog .modal-header .bootstrap-dialog-title {
  color: var(--foreground, #1f2937) !important;
  font-weight: 600 !important;
  font-size: 15px !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 8px !important;
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.3;
}
.ds-dialog .modal-header .bootstrap-dialog-title i,
.ds-dialog .modal-header .bootstrap-dialog-title .fa-light,
.ds-dialog .modal-header .bootstrap-dialog-title .fa-brands {
  color: var(--primary, var(--pp-primary-strong)) !important;
  font-size: 16px !important;
  margin-right: 2px;
  line-height: 1;
}
.ds-dialog .modal-header .btn-close {
  color: var(--muted-foreground, var(--pp-muted-fg)) !important;
  opacity: 1 !important;
  text-shadow: none !important;
  font-size: 22px !important;
  line-height: 1 !important;
  width: 30px !important;
  height: 30px !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  border-radius: 6px !important;
  margin: 0 !important;
  padding: 0 !important;
  background: transparent !important;
  border: 0 !important;
  transition: background 0.12s, color 0.12s;
  flex-shrink: 0;
}
.ds-dialog .modal-header .btn-close:hover,
.ds-dialog .modal-header .btn-close:focus {
  color: var(--foreground, #1f2937) !important;
  background: var(--muted, #f4f4f5) !important;
  outline: 0;
}
.ds-dialog .modal-body   { padding: 16px 20px; background: #fff; }
.ds-dialog .modal-footer { background: #fff; border-top: 1px solid var(--pp-border); margin-top: 0; padding: 12px 20px; }

.ds-search-row { display:flex; gap:8px; align-items:center; margin-bottom:10px; }
.ds-search-row input.ds-q  {
  flex:1; height:40px; font-size:14px; padding:8px 12px;
  border:1px solid var(--pp-border, var(--pp-text-soft));
  border-radius:6px;
  background:#fff;
  color: var(--foreground, #0f172a);
  box-shadow: none;
  transition: border-color .15s, box-shadow .15s;
}
.ds-search-row input.ds-q::placeholder { color: var(--muted-foreground, var(--pp-text-muted)); }
.ds-search-row input.ds-q:focus {
  outline: 0;
  border-color: var(--primary, var(--pp-primary)) !important;
  box-shadow: 0 0 0 3px rgba(29, 78, 216, 0.15) !important;
}
.ds-search-row .ds-hint    { font-size:11px; color:var(--pp-muted-fg); white-space:nowrap; }

.ds-domain-bar { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:10px; }
.ds-domain-chip {
  display:inline-flex; align-items:center; gap:5px;
  padding:4px 11px; border-radius:14px; font-size:11px; font-weight:600; cursor:pointer;
  background:#fff; color:#374151; user-select:none; border:1px solid #d0d7de;
  transition: all .12s;
}
.ds-domain-chip:hover { border-color:#0d4590; color:#0d4590; }
.ds-domain-chip.active { background:#0d4590; color:#fff; border-color:#0d4590; }
.ds-domain-chip .ds-cnt { font-weight:700; opacity:.85; }

.ds-badge {
  display:inline-block; padding:3px 8px; border-radius:10px; font-size:10px; font-weight:700;
  color:#fff; line-height:1; vertical-align:middle; letter-spacing: 0.3px;
}
.ds-badge-site         { background:#0a7ea4; }
.ds-badge-area         { background:#0f7857; }
.ds-badge-line         { background:#198754; }
.ds-badge-equipment    { background:#2da44e; }
.ds-badge-tag          { background:#bf8700; }
.ds-badge-opc          { background:#7b3ff2; }
.ds-badge-edge         { background:#0d9488; }
.ds-badge-alarm_config { background:#bf2b30; }
.ds-badge-user         { background:#0d4590; }
.ds-badge-employee     { background:#d2691e; }
.ds-badge-security     { background:#6b21a8; }
.ds-badge-customer     { background:var(--pp-border-strong); }
.ds-badge-product      { background:#1f6feb; }
.ds-badge-flow         { background:#9333ea; }

/* DataTable — 프로젝트 기본 bootstrap 테마 그대로 사용 (커스텀 최소화) */
.ds-dialog .dataTables_wrapper { margin-left: 5px; margin-right: 5px; }
/* 페이지네이션 오른쪽 정렬 (info 는 왼쪽) — flex 강제 */
.ds-dialog .dataTables_paginate {
  display: flex !important;
  justify-content: flex-end !important;
  text-align: right !important;
}
.ds-dialog .dataTables_paginate ul.pagination {
  margin-left: auto !important;
}
.ds-dialog .dataTables_info {
  float: left !important;
  text-align: left !important;
}

.ds-id-cell {
  cursor:pointer; font-family: Consolas, Menlo, monospace; font-size:12px;
  color:#0a58ca; text-decoration:none;
}
.ds-id-cell:hover { text-decoration:underline; }

.ds-action-btn {
  display:inline-flex; align-items:center; padding:2px 8px; border:1px solid #ccc; border-radius:3px;
  background:#fafafa; cursor:pointer; font-size:11px; color:#333; margin-right:3px;
}
.ds-action-btn:hover { background:#e9ecef; }

.ds-recent-row { font-size:11px; color:var(--pp-muted-fg); margin-bottom:6px; }
.ds-recent-chip {
  display:inline-block; padding:2px 9px; margin-right:4px; background:#fff;
  border:1px solid #d0d7de; border-radius:10px; cursor:pointer; font-size:11px; color:#374151;
}
.ds-recent-chip:hover { background:#0d4590; color:#fff; border-color:#0d4590; }

/* (제거됨) 구 .sc-empty/.ds-empty 빈상태 톤 — 마크업 사용 0(죽은 CSS). 표준은 .pp-empty-state(pp-25-cards). */
.ds-table-wrap { margin-top: 4px; }
/* 컬럼 고정 폭(JS th width) 기준 — 긴 ID/이름/설명은 말줄임(ellipsis), 전체는 title 툴팁 */
.ds-table { table-layout: fixed; }
.ds-table td.ds-ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-table td.ds-ellipsis > span,
.ds-table td.ds-ellipsis > .ds-id-cell { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* PrettyJSON 뷰어(공통) — 긴 JSON 문자열 값이 셀을 벗어나지 않도록 줄바꿈.
 * 벤더 pretty-json.css 의 leaf 폭 제한 규칙은 클래스명 오타(.leaft-container)로
 * 죽어 있어 .leaf-container 에 적용되지 않는다 → 값이 셀 폭을 넘쳐 가로로 흘렀다.
 * BS5 유틸로 표현 불가(서드파티 PrettyJSON 마크업 대상 선택자)라 part CSS 로 보정.
 * 모든 PrettyJSON 소비 페이지(query/alarm/blob/asset·data/tag 등)에 공통 적용. */
.json-view {
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* PrettyJSON 미적용(raw text) 경로: JSON.stringify(...,4) 들여쓰기/개행 보존 */
.json-view { white-space: pre-wrap; }
.json-view .node-content-wrapper,
.json-view .leaf-container,
.json-view .node-container {
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.json-view .leaf-container span {
  white-space: normal;
}

/* ── 공통 JSON 뷰어 (PP.json.html) — 네이티브 <details> 접힘/펼침 ───────────────
 * 표 셀/상세 패널 공통. JS 이벤트 핸들러가 없어 DataTables redraw 후에도 동작 보존
 * (구 PrettyJSON+Backbone 의 클릭 핸들러 소실 문제 해소). 타입별 색은 디자인토큰만 사용. */
.pp-json {
  text-align: left;
  font-family: 'Consolas', 'Menlo', monospace;
  font-size: 12px;
  line-height: 1.5;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.pp-json details { margin: 0; }
/* raw 들여쓰기 보존(트리 아닌 JSON.stringify(,4) 출력용) */
.pp-json-pre { white-space: pre-wrap; }
.pp-json-summary {
  cursor: pointer;
  list-style: none;
}
.pp-json-summary::-webkit-details-marker { display: none; }
.pp-json-summary::before {
  content: '\25B8';                 /* ▸ 접힘 표시 */
  display: inline-block;
  width: 1em;
  color: var(--muted-foreground);
}
.pp-json-node[open] > .pp-json-summary::before { content: '\25BE'; }   /* ▾ 펼침 */
.pp-json-node[open] > .pp-json-summary > .pp-json-ellipsis { display: none; }
.pp-json-ellipsis { color: var(--muted-foreground); }
.pp-json-body {
  padding-left: 14px;
  margin-left: 4px;
  border-left: 1px dotted var(--border);
}
.pp-json-row { white-space: normal; }
.pp-json-key { color: var(--foreground); font-weight: 600; }
.pp-json-colon,
.pp-json-bracket { color: var(--muted-foreground); }
.pp-json-string { color: var(--success); }
.pp-json-number { color: var(--warning); }
.pp-json-boolean { color: var(--primary); }
.pp-json-null { color: var(--destructive); }

/* === pp-82-flow-stats.css === */
/* ============================================================================
 * pp-50-flow-stats.css — Flow 통계 대시보드 위젯
 * 24h hourly bar chart + 30day daily line chart + KPI 요약.
 * pp-signal-theme.css (산출물) 의 part 로 ant concat-css 가 알파벳 순으로 concat 한다.
 * 인라인 스타일 금지 — 모든 모듈러 스타일은 본 파일에 시맨틱 클래스로 정의.
 * ============================================================================ */

/* 페이지 레이아웃 — KPI strip 위, 두 차트 옆으로 */
.flow-stats-page {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* KPI 4 카드 strip — KPI Stat Card 패턴 재사용 */
.flow-stats-kpi-strip {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}

.flow-stats-kpi-card {
    background: var(--pp-surface, #ffffff);
    border: 1px solid var(--pp-border-color, #e0e0e0);
    border-radius: 6px;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.flow-stats-kpi-label {
    color: var(--pp-text-muted, #666);
    font-size: 12px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.flow-stats-kpi-value {
    font-size: 24px;
    font-weight: 700;
    color: var(--pp-text-default, #333);
    line-height: 1.1;
}

.flow-stats-kpi-value.kpi-success { color: var(--pp-tone-success-bg); }
.flow-stats-kpi-value.kpi-error   { color: #c5221f; }
.flow-stats-kpi-value.kpi-rate    { color: #1a73e8; }

.flow-stats-kpi-sub {
    color: var(--pp-text-muted, #888);
    font-size: 11px;
}

/* 차트 그리드 — 24h hourly 와 30day daily 가 가로로 */
.flow-stats-chart-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}

@media (max-width: 1100px) {
    .flow-stats-chart-grid { grid-template-columns: 1fr; }
}

.flow-stats-chart-card {
    background: var(--pp-surface, #ffffff);
    border: 1px solid var(--pp-border-color, #e0e0e0);
    border-radius: 6px;
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.flow-stats-chart-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.flow-stats-chart-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--pp-text-default, #333);
}

.flow-stats-chart-sub {
    color: var(--pp-text-muted, #888);
    font-size: 11px;
}

.flow-stats-chart-legend {
    display: flex;
    gap: 12px;
    align-items: center;
    font-size: 11px;
}

.flow-stats-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.flow-stats-legend-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
    background: #999;
}

.flow-stats-legend-swatch.swatch-success { background: var(--pp-tone-success-bg); }
.flow-stats-legend-swatch.swatch-error   { background: #c5221f; }
.flow-stats-legend-swatch.swatch-rate    { background: #1a73e8; }

/* canvas 컨테이너 — 고정 높이 */
.flow-stats-chart-body {
    position: relative;
    height: 240px;
}

.flow-stats-chart-canvas {
    width: 100%;
    height: 100%;
}

/* 빈 상태 */
.flow-stats-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--pp-text-muted, #888);
    font-size: 12px;
    flex-direction: column;
    gap: 6px;
}

.flow-stats-empty i {
    font-size: 28px;
    opacity: 0.4;
}

/* flow-id 필터 행 */
.flow-stats-filter-row {
    display: flex;
    gap: 8px;
    align-items: center;
}

.flow-stats-filter-row .form-control { width: 280px; }

/* 컬러 뱃지 — 라이트 테마는 진한 배경 + 흰 텍스트가 표준 (사용자 메모리) */
.flow-stats-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 12px;
    font-size: 11px;
    font-weight: 600;
    color: #ffffff;
}

.flow-stats-badge.badge-success { background: var(--pp-tone-success-bg); }
.flow-stats-badge.badge-error   { background: #c5221f; }
.flow-stats-badge.badge-info    { background: #1a73e8; }

/* ---------------------------------------------------------------------------
 * Flow Top N 위젯 — 대시보드/통계 페이지 공용 가로 막대 차트 컨테이너
 * --------------------------------------------------------------------------- */

/* row 컨테이너 — 메인 패널과 동일 폭 / 여백 */
.flow-top-row {
    /* margin-top: 12px; */
    margin-bottom: 12px;
}

/* 차트 컨테이너 — echarts target. 인라인 height 금지 → 시맨틱 클래스 */
.flow-top-chart {
    width: 100%;
    height: 240px;
}

/* 시간별 트렌드 차트 (24h stacked bar) — bottom-content.jsp 의 col-lg-12 풀 너비 */
.flow-trend-row {
    /* margin-top: 12px; */
    margin-bottom: 12px;
}
.flow-trend-chart {
    width: 100%;
    height: 280px;
}

/* 빈 상태 (데이터 0건) — echarts 인스턴스 생성 전 fallback */
.flow-top-chart.flow-top-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--pp-text-muted, #888);
    font-size: 12px;
}

/* 엣지 헬스 시간별 차트 — 24h stacked bar (NORMAL/WARN/ERROR) */
.edge-health-row {
    margin-top: 12px;
    margin-bottom: 12px;
}
.edge-health-chart {
    width: 100%;
    height: 240px;
}
.edge-health-chart.edge-health-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--pp-text-muted, #888);
    font-size: 12px;
}

/* 엣지 일괄 계측 (24h) — 3 차트 row (REST / inventory+plugin / health 도넛) */
.edge-stats-row {
    margin-top: 12px;
    margin-bottom: 12px;
}
.edge-stats-chart {
    width: 100%;
    height: 240px;
}
.edge-stats-chart.edge-stats-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--pp-text-muted, #888);
    font-size: 12px;
}

/* flow 상세보기 성공/에러 비율 차트 박스 — 인라인 height/center 대체(BS5 정리) */
.flow-ratio-chart-box {
    height: 170px;
    text-align: center;
}

/* === pp-84-status-page.css === */
/* ============================================================
 * Status page — public /status (status.claude.com 스타일)
 * ------------------------------------------------------------
 * 사용처: /WEB-INF/jsp/status/index.jsp
 *         /public/module/status/status-page.js
 *
 * 시그널 테마 토큰 (--pp-*) 사용. 라이트/다크 모두에서 동작.
 * 인라인 스타일 0. !important 자제.
 * ============================================================ */

body.pp-status-body {
    /* SUIT 로컬 호스팅 폰트(@font-face 는 pp-00-fonts.css). status 페이지 전체 SUIT 적용. */
    font-family: 'SUIT', -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo", sans-serif;
    background: var(--pp-bg-muted, #f8fafc);
    color: var(--pp-text, #0f172a);
    min-height: 100vh;
    margin: 0;
}

.status-page {
    max-width: 1080px;
    margin: 0 auto;
    padding: 32px 24px 64px 24px;
}

/* ── Header ───────────────────────────────────────────────── */

.status-page-header {
    margin-bottom: 24px;
}

.status-page-brand {
    display: flex;
    align-items: center;
    gap: 16px;
}

.status-page-logo {
    height: 36px;
    width: auto;
    display: block;
}

.status-page-title-block {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.status-page-title {
    margin: 0;                  /* h1 승격(a11y) 시 기본 margin 중화 — 기존 div 외형 유지 */
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: #0d0e0e;
}

.status-page-subtitle {
    font-size: 13px;
    color: var(--pp-text-muted, #64748b);
}

/* ── Top banner ───────────────────────────────────────────── */

.status-banner {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 24px 28px;
    border-radius: 12px;
    margin-bottom: 28px;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 4px 12px rgba(15, 23, 42, 0.06);
    color: var(--pp-white, #ffffff);
    background: var(--pp-tone-muted-bg, #6b7280);
    transition: background 0.3s ease;
}

.status-banner-operational {
    background: var(--pp-tone-success-bg);
}

.status-banner-degraded {
    background: var(--pp-tone-warn-bg);
}

.status-banner-outage {
    background: var(--pp-tone-danger-bg);
}

.status-banner-loading {
    background: var(--pp-tone-muted-bg, #6b7280);
}

.status-banner-icon {
    font-size: 36px;
    line-height: 1;
    flex-shrink: 0;
}

.status-banner-text {
    flex: 1;
    min-width: 0;
}

.status-banner-headline {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.25;
    margin-bottom: 4px;
}

.status-banner-asof {
    font-size: 13px;
    opacity: 0.92;
}

.status-banner-uptime {
    text-align: right;
    flex-shrink: 0;
    padding-left: 16px;
    border-left: 1px solid rgba(255, 255, 255, 0.25);
}

.status-uptime-value {
    font-size: 28px;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.status-uptime-unit {
    font-size: 16px;
    font-weight: 600;
    margin-left: 2px;
    opacity: 0.85;
}

.status-uptime-label {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.85;
    margin-top: 2px;
}

/* ── Endpoint cards list ─────────────────────────────────── */

.status-endpoints {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.status-endpoints-skeleton {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.status-endpoints-empty {
    padding: 32px;
    text-align: center;
    color: var(--pp-text-muted, #64748b);
    background: var(--pp-bg, #ffffff);
    border: 1px solid var(--pp-border, #e5e7eb);
    border-radius: 10px;
}

.endpoint-card {
    background: var(--pp-bg, #ffffff);
    border: 1px solid var(--pp-border, #e5e7eb);
    border-radius: 10px;
    padding: 18px 20px;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.03);
    transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.endpoint-card:hover {
    box-shadow: 0 2px 6px rgba(15, 23, 42, 0.08);
    border-color: var(--pp-border-strong, #cbd5e1);
}

.endpoint-card-skeleton {
    height: 156px;
    background: linear-gradient(90deg,
        var(--pp-bg-muted, #f1f5f9) 0%,
        var(--pp-bg, #ffffff) 50%,
        var(--pp-bg-muted, #f1f5f9) 100%);
    background-size: 200% 100%;
    animation: pp-status-skeleton 1.6s ease-in-out infinite;
}

@keyframes pp-status-skeleton {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

.endpoint-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.endpoint-card-title {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
    flex: 1;
}

.endpoint-card-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--pp-text, #0f172a);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.endpoint-card-category {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--pp-text-muted, #64748b);
    padding: 2px 8px;
    border: 1px solid var(--pp-border, #e5e7eb);
    border-radius: 6px;
    background: var(--pp-bg-muted, #f8fafc);
}

/* ── Endpoint status badge (라이트 테마: 진한 배경 + 흰 텍스트) ── */

.endpoint-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    color: var(--pp-tone-on-solid, #ffffff);
}

.endpoint-status-badge > i {
    font-size: 8px;
    line-height: 1;
}

/* tone classes(pp-tone-*) 는 pp-12-status-tones.css 에서 배경/텍스트 색 공급. */

/* ── Endpoint metric grid ────────────────────────────────── */

.endpoint-card-metrics {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
    margin-bottom: 14px;
}

.endpoint-metric {
    min-width: 0;
}

.endpoint-metric-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--pp-text-muted, #64748b);
    margin-bottom: 2px;
}

.endpoint-metric-value {
    font-size: 18px;
    font-weight: 600;
    color: var(--pp-text, #0f172a);
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

.endpoint-metric-unit {
    font-size: 12px;
    font-weight: 500;
    color: var(--pp-text-muted, #64748b);
    margin-left: 2px;
}

/* ── 90-bar timeline ─────────────────────────────────────── */

.timeline-90 {
    display: grid;
    grid-template-columns: repeat(90, minmax(0, 1fr));
    gap: 2px;
    height: 28px;
    align-items: stretch;
}

.timeline-bar {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 2px;
    background: var(--pp-bg-muted, #e5e7eb);
}

.timeline-bar-ok {
    background: var(--pp-tone-success-bg);
}

.timeline-bar-degraded {
    background: var(--pp-tone-warn-bg);
}

.timeline-bar-outage {
    background: var(--pp-tone-danger-bg);
}

.timeline-bar-no-data {
    background: var(--pp-border, #e5e7eb);
}

/* ── Footer ──────────────────────────────────────────────── */

.status-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 28px;
    padding: 12px 4px;
    font-size: 12px;
    color: var(--pp-text-muted, #64748b);
    border-top: 1px solid var(--pp-border, #e5e7eb);
}

.status-footer-left,
.status-footer-right {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.status-footer-right span:last-child {
    font-variant-numeric: tabular-nums;
    color: var(--pp-text-soft, #334155);
}

/* ── Dark theme override (status page 전용) ──────────────── */

body.pp-status-body {
    /* Signal theme base tokens — pp-fonts.css paints `body { background: var(--background) }`,
       so the page-level dark background must override these, not just the pp-* tokens.
       Overriding them here makes the dark background hold regardless of which body
       rule wins the cascade — no !important needed. */
    --background:     #0f172a;
    --foreground:     #f1f5f9;
    --pp-bg:          #1e293b;
    --pp-bg-muted:    #0f172a;
    --pp-text:        #f1f5f9;
    --pp-text-muted:  #94a3b8;
    --pp-text-soft:   #cbd5e1;
    --pp-border:      #334155;
    --pp-border-strong: #475569;
    --pp-white:       #ffffff;
    background: #0f172a;
    color: #f1f5f9;
}

/* ── Section title (인프라 / API 구분자) ─────────────────── */

.status-section-title {
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--pp-text-muted, #94a3b8);
    margin: 0 0 12px 2px;
}

/* ── Infra section ───────────────────────────────────────── */

.status-infra-section {
    margin-bottom: 36px;
}

.infra-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}

.infra-card {
    background: var(--pp-bg, #1e293b);
    border: 1px solid var(--pp-border, #334155);
    border-radius: 10px;
    padding: 18px 18px 14px 18px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
    transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.infra-card:hover {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
    border-color: var(--pp-border-strong, #475569);
}

.infra-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}

.infra-card-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--pp-text, #f1f5f9);
}

.infra-card-uptime {
    font-size: 12px;
    color: var(--pp-text-muted, #94a3b8);
    font-variant-numeric: tabular-nums;
}

/* ── API section ─────────────────────────────────────────── */

.status-api-section {
    margin-bottom: 0;
}

/* ── Responsive ──────────────────────────────────────────── */

@media (max-width: 720px) {
    .status-page {
        padding: 20px 14px 48px 14px;
    }

    .status-banner {
        flex-direction: column;
        align-items: flex-start;
        gap: 12px;
        padding: 18px 20px;
    }

    .status-banner-uptime {
        padding-left: 0;
        border-left: none;
        border-top: 1px solid rgba(255, 255, 255, 0.25);
        padding-top: 10px;
        text-align: left;
        width: 100%;
    }

    .endpoint-card-metrics {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
    }

    .timeline-90 {
        height: 22px;
    }
}

/* === pp-86-cm-xq-light-tokens.css === */
/*
 * pp-86-cm-xq-light-tokens.css — CodeMirror 6 구문 토큰 xq-light 팔레트
 *
 * CM6 번들(codemirror-6.bundle.js)은 @codemirror/language defaultHighlightStyle +
 * classHighlighter 로 .tok-* CSS 클래스를 DOM 에 직접 주입한다.
 * 이 파일은 해당 클래스를 .cm-editor 스코프로 매핑해 xq-light 구문 색 완성.
 *
 * 팔레트: CodeMirror 5 xq-light 테마 정본 색상 (번들 재빌드 없음, specificity 스코프 사용).
 *
 * 클래스 출처 — bundle 내 classHighlighter(Js) 정의:
 *   tok-keyword   tok-atom/bool      tok-string/string2  tok-number
 *   tok-comment   tok-variableName   tok-propertyName    tok-typeName
 *   tok-operator  tok-meta           tok-punctuation     tok-namespace
 *   tok-className tok-macroName      tok-labelName
 *   tok-literal   tok-link           tok-heading/emphasis/strong
 *   tok-inserted  tok-deleted        tok-invalid         tok-url
 */

/* keyword: 예약어 (if/for/return/SELECT/WHERE …) */
.cm-editor .tok-keyword {
    color: #5a5cad;
}

/* atom: 특수 리터럴 원자값 (null, undefined, NaN, Infinity 등) */
.cm-editor .tok-atom {
    color: #6c8cd5;
}

/* bool: boolean 리터럴 (true / false) */
.cm-editor .tok-bool {
    color: #6c8cd5;
}

/* number: 숫자 리터럴 */
.cm-editor .tok-number {
    color: #6c8cd5;
}

/* string: 일반 문자열 */
.cm-editor .tok-string {
    color: #1a1aa6;
}

/* string2: regexp · escape · special(string) */
.cm-editor .tok-string2 {
    color: #1a1aa6;
}

/* literal: literal 태그 (템플릿 리터럴 등) */
.cm-editor .tok-literal {
    color: #1a1aa6;
}

/* comment: 주석 — 이탤릭 */
.cm-editor .tok-comment {
    color: #999988;
    font-style: italic;
}

/* meta: 메타 정보 (shebang, pragma, annotation) */
.cm-editor .tok-meta {
    color: #555555;
}

/* variableName: 변수명 */
.cm-editor .tok-variableName {
    color: #000000;
}

/* propertyName: 객체 프로퍼티 / SQL 컬럼명 */
.cm-editor .tok-propertyName {
    color: #1f7199;
}

/* typeName: 타입 식별자 */
.cm-editor .tok-typeName {
    color: #5a5cad;
}

/* namespace: 네임스페이스 */
.cm-editor .tok-namespace {
    color: #5a5cad;
}

/* className: 클래스명 */
.cm-editor .tok-className {
    color: #5a5cad;
}

/* macroName: 매크로 식별자 */
.cm-editor .tok-macroName {
    color: #5a5cad;
}

/* labelName: 레이블명 */
.cm-editor .tok-labelName {
    color: #1f7199;
}

/* operator: 연산자 */
.cm-editor .tok-operator {
    color: #000000;
}

/* punctuation: 구두점 (괄호, 쉼표, 세미콜론 등) */
.cm-editor .tok-punctuation {
    color: #333333;
}

/* url: URL 값 */
.cm-editor .tok-url {
    color: #1a1aa6;
    text-decoration: underline;
}

/* link: 하이퍼링크 */
.cm-editor .tok-link {
    color: #1a1aa6;
    text-decoration: underline;
}

/* heading: 제목 (마크업) */
.cm-editor .tok-heading {
    color: #5a5cad;
    font-weight: bold;
}

/* emphasis: 강조 (이탤릭) */
.cm-editor .tok-emphasis {
    font-style: italic;
}

/* strong: 강조 (볼드) */
.cm-editor .tok-strong {
    font-weight: bold;
}

/* inserted: diff 삽입 */
.cm-editor .tok-inserted {
    color: #2a7e43;
}

/* deleted: diff 삭제 */
.cm-editor .tok-deleted {
    color: #c0392b;
}

/* invalid: 파싱 오류 토큰 */
.cm-editor .tok-invalid {
    color: #ff0000;
}

/* === pp-88-ai-chat-drawer.css === */
/*
 * pp-88 AI 어시스턴트 drawer — 우측 슬라이드 패널(신규 커스텀 컴포넌트).
 * BS5 offcanvas 대신 신규 제작(사용자 요구). BS 유틸로 불가능한 고정 위치·슬라이드
 * 트랜지션·그라디언트 헤더/아바타/전송버튼·말풍선 지오메트리·타이핑 도트 애니메이션·
 * 마크다운 컨텐츠 타이포그래피만 커스텀 CSS 로 둔다(그 외 간격/플렉스는 유틸 사용).
 * 색상은 하드코딩 hex 없이 BS5.3 루트 변수·pp 토큰·rgba 오버레이만 사용(hex ratchet 준수).
 * 라이트/다크 공통: 그라디언트 요소는 다크 브랜드톤 + 흰 글자라 두 테마 모두 대비 확보.
 */
.pp-ai-drawer {
    position: fixed;
    top: 0;
    right: 0;
    width: 600px; /* 사용자 지시 확정 폭 */
    max-width: 90vw;
    height: 100vh;
    background: var(--bs-body-bg);
    border-left: 1px solid var(--bs-border-color);
    box-shadow: -4px 0 16px rgba(0, 0, 0, 0.12);
    transform: translateX(100%);
    transition: transform 0.24s ease;
    z-index: 1050;
    display: flex;
    flex-direction: column;
}
.pp-ai-drawer.is-open {
    transform: translateX(0);
}
/* 닫힘 상태(a11y): 슬라이드-아웃(0.24s) 종료 후 visibility:hidden — aria-hidden 인데 textarea/버튼이
   탭 포커스를 받는 문제 차단. visibility 는 0.24s 지연 0s 전환이라 나가는 애니메이션은 그대로 보이고,
   열릴 때는 .is-open(기본 transition: transform만)이 적용돼 즉시 visible 로 복귀한다. */
.pp-ai-drawer:not(.is-open) {
    visibility: hidden;
    transition: transform 0.24s ease, visibility 0s linear 0.24s;
}

/* ── 헤더: 브랜드 그라디언트 밴드 (토큰만 사용 — fallback hex 금지) ── */
/* 헤더 타이틀 대문자(사용자 지시) — 한글 로케일 무영향 */
.pp-ai-drawer-title {
    text-transform: uppercase;
}
.pp-ai-drawer-header {
    padding: 12px 16px;
    background: linear-gradient(135deg, var(--pp-primary-dark), var(--pp-primary-strong));
    color: var(--bs-white);
    font-weight: 600;
}
/* 닫기 버튼 — BS btn-close 배경 SVG 가 테마 광역 오버라이드와 충돌해 아이콘 방식 사용(플랫폼 관례) */
.pp-ai-close {
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: rgba(255, 255, 255, 0.85);
    font-size: 15px;
    cursor: pointer;
}
.pp-ai-close:hover {
    color: rgba(255, 255, 255, 1);
    background: rgba(255, 255, 255, 0.15);
}


/* ── 메시지 영역: 슬림 스크롤바 ── */
.pp-ai-messages {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 12px 16px;
    scrollbar-width: thin;
    scrollbar-color: var(--bs-border-color) transparent;
}
.pp-ai-messages::-webkit-scrollbar { width: 6px; }
.pp-ai-messages::-webkit-scrollbar-track { background: transparent; }
.pp-ai-messages::-webkit-scrollbar-thumb {
    background: var(--bs-border-color);
    border-radius: 3px;
}

/* ── 메시지 행: 신규 메시지 페이드-슬라이드 인 ── */
.pp-ai-msg {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-bottom: 14px;
    animation: pp-ai-msg-in 0.22s ease;
}
@keyframes pp-ai-msg-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.pp-ai-msg-user { justify-content: flex-end; }

/* 버블 첫/끝 요소의 외부 마진 제거 — 렌더된 마크다운(strong.mt-2 등)이 첫 줄일 때 상단 공백 방지 */
.pp-ai-bubble > :first-child { margin-top: 0 !important; }
.pp-ai-bubble > :last-child { margin-bottom: 0 !important; }
.pp-ai-bubble {
    max-width: 85%;
    word-break: break-word;
    font-size: 0.9rem;
    overflow-x: auto;
}
/* 사용자: 헤더 계열 브랜드 그라디언트 + 흰 글자, 우하단 꼬리 */
.pp-ai-msg-user .pp-ai-bubble {
    background: linear-gradient(135deg, var(--pp-primary-strong), var(--pp-primary-dark));
    color: var(--bs-white);
    border-radius: 16px 16px 4px 16px;
    padding: 10px 14px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
    white-space: pre-wrap; /* 사용자 입력은 plain text(textContent) — 줄바꿈 보존 */
}
/* 어시스턴트: 클린 카드(면+헤어라인 보더), 좌하단 꼬리 — 타이핑 도트 말풍선도 동일 카드 */
.pp-ai-msg-assistant .pp-ai-bubble {
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 16px 16px 16px 4px;
    padding: 12px 14px;
    max-width: 88%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);
    line-height: 1.55;
}

/* 어시스턴트 아바타: 28px 원형 그라디언트 + sparkles */
.pp-ai-avatar {
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--pp-primary-dark), var(--pp-primary-strong));
    color: var(--bs-white);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.76rem;
}

/* ── 타이핑 인디케이터: 점 3개 스태거 바운스 ── */
.pp-ai-typing {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 20px;
}
.pp-ai-typing > span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--bs-secondary-color);
    animation: pp-ai-bounce 1s infinite ease-in-out;
}
.pp-ai-typing > span:nth-child(2) { animation-delay: 0.15s; }
.pp-ai-typing > span:nth-child(3) { animation-delay: 0.3s; }
@keyframes pp-ai-bounce {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.45; }
    30%           { transform: translateY(-4px); opacity: 1; }
}

/* ── 정보 라인 · 도구 트레이스 칩 ── */
.pp-ai-msg-info {
    margin-bottom: 10px;
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
    text-align: center;
}
.pp-ai-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin-bottom: 10px;
}
.pp-ai-tools-label {
    font-size: 0.72rem;
    color: var(--bs-secondary-color);
}
.pp-ai-tool-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 10px;
    border-radius: 999px;
    background: var(--bs-secondary-bg);
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
}

/* ── 마크다운 컨텐츠 (renderMarkdown 산출물 — 어시스턴트 말풍선 한정) ── */
.pp-ai-bubble pre {
    margin: 6px 0;
    padding: 8px 10px;
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 6px;
    overflow-x: auto;
    font-size: 0.8rem;
}
.pp-ai-bubble pre code {
    padding: 0;
    background: transparent;
}
.pp-ai-bubble code {
    padding: 1px 6px;
    border-radius: 6px;
    background: var(--bs-tertiary-bg);
    font-size: 0.78rem;
}
.pp-ai-bubble ul,
.pp-ai-bubble ol {
    margin: 4px 0;
    padding-left: 18px;
}
/* 넓은 표 가로 스크롤 컨테이너 — 풍선 폭을 넘는 표가 drawer 밖으로 잘리지 않게 */
.pp-ai-table-scroll {
    max-width: 100%;
    overflow-x: auto;
}
/* 마크다운 테이블: 컴팩트 + 헤어라인 보더 + 라운드 외곽(collapse 해제로 radius 유지) */
.pp-ai-md-table {
    margin: 6px 0;
    font-size: 0.82rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden;
}
.pp-ai-md-table th,
.pp-ai-md-table td {
    padding: 4px 8px;
    border: 0;
    border-bottom: 1px solid var(--bs-border-color);
}
.pp-ai-md-table thead th { background: var(--bs-tertiary-bg); }
.pp-ai-md-table tbody tr:last-child td { border-bottom: 0; }

/* ── 빈 상태: 그라디언트 원 + 인사말 + 추천 질의 칩 ── */
.pp-ai-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 40px 16px 24px;
    text-align: center;
}
.pp-ai-empty-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--pp-primary-dark), var(--pp-primary-strong));
    color: var(--bs-white);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.pp-ai-empty-text {
    color: var(--bs-secondary-color);
    font-size: 0.9rem;
}
.pp-ai-suggests {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
}
.pp-ai-suggest {
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    padding: 6px 14px;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    font-size: 0.82rem;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.pp-ai-suggest:hover {
    background: var(--bs-primary-bg-subtle);
    border-color: var(--bs-primary-border-subtle);
}

/* ── 입력 바: 일체형 필 컴포저 — textarea+전송버튼을 한 캡슐에 (구 form-control 분리형 대체) ── */
.pp-ai-input {
    padding: 10px 12px 12px; /* 섹션 border-top 없음 — 캡슐 자체가 시각 구분자 */
}
.pp-ai-composer {
    border: 1px solid var(--bs-border-color);
    border-radius: 22px;
    background: var(--bs-body-bg);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* 포커스 시 파란 보더 없음(사용자 지시) — 그림자만 미세 강화해 활성 상태 표시 */
.pp-ai-composer:focus-within {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.10);
}
.pp-ai-textarea {
    flex: 1 1 auto;
    min-width: 0;
    border: 0;
    outline: none;
    box-shadow: none;
    background: transparent;
    color: var(--bs-body-color);
    padding: 10px 8px 10px 16px;
    font-size: 0.9rem;
    line-height: 1.4;
    resize: none;
    max-height: 120px; /* chat.js autoGrow 캡과 동기 */
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--bs-border-color) transparent;
}
.pp-ai-textarea::placeholder { color: var(--bs-secondary-color); }
/* 폼 SSOT(pp-23-forms.css)가 모든 textarea 에 강제 우선순위(bang-important)로 보더·min-height 72px·
   :focus 링(파란 보더+그림자)을 지정한다. 컴포저 캡슐이 시각 컨테이너이므로 내부 textarea 는 완전
   무보더여야 함 — 동일 우선순위로만 상쇄 가능(사유 있는 사용, 4건). min-height 40px 는 pp-23 의
   72px 를 눌러 1줄 슬림 높이로 시작한다(chat.js autoGrow 가 확장). */
.pp-ai-composer .pp-ai-textarea,
.pp-ai-composer .pp-ai-textarea:focus {
    background-color: transparent !important; /* pp-23 var(--card) 강제 상쇄 — 캡슐이 배경 담당 */
    border-radius: 22px !important;            /* pp-23 6px 강제 상쇄 — 캡슐 곡률 추종(왼쪽 라운드) */
    padding: 10px 8px 10px 16px !important;    /* pp-23 6px 12px 강제 상쇄 */

    border: 0 !important;
    box-shadow: none !important;
    outline: 0 !important;
    min-height: 40px !important;
}
/* 브라우저/BS form-control 잔재 포커스 링 제거 — 캡슐 :focus-within 링이 대체 */
.pp-ai-input textarea:focus {
    border: 0;
    outline: none;
    box-shadow: none;
}
.pp-ai-send {
    flex: 0 0 34px;
    width: 34px;
    height: 34px;
    margin: 4px 5px 4px 0; /* 캡슐 내부 우하단 안착 */
    border: 0;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--pp-primary-dark), var(--pp-primary-strong));
    color: var(--bs-white);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.82rem;
    cursor: pointer;
    transition: opacity 0.15s ease, transform 0.15s ease;
}
.pp-ai-send:hover:not(:disabled) { transform: translateY(-1px); }
.pp-ai-send:disabled {
    opacity: 0.5;
    cursor: default;
}
.pp-ai-send:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

/* 캡슐 하단 힌트: Enter 전송 · Shift+Enter 줄바꿈 (chat.js 가 PP.msg 로 채움) */
.pp-ai-hint {
    margin-top: 6px;
    font-size: 0.72rem;
    color: var(--bs-secondary-color);
    text-align: center;
}

/* ── 확인부 행동 카드: 변경 도구 승인 UI ([실행/취소]) ──
   생성 사유: 어시스턴트 카드 룩을 그대로 쓰되 브랜드 토큰(--pp-primary-strong) 좌측 강조 보더와
   해소(승인/취소) 후 톤다운이 필요 — BS 유틸에는 토큰 참조 보더/상태 톤이 없다(신규 hex 없음).
   버튼·간격은 BS 유틸(btn/d-flex/gap-2/mt-2)로 처리한다. */
.pp-ai-action-card {
    border-left: 3px solid var(--pp-primary-strong);
}
.pp-ai-action-title {
    font-weight: 600;
    font-size: 0.78rem;
    color: var(--pp-primary-strong);
    margin-bottom: 4px;
}
/* 해소 상태(실행/취소 후): 카드 톤다운 — 버튼은 disabled 로 이미 잠김(슬롯 1회성) */
.pp-ai-action-approved,
.pp-ai-action-cancelled {
    opacity: 0.72;
}

/* === pp-99-mobile-overflow.css === */
/* ============================================================
 * Narrow viewport overflow guardrails
 * Loaded after component parts so page-specific desktop widths
 * can stay intact while smaller screens avoid body-level x-scroll.
 * ============================================================ */

@media (min-width: 576px) and (max-width: 991.98px) {
    nav.navbar.pp-topnav {
        gap: 6px !important;
        overflow: hidden !important;
    }

    #nav.navbar-top-links.pp-nav-left {
        min-width: 0 !important;
        flex: 1 1 auto !important;
        overflow: hidden !important;
    }

    #nav-domain-search {
        min-width: 0 !important;
        max-width: none !important;
        flex: 1 1 auto !important;
    }

    #nav-domain-search .nav-domain-search-hint,
    #nav-domain-search .nav-domain-search-kbd {
        display: none !important;
    }

    .pp-top-toolbar {
        flex: 0 0 auto !important;
        max-width: 184px !important;
        gap: 4px !important;
        overflow: hidden !important;
    }

    .pp-top-toolbar .pp-tb-btn-action {
        display: none !important;
    }

    .pp-top-toolbar .pp-tb-btn-live {
        width: 36px !important;
        padding: 0 !important;
    }

    .pp-top-toolbar .pp-tb-live-text {
        display: none !important;
    }

    #page-wrapper .pp-page-header-row {
        align-items: flex-start !important;
        gap: 12px !important;
        flex-wrap: wrap !important;
    }

    #page-wrapper .pp-page-header-left,
    #page-wrapper .pp-page-header-right {
        flex: 1 1 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .pp-page-header-right {
        justify-content: flex-start !important;
        flex-wrap: wrap !important;
    }

    #page-wrapper .pp-page-header-right .form-inline {
        display: flex !important;
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
        flex-wrap: wrap !important;
    }

    #page-wrapper .pp-page-header-right .form-inline > * {
        min-width: 0 !important;
    }

    #page-wrapper .pp-page-header-right input.form-control,
    #page-wrapper .pp-page-header-right select.form-control {
        width: auto !important;
        max-width: 100% !important;
        min-width: 0 !important;
        flex: 1 1 180px !important;
    }

    #page-wrapper .pp-page-header-right .btn-group {
        max-width: 100% !important;
        flex: 0 1 auto !important;
    }

    #page-wrapper .tag-search-form,
    #page-wrapper .tag-search-row {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .tag-search-row {
        gap: 8px !important;
    }

    #page-wrapper .tag-search-row .tag-search-field {
        flex: 1 1 180px !important;
        min-width: 0 !important;
        max-width: 100% !important;
    }

    #page-wrapper .tag-search-row .tag-search-field-wide {
        flex: 1 1 100% !important;
    }

    #page-wrapper .tag-search-row .tag-search-field > label.form-label.form-label {
        flex: 0 0 64px !important;
        width: 64px !important;
        padding-right: 6px !important;
    }

    #page-wrapper .tag-search-row .tag-search-field > .form-control {
        min-width: 0 !important;
        max-width: 100% !important;
        width: auto !important;
        flex: 1 1 auto !important;
    }

    #page-wrapper .tag-search-row .alarm-advsearch-desc-input {
        width: auto !important;
        max-width: 100% !important;
    }

    #page-wrapper .tag-search-row .tag-search-actions {
        flex: 1 1 100% !important;
        justify-content: flex-start !important;
        margin-left: 0 !important;
    }

    #page-wrapper .tag-search-row .tag-search-actions .btn {
        min-width: 0 !important;
    }

    #page-wrapper .onto-site-banner {
        position: relative !important;
        z-index: auto !important;
        width: 100% !important;
        max-width: 100% !important;
        margin-left: 0 !important;
        padding: 0 20px 8px !important;
    }

    #page-wrapper .onto-site-banner-inner {
        display: flex !important;
        flex-wrap: wrap !important;
        align-items: center !important;
        gap: 4px 6px !important;
        padding: 6px 0 !important;
        line-height: 1.4 !important;
        white-space: normal !important;
    }

    #page-wrapper .onto-site-banner-inner > strong,
    #page-wrapper .onto-site-banner-inner #site_description,
    #page-wrapper .onto-site-banner-inner .fs-12 {
        min-width: 0 !important;
        overflow-wrap: anywhere !important;
    }

    #page-wrapper .onto-side-floater {
        position: relative !important;
        width: 100% !important;
        max-width: 100% !important;
        margin-left: 0 !important;
        padding: 0 20px !important;
    }

    #page-wrapper .onto-side-floater .row {
        margin-left: 0 !important;
        margin-right: 0 !important;
    }

    #page-wrapper .onto-side-floater [class*="col-"],
    #page-wrapper .onto-tree-canvas {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
        padding-left: 0 !important;
        padding-right: 0 !important;
    }

    #page-wrapper .basedata-tabs {
        display: flex !important;
        flex-wrap: wrap !important;
        gap: 6px !important;
        width: 100% !important;
        max-width: 100% !important;
        overflow: visible !important;
        border-bottom: 0 !important;
    }

    #page-wrapper .basedata-tabs > li {
        float: none !important;
        flex: 0 1 auto !important;
        margin-bottom: 0 !important;
    }

    #page-wrapper .basedata-tabs > li > a {
        white-space: normal !important;
        padding: 8px 10px !important;
        border-radius: 6px !important;
    }

    #page-wrapper .env-view-tabs {
        display: flex !important;
        flex-wrap: wrap !important;
        gap: 6px !important;
        width: 100% !important;
        max-width: 100% !important;
        overflow: visible !important;
        border-bottom: 0 !important;
    }

    #page-wrapper .env-view-tabs > li {
        float: none !important;
        flex: 0 1 auto !important;
        margin-bottom: 0 !important;
    }

    #page-wrapper .env-view-tabs > li > a {
        white-space: normal !important;
        padding: 8px 10px !important;
        border-radius: 6px !important;
    }

    #page-wrapper .env-view-panel-body {
        max-width: 100% !important;
        overflow-x: hidden !important;
    }

    #page-wrapper .env-view-table {
        width: 100% !important;
        min-width: 0 !important;
        max-width: 100% !important;
        table-layout: fixed !important;
    }

    #page-wrapper .env-view-table th,
    #page-wrapper .env-view-table td {
        white-space: normal !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
    }

    #page-wrapper .env-view-table td:first-child {
        width: 42% !important;
        max-width: 42% !important;
    }

    #page-wrapper .ds-row {
        display: block !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-toc,
    #page-wrapper .ds-content {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
        float: none !important;
    }

    #page-wrapper .ds-toc {
        position: static !important;
        max-height: none !important;
        border-right: 0 !important;
        border-bottom: 1px solid var(--pp-border) !important;
        padding: 8px 0 12px !important;
        margin-bottom: 12px !important;
    }

    #page-wrapper .ds-content {
        padding-bottom: 64px !important;
        overflow-x: hidden !important;
    }

    #page-wrapper .ds-content .ds-drawer:not(.show) {
        display: none !important;
    }

    #page-wrapper .ds-content .ds-drawer.show {
        display: flex !important;
        width: min(420px, calc(100vw - var(--pp-sidebar-w-collapsed, 64px) - 24px)) !important;
        max-width: calc(100vw - var(--pp-sidebar-w-collapsed, 64px) - 24px) !important;
    }

    #page-wrapper .ds-content .ds-table-wrapper,
    #page-wrapper .ds-content .table-responsive {
        max-width: 100% !important;
        overflow-x: hidden !important;
    }

    #page-wrapper .ds-content table {
        width: 100% !important;
        max-width: 100% !important;
        table-layout: fixed !important;
    }

    #page-wrapper .ds-content th,
    #page-wrapper .ds-content td {
        width: auto !important;
        max-width: none !important;
        white-space: normal !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
    }

    #page-wrapper .ds-content .CodeMirror,
    #page-wrapper .ds-content .CodeMirror-scroll,
    #page-wrapper .ds-content textarea {
        width: 100% !important;
        max-width: 100% !important;
    }

    #page-wrapper .ds-content .CodeMirror-scroll {
        overflow-x: auto !important;
    }
}

@media (max-width: 575.98px) {
    nav.navbar.pp-topnav {
        padding-left: calc(var(--pp-sidebar-w-collapsed, 64px) + 8px) !important;
        padding-right: 8px !important;
        gap: 4px !important;
        overflow: hidden !important;
    }

    #nav.navbar-top-links.pp-nav-left {
        min-width: 0 !important;
        flex: 1 1 auto !important;
        overflow: hidden !important;
    }

    #nav-toggle {
        flex: 0 0 auto !important;
        margin-left: 0 !important;
    }

    #nav-domain-search {
        min-width: 0 !important;
        max-width: none !important;
        flex: 1 1 44px !important;
        padding: 0 !important;
    }

    #nav-domain-search .nav-domain-search-input {
        min-width: 36px !important;
        justify-content: center !important;
        padding: 0 10px !important;
    }

    #nav-domain-search .nav-domain-search-label,
    #nav-domain-search .nav-domain-search-hint,
    #nav-domain-search .nav-domain-search-kbd {
        display: none !important;
    }

    .pp-top-toolbar {
        flex: 0 0 auto !important;
        max-width: 108px !important;
        gap: 2px !important;
        overflow: hidden !important;
    }

    .pp-top-toolbar .pp-tb-btn {
        width: 32px !important;
        height: 32px !important;
    }

    .pp-top-toolbar .pp-tb-btn-live {
        width: 32px !important;
        padding: 0 !important;
    }

    .pp-top-toolbar .pp-tb-live-text,
    .pp-top-toolbar .pp-tb-btn-action {
        display: none !important;
    }

    .pp-top-toolbar .pp-tb-popover.dropdown-menu {
        position: fixed !important;
        top: calc(var(--pp-topbar-h, 64px) - 8px) !important;
        right: 12px !important;
        left: auto !important;
        width: min(320px, calc(100vw - 24px)) !important;
        min-width: min(320px, calc(100vw - 24px)) !important;
        max-width: calc(100vw - 24px) !important;
        margin-top: 0 !important;
        transform: none !important;
    }

    #page-wrapper .onto-site-banner {
        position: relative !important;
        z-index: auto !important;
        width: 100% !important;
        max-width: 100% !important;
        margin-left: 0 !important;
        padding: 0 16px 8px !important;
    }

    #page-wrapper .onto-site-banner-inner {
        display: flex !important;
        flex-wrap: wrap !important;
        align-items: center !important;
        gap: 4px 6px !important;
        padding: 6px 0 !important;
        line-height: 1.4 !important;
        white-space: normal !important;
    }

    #page-wrapper .onto-site-banner-inner > strong,
    #page-wrapper .onto-site-banner-inner #site_description,
    #page-wrapper .onto-site-banner-inner .fs-12 {
        min-width: 0 !important;
        overflow-wrap: anywhere !important;
    }

    #page-wrapper .onto-site-banner-inner .fs-12 {
        flex: 1 1 100% !important;
    }

    #page-wrapper .onto-side-floater {
        position: relative !important;
        width: 100% !important;
        max-width: 100% !important;
        margin-left: 0 !important;
        padding: 0 16px !important;
    }

    #page-wrapper .onto-side-floater .row {
        margin-left: 0 !important;
        margin-right: 0 !important;
    }

    #page-wrapper .onto-side-floater [class*="col-"],
    #page-wrapper .onto-tree-canvas {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
        padding-left: 0 !important;
        padding-right: 0 !important;
    }

    #page-wrapper .basedata-tabs {
        display: flex !important;
        flex-wrap: wrap !important;
        gap: 6px !important;
        width: 100% !important;
        max-width: 100% !important;
        overflow: visible !important;
        border-bottom: 0 !important;
    }

    #page-wrapper .basedata-tabs > li {
        float: none !important;
        flex: 0 1 auto !important;
        margin-bottom: 0 !important;
    }

    #page-wrapper .basedata-tabs > li > a {
        white-space: normal !important;
        padding: 8px 10px !important;
        border-radius: 6px !important;
    }

    #page-wrapper .env-view-tabs {
        display: flex !important;
        flex-wrap: wrap !important;
        gap: 6px !important;
        width: 100% !important;
        max-width: 100% !important;
        overflow: visible !important;
        border-bottom: 0 !important;
    }

    #page-wrapper .env-view-tabs > li {
        float: none !important;
        flex: 0 1 auto !important;
        margin-bottom: 0 !important;
    }

    #page-wrapper .env-view-tabs > li > a {
        white-space: normal !important;
        padding: 8px 10px !important;
        border-radius: 6px !important;
    }

    #page-wrapper .tag-search-form,
    #page-wrapper .tag-search-row {
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .tag-search-row .tag-search-field {
        flex: 1 1 160px !important;
        min-width: 0 !important;
        max-width: 100% !important;
    }

    #page-wrapper .tag-search-row .tag-search-field-wide {
        flex-basis: 100% !important;
    }

    #page-wrapper .tag-search-row .tag-search-field > label.form-label.form-label {
        flex: 0 0 64px !important;
        width: 64px !important;
        padding-right: 6px !important;
    }

    #page-wrapper .tag-search-row .tag-search-field > .form-control {
        min-width: 0 !important;
        max-width: 100% !important;
        width: auto !important;
        flex: 1 1 auto !important;
    }

    #page-wrapper .tag-search-row .alarm-advsearch-desc-input {
        width: auto !important;
        max-width: 100% !important;
    }

    #page-wrapper .tag-search-row .tag-search-actions {
        flex: 1 1 100% !important;
        justify-content: flex-start !important;
        margin-left: 0 !important;
    }

    #page-wrapper .tag-search-row .tag-search-actions .btn {
        min-width: 0 !important;
    }

    #page-wrapper .model-tree-pane {
        max-width: 100% !important;
        overflow-x: auto !important;
        overflow-y: auto !important;
    }

    #page-wrapper .model-tree-pane #assetTreeDiv,
    #page-wrapper .model-tree-pane #opcTreeDiv {
        min-width: 0 !important;
        max-width: 100% !important;
    }

    #page-wrapper .model-tree-pane .jstree-anchor {
        max-width: calc(100vw - 156px) !important;
        overflow: hidden !important;
        text-overflow: ellipsis !important;
        vertical-align: top !important;
    }

    #page-wrapper .card-body > .form-inline,
    #page-wrapper .card-body > .pp-form-row {
        display: flex !important;
        flex-wrap: wrap !important;
        gap: 8px !important;
        max-width: 100% !important;
        min-width: 0 !important;
        align-items: center !important;
    }

    #page-wrapper .card-body > .form-inline > *,
    #page-wrapper .card-body > .pp-form-row > * {
        min-width: 0 !important;
    }

    #page-wrapper .card-body > .form-inline .form-control,
    #page-wrapper .card-body > .pp-form-row .form-control {
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .card-body > .form-inline .search-input-340,
    #page-wrapper .card-body > .pp-form-row .search-input-340 {
        width: auto !important;
        flex: 1 1 180px !important;
    }

    #page-wrapper .card-body > .form-inline .btn-group,
    #page-wrapper .card-body > .pp-form-row .btn-group {
        flex: 1 1 100% !important;
        justify-content: flex-start !important;
    }

    #page-wrapper .env-view-panel-body {
        max-width: 100% !important;
        overflow-x: hidden !important;
    }

    #page-wrapper .env-view-table {
        width: 100% !important;
        min-width: 0 !important;
        max-width: 100% !important;
        table-layout: fixed !important;
    }

    #page-wrapper .env-view-table th,
    #page-wrapper .env-view-table td {
        white-space: normal !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
    }

    #page-wrapper .env-view-table td:first-child {
        width: 42% !important;
        max-width: 42% !important;
    }

    #page-wrapper .ds-row {
        display: block !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-toc,
    #page-wrapper .ds-content {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
        float: none !important;
    }

    #page-wrapper .ds-toc {
        position: static !important;
        max-height: none !important;
        border-right: 0 !important;
        border-bottom: 1px solid var(--pp-border) !important;
        padding: 8px 0 12px !important;
        margin-bottom: 12px !important;
    }

    #page-wrapper .ds-content {
        padding-bottom: 48px !important;
        overflow-x: hidden !important;
    }

    #page-wrapper .ds-content .ds-code,
    #page-wrapper .ds-content .ds-codeblock,
    #page-wrapper .ds-content .ds-code-block-body {
        max-width: 100% !important;
        white-space: pre-wrap !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
        overflow-x: hidden !important;
    }

    #page-wrapper .ds-content .ds-code code,
    #page-wrapper .ds-content .ds-codeblock code,
    #page-wrapper .ds-content .ds-code-block-body code {
        white-space: inherit !important;
        overflow-wrap: anywhere !important;
        word-break: inherit !important;
    }

    #page-wrapper .ds-content :not(pre) > code {
        white-space: normal !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
    }

    #page-wrapper .ds-content .card-header {
        flex-wrap: wrap !important;
        gap: 8px !important;
        min-width: 0 !important;
        white-space: normal !important;
    }

    #page-wrapper .ds-content .card-header > .card-head-block {
        flex: 1 1 100% !important;
        min-width: 0 !important;
        white-space: normal !important;
    }

    #page-wrapper .ds-content .card-head-title,
    #page-wrapper .ds-content .card-head-sub {
        white-space: normal !important;
        overflow-wrap: anywhere !important;
    }

    #page-wrapper .ds-content .card-header > .card-head-actions,
    #page-wrapper .ds-content .card-head-actions.float-end {
        float: none !important;
        flex: 1 1 100% !important;
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
        margin-left: 0 !important;
        justify-content: flex-start !important;
        white-space: normal !important;
    }

    #page-wrapper .ds-content .card-head-actions > * {
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .card-head-actions > select.form-control,
    #page-wrapper .ds-content .card-head-actions > input.form-control,
    #page-wrapper .ds-content .card-head-actions > .input-group,
    #page-wrapper .ds-content .card-head-actions > .btn-group,
    #page-wrapper .ds-content .card-head-actions > .ph-field {
        flex: 1 1 126px !important;
        max-width: 100% !important;
    }

    #page-wrapper .ds-content .card-head-actions .form-control,
    #page-wrapper .ds-content .card-head-actions .btn {
        max-width: 100% !important;
    }

    #page-wrapper .ds-content .card-head-actions .ph-field {
        flex-wrap: wrap !important;
        height: auto !important;
        line-height: 1.4 !important;
    }

    #page-wrapper .ds-content .card-head-actions .ph-field > label {
        flex: 0 0 auto !important;
        height: auto !important;
        line-height: 1.4 !important;
    }

    #page-wrapper .ds-content .card-head-actions .ph-field > select.form-control,
    #page-wrapper .ds-content .card-head-actions .ph-field > input.form-control {
        flex: 1 1 78px !important;
        min-width: 0 !important;
        max-width: 100% !important;
    }

    #page-wrapper .ds-content .card-head-actions .ph-sep {
        display: none !important;
    }

    #page-wrapper .ds-content .stat-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .stat-box {
        min-width: 0 !important;
        max-width: 100% !important;
        overflow-wrap: anywhere !important;
    }

    #page-wrapper .ds-content .stat-box .stat-lbl,
    #page-wrapper .ds-content .stat-box .stat-num {
        white-space: normal !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
    }

    #page-wrapper .ds-content input.col-w-300,
    #page-wrapper .ds-content input.col-w-340,
    #page-wrapper .ds-content input.col-w-400,
    #page-wrapper .ds-content select.col-w-300,
    #page-wrapper .ds-content select.col-w-340,
    #page-wrapper .ds-content select.col-w-400,
    #page-wrapper .ds-content textarea.col-w-300,
    #page-wrapper .ds-content textarea.col-w-400,
    #page-wrapper .ds-content .input-group.col-w-300,
    #page-wrapper .ds-content .input-group.col-w-340,
    #page-wrapper .ds-content .input-group.col-w-400 {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .select2-container {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .select2-selection,
    #page-wrapper .ds-content .select2-selection__rendered,
    #page-wrapper .ds-content .select2-selection__choice {
        max-width: 100% !important;
    }

    #page-wrapper .ds-content .select2-selection--multiple .select2-search--inline,
    #page-wrapper .ds-content .select2-selection--multiple .select2-search__field {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .card-body > .input-group {
        display: flex !important;
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .card-body > .input-group > .form-control {
        width: auto !important;
        min-width: 0 !important;
        flex: 1 1 auto !important;
    }

    #page-wrapper .ds-content .card-body > .input-group > .input-group-text {
        display: inline-flex !important;
        align-items: center !important;
        flex: 0 0 auto !important;
    }

    #page-wrapper .ds-content #sec-toolbar > div[style*="width:420px"] {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content #sec-toolbar .input-group,
    #page-wrapper .ds-content #sec-toolbar .ds-search-results {
        width: 100% !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content #sec-toolbar .ds-search-item,
    #page-wrapper .ds-content #sec-toolbar .ds-search-item-body,
    #page-wrapper .ds-content #sec-toolbar .ds-search-item-title,
    #page-wrapper .ds-content #sec-toolbar .ds-search-item-meta {
        min-width: 0 !important;
        max-width: 100% !important;
        overflow-wrap: anywhere !important;
    }

    #page-wrapper .ds-content .ds-stb-row {
        flex-wrap: wrap !important;
        gap: 4px !important;
    }

    #page-wrapper .ds-content .ds-stb-label {
        width: 100% !important;
        max-width: 100% !important;
    }

    #page-wrapper .ds-content .ds-stb-track {
        flex: 1 1 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .ds-stb-axis {
        padding-left: 0 !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .ds-stb-axis > span {
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .ds-stl {
        flex-wrap: wrap !important;
        row-gap: 8px !important;
    }

    #page-wrapper .ds-content .ds-stl-step {
        width: auto !important;
        flex: 1 1 calc(50% - 8px) !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .ds-stl-line {
        display: none !important;
    }

    #page-wrapper .ds-content .ds-bulk-bar,
    #page-wrapper .ds-content .ds-bulk-bar-actions,
    #page-wrapper .ds-content .form-content-footer {
        flex-wrap: wrap !important;
        max-width: 100% !important;
        min-width: 0 !important;
    }

    #page-wrapper .ds-content .pp-top-toolbar .pp-tb-popover {
        width: min(320px, calc(100vw - var(--pp-sidebar-w-collapsed, 64px) - 16px)) !important;
        min-width: 0 !important;
        max-width: calc(100vw - var(--pp-sidebar-w-collapsed, 64px) - 16px) !important;
    }

    #page-wrapper .ds-content .ds-drawer:not(.show) {
        display: none !important;
    }

    #page-wrapper .ds-content .ds-drawer.show {
        display: flex !important;
        width: min(320px, calc(100vw - var(--pp-sidebar-w-collapsed, 64px) - 16px)) !important;
        max-width: calc(100vw - var(--pp-sidebar-w-collapsed, 64px) - 16px) !important;
    }

    #page-wrapper .ds-content .ds-table-wrapper,
    #page-wrapper .ds-content .table-responsive {
        max-width: 100% !important;
        overflow-x: hidden !important;
    }

    #page-wrapper .ds-content table {
        width: 100% !important;
        max-width: 100% !important;
        table-layout: fixed !important;
    }

    #page-wrapper .ds-content th,
    #page-wrapper .ds-content td {
        width: auto !important;
        max-width: none !important;
        white-space: normal !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
    }

    #page-wrapper .ds-content .CodeMirror,
    #page-wrapper .ds-content .CodeMirror-scroll,
    #page-wrapper .ds-content textarea {
        width: 100% !important;
        max-width: 100% !important;
    }

    #page-wrapper .ds-content .CodeMirror-scroll {
        overflow-x: auto !important;
    }
}

