/* ═══════════════════════════════════════════════════════════════════ InfraMonitor — NAS↔Windows 워커 파이프라인 관측 콘솔 다크 미션컨트롤 / 텔레메트리 미학 (index.css 토큰 재사용) ═══════════════════════════════════════════════════════════════════ */ .infra { display: flex; flex-direction: column; gap: 16px; } /* ── 상태 바 ───────────────────────────────────────────────────────── */ .infra-bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; } .infra-bar__stats { display: flex; gap: 8px; flex-wrap: wrap; } .infra-chip { font-family: var(--font-body); font-size: 12.5px; letter-spacing: 0.02em; color: var(--text-dim); background: var(--surface-card); border: 1px solid var(--line); border-radius: 999px; padding: 6px 12px; white-space: nowrap; } .infra-chip b { color: var(--text-bright); font-weight: 700; } .infra-chip.is-ok { color: #00d4ff; border-color: rgba(0, 212, 255, 0.35); box-shadow: 0 0 16px rgba(0, 212, 255, 0.12) inset; } .infra-chip.is-warn { color: #fbbf24; border-color: rgba(251, 191, 36, 0.35); } .infra-chip.is-danger { color: #fb923c; border-color: rgba(251, 146, 60, 0.4); } .infra-chip.is-down { color: #f43f5e; border-color: rgba(244, 63, 94, 0.4); box-shadow: 0 0 16px rgba(244, 63, 94, 0.1) inset; } .infra-bar__actions { display: flex; align-items: center; gap: 10px; } .infra-updated { font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; } .infra-toggle { display: inline-flex; border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; } .infra-toggle button { background: transparent; border: 0; color: var(--text-dim); font-size: 12px; padding: 6px 12px; cursor: pointer; transition: all 0.2s var(--ease-out); } .infra-toggle button.is-active { background: var(--neon-cyan-muted); color: var(--neon-cyan); } .infra-refresh { background: var(--surface-card); border: 1px solid var(--line); color: var(--text-dim); border-radius: var(--radius-sm); width: 34px; height: 32px; font-size: 16px; cursor: pointer; transition: all 0.2s var(--ease-out); } .infra-refresh:hover { color: var(--neon-cyan); border-color: var(--line-bright); transform: rotate(90deg); } /* ── 에러 / 경고 / 로딩 ────────────────────────────────────────────── */ .infra-error { display: flex; align-items: center; gap: 14px; padding: 16px 20px; background: rgba(244, 63, 94, 0.08); border: 1px solid rgba(244, 63, 94, 0.3); border-radius: var(--radius-md); color: var(--text); } .infra-error b { color: #f43f5e; } .infra-error span { color: var(--text-dim); font-size: 13px; flex: 1; } .infra-error button { background: rgba(244, 63, 94, 0.18); border: 1px solid rgba(244, 63, 94, 0.4); color: #ffd2da; border-radius: var(--radius-sm); padding: 6px 14px; cursor: pointer; } .infra-warn-banner { padding: 12px 18px; background: rgba(244, 63, 94, 0.1); border: 1px solid rgba(244, 63, 94, 0.28); border-radius: var(--radius-md); color: #ffb3bf; font-size: 13.5px; } .infra-loading { padding: 40px; text-align: center; color: var(--text-dim); font-family: var(--font-display); letter-spacing: 0.04em; } /* ── 3D 스테이지 ───────────────────────────────────────────────────── */ .infra-stage { position: relative; border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; background: radial-gradient(ellipse 90% 60% at 20% 0%, rgba(0, 212, 255, 0.08) 0%, transparent 60%), radial-gradient(ellipse 80% 60% at 85% 100%, rgba(139, 92, 246, 0.07) 0%, transparent 60%), linear-gradient(180deg, #060a16 0%, #04060f 100%); box-shadow: var(--shadow-card); } .infra-stage::before { /* 미세 그리드 텍스처 */ content: ''; position: absolute; inset: 0; background-image: linear-gradient(rgba(0, 212, 255, 0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 212, 255, 0.04) 1px, transparent 1px); background-size: 40px 40px; mask-image: radial-gradient(ellipse 100% 80% at 50% 50%, #000 40%, transparent 90%); pointer-events: none; } .pipeline-canvas { position: relative; width: 100%; height: 58vh; min-height: 440px; } .pipeline-labels { position: absolute; inset: 0; pointer-events: none; overflow: hidden; } .pipeline-label { position: absolute; top: 0; left: 0; display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; background: rgba(6, 10, 22, 0.78); border: 1px solid color-mix(in srgb, var(--pl-color, #00d4ff) 45%, transparent); border-radius: 999px; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); white-space: nowrap; will-change: transform; transition: opacity 0.3s; } .pipeline-label .pl-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--pl-color, #00d4ff); box-shadow: 0 0 8px var(--pl-color, #00d4ff); } .pipeline-label .pl-name { font-family: var(--font-display); font-size: 11.5px; font-weight: 600; color: var(--text-bright); letter-spacing: 0.01em; } .pipeline-label .pl-state { font-size: 10.5px; color: var(--pl-color, #8892b0); font-variant-numeric: tabular-nums; } .pipeline-label--anchor .pl-name { color: var(--pl-color, #e8f0fe); } .infra-legend { position: absolute; bottom: 12px; left: 14px; display: flex; gap: 14px; flex-wrap: wrap; padding: 6px 12px; background: rgba(6, 10, 22, 0.6); border: 1px solid var(--line); border-radius: 999px; font-size: 11px; color: var(--text-dim); } .infra-legend span { display: inline-flex; align-items: center; gap: 6px; } .infra-legend i { width: 9px; height: 9px; border-radius: 2px; display: inline-block; } /* ── 워커 카드 그리드 ──────────────────────────────────────────────── */ .infra-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; } .infra-grid--compact { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); } .infra-card { position: relative; background: var(--surface-card); border: 1px solid var(--line); border-left: 3px solid var(--c, #4a5572); border-radius: var(--radius-md); padding: 14px 16px; box-shadow: var(--shadow-sm); transition: transform 0.2s var(--ease-out), border-color 0.2s; } .infra-card:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--c) 40%, var(--line)); } .infra-card--down { opacity: 0.72; } .infra-card__head { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; } .infra-card__dot { width: 9px; height: 9px; border-radius: 50%; background: var(--c); box-shadow: 0 0 10px var(--c); flex-shrink: 0; } .infra-card__id { flex: 1; min-width: 0; } .infra-card__title { font-family: var(--font-display); font-size: 14px; font-weight: 600; color: var(--text-bright); } .infra-card__kind { font-size: 10.5px; color: var(--text-muted); letter-spacing: 0.03em; } .infra-card__state { font-size: 11px; font-weight: 600; color: var(--c); padding: 3px 9px; border: 1px solid color-mix(in srgb, var(--c) 35%, transparent); border-radius: 999px; white-space: nowrap; } .infra-card__metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-bottom: 10px; } .infra-metric { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 7px 4px; background: rgba(255, 255, 255, 0.02); border-radius: var(--radius-xs); } .infra-metric__v { font-family: var(--font-display); font-size: 16px; font-weight: 700; color: var(--text-bright); font-variant-numeric: tabular-nums; } .infra-metric__l { font-size: 10px; color: var(--text-muted); } .infra-metric--warn .infra-metric__v { color: #fbbf24; } .infra-metric--danger .infra-metric__v { color: #f43f5e; } .infra-card__foot { font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums; } @media (max-width: 768px) { .pipeline-canvas { height: 46vh; min-height: 340px; } .infra-bar { gap: 10px; } }