/* =============================================================================
   Orbrium — Project-specific CSS overrides
   ============================================================================= */

/* Prevent layout shift from scrollbar appearing/disappearing */
.content-scroll { scrollbar-gutter: stable; }

/* Utility — spin animation */
.spin { display: inline-block; animation: orbrium-spin 1s linear infinite; }
@keyframes orbrium-spin { to { transform: rotate(360deg); } }

/* -----------------------------------------------------------------------------
   Navbar Input Group (solid color)
   PUI input-group 기본 스타일은 rgba/transparent 기반이라
   navbar(primary 배경) 위에서는 색상이 묻힘.
   color-mix로 solid 색상을 직접 계산하여 배경과 무관하게 동일한 시각 결과를 보장.
   사용: <div class="input-group navbar-input-group ...">
   ----------------------------------------------------------------------------- */

/* Light mode */
.input-group.navbar-input-group > .input-group-text {
    background-color: color-mix(in srgb, rgb(var(--pui-input-group-color-rgb)) 20%, white) !important;
    color: rgb(var(--pui-input-group-color-rgb)) !important;
    border-color: rgb(var(--pui-input-group-color-rgb)) !important;
}

/* Dark mode */
[data-bs-theme=dark] .input-group.navbar-input-group > .input-group-text {
    background-color: color-mix(in srgb, rgb(var(--pui-input-group-color-rgb)) 15%, black) !important;
    color: color-mix(in srgb, rgb(var(--pui-input-group-color-rgb)) 80%, white 20%) !important;
    border-color: color-mix(in srgb, rgb(var(--pui-input-group-color-rgb)) 90%, white 10%) !important;
}

/* navbar-main overflow — 수평 넘침 방지 + 드롭다운 수직 표시 허용 */
.navbar-main { overflow-x: clip; overflow-y: visible; }

/* -----------------------------------------------------------------------------
   Navbar Project Buttons
   ----------------------------------------------------------------------------- */
/* FloatPage backdrop: input-group 자식 z-index 리셋 (Bootstrap z:2 → ::after z:1 위로 뜨는 문제) */
body:has(.float-page-global-backdrop.show) .navbar-main .navbar-input-group * {
    z-index: auto !important;
}

/* -----------------------------------------------------------------------------
   Navbar Shortcut Bar — MRU resource shortcuts
   ----------------------------------------------------------------------------- */
.navbar-shortcut-bar {
    display: flex;
    align-items: stretch;
    gap: 0.5rem;
    height: calc(1.5em + 0.5rem + calc(var(--bs-border-width, 1px) * 2));
    font-size: 0.875rem;
    margin: 0 0.5rem;
    overflow: hidden;
    flex-shrink: 1;
    min-width: 0;
}
.navbar-shortcut {
    --_sc-pad: 0.1875rem;
    display: flex;
    align-items: center;
    gap: 0.375rem;
    max-width: 8rem;
    flex-shrink: 0;
    padding: var(--_sc-pad) 0.5rem var(--_sc-pad) var(--_sc-pad);
    border-radius: var(--bs-border-radius-sm);
    cursor: pointer;
    font-size: 0.75rem;
    white-space: nowrap;
    overflow: hidden;
    background: var(--bs-body-bg);
    color: var(--bs-primary);
}
[data-bs-theme=dark] .navbar-shortcut {
    color: rgb(var(--pui-text-light));
}
.navbar-shortcut > i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: calc(var(--bs-border-radius-sm) * 0.7);
    background: var(--bs-primary);
    color: rgb(var(--pui-text-light));
    font-size: 0.6875rem;
    flex-shrink: 0;
}
.navbar-shortcut-label { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* -----------------------------------------------------------------------------
   PUIFloatPage footer — detach a button from the btn-group.
   PUI renders all buttons inside a single .btn-group (pui.overpage.js:_createButtons).
   Passing { class: 'btn-detached' } on a button pushes it to the right and
   restores its own rounded corners — visually splits the footer into
   [group] ... [detached].
   ----------------------------------------------------------------------------- */
.btn-group > .btn.btn-detached {
    /* Bootstrap's own `.btn-group > :not(.btn-check:first-child) + .btn`
       rule applies `margin-left: calc(var(--bs-border-width) * -1)` to
       collapse borders — that wins over plain margin-left declarations,
       so !important is needed to assert the explicit gap. 0.5rem matches
       the sibling .gap-2 rhythm used elsewhere in the footer. */
    margin-left: 0.5rem !important;
    border-top-left-radius: var(--bs-btn-border-radius) !important;
    border-bottom-left-radius: var(--bs-btn-border-radius) !important;
}
.btn-group > .btn:has(+ .btn-detached) {
    border-top-right-radius: var(--bs-btn-border-radius) !important;
    border-bottom-right-radius: var(--bs-btn-border-radius) !important;
}

/* -----------------------------------------------------------------------------
   Home — Card visual tokens (Announcements / Tickets / Memos / +N / Add)
   Abstracts inline Bootstrap utils (position-relative p-3) into semantic classes
   so all four card variants share one source of truth for padding & height.
   ----------------------------------------------------------------------------- */
.home-card      { min-height: 4.75rem; }
.home-card-body { position: relative; padding: 1rem; }

/* Severity-tier emphasis — border color + subtle glow; hover intensifies it.
   warning: ticket priority 2 (Normal), memo priority 'warning' (Share).
   danger:  announcement urgent, ticket priority 3 (High), memo priority 'danger' (Notice). */
.home-card.home-card-warning {
    border-color: var(--bs-warning);
    box-shadow: 0 0 0.75rem color-mix(in srgb, var(--bs-warning) 40%, transparent);
}
.home-card.home-card-warning:hover {
    box-shadow: 0 0 1rem color-mix(in srgb, var(--bs-warning) 55%, transparent);
}
.home-card.home-card-danger {
    border-color: var(--bs-danger);
    box-shadow: 0 0 0.75rem color-mix(in srgb, var(--bs-danger) 40%, transparent);
}
.home-card.home-card-danger:hover {
    box-shadow: 0 0 1rem color-mix(in srgb, var(--bs-danger) 55%, transparent);
}

/* Add-card placeholder (dashed border, no shadow). Relies on .home-card for
   min-height so its slot height stays in sync with the regular cards. */
.home-add-card {
    border: 1px dashed var(--bs-border-color);
    background: transparent;
    box-shadow: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Compact overflow row — when hidden cards exist AND an add-card is provided,
   the last slot splits into [small +N box | add-card (fills remainder)].
   Slot height stays 4.75rem to match .home-card. */
.home-card-row {
    display: flex;
    gap: 0.5rem;
    min-height: 4.75rem;
    align-items: stretch;
}
.home-card-row > .home-add-card { flex: 1; min-width: 0; }

/* Small +N box — fixed square-ish width, reduced padding (doesn't use
   .home-card-body so padding can shrink without affecting other slots). */
.home-card-more { flex: 0 0 auto; min-width: 4.75rem; }
.home-card-more > .card-body {
    padding: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* -----------------------------------------------------------------------------
   Memo overflow board — "post-it" feel for the +N dialog.
   Square cells tinted by memo priority (1=info / 2=warning / 3=danger), with
   subtle rotation. Colors use theme system vars so light/dark both adapt.
   ----------------------------------------------------------------------------- */
:root {
    --orb-sticky-tint-warning: color-mix(in srgb, var(--bs-warning) 22%, var(--bs-body-bg));
    --orb-sticky-tint-danger:  color-mix(in srgb, var(--bs-danger)  22%, var(--bs-body-bg));
}
.home-memo-board {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1rem;
    padding: 0.5rem;
}
.home-memo-board > .card {
    aspect-ratio: 1 / 1;
    box-shadow: 0.125rem 0.25rem 0.5rem rgba(0, 0, 0, 0.15);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    overflow: hidden;
}
/* Priority → background tint (value is the Bootstrap color token string) */
/* info priority keeps the default card background — only warning/danger get tint. */
.home-memo-board > .card[data-priority="warning"] { background: var(--orb-sticky-tint-warning); }
.home-memo-board > .card[data-priority="danger"]  { background: var(--orb-sticky-tint-danger); }
/* nth-child → subtle rotation variation across 7 slots (more organic repeat) */
.home-memo-board > .card:nth-child(7n+1) { transform: rotate(-1.5deg); }
.home-memo-board > .card:nth-child(7n+2) { transform: rotate( 1.2deg); }
.home-memo-board > .card:nth-child(7n+3) { transform: rotate( 0.6deg); }
.home-memo-board > .card:nth-child(7n+4) { transform: rotate(-0.8deg); }
.home-memo-board > .card:nth-child(7n+5) { transform: rotate( 1.4deg); }
.home-memo-board > .card:nth-child(7n+6) { transform: rotate(-1.0deg); }
.home-memo-board > .card:nth-child(7n+7) { transform: rotate( 0.3deg); }
.home-memo-board > .card:hover {
    transform: rotate(0) scale(1.03);
    box-shadow: 0.25rem 0.5rem 1rem rgba(0, 0, 0, 0.2);
    z-index: 1;
}
/* Post-it body: title + multi-line clamped preview + owner tag */
.home-memo-board .memo-sticky-body {
    padding: 0.75rem;
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.home-memo-board .memo-sticky-title {
    font-weight: 600;
    font-size: 0.875rem;
    line-height: 1.25;
}
.home-memo-board .memo-sticky-preview {
    flex: 1 1 auto;
    min-height: 0;
    font-size: 0.75rem;
    line-height: 1.3;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 5;
    -webkit-box-orient: vertical;
    white-space: pre-wrap;
    word-break: break-word;
    opacity: 0.8;
}
.home-memo-board .memo-sticky-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.7rem;
    opacity: 0.85;
}

/* Memo editor — title + priority dropdown side-by-side (revived from prior
   size-UI layout but re-purposed for priority). */
.memo-editor-header {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.memo-editor-header .memo-col-title    { flex: 4 1 0; min-width: 10rem; }
.memo-editor-header .memo-col-priority { flex: 1 1 0; min-width: 7rem; }

/* Memo header + button */
.home-memo-add-btn {
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--bs-border-radius);
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
    cursor: pointer;
    color: inherit;
}
.home-memo-add-btn:hover {
    border-color: var(--bs-secondary);
}
.home-memo-add-btn:active {
    color: var(--bs-primary);
    border-color: var(--bs-primary);
    background: transparent;
}

/* -----------------------------------------------------------------------------
   Home — Top section (Donuts + Stat Cards)
   ≤120rem: stats drop below donuts (same timing as catalog reflow)
   ----------------------------------------------------------------------------- */
.home-top {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    align-items: flex-start;
}

@container (max-width: 120rem) {
    .home-top-stats {
        flex: 0 0 100%;
        justify-content: center;
    }
}

/* Home — Chart area (nested donuts + gauges + count card) */
.home-chart-area {
    width: 35rem;
    height: 17.5rem;
    position: relative;
    flex-shrink: 0;
}
.home-chart-donut {
    position: absolute;
    left: 0;
    top: 0;
    width: 17.5rem;
    height: 17.5rem;
    z-index: 1;
}
.home-chart-donut-outer { position: absolute; inset: 0; overflow: hidden; }
.home-chart-donut-inner {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 11rem; height: 11rem;
    overflow: hidden;
    pointer-events: none;
}
/* Inner donut arcs receive pointer events (outer donut hover passes through empty space) */
.home-chart-donut-inner path { pointer-events: auto; }
.home-chart-gauges {
    position: absolute;
    left: 17.5rem;
    right: 0;
    top: 2.1rem;
    bottom: calc(50% + 1.5rem + 0.5rem);
    z-index: 1;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 0.5rem;
}
.home-chart-gauge { width: 8rem; height: 4rem; }
.home-chart-gauge-label { font-size: 0.625rem; margin-top: -0.25rem; }
/* Chart info bars — independent from .card to avoid border-radius conflicts */
.total-chart-bar {
    position: absolute;
    right: 0;
    z-index: 0;
    height: 3rem;
    color: var(--bs-body-color);
    background-color: var(--bs-card-bg, var(--bs-body-bg));
    border: var(--bs-card-border-width, var(--bs-border-width)) solid var(--bs-card-border-color, var(--bs-border-color-translucent));
    border-radius: 24px;
}
.total-chart-bar-count {
    left: 7.25rem;
    top: 50%;
    transform: translateY(-50%);
}
.total-chart-bar-count .bi { font-size: 2em; }
.total-chart-bar-cost {
    left: 16rem;
    top: calc(50% + 2rem);
}
/* Chart bar — shared label/number/separator styles */
.total-chart-bar .chart-bar-num { font-size: 1.5rem; font-weight: bold; color: var(--bs-primary); }
.total-chart-bar .chart-bar-sub { font-size: 1.1rem; font-weight: bold; color: var(--bs-primary); }
.total-chart-bar .chart-bar-success { color: var(--bs-success); }
.total-chart-bar small.text-nowrap { font-size: 0.85em; color: var(--bs-secondary-color); }
.total-chart-bar .chart-bar-sep { font-size: 0.85em; opacity: 0.4; }
[data-bs-theme="dark"] .total-chart-bar .chart-bar-num { color: rgba(var(--pui-info), 0.9); }
[data-bs-theme="dark"] .total-chart-bar .chart-bar-sub { color: rgba(var(--pui-info), 0.9); }
[data-bs-theme="dark"] .total-chart-bar .chart-bar-success { color: rgba(var(--pui-success), 1); }

/* Shared — watermark overlay content layer */
.wm-content { position: relative; z-index: 1; }

/* Shared — empty state placeholder icon */
.home-empty-icon { font-size: 2rem; }

/* Shared — small label text */
.fs-label { font-size: 0.8125rem; }

/* Resource stat cards — used by cloud.js, vm.js, subnet.js */
.res-stat-main { cursor: pointer; overflow: hidden; width: 15rem; aspect-ratio: 1/1; flex-shrink: 0; }
.res-stat-count { font-size: 5rem; }
.res-stat-mini { cursor: pointer; overflow: hidden; width: 15rem; flex: 1; min-height: 0; }
.res-stat-mini-val { font-size: 1.5rem; }
.res-stat-mini-stack { display: flex; flex-direction: column; gap: 0.5rem; flex-shrink: 0; height: 15rem; }

/* Resource top N panels — used by vm.js, subnet.js */
.res-top-panel { width: 15rem; height: 15rem; flex-shrink: 0; overflow: hidden; }
.res-top-panel-wide { width: 30rem; height: 15rem; flex-shrink: 0; overflow: hidden; }
.res-top-list { position: relative; z-index: 1; flex: 1; display: flex; flex-direction: column; justify-content: flex-start; gap: 0.1875rem; }
.res-top-row { display: flex; align-items: center; gap: 0.25rem; cursor: pointer; }
.res-top-row:hover { color: var(--bs-primary); text-decoration: underline; }
[data-bs-theme="dark"] .res-top-row:hover { color: rgba(var(--pui-info), 0.9); }
.res-top-name { flex: 1; min-width: 0; font-size: 0.75rem; }
.res-top-val { width: 2.5rem; flex-shrink: 0; text-align: right; font-size: 0.75rem; }
.res-top-bar { width: 15rem; flex-shrink: 0; height: 0.25rem; border-radius: 0.125rem; background: var(--bs-border-color); overflow: hidden; }

/* Resource type page layout — used by cloud.js, vm.js, subnet.js */
.res-type-layout { display: flex; flex-wrap: wrap-reverse; justify-content: space-between; gap: 0.75rem; margin-bottom: 1rem; }
.res-type-group { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* Stat card layout */
.home-stat-card { height: calc((17.5rem - 1rem) / 2); }
.home-stat-card .card { overflow: hidden; cursor: pointer; }
.home-stat-count { font-size: 3rem; }
.home-stat-inner { gap: 0.5rem; }
.home-stat-left { z-index: 1; min-width: 8rem; flex-shrink: 0; }
.home-stat-solo { z-index: 1; }

/* Stat card Top 5 */
.home-stat-top5 {
    z-index: 1; flex: 1; min-width: 0; gap: 0.15rem;
    container: stat-top5 / inline-size;
}
.home-stat-top5-row { font-size: 0.75rem; gap: 0.25rem; }
.home-stat-top5-name { flex: 1; min-width: 0; }
.home-stat-top5-bar { flex: 1; min-width: 2rem; height: 4px; }
.home-stat-top5-val { min-width: 2.2rem; flex-shrink: 0; text-align: right; white-space: nowrap; }
@container stat-top5 (max-width: 10rem) {
    .home-stat-top5-bar { display: none; }
}

/* -----------------------------------------------------------------------------
   Home — Bottom section responsive layout
   Wide:   [Announce 20rem] [Tickets 20rem] [Memo 20rem] [Catalog rest]
   Medium: [Announce 33%] [Tickets 33%] [Memo 33%] / [Catalog 100%]
   Small:  all 100% stacked (Catalog last, natural order) — 62rem ≈ Bootstrap lg
   ----------------------------------------------------------------------------- */
.home-bottom {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: flex-start;
}
.home-col-announce { width: 20rem; min-width: 0; }
.home-col-tickets  { width: 20rem; min-width: 0; }
.home-col-memos    { width: 20rem; min-width: 0; }
.home-col-catalogs { flex: 1; min-width: 0; }

/* Medium — announce+tickets+memos split evenly, catalog wraps to its own row below */
@container (max-width: 120rem) {
    .home-col-catalogs {
        flex: 0 0 100%;
    }
    .home-col-announce,
    .home-col-tickets,
    .home-col-memos {
        width: auto;
        flex: 1 1 0;
    }
}

/* Small — all stacked (Bootstrap lg boundary: 62rem ≈ 992px) */
@container (max-width: 62rem) {
    .home-col-announce,
    .home-col-tickets,
    .home-col-memos {
        flex: 0 0 100%;
    }
}

/* -----------------------------------------------------------------------------
   Home — Catalog grid (balanced rows via JS)
   ----------------------------------------------------------------------------- */
.home-catalog-grid {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fill, 15rem);
}

/* Catalog centered only when stacked above announce+memo */
@container (max-width: 120rem) {
    .home-catalog-grid {
        justify-content: center;
    }
}

/* -----------------------------------------------------------------------------
   Home — Empty (No Project) centered layout
   ----------------------------------------------------------------------------- */
.home-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 60vh;
}
.home-empty:has(.home-empty-memos) {
    flex-direction: row;
    align-items: flex-start;
    gap: 3rem;
}
.home-empty-create {
    display: inline-flex;
    align-items: center;
    padding: 1rem 3rem;
    font-size: 1.25rem;
    font-weight: 500;
    border: 2px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    background: transparent;
    color: inherit;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
    margin-bottom: 2.5rem;
}
.home-empty-create:hover {
    border-color: var(--bs-primary);
    color: var(--bs-primary);
}
.home-empty-announce, .home-empty-memos {
    width: 100%;
    max-width: 40rem;
}

/* -----------------------------------------------------------------------------
   Catalog Icon (brand-logo 기반, 크기 커스텀 가능)
   ----------------------------------------------------------------------------- */
.catalog-icon {
    object-fit: contain;
    filter: none;
    background-color: #fff;
    padding: 0.15rem;
    border-radius: var(--bs-border-radius-sm);
}

/* Catalog Card — hover gradient from bottom */
.catalog-card {
    position: relative;
    cursor: pointer;
}
.catalog-card::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, var(--catalog-accent) 0%, transparent 60%);
    opacity: 0;
    transition: opacity 0.3s ease;
    pointer-events: none;
    z-index: 0;
}
.catalog-card:hover::after {
    opacity: 0.25;
}

/* -----------------------------------------------------------------------------
   Power State LED Indicator (orb-power)
   ----------------------------------------------------------------------------- */
.orb-power {
    display: inline-block;
    width: 0.75rem;
    height: 0.75rem;
    border-radius: 50%;
    vertical-align: middle;
}
.orb-power.on {
    background-color: var(--bs-success);
    color: var(--bs-success);
    box-shadow: 0 0 5px;
    animation: orb-power-blink 3s infinite;
}
.orb-power.off {
    background-color: var(--bs-danger);
    color: var(--bs-danger);
    box-shadow: 0 0 5px;
}
.orb-power.suspend {
    background-color: var(--bs-warning);
    color: var(--bs-warning);
    box-shadow: 0 0 5px;
}
.orb-power.unknown {
    background-color: var(--bs-secondary);
    color: var(--bs-secondary);
    box-shadow: 0 0 5px;
}
@keyframes orb-power-blink {
    0%   { box-shadow: 0 0 5px; }
    50%  { box-shadow: 0 0 15px; }
    100% { box-shadow: 0 0 5px; }
}

/* -----------------------------------------------------------------------------
   OIDC Status Tooltip — color-matched, arrow gap
   ----------------------------------------------------------------------------- */
.tooltip-success .tooltip-inner { background-color: var(--bs-success); max-width: none; }
.tooltip-danger .tooltip-inner { background-color: var(--bs-danger); max-width: none; }
.tooltip-warning .tooltip-inner { background-color: var(--bs-warning); color: var(--bs-dark); max-width: none; }
.tooltip-success .tooltip-arrow, .tooltip-danger .tooltip-arrow, .tooltip-warning .tooltip-arrow { display: none; }

/* -----------------------------------------------------------------------------
   Memo Editor
   ----------------------------------------------------------------------------- */
.memo-editor .memo-textarea {
    resize: none;
}

/* -----------------------------------------------------------------------------
   Card Body — remove bottom margin from last child
   ----------------------------------------------------------------------------- */
.card-body > :last-child {
    margin-bottom: 0 !important;
}

/* -----------------------------------------------------------------------------
   Activity Log — Resource Detail leftPage
   Route-map style vertical timeline (newest on top)
   ----------------------------------------------------------------------------- */

/* Split layout */
.activity-log {
    display: flex;
    height: 100%;
    overflow: hidden;
}

/* Left: Timeline (route map) */
.activity-log-timeline {
    width: 15rem;
    flex-shrink: 0;
    overflow-y: auto;
    border-right: 1px solid var(--bs-border-color);
    padding: 1rem 0;
}

/* Right: Detail */
.activity-log-detail {
    flex: 1;
    min-width: 0;
    overflow-y: auto;
    padding: 1rem;
}

/* --- Route map node --- */
.activity-log-node {
    display: flex;
    align-items: flex-start;
    padding: 0 0.75rem 0 0;
    cursor: pointer;
    position: relative;
}
.activity-log-node:hover .activity-log-node-label {
    background: var(--bs-tertiary-bg);
}
.activity-log-node.active .activity-log-node-label {
    background: var(--bs-tertiary-bg);
    font-weight: 600;
}

/* Track column: vertical line + circle */
.activity-log-node-track {
    width: 3.5rem;
    flex-shrink: 0;
    align-self: stretch;
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
}

/* Vertical rail (continuous line through all nodes) */
.activity-log-node-track::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 2px;
    background: var(--bs-border-color);
    transform: translateX(-50%);
}
.activity-log-node:first-child .activity-log-node-track::before { top: 0.625rem; }
.activity-log-node:last-child .activity-log-node-track::before { bottom: calc(100% - 1.625rem - 0.625rem); }

/* Station circle */
.activity-log-node-circle {
    width: 1.625rem;
    height: 1.625rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    position: relative;
    z-index: 1;
    margin-top: 0.625rem;
    font-size: 0.75rem;
    line-height: 1;
    color: #fff;
}
.activity-log-node.active .activity-log-node-circle {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--node-color) 30%, transparent);
}
.activity-log-node-circle.spinning {
    border: none !important;
}
.activity-log-node-circle.spinning::after {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    border: 2px solid transparent;
    border-top-color: rgba(255,255,255,0.85);
    border-right-color: rgba(255,255,255,0.25);
    animation: activity-spin 1s linear infinite;
}
@keyframes activity-spin { to { transform: rotate(360deg); } }

/* Content column */
.activity-log-node-label {
    flex: 1;
    min-width: 0;
    padding: 0.5rem 0.5rem;
    margin: 0.125rem 0;
    border-radius: var(--bs-border-radius);
    transition: background 0.15s ease;
}
.activity-log-node-date {
    font-size: 0.6875rem;
    opacity: 0.5;
    line-height: 1.2;
}
.activity-log-node-name {
    font-size: 0.8125rem;
    margin-top: 0.125rem;
    word-break: break-word;
    line-height: 1.3;
}
.activity-log-node-user {
    font-size: 0.6875rem;
    margin-top: 0.125rem;
}

/* --- Detail panel --- */

/* Detail header */
.activity-log-header {
    padding-bottom: 0.75rem;
    margin-bottom: 0.75rem;
    border-bottom: 1px solid var(--bs-border-color);
}
.activity-log-header-title {
    font-size: 1rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.activity-log-header-badge {
    font-size: 0.6875rem;
    padding: 0.15em 0.5em;
    border-radius: var(--bs-border-radius-sm);
    color: #fff;
    font-weight: 500;
    transition: background 0.3s ease;
}
.activity-log-header-meta {
    font-size: 0.8125rem;
    opacity: 0.7;
    margin-top: 0.375rem;
}
.activity-log-header-id {
    font-size: 0.75rem;
    opacity: 0.4;
    margin-top: 0.125rem;
    font-family: var(--bs-font-monospace);
}

/* Progress */
.activity-log-progress {
    height: 0.25rem;
    border-radius: var(--pui-badge-radius);
}
.activity-log-progress .progress-bar {
    transition: width 0.5s ease, background 0.3s ease;
}

/* Empty state */
.activity-log-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    opacity: 0.5;
    font-size: 0.875rem;
}

/* Events table */
.resource-detail-table .table {
    font-size: 0.8125rem;
}
.resource-detail-table .table th {
    font-weight: 500;
    white-space: nowrap;
}

/* --- PUITab full-height inside leftPage --- */
.activity-log-tab { display: flex; flex-direction: column; height: 100%; }
.activity-log-tab .pui-tab-content { flex: 1; min-height: 0; overflow: hidden; }
.activity-log-tab .pui-tab-pane { height: 100%; }
.activity-log-tab .pui-tab-pane.active { display: flex; flex-direction: column; }

/* --- Approval tab --- */
.approval-tab { overflow-y: auto; height: 100%; padding: 1rem; }
.approval-card { margin-bottom: 1.5rem; padding: 0.75rem 0.75rem 0.75rem 1rem; border-radius: var(--bs-border-radius); background: var(--bs-tertiary-bg); }
.approval-card-header { padding-bottom: 0.75rem; margin-bottom: 0.5rem; border-bottom: 1px solid var(--bs-border-color); }

/* --- Ticket detail — two-column split inside the floatPage body.
   refs : main = 1 : 3 by flex-basis 0 so the widths scale with modal size
   instead of being pinned. min-width:0 lets both columns shrink so their
   inner overflow-auto scroll containers can actually clip and scroll
   (default flex children refuse to shrink below content width). */
.ticket-detail-refs { flex: 1 1 0; min-width: 0; }
.ticket-detail-main { flex: 3 1 0; min-width: 0; }

/* --- Metrics page (rightPage) --- */
/* Resource Top Content (ModelPage topContent) — 3-row stat card layout */
.resource-top-row1 { display: flex; gap: 0.75rem; margin-bottom: 0.75rem; }
.resource-top-left { display: flex; flex-direction: column; gap: 0.75rem; width: 200px; flex-shrink: 0; }
.resource-top-health { width: 100%; aspect-ratio: 1 / 1; }
.resource-top-action { width: 100%; }
.resource-top-action > [data-pui-dropdown]::after { margin-left: auto; }
.resource-top-relation { flex: 1; min-width: 0; align-self: stretch; }
.resource-top-plugin { /* invisible when empty — no padding/margin */ }
.resource-top-metrics { display: flex; flex-direction: column; gap: 0.75rem; padding-bottom: 0.75rem; }
.resource-top-metric-card { width: 100%; height: 200px; cursor: grab; transition: opacity 0.2s; }
.resource-top-metric-card.dragging { opacity: 0.4; }
.resource-top-metric-card:active { cursor: grabbing; }
.resource-top-metric-label { font-size: 0.875rem; font-weight: 600; margin-bottom: 0.375rem; }
.resource-top-metric-chart { height: 140px; }

/* Topology layout — direct child of main-content, fills viewport */
.topology-layout { display: flex; gap: 1rem; flex: 1; min-height: 0; padding: 1rem 0 0.5rem 0.25rem; overflow: hidden; }
.topology-catalogs { flex: 0 0 15rem; min-height: 0; overflow-y: auto; overflow-x: hidden; display: grid; grid-template-columns: 1fr; grid-auto-rows: min-content; gap: 0.75rem; align-content: start; scrollbar-width: none; }
.topology-catalogs::-webkit-scrollbar { display: none; }
.topology-graph-col { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
#topology-graph-spacer { transition: height var(--pui-transition-speed, 0.3s) ease; }
.topology-graph { flex: 1; min-width: 0; min-height: 0; }

/* Topology — indicator 아이콘: 1rem, 중심을 노드 상단 보더에 맞춤 */
.pui-graph-node-indicators { align-items: center; }
.pui-graph-node-indicator { font-size: 1.15rem; line-height: 1; }

/* Topology — Network overlay (backbone tree diagram) */
.topo-net-overlay { position: fixed; z-index: 20; min-width: 14rem; }
.topo-net-tree { position: relative; padding-left: 1rem; }
.topo-net-row { position: relative; padding: 0.125rem 0; }
.topo-net-row::before { content: ''; position: absolute; left: -1rem; top: 50%; width: 1rem; border-top: 0.25rem solid var(--bs-primary); }
.topo-net-row::after { content: ''; position: absolute; left: -1rem; top: 0; bottom: 0; border-left: 0.25rem solid var(--bs-primary); }
.topo-net-row:first-child::after { top: 50%; }
.topo-net-row:last-child::after { bottom: 0; }
.topo-net-tree::after { content: ''; position: absolute; left: 0; top: 100%; height: var(--ext-h, 0.75rem); border-left: 0.25rem solid var(--bs-primary); }
.topo-net-line { display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0.5rem; border-radius: var(--bs-border-radius-sm); font-size: 0.75rem; white-space: nowrap; border: 1px solid; }
.topo-net-line-primary { border-color: var(--bs-primary); background: var(--bs-primary-bg-subtle); color: var(--bs-primary); }
.topo-net-line-info { border-color: var(--bs-info); background: var(--bs-info-bg-subtle); color: var(--bs-info); }
.topo-net-label { font-weight: 600; }
.topo-net-addr { margin-left: auto; font-weight: 600; }
[data-bs-theme=dark] .topo-net-line,
[data-bs-theme=dark] .topo-net-label,
[data-bs-theme=dark] .topo-net-addr,
[data-bs-theme=dark] .topo-net-line i { color: rgb(var(--pui-text-light)); }

/* Topology — Disk overlay (backbone tree diagram, below node) */
.topo-disk-overlay { position: fixed; z-index: 20; }
.topo-disk-tree { position: relative; padding-left: 1rem; }
.topo-disk-tree::before { content: ''; position: absolute; left: 0; bottom: 100%; height: var(--ext-h, 0.75rem); border-left: 0.25rem solid var(--bs-info); }
.topo-disk-row { position: relative; padding: 0.125rem 0; }
.topo-disk-row::before { content: ''; position: absolute; left: -1rem; top: 50%; width: 1rem; border-top: 0.25rem solid var(--bs-info); }
.topo-disk-row::after { content: ''; position: absolute; left: -1rem; top: 0; bottom: 0; border-left: 0.25rem solid var(--bs-info); }
.topo-disk-row:first-child::after { top: 0; }
.topo-disk-row:last-child::after { bottom: 50%; }
.topo-disk-line { display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0.5rem; border-radius: var(--bs-border-radius-sm); font-size: 0.75rem; white-space: nowrap; border: 1px solid; width: 10.25rem; }
.topo-disk-line-warning { border-color: var(--bs-warning); background: var(--bs-warning-bg-subtle); color: var(--bs-warning); }
.topo-disk-label { font-weight: 600; }
.topo-disk-size { margin-left: auto; font-weight: 600; }
.topo-disk-console { position: relative; width: 10.25rem; aspect-ratio: 1/1; display: flex; align-items: center; justify-content: center; overflow: hidden; background: var(--bs-dark, #0a0a0a); border-radius: var(--bs-border-radius-sm); cursor: pointer; }
.topo-disk-console:hover { filter: brightness(1.15); }
.topo-console-icon { font-size: 5rem; opacity: 0.07; color: rgb(var(--pui-text-light)); position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
.topo-console-img { display: none; opacity: 0; position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: opacity 0.3s; }
.topo-disk-specs { display: flex; gap: 0; }
.topo-disk-spec-line { width: 0.25rem; align-self: center; border-top: 0.25rem solid var(--bs-info); }
.topo-disk-spec { display: flex; align-items: center; gap: 0.375rem; width: 5rem; padding: 0.25rem 0.5rem; border-radius: var(--bs-border-radius-sm); font-size: 0.75rem; white-space: nowrap; border: 1px solid; }
.topo-disk-spec-success { border-color: var(--bs-success); background: var(--bs-success-bg-subtle); color: var(--bs-success); }
[data-bs-theme=dark] .topo-disk-line,
[data-bs-theme=dark] .topo-disk-label,
[data-bs-theme=dark] .topo-disk-size,
[data-bs-theme=dark] .topo-disk-line i,
[data-bs-theme=dark] .topo-disk-spec,
[data-bs-theme=dark] .topo-disk-spec i { color: rgb(var(--pui-text-light)); }

/* Topology — Workload gauge overlay (left of node) */
.topo-workload-overlay { position: fixed; z-index: 10; width: 12rem; height: 12rem; }
.topo-workload-gauge { width: 100%; height: 100%; transform: rotate(-90deg); }
.topo-workload-bg { position: fixed; z-index: 25; width: 6rem; height: 6rem; border-radius: 50%; background: rgba(255, 255, 255, 0.9); border: 1px solid var(--bs-primary); pointer-events: none; }
[data-bs-theme=dark] .topo-workload-bg { background: rgba(var(--bs-dark-rgb), 0.9); }
.topo-workload-value { position: fixed; z-index: 30; display: flex; flex-direction: column; align-items: center; justify-content: center; width: 6rem; height: 6rem; pointer-events: none; }
.topo-workload-num { font-size: 2.25rem; font-weight: 700; line-height: 1; }
.topo-workload-pct { position: absolute; bottom: 0.75rem; font-size: 0.75rem; font-weight: 600; opacity: 0.7; }

/* Shared action menu items */
.action-menu .ctx-item { display: block; width: 100%; padding: 0.375rem 1rem; font-size: 0.875rem; cursor: pointer; border: none; background: none; text-align: start; color: var(--bs-body-color); white-space: nowrap; border-radius: var(--bs-border-radius-sm); }
.action-menu .ctx-item:hover, .action-menu .ctx-item:focus { color: var(--bs-primary); background-color: rgba(var(--bs-primary-rgb), 0.1); }
.action-menu .ctx-item:disabled { color: var(--bs-secondary-color); pointer-events: none; opacity: 0.65; }
.action-menu hr { margin: 0.25rem 0; opacity: var(--bs-border-opacity, 0.25); }
.action-menu .ctx-item-danger { color: var(--bs-danger); }
.action-menu .ctx-item-danger:hover, .action-menu .ctx-item-danger:focus { color: var(--bs-danger); background-color: rgba(var(--bs-danger-rgb), 0.1); }
.pui-dropdown-menu.action-menu { padding: 0.25rem; }
.action-menu-spinner { display: flex; justify-content: center; padding: 0.5rem; }
/* Topology context menu container */
.topology-context-menu { position: fixed; z-index: 20; min-width: 10rem; padding: 0.25rem; background: var(--bs-body-bg); border: 1px solid rgb(var(--bs-primary-rgb)); border-radius: var(--bs-border-radius); box-shadow: var(--bs-box-shadow); }

.metrics-alerts-section { padding: 1rem; }
.metrics-range-bar { display: flex; gap: 0.25rem; padding-bottom: 0.5rem; flex-shrink: 0; justify-content: flex-end; }
.metrics-range-btn { border: 1px solid var(--bs-border-color); background: transparent; border-radius: var(--bs-border-radius-sm); padding: 0.125rem 0.625rem; font-size: 0.75rem; cursor: pointer; opacity: 0.6; }
.metrics-range-btn:hover { opacity: 0.85; }
.metrics-range-btn.active { opacity: 1; border-color: var(--bs-primary); background: var(--bs-primary-bg-subtle); }

.metrics-page { display: flex; flex-direction: column; height: 100%; padding: 1rem; overflow: hidden; }
.metrics-chart-area { flex-shrink: 0; margin-bottom: 0.75rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--bs-border-color); }
.metrics-chart-area.has-chart { height: 280px; }
.metrics-chart-placeholder { display: flex; align-items: center; justify-content: center; opacity: 0.5; font-size: 0.8125rem; padding: 1rem 0; }
.metrics-list-area { flex: 1; min-height: 0; overflow-y: auto; }
.metrics-ops-badge { display: flex; align-items: center; gap: 0.25rem; font-size: 0.8125rem; padding-bottom: 0.75rem; margin-bottom: 0.75rem; border-bottom: 1px solid var(--bs-border-color); }
.metrics-ops-badge-count { margin-left: auto; opacity: 0.6; }
.metrics-group { margin-bottom: 0.25rem; }
.metrics-group-header { font-weight: 600; font-size: 0.8125rem; padding: 0.375rem 0.5rem; cursor: pointer; display: flex; align-items: center; gap: 0.375rem; border-radius: var(--bs-border-radius-sm); }
.metrics-group-header:hover { background: var(--bs-tertiary-bg); }
.metrics-group-count { margin-left: auto; font-weight: 400; opacity: 0.5; font-size: 0.75rem; }
.metrics-group-star { font-size: 0.625rem; opacity: 0.5; }
.metrics-group-items { padding-left: 0.5rem; }
.metrics-item { display: flex; align-items: center; gap: 0.25rem; padding: 0.25rem 0.75rem; font-size: 0.8125rem; cursor: pointer; border-radius: var(--bs-border-radius-sm); }
.metrics-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.metrics-star { flex-shrink: 0; font-size: 0.6875rem; opacity: 0.3; cursor: pointer; transition: opacity 0.15s; }
.metrics-star:hover { opacity: 0.7; }
.metrics-star.active { opacity: 0.85; }
.metrics-item:hover { background: var(--bs-tertiary-bg); }
.metrics-item.active { background: var(--bs-primary-bg-subtle); }

/* -----------------------------------------------------------------------------
   Cost Receipt — Korean POS receipt style
   ----------------------------------------------------------------------------- */
.cost-receipt {
    --_receipt-bg: #f5f4ef;
    --_receipt-text: #333;
    --_receipt-muted: #777;
    --_receipt-line: #bbb;
    background: var(--_receipt-bg);
    padding: 1.5rem 1.25rem;
    position: relative;
    margin: 8px 0;
    font-family: var(--bs-font-monospace);
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--_receipt-text);
    box-shadow: 0 2px 10px rgba(0,0,0,0.06);
}
/* Zigzag edges — fine sawtooth */
.cost-receipt::before,
.cost-receipt::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    height: 8px;
    background-repeat: repeat-x;
    background-size: 14px 8px;
}
.cost-receipt::before {
    top: -8px;
    background-image:
        linear-gradient(135deg, transparent 33.33%, var(--_receipt-bg) 33.33%),
        linear-gradient(225deg, transparent 33.33%, var(--_receipt-bg) 33.33%);
}
.cost-receipt::after {
    bottom: -8px;
    background-image:
        linear-gradient(315deg, transparent 33.33%, var(--_receipt-bg) 33.33%),
        linear-gradient(45deg, transparent 33.33%, var(--_receipt-bg) 33.33%);
}
/* Header: brand + project */
.cost-receipt-header { text-align: center; margin-bottom: 0.625rem; }
.cost-receipt-brand { font-weight: 700; font-size: 0.875rem; letter-spacing: 0.05em; }
.cost-receipt-project { font-size: 0.8125rem; color: var(--_receipt-muted); }
/* Meta: issue date */
.cost-receipt-meta { font-size: 0.75rem; color: var(--_receipt-muted); margin-bottom: 0.25rem; }
/* Separator — dash characters */
.cost-receipt-sep { overflow: hidden; white-space: nowrap; color: var(--_receipt-line); margin: 0.375rem 0; font-size: 0.6875rem; user-select: none; }
.cost-receipt-sep::after { content: '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -'; }
/* Description column header */
.cost-receipt-desc { display: flex; justify-content: space-between; font-size: 0.875rem; font-weight: 700; padding: 0.125rem 0; }
/* Items */
.cost-receipt-items { padding: 0.125rem 0; }
.cost-receipt-item { display: flex; align-items: baseline; padding: 0.2rem 0; }
.cost-receipt-item .receipt-label { white-space: nowrap; }
.cost-receipt-item .receipt-dots { flex: 1; overflow: hidden; white-space: nowrap; margin: 0 0.375rem; color: var(--_receipt-line); font-size: 0.5rem; position: relative; top: -2px; }
.cost-receipt-item .receipt-dots::after { content: '· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · '; }
.cost-receipt-item .receipt-amount { white-space: nowrap; text-align: right; }
/* Total */
.cost-receipt-total { display: flex; justify-content: space-between; align-items: baseline; font-weight: 700; padding: 0.375rem 0; font-size: 0.875rem; }

/* Dark mode */
[data-bs-theme=dark] .cost-receipt { --_receipt-bg: #28261f; --_receipt-text: #ddd; --_receipt-muted: #999; --_receipt-line: #555; }

/* -----------------------------------------------------------------------------
   PUI Lock — TR gradient 이중 렌더링 방지
   TR에 gradient, TD가 inherit → 셀마다 gradient 중복. transparent로 TR만 표시.
   TODO: 업스트림 반영 후 제거
   ----------------------------------------------------------------------------- */
tr.pui-lock-primary > td,
tr.pui-lock-success > td,
tr.pui-lock-warning > td,
tr.pui-lock-danger > td,
tr.pui-lock-info > td,
tr.pui-lock-nav > td {
  background: transparent;
}

/* Form required-field asterisk — theme-aware via Bootstrap danger variable */
.required-marker {
  color: var(--bs-danger);
  font-weight: 600;
  margin-left: 0.15em;
}

/* -----------------------------------------------------------------------------
   Attachment chip close button — match PUIFloatPage header X.
   PUI scopes its custom X visual under `.modal-header .btn-close` only
   (vendor pui.css:21807-21850). Chips inside form bodies fall back to the
   Bootstrap base SVG icon, which looks foreign next to the rest of the modal.
   These rules replicate the PUI .modal-header treatment for `[data-attachment-list]`.
   TODO: 업스트림에 generic `.pui-close-icon` 클래스 추출 후 본 규칙 제거.
   ----------------------------------------------------------------------------- */
[data-attachment-list] .btn-close {
  background-image: none;
  width: 1.25rem;
  height: 1.25rem;
  padding: 0;
  border-radius: 50%;
  opacity: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.15s ease-in-out;
}
[data-attachment-list] .btn-close::before {
  content: '\F62A';
  font-family: 'bootstrap-icons';
  font-size: 1rem;
  line-height: 1;
  color: var(--bs-body-color);
  opacity: 0.65;
  transition: opacity 0.15s ease-in-out;
}
[data-bs-theme=dark] [data-attachment-list] .btn-close::before {
  color: rgb(var(--pui-text-dark));
}
[data-attachment-list] .btn-close:hover {
  background-color: rgba(var(--bs-body-color-rgb), 0.1);
}
[data-attachment-list] .btn-close:hover::before {
  opacity: 1;
}

