/* VLAN24 Operations — 운영 콘솔 전용 화면 규칙.

   토큰과 공통 부품은 vlan24-ui.css 로 떨어져 나갔다(고객 포털과 함께 쓴다). 이 파일에는
   콘솔에만 있는 화면의 규칙만 남는다 — 달력, 케이지 도면, 근무표, 업무 상세 같은 것들.

   실리는 차례는 styles.css → vlan24-ui.css → 이 파일이다. 공통 부품보다 뒤에 두어야
   화면별로 덮어 적은 것이 그대로 이긴다.
*/
/* 승인된 Operations 화면 밀도(2026-10-22). 공유/Portal·인쇄 토큰은 유지한다.
   제목·micro 숫자·도면 계측은 그대로, 본문/조작/목록 역할만 12/11/10으로 매핑한다. */
@media screen {
  :root {
    --fs-body: 12px;
    --fs-callout: 11px;
    --fs-caption: 10px;
    --ops-reading-size: var(--fs-body);
    --ops-record-name-size: var(--fs-caption);
  }
  body { font-size: var(--fs-body); }
}
/* ── 짜임새 있는 부품 ─────────────────────────────────────────────────────
   토큰만으로 따라오지 않는 것들. 옛 파일이 색을 #hex 로 박아 둔 자리라 여기서 다시 적는다.
   새로 만든 이름(.fact-list, .inline-field)도 함께 둔다. */

/* 왼쪽 기둥 + 본문. 고객·사이트처럼 "무엇으로 걸러 볼 것인가" 가 목록보다 먼저 온다. */
.inventory-body {
  grid-template-columns: 224px minmax(0, 1fr);
  gap: var(--s-3);
}
.inventory-rail {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--s-1);
  top: calc(var(--topbar-h) + 12px);
  max-height: calc(100vh - var(--topbar-h) - 24px);
}
.inventory-rail h3 {
  color: var(--text-faint);
  font: 560 var(--fs-micro) var(--sans);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  margin: var(--s-2) var(--s-2) var(--s-1);
}
.inventory-rail hr {
  border-top: 1px solid var(--divider);
  margin: var(--s-2) var(--s-1);
}
.inventory-rail-item {
  color: var(--text-secondary);
  font: 450 var(--fs-callout) var(--sans);
  border-radius: var(--radius);
  padding: 5px var(--s-2);
  min-height: 28px;
  transition: background var(--t-fast);
}
.inventory-rail-item b {
  color: var(--text-faint);
  font: 500 var(--fs-micro) var(--mono);
}
.inventory-rail-item:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.inventory-rail-item.active {
  background: var(--surface-active);
  color: var(--text);
  font-weight: 560;
}
.inventory-rail-item.active b {
  color: var(--text-secondary);
}
.inventory-rail-item.is-child {
  color: var(--text-muted);
}
.inventory-rail-empty {
  color: var(--text-faint);
}

/* 근무 현황. 대시보드에서 가장 먼저 읽는 줄이라 카드 두 장을 나란히 두되, 오른쪽의
   남은 시간을 크게 둔다 — 교대까지 몇 분 남았는가가 이 줄의 요점이다. */
.shift-overview {
  grid-template-columns: minmax(0, 1fr) 236px;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}
.shift-overview-main,
.shift-countdown {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.shift-overview-main {
  padding: var(--s-4);
}
.shift-overview-head {
  border-bottom: 1px solid var(--divider);
  padding-bottom: var(--s-3);
  margin-bottom: var(--s-3);
}
.shift-countdown strong {
  font-size: var(--fs-display);
  font-weight: 620;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

/* 대시보드·상세에 쓰이는 작은 줄들. */
.handover-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--s-3);
}
.handover-card h3 {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.handover-card p {
  margin: var(--s-2) 0 0;
  color: var(--text-secondary);
}
.candidate {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px 0;
  border-bottom: 1px solid var(--divider);
  font-size: var(--fs-callout);
  min-width: 0;
}
.candidate:last-child {
  border-bottom: 0;
}
.candidate span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.todo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  width: 100%;
  padding: var(--s-2) var(--s-1);
  border: 0;
  border-bottom: 1px solid var(--divider);
  border-radius: var(--radius);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--t-fast);
}
.todo:hover {
  background: var(--surface-hover);
}
.field > label.todo {
  display: flex;
  margin: 0;
  align-items: flex-start;
}
.field > label.todo input {
  flex: 0 0 15px;
}
.field > label.todo > span {
  display: block;
  flex: 1;
  white-space: normal;
  overflow-wrap: anywhere;
}
.field > label.todo .badge {
  display: inline-flex;
  width: auto;
}
.todo:last-child {
  border-bottom: 0;
}
.todo > span {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.todo b {
  font-size: var(--fs-callout);
  font-weight: 540;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.event-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-1);
  border-bottom: 1px solid var(--divider);
  font-size: var(--fs-callout);
}
.event-row:last-child {
  border-bottom: 0;
}
.event-row time {
  grid-column: 1 / -1;
  min-width: 0;
  font-family: var(--sans);
  color: var(--text-muted);
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.5;
}
.event-row > b {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* 상세 옆 기둥. 카드 여러 장을 세로로 쌓고, 화면이 길어도 따라오게 붙여 둔다. */
.detail-aside {
  display: grid;
  gap: var(--s-3);
  align-content: start;
  position: sticky;
  top: calc(var(--topbar-h) + 12px);
}
/* 이름과 값을 두 칸으로 둔다. 값이 길어도 이름 칸은 흔들리지 않는다 — 세로로 훑을 때
   왼쪽 줄이 맞아 있어야 찾는 값으로 바로 눈이 간다. */
.fact-list {
  display: grid;
  gap: 0;
}
.fact {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  gap: var(--s-2);
  align-items: baseline;
  padding: 7px 0;
  border-bottom: 1px solid var(--divider);
  font-size: var(--fs-callout);
}
.fact:last-child {
  border-bottom: 0;
}
.fact > span {
  color: var(--text-muted);
  font-size: var(--fs-caption);
}
.fact > b {
  font-weight: 500;
  overflow-wrap: anywhere;
}
.linked-row {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px 0;
  border-bottom: 1px solid var(--divider);
  font-size: var(--fs-callout);
  min-width: 0;
}
.linked-row:last-child {
  border-bottom: 0;
}
.linked-row span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 라벨과 입력을 한 줄에 두는 자리(상단 조작 줄). 라벨을 자리표시자로 대신하지 않으면서도
   높이를 한 줄로 유지한다. */
.inline-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.inline-field .select {
  width: auto;
  min-width: 120px;
  height: 27px;
  min-height: 27px;
  padding-top: 0;
  padding-bottom: 0;
  font-size: var(--fs-caption);
  background-position:
    calc(100% - 14px) 12px,
    calc(100% - 9px) 12px;
}

/* 티켓 대화. 고객 글은 왼쪽, 우리 글은 오른쪽, 내부 메모는 가운데. 내부 메모는 테두리까지
   달리 두어 "이건 고객에게 안 나간다" 를 색 없이도 알 수 있게 한다. */
.ticket-thread {
  gap: var(--s-4);
}
.ticket-bubble {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--s-3);
  font-size: var(--fs-callout);
}
.ticket-us .ticket-bubble {
  background: var(--accent-soft);
  border-color: var(--accent-border);
}
.ticket-internal .ticket-bubble {
  background: var(--warn-soft);
  border-color: var(--warn-border);
  border-style: dashed;
}
.ticket-internal-tag {
  color: var(--warn);
  font: 560 var(--fs-micro) var(--sans);
}
.ticket-message-no {
  color: var(--text-faint);
}
.ticket-reply {
  border-top: 1px solid var(--divider);
  background: var(--surface-2);
}
.ticket-reply-modes {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
  flex-wrap: wrap;
}
.ticket-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-2);
}
.ticket-shot img {
  max-height: 180px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: block;
}
.ticket-file {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-caption);
}
.ticket-file:hover {
  background: var(--surface-hover);
  text-decoration: none;
}

/* 모바일. 기둥은 위로 올려 가로로 넘기고, 표는 표만 넘긴다. */
@media (max-width: 900px) {
  .inventory-body {
    grid-template-columns: minmax(0, 1fr);
  }
  .inventory-rail {
    position: static;
    max-height: none;
    display: flex;
    gap: var(--s-1);
    overflow-x: auto;
    align-items: center;
  }
  .inventory-rail h3,
  .inventory-rail hr {
    display: none;
  }
  .inventory-rail-item {
    width: auto;
    flex: none;
  }
  .detail-aside {
    position: static;
  }
  .shift-overview {
    grid-template-columns: minmax(0, 1fr);
  }
  .ticket-message {
    max-width: 100%;
  }
}

/* 상세 화면은 화면마다 따로 만들어졌다. 옆 기둥에 이름이 없는 것들도 같은 간격을 갖도록
   구조로 집는다 — 화면 스무 개에 class 를 새로 달지 않고도 모습이 맞는다. */
.detail-layout > aside {
  display: grid;
  gap: var(--s-3);
  align-content: start;
  min-width: 0;
}
.detail-layout > div {
  display: grid;
  gap: var(--s-3);
  align-content: start;
  min-width: 0;
}
/* 카드를 세로로 쌓을 때 화면마다 margin 을 직접 적어 두었다. 간격은 부모가 정하게 하고,
   옛 margin 은 여기서 거둔다. */
.detail-layout .panel[style*='margin-top'] {
  margin-top: 0 !important;
}

/* 정렬 가능한 기둥 머리. 지금 기준인 기둥만 표시가 진해진다. */
.data-table th.sortable {
  cursor: pointer;
  user-select: none;
}
.data-table th.sortable:hover {
  color: var(--text);
}
.data-table th.is-sorted {
  color: var(--text);
}
.sort-mark {
  margin-left: 4px;
  opacity: 0.45;
  font-size: var(--fs-micro);
}
.data-table th.is-sorted .sort-mark {
  opacity: 1;
  color: var(--accent);
}
.record-sort-button {
  display: inline-flex;
  align-items: center;
  padding: var(--s-1) 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-align: left;
}
.record-sort-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.record-list-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
  padding: var(--s-3);
  border-bottom: 1px solid var(--border);
}
.record-list-toolbar .search {
  flex: 1 1 240px;
  min-width: 0;
}
.record-list-toolbar .task-filter-chips {
  flex-wrap: wrap;
  white-space: normal;
  grid-row: auto;
  padding: 0;
}
.record-sort-control {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  max-width: 100%;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
/* Search and period are one primary row; optional filters stay below it. */
.record-filter-top,
.record-filter-options {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  grid-column: 1 / -1;
  width: 100%;
  min-width: 0;
}
.tasks-page > .panel:has(> .task-filter-bar) {
  overflow: visible;
}
.tasks-page .task-filter-bar {
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.tasks-page .record-filter-options {
  position: relative;
}
.customer-cage-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
}
.customer-cage-controls > .select {
  flex: 1 1 180px;
  min-width: 0;
}
.customer-cage-controls > .tabs {
  margin: 0;
}
.customer-cage-preview {
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.customer-cage-preview .cage-svg {
  display: block;
  width: 100%;
  height: auto;
  max-height: 480px;
  touch-action: auto;
}
.record-filter-top > .input.search {
  flex: 1 1 220px;
  width: auto;
  height: var(--row-h);
}
.task-date-toolbar.compact-period-toolbar,
.compact-period-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
}
.compact-period-toolbar .tabs {
  display: inline-flex;
  flex-shrink: 0;
  height: var(--row-h);
  margin: 0;
  padding: 2px;
}
.compact-period-toolbar .tabs button {
  min-height: 0;
  height: calc(var(--row-h) - 4px);
  padding: 0 var(--s-2);
  font-size: var(--fs-caption);
  line-height: 1;
}
.compact-period-toolbar .select,
.compact-period-toolbar .input,
.compact-period-toolbar .button {
  height: var(--row-h);
  min-height: var(--row-h);
  padding-block: 0;
  font-size: var(--fs-caption);
}
.compact-period-toolbar .report-custom-dates {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  flex-basis: 100%;
}
.compact-period-toolbar .report-custom-dates .input {
  flex: 1 1 120px;
  width: 120px;
  min-width: 0;
}
.record-filter-options .personal-view-toolbar {
  padding: 0;
  margin-left: auto;
  gap: var(--s-2);
  max-width: 100%;
  min-width: 0;
}
.record-filter-options .personal-view-toolbar > label {
  flex-basis: auto;
}
.record-filter-options .personal-view-toolbar > .select {
  flex: 0 1 140px;
  width: 140px;
  height: var(--row-h);
}
.field-range-bar.compact-period-toolbar {
  margin-bottom: var(--s-3);
}
.field-range-bar .report-period-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-left: auto;
}
.field-range-bar .report-period-summary strong {
  font-size: var(--fs-caption);
  font-weight: 500;
}
.field-range-bar .report-period-summary small {
  font-size: var(--fs-micro);
}
@media (any-pointer: coarse), (max-width: 767px) {
  .record-filter-top > .input.search,
  .compact-period-toolbar .tabs,
  .compact-period-toolbar .select,
  .compact-period-toolbar .input,
  .compact-period-toolbar .button {
    height: 44px;
    min-height: 44px;
  }
  .compact-period-toolbar .tabs button {
    height: 44px;
    min-height: 44px;
    min-width: 44px;
  }
  .compact-period-toolbar .tabs { padding: 0; }
}
@media (max-width: 760px) {
  .tasks-page .task-filter-pop-wrap {
    position: static;
  }
  .tasks-page .task-filter-pop {
    left: 0;
    right: auto;
    top: calc(100% + var(--s-2));
    max-width: 100%;
  }
}
.record-sort-control .select {
  width: auto;
  min-width: 0;
  max-width: 100%;
}
.record-list-count {
  margin-left: auto;
  white-space: nowrap;
}
@media (any-pointer: coarse), (max-width: 767px) {
  .record-list-toolbar .task-filter-chip,
  .record-list-toolbar .select,
  .record-list-toolbar .button,
  .record-sort-button {
    min-height: 44px;
  }
}
@media (max-width: 600px) {
  .record-list-toolbar > .search,
  .record-list-toolbar > .task-filter-chips {
    flex-basis: 100%;
  }
  .record-sort-control {
    flex: 1 1 180px;
  }
  .record-sort-control .select {
    flex: 1;
  }
}
/* 쪽 넘김 줄. 표 아래에 붙어 카드 안에서 끝난다. */
.pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding: var(--s-2) var(--s-4);
  border-top: 1px solid var(--divider);
  background: var(--surface);
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.pagination-controls {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.page-size {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.page-size .select {
  width: auto;
  min-width: 78px;
  height: 27px;
  min-height: 27px;
  padding-top: 0;
  padding-bottom: 0;
  font-size: var(--fs-caption);
  background-position:
    calc(100% - 14px) 12px,
    calc(100% - 9px) 12px;
}

/* ── 빠른 이동 ────────────────────────────────────────────────────────────
   운영 중 화면 이동은 대부분 검색으로 일어난다(Ctrl K). 그래서 이 창은 모달이 아니라
   화면 위쪽에 떠 있고, 여는 순간 입력칸에 초점이 가 있다. */
.global-search-backdrop {
  background: rgba(13, 13, 15, 0.42);
  backdrop-filter: blur(3px);
  animation: ds-fade var(--t) both;
}
.global-search-dialog {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-modal);
  animation: ds-rise var(--t) both;
}
.global-search-dialog > header {
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--divider);
}
.global-search-dialog > header > span {
  color: var(--text-faint);
  font-size: var(--fs-title3);
}
.global-search-dialog input {
  color: var(--text);
  font: 450 var(--fs-body) var(--sans);
}
.global-search-dialog input::placeholder {
  color: var(--text-faint);
}
.global-search-body {
  padding: var(--s-2);
}
.global-search-state {
  color: var(--text-muted);
}
.global-search-state.error {
  color: var(--danger);
}
.global-search-group h3,
.global-search-recent h3 {
  color: var(--text-faint);
  font: 560 var(--fs-micro) var(--sans);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.global-search-result {
  color: var(--text);
  border-radius: var(--radius);
  padding: var(--s-2);
}
.global-search-result:hover,
.global-search-result.active {
  background: var(--surface-active);
}
/* 키보드로 고른 줄은 마우스로 지나간 줄과 달라 보여야 한다 — 둘이 같으면 Enter 가
   어디로 갈지 알 수 없다. */
.global-search-result.active {
  background: var(--accent-soft);
  box-shadow: inset 2px 0 0 var(--accent);
}
.global-search-result small {
  color: var(--text-muted);
}
.global-search-type {
  color: var(--text-muted);
  font: 500 var(--fs-micro) var(--mono);
  letter-spacing: 0.02em;
}
.global-search-dialog kbd,
.global-search-trigger kbd {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-faint);
}
.global-search-dialog > footer {
  border-top: 1px solid var(--divider);
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: var(--fs-caption);
}

/* ── 작은 화면 ───────────────────────────────────────────────────────────
   기둥은 서랍으로, 아래 막대는 다섯 자리로. 데스크톱 화면을 줄여 보여 주지 않는다. */
@media (max-width: 900px) {
  .mobile-bottom-nav {
    border-top: 1px solid var(--border);
    background: var(--surface);
    height: 62px;
  }
  .mobile-bottom-nav button {
    color: var(--text-muted);
    border-radius: var(--radius);
  }
  .mobile-bottom-nav button > b {
    font-size: var(--fs-micro);
    font-weight: 560;
  }
  .mobile-bottom-nav button.active {
    background: var(--surface-active);
    color: var(--text);
  }
  .mobile-nav-backdrop {
    background: rgba(13, 13, 15, 0.42);
  }
  .mobile-nav-sheet {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-modal);
  }
  .mobile-nav-sheet header {
    border-bottom: 1px solid var(--divider);
  }
  .main {
    padding-bottom: 68px;
  }
  .topbar {
    height: var(--topbar-h);
  }
  /* 표는 가로로만 넘긴다. 줄을 카드로 접으면 기둥끼리 비교가 안 되는데, 운영 화면에서
     표를 보는 이유가 바로 그 비교다. 대신 첫 칸(식별자)은 붙잡아 둔다. */
  .table-wrap {
    margin: 0 calc(var(--s-3) * -1);
    padding: 0 var(--s-3);
  }
  .panel > .table-wrap {
    margin: 0;
    padding: 0;
  }
  .data-table td,
  .data-table th {
    white-space: nowrap;
  }
  .data-table td .cell-truncate {
    max-width: 30ch;
  }
}

/* 어두운 판. styles.css 의 body.theme-dark 가 배경색과 옛 이름들을 직접 박아 두어,
   토큰만 바꾸면 남색 바탕이 그대로 남는다. 같은 자리에서 다시 적어 덮는다. */
body.theme-dark {
  background: var(--bg);
  color: var(--text);
  --ink: var(--text);
  --muted: var(--text-muted);
  --line: var(--border);
  --panel: var(--surface);
  --panel-soft: var(--surface-2);
  --navy: var(--sidebar-bg);
  --blue: var(--accent);
  --critical: var(--danger);
  --high: var(--warn);
  --success: var(--ok);
  --warning: var(--warn);
}
body.theme-dark .inventory-rail,
body.theme-dark .panel,
body.theme-dark .shift-overview-main,
body.theme-dark .shift-countdown,
body.theme-dark .detail-header,
body.theme-dark .stat-strip,
body.theme-dark .kpi-grid,
body.theme-dark .global-search-dialog,
body.theme-dark .modal {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .data-table thead th,
body.theme-dark .task-list thead th,
body.theme-dark .table thead th {
  background: var(--surface-2);
}
body.theme-dark .ticket-bubble {
  background: var(--surface-2);
  border-color: var(--border);
}
body.theme-dark .ticket-us .ticket-bubble {
  background: var(--accent-soft);
  border-color: var(--accent-border);
}
body.theme-dark .ticket-internal .ticket-bubble {
  background: var(--warn-soft);
  border-color: var(--warn-border);
}

/* 폼에서 쓰이던 이름 없는 토큰들. 정의가 어디에도 없어 글자색이 상속으로 떨어지고 있었다 —
   긴급 표시가 본문과 같은 색으로 나왔다는 뜻이다. */
:root {
  --fault: var(--danger);
  --ink-light: var(--text-muted);
}

/* 업무 등록·편집 폼. 묶음마다 제목을 두고, 묶음 사이는 선 하나로 나눈다. */
.task-form .form-section {
  padding: var(--s-4) 0;
}
.task-form .form-section:first-child {
  padding-top: 0;
}
.task-form .form-section > h3 {
  margin-bottom: var(--s-3);
  color: var(--text);
  font-size: var(--fs-caption);
  font-weight: 600;
}
.task-form .field.wide > label,
.task-form .field > label {
  font-size: var(--fs-caption);
  font-weight: 540;
  color: var(--text-secondary);
}
/* 체크 상자는 손이 닿는 크기로 둔다. */
input[type='checkbox'],
input[type='radio'] {
  width: 15px;
  height: 15px;
  accent-color: var(--accent);
  cursor: pointer;
}
.device-results-dropdown {
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  background: var(--surface) !important;
  box-shadow: var(--shadow-pop) !important;
}
.task-workdate-row {
  display: grid !important;
  grid-template-columns: auto auto auto auto;
  align-items: center;
  gap: var(--s-2);
  justify-content: start;
}
.task-workdate-row > label {
  grid-column: 1 / -1;
}
.task-workdate-row .input {
  width: auto;
  min-width: 132px;
}
.task-workdate-row .field-hint {
  grid-column: 1 / -1;
}

/* ── 고쳐 적는 것들 ───────────────────────────────────────────────────────

   1. 알림 줄이 크림색 판이라 혼자 다른 화면에서 온 것처럼 보였다. 바탕은 다른 카드와
      같게 두고, 왼쪽 선 하나로만 "여기 볼 것이 있다" 를 말한다.
   2. 카드 안에 또 카드가 있었다. 인수인계 요약과 전달 업무 줄이 각각 상자를 갖고 있어,
      패널 안에 상자, 그 안에 또 배지가 겹쳤다. 배지는 남기고 상자를 없앤다 — 이 화면에서
      정보를 나누는 것은 선과 여백이지 상자가 아니다. */
.alert {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius);
  color: var(--text);
  padding: var(--s-3) var(--s-4);
}
.alert b {
  font-weight: 600;
}
.alert.critical {
  border-color: var(--border);
  border-left-color: var(--danger);
}
.alert.warning {
  border-color: var(--border);
  border-left-color: var(--warn);
}

.handover-card {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--divider);
  border-radius: 0;
  padding: 0 0 var(--s-3);
  margin-bottom: var(--s-3);
}
.candidate {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--divider);
  border-radius: 0;
  margin: 0;
  padding: 7px 0;
  overflow: visible;
  white-space: normal;
}
.candidate:last-of-type {
  border-bottom: 0;
}

/* ── 티켓 상태 배지 ───────────────────────────────────────────────────────
   티켓은 업무와 다른 class 이름(ticket-status-*)을 쓰는데, 그 이름에 붙은 규칙이 어디에도
   없어 다섯 상태가 모두 같은 회색으로 나왔다. 업무 상태와 같은 규칙을 준다 — 같은 뜻의
   상태가 화면마다 달라 보이면 그때부터 배지는 읽히지 않고 장식이 된다. */
.badge.ticket-status-new {
  background: var(--accent-soft);
  border-color: var(--accent-border);
  color: var(--accent-text);
}
.badge.ticket-status-open {
  background: var(--accent-soft);
  border-color: var(--accent-border);
  color: var(--accent-text);
}
.badge.ticket-status-pending {
  background: var(--warn-soft);
  border-color: var(--warn-border);
  color: var(--warn);
}
.badge.ticket-status-resolved {
  background: var(--ok-soft);
  border-color: var(--ok-border);
  color: var(--ok);
}
.badge.ticket-status-closed {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text-muted);
}

/* 근무 중 표시와 현장작업 상태도 같은 규칙 위로 올린다. */
.coverage-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border: 1px solid var(--ok-border);
  border-radius: var(--radius-sm);
  background: var(--ok-soft);
  color: var(--ok);
  font-size: var(--fs-micro);
  font-weight: 540;
}
.dispatch-status {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-secondary);
  font-size: var(--fs-micro);
  font-weight: 540;
}
.dispatch-requested {
  background: var(--warn-soft);
  border-color: var(--warn-border);
  color: var(--warn);
}
.dispatch-dispatched,
.dispatch-on-site {
  background: var(--accent-soft);
  border-color: var(--accent-border);
  color: var(--accent);
}
.dispatch-resolved {
  background: var(--ok-soft);
  border-color: var(--ok-border);
  color: var(--ok);
}
.dispatch-closed {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text-muted);
}

/* 메뉴 아이콘은 이제 모두 같은 선으로 그린 SVG 다. 글자와 같은 색으로 따라오게 둔다. */
.nav-icon {
  stroke: currentColor;
  fill: none;
  stroke-width: 1.6;
}

.task-id {
  color: var(--text-secondary);
}
.task-reference-link {
  color: var(--accent);
  background: none;
  border: 0;
  padding: 0;
  font: 500 var(--fs-caption) var(--mono);
  cursor: pointer;
}
.task-reference-link:hover {
  text-decoration: underline;
}

/* ── 다크 모드 되돌리기 (자동 생성) ──────────────────────────────────────

   styles.css 에는 흰색·연한 색을 직접 박아 둔 규칙이 385개 있고, 그중 상당수에 다크 판이
   없었다. 토큰만 바꾸면 그 자리는 흰 상자로 남고 글자만 밝아진다 — 실제로 인수인계 카드의
   전달 업무 줄이 흰 바탕에 흰 글씨로 나왔다.

   그래서 styles.css 를 훑어 밝은 배경·어두운 글자·밝은 테두리를 쓰는 규칙을 찾고, 그 색의
   밝기와 색상(hue)으로 어느 토큰에 해당하는지 정해 다크 판만 다시 적었다. 디자인 시스템이
   이미 두 판 모두 손보는 부품(.badge, .panel, .button …)은 건드리지 않는다 — 둘이 겹치면
   나중에 어느 쪽이 이겼는지 알 수 없게 된다.

   styles.css 에 색을 새로 박으면 이 목록도 다시 만들어야 한다. 앞으로 새로 적는 규칙은
   #hex 대신 토큰을 쓰는 것이 옳다. */
body.theme-dark .timeline {
  background: var(--accent-soft);
}
body.theme-dark .description {
  color: var(--text);
}
body.theme-dark .info-list {
  border-color: var(--border);
}
body.theme-dark .info-list div {
  border-color: var(--border);
}
body.theme-dark .timeline-event {
  border-color: var(--border);
}
body.theme-dark .timeline-event p {
  color: var(--text);
}
body.theme-dark .settings-row {
  border-color: var(--border);
}
body.theme-dark .leave-calendar {
  background: var(--surface);
}
body.theme-dark .leave-cal-cell {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .leave-cal-cell:hover:not(.leave-cal-blank) {
  background: var(--surface);
}
body.theme-dark .cal-holiday-tag.is-kr {
  background: var(--danger-soft);
  color: var(--danger);
}
body.theme-dark .cal-holiday-tag.is-la {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .muted-day {
  background: var(--surface);
}
body.theme-dark .cal-event {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .shift-row + .shift-row {
  border-color: var(--border);
}
body.theme-dark .shift-range {
  color: var(--text);
}
body.theme-dark .report-kpi-grid article {
  background: var(--surface);
}
body.theme-dark .report-kpi-grid strong {
  color: var(--text);
}
body.theme-dark .report-kpi-grid .attention strong {
  color: var(--warn);
}
body.theme-dark .report-kpi-grid .fault strong,
body.theme-dark .report-health .fault strong {
  color: var(--danger);
}
body.theme-dark .report-stock {
  color: var(--ok);
}
body.theme-dark .report-use {
  color: var(--text);
}
body.theme-dark .report-fault {
  color: var(--danger);
}
body.theme-dark .report-team-row > strong {
  color: var(--text);
}
body.theme-dark .report-health > div {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .report-health strong {
  color: var(--text);
}
body.theme-dark .report-incidents > div {
  border-color: var(--border);
}
body.theme-dark .task-todo-link:hover {
  background: var(--surface);
}
body.theme-dark .handover-summary-strip article {
  background: var(--surface);
}
body.theme-dark .handover-summary-strip strong {
  color: var(--text);
}
body.theme-dark .handover-detail > header b {
  color: var(--text);
}
body.theme-dark .handover-focus-grid section,
body.theme-dark .handover-all-notes {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .handover-focus-grid .next-action {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .handover-focus-grid .critical-note {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .handover-focus-grid h3,
body.theme-dark .handover-all-notes h3,
body.theme-dark .handover-task-section h3 {
  color: var(--text);
}
body.theme-dark .handover-all-notes {
  background: var(--surface);
}
body.theme-dark .handover-reading-section:nth-child(even) {
  border-color: var(--border);
}
body.theme-dark .handover-task-section h3 span {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .handover-history-list article > b {
  color: var(--text);
}
body.theme-dark .handover-ack-count {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .handover-ack-row {
  border-color: var(--border);
}
body.theme-dark .handover-ack-name {
  color: var(--text);
}
body.theme-dark .handover-ack-state {
  color: var(--ok);
}
body.theme-dark .handover-ack-waiting {
  color: var(--warn);
}
body.theme-dark .handover-history-link {
  border-color: var(--border);
}
body.theme-dark .handover-history-link:hover {
  background: var(--surface);
}
body.theme-dark .handover-history-link.is-open {
  background: var(--surface);
}
body.theme-dark .handover-history-link b {
  color: var(--text);
}
body.theme-dark .handover-history-link span {
  color: var(--text);
}
body.theme-dark .handover-history-link p {
  color: var(--text);
}
body.theme-dark .handover-list-table tr.is-open td {
  background: var(--surface);
}
body.theme-dark .handover-ack-extra {
  background: var(--surface);
}
body.theme-dark .handover-overview dl > div:nth-child(3) {
  border-color: var(--border);
}
body.theme-dark .handover-overview dl > div:nth-child(4) {
  border-color: var(--border);
}
body.theme-dark .dispatch-summary strong {
  color: var(--text);
}
body.theme-dark .dispatch-task-link {
  color: var(--text);
}
body.theme-dark .active-dispatch-panel {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .active-dispatch-panel > div:first-child span {
  color: var(--danger);
}
body.theme-dark .active-dispatch-panel > div:first-child b {
  color: var(--danger);
}
body.theme-dark .active-dispatch-panel button {
  background: var(--surface);
  color: var(--danger);
  border-color: var(--border);
}
body.theme-dark .dispatch-flow b {
  color: var(--text);
}
body.theme-dark .dispatch-title-link:hover b {
  color: var(--text);
}
body.theme-dark .dispatch-time-grid strong {
  color: var(--text);
}
body.theme-dark .dispatch-time-grid .time-total {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .license-quantity.available {
  color: var(--ok);
}
body.theme-dark .license-quantity.quantity-invalid {
  background: var(--surface);
  color: var(--danger);
}
body.theme-dark .leave-summary strong {
  color: var(--text);
}
body.theme-dark .leave-team-list > div {
  border-color: var(--border);
}
body.theme-dark .calendar-legend .kr {
  background: var(--danger-soft);
}
body.theme-dark .calendar-legend .la {
  background: var(--accent-soft);
}
body.theme-dark .shift-row:has(.offline) .shift-segment {
  background: var(--accent-soft);
}
body.theme-dark .report-page-tabs {
  border-color: var(--border);
}
body.theme-dark .report-page-tabs button {
  color: var(--text);
}
body.theme-dark .report-page-tabs button.active {
  color: var(--text);
}
body.theme-dark .report-period-note {
  color: var(--text);
}
body.theme-dark .license-expiry-alert header span {
  color: var(--warn);
}
body.theme-dark .license-expiry-alert p {
  color: var(--warn);
}
body.theme-dark .license-alert-row span,
body.theme-dark .license-alert-row time {
  color: var(--text);
}
body.theme-dark .license-alert-row em {
  color: var(--warn);
}
body.theme-dark .report-period-summary {
  color: var(--text);
}
body.theme-dark .report-topic-tabs button.active {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .report-topic-tabs button.active span {
  color: var(--text);
}
body.theme-dark .report-hero-kpis .urgent {
  border-color: var(--border);
}
body.theme-dark .report-hero-kpis .urgent strong {
  color: var(--warn);
}
body.theme-dark .report-hero-kpis .danger {
  border-color: var(--border);
}
body.theme-dark .report-hero-kpis .danger strong {
  color: var(--danger);
}
body.theme-dark .report-visual-panel > header {
  border-color: var(--border);
}
body.theme-dark .report-visual-panel > header span,
body.theme-dark .report-section-heading > div > span {
  color: var(--text);
}
body.theme-dark .report-visual-panel h2,
body.theme-dark .report-section-heading h2 {
  color: var(--text);
}
body.theme-dark .report-focus-grid article {
  border-color: var(--border);
}
body.theme-dark .report-activity article {
  border-color: var(--border);
}
body.theme-dark .report-activity article:nth-child(odd) {
  border-color: var(--border);
}
body.theme-dark .report-activity .id {
  color: var(--text);
}
body.theme-dark .report-activity .status {
  color: var(--text);
}
body.theme-dark .report-asset-card strong {
  color: var(--text);
}
body.theme-dark .report-asset-card p b {
  color: var(--text);
}
body.theme-dark .report-stack {
  background: var(--surface);
}
body.theme-dark .report-model-list > div {
  border-color: var(--border);
}
body.theme-dark .report-model-list .type {
  color: var(--text);
}
body.theme-dark .report-model-list em {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .report-model-list em.stock {
  background: var(--ok-soft);
  color: var(--ok);
}
body.theme-dark .report-model-list em.use {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .report-model-list em.fault {
  background: var(--danger-soft);
  color: var(--danger);
}
body.theme-dark .report-license-card {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .report-license-card span {
  color: var(--warn);
}
body.theme-dark .report-license-card h3 {
  color: var(--text);
}
body.theme-dark .report-license-card > strong {
  color: var(--warn);
}
body.theme-dark .report-license-card > em {
  color: var(--warn);
}
body.theme-dark .report-people-list article {
  border-color: var(--border);
}
body.theme-dark .report-people-list em {
  color: var(--ok);
}
body.theme-dark .report-leave-list article {
  border-color: var(--border);
}
body.theme-dark .report-leave-list article div span {
  color: var(--text);
}
body.theme-dark .report-leave-list em {
  color: var(--text);
}
body.theme-dark .pdf-option-card:hover {
  background: var(--surface);
}
body.theme-dark .license-expiry-alert h2 b {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .license-alert-more {
  color: var(--warn);
}
body.theme-dark .runbook-summary strong {
  color: var(--text);
}
body.theme-dark .runbook-card h3 {
  color: var(--text);
}
body.theme-dark .runbook-card > p {
  color: var(--text);
}
body.theme-dark .runbook-card footer {
  border-color: var(--border);
}
body.theme-dark .runbook-status.approved {
  background: var(--ok-soft);
  color: var(--ok);
}
body.theme-dark .runbook-status.draft {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .runbook-status.deprecated {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .runbook-default {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .runbook-taxonomy span,
body.theme-dark .task-classification span {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .runbook-empty {
  background: var(--surface);
}
body.theme-dark .runbook-detail-head h1 {
  color: var(--text);
}
body.theme-dark .runbook-detail-head p {
  color: var(--text);
}
body.theme-dark .runbook-detail-head dl div,
body.theme-dark .runbook-side-card dl div {
  border-color: var(--border);
}
body.theme-dark .runbook-scope > div {
  background: var(--surface);
}
body.theme-dark .runbook-scope b {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .runbook-section header span {
  color: var(--text);
}
body.theme-dark .runbook-section h2,
body.theme-dark .runbook-side-card h2 {
  color: var(--text);
}
body.theme-dark .runbook-section ul,
body.theme-dark .runbook-section ol,
body.theme-dark .runbook-side-card ul {
  color: var(--text);
}
body.theme-dark .runbook-section.procedure li {
  border-color: var(--border);
}
body.theme-dark .runbook-section.procedure li:before {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .runbook-side-card > span {
  color: var(--text);
}
body.theme-dark .runbook-side-card.warning {
  background: var(--surface);
}
body.theme-dark .runbook-side-card.warning > span {
  color: var(--warn);
}
body.theme-dark .runbook-side-card.review {
  background: var(--surface);
}
body.theme-dark .choice-grid label {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .runbook-default-check {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .task-classification {
  border-color: var(--border);
}
body.theme-dark .task-runbook-link > span {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .task-checklist-progress b {
  color: var(--text);
}
body.theme-dark .task-checklist-progress i {
  background: var(--surface-2);
}
body.theme-dark .taxonomy-row {
  border-color: var(--border);
}
body.theme-dark .taxonomy-row b {
  color: var(--text);
}
body.theme-dark .taxonomy-row > span,
body.theme-dark .master-status {
  background: var(--surface);
  color: var(--ok);
}
body.theme-dark .taxonomy-row.inactive > span,
body.theme-dark .master-status {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .master-status.active {
  background: var(--surface);
  color: var(--ok);
}
body.theme-dark .symptom-group header b {
  color: var(--text);
}
body.theme-dark .symptom-group header span {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .symptom-chip:hover {
  background: var(--surface);
}
body.theme-dark .taxonomy-none {
  border-color: var(--border);
}
body.theme-dark .organization-token,
body.theme-dark .organization-detail-token {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .organization-token button {
  color: var(--text);
}
body.theme-dark .organization-token button:hover {
  color: var(--danger);
}
body.theme-dark .organization-type {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .organization-type.internal {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .organization-type.customer {
  background: var(--surface);
  color: var(--ok);
}
body.theme-dark .organization-type.vendor {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .organization-type.carrier {
  background: var(--surface-2);
  color: var(--text);
}
body.theme-dark .task-activity-empty {
  border-color: var(--border);
}
body.theme-dark .task-reference-link:hover {
  background: var(--accent-soft);
}
body.theme-dark .inventory-page .asset-serial {
  color: var(--text);
}
body.theme-dark .triage-head h2 {
  color: var(--text);
}
body.theme-dark .auth-card {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .auth-brand small {
  color: var(--text);
}
body.theme-dark .auth-heading > span {
  color: var(--text);
}
body.theme-dark .auth-heading p {
  color: var(--text);
}
body.theme-dark .auth-form label {
  color: var(--text);
}
body.theme-dark .auth-form input {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border);
}
body.theme-dark .auth-divider:before,
body.theme-dark .auth-divider:after {
  background: var(--accent-soft);
}
body.theme-dark .auth-microsoft span {
  color: var(--text);
}
body.theme-dark .auth-security {
  background: var(--surface);
}
body.theme-dark .auth-spinner {
  border-color: var(--border);
}
body.theme-dark .auth-status-error {
  background: var(--surface);
  color: var(--danger);
  border-color: var(--border);
}
body.theme-dark .shift-day-col .day-time {
  color: var(--text);
}
body.theme-dark .print-header h1 {
  color: var(--text);
}
body.theme-dark .report-license-card {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .walkthrough-page {
  border-color: var(--border);
}
body.theme-dark .walkthrough-scope-card > div > span,
body.theme-dark .walkthrough-progress-head > div > span,
body.theme-dark .walkthrough-rack-summary span {
  color: var(--text);
}
body.theme-dark .walkthrough-task-link {
  color: var(--text);
}
body.theme-dark .walkthrough-rack-summary strong {
  color: var(--text);
}
body.theme-dark .walkthrough-kpis article.pass strong {
  color: var(--ok);
}
body.theme-dark .walkthrough-kpis article.fail strong {
  color: var(--danger);
}
body.theme-dark .walkthrough-customer-templates summary em {
  color: var(--text);
}
body.theme-dark .walkthrough-customer-templates button b {
  color: var(--text);
}
body.theme-dark .walkthrough-kpis article.fail:last-child {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .walkthrough-template-card > div:first-child > span {
  color: var(--text);
}
body.theme-dark .walkthrough-template-card p {
  color: var(--text);
}
body.theme-dark .walkthrough-template-card > strong {
  color: var(--text);
}
body.theme-dark .walkthrough-icon-button.danger:hover {
  color: var(--danger);
}
body.theme-dark .walkthrough-session-counts > small {
  border-color: var(--border);
}
body.theme-dark .walkthrough-session-counts > small b {
  color: var(--text);
}
body.theme-dark .walkthrough-session-counts > small.fail b {
  color: var(--danger);
}
body.theme-dark .walkthrough-session-counts em.complete {
  background: var(--ok-soft);
  color: var(--ok);
}
body.theme-dark .walkthrough-session-counts em.progress {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .walkthrough-session-counts em.cancelled {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .walkthrough-rack-unit button {
  color: var(--text);
}
body.theme-dark .walkthrough-rack-unit button:hover {
  background: var(--accent-soft);
}
body.theme-dark .walkthrough-template-help {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .walkthrough-issue-form > div {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .walkthrough-issue-form b {
  color: var(--text);
}
body.theme-dark .walkthrough-issue-form small {
  color: var(--warn);
}
body.theme-dark .walkthrough-back {
  color: var(--text);
}
body.theme-dark .walkthrough-detail-kpis .pass strong {
  color: var(--ok);
}
body.theme-dark .walkthrough-detail-kpis .fail strong {
  color: var(--danger);
}
body.theme-dark .walkthrough-result-row.fail {
  background: var(--surface);
}
body.theme-dark .walkthrough-result-row.pass {
  background: var(--surface);
}
body.theme-dark .walkthrough-issue-detail strong {
  color: var(--danger);
}
body.theme-dark .walkthrough-rack-target:hover {
  background: var(--surface);
}
body.theme-dark .walkthrough-rack-device:hover {
  background: var(--accent-soft);
}
body.theme-dark .walkthrough-rack-device.full-depth {
  background: var(--accent-soft);
}
body.theme-dark .walkthrough-rack-legend i {
  background: var(--accent-soft);
}
body.theme-dark .walkthrough-rack-legend i.rear {
  background: var(--surface);
}
body.theme-dark .mention-popup {
  background: var(--surface);
}
body.theme-dark .asset-reference-link {
  background: var(--accent-soft);
  color: var(--text);
  border-color: var(--border);
}
body.theme-dark .excel-template-upload label {
  color: var(--text);
}
body.theme-dark .excel-template-icon {
  background: var(--ok-soft);
  color: var(--ok);
}
body.theme-dark .settings-error {
  background: var(--surface);
  color: var(--danger);
}
body.theme-dark .walkthrough-temperature-setting > [data-temperature-template] {
  border-color: var(--border);
}
body.theme-dark .walkthrough-temperature-setting label {
  color: var(--text);
}
body.theme-dark .cross-linked-field-work button {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border);
}
body.theme-dark .ipam-network-row td {
  border-color: var(--border);
}
body.theme-dark .ipam-indent {
  color: var(--text);
}
body.theme-dark .walkthrough-temp-group .temp-divider {
  background: var(--accent-soft);
}
body.theme-dark .runbook-summary article > i {
  background: var(--surface);
  color: var(--ok);
}
body.theme-dark .runbook-summary article.draft > i {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .runbook-summary article.default > i {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .access-user:hover {
  border-color: var(--border);
}
body.theme-dark .access-editor-head {
  border-color: var(--border);
}
body.theme-dark .access-choice:hover {
  border-color: var(--border);
}
body.theme-dark .account-identity {
  border-color: var(--border);
}
body.theme-dark .account-balance strong {
  color: var(--text);
}
body.theme-dark .account-request p {
  color: var(--text);
}
body.theme-dark .account-reply {
  color: var(--text);
  border-color: var(--border);
}
body.theme-dark .standby-head-actions .is-on {
  color: var(--text);
}
body.theme-dark .standby-cell.is-sun {
  color: var(--danger);
}
body.theme-dark .standby-cell.is-sat {
  color: var(--text);
}
body.theme-dark .standby-cell:hover,
body.theme-dark .standby-week:hover {
  background: var(--surface);
}
body.theme-dark .cal-standby-chip {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .cal-standby-chip.is-open {
  background: var(--danger-soft);
  color: var(--danger);
}
body.theme-dark .leave-grant-diff em {
  color: var(--text);
}
body.theme-dark .leave-grant-log > div {
  border-color: var(--border);
}
body.theme-dark .leave-grant-log em {
  color: var(--text);
}
body.theme-dark .leave-grant-log p {
  color: var(--text);
}
body.theme-dark .walkthrough-order-panel > span {
  color: var(--text);
}
body.theme-dark .walkthrough-order-actions button:hover:not(:disabled) {
  background: var(--accent-soft);
}
body.theme-dark .asset-disk-group summary {
  color: var(--text);
}
body.theme-dark .asset-address span {
  color: var(--text);
}
body.theme-dark .inventory-ip-kind {
  color: var(--ok);
}
body.theme-dark .asset-head-source {
  color: var(--text);
}
body.theme-dark .asset-chain-node.current b {
  color: var(--text);
}
body.theme-dark .asset-chain-note {
  color: var(--warn);
}
body.theme-dark .asset-chain-empty b {
  color: var(--text);
}
body.theme-dark .customer-totals article {
  background: var(--surface);
}
body.theme-dark .customer-kind {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .customer-kind.server {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .customer-kind.vm {
  background: var(--surface-2);
  color: var(--text);
}
body.theme-dark .customer-kind.network {
  background: var(--ok-soft);
  color: var(--text);
}
body.theme-dark .customer-rack {
  background: var(--surface);
}
body.theme-dark .customer-rack:hover {
  border-color: var(--border);
}
body.theme-dark .customer-rack-share b {
  color: var(--warn);
}
body.theme-dark .aging-stat-card i {
  background: var(--surface-2);
}
body.theme-dark .aging-warning {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .aging-critical {
  background: var(--danger-soft);
  color: var(--danger);
}
body.theme-dark .handover-float {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .handover-float header b {
  color: var(--text);
}
body.theme-dark .handover-float-line {
  color: var(--text);
}
body.theme-dark .handover-float-summary {
  color: var(--text);
}
body.theme-dark .handover-state.is-waiting {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .handover-state.is-done {
  background: var(--surface);
  color: var(--ok);
}
body.theme-dark .asset-history {
  background: var(--surface);
}
body.theme-dark .asset-history-row {
  background: var(--surface);
}
body.theme-dark .asset-history-row:not(.is-flat):hover {
  background: var(--surface);
}
body.theme-dark .asset-history-id {
  color: var(--text);
}
body.theme-dark .asset-history-kind.is-task {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .asset-history-kind.is-incident {
  background: var(--danger-soft);
  color: var(--danger);
}
body.theme-dark .asset-history-kind.is-dispatch {
  background: var(--surface);
  color: var(--ok);
}
body.theme-dark .asset-history-kind.is-check {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .asset-history-kind.is-urgent {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .login-log-ip {
  color: var(--text);
}
body.theme-dark .login-log-kind.is-ok {
  background: var(--surface);
  color: var(--ok);
}
body.theme-dark .login-log-kind.is-fail {
  background: var(--danger-soft);
  color: var(--danger);
}
body.theme-dark .login-log-kind.is-warn {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .login-log-kind.is-muted {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .shift-chain {
  background: var(--surface);
}
body.theme-dark .shift-chain-next {
  color: var(--text);
}
body.theme-dark .shift-chain-card {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .shift-chain-code {
  color: var(--text);
}
body.theme-dark .shift-chain-team {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .shift-chain-mine {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .shift-chain-time {
  color: var(--text);
}
body.theme-dark .shift-chain-who {
  color: var(--text);
}
body.theme-dark .shift-chain-empty {
  color: var(--danger);
}
body.theme-dark .shift-chain-flag {
  background: var(--accent-soft);
  color: var(--text);
}
body.theme-dark .shift-chain-card.is-now {
  background: var(--surface);
}
body.theme-dark .shift-chain-card.is-empty {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .shift-chain-note {
  border-color: var(--border);
}
body.theme-dark .shift-chain-note b {
  color: var(--text);
}
body.theme-dark .standby-band {
  border-color: var(--border);
}
body.theme-dark .standby-label {
  color: var(--warn);
}
body.theme-dark .standby-chip {
  background: var(--surface);
  color: var(--warn);
  border-color: var(--border);
}
body.theme-dark .standby-chip.is-open {
  background: var(--surface);
  color: var(--danger);
}
body.theme-dark .standby-kind {
  background: var(--surface);
  color: var(--text);
}
body.theme-dark .standby-kind.is-standby {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .shift-chain-main {
  background: var(--surface);
}
body.theme-dark .shift-chain-side {
  background: var(--surface);
}
body.theme-dark .shift-chain-side > strong {
  color: var(--text);
}
body.theme-dark .shift-chain-side > div {
  border-color: var(--border);
}
body.theme-dark .shift-chain-side b {
  color: var(--text);
}
body.theme-dark .site-clocks {
  background: var(--surface);
}
body.theme-dark .site-clock {
  background: var(--surface);
}
body.theme-dark .site-clock header b {
  color: var(--text);
}
body.theme-dark .site-clock strong {
  color: var(--text);
}
body.theme-dark .site-clock-date {
  color: var(--text);
}
body.theme-dark .shift-chain-side.is-waiting {
  background: var(--surface);
  border-color: var(--border);
}
body.theme-dark .shift-chain-side.is-waiting .shift-chain-standing {
  background: var(--warn-soft);
  color: var(--warn);
}
body.theme-dark .shift-chain-side.is-late {
  background: var(--surface);
}
body.theme-dark .shift-chain-side.is-late > strong {
  color: var(--danger);
}
body.theme-dark .shift-chain-side.is-late .shift-chain-standing {
  background: var(--danger-soft);
  color: var(--danger);
}
/* App-only world clocks. The shared topbar/date typography stays in vlan24-ui.css.
   Use one flexible spacer, then keep clocks beside the date and account controls. */
.world-clocks {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  margin-left: auto;
}
.world-clock {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  padding: var(--s-1) var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
}
.world-clock-label {
  min-width: 0;
}
.world-clock-flag {
  flex: 0 0 var(--s-5);
  width: var(--s-5);
  height: calc(var(--s-5) * 0.75);
  border-radius: 0;
  object-fit: contain;
}
.world-clock-flag.is-text {
  display: grid;
  place-items: center;
  background: var(--surface-hover);
  color: var(--text-muted);
  font: 600 var(--fs-micro) var(--sans);
}
.world-clock b {
  display: block;
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-size: var(--fs-micro);
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.world-clock small {
  display: block;
  overflow: hidden;
  color: var(--text-muted);
  font: var(--fs-micro) var(--mono);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.world-clock-move {
  flex: 0 0 var(--s-6);
  width: var(--s-6);
  height: var(--s-6);
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-body);
  line-height: 1;
  cursor: pointer;
}
.world-clock-move:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.world-clock-row {
  gap: var(--s-2);
}
.world-clock-row > .input,
.world-clock-row > .select {
  flex: 1;
}
.world-clock-preview {
  display: flex;
  flex: 0 0 var(--s-5);
}
.world-clock-country {
  flex: 0 0 62px !important;
  text-align: center;
  text-transform: uppercase;
}
@media (min-width: 1081px) {
  .world-clocks + .top-actions {
    margin-left: 0;
  }
}
@media (max-width: 1280px) {
  .world-clocks .world-clock:nth-child(n + 2) {
    display: none;
  }
}
@media (max-width: 1080px) {
  .world-clocks {
    display: none;
  }
}
body.theme-dark .coverage-dot {
  background: var(--accent-soft);
}
body.theme-dark .coverage-onair.is-gap {
  color: var(--danger);
}
body.theme-dark .coverage-totals .is-gap b {
  color: var(--danger);
}
body.theme-dark .runbook-editor-block-remove:hover {
  color: var(--danger);
}
body.theme-dark .runbook-editor-step-remove:not(:disabled):hover {
  color: var(--danger);
}
body.theme-dark button.inventory-total:hover {
  background: var(--surface);
}
body.theme-dark .inventory-total.active {
  background: var(--surface);
}

/* 남은 시간 카드. styles.css 에서는 남색 판에 흰 글씨였는데, 바탕만 밝게 덮는 바람에 흰
   카드에 흰 글씨가 됐다. 글자색까지 토큰으로 다시 적는다 — 바탕을 바꿀 때는 그 위에 얹힌
   글자색도 같이 봐야 한다.

   판을 뒤집지 않는 이유는 다크 모드 때문이다. 밝은 판에서만 통하는 강조는 어두운 판에서
   두 번 뒤집혀 원래대로 돌아온다. 강조는 색이 아니라 숫자 크기로 준다. */
.shift-countdown {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text);
  padding: var(--s-4);
}
.shift-countdown > span {
  color: var(--text-faint);
  font: 560 var(--fs-micro) var(--sans);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.shift-countdown > strong {
  color: var(--text);
}
.shift-countdown > p,
.shift-countdown small {
  color: var(--text-muted);
}
.shift-countdown > div {
  border-top: 1px solid var(--divider);
}
.shift-countdown b {
  color: var(--text);
}

/* 즐겨찾기 별. 사이드바에서 유일하게 금색이던 것 — 티켓 아이콘과 같은 이유로 눈에 먼저
   들어왔다. 켜진 별만 강조색으로 두고 나머지는 회색으로 둔다. */
.nav button .fav-star {
  color: var(--text-faint);
  opacity: 0.55;
}
.nav button .fav-star:hover {
  color: var(--accent);
  opacity: 1;
}
.nav button .fav-star.on {
  color: var(--accent);
  opacity: 1;
}

/* ── 세로 띠를 걷어낸다 ───────────────────────────────────────────────────

   숫자 타일은 칸막이로 나누고, 알림 줄은 왼쪽에 강조선을 세워 두었다. 둘 다 화면의 다른
   어디에도 없는 장치였다 — 표는 가로선으로만 나뉘고 카드는 테두리 하나로 끝난다. 그래서
   이 두 줄만 다른 화면에서 온 것처럼 보였다.

   숫자 타일은 카드 다섯 장으로 바꾸고, 알림 줄은 여느 카드와 같은 테두리만 두른다. 강조는
   선이 아니라 앞에 찍는 점 하나로 준다 — 점은 글자와 같은 줄에 있으므로 카드의 모양을
   건드리지 않는다. */
.stat-strip,
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)) !important;
  gap: var(--s-3);
  background: transparent;
  border: 0;
  border-radius: 0;
  overflow: visible;
  margin-bottom: var(--s-3);
}
.stat-tile,
.kpi {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--s-3) var(--s-4);
  min-height: 0;
  transform: none;
}
.stat-tile:first-child,
.kpi:first-child {
  border-left: 1px solid var(--border);
}
.stat-tile:hover,
.kpi:hover {
  background: var(--surface);
  border-color: var(--border-strong);
  transform: none;
}
.stat-tile.is-selected {
  border-color: var(--accent);
  background: var(--surface);
}

.alert {
  border-left: 1px solid var(--border);
  border-radius: var(--radius-lg);
  gap: var(--s-3);
}
.alert.critical,
.alert.warning {
  border-left-color: var(--border);
}
/* 무슨 알림인지는 점 하나로 말한다. 기본은 강조색, 위험한 것은 빨강. */
.alert > span:first-child::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: 0.1em;
}
.alert.critical > span:first-child::before {
  background: var(--danger);
}
.alert.warning > span:first-child::before {
  background: var(--warn);
}

/* 작은 화면에서도 같은 규칙이 되도록, 앞서 칸막이에 맞춰 두었던 것을 거둔다. */
@media (max-width: 760px) {
  .stat-strip,
  .kpi-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
  .stat-tile,
  .kpi,
  .stat-tile:nth-child(odd),
  .kpi:nth-child(odd),
  .stat-tile:nth-child(-n + 2),
  .kpi:nth-child(-n + 2) {
    border: 1px solid var(--border);
  }
}

/* ── 탭 ───────────────────────────────────────────────────────────────────
   설정·리포트·현장작업이 저마다 다른 탭을 갖고 있었다. 하나로 맞춘다 — 밑줄 하나로
   지금 위치를 말하고, 상자를 만들지 않는다. 설정 탭의 그림(📅 🏷️ 🌴 …)은 걷어냈다.
   열 개가 나란히 서는 자리라 그림이 붙으면 한국어 이름이 두 줄로 접혔다. */
.tabs {
  gap: var(--s-4);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--s-4);
  overflow-x: auto;
}
.tabs button {
  padding: var(--s-2) 2px;
  color: var(--text-muted);
  font: 450 var(--fs-callout) var(--sans);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color var(--t-fast);
}
.tabs button:hover {
  color: var(--text);
}
.tabs button.active {
  color: var(--text);
  font-weight: 560;
  border-bottom-color: var(--accent);
}

/* 리포트 주제 탭은 세 장짜리라 상자를 유지하되, 카드와 같은 규칙으로 맞춘다.
   번호(01·02·03)는 남긴다 — 이 셋은 실제로 보고서의 1·2·3장이다. */
.report-topic-tabs {
  gap: var(--s-3);
  margin-bottom: var(--s-4);
}
.report-topic-tabs button {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text-secondary);
  padding: var(--s-3) var(--s-4);
  box-shadow: none;
  transition:
    border-color var(--t-fast),
    color var(--t-fast);
}
.report-topic-tabs button span {
  color: var(--text-faint);
  font: 500 var(--fs-micro) var(--mono);
}
.report-topic-tabs button:hover {
  border-color: var(--border-strong);
  color: var(--text);
}
.report-topic-tabs button.active {
  border-color: var(--accent);
  background: var(--surface);
  color: var(--text);
  box-shadow: none;
  font-weight: 560;
}
.report-topic-tabs button.active span {
  color: var(--accent);
}

/* 리포트·휴가의 숫자 카드도 대시보드 타일과 같은 규칙으로. */
.report-hero-kpis article,
.report-kpi-grid article,
.leave-summary > div,
.handover-summary-strip article,
.dispatch-summary article {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--s-3) var(--s-4);
  min-height: 0;
}
.report-hero-kpis strong,
.report-kpi-grid strong,
.leave-summary strong {
  color: var(--text);
  font: 600 var(--fs-display)/1.15 var(--sans);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.report-hero-kpis span,
.report-kpi-grid span,
.leave-summary span {
  color: var(--text-muted);
  font-size: var(--fs-caption);
}
.report-hero-kpis .urgent strong,
.report-kpi-grid .attention strong {
  color: var(--warn);
}
.report-hero-kpis .danger strong,
.report-kpi-grid .fault strong {
  color: var(--danger);
}
.report-hero-kpis small {
  position: static;
  display: block;
  margin-top: 2px;
  color: var(--text-faint);
}
.report-visual-panel {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.report-visual-panel > header {
  border-bottom: 1px solid var(--divider);
  padding: var(--s-3) var(--s-4);
}
.report-period {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--s-3) var(--s-4);
}

/* 업무가 어디서 왔는지 알리는 배지. 그림(🎫 ✉)을 빼고 글자만 남겼으므로 배지 모양을 준다. */
.triage-source-badge {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-muted);
  font: 500 var(--fs-micro) var(--sans);
  letter-spacing: 0;
}
/* 긴급은 뜻이 있는 표시라 남기되, 색이 박힌 그림 대신 상태 배지로 말한다. */
.field-emergency-icon {
  margin-left: 6px;
  vertical-align: 1px;
}

/* ── 앞 판이 남긴 것들 ────────────────────────────────────────────────────

   1. 설정 탭은 고른 것을 남색 상자로 칠하고 있었다(.settings-tabs button.active). 밑줄
      규칙만 덮고 배경은 그대로 둔 탓에, 남색 판 위에 새 글자색(거의 검정)이 얹혀 글씨가
      안 보였다. 배경까지 함께 거둔다 — 색을 바꿀 때는 그 위에 얹힌 것도 같이 봐야 한다.
   2. 사이드바 이름 두 번째 줄(Operations)은 어두운 기둥에 맞춘 연한 하늘색이었다. 기둥이
      밝아졌으니 바탕에 묻힌다.
   3. 탭이 화면마다 셋이었다 — 설정은 상자, 현장작업은 알약, 나머지는 밑줄. 안쪽 여백이
      제각각이라 탭의 첫 글자가 화면 제목과 어긋나 보였다. 하나로 맞춘다. */

.brand b {
  color: var(--text);
  font-size: var(--fs-body);
  font-weight: 620;
  letter-spacing: -0.015em;
}
.brand span {
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-weight: 450;
  letter-spacing: 0;
}

/* 탭 한 벌. 밑줄로 지금 위치를 말하고, 글자는 화면 제목과 같은 선에서 시작한다. */
.tabs,
.settings-tabs,
.field-work-tabs,
.page-actions .field-work-tabs {
  display: flex;
  width: auto;
  gap: var(--s-4);
  padding: 0;
  margin: 0 0 var(--s-4);
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
  overflow-x: auto;
}
.tabs button,
.settings-tabs button,
.field-work-tabs button,
.page-actions .field-work-tabs button {
  flex: none;
  min-width: 0;
  padding: var(--s-2) 2px;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--text-muted);
  font: 450 var(--fs-callout) var(--sans);
  letter-spacing: 0;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--t-fast);
}
.tabs button:hover,
.settings-tabs button:hover,
.field-work-tabs button:hover,
.page-actions .field-work-tabs button:hover {
  background: transparent;
  color: var(--text);
}
.tabs button.active,
.settings-tabs button.active,
.field-work-tabs button.active,
.page-actions .field-work-tabs button.active {
  background: transparent;
  border-color: transparent;
  border-bottom: 2px solid var(--accent);
  color: var(--text);
  font-weight: 560;
}
body.theme-dark .settings-tabs button.active,
body.theme-dark .field-work-tabs button.active,
body.theme-dark .settings-tabs button:hover,
body.theme-dark .field-work-tabs {
  background: transparent;
  color: var(--text);
  border-color: transparent;
}
body.theme-dark .settings-tabs button.active,
body.theme-dark .field-work-tabs button.active {
  border-bottom-color: var(--accent);
}
/* 현장작업 탭은 머리줄 오른쪽에 있어, 밑줄만 남기면 선이 화면을 가로지른다. */
.page-actions .field-work-tabs {
  border-bottom: 0;
  margin: 0;
  gap: var(--s-3);
}

/* ── 달력 ─────────────────────────────────────────────────────────────────

   1. 년·월 고르개가 잘려 "202⌄" 로 보였다. 앞 판이 안쪽 여백을 8px 로 줄여 놓았는데 새
      고르개는 오른쪽 26px 을 화살표 자리로 쓰므로, 글자가 그 밑으로 밀려 들어갔다.
   2. 근무 칸의 이름이 한 줄에 눌려 잘렸다. 창을 키워야 이름이 보이는 것은 화면이 할 일을
      사람에게 떠넘기는 것이다. 근무 코드·시각을 윗줄로 올리고 이름은 아랫줄에서 줄바꿈해
      다 보여 준다.
   3. 주 단위 폭을 더했다. 같은 일곱 칸에 7일만 들어가니 칸이 세로로 길어지고, 이름과 휴가·
      비상대기가 잘리지 않는다. */
.calendar-navigator {
  display: flex;
  align-items: center;
  gap: 6px;
  width: auto;
  flex-wrap: wrap;
}
.calendar-navigator .select {
  flex: none;
  width: auto;
  min-width: 84px;
  height: 27px;
  min-height: 27px;
  padding: 0 26px 0 var(--s-2);
  font-size: var(--fs-caption);
  background-position:
    calc(100% - 14px) 12px,
    calc(100% - 9px) 12px;
}
.calendar-week-range {
  margin-left: var(--s-2);
  font-family: var(--mono);
}
.calendar-span-toggle {
  display: inline-flex;
  gap: 4px;
}
.calendar-panel-head {
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
}

.cal-cell {
  min-height: 112px;
  padding: var(--s-2);
  border-color: var(--divider);
}
.calendar-grid {
  border-color: var(--border);
}
/* 주 단위. 칸 하나가 세로로 길어져 그날 있는 일이 다 들어간다. */
.calendar-grid.is-week .cal-cell {
  min-height: 380px;
}
.calendar-grid.is-week .cal-shift-members {
  white-space: normal;
}

.cal-shift-chip {
  display: block;
  padding: 4px 6px;
  margin: 3px 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-secondary);
  line-height: 1.35;
}
.cal-shift-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
}
.cal-shift-head b {
  font: 600 var(--fs-micro) var(--mono);
  letter-spacing: 0;
  color: var(--text);
}
.cal-shift-chip time {
  flex: none;
  font: 500 var(--fs-micro) var(--mono);
  color: var(--text-muted);
}
/* 이름은 두 줄까지 보이고 넘치면 자른다. 달 단위 칸에서 근무 셋이 각각 다섯 줄이 되면
   정작 그날 무슨 근무가 있는지가 안 보인다. 다 보려면 주 단위로 넓히거나 칩에 올리면 된다. */
.cal-shift-members {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 1px;
  font-size: var(--fs-micro);
  color: var(--text-secondary);
  word-break: keep-all;
}
.cal-shift-chip.work-kr {
  background: var(--accent-soft);
  border-color: var(--accent-border);
}
.cal-shift-chip.work-kr .cal-shift-head b {
  color: var(--accent);
}
.cal-shift-chip.work-us {
  background: var(--surface-2);
  border-color: var(--border);
}
.cal-leave-chip,
.cal-license-chip {
  display: block;
  margin: 3px 0;
  padding: 3px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-secondary);
  font-size: var(--fs-micro);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.calendar-grid.is-week .cal-leave-chip,
.calendar-grid.is-week .cal-license-chip {
  white-space: normal;
}
@media (max-width: 760px) {
  /* 좁은 화면에서는 주 단위가 더 낫다. 달 단위 칸이 손가락 너비보다 좁아지기 때문이다. */
  .calendar-grid.is-week .cal-cell {
    min-height: 180px;
  }
}

/* ── 업무 번호 칸 ─────────────────────────────────────────────────────────
   업무 번호는 TSK-20260917-002 처럼 열여섯 글자다. 예전 번호(TASK-812)에 맞춰 잡아 둔
   90px 칸에는 들어가지 않아, table-layout: fixed 인 표에서 두 줄로 접히거나 옆 칸으로
   흘러넘쳤다.

   번호는 끊어 읽을 곳이 없는 한 덩어리라 줄바꿈으로 해결할 수 없다. 칸을 번호에 맞춘다.
   좁은 화면에서도 같다 — 표는 table-wrap 안에서 가로로 밀리므로 칸을 줄일 이유가 없고,
   줄이면 그때부터 번호가 다시 넘친다. */
.task-id,
td.task-id,
.customer-number {
  white-space: nowrap;
}
.handover-task-table th:nth-child(2),
.handover-candidate-table th:nth-child(2),
.dashboard-grid .task-list th:nth-child(2) {
  width: 132px;
}

/* ── 팀 그룹 ─────────────────────────────────────────────────────────────
   팀 고르기는 단추 줄에서 목록 하나로 바뀌었다(app.js teamFilterPicker). 단추 줄에 맞춰
   두었던 settings-team-picker 의 간격이 남아 있으면 목록 앞에 빈자리가 생긴다. */
.settings-team-picker {
  margin-right: 0;
}
/* 팀 고르기. <details> 가 여닫고, 펼친 판은 흐름에서 띄워 표 위에 얹는다 — 흐름에
   남겨 두면 판을 펼칠 때마다 달력이 아래로 밀린다. */
.team-scope {
  position: relative;
  display: inline-block;
}
.team-scope > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  list-style: none;
  cursor: pointer;
}
.team-scope > summary::-webkit-details-marker {
  display: none;
}
.team-scope > summary::after {
  content: '';
  width: 5px;
  height: 5px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-1px) rotate(45deg);
}
.team-scope[open] > summary::after {
  transform: translateY(1px) rotate(225deg);
}
.team-scope-panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 4px);
  left: 0;
  min-width: 220px;
  max-height: 60vh;
  overflow: auto;
  padding: var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-pop);
}
.team-pick {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 5px var(--s-2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-callout);
  cursor: pointer;
}
.team-pick:hover {
  background: var(--surface-hover);
}
.team-pick input {
  flex: none;
  margin: 0;
}
.team-pick.is-group {
  font-weight: 560;
}
.team-pick-group {
  padding-top: var(--s-2);
  margin-top: var(--s-2);
  border-top: 1px solid var(--divider);
}
.team-pick-group > b {
  display: block;
  padding: 0 var(--s-2) 3px;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.calendar-team-scope {
  display: inline-flex;
  align-items: center;
}
/* 좁은 화면에서는 판이 화면 밖으로 나가지 않게 오른쪽 기준으로 붙인다. */
@media (max-width: 760px) {
  .team-scope-panel {
    left: auto;
    right: 0;
  }
}

/* 설정의 팀 목록. 그룹 이름은 줄마다 되풀이하지 않고 묶음 머리글로 한 번만 적는다. */
.team-group + .team-group {
  margin-top: var(--s-4);
}
.team-group-head {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  padding-bottom: var(--s-2);
  margin-bottom: var(--s-1);
  border-bottom: 1px solid var(--divider);
}
.team-group-head h3 {
  margin: 0;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ── 사용자 권한 · 고른 사람 ───────────────────────────────────────────────
   고른 사람을 고치는 자리와 그 아래 권한 표가 같은 바탕에 붙어 있어, 어디까지가 "이 사람의
   역할과 상태" 이고 어디부터가 "권한 목록" 인지 읽히지 않았다. 고치는 자리를 한 덩어리로
   띄우고 그 아래를 비워 가른다.

   '역할' 이 세로로 쪼개지던 것도 여기서 온다. 라벨과 목록이 한 줄(flex)인데 목록이 폭을
   100% 로 가져가면서 라벨에 글자 하나 너비만 남았다. 목록을 제 내용만큼만 차지하게 한다. */
.access-editor-head {
  align-items: flex-start;
  gap: var(--s-3) var(--s-4);
  padding: var(--s-3);
  margin-bottom: var(--s-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
}
.access-editor-controls {
  gap: var(--s-2) var(--s-3);
}
.access-editor-controls label {
  white-space: nowrap;
  color: var(--text-secondary);
  font-weight: 500;
}
.access-editor-controls .select {
  width: auto;
  min-width: 132px;
  flex: none;
}
.access-editor-head + .meta {
  margin: 0 0 var(--s-4);
}
/* 권한 표는 묶음마다 제목을 이고 있다. 묶음 사이가 붙어 있으면 그 제목이 앞 표의 마지막
   줄처럼 읽힌다. */
.access-category + .access-category {
  margin-top: var(--s-4);
}

/* ── 특별 근무 · 월 비상대기 ──────────────────────────────────────────────
   특별 근무는 "이 날만 그런 것" 이다. 템플릿 근무와 똑같이 그리면 달력을 보고 근무표가
   바뀐 줄 알게 되므로, 같은 줄 모양을 쓰되 왼쪽에 표시를 남기고 바탕을 비운다. */
.cal-shift-chip.is-extra {
  background: transparent;
  border-color: var(--warn-border);
  border-left-width: 3px;
  border-left-color: var(--warn);
}
.cal-shift-chip.is-extra .cal-shift-head b {
  color: var(--warn);
}
/* 비상대기는 날짜 칸에서 빼 머리글 오른쪽에 모은다. 한 달 당번은 그 달 내내 같은 사람이라
   칸마다 적으면 서른 번 같은 이름을 읽게 된다. */
.calendar-shiftless {
  flex-basis: 100%;
}
.standby-panel {
  margin-left: auto;
  display: grid;
  gap: 4px;
  justify-items: end;
  padding: 6px var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
}
.standby-panel h3 {
  margin: 0;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.standby-panel.is-empty {
  background: transparent;
}
.standby-panel-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
  justify-content: flex-end;
}
.standby-panel-row.is-exceptions {
  padding-top: 4px;
  border-top: 1px solid var(--divider);
}
.standby-duty-chip,
.standby-exception-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 7px;
  border: 1px solid var(--warn-border);
  border-radius: var(--radius-pill);
  background: var(--warn-soft);
  color: var(--text);
  font-size: var(--fs-caption);
  white-space: nowrap;
}
.standby-duty-chip b,
.standby-exception-chip b {
  font-family: var(--mono);
  font-size: var(--fs-micro);
  color: var(--text-secondary);
}
/* 날짜별 예외는 당번보다 약하게. 당번이 그 달의 기본이고 이쪽이 덧붙는 것이다. */
.standby-exception-chip {
  border-color: var(--border);
  background: var(--surface);
  color: var(--text-secondary);
}
.standby-exception-chip.is-more {
  border-style: dashed;
}
@media (max-width: 900px) {
  .standby-panel {
    margin-left: 0;
    justify-items: start;
  }
  .standby-panel-row {
    justify-content: flex-start;
  }
}
/* 월 당번 표는 달 × 팀이다. 달 칸만 붙여 두고 나머지는 단추가 폭을 정한다. */
.standby-duty-table th:first-child,
.standby-duty-table td:first-child {
  width: 120px;
  white-space: nowrap;
}

/* ── 고객 포털 계정 · 고객사 단위 ─────────────────────────────────────────
   계정 줄을 늘어놓던 화면을 고객사로 묶었다. 한 고객사에 담당자가 둘셋 있고 그 셋에게
   보여 줄 자산은 하나인데, 계정 줄마다 자산 체크박스를 두면 같은 것을 세 번 정하게 된다. */
.customers-page {
  width: 100%;
  max-width: 1480px;
}
.customer-main-tabs,
.ticket-work-tabs {
  margin-bottom: var(--s-4);
}
.customer-main-tabs .badge,
.ticket-work-tabs .badge {
  margin-left: 4px;
}
.ticket-search-toolbar {
  gap: var(--s-3);
}
.ticket-search-toolbar .search {
  flex: 1;
  width: auto;
  min-width: 0;
}
.ticket-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-6);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--divider);
  background: var(--bg-sunken);
}
.ticket-filter-group {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  min-width: 0;
  gap: var(--s-2);
}
.ticket-filter-group > .meta {
  font-weight: 600;
}
.ticket-filter-group .filters {
  flex-wrap: wrap;
  padding: 0;
  border: 0;
  gap: var(--s-1);
}
@media (max-width: 600px) {
  .ticket-filter-group {
    width: 100%;
  }
  .ticket-filter-group > .meta {
    flex: 0 0 100%;
  }
}
.customer-workspace {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  align-items: start;
  gap: var(--s-4);
}
.customer-workspace-main {
  min-width: 0;
}
.customer-workspace-rail {
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
  max-height: calc(100vh - var(--topbar-h) - var(--s-8));
  overflow: hidden;
}
.customer-workspace-rail .input {
  width: 100%;
  margin: var(--s-2) 0;
}
.customer-rail-list {
  max-height: calc(100vh - var(--topbar-h) - 150px);
  overflow-y: auto;
}
.empty.compact {
  min-height: 0;
  padding: var(--s-6) var(--s-4);
}
.cportal-customer-tab {
  display: grid;
  gap: var(--s-4);
}
.cportal-section-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-3);
}
.cportal-section-head h2 {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.cportal-subsection {
  padding: var(--s-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.cportal-credential-result {
  display: grid;
  grid-template-columns: minmax(210px, 0.8fr) minmax(180px, 0.7fr) minmax(260px, 1.2fr) auto;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--warn-border);
  border-radius: var(--radius);
  background: var(--warn-soft);
}
.cportal-credential-result > div {
  display: grid;
  gap: 2px;
}
.cportal-person-form {
  display: grid;
  gap: var(--s-4);
}
.cportal-person-form > label,
.cportal-person-fields > label,
.cportal-person-options > label:not(.todo) {
  display: grid;
  gap: 4px;
  font-size: var(--fs-micro);
  color: var(--text-muted);
}
.cportal-person-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-3);
}
.cportal-person-options {
  display: flex;
  align-items: end;
  gap: var(--s-4);
}
.cportal-customer-list {
  display: grid;
  gap: var(--s-2);
}
.cportal-active-customers,
.cportal-quiet-customers {
  display: grid;
  gap: var(--s-2);
}
.cportal-customer {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
}
.cportal-customer.is-open {
  border-color: var(--border-strong);
}
.cportal-customer-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  padding: 10px var(--s-3);
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: var(--text);
}
.cportal-customer-head:hover {
  background: var(--surface-hover);
}
.cportal-customer-name {
  font-weight: 560;
  min-width: 0;
  overflow-wrap: anywhere;
}
/* 펼침 표시는 오른쪽 끝에 고정한다. 가운데 meta 가 길어져도 자리가 흔들리지 않는다. */
.cportal-customer-mark {
  margin-left: auto;
  flex: none;
  width: 18px;
  text-align: center;
  font-family: var(--mono);
  color: var(--text-muted);
}
.cportal-customer-body {
  padding: 0 var(--s-3) var(--s-3);
  border-top: 1px solid var(--divider);
}
.cportal-customer-body h3 {
  margin: var(--s-4) 0 var(--s-2);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* 계정과 연결 연락처를 한 행에서 관리한다. 로그인 없는 수동 연락처도 같은 표에 둔다. */
.cportal-contact-summary {
  margin-bottom: var(--s-2);
}

.cportal-contacts .table {
  margin-bottom: var(--s-2);
  min-width: 1100px;
}
.cportal-people-scroll {
  max-width: 100%;
  overflow-x: auto;
}
.cportal-contacts .table th,
.cportal-contacts .table td,
.cportal-contact-actions .button {
  white-space: nowrap;
}
.cportal-contact-actions .meta,
.cportal-contact-actions .cportal-role-editor {
  white-space: normal;
}

.cportal-contacts tr.is-muted {
  opacity: 0.62;
}

.cportal-contacts [data-contact-row] .input {
  min-width: 130px;
  margin-bottom: 4px;
}

.cportal-role-editor {
  min-width: 0;
  max-width: 360px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-align: left;
  white-space: normal;
}
.cportal-role-editor label {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.cportal-role-editor p {
  margin: 8px 0;
  overflow-wrap: anywhere;
}
.cportal-role-editor .row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.cportal-role-label {
  display: inline-block;
  margin-left: 8px;
  white-space: nowrap;
}

.cportal-contact-actions {
  text-align: right;
  white-space: nowrap;
}

.cportal-contact-new {
  display: grid;
  grid-template-columns:
    minmax(120px, 1fr) minmax(100px, 0.7fr) minmax(180px, 1.35fr)
    minmax(160px, 1fr) auto auto;
  align-items: end;
  gap: var(--s-2);
  margin-top: var(--s-2);
  padding: var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}

.cportal-contact-new > label:not(.todo) {
  display: grid;
  gap: 4px;
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

.cportal-contact-new .todo {
  align-self: center;
  white-space: nowrap;
}

/* 계정 초대도 고객 관리 화면의 기존 panel/table/input 체계를 그대로 쓴다. 링크 결과와 발급 폼은
   정보 밀도만 맞추고 별도의 색상이나 카드 규칙을 만들지 않는다. */
.cportal-invite-form {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) minmax(220px, 1.4fr) 110px auto;
  align-items: end;
  gap: var(--s-2);
  margin-bottom: var(--s-4);
}

.cportal-invite-form > label {
  display: grid;
  gap: 4px;
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

.cportal-invite-result {
  display: grid;
  grid-template-columns: minmax(220px, 0.9fr) minmax(280px, 1.4fr) auto auto;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-4);
  padding: var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--accent-soft);
}

.cportal-invite-table {
  margin-top: var(--s-2);
}

.cportal-interactions {
  display: grid;
  gap: var(--s-3);
}

.cportal-interaction-test {
  display: grid;
  grid-template-columns: 100px 100px minmax(180px, 1.2fr) minmax(160px, 1fr) minmax(200px, 1.4fr) 80px auto;
  align-items: end;
  gap: var(--s-2);
  padding: var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}

.cportal-interaction-test > label {
  display: grid;
  gap: 4px;
  min-width: 0;
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

.cportal-eml-picker {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.cportal-unmatched-action {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 360px;
}

.cportal-unmatched-action .select {
  min-width: 160px;
}

.cportal-eml-picker [data-eml-filename] {
  min-width: 0;
  flex: 1;
  overflow-wrap: anywhere;
}

.cportal-eml-result {
  display: grid;
  gap: var(--s-3);
  margin-top: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}

.cportal-eml-result > div {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.cportal-eml-result dl {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-2) var(--s-4);
  margin: 0;
}

.cportal-eml-result dl > div {
  min-width: 0;
}

.cportal-eml-result dt {
  margin-bottom: 3px;
  color: var(--text-muted);
  font-size: var(--fs-micro);
}

.cportal-eml-result dd {
  margin: 0;
  overflow-wrap: anywhere;
  font-size: var(--fs-callout);
}

@media (max-width: 1100px) {
  .customer-workspace {
    grid-template-columns: minmax(0, 1fr);
  }
  .customer-workspace-rail {
    position: static;
    max-height: none;
  }
  .customer-rail-list {
    display: flex;
    max-height: none;
    gap: var(--s-2);
    overflow-x: auto;
  }
  .customer-rail-list .inventory-rail-item {
    min-width: 180px;
  }
  .cportal-contact-new,
  .cportal-invite-form,
  .cportal-invite-result,
  .cportal-interaction-test {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .cportal-eml-result dl {
    grid-template-columns: minmax(0, 1fr);
  }
  .cportal-credential-result {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 720px) {
  .cportal-section-head,
  .cportal-person-options {
    align-items: stretch;
    flex-direction: column;
  }
  .cportal-person-fields {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* 자산 고르개. 한 고객사에 수백 대가 붙는 경우가 있어 종류로 묶고 검색을 둔다. */
.cportal-assets .toolbar {
  padding-left: 0;
  padding-right: 0;
  border: 0;
}
.cportal-asset-group {
  margin-top: var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.cportal-asset-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  padding: 6px var(--s-2);
  background: var(--surface-2);
  border-bottom: 1px solid var(--divider);
}
.cportal-asset-head .meta {
  margin-left: auto;
}
.cportal-asset-row {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  margin: 0;
  padding: 5px var(--s-2);
  font-size: var(--fs-callout);
}
.cportal-asset-row:hover {
  background: var(--surface-hover);
}
/* 모델·위치는 오른쪽으로. 이름이 왼쪽에 줄줄이 붙어 있어야 눈이 한 줄로 내려가며 찾는다. */
.cportal-asset-row .meta {
  margin-left: auto;
  text-align: right;
}
.cportal-asset-head input,
.cportal-asset-row input {
  flex: none;
  margin: 0;
}

/* 자산 줄에서 «이 장비는 어느 서비스인가» 를 고르는 칸.

   줄 끝에 둔다. 이름 → 모델·위치 → 서비스 순으로 읽히고, 여러 줄을 훑을 때 서비스만 세로로
   따라 내려갈 수 있다. 폭을 고정하는 이유는, 서비스 이름 길이에 따라 칸이 들쭉날쭉하면
   그 세로줄이 깨지기 때문이다. */
.cportal-asset-service {
  flex: none;
  width: 168px;
  height: 24px;
  padding: 0 var(--s-2);
  font-size: var(--fs-caption);
}

/* 종류 머리글의 것은 «이 묶음 통째로» 라 조금 더 눈에 띄게 둔다. */
.cportal-asset-head .cportal-asset-service {
  margin-left: var(--s-2);
  border-color: var(--border-strong);
}

/* ── 받는 서비스 ─────────────────────────────────────────────────────────── */
.cportal-services table {
  margin-bottom: var(--s-2);
}

.cportal-services .input.sm {
  height: 26px;
  font-size: var(--fs-caption);
}

/* 네트워크 값은 줄글로 적는다. 칸을 나눠 만들지 않은 이유는 무엇을 적을지가 서비스마다
   다르기 때문이다 — 회선은 대역폭, 보호는 방어 용량. */
.cportal-service-net td {
  padding-top: 0;
  background: var(--surface-2);
}

.cportal-service-net textarea {
  width: 100%;
  font-family: var(--mono);
  font-size: var(--fs-caption);
  line-height: 1.6;
  resize: vertical;
}

.cportal-service-net .meta {
  display: block;
  margin: 2px 0;
}

/* 자산이 수십·수백 건일 때도 좌측에서 종류를 고르고 오른쪽 목록만 읽는다. */
.cportal-asset-browser {
  display: grid;
  grid-template-columns: 176px minmax(0, 1fr);
  gap: var(--s-3);
  margin-top: var(--s-3);
  min-height: 280px;
}
.cportal-asset-types {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-right: var(--s-3);
  border-right: 1px solid var(--divider);
}
.cportal-asset-types button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  width: 100%;
  padding: 7px 9px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-secondary);
  text-align: left;
}
.cportal-asset-types button:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.cportal-asset-types button.active {
  background: var(--accent-soft);
  color: var(--accent);
}
.cportal-asset-types button b {
  font-size: var(--fs-micro);
  font-weight: 600;
}
.cportal-asset-results {
  min-width: 0;
}
.cportal-asset-results .cportal-asset-group {
  margin-top: 0;
}

@media (max-width: 760px) {
  .cportal-asset-browser {
    grid-template-columns: 1fr;
  }
  .cportal-asset-types {
    flex-direction: row;
    overflow-x: auto;
    border-right: 0;
    padding-right: 0;
  }
  .cportal-asset-types button {
    width: auto;
    flex: none;
  }
}

/* 랙 도면 공개 스위치. 자산 체크박스들과 같은 부품으로 보이면 안 된다 — 그것들은 "이 자산을
   보여 준다" 이고 이것은 "그 자산을 어떻게 보여 준다" 라, 잘못 누르면 되돌리기 어려운 쪽이다. */
.cportal-asset-layout {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 2px var(--s-2);
  margin: var(--s-2) 0 var(--s-3);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}

.cportal-asset-layout b {
  font-size: var(--fs-callout);
  font-weight: 600;
}

.cportal-asset-layout .meta {
  grid-column: 2;
  line-height: 1.45;
}

/* 계정 없는 고객사를 펼치는 줄. 단추처럼 보이지 않게 둔다 — 여기서 할 일이 있는 사람은
   드물고, 눈에 띄면 «눌러야 하는 것» 으로 읽힌다. */
.cportal-quiet-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  margin-top: var(--s-2);
  padding: 6px 8px;
  border: 0;
  border-top: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-caption);
  text-align: left;
  cursor: pointer;
}

.cportal-quiet-toggle:hover {
  color: var(--text);
}

.cportal-quiet-toggle b {
  font-family: var(--mono);
}

/* ── 케이지 도면 ────────────────────────────────────────────────────────────

   도면이 주인공이다. 그래서 여기에는 카드도, 그림자도, 진한 색도 거의 없다 — 랙 네모와 그
   위에 적힌 번호가 가장 진하고, 바닥·격자·통로·벽은 그보다 몇 단 연하게 둔다. 색을 아끼는
   이유는 도면에서 눈에 띄는 것이 «급한 것» 이어야 하기 때문이다. 사용량으로 랙을 원색으로
   칠하면 꽉 찬 랙이 고장난 랙과 같은 무게로 보인다.

   격자는 편집할 때만 보인다. 늘 보이면 이 화면이 «배치를 보는 곳» 이 아니라 «바둑판에
   아이콘을 넣는 툴» 로 읽힌다 — 앞 판이 그랬다. */

.cage-workspace {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  container-type: inline-size;
  container-name: cage-workspace;
}

.cage-header {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--border);
}

.cage-header-title h2 {
  margin: 0;
}

.cage-header-title .meta {
  display: block;
}

.cage-header-title {
  min-width: 0;
  overflow-wrap: anywhere;
}

.cage-header-tools {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-left: auto;
  flex-wrap: wrap;
}

.cage-select {
  max-width: 220px;
}

.cage-find {
  width: 170px;
}

/* 편집 중이라는 것은 화면에서 한 번은 눈에 걸려야 한다. 모르고 옮겨 놓은 채 나가면 저장하지
   않은 변경이 사라지고, 저장했다면 남의 도면이 바뀐다. */
.cage-editing-flag {
  padding: 3px 8px;
  border: 1px solid var(--accent-border);
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 11px;
  font-weight: 600;
}

.cage-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 260px;
  gap: var(--s-4);
  align-items: stretch;
}

/* 도면 판. 페이지가 아니라 이 안에서 움직인다 — 확대한 도면을 보다가 페이지가 따라 움직이면
   도면이 화면에서 사라진다. */
.cage-canvas {
  position: relative;
  height: min(72vh, 780px);
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-sunken);
  cursor: grab;
}

.cage-canvas.is-panning,
.cage-canvas.is-panning .cage-obj {
  cursor: grabbing;
}
/* SVG g/text에는 touch-action이 적용되지 않는다. 선택 편집에서만 SVG 루트가 잡고,
   빈 곳은 pointer pan으로 민다. 보기 모드/다른 도구는 기본 스크롤을 유지한다. */
.cage-canvas.is-tool-select .cage-svg {
  touch-action: none;
}

.cage-canvas.is-drop-target {
  border-color: var(--accent);
}

.cage-workspace.is-editing .cage-canvas:not(.is-tool-select):not(.is-tool-rack) {
  cursor: crosshair;
}

.cage-svg {
  display: block;
  -webkit-user-select: none;
  user-select: none;
}

.cage-floor {
  fill: var(--surface);
}

.cage-outline {
  fill: none;
  stroke: var(--border-strong);
  stroke-width: 24;
}

.cage-grid-line {
  stroke: var(--border);
}

/* 랙. 위에서 내려다본 네모 하나. */
.cage-obj {
  cursor: pointer;
}

.cage-obj-rack .cage-rack-body {
  fill: var(--n-100);
  stroke: var(--n-500);
  stroke-width: 14;
}

/* 앞면과 뒷면. 한쪽만 굵게 칠해 보았더니 옆에 비교할 랙이 있어야 어느 쪽이 굵은지 알 수
   있었다 — 한 줄로 늘어선 랙이 다 같은 방향이면 비교할 대상이 없다. 그래서 앞면은 굵은 실선
   바, 뒷면은 얇은 점선으로 서로 다르게 그린다. 굵기를 견주지 않고 «실선인가 점선인가» 만
   보면 되므로 랙 한 대만 보고도 알 수 있다. */
.cage-obj-rack .cage-rack-front {
  fill: var(--n-700);
}

.cage-obj-rack .cage-rack-rear {
  stroke: var(--n-400);
  stroke-width: 26;
  stroke-dasharray: 70 60;
}

/* F·R 글자는 크게 볼 때만. 작게 볼 때는 뭉개져 읽히지도 않으면서 랙 이름과 자리를 다툰다. */
.cage-face-mark {
  font: 700 105px var(--mono);
  letter-spacing: 0;
}

.cage-face-mark.is-front {
  fill: var(--surface);
}

.cage-face-mark.is-rear {
  fill: var(--text-muted);
}

/* 크기 손잡이. 고른 물체의 오른쪽 아래 한 곳에만 둔다 — 네 귀퉁이에 다 달면 작은 랙 옆에서
   손잡이가 물체보다 커진다. */
.cage-handle {
  fill: var(--surface);
  stroke: var(--accent);
  stroke-width: 26;
  cursor: nwse-resize;
}

.cage-rack-name {
  font: 600 210px var(--sans);
  fill: var(--text);
}

.cage-rack-sub {
  font: 500 150px var(--mono);
  fill: var(--text-muted);
}

.cage-rack-gauge-bed {
  fill: var(--n-200);
}

.cage-rack-gauge {
  fill: var(--n-500);
}

/* 상태는 모서리 점 하나로만 말한다. 색은 운영 콘솔이 이미 쓰는 것을 그대로 쓴다 — 도면만의
   색 체계를 새로 만들면 같은 빨강이 다른 화면에서 다른 뜻이 된다. */
.cage-rack-dot {
  fill: var(--ok);
  stroke: var(--surface);
  stroke-width: 18;
}

.cage-obj-rack.is-empty .cage-rack-dot {
  fill: var(--n-400);
}

.cage-obj-rack.is-warning .cage-rack-dot {
  fill: var(--warn);
}

.cage-obj-rack.is-critical .cage-rack-dot {
  fill: var(--danger);
}

.cage-obj-rack.is-maintenance .cage-rack-dot {
  fill: var(--accent);
}

/* 인벤토리에 없는 랙. 지우지 않고 남겨 표시한다 — 조용히 사라지면 랙이 빠진 것인지 동기화가
   덜 된 것인지 알 수 없고, 그 자리가 비어 보인다. */
.cage-obj-rack.is-missing .cage-rack-body {
  stroke-dasharray: 60 40;
  stroke: var(--danger);
}

.cage-obj:hover .cage-rack-body {
  stroke: var(--text);
}

.cage-obj.is-picked > rect:first-of-type {
  stroke: var(--accent);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

/* 검색으로 찾아 간 랙. 번쩍이지 않는다 — 도면을 열어 두고 일하는 화면에서 움직이는 것이 하나
   있으면 그것만 보인다. */
.cage-obj.is-flash .cage-rack-body {
  stroke: var(--accent);
  stroke-width: 2;
}

.cage-obj.is-dragging {
  opacity: 0.75;
}

/* 통로·벽·출입구·글자. 도면의 주인공은 랙이므로 전부 랙보다 약하게 둔다. */
.cage-obj-aisle rect {
  fill: var(--bg-sunken);
  stroke: var(--border);
  stroke-width: 10;
  stroke-dasharray: 80 60;
}

.cage-obj-wall rect {
  fill: var(--n-600);
}

.cage-obj-door rect {
  fill: var(--surface);
  stroke: var(--text-muted);
  stroke-width: 14;
}

.cage-obj-text .cage-text-hit {
  fill: transparent;
}

.cage-area-label {
  font: 600 150px var(--sans);
  letter-spacing: 0.08em;
  fill: var(--text-muted);
  text-transform: uppercase;
}

.cage-plan-text {
  font: 600 190px var(--sans);
  fill: var(--text-muted);
}

/* Reference drawing: predictable lines and bounded labels, independent of zoom. */
.cage-svg .cage-rack-body {
  vector-effect: non-scaling-stroke;
  stroke-width: 1;
  fill: var(--surface-2);
}
.cage-svg .is-picked .cage-rack-body,
.cage-svg .is-flash .cage-rack-body,
.cage-svg .cage-obj-rack.has-incident .cage-rack-body {
  stroke-width: 2;
}
.cage-dimensions {
  pointer-events: none;
}
.cage-dimensions path {
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.cage-dimensions text {
  font: 500 150px var(--sans);
  fill: var(--text-muted);
}
.cage-door-threshold {
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 18;
  stroke-dasharray: 30 30;
  pointer-events: none;
}
.cage-plan-disclaimer {
  margin: 10px 0;
  line-height: 1.5;
}
.cage-arrange-list {
  display: grid;
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
  margin: 16px 0;
}
.cage-arrange-list label {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.cage-arrange-list span {
  min-width: 0;
  overflow-wrap: anywhere;
}
.cage-sheet-preview {
  max-height: 65vh;
  overflow: auto;
  border: 1px solid var(--border);
  background: white;
}
.cage-sheet-preview > svg {
  display: block;
  width: 100%;
  height: auto;
  min-width: 580px;
}

/* 진행 중 장애·작업. 랙 왼쪽 위에 점 하나와 건수만. 랙 전체를 빨갛게 칠하지 않는 이유는,
   그러면 도면이 «어디에 무엇이 있나» 를 말하지 못하고 경보판이 되기 때문이다 — 랙 이름을
   읽으러 온 눈이 색에 먼저 걸린다. */
.cage-rack-live {
  fill: var(--danger);
  stroke: var(--surface);
  stroke-width: 18;
}

.cage-obj-rack.has-maintenance .cage-rack-live {
  fill: var(--accent);
}

.cage-rack-live-count {
  font: 700 130px var(--mono);
  fill: var(--surface);
}

.cage-obj-rack.has-incident .cage-rack-body {
  stroke: var(--danger);
  stroke-width: 22;
}

/* 사용률 층. 신호등 색이 아니라 한 색의 짙기로만 칠한다 — 초록·노랑·빨강으로 칠하면 «꽉 찬
   랙» 이 «고장난 랙» 과 같은 뜻으로 읽힌다. 짙기는 순서만 말하므로 그 오해가 없다. */
.cage-obj-rack[class*='heat-'] .cage-rack-body {
  stroke: var(--accent-border);
}

.cage-obj-rack.heat-1 .cage-rack-body {
  fill: color-mix(in srgb, var(--accent) 8%, var(--surface));
}

.cage-obj-rack.heat-2 .cage-rack-body {
  fill: color-mix(in srgb, var(--accent) 22%, var(--surface));
}

.cage-obj-rack.heat-3 .cage-rack-body {
  fill: color-mix(in srgb, var(--accent) 38%, var(--surface));
}

.cage-obj-rack.heat-4 .cage-rack-body {
  fill: color-mix(in srgb, var(--accent) 58%, var(--surface));
}

.cage-obj-rack.heat-5 .cage-rack-body {
  fill: color-mix(in srgb, var(--accent) 80%, var(--surface));
}

/* 층이 무엇을 말하는지 적는 자리와 그 눈금. 색만 칠해 두면 짙은 쪽이 꽉 찬 것인지 빈 것인지
   사람마다 다르게 읽고, 그 한 번의 오해로 엉뚱한 랙에 장비를 넣는다. */
.cage-overlay-note {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.cage-heat-scale {
  display: flex;
  align-items: center;
  gap: 3px;
}

.cage-heat-scale i {
  width: 16px;
  height: 10px;
  border: 1px solid var(--accent-border);
  border-radius: 2px;
}

.cage-heat-scale i.heat-1 {
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
}

.cage-heat-scale i.heat-2 {
  background: color-mix(in srgb, var(--accent) 22%, var(--surface));
}

.cage-heat-scale i.heat-3 {
  background: color-mix(in srgb, var(--accent) 38%, var(--surface));
}

.cage-heat-scale i.heat-4 {
  background: color-mix(in srgb, var(--accent) 58%, var(--surface));
}

.cage-heat-scale i.heat-5 {
  background: color-mix(in srgb, var(--accent) 80%, var(--surface));
}

/* 회선 층. 랙 뒤에 깔리므로 랙 이름을 가리지 않는다. */
.cage-link {
  stroke: var(--accent);
  stroke-opacity: 0.45;
  stroke-linecap: round;
}

.cage-link.is-management {
  stroke: var(--n-500);
  stroke-dasharray: 90 70;
}

/* 시설물. 랙보다 연하게 — 이것들이 랙만큼 진하면 «어느 랙» 을 찾는 눈이 먼저 CRAC 에 걸린다. */
.cage-obj-facility rect {
  fill: var(--bg-sunken);
  stroke: var(--border-strong);
  stroke-width: 12;
}

.cage-obj-facility.is-column rect {
  fill: var(--n-300);
  stroke: var(--n-500);
}

.cage-obj-facility.is-tray rect {
  fill: transparent;
  stroke-dasharray: 100 60;
}

.cage-facility-mark {
  font: 600 130px var(--sans);
  letter-spacing: 0.06em;
  fill: var(--text-muted);
}

.cage-facility-sub {
  font: 500 120px var(--mono);
  fill: var(--text-muted);
}

.cage-facility-pick {
  height: 26px;
  max-width: 96px;
  font-size: 11.5px;
}

/* 오른쪽 칸의 진행 중 목록. 카드로 감싸지 않고 줄로 둔다. */
.cage-live-line {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  flex-wrap: wrap;
}

.cage-live-list h4 {
  margin: var(--s-2) 0 4px;
  font-size: var(--fs-caption);
}

.cage-live-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  width: 100%;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-left: 2px solid var(--danger);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}

.cage-live-item.is-maintenance {
  border-left-color: var(--accent);
}

.cage-live-item:hover {
  background: var(--bg-sunken);
}

.cage-live-item b {
  font-size: var(--ops-record-name-size, 12.5px);
  font-weight: 600;
}

/* 도면 밖의 도구 줄. 배치 / 기록 / 보기로 묶고, 좁은 화면에서도 캔버스를 덮지 않는다. */
.cage-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.cage-tool-group {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-1);
  min-width: 0;
}

.cage-float-btn {
  min-width: var(--s-8);
}

.cage-toolbar .button.cage-float-btn.is-on {
  border-color: var(--accent-border);
  background: var(--accent-soft);
  color: var(--accent-text);
}

.cage-zoom-label {
  min-width: var(--s-10);
  text-align: center;
  font-family: var(--mono);
  font-size: var(--fs-caption);
  color: var(--text-muted);
}

.cage-placement-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-4);
}

.cage-placement-bar p {
  margin: 0;
}

.cage-placement-bar .field {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  max-width: 100%;
}

.cage-placement-bar .field label {
  flex: none;
}

.cage-placement-choice {
  display: grid;
  gap: var(--s-2);
  padding: var(--s-2);
  border: 1px solid var(--accent-border);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  overflow-wrap: anywhere;
}

.cage-options {
  min-width: 0;
}

.cage-options[open] {
  flex-basis: 100%;
}

.cage-options summary,
.cage-rack-info summary {
  cursor: pointer;
  font-size: var(--fs-callout);
  color: var(--text-muted);
  padding-block: var(--s-2);
}

.cage-options-body {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  padding-block: var(--s-1);
}

.button.cage-remove {
  color: var(--danger);
}

.cage-property-error {
  color: var(--danger);
}

.cage-property-error:empty {
  display: none;
}

/* 오른쪽 칸. 카드로 감싸지 않고 선 하나로 도면과 가른다. */
.cage-panel {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
  padding-left: var(--s-4);
  border-left: 1px solid var(--border);
}

.cage-panel-head {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  flex-wrap: wrap;
}

.cage-panel-head h3 {
  margin: 0;
}

.cage-panel .meta {
  margin: 0;
}

.cage-facts {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
}

.cage-fact {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  padding: 4px 0;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
}

.cage-fact span {
  color: var(--text-muted);
}

.cage-fact b {
  font-variant-numeric: tabular-nums;
  text-align: right;
  overflow-wrap: anywhere;
  min-width: 0;
}

.cage-status-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.cage-status-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: 11px;
  color: var(--text-muted);
}

.cage-status-tag.is-normal {
  border-color: var(--ok-border);
  color: var(--ok);
}

.cage-status-tag.is-warning {
  border-color: var(--warn-border);
  color: var(--warn);
}

.cage-status-tag.is-critical {
  border-color: var(--danger-border);
  color: var(--danger);
}

.cage-status-tag.is-maintenance {
  border-color: var(--accent-border);
  color: var(--accent);
}

/* 색 고르개. 칠한 물체는 SVG 쪽에서 inline style 로 색이 박히므로 여기서는 고르개의
   생김새만 맡는다. */
.cage-color-row {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  margin-top: var(--s-1);
}

.cage-color-row label {
  font-size: var(--fs-caption);
  color: var(--text-muted);
}

.cage-color-input {
  width: 44px;
  height: 28px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
}

/* 칠한 아이템의 글자는 칠한 네모 위에 올라간다. 연한 회색으로 두면 밝은 색 위에서 읽히지
   않아, 본문 색으로 올린다. */
.cage-obj-text.is-filled .cage-plan-text {
  fill: var(--text);
}

.cage-panel-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin-top: var(--s-1);
}

/* 놓을 랙. 랙이 많아질 수 있으므로 자기 자리에서만 흐르고, 위에 검색창을 둔다. */
.cage-unplaced {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 320px;
  min-height: 40px;
  overflow-y: auto;
}

.cage-unplaced.is-drop-target {
  outline: 2px dashed var(--accent-border);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.cage-unplaced-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  padding: 4px 6px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  text-align: left;
  cursor: grab;
  min-height: var(--s-8);
}

.cage-unplaced-item b {
  font: 600 var(--fs-caption) var(--sans);
  overflow-wrap: anywhere;
  min-width: 0;
}

.cage-unplaced-item .meta {
  flex: none;
}

.cage-unplaced-item:hover {
  background: var(--bg-sunken);
}

.cage-unplaced-item.is-picked {
  border-color: var(--accent-border);
  background: var(--accent-soft);
}

.cage-hint,
.cage-edit-note {
  margin: 0;
}

@media (max-width: 1000px) {
  .cage-main {
    grid-template-columns: 1fr;
  }

  .cage-panel {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--border);
    padding-top: var(--s-3);
  }

  .cage-canvas {
    height: min(50vh, 480px);
  }
}

/* 설정 메뉴/앱 사이드바가 차지한 너비를 제외한 실제 작업 공간을 기준으로 배치한다. */
@container cage-workspace (max-width: 680px) {
  .cage-main {
    grid-template-columns: 1fr;
  }

  .cage-panel {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--border);
    padding-top: var(--s-3);
  }

  .cage-canvas {
    height: min(50vh, 480px);
  }
}

@media (max-width: 600px) {
  .cage-header-tools {
    width: 100%;
    margin-left: 0;
  }

  .cage-placement-bar .field {
    width: 100%;
  }

  .cage-placement-bar .input {
    min-width: 0;
  }
}

@media (any-pointer: coarse), (max-width: 767px) {
  .cage-toolbar .button,
  .cage-unplaced-item,
  .cage-options summary,
  .cage-rack-info summary {
    min-height: 44px;
    min-width: 44px;
  }
}

/* ── 월 비상대기 당번 ──────────────────────────────────────────────────────

   달을 세로로 쌓지 않고 팀마다 한 줄로 눕힌다. 앞에는 열두 달 × 팀 수의 표였는데, 팀이 둘이어도
   열세 줄이라 설정 화면의 절반을 차지했다. 정작 그 표에서 읽는 것은 거의 언제나 "이번 달과 다음
   달 누구인가" 한 줄이었다.

   좁은 화면에서는 그 줄만 옆으로 밀린다. 접어서 두 줄로 만들지 않는 이유는 달 순서가 곧 시간
   순서라, 접히면 다음 달이 아래로 내려가 순서가 깨져 보이기 때문이다. */
.standby-strip {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) 0;
}

.standby-strip + .standby-strip {
  border-top: 1px solid var(--divider);
}

.standby-strip-team {
  font-size: var(--fs-callout);
  font-weight: 600;
  color: var(--text);
}

.standby-strip-months {
  display: flex;
  gap: var(--s-1);
  overflow-x: auto;
  padding-bottom: 2px;
}

.standby-month {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  flex: none;
  min-width: 78px;
  padding: 4px var(--s-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
}

.standby-month:disabled,
div.standby-month {
  cursor: default;
}

.standby-month-label {
  font: var(--fs-micro) var(--mono);
  letter-spacing: 0.02em;
  color: var(--text-muted);
}

.standby-month b {
  font-size: var(--fs-caption);
  font-weight: 600;
  white-space: nowrap;
}

/* 이번 달이 어디인지가 이 줄에서 가장 먼저 읽혀야 한다. 맨 앞에 있다는 것만으로는 부족하다 —
   옆으로 밀어 둔 뒤에 돌아오면 어디가 이번 달인지 다시 세어야 한다. */
.standby-month.is-now {
  border-color: var(--accent-border);
  background: var(--accent-soft);
}

.standby-month.is-now b {
  color: var(--accent);
}

/* 아직 안 정한 달. 비워 두면 정한 달과 구별되지 않아 "이미 정했나" 를 매번 확인하게 된다. */
.standby-month.is-empty {
  border-style: dashed;
}

.standby-month.is-empty b {
  color: var(--text-faint);
}

.standby-month:hover:not(:disabled) {
  border-color: var(--border-strong);
}

@media (max-width: 720px) {
  .standby-strip {
    grid-template-columns: 1fr;
    gap: var(--s-1);
  }
}

/* 근무표에 서지 않는 사람. 파란 알약으로 두면 근무가 배정된 사람과 한눈에 구별되지 않아,
   표를 훑을 때 빠진 사람을 찾지 못한다. */
.shift-tmpl-pill.is-none {
  background: transparent;
  border-color: var(--border);
  color: var(--text-muted);
  font-weight: 500;
}

/* ── 여럿 고르는 칸 ─────────────────────────────────────────────────────────

   고른 것은 칩으로 남고, 고르개는 그 아래에 그대로 있다. <select multiple> 을 쓰지 않는
   이유는 Ctrl 을 눌러야 여럿이 골라지는 물건이라 «하나만 골라지는데요» 로 돌아오기
   때문이다. 칩은 고른 것이 눈에 남고, 빼는 자리가 각자 붙어 있다. */
.chip-picker {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.chip-list:empty {
  display: none;
}

.pick-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 4px 3px 10px;
  border: 1px solid var(--accent-border);
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--fs-caption);
  font-weight: 560;
  max-width: 100%;
}

.pick-chip > b {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pick-chip-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font-size: var(--fs-body);
  line-height: 1;
  cursor: pointer;
}

.pick-chip-x:hover {
  background: var(--accent-border);
}

/* 상세 화면에서 여럿을 적는 자리. 쉼표로 이어 한 줄로 적으면 이름 안의 쉼표와 구분되지
   않아, 자산 하나인지 둘인지 읽는 사람이 세어 봐야 한다. */
.info-tokens {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
}

.info-tokens > b {
  padding: 1px 7px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface-hover);
  font-size: var(--fs-caption);
  font-weight: 560;
}

/* ── 공휴일 당번 ────────────────────────────────────────────────────────────

   달력에서 당번 칸은 평소 근무와 달라 보여야 한다. 시각도 사람 수도 평소와 다른데 같은
   생김새로 두면, 추석에 한 명이 선 것과 평일에 한 조가 돈 것을 구별하려고 이름을 세게 된다. */
.cal-shift-chip.is-holiday-duty {
  border-style: dashed;
  border-color: var(--warn-border, var(--border));
  background: var(--warn-soft, var(--surface-hover));
}

.holiday-duty-days {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  max-height: 60vh;
  overflow: auto;
}

.holiday-duty-day {
  padding: var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.holiday-duty-day > header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}

.holiday-duty-person {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 5px 0;
  border-top: 1px solid var(--divider);
}

.holiday-duty-person > .meta {
  flex: 1;
}

/* 고르개 넷과 단추가 한 줄에 선다. 좁아지면 접히되 시각 두 칸은 끝까지 붙어 있다 —
   시작과 종료는 함께 읽는 값이다. */
.holiday-duty-add {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--divider);
}

.holiday-duty-add [data-duty-user] {
  flex: 1 1 160px;
}

.holiday-duty-add [data-duty-note] {
  flex: 1 1 120px;
}

.holiday-duty-add input[type='time'] {
  flex: 0 0 auto;
  width: auto;
}

/* ── 업무 폼의 부가 옵션 한 줄 ──────────────────────────────────────────────

   긴급과 마감일은 업무를 여는 데 꼭 필요한 값이 아니다. 그래서 필수 칸 뒤에 한 줄로 붙이고,
   그 줄 안에서도 왼쪽부터 읽히게 둔다 — 전에는 체크칸이 왼쪽 끝, 그것을 설명하는 글자가
   오른쪽 끝에 있어서 둘이 한 조작이라는 것이 보이지 않았다. */
/* 이 줄도 .field 라서 세로로 쌓는 규칙(.field { flex-direction: column })을 물려받는다.
   display:flex 만 적어 두면 방향은 물려받은 column 이 남아, 스위치와 마감일이 가운데
   정렬로 두 줄이 된다 — 한 줄로 합친 보람이 없어진다. 방향을 여기서 못 박는다. */
.task-options-row.field {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--s-3) var(--s-6);
  padding: var(--s-3) 0;
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
}
.task-workdate-row.field {
  display: grid;
  grid-template-columns: minmax(0, 180px) minmax(0, 130px) auto minmax(0, 130px);
  gap: var(--s-2);
  align-items: center;
}
.task-workdate-row.field > label,
.task-workdate-row.field > .field-hint {
  grid-column: 1 / -1;
}
.task-workdate-row.field > input {
  min-width: 0;
  max-width: none;
}
.task-workdate-dash {
  text-align: center;
}
@media (max-width: 600px) {
  .task-workdate-row.field {
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  }
  .task-workdate-row.field > input[type='date'] {
    grid-column: 1 / -1;
  }
}

/* 스위치. 체크칸 대신 쓰는 이유는 «지금 켜져 있는가» 가 한 눈에 들어와야 하기 때문이다 —
   긴급은 잘못 켜 두면 남의 밤잠을 깨우는 값이라, 켜졌는지 눈을 붙여 확인하게 두지 않는다.

   input 은 지우지 않고 자리만 없앤다. display:none 으로 지우면 키보드로 닿을 수 없고
   label 이 안 읽힌다 — 폼을 키보드로 넘기는 사람에게 이 칸만 건너뛰어진다. */
/* .field > label 이 글자 크기와 색을 정해 두고 있어, 같은 자리를 이기려면 선택자를 한 칸
   더 붙여야 한다. 자리를 숨긴 input 이 이 상자 안에 머물도록 position 도 여기서 잡는다 —
   안 잡으면 훨씬 바깥의 상자를 기준으로 떠서 엉뚱한 자리를 덮는다. */
.task-options-row > .task-switch {
  position: relative;
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  cursor: pointer;
  font-size: var(--fs-callout);
  font-weight: 560;
  color: var(--text-muted);
  user-select: none;
}

.task-switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.task-switch .task-switch-track {
  position: relative;
  display: block;
  flex: 0 0 auto;
  width: 34px;
  min-width: 34px;
  height: 20px;
  border-radius: var(--radius-pill);
  background: var(--n-300, #cbd5e1);
  transition: background 0.15s ease;
}

.task-switch .task-switch-track::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s ease;
}

/* 켜져 있을 때만 빨강을 쓴다. 꺼져 있을 때도 빨가면 그 색이 «지금 긴급» 을 뜻하지 못하고
   그냥 이 칸의 색이 된다 — 목록을 훑는 눈이 그 색에 반응하지 않게 된다. */
.task-switch input:checked ~ .task-switch-track,
.task-options-row .task-switch input:checked ~ .task-switch-track {
  background: var(--danger, #dc2626);
}

.task-switch input:checked ~ .task-switch-track::after {
  transform: translateX(14px);
}

.task-switch input:checked ~ span {
  color: var(--danger, #dc2626);
}

.task-switch input:focus-visible ~ .task-switch-track {
  box-shadow: var(--focus-ring, 0 0 0 3px rgba(37, 99, 235, 0.35));
}

.task-options-row > .task-due {
  display: inline-flex;
  flex-direction: row;
  flex-wrap: wrap;
  min-width: 0;
  max-width: 100%;
  align-items: center;
  gap: var(--s-2);
}

.task-options-row .task-due > label {
  margin: 0;
  font-size: var(--fs-callout);
  font-weight: 560;
  color: var(--text-muted);
  white-space: nowrap;
}

.task-options-row .task-due > .input {
  width: 220px;
  max-width: 100%;
}

/* ── 업무 상세 ──────────────────────────────────────────────────────────────

   이 화면에 들어온 사람이 3초 안에 알아야 하는 것은 «무슨 업무인가 · 지금 어떤 상태인가 ·
   누가 맡는가 · 언제까지인가» 넷이다. 전에는 그 넷이 열두 줄짜리 표 안에 «Site: KR» 과 같은
   무게로 흩어져 있었고, 정작 본문인 업무 내용도 그 표 위에 같은 굵기로 놓여 있었다.

   여기서 하는 일은 무게를 다시 나누는 것뿐이다 — 데이터도 기능도 그대로다.

     머리(제목·배지·넷)  →  본문(업무 내용)  →  딸린 사실  →  옆칸

   옆칸을 없애지 않고 한 단계 뒤로 물린다. 거기 있는 것은 «읽을 것» 이 아니라 «할 수 있는 것»
   이라, 필요할 때 찾으면 되고 들어오자마자 눈을 가져갈 이유는 없다. */
.task-detail-page .page-head {
  margin-bottom: var(--s-4);
}

/* 머리는 두 칸이다 — 왼쪽은 «무슨 업무인가», 오른쪽은 «누구 것이고 어디인가».

   오른쪽을 본문 아래에 두었더니 그 답이 본문을 다 지나친 뒤에야 나왔고, 옆칸으로 내렸더니
   이번에는 제목 오른쪽이 통째로 비었다. 이 값들은 제목을 읽는 동안 함께 읽히는 것이라
   제목 옆이 제자리다. */
.task-brief {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s-5) var(--s-6);
  align-items: start;
  padding: 0 0 var(--s-5);
  margin-bottom: var(--s-5);
  border-bottom: 1px solid var(--divider);
}

/* 오른쪽 칸은 카드가 아니다. 테두리를 두르면 머리 안에 카드가 하나 떠 있는 꼴이 되어,
   제목과 한 덩어리로 읽히지 않는다. 왼쪽과 가르는 것은 세로선 하나면 된다. */
.task-brief-scope {
  padding-left: var(--s-5);
  border-left: 1px solid var(--divider);
}

.task-brief-scope > h2 {
  margin: 0 0 var(--s-3);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.task-brief-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}

.task-brief h1 {
  margin: 0;
  font-size: var(--fs-display);
  line-height: 1.3;
  letter-spacing: -0.015em;
}

/* 긴급은 배지 가운데 가장 먼저 읽혀야 한다. 다른 배지와 같은 모양이면 우선순위 배지와
   구별되지 않아, 긴급인지 아닌지를 글자를 읽어 확인하게 된다. */
.task-emergency {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
  font-weight: 650;
}

/* 머리에 붙는 사실 넉 장. 표가 아니라 한 줄이다 — 이 넷은 제목에 딸린 값이라 제목과 한 번에
   읽혀야 하고, 줄을 그어 칸을 나누면 아래의 «딸린 사실» 과 같은 것으로 보인다. */
.task-brief-facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-6);
  margin-top: var(--s-4);
}

.task-brief-fact {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.task-brief-fact > span {
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.task-brief-fact > b {
  font-size: var(--fs-body);
  font-weight: 560;
  color: var(--text);
}

/* 본문 카드. 여백을 넉넉히 주는 것이 이 카드를 다른 카드와 가르는 유일한 장치다 — 배경색이나
   테두리로 강조하면 화면이 시끄러워지고, 그 강조는 카드가 하나 더 늘어나는 순간 무너진다. */
.task-description-panel .panel-body {
  padding: 22px 24px 24px;
}

.task-description {
  font-size: var(--fs-body);
  line-height: 1.68;
  color: var(--text);
}

.task-description p {
  margin: 0 0 1em;
}

.task-description p:last-child {
  margin-bottom: 0;
}

.task-description-empty {
  color: var(--text-muted);
}

/* 접어 둘 때는 여섯 줄까지만. 줄 수로 자르는 이유는 «화면 몇 픽셀» 로 자르면 글자 크기를
   키워 놓은 사람에게는 두 줄만 보이기 때문이다. */
.task-description.is-clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  line-clamp: 6;
  overflow: hidden;
}

.task-description-more {
  margin-top: var(--s-3);
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-size: var(--fs-callout);
  font-weight: 560;
  cursor: pointer;
}

.task-description-more:hover {
  text-decoration: underline;
}

/* 딸린 사실. 두 칸 그리드는 그대로 두되 줄을 지운다 — 선이 있으면 표가 되고, 표가 되면 본문과
   같은 무게로 읽힌다. 여기서 필요한 것은 «찾으면 있다» 뿐이다. */
/* 머리의 오른쪽 칸은 왼쪽과 키를 맞춘다.

   두 칸으로 나눴더니 아홉 줄이 다섯 줄이 되어, 오른쪽이 왼쪽보다 두 배 길었다. 머리가
   본문보다 길어지면 «먼저 읽을 것» 이 뒤집힌다 — 제목을 보러 온 눈이 딸린 값부터 훑게 된다.

   세 칸으로 나누고 글자를 한 급 줄여 세 줄로 만든다. 왼쪽(꼬리표 · 제목 · 사실 넉 장)과
   대략 같은 키다. 꼭 맞추지는 않는다 — 한 줄이 두 줄로 접히는 값이 있고(고객 이름이 긴
   경우가 그렇다), 딱 맞춰 두면 그때마다 어긋난 것처럼 보인다. */
.info-list.task-facts {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 0;
  border-top: 0;
  gap: var(--s-3) var(--s-4);
}

/* 여기서는 «넓게 차지하라» 는 지시를 듣지 않는다. 조직 화면이 채우는 협업 조직 줄이 그
   지시를 달고 오는데, 세 칸 가운데 한 줄을 통째로 먹으면 다시 다섯 줄이 된다. */
.info-list.task-facts > .organization-info-wide {
  grid-column: auto;
}

/* 값은 왼쪽 사실 넉 장과 같은 크기로 둔다. 두 묶음이 같은 것을 말하므로 크기가 다르면
   한쪽이 더 중요한 값처럼 읽힌다. */
.info-list.task-facts > div {
  padding: 0;
  border-bottom: 0;
  font-size: var(--fs-callout);
  line-height: 1.45;
  color: var(--text);
}

.info-list.task-facts label {
  margin-bottom: 2px;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}

/* 빈 값은 있는 값보다 연하게 둔다. 같은 굵기로 두면 «—» 열두 개가 화면에서 가장 규칙적인
   무늬가 되어, 정작 적혀 있는 값보다 먼저 눈에 걸린다. */
.task-fact-empty {
  color: var(--text-subtle, var(--text-muted));
  opacity: 0.6;
}

/* 분류 꼬리표는 본문 카드의 머리로 올라간다. 무엇에 관한 업무인지는 제목 다음으로 먼저
   읽히는 값이라, 본문 아래에 있으면 다 읽고 나서야 알게 된다. */
.task-description-panel .panel-head {
  align-items: center;
  gap: var(--s-3);
}

.task-description-panel .task-classification {
  margin: 0;
  justify-content: flex-end;
}

/* 옆칸을 뒤로 물린다. 카드 자체를 없애지 않는 이유는 여기서 하는 일(내 TODO 지정, 현장 작업
   발행, 런북 열기)이 실제로 쓰이기 때문이다 — 찾을 수 있되 먼저 보이지만 않으면 된다. */
.task-aside > .panel {
  margin-top: var(--s-3);
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}

.task-aside > .panel:first-child {
  margin-top: 0;
}

.task-aside .panel-head h2 {
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.task-aside .panel-body {
  font-size: var(--fs-callout);
}

@media (max-width: 900px) {
  .task-brief {
    grid-template-columns: minmax(0, 1fr);
  }

  .task-brief-scope {
    padding-left: 0;
    padding-top: var(--s-4);
    border-left: 0;
    border-top: 1px solid var(--divider);
  }

  .info-list.task-facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .task-brief h1 {
    font-size: var(--fs-title1);
  }

  .task-description-panel .panel-body {
    padding-left: var(--s-4);
    padding-right: var(--s-4);
  }

  .task-description-panel .panel-head {
    flex-wrap: wrap;
  }

  .task-description-panel .task-classification {
    justify-content: flex-start;
  }
}
/* Separate-origin draw.io editor; existing physical cage editor is unchanged. */
.workforce-panel {
  margin-top: 16px;
}
.workforce-planner {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 24px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--divider);
}
.workforce-planner-copy {
  min-width: 0;
}
.workforce-planner-copy h3 {
  margin: 0 0 4px;
  color: var(--text);
  font-size: var(--fs-callout);
}
.workforce-planner-copy .meta {
  display: block;
  margin: 0;
  line-height: 1.5;
}
.workforce-toolbar {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  flex: 0 0 auto;
}
.workforce-toolbar .field {
  margin: 0;
}
.workforce-toolbar .field > span {
  display: block;
  margin-bottom: 5px;
  color: var(--text-secondary);
  font-size: var(--fs-micro);
  font-weight: 600;
  line-height: 1.2;
}
.workforce-toolbar .input,
.workforce-toolbar .select,
.workforce-toolbar .button {
  min-height: 34px;
  margin: 0;
}
.workforce-cycle {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}
.workforce-members {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  max-height: 240px;
  overflow: auto;
  padding: 8px;
}
.workforce-check {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  overflow-wrap: anywhere;
}
.workforce-check input {
  width: auto;
  flex: 0 0 auto;
}
.workforce-preview {
  max-height: 55vh;
  overflow: auto;
}
.workforce-panel table {
  min-width: 650px;
}
@media (max-width: 600px) {
  .workforce-planner {
    display: block;
  }
  .workforce-toolbar {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin-top: 12px;
  }
  .workforce-toolbar .input,
  .workforce-toolbar .select,
  .workforce-toolbar .button {
    width: 100%;
  }
  .workforce-toolbar .button {
    grid-column: 1 / -1;
  }
  .workforce-cycle {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .workforce-members {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* 업무 목록 필터는 자주 쓰는 조건을 한눈에 비교하고 바로 조합할 수 있어야 한다. */
.task-filter-bar {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) auto minmax(120px, 180px) auto auto;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--surface, #fff);
}
.task-filter-bar .search {
  width: 100%;
  min-width: 0;
}
.task-filter-chips {
  display: flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}
.task-filter-chip {
  min-height: 30px;
  padding: 5px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface, #fff);
  color: var(--muted);
  font: 600 var(--fs-caption) var(--sans);
  line-height: 1;
  cursor: pointer;
}
.task-filter-chip:hover {
  border-color: var(--primary, #3478f6);
  color: var(--text);
}
.task-filter-chip.active {
  border-color: color-mix(in srgb, var(--primary, #3478f6) 38%, var(--line));
  background: color-mix(in srgb, var(--primary, #3478f6) 10%, var(--surface, #fff));
  color: var(--primary, #3478f6);
}
.task-filter-chip:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--primary, #3478f6) 36%, transparent);
  outline-offset: 1px;
}
.task-team-filter {
  width: 100%;
  min-width: 0;
  height: 32px;
  padding-block: 5px;
}
.task-filter-bar .button.sm {
  width: auto;
  min-height: 32px;
  margin: 0;
  white-space: nowrap;
}
.task-result-count {
  min-width: 34px;
  text-align: right;
  white-space: nowrap;
}
body.theme-dark .task-filter-bar,
body.theme-dark .task-filter-chip {
  background: var(--surface);
}
@media (max-width: 1100px) {
  .task-filter-bar {
    grid-template-columns: minmax(220px, 1fr) auto auto auto;
  }
  .task-filter-chips {
    grid-column: 1 / -1;
    grid-row: 2;
    flex-wrap: wrap;
  }
}
@media (max-width: 700px) {
  .task-filter-bar {
    grid-template-columns: minmax(0, 1fr) auto auto;
    padding: 8px;
  }
  .task-filter-bar .search,
  .task-filter-chips {
    grid-column: 1 / -1;
  }
  .task-filter-chips {
    overflow-x: auto;
    flex-wrap: nowrap;
    padding-bottom: 2px;
  }
  .task-team-filter {
    max-width: 150px;
  }
}
.diagram-customer-picker {
  display: flex;
  align-items: end;
  gap: 12px;
  flex-wrap: wrap;
}
.diagram-customer-picker .field {
  width: min(100%, 460px);
  margin: 0;
}
.diagram-list {
  display: grid;
  gap: 16px;
}
.diagram-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 16px;
  border: 1px solid var(--border, #e1e1e6);
  border-radius: 8px;
}
.diagram-row > div {
  min-width: 0;
}
.diagram-row h3 {
  margin: 0 0 8px;
  overflow-wrap: anywhere;
}
.diagram-row .page-head-actions {
  flex-wrap: wrap;
  flex-shrink: 0;
}
.diagram-editor-backdrop {
  padding: 12px;
  z-index: 1100;
}
.diagram-editor-shell {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: calc(100dvh - 24px);
  background: var(--panel, #fff);
  border-radius: 10px;
  overflow: hidden;
}
.diagram-editor-shell iframe {
  width: 100%;
  flex: 1;
  min-height: 0;
  border: 0;
  background: white;
}
.diagram-editor-status {
  margin: 0;
  padding: 8px 20px;
}
.diagram-editor-status:empty {
  display: none;
}
.diagram-review {
  width: min(1100px, calc(100vw - 32px));
  max-width: 1100px;
}
.diagram-preview {
  display: block;
  width: 100%;
  height: auto;
  max-height: 65vh;
  object-fit: contain;
  background: #fff;
  border: 1px solid #e1e1e6;
}
@media (max-width: 700px) {
  .diagram-row {
    flex-direction: column;
    align-items: stretch;
  }
  .diagram-editor-backdrop {
    padding: 0;
  }
  .diagram-editor-shell {
    height: 100dvh;
    border-radius: 0;
  }
  .diagram-editor-shell .panel-head {
    gap: 8px;
    padding: 12px;
  }
}
/* Task content is one editable surface, not a stack of attachment cards. */
.task-content-editor,
.task-content-view {
  min-width: 0;
  max-width: 100%;
}
.task-form textarea[name='description'][hidden] {
  display: none !important;
}
.task-content-editor {
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface, #fff);
}
.task-content-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--line);
}
.task-content-toolbar .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-height: 32px;
  margin: 0;
  padding: 5px 12px;
  line-height: 1.3;
  white-space: nowrap;
}
.task-rich-input {
  min-height: 180px;
  max-height: 55vh;
  overflow: auto;
  padding: 12px;
  color: var(--text);
  font: inherit;
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  outline: none;
}
.task-rich-input:focus {
  box-shadow: inset 0 0 0 1px var(--primary, #3478f6);
}
.task-rich-input p,
.task-content-view > p {
  margin: 0 0 10px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.task-content-editor > .meta {
  margin: 0;
  padding: 8px 12px;
  border-top: 1px solid var(--line);
}
.task-content-table {
  max-width: 100%;
  overflow: auto;
  margin: 12px 0;
  white-space: normal;
}
.task-content-table table {
  border-collapse: collapse;
  width: max-content;
  min-width: 100%;
}
.task-content-table td {
  border: 1px solid var(--line);
  padding: 8px 10px;
  min-width: 100px;
  max-width: 360px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  vertical-align: top;
}
.task-inline-media {
  cursor: grab;
  display: inline-flex;
  align-items: flex-start;
  gap: var(--s-2);
  position: relative;
  max-width: 100%;
  min-width: 44px;
  min-height: 44px;
  margin: 8px 4px;
  vertical-align: middle;
  white-space: normal;
}
.task-content-image {
  display: block;
  padding: 0;
  margin: 12px 0;
  border: 0;
  background: transparent;
  max-width: 100%;
  cursor: zoom-in;
}
.task-inline-media img,
.task-content-image img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 480px;
  object-fit: contain;
}
.task-content-remove {
  position: static;
  flex-shrink: 0;
  width: calc(var(--s-10) + var(--s-1));
  height: calc(var(--s-10) + var(--s-1));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface, #fff);
  color: var(--text);
  cursor: pointer;
  font: inherit;
}
.task-content-download {
  display: inline-block;
  max-width: 100%;
  padding: 6px 32px 6px 8px;
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow-wrap: anywhere;
  color: var(--primary, #3478f6);
}
.task-content-select {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  min-width: calc(var(--s-10) + var(--s-1));
  min-height: calc(var(--s-10) + var(--s-1));
  max-width: calc(100% - var(--s-10) - var(--s-3));
}
.task-content-diff {
  margin: 8px 0;
  white-space: normal;
}
.task-content-diff summary {
  cursor: pointer;
}
.task-content-diff pre {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font: inherit;
}
.thd-body { margin-top: 8px; }
.thd-lines { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; font-size: var(--fs-caption, 13px); }
.thd-lines li { display: flex; gap: 8px; padding: 2px 10px; white-space: pre-wrap; overflow-wrap: anywhere; }
.thd-mark { flex: none; width: 1ch; font-family: var(--mono); color: var(--text-secondary); }
.thd-add { background: var(--ok-soft); }
.thd-add .thd-mark { color: var(--ok); }
.thd-del { background: var(--danger-soft); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.thd-del .thd-mark { color: var(--danger); }
.thd-fold { color: var(--text-secondary); font-style: italic; }
.thd-table { margin: 8px 0 0; padding-left: 18px; }
.thd-media { margin-top: 8px; }
.thd-media > b { display: block; margin-bottom: 4px; }
.thd-thumbs img { max-height: 96px; width: auto; }
.thd-full { margin-top: 10px; }
.thd-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (max-width: 600px) {
  .task-rich-input {
    padding: 10px;
  }
  .task-content-toolbar {
    gap: 6px;
  }
  .task-inline-media {
    margin-inline: 0;
  }
}

/* Cloud resource views: one typography scale, state semantics, and selected detail. */
.cloud-page {
  font: 400 var(--fs-body)/1.5 var(--sans);
}
/* Compact controls move the advanced-search trigger. Bound its popup to the
   Operations search row, not the viewport or the trigger's intrinsic width. */
.cloud-page .cloud-policy-search {
  position: relative;
}
.cloud-page .cloud-policy-advanced {
  position: static;
}
.cloud-page .cloud-policy-advanced-fields {
  top: 100%;
  left: 0;
  right: auto;
  width: min(460px, 100%);
}
@media (max-width: 600px) {
  .cloud-page .cloud-policy-advanced[open] {
    flex-basis: 100%;
  }
}
.cloud-page h2,
.cloud-section-heading h2 {
  margin: 0;
  font-size: var(--fs-title3);
  font-weight: 650;
}
.cloud-page h3 {
  margin: 20px 0 12px;
  font-size: var(--fs-body);
  font-weight: 650;
}
.cloud-page .panel-head {
  align-items: center;
  padding: 18px 20px;
}
.cloud-page > .panel + .panel {
  margin-top: 18px;
}
.cloud-page .cloud-summary strong {
  font: 650 var(--fs-display)/1.2 var(--sans);
}
.cloud-page .cloud-summary small {
  font-size: var(--fs-callout);
  font-weight: 500;
}
.cloud-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  max-width: 100%;
  padding: 3px 9px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font: 600 var(--fs-caption)/1.5 var(--sans);
  white-space: nowrap;
}
.cloud-status.is-success {
  color: var(--ok);
  background: var(--ok-soft);
  border-color: var(--ok-border);
}
.cloud-status.is-danger {
  color: var(--danger);
  background: var(--danger-soft);
  border-color: var(--danger-border);
}
.cloud-status.is-warning {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: var(--warn-border);
}
.cloud-status.is-neutral {
  color: var(--text-secondary);
  background: var(--surface-hover);
}
.cloud-page .cloud-list {
  padding: 0;
  gap: 0;
}
.cloud-page .cloud-list > article {
  border: 0;
  border-top: 1px solid var(--divider);
  border-radius: 0;
  background: transparent;
  padding: 16px 20px;
}
.cloud-page .cloud-list > article strong {
  font-size: var(--fs-body);
  font-weight: 600;
}
.cloud-page .cloud-list small,
.cloud-resource-meta {
  color: var(--text-secondary);
  font-size: var(--fs-callout);
  font-weight: 400;
  line-height: 1.5;
}
.cloud-connection-details {
  color: var(--text-muted);
  font-size: var(--fs-caption);
}
.cloud-connection-details summary,
.cloud-alert-detail summary {
  cursor: pointer;
}
.cloud-page .cloud-attention-list li {
  gap: 16px;
  padding: 18px 20px;
  align-items: flex-start;
}
.cloud-page .cloud-attention-list li:last-child {
  border-bottom: 0;
}
.cloud-page .cloud-attention-list li strong {
  display: block;
  font: 600 var(--fs-body)/1.5 var(--sans);
}
.cloud-page .cloud-attention-list li small {
  margin-top: 4px;
  font: 400 var(--fs-callout)/1.5 var(--sans);
  color: var(--text-secondary);
}
.cloud-page .cloud-attention-critical {
  background: color-mix(in srgb, var(--danger-soft) 45%, var(--surface));
  border-left: 3px solid var(--danger);
}
.cloud-page .cloud-attention-warn {
  border-left: 3px solid var(--warn);
}
.cloud-alert-detail {
  margin-top: 8px;
  font-size: var(--fs-caption);
  color: var(--text-secondary);
}
.cloud-alert-detail > span {
  display: block;
  margin-top: 6px;
  overflow-wrap: anywhere;
}
.cloud-inline-actions,
.cloud-portal-cell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.cloud-service-actions .cloud-inline-actions {
  justify-content: flex-end;
}
.cloud-page .cloud-service-table td {
  font-size: var(--fs-body);
  padding: 16px 12px;
}
.cloud-page .cloud-service-table td > small {
  font-size: var(--fs-caption);
  margin-top: 4px;
}
.cloud-page .cloud-service-features {
  max-width: 270px;
}
.cloud-page .cloud-service-actions {
  white-space: normal;
}
.cloud-page .cloud-service-actions .button + .button {
  margin: 0;
}
.cloud-resource-menu {
  position: relative;
}
.cloud-resource-menu > summary {
  list-style: none;
  cursor: pointer;
}
.cloud-resource-menu > summary::-webkit-details-marker {
  display: none;
}
.cloud-resource-menu-items {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-hover);
}
.cloud-resource-menu-items [data-action='cloud-service-decommission'],
.cloud-danger-zone [data-action='cloud-retire-pair'],
[data-action='cloud-revoke-agent'] {
  color: var(--danger);
}
.cloud-section-heading {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin: 24px 0 14px;
}
.cloud-gateway-workspace {
  display: grid;
  grid-template-columns: minmax(250px, 310px) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
.cloud-gateway-directory,
.cloud-gateway-detail {
  min-width: 0;
  margin: 0;
}
.cloud-resource-search {
  padding: 14px;
  border-bottom: 1px solid var(--border);
}
.cloud-resource-search input {
  width: 100%;
  min-width: 0;
}
.cloud-gateway-list {
  display: grid;
}
.cloud-gateway-row {
  display: grid;
  gap: 10px;
  padding: 18px 16px;
  border: 0;
  border-bottom: 1px solid var(--divider);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  min-width: 0;
}
.cloud-gateway-row:last-child {
  border-bottom: 0;
}
.cloud-gateway-row.is-selected {
  background: var(--accent-soft);
  box-shadow: inset 3px 0 var(--accent);
}
.cloud-gateway-row:hover {
  background: var(--surface-hover);
}
.cloud-gateway-row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -3px;
}
.cloud-gateway-row-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.cloud-gateway-row-head strong {
  font-size: var(--fs-body);
  overflow-wrap: anywhere;
}
.cloud-resource-indicators {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-caption);
  color: var(--text-secondary);
}
.cloud-detail-tabs {
  padding: 0 16px;
  margin: 0;
  overflow-x: auto;
}
.cloud-detail-tabs button {
  flex-shrink: 0;
  font-size: var(--fs-callout);
}
.cloud-detail-body {
  padding: 20px;
  min-width: 0;
}
.cloud-detail-body[hidden] {
  display: none;
}
.cloud-detail-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}
.cloud-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 24px;
  margin: 0;
}
.cloud-facts > div {
  min-width: 0;
}
.cloud-facts dt {
  color: var(--text-secondary);
  font-size: var(--fs-callout);
  margin-bottom: 5px;
}
.cloud-facts dd {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 500;
  overflow-wrap: anywhere;
}
.cloud-detail-body .cloud-node-grid > div {
  border: 1px solid var(--border);
  background: var(--surface-hover);
  display: grid;
  gap: 6px;
  padding: 16px;
}
.cloud-detail-body .cloud-node-grid > div > span:first-child {
  font: 500 var(--fs-caption) var(--sans);
  letter-spacing: 0;
  color: var(--text-secondary);
}
.cloud-detail-body .cloud-node-grid strong {
  font-size: var(--fs-body);
  font-weight: 600;
}
.cloud-detail-body .cloud-node-grid small {
  font-size: var(--fs-callout);
  color: var(--text-secondary);
}
.cloud-detail-body .cloud-ha-line {
  display: grid;
  gap: 16px;
  margin: 0 0 20px;
  padding: 0 0 20px;
  border-bottom: 1px solid var(--divider);
}
.cloud-detail-body .cloud-ha-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  font-size: var(--fs-body);
}
.cloud-detail-body .cloud-pair-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.cloud-verification {
  margin: 20px 0;
  padding: 16px;
  background: var(--surface-hover);
  border-radius: 8px;
}
.cloud-verification strong {
  display: block;
  font-size: var(--fs-body);
  margin-bottom: 12px;
}
.cloud-danger-zone {
  margin-top: 24px;
  border-top: 1px solid var(--border);
  padding-top: 16px;
}
.cloud-danger-zone summary {
  font-size: var(--fs-callout);
  color: var(--text-secondary);
  cursor: pointer;
}
.cloud-danger-zone p {
  font-size: var(--fs-callout);
  margin: 12px 0;
  color: var(--text-secondary);
}
.cloud-pool-list {
  display: grid;
  gap: 12px;
}
.cloud-detail-body .cloud-pool {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.cloud-pool strong {
  font-size: var(--fs-body);
  font-weight: 600;
}
.cloud-pool > span {
  color: var(--text-secondary);
  font-size: var(--fs-callout);
}
.cloud-pool > .button {
  margin-left: auto;
}
.cloud-wan-detail h3 {
  margin-top: 0;
}
.cloud-wan-detail > .button {
  margin-top: 18px;
}
.cloud-page .cloud-agent-row {
  display: grid;
  grid-template-columns: minmax(140px, 1.2fr) max-content minmax(100px, 0.7fr) minmax(170px, 1fr) auto;
  gap: 20px;
  align-items: center;
}
.cloud-agent-row > .cloud-pair-actions {
  display: flex;
  gap: 8px;
}
.cloud-agent-row .cloud-agent-version,
.cloud-agent-row .cloud-agent-contact {
  display: grid;
  gap: 4px;
}
.cloud-agent-version > span:first-child,
.cloud-agent-contact > span:first-child {
  font-size: var(--fs-caption);
  color: var(--text-secondary);
}
.cloud-agent-row .cloud-agent-version strong,
.cloud-agent-row .cloud-agent-contact strong {
  font-size: var(--fs-callout);
  font-weight: 500;
}
.cloud-agent-contact details {
  font-size: var(--fs-caption);
  color: var(--text-secondary);
}
.cloud-settings-summary {
  padding: 18px 20px;
  font-size: var(--fs-body);
  font-weight: 600;
  cursor: pointer;
}
.cloud-settings-content {
  padding: 0 20px 20px;
}
.cloud-agent-example {
  border-top: 1px solid var(--border);
  padding: 14px 0;
}
.cloud-agent-example summary {
  font-size: var(--fs-callout);
  cursor: pointer;
}
.cloud-agent-example pre {
  max-width: 100%;
  overflow-x: auto;
  padding: 16px;
  font: var(--fs-caption)/1.7 var(--mono);
  background: var(--surface-hover);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.cloud-config-sheet .modal {
  width: min(920px, 100vw);
}
.cloud-config-sheet .cloud-ref-choices {
  max-height: 170px;
}
.cloud-ref-selector {
  margin: 10px 0;
}
.cloud-ref-selector > summary {
  color: var(--accent);
  font-size: var(--fs-callout);
  font-weight: 600;
  cursor: pointer;
}
.cloud-ref-selector > input {
  margin-top: 10px;
}
.cloud-policy-advanced {
  margin: 16px 0;
}
.cloud-policy-advanced > summary {
  color: var(--text-secondary);
  font-size: var(--fs-callout);
  font-weight: 600;
  cursor: pointer;
}
.cloud-policy-advanced > .field {
  margin-top: 16px;
}
@media (max-width: 1100px) {
  .cloud-gateway-workspace {
    grid-template-columns: minmax(220px, 260px) minmax(0, 1fr);
  }
  .cloud-page .cloud-agent-row {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 14px;
  }
  .cloud-agent-version {
    grid-column: 1;
  }
  .cloud-agent-contact {
    grid-column: 1 / -1;
  }
  .cloud-agent-row > .cloud-pair-actions {
    grid-column: 2;
    grid-row: 3;
    justify-content: flex-end;
  }
}
@media (max-width: 760px) {
  .cloud-gateway-workspace,
  .cloud-page .cloud-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .cloud-agent-version,
  .cloud-agent-contact {
    grid-column: 1 / -1;
  }
  .cloud-agent-row > .cloud-pair-actions {
    grid-column: 1 / -1;
    grid-row: auto;
    justify-content: flex-end;
  }
  .cloud-gateway-list {
    max-height: 320px;
    overflow-y: auto;
  }
  .cloud-page .cloud-service-table thead {
    display: none;
  }
  .cloud-page .cloud-service-table,
  .cloud-page .cloud-service-table tbody {
    display: block;
    width: 100%;
  }
  .cloud-page .cloud-service-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
    padding: 18px 0;
    border-bottom: 1px solid var(--border);
  }
  .cloud-page .cloud-service-table td {
    display: block;
    border: 0;
    padding: 0;
    min-width: 0;
    overflow-wrap: anywhere;
    white-space: normal;
  }
  .cloud-page .cloud-service-table td:nth-child(1) {
    grid-column: 1;
    grid-row: 1;
  }
  .cloud-page .cloud-service-table td:nth-child(5) {
    grid-column: 2;
    grid-row: 1;
  }
  .cloud-page .cloud-service-table td:nth-child(2),
  .cloud-page .cloud-service-table td:nth-child(3),
  .cloud-page .cloud-service-table td:nth-child(4),
  .cloud-page .cloud-service-table td:nth-child(6),
  .cloud-page .cloud-service-table td:nth-child(7) {
    grid-column: 1 / -1;
  }
  .cloud-service-actions .cloud-inline-actions {
    justify-content: flex-start;
  }
  .cloud-page .cloud-service-features {
    max-width: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .cloud-page .table-wrap {
    margin: 0;
    padding: 0;
  }
  .cloud-page .cloud-service-table tr {
    padding: 18px 16px;
  }
  .cloud-page .cloud-summary {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .cloud-config-sheet .cloud-policy-endpoints {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* VM creation records keep the outcome readable without horizontal scrolling. */
.cloud-vm-history-label {
  display: none;
}
.cloud-vm-history-table small {
  display: block;
  margin-top: 4px;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
@media (max-width: 640px) {
  .cloud-vm-history-wrap {
    overflow: visible;
    border: 0;
  }
  .cloud-vm-history-table,
  .cloud-vm-history-table tbody {
    display: block;
    min-width: 0;
    width: 100%;
  }
  .cloud-vm-history-table thead {
    display: none;
  }
  .cloud-vm-history-table tr {
    display: block;
    margin-bottom: 12px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .cloud-vm-history-table td {
    display: grid;
    grid-template-columns: 84px minmax(0, 1fr);
    gap: 8px;
    padding: 6px 0;
    border: 0;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .cloud-vm-history-label {
    display: block;
    color: var(--text-muted);
  }
  .cloud-vm-history-table .cloud-status {
    max-width: 100%;
    white-space: normal;
  }
}
@media (max-width: 480px) {
  .cloud-page .panel-head,
  .cloud-detail-body {
    padding: 16px;
  }
  .cloud-facts,
  .cloud-detail-body .cloud-node-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .cloud-page .cloud-attention-list li {
    padding: 16px;
  }
  .cloud-page .cloud-attention-actions {
    justify-content: flex-start;
  }
  .cloud-page .cloud-summary strong {
    font-size: var(--fs-display);
  }
  .cloud-page .cloud-list > article {
    padding: 16px;
  }
}

/* 업무 목록 상태 칸의 작은 단계 점. 상세의 .status-stepper 를 줄인 것이다. */
.status-cell {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  white-space: nowrap;
}

.step-dots {
  display: inline-flex;
  gap: 3px;
}

.step-dots i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--line);
}

.step-dots i.is-done {
  background: var(--accent);
}

.step-dots i.is-current {
  background: color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: 0 0 0 1px var(--accent);
}

.step-dots.is-cancelled {
  opacity: 0.4;
}

/* ── 2026-10 개편 ─────────────────────────────────────────────────────────────
   공통 부품의 새 모양은 vlan24-ui.css 에 있다. 이 파일 앞쪽에 콘솔 전용으로 다시 적은 탭·번호
   규칙이 그것을 덮고 있어서, 맨 끝에서 한 번 더 맞춘다. 앞쪽 규칙을 지우지 않은 이유는
   리포트 주제 탭처럼 그 규칙에 기대는 변형이 있어서다 — 화면을 옮길 때 하나씩 걷어낸다. */
.tabs,
.settings-tabs,
.field-work-tabs,
.page-actions .field-work-tabs {
  display: inline-flex;
  max-width: 100%;
  gap: 2px;
  padding: 2px;
  border: 0;
  border-radius: 9px;
  background: var(--surface-active);
}
.tabs button,
.settings-tabs button,
.field-work-tabs button {
  padding: 5px 12px;
  border: 0;
  border-radius: 7px;
  color: var(--text-secondary);
  font: 500 var(--fs-callout) var(--sans);
}
.tabs button.active,
.tabs button[aria-pressed='true'],
.settings-tabs button.active,
.field-work-tabs button.active {
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  border: 0;
  box-shadow: 0 1px 2px rgba(13, 13, 15, 0.12);
}
body.theme-dark .tabs button.active,
body.theme-dark .settings-tabs button.active,
body.theme-dark .field-work-tabs button.active {
  background: var(--n-300);
}

/* 업무·티켓·인수인계 번호는 사람이 서로 부르는 이름이라 주변 글자와 섞이면 안 된다.
   회색 바탕의 굵은 고정폭 배지로 떼어 낸다. 표 칸(td)에는 바탕을 깔지 않고 굵기만 준다 —
   칸 전체가 회색이 되면 줄 강조와 구별되지 않는다. */
.task-id:not(td):not(th),
.customer-number:not(td):not(th) {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 5px;
  background: var(--surface-active);
  color: var(--text);
  font-weight: 600;
  line-height: 1.5;
}
td.task-id,
td.customer-number,
th.customer-number {
  color: var(--text);
  font-weight: 600;
}

/* 화면 제목은 한 화면에 하나, 가장 크게. 설명 줄은 회색으로 한 단계 낮춘다. */
.page-head h1 {
  font-size: var(--fs-title1);
  font-weight: 650;
  letter-spacing: -0.02em;
}
.page-head {
  border-bottom: 0;
  padding: 0;
  align-items: center;
  gap: var(--s-3);
  min-height: 40px;
  margin-bottom: var(--s-3);
}
.page-head h1 { margin:0; }
.page-head > div:first-child { display:flex; align-items:center; gap:var(--s-3); min-width:0; flex-wrap:wrap; }
.page-head .page-head-actions { display:flex; align-items:center; gap:var(--s-2); }
.page-head summary { list-style:none; }
.page-head summary::-webkit-details-marker { display:none; }
.page-head-more { position:relative; }
.page-head-more > .form-actions { position:absolute; right:0; top:calc(100% + var(--s-1)); z-index:var(--z-popover, 50); min-width:max-content; padding:var(--s-2); background:var(--surface); border:1px solid var(--divider); border-radius:var(--radius-md); box-shadow:var(--shadow-pop); }
@media(min-width:901px) {
  .page-head { flex-wrap:nowrap; }
  .page-head > div:first-child { flex:1 1 auto; flex-wrap:nowrap; }
  .page-head .page-head-actions { flex-shrink:0; }
  .page-head .tabs { min-width:0; overflow-x:auto; flex-wrap:nowrap; white-space:nowrap; }
  .page-head .button { height:27px; min-height:27px; }
  .page-head h1 { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
}
.page-head > div:first-child > h1 + nav { margin:0; }
.page-head .page-meta { color:var(--text-muted); font-size:var(--fs-caption); }
.page-head .button { min-height:27px; padding:var(--s-1) var(--s-2); font-size:var(--fs-caption); }
.panel {
  border-color: var(--divider);
  border-radius: var(--radius-lg);
}

/* ── 2026-10 개편: 업무 목록 ─────────────────────────────────────────────── */
.page-count {
  margin-left: 6px;
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.tasks-page .task-filter-bar {
  grid-template-columns: minmax(200px, 1fr) auto auto auto auto;
  align-items: center;
}
.tasks-page .task-filter-chips:not(.is-stacked) {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border-radius: 9px;
  background: var(--surface-active);
}
.tasks-page .task-filter-chips:not(.is-stacked) .task-filter-chip {
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--text-secondary);
  font-weight: 500;
  padding: 5px 12px;
}
.tasks-page .task-filter-chips:not(.is-stacked) .task-filter-chip.active {
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(13, 13, 15, 0.12);
}
.task-filter-pop-wrap {
  position: relative;
}
.task-filter-pop {
  position: absolute;
  z-index: 30;
  top: calc(100% + 6px);
  right: 0;
  width: 240px;
  padding: var(--s-3);
  display: grid;
  gap: var(--s-3);
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow:
    0 0 0 1px var(--border),
    var(--shadow-pop);
  animation: none;
}
.task-filter-pop[hidden] {
  display: none;
}
.task-filter-chips.is-stacked {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  overflow: visible;
}
.task-filter-team {
  display: grid;
  gap: 4px;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.task-date-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-4);
  background: var(--surface-2);
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
}
.task-date-field {
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.due-over {
  color: var(--danger);
  font-weight: 600;
}
.due-today {
  color: var(--text);
  font-weight: 600;
}
@media (max-width: 760px) {
  .tasks-page .task-filter-bar {
    grid-template-columns: auto auto 1fr;
  }
  .tasks-page .task-result-count {
    justify-self: end;
  }
  .tasks-page .task-filter-bar .input.search,
  .tasks-page .task-filter-chips:not(.is-stacked) {
    grid-column: 1 / -1;
  }
  .task-filter-pop {
    right: auto;
    left: 0;
  }
}

/* ── 2026-10 개편: 업무 상세 머리 ───────────────────────────────────────────
   왼쪽은 어디서 왔는지(‹ 업무), 오른쪽은 할 일. 주 행동(완료)을 맨 오른쪽 끝에 두고,
   되돌릴 수 없는 삭제는 ••• 메뉴 맨 아래 빨간 글자로 내린다. */
.task-detail-toolbar {
  align-items: center;
  margin-bottom: var(--s-2);
  padding-bottom: 0;
}
.task-detail-crumb {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.more-menu-wrap {
  position: relative;
}
.more-menu {
  position: absolute;
  z-index: 40;
  top: calc(100% + 6px);
  right: 0;
  min-width: 200px;
  padding: 5px;
  display: grid;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow:
    0 0 0 1px var(--border),
    var(--shadow-pop);
  animation: ds-drop var(--t) both;
}
.more-menu[hidden] {
  display: none;
}
.more-menu .button {
  justify-content: flex-start;
  width: 100%;
  background: transparent;
  border: 0;
  color: var(--text);
  font-weight: 500;
}
.more-menu .button:hover {
  background: var(--surface-active);
}
.more-menu .button.danger {
  color: var(--danger);
}
.more-menu .button.danger:hover {
  background: var(--danger-soft);
  filter: none;
}
.more-menu hr {
  border: 0;
  border-top: 1px solid var(--divider);
  margin: 4px 6px;
}
/* 마감순 묶음 머리. 표의 한 줄이지만 업무가 아니라 구분선이라 바탕 없이 작은 글자로. */
.data-table tbody tr.task-group-row td {
  padding: var(--s-4) var(--s-3) var(--s-1);
  font-size: var(--fs-caption);
  font-weight: 650;
  color: var(--text-muted);
  background: transparent;
  border-bottom: 0;
}
.data-table tbody tr.task-group-row.is-over td {
  color: var(--danger);
}
.data-table tbody tr.task-group-row:hover {
  background: transparent;
}

/* ── 2026-10 개편: 대시보드 ────────────────────────────────────────────────
   사무실 모니터에 띄워 두는 화면이다. 멀리서도 "지금 누가 있나, 다음 교대까지 얼마나,
   일이 얼마나 쌓였나" 세 가지가 먼저 읽히게, 글자보다 막대와 큰 숫자로 말한다. */
.coverage-region {
  padding: var(--s-2) 0 2px;
  font: 650 var(--fs-micro) var(--sans);
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.coverage-bar {
  height: 20px;
  border-radius: 6px;
}
.coverage-bar.region-kr {
  background: #c9d8fa;
}
.coverage-bar.region-us {
  background: #c4e3cf;
}
.coverage-bar.region-kr .coverage-hours {
  color: #1f4fb8;
}
.coverage-bar.region-us .coverage-hours {
  color: #17602d;
}
.coverage-hours {
  font-size: var(--fs-micro);
}
body.theme-dark .coverage-bar.region-kr {
  background: #2b4170;
}
body.theme-dark .coverage-bar.region-us {
  background: #24503a;
}
body.theme-dark .coverage-bar.region-kr .coverage-hours,
body.theme-dark .coverage-bar.region-us .coverage-hours {
  color: #fff;
}
/* 다음 교대 카드는 화면에서 가장 진한 면 하나로 둔다. 큰 숫자가 멀리서도 읽혀야 한다. */
.shift-chain-side {
  border: 0;
  border-radius: var(--radius-lg);
  background: #1d1d1f;
  color: #fff;
  padding: var(--s-5);
}
.shift-chain-side > span {
  color: rgba(255, 255, 255, 0.6);
  font: 600 var(--fs-caption) var(--sans);
  letter-spacing: 0;
}
.shift-chain-side > strong {
  font: 600 48px/1.05 var(--mono);
  color: #fff;
  letter-spacing: -0.02em;
}
.shift-chain-side > p {
  color: rgba(255, 255, 255, 0.75);
  font-size: var(--fs-callout);
}
.shift-chain-side > div {
  border-top-color: rgba(255, 255, 255, 0.14);
}
.shift-chain-side b {
  color: #fff;
  font-size: var(--fs-callout);
}
.shift-chain-side small {
  color: rgba(255, 255, 255, 0.6);
  font-size: var(--fs-caption);
}
.shift-chain-standing {
  color: #ffc266;
}

.status-flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4) var(--s-6);
  margin: var(--s-4) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.status-flow h2 {
  flex: none;
  font-size: var(--fs-body);
}
.status-flow-main {
  flex: 1 1 360px;
  display: grid;
  gap: var(--s-2);
}
.status-flow-bar {
  display: flex;
  gap: 2px;
  height: 14px;
  border-radius: 7px;
  overflow: hidden;
}
.status-flow-bar .is-new {
  background: var(--n-400);
}
.status-flow-bar .is-progress {
  background: var(--accent);
}
.status-flow-bar .is-waiting {
  background: #b25000;
}
.status-flow-bar .is-done {
  background: var(--ok);
}
.status-flow-bar .is-empty {
  background: var(--surface-active);
}
.status-flow-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-5);
}
.status-flow-item,
.status-flow-critical {
  border: 0;
  background: none;
  padding: 2px 0;
  font: 500 var(--fs-callout) var(--sans);
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: var(--radius);
  transition: color var(--t-fast);
}
.status-flow-item b {
  font-size: var(--fs-title1);
  font-weight: 650;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.status-flow-item.is-progress b {
  color: var(--accent);
}
.status-flow-item.is-waiting b {
  color: #b25000;
}
.status-flow-item.is-done b {
  color: var(--ok);
}
.status-flow-item:hover {
  color: var(--text);
}
.status-flow-critical {
  padding: 8px 14px;
  font-weight: 600;
  background: var(--surface-active);
}
.status-flow-critical b {
  font-size: var(--fs-title1);
  font-weight: 650;
}
.status-flow-critical.has-items {
  background: var(--danger-soft);
  color: var(--danger);
}
/* 인수 대기·지연은 카드 전체가 아니라 아래 표시 한 줄로 말한다. 카드 바탕까지 노랗게 바꾸면
   흰 숫자가 묻힌다. 지연일 때만 숫자를 붉게 해 멀리서도 알아보게 한다. */
.shift-chain-side.is-waiting,
.shift-chain-side.is-late,
body.theme-dark .shift-chain-side.is-waiting,
body.theme-dark .shift-chain-side.is-late {
  background: #1d1d1f;
  border: 0;
}
.shift-chain-side.is-waiting .shift-chain-standing,
.shift-chain-side.is-late .shift-chain-standing,
body.theme-dark .shift-chain-side.is-waiting .shift-chain-standing,
body.theme-dark .shift-chain-side.is-late .shift-chain-standing {
  background: rgba(255, 179, 64, 0.18);
  border-color: transparent;
  color: #ffc266;
}
.shift-chain-side.is-late > strong,
body.theme-dark .shift-chain-side.is-late > strong {
  color: #ff8a80;
}
.shift-chain-side.is-late .shift-chain-standing,
body.theme-dark .shift-chain-side.is-late .shift-chain-standing {
  background: rgba(255, 107, 107, 0.2);
  color: #ff9a92;
}

/* ── 2026-10 개편: 인수인계 ───────────────────────────────────────────────
   메일함처럼 왼쪽 목록·오른쪽 본문. 지금 것은 파란 테두리 카드 한 장, 지난 것은 작은 회색 줄. */
.handover-mail {
  display: grid;
  grid-template-columns: minmax(260px, 300px) minmax(0, 1fr);
  gap: var(--s-6);
  align-items: start;
}
.handover-list-col {
  display: grid;
  gap: var(--s-2);
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
}
.handover-now-label {
  font: 700 var(--fs-micro) var(--sans);
  letter-spacing: 0.04em;
  color: var(--accent);
  padding: 0 4px;
}
.handover-now,
.handover-recent {
  display: grid;
  gap: 4px;
  width: 100%;
  text-align: left;
  border: 0;
  cursor: pointer;
  font: inherit;
  color: var(--text);
  transition:
    background-color var(--t-fast),
    box-shadow var(--t-fast);
}
.handover-now {
  padding: var(--s-4);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow:
    inset 0 0 0 2px var(--accent),
    0 4px 14px rgba(47, 111, 235, 0.12);
}
.handover-recent-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-2);
}
.handover-now-badge {
  font: 700 var(--fs-micro) var(--sans);
  color: #fff;
  background: var(--accent);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
}
.handover-now-summary {
  font-size: var(--fs-caption);
  line-height: 1.5;
}
.handover-now-meta {
  font-size: var(--fs-caption);
  font-weight: 600;
  color: #9a4a00;
}
.handover-recent-head {
  display: flex;
  justify-content: space-between;
  margin-top: var(--s-4);
  padding: var(--s-3) 4px 0;
  border-top: 1px solid var(--divider);
  font: 700 var(--fs-micro) var(--sans);
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.handover-search {
  height: 30px;
  font-size: var(--fs-callout);
}
.handover-recent-list {
  display: grid;
}
.handover-recent {
  padding: 9px 10px;
  border-radius: var(--radius);
  background: transparent;
}
.handover-recent:hover {
  background: var(--surface-active);
}
.handover-recent .task-id {
  font-size: var(--fs-micro);
  background: transparent;
  padding: 0;
  color: var(--text-muted);
}
.handover-recent-line {
  font-size: var(--fs-caption);
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.handover-recent time {
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.handover-recent-ack {
  font: 600 var(--fs-micro) var(--sans);
  color: var(--text-muted);
}
.handover-recent-ack.is-done {
  color: var(--ok);
}
.handover-all {
  justify-self: start;
}
.handover-reader {
  display: grid;
  gap: var(--s-6);
  min-width: 0;
  max-width: 920px;
}
.handover-reader-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--fs-callout);
  color: var(--text-muted);
}
.handover-reader-meta .task-id {
  font-size: var(--fs-callout);
}
.handover-flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4);
  margin-top: var(--s-4);
}
.handover-team b {
  display: inline-grid;
  place-items: center;
  min-width: 56px;
  height: 48px;
  padding: 0 var(--s-3);
  border-radius: 14px;
  font-size: var(--fs-body);
  font-weight: 700;
}
.handover-team.region-kr b {
  background: rgba(47, 111, 235, 0.12);
  color: #1f4fb8;
}
.handover-team.region-us b {
  background: rgba(31, 122, 58, 0.12);
  color: #17602d;
}
.handover-flow-arrow {
  width: 64px;
  height: 2px;
  background: var(--border-strong);
  position: relative;
}
.handover-flow-arrow::after {
  content: '';
  position: absolute;
  right: -1px;
  top: -4px;
  width: 8px;
  height: 8px;
  border-top: 2px solid var(--border-strong);
  border-right: 2px solid var(--border-strong);
  transform: rotate(45deg);
}
.handover-flow-ack {
  margin-left: auto;
  display: grid;
  justify-items: end;
  gap: 6px;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.handover-faces {
  display: flex;
  gap: 6px;
}
.handover-face {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font: 650 var(--fs-micro) var(--sans);
  color: var(--text-muted);
  box-shadow: inset 0 0 0 1.5px var(--border-strong);
  transition:
    background-color var(--t),
    color var(--t);
}
.handover-face.is-done {
  background: var(--ok);
  color: #fff;
  box-shadow: none;
}
.handover-first {
  padding: var(--s-5);
  border-radius: var(--radius-lg);
  background: var(--surface-active);
}
.handover-first h2 {
  font-size: var(--fs-callout);
  margin-bottom: var(--s-2);
}
.handover-first,
.handover-first li,
.handover-first p {
  font-size: var(--ops-reading-size, var(--fs-title3));
  line-height: 1.6;
}
.handover-ack-bar {
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--divider);
}
.handover-ack-bar .meta {
  flex: 1;
  font-size: var(--fs-callout);
}
.handover-acked {
  font-weight: 600;
  color: var(--ok);
}
@media (max-width: 900px) {
  .handover-mail {
    grid-template-columns: 1fr;
  }
  .handover-list-col {
    position: static;
  }
  .handover-flow-ack {
    margin-left: 0;
    justify-items: start;
  }
}
/* 한 줄 말줄임이 격자 칸을 밀어내지 않게 — 격자 칸은 기본으로 내용 너비 아래로 줄지 않는다. */
.handover-list-col,
.handover-list-col > *,
.handover-recent,
.handover-now,
.handover-recent-list {
  min-width: 0;
}
.handover-mail {
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
}
@media (max-width: 900px) {
  .handover-mail {
    grid-template-columns: minmax(0, 1fr);
  }
  /* 휴대폰 아래 탭 막대 위에 확인 줄이 서도록 띄운다. */
  .handover-ack-bar {
    bottom: 64px;
  }
}
.handover-reader > *,
.handover-task-section {
  min-width: 0;
}
.handover-reader {
  grid-template-columns: minmax(0, 1fr);
}

/* Team handover briefing: the existing Operations tokens remain authoritative. */
.handover-brief-mail { grid-template-columns:208px minmax(0,1fr); }
.handover-brief-reader { max-width:none; gap:0; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg); }
.handover-brief-head { padding:var(--s-4) var(--s-5); border-bottom:1px solid var(--divider); }
.handover-brief-flow { display:flex; align-items:center; gap:var(--s-3); margin-bottom:var(--s-2); font-size:var(--fs-body); }
.handover-brief-flow .handover-flow-arrow { width:24px; flex:none; }
.handover-brief-flow strong:last-child { color:var(--accent-text); }
.handover-brief-head .handover-reader-meta { font-size:var(--fs-caption); }
.handover-brief-head .task-id { font-size:var(--fs-micro); }
.handover-brief-grid { display:grid; grid-template-columns:minmax(0,1fr) 240px; min-width:0; }
.handover-brief-document { min-width:0; padding:var(--s-5); }
.handover-brief-document > * + * { margin-top:var(--s-5); }
.handover-brief-document .handover-first { padding:0; border-radius:0; background:transparent; }
.handover-brief-document .handover-first ul { max-width:72ch; padding-left:var(--s-5); }
.handover-brief-document h2 { font-size:var(--fs-body); font-weight:600; margin:0 0 var(--s-3); }
.handover-brief-section { border-top:1px solid var(--divider); padding-top:var(--s-4); }
.handover-brief-section-head { display:flex; justify-content:space-between; gap:var(--s-3); flex-wrap:wrap; align-items:baseline; }
.handover-brief-side { min-width:0; padding:var(--s-4); border-left:1px solid var(--divider); background:var(--surface-2); border-radius:0 0 var(--radius-lg) 0; }
.handover-brief-side .handover-ack-panel { background:transparent; border:0; box-shadow:none; }
.handover-brief-side .panel-head,.handover-brief-side .panel-body { padding:0; }
.handover-brief-side .panel-head { align-items:start; margin-bottom:var(--s-3); }
.handover-brief-side .panel-head h2 { font-size:var(--fs-body); }
.handover-brief-side .handover-ack-row { flex-wrap:wrap; padding:var(--s-2) 0; }
.handover-brief-side .handover-ack-list { margin-top:var(--s-3); }
.handover-brief-side > .meta { margin-top:var(--s-4); border-top:1px solid var(--divider); padding-top:var(--s-3); }
.handover-brief-document .handover-ack-bar { position:static; background:transparent; backdrop-filter:none; }
.handover-brief-mail .handover-now { padding:var(--s-3); box-shadow:inset 0 0 0 1px var(--accent); }
.handover-brief-mail .handover-now .handover-now-meta { color:var(--text-secondary); font-weight:400; }
.handover-brief-mail .handover-recent-line { white-space:normal; }
.handover-history { min-width:0; }
.handover-history > summary { cursor:pointer; color:var(--text-secondary); font-size:var(--fs-callout); margin-top:var(--s-4); padding:var(--s-2) 0; border-top:1px solid var(--divider); }
.handover-history > .handover-search { margin:var(--s-2) 0; width:100%; }
.handover-brief-document .button.link-button,.handover-compose-preview .button.link-button { padding:0; min-height:26px; height:auto; background:transparent; color:var(--accent-text); border:0; border-radius:var(--radius-sm); text-align:left; white-space:normal; line-height:1.5; font-size:inherit; font-weight:600; overflow-wrap:anywhere; }
.handover-brief-document .button.link-button:hover { text-decoration:underline; }
.handover-priorities { margin:0; padding-left:var(--s-5); }
.handover-priorities li { padding:var(--s-3) 0; border-bottom:1px solid var(--divider); }
.handover-priorities li:last-child { border-bottom:0; }
.handover-priorities li::marker { color:var(--accent-text); font-weight:600; }
.handover-priorities h3 { font-size:var(--fs-body); margin:0; }
.handover-priorities p { max-width:72ch; white-space:pre-wrap; overflow-wrap:anywhere; margin:var(--s-2) 0; font-size:var(--fs-callout); color:var(--text-secondary); }
.handover-check-time { display:inline-block; margin-top:var(--s-2); font-size:var(--fs-caption); color:var(--warn); background:var(--warn-soft); border:1px solid var(--warn-border); padding:2px 6px; border-radius:var(--radius-sm); }
.handover-context { border-bottom:1px solid var(--divider); padding:var(--s-2) 0; }
.handover-context:last-child { border-bottom:0; }
.handover-context summary { cursor:pointer; overflow-wrap:anywhere; }
.handover-context-title { font-size:var(--fs-callout); font-weight:600; }
.handover-context summary .task-id { margin-left:var(--s-2); font-size:var(--fs-caption); }
.handover-context-body { padding:var(--s-3) 0 var(--s-2); display:grid; gap:var(--s-3); }
.handover-context-body h3 { margin:0 0 var(--s-1); font-size:var(--fs-callout); color:var(--text-secondary); font-weight:500; }
.handover-context-body p { margin:0; white-space:pre-wrap; overflow-wrap:anywhere; max-width:72ch; }
.handover-linked-events { margin:0; padding-left:var(--s-4); }
.handover-linked-events li { padding:var(--s-2) 0; }
.handover-linked-events p { margin:var(--s-1) 0; }
.handover-brief-reader .handover-task-table td:nth-child(3) { white-space:normal; overflow-wrap:anywhere; }
.handover-brief-reader .handover-task-table td:nth-child(3) > b { display:block; }
.handover-compose-modal { width:min(920px,100%); min-width:0; }
.handover-compose,.handover-compose-preview,.handover-compose .field { min-width:0; }
.handover-compose,.handover-compose .form-stack { grid-template-columns:minmax(0,1fr); }
.handover-compose-candidates .todo > span { min-width:0; overflow-wrap:anywhere; }
.handover-compose h3 { font-size:var(--fs-body); margin:0 0 var(--s-2); }
.handover-compose .todo { justify-content:flex-start; }
.handover-compose .todo > input { flex:none; }
.handover-compose-candidates { max-height:190px; overflow:auto; border:1px solid var(--border); border-radius:var(--radius); padding:var(--s-2); }
.handover-compose-candidates .todo { margin:0; min-height:36px; padding:var(--s-2); align-items:flex-start; }
.handover-compose-candidates .todo span span { display:block; }
.handover-compose-candidates .todo b { font-size:var(--ops-record-name-size,var(--fs-caption)); font-weight:600; line-height:1.5; }
.handover-compose-items { display:grid; gap:var(--s-3); }
.handover-compose-item { border:1px solid var(--border); border-radius:var(--radius); }
.handover-compose-item > summary { cursor:pointer; padding:var(--s-3); font-size:var(--fs-callout); overflow-wrap:anywhere; }
.handover-compose-item > summary .meta { display:block; padding-left:var(--s-3); }
.handover-compose-item > .form-stack { padding:var(--s-3); border-top:1px solid var(--divider); }
.handover-compose textarea { width:100%; resize:vertical; }
.handover-compose-order { display:grid; gap:var(--s-2); }
.handover-order-row { display:flex; align-items:center; justify-content:space-between; gap:var(--s-3); }
.handover-order-row > span { min-width:0; overflow-wrap:anywhere; }
.handover-order-row > div { display:flex; gap:var(--s-2); flex:none; }
.handover-compose-preview { border-top:1px solid var(--border); padding-top:var(--s-4); }
.handover-compose-preview:focus { outline:2px solid var(--accent); outline-offset:4px; }
.handover-compose-preview > .handover-first { margin-top:var(--s-3); }
@media(max-width:1250px) {
  .handover-brief-grid { grid-template-columns:minmax(0,1fr); }
  .handover-brief-side { border-left:0; border-top:1px solid var(--divider); border-radius:0 0 var(--radius-lg) var(--radius-lg); }
}
@media(max-width:900px) {
  .handover-compose .form-grid { grid-template-columns:minmax(0,1fr); }
  .handover-brief-mail { grid-template-columns:minmax(0,1fr); gap:var(--s-4); }
  .handover-brief-head,.handover-brief-document { padding:var(--s-4); }
  .handover-brief-flow { flex-wrap:wrap; }
  .handover-brief-document .handover-ack-bar { flex-wrap:wrap; }
  .handover-order-row { flex-wrap:wrap; }
}
@media(pointer:coarse) {
  .handover-compose summary,.handover-compose .todo,.handover-context summary { min-height:44px; }
  .handover-brief-document .button.link-button,.handover-compose .button { min-height:44px; }
}

/* ── 2026-10 개편: 캘린더 ────────────────────────────────────────────────
   달 보기 칸에는 근무를 조 이름·시각만 짧게, 평소와 다른 것(휴가·공휴일·교환·당번·일정)은
   또렷하게. 누가 서는지는 날짜를 눌러 오른쪽 패널에서 본다. */
.calendar-page .panel-body:has(> .cal-day-panel) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--s-5);
  align-items: start;
}
.calendar-page .panel-body:has(> .cal-day-panel) > .calendar-legend {
  grid-column: 1 / -1;
}
.calendar-page .panel-body:has(> .cal-day-panel) > .calendar-grid { grid-column: 1; grid-row: 1; }
.calendar-page .panel-body > .cal-day-panel { grid-column: 2; grid-row: 1; }
.calendar-grid:not(.is-week) .cal-shift-members {
  display: none;
}
.calendar-grid:not(.is-week) .cal-shift-chip {
  padding: 1px 6px;
  border-radius: 5px;
  font-size: var(--fs-micro);
  opacity: 0.85;
}
.calendar-grid:not(.is-week) .cal-shift-chip.is-swap,
.calendar-grid:not(.is-week) .cal-shift-chip.is-extra,
.calendar-grid:not(.is-week) .cal-shift-chip.is-holiday-duty {
  opacity: 1;
  box-shadow: inset 0 0 0 1.5px currentColor;
}
.calendar-grid:not(.is-week) .cal-shift-chip.is-swap .cal-shift-head b::after {
  content: ' ↔';
}
.cal-day-pick {
  border: 0;
  background: none;
  padding: 0;
  min-width: 24px;
  height: 24px;
  border-radius: 50%;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background-color var(--t-fast);
}
.cal-day-pick:hover {
  background: var(--surface-active);
}
.cal-day-pick[aria-pressed='true'] {
  background: var(--accent);
  color: #fff;
}
.cal-cell.is-selected {
  background: var(--accent-soft);
}
.cal-day-panel {
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
  display: grid;
  gap: var(--s-2);
  padding: var(--s-4);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  border: 1px solid var(--divider);
  animation: ds-rise var(--t) both;
}
.cal-day-panel h3 {
  font-size: var(--fs-title3);
  font-weight: 650;
}
.cal-day-panel h4 {
  margin: var(--s-3) 0 0;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.cal-day-axis {
  display: flex;
  justify-content: space-between;
  margin-left: 0;
  font: var(--fs-micro) var(--mono);
  color: var(--text-faint);
}
.cal-day-lane {
  display: grid;
  gap: 3px;
}
.cal-day-team {
  font-size: var(--fs-caption);
  font-weight: 600;
}
.cal-day-track {
  position: relative;
  height: 12px;
  border-radius: 6px;
  background: var(--surface-active);
}
.cal-day-bar {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 6px;
  background: #8fb0f3;
}
.cal-day-bar.region-us {
  background: #8cc7a1;
}
.cal-day-bar.is-holiday-duty {
  background: #b9a3e6;
}
.cal-day-who {
  font-size: var(--fs-caption);
  color: var(--text-secondary);
}
.cal-day-changes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
  font-size: var(--fs-callout);
}
.cal-day-changes li::before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--accent);
}
.cal-day-changes li.is-holiday::before {
  background: var(--danger);
}
.cal-day-changes li.is-leave::before {
  background: #b25000;
}
.cal-day-changes .cal-event {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--accent);
  cursor: pointer;
}
@media (max-width: 1100px) {
  .calendar-page .panel-body:has(> .cal-day-panel) {
    grid-template-columns: minmax(0, 1fr);
  }
  .cal-day-panel {
    position: static;
  }
  .calendar-page .panel-body > .cal-day-panel { grid-column: 1; grid-row: 1; }
  .calendar-page .panel-body:has(> .cal-day-panel) > .calendar-grid { grid-row: 2; }
}

/* ── 2026-10 개편: 고객 티켓 ─────────────────────────────────────────────── */
.ticket-rail h3 + .inventory-rail-item {
  margin-top: 2px;
}
.ticket-filter-bar .ticket-seg {
  margin: 0;
  flex-wrap: nowrap;
}
.ticket-age {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 5px;
  font: 650 var(--fs-micro) var(--sans);
  background: var(--surface-active);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.ticket-age.is-warn {
  background: var(--warn-soft);
  color: #9a4a00;
}
.ticket-age.is-late {
  background: var(--danger-soft);
  color: var(--danger);
}

/* ── 2026-10 개편: 숫자 줄 ─────────────────────────────────────────────────
   화면마다 숫자 카드 네다섯 장이 따로 떠 있었다. 카드가 여럿 서면 같은 무게로 보여 어느 숫자가
   중요한지 말하지 못하고, 화면 위쪽을 상자들이 차지한다. 한 면 위에 얇은 선으로 나눈 한 줄로
   바꾼다 — 숫자는 그대로, 상자만 걷는다. 누를 수 있는 칸(고르기)은 그대로 누를 수 있다. */
.inventory-totals,
.customer-totals,
.walkthrough-kpis,
.field-work-kpis,
.cloud-summary,
.runbook-summary,
.leave-summary,
.report-hero-kpis {
  gap: 0 !important;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: none;
}
.inventory-totals > *,
.customer-totals > *,
.walkthrough-kpis > *,
.field-work-kpis > *,
.cloud-summary > *,
.runbook-summary > *,
.leave-summary > *,
.report-hero-kpis > * {
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  background: transparent;
}
.inventory-totals > * + *,
.customer-totals > * + *,
.walkthrough-kpis > * + *,
.field-work-kpis > * + *,
.cloud-summary > * + *,
.runbook-summary > * + *,
.leave-summary > * + *,
.report-hero-kpis > * + * {
  box-shadow: inset 1px 0 0 var(--divider) !important;
}
.inventory-totals > .is-selected,
.inventory-totals > .active {
  background: var(--accent-soft);
}

/* ── 2026-10 개편: 진행 중 장애 ───────────────────────────────────────────── */
.incident-active {
  display: grid;
  gap: var(--s-3);
  margin-bottom: var(--s-5);
}
.incident-active-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(220px, 1fr);
  gap: var(--s-6);
  padding: var(--s-5) var(--s-6);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow:
    0 0 0 1px var(--danger-border),
    0 6px 20px rgba(196, 55, 59, 0.08);
  overflow: hidden;
}
.incident-active-card::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 5px;
  background: var(--danger);
}
.incident-active-card.sev-sev3,
.incident-active-card.sev-sev4 {
  box-shadow:
    0 0 0 1px var(--warn-border),
    0 6px 20px rgba(154, 98, 5, 0.06);
}
.incident-active-card.sev-sev3::before,
.incident-active-card.sev-sev4::before {
  background: #b25000;
}
.incident-active-main {
  display: grid;
  gap: var(--s-3);
  min-width: 0;
}
.incident-active-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.incident-active-card h2 {
  font-size: var(--fs-title1);
  font-weight: 650;
  letter-spacing: -0.01em;
}
.incident-active-facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-6);
}
.incident-active-facts span,
.incident-active-label {
  display: block;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.incident-active-facts b {
  font-size: var(--fs-body);
  font-weight: 600;
}
.incident-elapsed {
  font: 650 var(--fs-display) var(--mono) !important;
  color: var(--danger);
}
.incident-active-side {
  display: grid;
  align-content: start;
  gap: 6px;
  min-width: 0;
}
.incident-active-side p {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.5;
}
.incident-active-side time {
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.incident-active-side .button {
  justify-self: start;
  margin-top: var(--s-2);
}
@media (max-width: 760px) {
  .incident-active-card {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-4);
    padding: var(--s-4);
  }
}

/* ── 2026-10 개편: 설정 ──────────────────────────────────────────────────
   맥 시스템 설정처럼 왼쪽 목록(무리 넷) + 오른쪽 내용. 좁은 화면에서는 목록이 위로 올라가
   가로로 밀린다. */
.settings-layout {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  gap: var(--s-6);
  align-items: start;
}
.settings-nav {
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
  display: grid;
  gap: var(--s-4);
}
.settings-nav-group {
  display: grid;
  gap: 1px;
}
.settings-nav-group h3 {
  margin: 0 0 4px;
  padding: 0 10px;
  font: 600 var(--fs-micro) var(--sans);
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.settings-nav button {
  text-align: left;
  border: 0;
  background: none;
  padding: 7px 10px;
  border-radius: var(--radius);
  font: 500 var(--fs-callout) var(--sans);
  color: var(--text);
  cursor: pointer;
  transition: background-color var(--t-fast);
}
.settings-nav button:hover {
  background: var(--surface-active);
}
.settings-nav button.active {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}
.settings-tab-content {
  min-width: 0;
}
@media (max-width: 900px) {
  .settings-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .settings-nav {
    position: static;
    display: flex;
    overflow-x: auto;
    gap: var(--s-3);
  }
  .settings-nav-group {
    display: flex;
    align-items: center;
    gap: 2px;
    flex: none;
  }
  .settings-nav-group h3 {
    display: none;
  }
  .settings-nav button {
    white-space: nowrap;
  }
}

/* ── 2026-10 개편: 팀 ─────────────────────────────────────────────────── */
.data-table tbody tr.team-group-row td,
.table tbody tr.team-group-row td {
  padding-top: var(--s-4);
  font-size: var(--fs-callout);
  background: transparent;
  border-bottom: 1px solid var(--divider);
}
.team-region {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 5px;
  font: 700 var(--fs-micro) var(--sans);
}
.team-region.region-kr {
  background: rgba(47, 111, 235, 0.12);
  color: #1f4fb8;
}
.team-region.region-us {
  background: rgba(31, 122, 58, 0.12);
  color: #17602d;
}
.team-members-page .team-region.is-global,
body.theme-dark .team-members-page .team-region.is-global { background:var(--surface-2); color:var(--text-secondary); }
.team-members-page .team-region { display:inline-flex; align-items:center; gap:var(--s-1); }
.team-country-flag { object-fit:contain; border-radius:0; flex:none; }
.team-members-page .page-head-actions { flex-wrap:wrap; min-width:0; max-width:100%; }
.team-country-filter { display:flex; align-items:center; gap:var(--s-2); font-size:var(--fs-callout); }
.team-country-filter > span { white-space:nowrap; flex:none; }
.record-status-details { font-size:var(--fs-callout); }
.record-status-details summary { cursor:pointer; display:list-item; min-height:27px; line-height:27px; margin-inline-start:var(--s-3); padding-inline:var(--s-2); }
@media(pointer:coarse) {
  .record-status-details summary { min-height:44px; line-height:44px; }
}
.week-strip {
  display: flex;
  gap: 2px;
  width: 112px;
  margin-bottom: 4px;
}
.week-strip i {
  flex: 1;
  height: 10px;
  border-radius: 3px;
  background: var(--surface-active);
}
.week-strip i.is-on {
  background: #8fb0f3;
}
.week-strip i.is-night {
  background: #4a4a8a;
}

/* ── 2026-10 개편: 2주 부재 ────────────────────────────────────────────── */
.absence-panel {
  margin: var(--s-4) 0;
}
.absence-grid {
  display: grid;
  gap: 4px;
  overflow-x: auto;
}
.absence-row {
  display: grid;
  grid-template-columns: 120px repeat(14, minmax(18px, 1fr));
  gap: 3px;
  align-items: center;
  min-width: 420px;
}
.absence-row > span:first-child {
  font-size: var(--fs-callout);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.absence-row.is-head span {
  font: var(--fs-micro) var(--mono);
  color: var(--text-muted);
  text-align: center;
}
.absence-row.is-head span.is-weekend {
  color: var(--danger);
}
.absence-row i {
  height: 22px;
  border-radius: 4px;
  background: var(--surface-active);
}
.absence-row i.is-weekend {
  background: var(--n-150);
}
.absence-row i.is-leave,
.absence-legend i.is-leave {
  background: rgba(178, 80, 0, 0.4);
}
.absence-row i.is-comp,
.absence-legend i.is-comp {
  background: rgba(110, 60, 200, 0.35);
}
.absence-row i.is-pending {
  background: repeating-linear-gradient(45deg, rgba(178, 80, 0, 0.35) 0 4px, transparent 4px 8px);
}
.absence-legend {
  display: flex;
  gap: var(--s-3);
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.absence-legend i {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 4px;
  border-radius: 3px;
  vertical-align: -1px;
}

/* ── 2026-10 개편: IPAM 사용률 ─────────────────────────────────────────── */
.ipam-usage {
  display: inline-grid;
  grid-template-columns: 90px auto auto;
  align-items: center;
  gap: 8px;
}
.ipam-usage-bar {
  display: flex;
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--surface-active);
}
.ipam-usage-bar .is-allocated {
  background: var(--accent);
}
.ipam-usage-bar .is-reserved {
  background: #b9a3e6;
}
.ipam-usage small {
  font-size: var(--fs-micro);
  color: var(--text-muted);
}
.ipam-usage.is-busy small {
  color: #9a4a00;
  font-weight: 600;
}
.ipam-usage.is-full small,
.ipam-usage.is-full b {
  color: var(--danger);
  font-weight: 650;
}

/* ── 2026-10 개편: 랙 지도 ─────────────────────────────────────────────── */
.walkthrough-rack-map {
  display: grid;
  gap: var(--s-3);
  margin: var(--s-5) 0;
}
.walkthrough-rack-map .walkthrough-section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.rack-map-legend {
  display: flex;
  gap: var(--s-3);
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.rack-map-legend i {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 4px;
  border-radius: 3px;
  background: var(--surface-active);
  vertical-align: -1px;
}
.rack-map-legend i.is-pass,
.rack-tile.is-pass {
  background: var(--ok-soft);
  color: var(--ok);
}
.rack-map-legend i.is-pass {
  background: var(--ok);
}
.rack-map-legend i.is-fail,
.rack-tile.is-fail {
  background: var(--danger);
  color: #fff;
}
.rack-map-site h3 {
  margin: 0 0 6px;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.rack-map-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 6px;
}
.rack-tile {
  height: 52px;
  display: flex;
  align-items: flex-end;
  padding: 5px 6px;
  box-sizing: border-box;
  border-radius: 6px;
  background: var(--surface-active);
  color: var(--text-muted);
  font: 600 10.5px var(--mono);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.rack-tile.is-pass {
  background: rgba(31, 122, 77, 0.2);
}
.rack-map-legend i {
  box-shadow: inset 0 0 0 1px var(--border-strong);
}

/* ── 2026-10 개편: 런북 목록 ──────────────────────────────────────────────
   카드 격자는 칸마다 같은 크기의 상자가 서서 제목을 훑기 어려웠다. 한 줄씩 늘어놓는 목록으로 —
   왼쪽 번호·상태, 가운데 제목·요약·분류, 오른쪽 예상 시간·버전. 마크업은 그대로 두고 배치만 바꾼다. */
.runbook-grid {
  display: grid !important;
  grid-template-columns: minmax(0, 1fr) !important;
  gap: 0 !important;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.runbook-grid > .runbook-card {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) 180px;
  grid-template-areas:
    'head title foot'
    'head sum foot'
    'head tax foot';
  column-gap: var(--s-5);
  row-gap: 4px;
  padding: var(--s-4) var(--s-5);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  cursor: pointer;
  transition: background-color var(--t-fast);
}
.runbook-grid > .runbook-card + .runbook-card {
  border-top: 1px solid var(--divider);
}
.runbook-grid > .runbook-card:hover {
  background: var(--surface-hover);
  transform: none;
}
.runbook-card > header {
  grid-area: head;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 6px;
  margin: 0;
}
.runbook-card > h3 {
  grid-area: title;
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 650;
}
.runbook-card > p {
  grid-area: sum;
  margin: 0;
  font-size: var(--fs-callout);
  color: var(--text-secondary);
}
.runbook-card > .runbook-taxonomy {
  grid-area: tax;
  margin: 2px 0 0;
}
.runbook-card > footer {
  grid-area: foot;
  display: grid;
  align-content: center;
  justify-items: end;
  gap: 2px;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
@media (max-width: 760px) {
  .runbook-grid > .runbook-card {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: 'head' 'title' 'sum' 'tax' 'foot';
  }
  .runbook-card > header {
    flex-direction: row-reverse;
    justify-content: space-between;
    width: 100%;
  }
  .runbook-card > footer {
    justify-items: start;
  }
}
.runbook-grid > .runbook-card {
  min-height: 0;
  height: auto;
  align-content: start;
}
.runbook-card > .runbook-taxonomy {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 4px;
}
.runbook-card > .runbook-taxonomy span {
  height: auto;
  align-self: flex-start;
}
.runbook-card > p {
  margin-top: 0 !important;
}

/* ── 2026-10 개편: Cloud 지역 카드 ─────────────────────────────────────── */
.cloud-region-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--s-3);
  padding: var(--s-4);
}
.cloud-region-card {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-4);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  border: 1px solid var(--divider);
}
.cloud-region-card.is-warn {
  border-color: var(--warn-border);
  box-shadow: 0 0 0 1px var(--warn-border);
}
.cloud-region-card header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.cloud-region-card h3 {
  font-size: var(--fs-title3);
  font-weight: 650;
}
.cloud-region-state {
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--ok);
}
.cloud-region-card.is-warn .cloud-region-state {
  color: #9a4a00;
}
.cloud-region-card.is-unknown .cloud-region-state { color: var(--text-muted); }
.cloud-ha-pair {
  display: grid;
  gap: 6px;
}
.cloud-ha-name {
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.cloud-ha-nodes {
  display: flex;
  align-items: center;
  gap: 6px;
}
.cloud-ha-node {
  flex: 1;
  display: grid;
  padding: 8px 10px;
  border-radius: var(--radius);
  background: var(--surface);
  font-size: var(--fs-callout);
}
.cloud-ha-node small {
  color: var(--text-muted);
  font-size: var(--fs-micro);
}
.cloud-ha-pair.is-ok .cloud-ha-node:not(.is-standby) {
  background: var(--ok-soft);
}
.cloud-ha-pair.is-warn .cloud-ha-node {
  background: var(--warn-soft);
}
.cloud-ha-link {
  color: var(--text-faint);
}
.cloud-region-meta {
  margin: 0;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}

/* ── 2026-10-05 수정: 다음 교대 카드 ─────────────────────────────────────
   검은 면은 밝은 화면 안에서 혼자 튀었고, 지연 때 연분홍 숫자는 경고로도 정돈된 화면으로도 읽히지
   않았다. 다른 면과 같은 흰 면으로 돌리고 큰 숫자만 남긴다. 지연은 숫자를 빨강, 아래 줄을 옅은
   빨강 바탕으로 — 다른 화면의 경고와 같은 색이다. */
.shift-chain-side,
.shift-chain-side.is-waiting,
.shift-chain-side.is-late,
body.theme-dark .shift-chain-side.is-waiting,
body.theme-dark .shift-chain-side.is-late {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--divider);
}
.shift-chain-side > span {
  color: var(--text-muted);
}
.shift-chain-side > strong {
  color: var(--text);
}
.shift-chain-side > p,
.shift-chain-side small {
  color: var(--text-muted);
}
.shift-chain-side b {
  color: var(--text);
}
.shift-chain-side > div {
  border-top-color: var(--divider);
}
.shift-chain-side.is-waiting .shift-chain-standing,
body.theme-dark .shift-chain-side.is-waiting .shift-chain-standing {
  background: var(--warn-soft);
  color: var(--warn);
}
.shift-chain-side.is-late > strong,
body.theme-dark .shift-chain-side.is-late > strong {
  color: var(--danger);
}
.shift-chain-side.is-late .shift-chain-standing,
body.theme-dark .shift-chain-side.is-late .shift-chain-standing {
  background: var(--danger-soft);
  color: var(--danger);
}

/* ── 2026-10-05 재점검: 시안과 어긋난 공통 부분 ──────────────────────────────
   시안은 "선과 상자를 덜" 이 원칙이었는데, 옛 규칙이 남아 화면마다 같은 소음이 반복됐다. */

/* 메뉴의 별은 모든 줄에 늘 떠 있어 메뉴가 두 줄짜리 표처럼 보였다. 즐겨찾기한 것과 마우스를
   올린 줄에만 보인다. 키보드로 왔을 때도 보인다. */
.nav button .fav-star {
  opacity: 0;
  transition: opacity var(--t-fast);
}
.nav button:hover .fav-star,
.nav button:focus-visible .fav-star,
.nav button .fav-star.on,
.nav button .fav-star:focus-visible {
  opacity: 1;
}

/* 표 머리의 대문자·자간은 영문 표 습관이다. 한글 화면에서는 작은 회색 글자면 충분하다. */
.data-table thead th,
.task-list thead th,
.table thead th {
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--fs-caption);
  font-weight: 600;
}

/* 패널 머리 아래 선을 걷는다. 제목과 내용 사이는 여백으로 나눈다. */
.panel-head {
  border-bottom-color: transparent;
}

/* Page headers carry titles/actions. Guidance belongs beside its related control. */

/* 인수인계 본문의 파란 세로 막대 제목은 옛 꾸밈이라 다른 화면과 맞지 않았다. */
.handover-reading-section h3 {
  border-left: 0 !important;
  padding-left: 0 !important;
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-weight: 600;
}
.handover-reading-grid {
  border: 0;
  gap: var(--s-5);
}
.handover-reading-section {
  border: 0 !important;
  padding: 0 !important;
}

/* ── 2026-10-05: 캘린더 칸은 사람 이름이 먼저 (A안) ─────────────────────────
   달 보기 칸: ● 이름(둘까지, 넘으면 "외 N") + 시작 시각. 팀은 점 색으로만. 주 보기는 칸이 넓어
   지금처럼 팀·시각·명단을 다 보인다. */
.cal-shift-dot,
.cal-shift-who,
.cal-shift-start {
  display: none;
}
.calendar-grid:not(.is-week) .cal-shift-chip {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 4px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  opacity: 1;
  font: 500 var(--fs-caption) var(--sans);
  color: var(--text);
}
.calendar-grid:not(.is-week) .cal-shift-chip:hover {
  background: var(--surface-active);
}
.calendar-grid:not(.is-week) .cal-shift-head,
.calendar-grid:not(.is-week) .cal-shift-members {
  display: none;
}
.calendar-grid:not(.is-week) .cal-shift-dot {
  display: inline-block;
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
}
.calendar-grid:not(.is-week) .cal-shift-who {
  display: inline;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.calendar-grid:not(.is-week) .cal-shift-start {
  display: inline;
  margin-left: auto;
  flex: none;
  font: var(--fs-micro) var(--mono);
  color: var(--text-muted);
}
.calendar-grid:not(.is-week) .cal-shift-chip.is-swap,
.calendar-grid:not(.is-week) .cal-shift-chip.is-extra,
.calendar-grid:not(.is-week) .cal-shift-chip.is-holiday-duty {
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.calendar-grid:not(.is-week) .cal-shift-chip.is-extra .cal-shift-head {
  display: inline;
}

.cal-day-who {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
}
.cal-person {
  border: 0;
  background: var(--surface-active);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  font: 500 var(--fs-callout) var(--sans);
  color: var(--text);
  cursor: pointer;
  transition: background-color var(--t-fast);
}
.cal-person:hover {
  background: var(--accent-soft);
  color: var(--accent);
}
.cal-person.is-changed {
  box-shadow: inset 0 0 0 1.5px var(--accent);
}
.cal-day-changes li.is-off::before {
  background: var(--text-muted);
}
.day-change-choice {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: 7px;
  font-size: var(--fs-callout);
  cursor: pointer;
}
.field .day-change-choice { color: var(--text-secondary); }
.day-change-choice:has(input:checked) {
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(13, 13, 15, 0.12);
  font-weight: 600;
}
@media (max-width:900px) {
  .day-change-choice { min-height:44px; }
}
/* 휴대폰은 칸이 좁아 이름이 잘려 시각 조각만 남았다. 칸에는 근무마다 색 점 하나만 두고,
   이름·시각은 날짜를 눌러 아래 패널에서 본다. */
@media (max-width: 760px) {
  .calendar-grid:not(.is-week) .cal-cell {
    align-content: start;
  }
  .calendar-grid:not(.is-week) .cal-shift-chip {
    display: inline-flex;
    padding: 1px;
    margin: 0;
  }
  .calendar-grid:not(.is-week) .cal-shift-who,
  .calendar-grid:not(.is-week) .cal-shift-start {
    display: none;
  }
}
.team-color-field {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.team-color-field input[type='color'] {
  width: 44px;
  height: 32px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
}
.calendar-pick-hint {
  margin: var(--s-2) 0 0;
  color: var(--accent);
  font-weight: 600;
}

/* ── 2026-10-05: 업무 목록 줄 ──────────────────────────────────────────── */
.tasks-page .data-table tbody td {
  padding-top: 10px;
  padding-bottom: 10px;
  vertical-align: middle;
}
.task-main {
  min-width: 280px;
  max-width: 520px;
}
.task-line {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.task-line .task-id {
  flex: none;
  font-size: var(--fs-micro);
}
.task-line .cell-truncate {
  min-width: 0;
}
/* 승인된 목록 주 이름 역할: 화면/표/카드에 같은 caption·600·1.5.
   Operations 화면은 10px, 인쇄·공유 기본은 12px. 상세/참조 ID는 제외한다. */
.record-title,
.task-line .cell-truncate,
.triage-card-title,
.data-table .dispatch-title-link > b,
.inventory-page .inventory-table td:first-child b,
.inventory-card-name b,
.customer-rail-text b,
.customer-table td:first-child b,
.customer-busy-row > b,
.handover-task-table td:nth-child(3) > b,
.handover-page .handover-list-table td.task-id:first-child,
.handover-now-flow,
.handover-recent-line > b {
  font-size: var(--fs-caption);
  font-weight: 600;
  line-height: 1.5;
}
.task-main .subtext {
  display: block;
  margin-top: 2px;
  padding-left: 0;
}
.task-row.is-critical > td:first-child {
  box-shadow: inset 3px 0 0 var(--danger);
}
.task-row.is-high > td:first-child {
  box-shadow: inset 3px 0 0 #b25000;
}
.task-person {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.task-person b {
  display: block;
  font-weight: 500;
  font-size: var(--fs-callout);
}
.task-person small {
  display: block;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.task-avatar {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font: 650 var(--fs-micro) var(--sans);
  font-style: normal;
  background: var(--surface-active);
  color: var(--text-secondary);
}
/* 일반 우선순위는 배지를 그리지 않는다(빈 칸). 모든 줄의 "일반" 이 진짜 신호(긴급·높음)를 묻었다. */
.task-main .subtext {
  max-width: 520px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── 2026-10-05: 업무 상세 — 제목은 넓게, 사실은 옆칸 인스펙터 ─────────────── */
.task-detail-page .task-brief {
  grid-template-columns: minmax(0, 1fr) !important;
}
.task-detail-page .task-brief h1 {
  font-size: var(--fs-display);
  line-height: 1.3;
}
.task-inspector {
  padding: var(--s-4);
  margin-bottom: var(--s-4);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  border: 1px solid var(--divider);
}
.task-inspector h2 {
  margin: 0 0 var(--s-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--text-muted);
}
.task-inspector .info-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr) !important;
  gap: 0;
}
.task-inspector .info-list > div {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  padding: 8px 0;
  border: 0;
  font-size: var(--fs-callout);
}
.task-inspector .info-list > div + div {
  border-top: 1px solid var(--divider);
}
.task-inspector .info-list label {
  flex: none;
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-callout);
}
.task-inspector .info-list > div > :last-child {
  text-align: right;
}
.task-todo-note {
  margin: 0 0 var(--s-4);
  font-size: var(--fs-callout);
}
.dashboard-tasks .task-main {
  min-width: 0;
  max-width: none;
}
.dashboard-tasks td {
  white-space: nowrap;
}
.dashboard-tasks td.task-main {
  white-space: normal;
}
.dashboard-tasks .task-line .badge {
  flex: none;
}

/* ── 2026-10-05: Cloud 대시보드 ────────────────────────────────────────────
   숫자 여섯 칸이 4+2 로 꺾여 두 번째 줄 오른쪽이 비었다. 넓은 화면은 한 줄 여섯 칸, 좁으면 세 칸씩.
   운영 알림은 줄마다 빨강·노랑 면을 깔아 일곱 줄이 쌓이면 화면 전체가 경고처럼 보였다. 면은 걷고
   왼쪽 점 하나와 제목 색으로만 수준을 말한다 — 대시보드의 다른 경고와 같은 무게. */
.cloud-page .cloud-summary {
  display: grid !important;
  grid-template-columns: repeat(6, minmax(0, 1fr)) !important;
}
@media (max-width: 1100px) {
  .cloud-page .cloud-summary {
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
}
@media (max-width: 560px) {
  .cloud-page .cloud-summary {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}
.cloud-page .cloud-summary > * {
  box-shadow: inset 1px 0 0 var(--divider) !important;
}
.cloud-page .cloud-attention-critical,
.cloud-page .cloud-attention-warn {
  background: transparent;
  border-left: 0;
}
.cloud-page .cloud-attention-list li {
  position: relative;
  padding: 14px 20px 14px 36px;
}
.cloud-page .cloud-attention-list li::before {
  content: '';
  position: absolute;
  left: 18px;
  top: 21px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
}
.cloud-page .cloud-attention-critical::before {
  background: var(--danger) !important;
}
.cloud-page .cloud-attention-warn::before {
  background: #e07a00 !important;
}
.cloud-page .cloud-attention-list li strong {
  color: var(--text);
}
.cloud-page .cloud-attention-critical strong {
  color: var(--danger);
}

/* 랙 지도 — 사이트별 접이식 줄. */
.rack-map-sites {
  display: grid;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.rack-map-site + .rack-map-site {
  border-top: 1px solid var(--divider);
}
.rack-map-site-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  width: 100%;
  min-width: 0;
  padding: 12px 14px;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.rack-map-site-head:hover {
  background: var(--surface-hover, var(--n-50));
}
.rack-map-caret {
  color: var(--text-muted);
  transition: transform var(--motion-fast, 120ms);
}
.rack-map-site.is-open .rack-map-caret {
  transform: rotate(90deg);
}
.rack-map-count {
  color: var(--text-muted);
  font-size: var(--fs-caption);
}
.rack-map-status {
  margin-left: auto;
  display: flex;
  gap: 6px;
}
.rack-map-status > span {
  min-width: 28px;
  padding: 2px 8px;
  border-radius: 999px;
  font: 600 12px var(--mono);
  text-align: center;
  background: var(--surface-active);
  color: var(--text-muted);
}
.rack-map-status .is-pass {
  background: var(--ok-soft);
  color: var(--ok);
}
.rack-map-site.has-fail .rack-map-status .is-fail {
  background: var(--danger);
  color: #fff;
}
.rack-map-site.has-fail .rack-map-site-head b {
  color: var(--danger);
}
.rack-map-site .rack-map-grid {
  padding: 0 14px 14px;
}

.rack-map-locations {
  display: grid;
  gap: var(--s-3);
  padding: 0 14px 14px;
}
.rack-map-location .rack-map-grid {
  padding: 0;
}
.rack-map-location h3 {
  margin: 0 0 6px;
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--text-muted);
}

/* ── 2026-10 개편 2차: 고객 ────────────────────────────────────────────────
   시안대로 왼쪽 고객 목록(표식·사이트·자산 수), 오른쪽 내용. 머리는 제목 옆에 고객사/가입 요청 세그먼트. */
.customer-head {
  align-items: center;
}
.customer-head > div:first-child {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.customer-head .customer-main-tabs {
  margin: 0;
}
.customer-detail-page .customer-head-title {
  display: none;
}
.customer-workspace-rail {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--s-3) var(--s-2);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.customer-workspace-rail .input {
  margin: 0 0 var(--s-2);
}
.customer-rail-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.customer-rail-item,
.customer-busy-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-width: 0;
  padding: 8px 10px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.customer-rail-item:hover,
.customer-busy-row:hover {
  background: var(--surface-hover, var(--n-50));
}
.customer-rail-item.active {
  background: var(--accent-soft);
  color: var(--accent-text);
}
.customer-rail-item.active small {
  color: inherit;
}
.customer-rail-text {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}
.customer-rail-text b,
.customer-rail-text small {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.customer-rail-text small {
  font-size: var(--fs-caption);
  color: var(--text-muted);
}
.customer-rail-flag {
  flex: 0 0 auto;
  padding: 1px 7px;
  border-radius: 8px;
  font-size: var(--fs-micro);
  font-weight: 600;
  background: var(--warn-soft, rgba(178, 80, 0, 0.1));
  color: var(--warn, #9a4a00);
}
.customer-rail-item.active .customer-rail-flag {
  background: transparent;
  color: inherit;
}
.customer-mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  font-size: var(--fs-caption);
  font-weight: 700;
  background: hsl(var(--mark-hue) 60% 93%);
  color: hsl(var(--mark-hue) 55% 32%);
}
.customer-mark.is-big {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  font-size: var(--fs-title3);
}
.customer-rail-item.active .customer-mark {
  background: transparent;
  color: inherit;
}
.customer-hero {
  display: flex;
  align-items: center;
  gap: var(--s-4);
}
.customer-hero h2 {
  margin: 0;
  font-size: var(--fs-display);
  font-weight: 650;
}
.customer-detail-page .detail-header {
  margin-bottom: var(--s-4);
}
.customer-overview-busy {
  margin-top: var(--s-5);
  padding: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.customer-cap {
  margin: 0 0 var(--s-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--text-muted);
}
.customer-busy-row .meta {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.customer-busy-row .customer-rail-flag {
  margin-left: auto;
}
/* 넓은 화면은 두 칸이라 표가 필요 없다. 좁은 화면은 목록이 위로 접혀 가로로 흐르므로 표를 되살린다. */
.customer-list-workspace .customer-table-narrow {
  display: none;
}
@media (max-width: 1100px) {
  .customer-list-workspace .customer-table-narrow {
    display: block;
    margin-top: var(--s-4);
  }
  .customer-list-workspace .customer-rail-list,
  .customer-list-workspace .customer-workspace-rail > [data-auto-pager],
  .customer-list-workspace .customer-overview-busy {
    display: none;
  }
  .customer-list-workspace .customer-workspace-rail {
    padding: 0;
    border: 0;
    background: none;
  }
  .customer-list-workspace .customer-workspace-rail .input {
    margin: 0;
  }
  .customer-rail-list {
    flex-direction: row;
  }
  .customer-rail-item {
    min-width: 200px;
  }
  .customer-head {
    flex-wrap: wrap;
  }
}

/* ── 2026-10 개편 2차: 인벤토리 상태 막대 ─────────────────────────────── */
.inventory-status-bar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.inventory-status-track {
  display: flex;
  gap: 2px;
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--surface-active);
}
.inventory-status-track .is-use { background: var(--ok); }
.inventory-status-track .is-stock { background: #c7c7cc; }
.inventory-status-track .is-other { background: var(--warn, #b25000); }
.inventory-status-track .is-fault { background: var(--danger); }
.inventory-status-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
}
.inventory-status-chip {
  padding: 2px 8px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--text-secondary, #424245);
  font: inherit;
  font-size: var(--fs-caption);
  cursor: pointer;
}
.inventory-status-chip:hover { background: var(--surface-hover, var(--n-50)); }
.inventory-status-chip.active { background: var(--accent-soft); color: var(--accent-text); }
.inventory-status-chip.is-fault { color: var(--danger); }
@media (max-width: 760px), (pointer: coarse) {
  .inventory-status-chip { min-width: 44px; min-height: 44px; }
}
.inventory-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  border-radius: 50%;
  background: #c7c7cc;
  vertical-align: 1px;
}
.inventory-dot.status-in-use { background: var(--ok); }
.inventory-dot.status-fault { background: var(--danger); }
.inventory-dot.status-maintenance { background: var(--warn, #b25000); }

/* ── 2026-10 개편 2차: IPAM 서브넷 목록 + 주소 지도 ─────────────────────── */
.ipam-layout.has-map {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: var(--s-4);
  align-items: start;
}
.ipam-subnets {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: calc(100vh - var(--topbar-h) - 120px);
  overflow-y: auto;
  padding: var(--s-3) var(--s-2);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
}
.ipam-subnets-cap {
  padding: 0 10px 6px;
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--text-muted);
}
.ipam-subnet {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-callout);
  text-align: left;
  cursor: pointer;
}
.ipam-subnet:hover { background: var(--surface-hover, var(--n-50)); }
.ipam-subnet.active { background: var(--surface); box-shadow: 0 0 0 1.5px var(--accent); }
.ipam-subnet-top { display: flex; justify-content: space-between; }
.ipam-subnet-top b { font-family: var(--mono); font-weight: 600; }
.ipam-subnet-pct { font-weight: 600; }
.ipam-subnet.is-busy .ipam-subnet-pct { color: var(--warn, #9a4a00); }
.ipam-subnet.is-full .ipam-subnet-pct { color: var(--danger); }
.ipam-subnet .ipam-usage-bar { width: 100%; }
.ipam-subnet small {
  color: var(--text-muted);
  font-size: var(--fs-caption);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ipam-detail {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
  padding: var(--s-5);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.ipam-detail-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--s-3);
}
.ipam-detail-head h2 { margin: 4px 0 0; font-size: var(--fs-display); font-weight: 650; font-family: var(--mono); }
.ipam-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: var(--fs-caption); color: var(--text-secondary, #424245); }
.ipam-legend i,
.ipam-cell {
  background: var(--surface-active);
}
.ipam-legend i {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 4px;
  border-radius: 3px;
  vertical-align: -1px;
}
.ipam-legend .is-allocated, .ipam-cell.is-allocated { background: var(--accent); }
.ipam-legend .is-reserved, .ipam-cell.is-reserved { background: #b9a3e6; }
.ipam-legend .is-edge, .ipam-cell.is-edge { background: #8e8e93; }
.ipam-map {
  display: grid;
  grid-template-columns: repeat(32, minmax(0, 1fr));
  gap: 3px;
}
.ipam-map.is-dense { grid-template-columns: repeat(64, minmax(0, 1fr)); gap: 2px; }
.ipam-cell {
  aspect-ratio: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: 3px;
  cursor: pointer;
}
.ipam-cell:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
.ipam-cell.active { outline: 2px solid var(--text); outline-offset: 1px; }
.ipam-address-info {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) 28px;
  padding: 14px 16px;
  border-radius: 12px;
  background: var(--n-50, #f5f5f7);
  font-size: var(--fs-callout);
}
.ipam-address-info > div { display: flex; flex-direction: column; gap: 2px; }
.ipam-address-info .mono { font-family: var(--mono); font-size: var(--fs-title3); }
.ipam-map-hint { margin: 0; }
@media (max-width: 1100px) {
  .ipam-layout.has-map { grid-template-columns: minmax(0, 1fr); }
  .ipam-subnets { position: static; max-height: 260px; }
  .ipam-map { grid-template-columns: repeat(16, minmax(0, 1fr)); }
  .ipam-map.is-dense { grid-template-columns: repeat(32, minmax(0, 1fr)); }
}

/* ── 2026-10 개편 2차: Cloud 상태 탭 ───────────────────────────────────── */
.cloud-region-top {
  margin: var(--s-4) 0;
}
.cloud-region-top .cloud-region-card {
  background: var(--surface);
  border-radius: 14px;
  padding: 18px 20px;
}
.cloud-alerts-more {
  margin: var(--s-3) var(--s-4) var(--s-4);
}

/* ── 2026-10 개편 2차: 리포트 머리 ─────────────────────────────────────── */
.reports-page > .report-bar {
  height: auto !important;
  min-height: 0;
  overflow: visible !important;
  flex: 0 0 auto;
  padding: 0 !important;
  background: none !important;
  border: 0 !important;
  box-shadow: none !important;
}
.reports-page > .report-period-summary strong {
  letter-spacing: normal;
  word-spacing: normal;
}
.report-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-2);
}
.reports-page .report-seg {
  display: inline-flex;
  flex-wrap: wrap;
  margin: 0;
}
.reports-page .report-custom-dates {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}
.reports-page .report-custom-dates .input {
  width: auto;
}
.reports-page > .report-period-summary {
  display: block;
  margin: 0 0 var(--s-4);
  text-align: left;
}
.reports-page > .report-period-summary strong {
  font-weight: 600;
  color: var(--text);
}
@media print {
  .reports-page > .report-bar,
  .reports-page > .report-custom-dates,
  .reports-page > .report-period-summary {
    display: none !important;
  }
}

/* ── 2026-10 개편 2차: 런북 목록 + 읽는 화면 ───────────────────────────── */
.runbook-split {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: var(--s-5);
  align-items: start;
}
.runbook-list-col {
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  max-height: calc(100vh - var(--topbar-h) - var(--s-8));
  padding: var(--s-4) var(--s-3);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.runbook-list-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 4px 4px;
}
.runbook-list-head h1 { margin: 0; font-size: var(--fs-title1); font-weight: 650; }
.runbook-list-col .input.search { width: 100%; }
.runbook-list-filters { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; }
.runbook-list-filters .select { min-width: 0; height: 30px; font-size: var(--fs-caption); padding-inline: 6px 20px; }
.runbook-list-items { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; min-height: 0; }
.runbook-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 14px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-callout);
  text-align: left;
  cursor: pointer;
}
.runbook-item:hover { background: var(--surface-hover, var(--n-50)); }
.runbook-item.active { background: var(--surface); box-shadow: 0 0 0 1.5px var(--accent); }
.runbook-item-top { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.runbook-item-meta { font-size: var(--fs-caption); color: var(--text-muted); white-space: nowrap; }
.runbook-item b { font-size: var(--fs-body); font-weight: 600; }
.runbook-item small { font-size: var(--fs-caption); color: var(--text-muted); }
.runbook-split-main { min-width: 0; }
.runbook-pick-hint { margin-top: var(--s-4); }
.runbook-detail-page .runbook-detail-actions { justify-content: flex-end; }
.runbook-detail-page .runbook-detail-actions .runbook-back { margin-right: auto; }
@media (max-width: 1100px) {
  .runbook-split { grid-template-columns: minmax(0, 1fr); }
  .runbook-list-col { position: static; max-height: none; }
  .runbook-detail-page .runbook-list-col { display: none; }
  .runbook-list-items { max-height: none; }
}

/* ── 2026-10 개편 2차: 고객 티켓 ───────────────────────────────────────── */
.ticket-table .ticket-main { min-width: 0; max-width: 520px; }
.ticket-line { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ticket-line b { font-weight: 600; min-width: 0; }
.ticket-main .subtext { display: block; margin-top: 3px; }
.ticket-split {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: var(--s-5);
  align-items: start;
}
.ticket-split-main { min-width: 0; }
.ticket-list-col {
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  max-height: calc(100vh - var(--topbar-h) - var(--s-8));
  padding: var(--s-3) var(--s-2);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.ticket-list-col .input.search { width: 100%; }
.ticket-list-items { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; min-height: 0; }
.ticket-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 12px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-callout);
  text-align: left;
  cursor: pointer;
}
.ticket-item:hover { background: var(--surface-hover, var(--n-50)); }
.ticket-item.active { background: var(--accent); color: #fff; }
.ticket-item.active small { color: rgba(255, 255, 255, 0.85); }
.ticket-item.active .task-id { color: #fff; background: rgba(255, 255, 255, 0.18); }
.ticket-item-top { display: flex; justify-content: space-between; align-items: center; gap: 6px; }
.ticket-item b { font-weight: 600; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ticket-item small { font-size: var(--fs-caption); color: var(--text-muted); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ticket-mode-seg { display: inline-flex; margin: 0; }
.ticket-reply-modes { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); }
@media (max-width: 1100px) {
  .ticket-split { grid-template-columns: minmax(0, 1fr); }
  .ticket-list-col { display: none; }
}

.runbook-detail-page:not(.has-back-task) .runbook-back { display: none; }

/* 접힌 알림 목록은 위험한 것 세 줄만 보인다. 나머지도 DOM 에는 남겨 둔다(검색·인쇄·번역 검사가 읽는다). */
.cloud-attention-list.is-folded > li:nth-child(n + 4) { display: none; }

/* 글자 단계(vlan24-ui.css --fs-*) — 창 제목은 판 제목과 같은 title3. */
.modal-head h2,
.modal-head h3 {
  font-size: var(--fs-title3);
  font-weight: 600;
}

/* ── IPAM 탐색기(시안 12-A): 상위 대역 + /24 줄 ─────────────────────────── */
.ipam-layout.has-map {
  grid-template-columns: 280px minmax(0, 1fr);
}
.ipam-blocks {
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: calc(100vh - var(--topbar-h) - 120px);
  overflow-y: auto;
  padding: var(--s-3) var(--s-2);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.ipam-blocks-cap {
  padding: 0 10px 6px;
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--text-muted);
}
.ipam-block {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-body);
  text-align: left;
  cursor: pointer;
}
.ipam-block:hover { background: var(--surface-hover, var(--n-50)); }
.ipam-block.active { background: var(--surface); box-shadow: 0 0 0 1.5px var(--accent); }
.ipam-block b { font-family: var(--mono); font-weight: 600; }
.ipam-block small {
  font-size: var(--fs-caption);
  color: var(--text-muted);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ipam-block-bar { height: 4px; border-radius: 2px; background: var(--surface-active); overflow: hidden; }
.ipam-block-bar i { display: block; height: 4px; background: var(--accent); }
.ipam-singles-toggle {
  margin-top: var(--s-2);
  padding: 8px 12px;
  border: 0;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-caption);
  text-align: left;
  cursor: pointer;
}
.ipam-search-panel { margin-bottom: var(--s-4); }
.ipam-search-panel .toolbar-right { display: flex; align-items: center; gap: var(--s-3); }
.ipam-legend .is-p2p, .ipam-cell.is-p2p, .ipam-row-cells .is-p2p { background: #8e8e93; }
.ipam-rows-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-2);
}
.ipam-rows-head b { font-size: var(--fs-title3); font-weight: 600; }
.ipam-rows { display: flex; flex-direction: column; gap: 2px; }
.ipam-row {
  display: grid;
  grid-template-columns: 150px minmax(0, 170px) minmax(0, 1fr) 44px;
  gap: 14px;
  align-items: center;
  width: 100%;
  padding: 7px 8px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-body);
  text-align: left;
  cursor: pointer;
}
.ipam-row:hover, .ipam-row.active { background: var(--n-50, #f5f5f7); }
.ipam-row b { font-weight: 600; }
.ipam-row-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--text-secondary, #424245); }
.ipam-row-cells {
  display: grid;
  grid-template-columns: repeat(64, minmax(0, 1fr));
  gap: 1px;
  height: 18px;
}
.ipam-row-cells i { background: var(--surface-active); border-radius: 1px; }
.ipam-row-cells .is-allocated { background: var(--accent); }
.ipam-row-cells .is-reserved { background: #b9a3e6; }
.ipam-row-pct { font-size: var(--fs-caption); color: var(--text-muted); text-align: right; }
.ipam-row-pct.is-full { color: var(--danger); font-weight: 600; }
.ipam-row.is-empty-run { cursor: default; grid-template-columns: 150px minmax(0, 1fr); }
.ipam-row.is-empty-run:hover { background: none; }
.ipam-row.is-empty-run b { color: var(--text-muted); font-weight: 500; }
.ipam-row-open { display: flex; flex-direction: column; gap: var(--s-3); padding: var(--s-3) 8px var(--s-4); }
.ipam-free { margin: 0; font-size: var(--fs-callout); }
.ipam-free b { padding: 2px 8px; border-radius: 6px; background: var(--ok-soft); color: var(--ok); }
@media (max-width: 1100px) {
  .ipam-blocks { position: static; max-height: 240px; }
  .ipam-row { grid-template-columns: 120px minmax(0, 1fr) 40px; }
  .ipam-row-name { display: none; }
}

@media (max-width: 1100px) {
  .ipam-layout.has-map { grid-template-columns: minmax(0, 1fr); }
}

/* ── 2026-10 개편 3차: 화면 머리 한 줄 ────────────────────────────────────
   시안의 머리는 «제목 · 세그먼트 탭 · (빈칸) · 단추» 한 줄이다. 탭이 머리 아래 따로 서면 화면 위
   제목 옆에 보기 탭을 두며 일반 설명은 소스에서 제거한다. 데이터·안전 안내는 해당 맥락에 남긴다. */
.inventory-page-head > div:first-child { flex:0 1 auto; }
.inventory-page-head .inventory-view-tabs { margin:0; }
.inventory-tax-options .button { height:auto; min-height:27px; line-height:1.4; }
.im-form .field:has(#im-name) { grid-column:1 / -1; }
.page-head .field-work-tabs,
.page-head .tabs {
  margin: 0;
}
/* 현장작업 기간 줄: 리포트와 같은 세그먼트 한 줄. 날짜 칸은 직접 선택일 때만. */
.field-range-bar {
  display: flex !important;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
  padding: 0 !important;
  background: none !important;
  border: 0 !important;
  box-shadow: none !important;
}
.field-range-bar .report-seg { display: inline-flex; margin: 0; }
.field-range-bar .report-custom-dates { display: flex; align-items: center; gap: var(--s-2); }
.field-range-bar .report-custom-dates .input { width: auto; }
.field-range-bar .report-period-summary { text-align: right; }

/* ── 2026-10 개편 3차: 런북 본문 ─────────────────────────────────────────
   시안: 단계마다 카드가 아니라 한 면 위의 번호 동그라미 + 굵은 단계 + 아래 설명·명령. 카드가
   단계 묶음마다 서면 읽는 문서가 아니라 대시보드처럼 보였다. */
.runbook-detail-page .runbook-body {
  padding: var(--s-5) var(--s-6);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.runbook-detail-page .runbook-body .runbook-steps {
  padding: 0 !important;
  margin: 0 0 var(--s-5);
  background: none !important;
  border: 0 !important;
  box-shadow: none !important;
}
.runbook-detail-page .runbook-steps h3 {
  margin: 0 0 var(--s-2);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--text-muted);
}
.runbook-detail-page .runbook-steps ol {
  list-style: none;
  counter-reset: rb-step;
  margin: 0;
  padding: 0;
}
.runbook-detail-page .runbook-steps li {
  counter-increment: rb-step;
  position: relative;
  padding: 12px 0 12px 42px;
  font-size: var(--fs-body);
}
.runbook-detail-page .runbook-steps li + li {
  box-shadow: inset 0 1px 0 var(--divider);
}
.runbook-detail-page .runbook-steps li::before {
  content: counter(rb-step);
  position: absolute;
  left: 0;
  top: 10px;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--fs-callout);
  font-weight: 600;
}
.runbook-detail-page .runbook-steps li::marker { content: ''; }
.runbook-detail-page .runbook-step-text { font-weight: 600; }
.runbook-detail-page .runbook-step-note { margin-top: 3px; color: var(--text-muted); font-size: var(--fs-callout); }
.runbook-detail-page .runbook-code pre {
  margin: 8px 0 0;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--n-50, #f5f5f7);
  font-size: var(--fs-callout);
}
.runbook-side-card > span {
  letter-spacing: normal !important;
  text-transform: none;
  font-size: var(--fs-caption);
}
.runbook-detail-head {
  border-top: 1px solid var(--divider) !important;
}
.task-date-toolbar .report-seg { display: inline-flex; margin: 0; }

/* 팀 «오늘» 칸 — 점 하나와 말. 근무 중 초록, 휴가 주황, 쉬는 중·비활성 회색. */
.team-today {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-callout);
  color: var(--text-muted);
  white-space: nowrap;
}
.team-today::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.team-today.is-on { color: var(--ok); }
.team-today.is-leave { color: var(--warn, #9a4a00); }
.team-today.is-off { color: var(--text-muted); opacity: 0.7; }

/* 휴가: 내 휴가 카드 */
.my-leave {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: var(--s-4);
  padding: 18px 22px;
  border-radius: var(--radius-lg);
  background: var(--n-50, #f5f5f7);
  border: 1px solid var(--divider);
}
.my-leave-cap { font-size: var(--fs-caption); font-weight: 600; color: var(--text-muted); }
.my-leave-nums { display: flex; flex-wrap: wrap; gap: var(--s-6); }
.my-leave-nums > div { display: flex; flex-direction: column; gap: 2px; }
.my-leave-nums b { font-size: var(--fs-display); font-weight: 650; line-height: 1.1; }
.my-leave-nums small { font-size: var(--fs-body); font-weight: 500; color: var(--text-muted); }
.my-leave-bar { height: 8px; border-radius: 4px; background: var(--accent-soft); overflow: hidden; }
.my-leave-bar i { display: block; height: 8px; background: var(--warn, #b25000); }

/* 현장작업: 주별 현장 시간 막대 */
.field-week-chart {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0 0 var(--s-4);
  padding: var(--s-3) var(--s-4);
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: var(--radius-lg);
}
.field-week-bars { display: flex; align-items: flex-end; gap: 10px; height: 96px; }
.field-week { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 4px; min-width: 0; height: 100%; }
.field-week-bar { width: 100%; border-radius: 5px; background: var(--accent-soft); }
.field-week.is-current .field-week-bar { background: var(--accent); }
.field-week-value { font-size: var(--fs-micro); color: var(--text-muted); }
.field-week-label { font-size: var(--fs-caption); color: var(--text-muted); }
.field-week.is-current .field-week-label { color: var(--text); font-weight: 600; }

/* ── 2026-10-05: UI 점검 P1 ──────────────────────────────────────────────
   인수인계 소제목의 파란 막대는 border 가 아니라 styles.css 의 h3:before 였다. 앞서 border 만
   지워서 막대가 남아 있었다. */
.handover-reading-section h3:before {
  content: none;
}
/* 받는 팀이 아니면 확인 줄이 옅은 한 줄이라 왜 단추가 없는지 알기 어려웠다. 경고 면으로 이유를 보인다. */
.handover-ack-bar.is-locked .meta {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  flex: 0 1 auto;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--radius-sm, 6px);
  background: var(--warn-soft, #fdf3e1);
  color: var(--warn, #8a5a00);
}
.handover-lock {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
/* 시각은 글자가 아니라 숫자만 고정폭이면 된다. mono 를 그대로 쓰면 "10월"·"작성 일시" 같은 한글이
   고정폭 칸에 하나씩 놓여 띄어 쓴 것처럼 보였다. */
.local-clock,
.task-activity-time b {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
}
.task-activity-time span {
  letter-spacing: 0;
}
/* 휴대폰 대시보드 우선 업무: 표 칸이 화면 밖으로 밀려 제목이 잘리고 상태·담당이 보이지 않았다.
   제목은 두 줄까지 감싸고, 상태·담당·시각은 그 아래 한 줄로 모은다. */
@media (max-width: 560px) {
  .dashboard-tasks thead {
    display: none;
  }
  .dashboard-tasks,
  .dashboard-tasks tbody {
    display: block;
    width: 100%;
  }
  .dashboard-tasks tr.task-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px var(--s-2);
    padding: var(--s-2) var(--s-3);
  }
  .dashboard-tasks tr.task-row > td {
    display: block;
    padding: 0;
    border: 0;
    white-space: nowrap;
    font-size: var(--fs-caption);
    color: var(--text-muted);
  }
  .dashboard-tasks tr.task-row > td.task-main {
    flex: 1 0 100%;
    min-width: 0;
    white-space: normal;
    font-size: inherit;
    color: inherit;
  }
  .dashboard-tasks .task-line {
    flex-wrap: wrap;
  }
  .dashboard-tasks .task-line .cell-truncate {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}
/* 업데이트 칸의 "40분 전" 도 한글이 섞이므로 같은 이유로 sans + 숫자 고정폭. */
.task-list td.meta time,
.task-list td.meta {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
}
/* 900px 이하(사이드바가 빠지는 폭)부터 NOW·날짜 옆 눈금은 겹친다. 하나 걸러 숨기기는 휴대폰에서만. */
@media (max-width: 900px) {
  .coverage-axis > span.is-crowded {
    display: none;
  }
}
@media (max-width: 560px) {
  .coverage-axis > span.is-minor {
    display: none;
  }
  /* 휴대폰에서는 색 띠가 글자 위에 그려졌다(표 칸이 사라지며 td 안쪽 그림자가 글자 밑으로 감). 줄 왼쪽 테두리로 옮긴다. */
  .dashboard-tasks tr.task-row.is-critical,
  .dashboard-tasks tr.task-row.is-high {
    border-left: 3px solid var(--danger);
  }
  .dashboard-tasks tr.task-row.is-high {
    border-left-color: #b25000;
  }
  .dashboard-tasks tr.task-row > td:first-child {
    box-shadow: none;
  }
}
.task-activity-time span {
  font-family: var(--sans);
  letter-spacing: 0 !important;
  word-spacing: 0;
}
/* 신규 업무 배정 카드: "원본 티켓" 링크가 인라인 10px 이었다. 글자 단계 토큰으로. */
.triage-source-link {
  color: var(--accent);
  font-size: var(--fs-caption);
  text-decoration: underline;
}
/* 휴대폰에서 배정 판이 첫 화면을 다 덮었다: 제목이 "신규 업무 배 / 정 2" 로 꺾이고, ID·고객·사이트가
   좁은 칸에서 두세 줄씩 접히고, 단추와 선택이 위아래로 쌓여 카드 하나가 화면 절반이었다.
   머리는 위아래로, 사실 줄은 줄바꿈 허용(각 항목은 한 덩어리), 단추와 선택은 한 줄에 나란히. */
@media (max-width: 560px) {
  .triage-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }
  .triage-head h2 {
    white-space: nowrap;
  }
  .triage-list {
    grid-template-columns: minmax(0, 1fr);
  }
  .triage-card {
    gap: 8px;
    min-width: 0;
  }
  .triage-card-meta {
    flex-wrap: wrap;
    gap: 2px 10px;
  }
  .triage-card-meta > span {
    white-space: nowrap;
  }
  .triage-card-meta > * {
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .triage-card-actions {
    flex-direction: row;
    align-items: center;
  }
  .triage-card-actions .triage-claim {
    flex: none;
  }
  .triage-assign-select {
    flex: 1;
    min-width: 0;
    width: auto;
  }
}
/* 고객 티켓 표: 휴대폰에서 다섯 칸 표가 가로 스크롤이라 첫 화면에 상태 칸이 보이지 않았다.
   표가 받은 폭이 640px 보다 좁으면 줄 배치 — 티켓(번호·제목·고객) 한 줄 전체, 아래에 상태·담당·대기·변경. */
.ticket-search-toolbar ~ .table-wrap {
  container-type: inline-size;
}
@container (max-width: 639.98px) {
  .ticket-table thead {
    display: none;
  }
  .ticket-table,
  .ticket-table tbody {
    display: block;
    width: 100%;
    min-width: 0;
  }
  .ticket-table tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    padding: var(--s-3);
    border-bottom: 1px solid var(--divider);
  }
  .ticket-table tbody td {
    display: block;
    padding: 0;
    border: 0;
    height: auto;
    font-size: var(--fs-caption);
    color: var(--text-muted);
  }
  .ticket-table tbody td.ticket-main {
    flex: 1 0 100%;
    max-width: none;
    font-size: inherit;
    color: inherit;
  }
  .ticket-table .ticket-line b {
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .ticket-table tbody td[colspan] {
    flex: 1 0 100%;
  }
}
/* 사이드바: 1100px 이하에서 옛 styles.css 는 글자를 숨기고 66px 아이콘 막대로 접는데, 뒤에 실리는
   vlan24-ui.css 가 폭을 --sidebar-w(204px)로 다시 덮어 "넓은데 아이콘만 있는" 막대가 됐다.
   아이콘만으로는 메뉴 열여덟 개를 구별하기 어렵고(달력·휴가, 고객·팀 아이콘이 같다), 폭도 이미
   있으므로 글자를 되살린다. 휴대폰(하단 탭)으로 넘어가기 전까지 같은 사이드바. */
@media (min-width: 901px) and (max-width: 1100px) {
  html:not(.nav-collapsed) .brand span,
  html:not(.nav-collapsed) .nav button span {
    display: inline;
  }
  html:not(.nav-collapsed) .workspace,
  html:not(.nav-collapsed) .nav .section,
  html:not(.nav-collapsed) .side-user div {
    display: block;
  }
  .sidebar {
    padding: var(--s-4) var(--s-2);
  }
  html:not(.nav-collapsed) .brand {
    padding: var(--s-1) var(--s-2) var(--s-5);
    justify-content: flex-start;
    text-align: left;
    align-items: flex-start;
  }
  html:not(.nav-collapsed) .nav button {
    justify-content: flex-start;
    padding: 6px var(--s-2);
  }
  .nav .indent {
    padding-left: var(--s-6, 24px);
  }
  .side-user {
    justify-content: flex-start;
    padding: var(--s-2);
  }
}
/* 팀 고르기 판: 화면 머리 오른쪽 끝에 있는데 왼쪽 기준으로 펼쳐져 800~1024px 에서 화면 밖으로 나갔다. */
.page-head .team-scope-panel {
  left: auto;
  right: 0;
}
/* 가로로 넘기는 표가 비어 있을 때 안내 문구가 표 전체 폭(예: 720px)의 가운데에 놓여, 휴대폰에서는
   잘린 채 보였다(휴가 «승인 대기 요청»). 안내는 보이는 폭 안에 붙여 둔다. */
.leave-approval-grid .table-wrap {
  container-type: inline-size;
}
.leave-approval-grid .table-wrap td[colspan] > .empty {
  position: sticky;
  left: 0;
  max-width: 100cqw;
  box-sizing: border-box;
}
/* 업무 상세: 비어 있는 장애 판은 머리 + 연결 줄 한 줄. */
.task-incident-empty .panel-head {
  justify-content: flex-start;
  gap: var(--s-3);
}
.task-incident-empty .panel-body {
  padding-top: 0;
}
/* 옆칸의 «현장 작업 연동»·«추천 런북» 이 카드 없이 떠 있어, 바로 위 «대상 · 일정» 인스펙터 카드와
   다른 화면처럼 보였다. 같은 면으로 맞추되 여백을 줄여 무게는 낮게 둔다. */
.task-aside > .panel {
  background: var(--surface);
  border-color: var(--border);
}
.task-aside > .panel .panel-head {
  padding-bottom: 0;
}
.task-aside > .panel .panel-body {
  padding-top: var(--s-2);
}
/* 단축키 표시가 10px 로 글자 단계 밖이었다. 가장 작은 단계(11px)로. */
.global-search-dialog kbd,
.global-search-trigger kbd {
  font-size: var(--fs-micro);
}
/* 리포트 «업무별 진행 상황» 휴대폰: 번호 칸이 62px 로 고정돼 긴 번호(TSK-20261005-001)는 혼자 한 줄,
   짧은 번호는 제목 옆에 놓여 줄마다 모양이 달랐다. 번호를 언제나 제목 위 작은 줄로. */
@media (max-width: 560px) {
  .report-task-item > summary {
    flex-wrap: wrap;
    gap: 2px var(--s-2);
  }
  .report-task-item > summary > .id {
    flex: 1 0 100%;
    width: auto;
    min-width: 0;
    font-size: var(--fs-caption);
    color: var(--text-muted);
  }
  .report-task-item > summary > b {
    flex: 1 0 100%;
    min-width: 0;
  }
  .report-note-form button {
    white-space: nowrap;
  }
}
/* ── 휴대폰 표: 줄 배치 (2026-10-05) ──
   인수인계·장애·유지보수·현장작업·업무 표가 휴대폰에서 760~940px 표를 가로로 넘겨야 해서 첫 화면에는
   왼쪽 두세 칸만 보였다. `table-stack` 이 붙은 표는 핵심 칸(기본 첫 칸, stack-main-N 이면 N번째)을
   한 줄 전체로 올리고 나머지를 그 아래 작은 글자로 이어 붙인다. 칸 이름은 빠지지만 상태·담당·시각은
   값만으로 읽힌다 — 정확히 비교해야 할 때는 넓은 화면이나 상세를 쓴다. */
@media (max-width: 560px) {
  .table-stack thead {
    display: none;
  }
  .table-stack,
  .table-stack tbody {
    display: block;
    width: 100%;
    min-width: 0 !important;
  }
  .table-stack tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    padding: var(--s-3);
    border-bottom: 1px solid var(--divider);
  }
  .table-stack tbody td {
    display: block;
    max-width: 100%;
    min-width: 0;
    height: auto;
    padding: 0;
    border: 0;
    white-space: normal;
    font-size: var(--fs-caption);
    color: var(--text-muted);
  }
  .table-stack tbody td:empty {
    display: none;
  }
  .table-stack:not([class*='stack-main-']) tbody td:first-child,
  .table-stack.stack-main-2 tbody td:nth-child(2),
  .table-stack.stack-main-3 tbody td:nth-child(3),
  .table-stack tbody td[colspan] {
    order: -1;
    flex: 1 0 100%;
    font-size: inherit;
    color: inherit;
  }
  .table-stack tbody td .cell-truncate {
    white-space: normal;
  }
}
@media (max-width: 560px) {
  /* 우선순위 띠: 칸 안쪽 그림자가 줄 배치에서는 글자 위로 온다. 줄 왼쪽 테두리로. */
  .table-stack tr.task-row > td:first-child {
    box-shadow: none;
  }
  .table-stack tr.task-row.is-critical {
    border-left: 3px solid var(--danger);
  }
  .table-stack tr.task-row.is-high {
    border-left: 3px solid #b25000;
  }
}
@media (max-width: 560px) {
  /* 업무 목록 칸에는 더 구체적인 선택자의 위아래 10px 여백이 있어 줄 배치에서 줄 사이가 벌어졌다. */
  .table-stack tbody tr > td {
    padding: 0 !important;
    height: auto !important;
    min-height: 0 !important;
  }
}
@media (max-width: 560px) {
  /* 긴 제목은 두 줄까지(전체 제목은 title 과 상세에). 풀어 두면 한 줄이 화면 하나를 차지했다. */
  .table-stack tbody td .cell-truncate {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
  }
}
/* 줄 배치에서는 빈 값(—) 칸을 접는다. 표에서는 칸 자리를 지키느라 필요하지만, 한 줄로 이어 붙이면
   "처리중 — — 10월 1일" 처럼 의미 없는 줄표만 남았다. */
@container (max-width: 639.98px) {
  .ticket-table tbody td.is-empty {
    display: none;
  }
}
@media (max-width: 560px) {
  .table-stack tbody td.is-empty {
    display: none;
  }
}
/* «신규 업무 배정» 카드: 900~1100px 에서 사실 줄(고객·사이트)이 한 줄로 버티다 오른쪽 단추 밑으로 잘렸다.
   사실 줄은 언제나 줄바꿈 허용, 1100px 이하에서는 단추 줄을 카드 아래로. */
.triage-card-meta {
  flex-wrap: wrap;
  row-gap: 2px;
}
@media (max-width: 1100px) {
  .triage-card {
    grid-template-columns: minmax(0, 1fr);
  }
  .triage-card-actions {
    justify-content: flex-start;
  }
}

/* ── 다크 모드 대비 (2026-10-05) ───────────────────────────────────────────
   18화면을 다크로 그려 글자 대비를 쟀다(본문 4.5:1, 큰 글자 3:1). 공통 토큰을 올린 뒤에도 남은 것은
   라이트 색을 그대로 박아 둔 요소들이라, 여기서 다크 값을 준다. */
body.theme-dark .global-search-trigger > span {
  color: var(--text-muted);
}
body.theme-dark .notification-count,
body.theme-dark .handover-now-badge,
body.theme-dark .settings-nav button.active,
body.theme-dark .button:not(.secondary):not(.ghost):not(.danger):not(.link) {
  background-color: var(--accent-fill);
  border-color: var(--accent-fill);
  color: #fff;
}
body.theme-dark .task-filter-bar .button {
  color: var(--text);
}
body.theme-dark .work-current,
body.theme-dark .work-apply-options {
  background: var(--surface-2);
  color: var(--text);
}
body.theme-dark .work-current > span {
  color: var(--text-muted);
}
body.theme-dark .handover-now-meta,
body.theme-dark .handover-now-meta span {
  color: var(--warn);
}
body.theme-dark .off-lbl,
body.theme-dark .field-work-kpis span,
body.theme-dark .field-work-kpis small,
body.theme-dark .walkthrough-empty span,
body.theme-dark .report-kpis span,
body.theme-dark .report-kpis em {
  color: var(--text-muted);
}
body.theme-dark .team-region {
  background: var(--accent-soft);
  color: var(--accent-hover);
}
body.theme-dark .cal-shift-start {
  color: var(--text-secondary);
}
body.theme-dark .inventory-rail-item b {
  color: var(--text);
}
body.theme-dark .report-focus-grid small,
body.theme-dark .report-activity em,
body.theme-dark .report-activity span,
body.theme-dark .report-asset-card p,
body.theme-dark .report-section-heading > p,
body.theme-dark .report-license-card p,
body.theme-dark .report-people-list small,
body.theme-dark .report-leave-list p,
body.theme-dark .walkthrough-empty {
  color: var(--text-muted);
}
/* 남은 것: 라이트용 진한 색을 직접 적어 둔 곳, 더 구체적인 선택자가 이기던 곳. */
body.theme-dark .aging-stat-card.total { --aging-tone: var(--accent-hover); }
body.theme-dark .aging-stat-card.ok { --aging-tone: var(--ok); }
body.theme-dark .aging-stat-card.alert-24 { --aging-tone: var(--warn); }
body.theme-dark .aging-stat-card.alert-48 { --aging-tone: var(--danger); }
body.theme-dark .handover-team.region-kr b {
  background: var(--accent-soft);
  color: var(--accent-hover);
}
body.theme-dark .handover-team.region-us b {
  background: var(--ok-soft);
  color: var(--ok);
}
body.theme-dark .work-apply-label,
body.theme-dark .work-effective-preview span {
  color: var(--text-secondary);
}
body.theme-dark .shift-day-col.is-off .off-lbl,
body.theme-dark .calendar-grid .cal-shift-chip .cal-shift-start {
  color: var(--text-secondary);
}
body.theme-dark .report-activity article span,
body.theme-dark .standby-month b {
  color: var(--text-muted) !important;
}
body.theme-dark .today-cell .cal-day-pick b {
  background-color: var(--accent-fill);
}
/* ── 키보드 (2026-10-05) ── */
/* 행·카드에는 그림자 고리가 잘리거나 칸마다 끊겨 보여, 안쪽 테두리로 표시한다. */
tr[tabindex]:focus-visible,
article.triage-card[tabindex]:focus-visible,
th[data-sort]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  box-shadow: none;
}

/* 서비스 구성 Overview: 흐름도 패널과 최근 작업 패널 사이 간격. */
.cloud-config-view[data-config-view='overview'] > .panel + .panel {
  margin-top: var(--s-4);
}

/* 저장하지 못한 변경 안내(2026-10-07). 사라지는 토스트 대신 화면 아래에 남는다 — 전에는 3초 토스트만
   뜨고 장애가 만든 사람의 화면에만 남았다. */
.save-problem {
  position: fixed;
  right: var(--s-4);
  bottom: var(--s-4);
  /* Keep the unresolved alert above the page, below the shared modal (200).
     A background failure must not intercept a draft's save/cancel controls. */
  z-index: 100;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  max-width: min(560px, calc(100vw - 2 * var(--s-4)));
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--warn-border);
  border-left: 4px solid var(--warn);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-pop);
}
.save-problem p {
  margin: 2px 0 0;
  color: var(--text-secondary);
  font-size: var(--fs-caption);
  overflow-wrap: anywhere;
}
.save-problem-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

/* 기존 운영 콘솔의 부품을 유지하고 모바일에서는 인수 행동부터 보여 준다. */
.dashboard-mobile-priority {
  display: none;
}
.dashboard-mobile-priority .form-actions {
  margin: 0;
  padding: 0;
  border: 0;
  justify-content: flex-start;
}
.dashboard-shift-overview,
.dashboard-context-panels {
  display: contents;
}
.task-active-filters {
  padding: 0 var(--s-4) var(--s-3);
  overflow-wrap: anywhere;
}
.modal-discard-prompt {
  display: block;
  flex-shrink: 0;
  margin: var(--s-3) var(--s-4);
}
.modal-discard-prompt p {
  margin: 0 0 var(--s-3);
}
.modal-discard-prompt .form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}
@media (max-width: 767px) {
  .dashboard-page {
    display: flex;
    flex-direction: column;
  }
  .dashboard-mobile-priority {
    display: block;
  }
  .dashboard-shift-overview {
    display: block;
    order: 2;
  }
  .dashboard-context-panels {
    display: block;
    order: 1;
  }
  .dashboard-handover {
    order: -1;
  }
}

/* 900px 이하에서는 하단 탭(66px, styles.css .mobile-bottom-nav) 위로 올린다. 겹치면 단추를 누를 수 없다. */
@media (max-width: 900px) {
  .save-problem {
    right: var(--s-2);
    bottom: calc(66px + var(--s-2) + env(safe-area-inset-bottom));
    left: var(--s-2);
    max-width: none;
  }
}
.personal-view-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding: var(--s-3) var(--s-4); }
.personal-view-toolbar > label { color: var(--text-secondary); font-size: var(--fs-caption); }
.personal-view-toolbar > .select { flex: 0 1 220px; min-width: 0; }
.personal-view-toolbar > .meta { margin-left: auto; }
.reports-page .personal-view-toolbar { padding-inline: 0; }
.personal-view-options { min-width: 0; border: 0; margin: 0; padding: 0; }
.personal-view-options legend { margin-bottom: var(--s-2); color: var(--text-secondary); font-size: var(--fs-caption); }
.cal-day-panel { scroll-margin-top: calc(var(--topbar-h) + var(--s-4)); }
@media (max-width: 560px) {
  .personal-view-toolbar > label { flex-basis: 100%; }
  .personal-view-toolbar > .select { flex: 1 1 100%; }
  .personal-view-toolbar > .meta { margin-left: 0; }
}
@media print { .personal-view-toolbar { display: none !important; } }
/* Live RackTables records reuse asset panels and the shared form/button kit. */
.rt-record-panel .panel-body,
.rt-record-panel .form-stack {
  display: grid;
  gap: var(--s-3);
  min-width: 0;
}
.rt-record-tabs,
.rt-record-pager,
.rt-log-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
}
.rt-record-panel .rt-record-tabs .button[aria-selected='true'] {
  color: var(--accent);
  border-color: var(--accent);
}
.rt-record-tabs > :last-child {
  margin-left: auto;
}
.rt-record-raw,
.rt-log-content {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: normal;
  font: inherit;
  margin: 0;
  max-height: 22rem;
  overflow: auto;
}
.rt-record-panel textarea {
  resize: vertical;
  min-height: 6rem;
}
.rt-record-view {
  min-width: 0;
  max-height: 22rem;
  overflow: auto;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}
.rt-record-view p {
  margin: 0 0 var(--s-2);
}
.rt-record-view p:last-child {
  margin-bottom: 0;
}
.rt-record-view a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.rt-record-view table {
  border-collapse: collapse;
  max-width: 100%;
}
.rt-record-view td,
.rt-record-view th {
  border: 1px solid var(--line);
  padding: var(--s-2);
}
.rt-record-view pre,
.rt-record-view code {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.rt-record-source summary {
  color: var(--text-secondary);
  cursor: pointer;
  padding-block: var(--s-2);
}
.rt-record-source[open] .rt-record-raw {
  margin-top: var(--s-2);
}
.rt-record-notice {
  color: var(--text-secondary);
  margin: var(--s-2) 0;
}
.rt-record-notice.is-error {
  color: var(--danger);
}
.rt-log-entry {
  padding-block: var(--s-2);
  border-top: 1px solid var(--line);
}
.rt-log-meta {
  justify-content: space-between;
  margin-bottom: var(--s-2);
  color: var(--text-secondary);
}
.rt-log-meta time {
  font-size: var(--fs-caption);
  overflow-wrap: anywhere;
}
.rt-record-pager {
  justify-content: flex-end;
  margin-top: var(--s-3);
}
@media (max-width: 767px) {
  .rt-record-panel button {
    min-height: 44px;
  }
  .rt-record-source summary {
    min-height: 44px;
  }
  .rt-record-panel .form-actions {
    flex-wrap: wrap;
  }
}

/* ── 장착 부품 (parts.js) — 서버 디스크 칸, 장착·교체·분리, 사후 확인, RackTables 반영 상태 ── */
.parts-panel .panel-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-3);
}
.parts-notice {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--fs-caption);
}
.parts-notice.is-error,
.parts-error {
  margin: 0;
  color: var(--danger);
  font-size: var(--fs-caption);
}
.parts-attention {
  color: var(--warn);
}
/* Wraps instead of overflowing: narrow screens and 24-bay chassis both stay inside the panel. */
.parts-bays {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  padding: 4px;
  width: fit-content;
  max-width: 100%;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.parts-bay {
  flex: 0 0 30px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  height: 54px;
  margin: 0;
  padding: 4px 2px;
  border: 1px solid var(--border-strong);
  border-radius: 2px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-micro);
  cursor: pointer;
}
.parts-bay i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ok);
}
.parts-bay.is-unknown {
  border-color: var(--warn);
}
.parts-bay.is-unknown i {
  background: var(--warn);
}
.parts-bay.is-selected,
.parts-bay:hover:not(:disabled) {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.parts-bay:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.parts-bay:disabled {
  cursor: default;
}
.parts-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}
.parts-drift {
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--warn-border);
  border-radius: var(--radius-sm);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: var(--fs-caption);
}
.parts-drift ul {
  margin: var(--s-1) 0 0;
  padding-left: var(--s-4);
}
.parts-editor {
  display: grid;
  gap: var(--s-2);
  padding: var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.parts-editor-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}
.parts-editor-head h3 {
  margin: 0;
  font-size: var(--fs-callout);
}
.parts-segment {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.parts-segment button {
  padding: var(--s-1) var(--s-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--fs-caption);
  cursor: pointer;
}
.parts-segment button.is-active {
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 560;
}
.parts-current,
.parts-caption {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--fs-caption);
}
.parts-row {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--divider);
}
.parts-row-label {
  padding-top: var(--s-1);
  color: var(--text-muted);
  font-size: var(--fs-caption);
  font-weight: 540;
}
.parts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--s-2);
}
.parts-grid .field {
  margin: 0;
  min-width: 0;
}
.parts-grid .field.is-wide {
  grid-column: span 2;
}
.parts-editor .form-actions {
  margin: 0;
}
.parts-task-choice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
}
.parts-task-choice select {
  flex: 1 1 180px;
  min-width: 0;
}
.parts-task-context {
  grid-column: 1 / -1;
}
.parts-review th {
  width: 30%;
  font-weight: 540;
}
.parts-changes {
  list-style: none;
  margin: 0;
  padding: 0;
}
.parts-changes li {
  padding: var(--s-2) 0;
  border-top: 1px solid var(--divider);
  font-size: var(--fs-caption);
}
.parts-change-head {
  display: flex;
  justify-content: space-between;
  gap: var(--s-2);
}
.parts-change-head time {
  color: var(--text-muted);
}
.parts-change-body {
  margin-top: 2px;
  color: var(--text-secondary);
  overflow-wrap: anywhere;
}
.parts-change-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-1);
}
.parts-sync {
  color: var(--text-muted);
}
.parts-sync.is-blocked {
  color: var(--danger);
}
.parts-dispute {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--s-1);
}
@media (max-width: 900px) {
  .parts-row {
    grid-template-columns: minmax(0, 1fr);
  }
  .parts-grid .field.is-wide {
    grid-column: 1 / -1;
  }
  .parts-segment button,
  .parts-editor [data-action="parts-task-mode"],
  .parts-editor .form-actions .button {
    min-height: 44px;
  }
}
@media (max-width: 600px) {
  .parts-review,
  .parts-review tbody {
    display: block;
    width: 100%;
    min-width: 0;
  }
  .parts-review tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    border-bottom: 1px solid var(--border);
  }
  .parts-review tr > th,
  .parts-review tr > td {
    display: block;
    width: auto;
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
    border: 0;
  }
}

/* ── 부품 작업 (parts-stock.js) — 통합 자산 목록 안의 필요 시 편집기 ── */
.parts-stock {
  margin-bottom: var(--s-3);
}
.inventory-list-toolbar { flex-wrap:wrap; gap:var(--s-2); }
.inventory-list-toolbar .search { flex:1 1 240px; max-width:360px; min-width:0; }
.inventory-list-tools { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s-2); margin-left:auto; }
.inventory-column-head { display:flex; align-items:center; gap:var(--s-1); }
.inventory-column-head button { display:inline-flex; align-items:center; justify-content:center; gap:var(--s-1); border:0; background:transparent; color:inherit; font:inherit; cursor:pointer; min-height:28px; padding:0; border-radius:var(--radius-sm); }
.inventory-column-head button:hover { background:var(--surface-hover); }
.inventory-column-head .inventory-column-filter { flex-shrink:0; width:24px; color:var(--text-secondary); }
.inventory-column-head button:first-child svg { display:none; }
.inventory-table th[aria-sort="ascending"] button:first-child svg, .inventory-table th[aria-sort="descending"] button:first-child svg { display:block; }
.inventory-column-filter.is-active, .inventory-table th[aria-sort="ascending"] button:first-child, .inventory-table th[aria-sort="descending"] button:first-child { color:var(--accent-text); background:var(--accent-soft); }
.inventory-table th[aria-sort="descending"] button:first-child svg { transform:rotate(180deg); }
.inventory-conditions { display:flex; align-items:center; flex-wrap:wrap; gap:var(--s-2); padding:0 var(--s-3) var(--s-2); }
.inventory-conditions > span { flex:1; min-width:0; overflow-wrap:anywhere; }
.inventory-inline-parts { margin:0; padding:var(--s-3); border-top:1px solid var(--line); display:grid; gap:var(--s-2); min-width:0; }
.inventory-inline-parts .parts-editor { margin:0; }
.inventory-intake-fields { border:0; margin:0; padding:0; min-width:0; }
.inventory-filter-popover { position:fixed; inset:auto; margin:0; width:min(340px,calc(100vw - 16px)); max-height:calc(100dvh - 16px); overflow-y:auto; padding:var(--s-3); background:var(--surface); color:var(--text); border:1px solid var(--line); border-radius:var(--radius); font-family:var(--sans); z-index:100; }
.inventory-filter-popover .field { margin-bottom:var(--s-2); }
.inventory-filter-popover label { color:var(--text); }
.inventory-filter-sort { display:flex; flex-wrap:wrap; gap:var(--s-2); margin-bottom:var(--s-3); }
.inventory-filter-bulk { display:flex; flex-wrap:wrap; gap:var(--s-2); margin-bottom:var(--s-2); }
.inventory-filter-sort [aria-pressed="true"] { background:var(--accent-soft); color:var(--accent-text); }
.inventory-filter-values { max-height:240px; overflow-y:auto; border-block:1px solid var(--line); padding:var(--s-1) 0; }
.inventory-filter-value { display:flex; align-items:center; gap:var(--s-2); min-height:40px; padding:var(--s-1); cursor:pointer; }
.inventory-filter-value[hidden] { display:none; }
.inventory-filter-value span { flex:1; min-width:0; overflow-wrap:anywhere; }
.inventory-filter-value small { color:var(--text-muted); font-variant-numeric:tabular-nums; }
.inventory-filter-value input[type="checkbox"] { width:16px; height:16px; flex-shrink:0; accent-color:var(--accent); }
.inventory-filter-popover .form-actions { flex-wrap:wrap; gap:var(--s-2); }
.inventory-part-detail { min-width:0; }
.inventory-part-detail h3 { font-size:var(--fs-callout); margin:var(--s-3) 0 var(--s-2); overflow-wrap:anywhere; }
.inventory-part-facts { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--s-2) var(--s-4); margin:var(--s-3) 0; }
.inventory-part-facts dt { color:var(--text-muted); font-size:var(--fs-caption); }
.inventory-part-facts dd { margin:var(--s-1) 0; overflow-wrap:anywhere; }
.inventory-part-history { list-style:none; margin:0; padding:0; }
.inventory-part-history li { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:var(--s-1) var(--s-2); padding:var(--s-2) 0; border-top:1px solid var(--line); }
.inventory-part-history li > span { grid-column:1/-1; overflow-wrap:anywhere; color:var(--text-secondary); }
.inventory-part-history time { font-size:var(--fs-caption); color:var(--text-muted); }
.inventory-status.status-rma { color:var(--warn); background:var(--warn-soft); }
.inventory-status.status-disposal { color:var(--danger); background:var(--danger-soft); }
@media (max-width:900px) {
  .inventory-list-toolbar .search { max-width:none; flex-basis:100%; }
  .inventory-list-tools { margin-left:0; }
  .inventory-list-toolbar .button, .inventory-column-head button, .inventory-filter-popover .button, .inventory-inline-parts .button { min-height:44px; }
  .inventory-column-head .inventory-column-filter { width:44px; }
  .inventory-filter-value { min-height:44px; }
  .inventory-part-facts { grid-template-columns:minmax(0,1fr); }
  .inventory-part-history li { grid-template-columns:minmax(0,1fr); }
}
.parts-stock .panel-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-3);
}
.parts-stock-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
}
.parts-stock-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
}
.parts-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
}
.parts-stock-search {
  display: flex;
  gap: var(--s-1);
  margin-left: auto;
  min-width: 0;
}
.parts-stock-search .input {
  width: 220px;
  max-width: 100%;
}
.parts-sub {
  display: block;
  color: var(--text-muted);
  font-size: var(--fs-caption);
}
.parts-stock-table td {
  overflow-wrap: anywhere;
}
@media (max-width: 900px) {
  .parts-stock-search {
    margin-left: 0;
    width: 100%;
  }
  .parts-stock-search .input {
    flex: 1;
    width: auto;
  }
}

/* ── 부품 변경 처리 (parts-queue.js) — 대시보드 ── */
.parts-queue .panel-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-3);
}
.parts-queue-section h3 {
  margin: 0 0 var(--s-1);
  font-size: var(--fs-callout);
}
.parts-queue .parts-change-head strong {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  flex-wrap: wrap;
  min-width: 0;
}
.parts-queue .parts-change-body {
  margin: 2px 0 0;
}
.parts-queue .button.ghost[data-asset] {
  height: auto;
  min-height: 0;
  padding: 0;
  white-space: normal;
  text-align: left;
  overflow-wrap: anywhere;
}

/* Physical geometry uses the incumbent parts palette; it is not an asset image. */
/* Approved Operations object workspace; rack detail retains its own layout. */
.asset-object-page .asset-object-header { display:flex; align-items:start; justify-content:space-between; flex-wrap:wrap; gap:var(--s-3); margin-bottom:var(--s-3); }
.asset-object-identity { flex:1 1 440px; min-width:0; }
.asset-object-title { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s-2); }
.asset-object-title h1 { margin:0; font-size:var(--fs-title1); overflow-wrap:anywhere; }
.asset-object-identity > p { margin:var(--s-1) 0 var(--s-3); font-size:var(--fs-caption); overflow-wrap:anywhere; }
.asset-object-facts { display:flex; flex-wrap:wrap; gap:var(--s-2) var(--s-4); margin:0; font-size:var(--fs-caption); }
.asset-object-facts > div { display:flex; gap:var(--s-1); min-width:0; max-width:100%; }
.asset-object-facts dt { flex-shrink:0; color:var(--text-muted); }
.asset-object-facts dd { margin:0; min-width:0; overflow-wrap:anywhere; }
.asset-object-actions { display:flex; flex-wrap:wrap; gap:var(--s-2); }
.asset-object-tabs { margin-bottom:var(--s-3); max-width:100%; overflow-x:auto; }
.asset-object-tabs button { flex-shrink:0; }
.asset-object-grid { display:grid; grid-template-columns:minmax(0,1.8fr) minmax(320px,1fr); gap:var(--s-3); align-items:start; }
.asset-main-column, .asset-side-column { display:grid; gap:var(--s-3); min-width:0; }
.asset-object-page .asset-panel + .asset-panel { margin-top:0; }
.asset-object-page .asset-panel { min-width:0; margin:0; }
.asset-object-page .asset-panel .panel-head { gap:var(--s-2); flex-wrap:wrap; }
.asset-object-page .asset-panel .panel-head time { font-size:var(--fs-caption); color:var(--text-muted); }
.asset-object-page .asset-comment { margin:0; padding:0; color:var(--text); background:transparent; }
.asset-object-page .rt-record-tools { display:flex; justify-content:flex-end; margin-bottom:var(--s-2); }
.asset-object-page .rt-record-fetched { display:block; margin-top:var(--s-2); font-size:var(--fs-caption); text-align:right; }
.asset-object-page .rt-record-view { font-size:var(--fs-callout); line-height:1.65; max-height:320px; overflow:auto; }
.asset-object-page .asset-section-link { display:block; width:100%; margin-top:var(--s-2); white-space:normal; height:auto; min-height:27px; }
.asset-work-list { list-style:none; margin:0; padding:0; }
.asset-work-list li + li { border-top:1px solid var(--line); }
.asset-work-row { display:grid; grid-template-columns:auto minmax(0,1fr) minmax(64px,auto) auto; gap:var(--s-2); align-items:center; border:0; padding:var(--s-2) 0; background:transparent; color:var(--text); width:100%; font:inherit; font-size:var(--fs-caption); text-align:left; cursor:pointer; }
.asset-work-row:hover { background:var(--surface-2); }
.asset-work-title { min-width:0; overflow-wrap:anywhere; }
.asset-work-title b { display:block; font-weight:560; }
.asset-work-title small { display:block; color:var(--text-muted); font-size:var(--fs-caption); }
.asset-work-row time { color:var(--text-muted); font-size:var(--fs-caption); }
.asset-object-page .asset-history { background:transparent; }
.asset-object-page .asset-history-row { grid-template-columns:54px minmax(0,1fr) auto; gap:var(--s-1) var(--s-2); padding:var(--s-2) 0; border-bottom:1px solid var(--line); background:transparent; font-size:var(--fs-caption); }
.asset-object-page .asset-history-row b { grid-column:2; grid-row:1; white-space:normal; overflow-wrap:anywhere; font-weight:560; }
.asset-object-page .asset-history-row time { grid-column:3; grid-row:1; font:inherit; color:var(--text-muted); }
.asset-object-page .asset-history-kind { grid-column:1; grid-row:1 / span 3; align-self:start; font-size:var(--fs-caption); font-weight:540; }
.asset-object-page .asset-history-kind.is-part { background:var(--accent-soft); color:var(--accent-text); }
.asset-object-page .asset-history-id { grid-column:2; grid-row:2; font:inherit; color:var(--text-muted); overflow-wrap:anywhere; }
.asset-object-page .asset-history-row > span:last-of-type { grid-column:3; grid-row:2; overflow-wrap:anywhere; }
.asset-event-body { grid-column:2 / -1; font-size:var(--fs-caption); color:var(--text-secondary); overflow-wrap:anywhere; }
.asset-object-pager { display:flex; align-items:center; justify-content:flex-end; gap:var(--s-2); margin-top:var(--s-3); font-size:var(--fs-caption); }
.asset-history-boundary { margin:0; font-size:var(--fs-caption); }
.asset-configuration-facts { display:grid; grid-template-columns: auto minmax(0,1fr); gap:var(--s-1) var(--s-3); margin:var(--s-3) 0; font-size:var(--fs-caption); }
.asset-configuration-facts dt { color:var(--text-muted); }
.asset-configuration-facts dd { text-align:right; margin:0; overflow-wrap:anywhere; }
.asset-configuration .chassis-surface > p { margin-bottom:var(--s-2); }
.asset-configuration .chassis-face + .chassis-face { margin-top:var(--s-2); }
.asset-configuration .chassis-port-group { flex-basis:80px; }
.asset-configuration .chassis-frame { padding:var(--s-1); }
.asset-configuration .chassis-rear { gap:var(--s-2); }
.asset-integration { margin-top:var(--s-4); padding-top:var(--s-3); border-top:1px solid var(--line); font-size:var(--fs-caption); color:var(--text-muted); }
.asset-integration summary { cursor:pointer; }
.asset-integration p { max-width:75ch; line-height:1.6; }
.asset-integration .asset-tag-list { margin-bottom:var(--s-2); }
@media (max-width:1100px) {
  .asset-object-grid { grid-template-columns:minmax(0,1.3fr) minmax(300px,1fr); }
  .asset-work-row { grid-template-columns:auto minmax(0,1fr); }
  .asset-work-row > .meta, .asset-work-row > time { grid-column:2; }
}
@media (max-width:900px) {
  .asset-object-grid { grid-template-columns:minmax(0,1fr); }
  .asset-side-column { grid-template-columns:repeat(2,minmax(0,1fr)); }
  .asset-object-page .asset-object-tabs button, .asset-object-page .button, .asset-object-page .asset-work-row { min-height:44px; }
  .asset-object-page .asset-history-row { min-height:44px; grid-template-columns:54px minmax(0,1fr); }
  .asset-object-page .asset-history-row time { grid-column:2; grid-row:2; }
  .asset-object-page .asset-history-id { grid-column:2; grid-row:3; }
  .asset-object-page .asset-history-row > span:last-of-type { grid-column:2; grid-row:4; }
  .asset-event-body { grid-column:2; }
}
@media (max-width:600px) {
  .asset-side-column { grid-template-columns:minmax(0,1fr); }
  .asset-object-facts > div { flex-wrap:wrap; }
  .asset-object-actions { width:100%; }
  .asset-object-page .asset-object-tabs { width:100%; }
}
.chassis-surface, .chassis-settings, .chassis-rack { min-width: 0; }
.chassis-profile { margin-bottom: var(--s-4); }
.chassis-assignment { display: flex; align-items: end; flex-wrap: wrap; gap: var(--s-2); }
.chassis-assignment .field { flex: 1 1 220px; min-width: 0; }
.chassis-assignment select { width: 100%; }
.chassis-face + .chassis-face, .chassis-outside, .chassis-internal { margin-top: var(--s-4); }
.chassis-face h3 { margin: 0 0 var(--s-2); font-size: var(--fs-caption); color: var(--text-muted); }
.chassis-scroll { overflow-x: auto; padding: var(--s-1); margin: calc(-1 * var(--s-1)); }
.chassis-frame { width: 100%; box-sizing: border-box; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2); padding: var(--s-2); }
.chassis-front { display: grid; gap: var(--s-1); grid-template-columns: repeat(var(--chassis-cols),minmax(24px,1fr)); grid-template-rows: repeat(var(--chassis-rows),minmax(var(--chassis-bay-h,52px),auto)); min-width: calc(var(--chassis-cols) * 28px + 12px); }
.chassis-front.is-lff { --chassis-bay-h: 32px; }
.chassis-front .parts-bay { width: 100%; height: 100%; min-height: var(--chassis-bay-h,52px); min-width: 24px; }
.chassis-front .parts-bay.is-empty { border-color: var(--line); background: var(--surface); }
.chassis-front .parts-bay.is-empty i { background: var(--text-muted); }
.chassis-rear { display: flex; gap: var(--s-3); flex-wrap: wrap; min-height: 72px; }
.chassis-port-group { min-width: 0; flex: 1 1 110px; }
.chassis-port-group > strong { display: block; font-size: var(--fs-caption); margin-bottom: var(--s-1); }
.chassis-port-group > div, .chassis-internal > div { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.chassis-port-group .button, .chassis-internal .button { max-width: 100%; height: auto; white-space: normal; overflow-wrap: anywhere; }
.chassis-port { display: inline-flex; align-items: center; min-height: 27px; padding: 0 var(--s-2); border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); font-size: var(--fs-caption); overflow-wrap: anywhere; }
.chassis-port.is-linked { color: var(--ok); background: var(--ok-soft); }
.chassis-internal { display: grid; grid-template-columns: 64px minmax(0,1fr); gap: var(--s-2); border-top: 1px solid var(--line); padding-top: var(--s-3); font-size: var(--fs-caption); }
.chassis-part-label { padding: var(--s-1) var(--s-2); background: var(--surface-2); overflow-wrap: anywhere; }
.chassis-outside strong { font-size: var(--fs-caption); }
.chassis-outside .parts-bays { display: flex; flex-wrap: wrap; max-width: 100%; }
.chassis-outside .button { max-width: 100%; white-space: normal; height: auto; overflow-wrap: anywhere; }
/* Inventory sync: source freshness is not the timestamp of the displayed list. */
.inventory-page .inventory-sync-status { display: grid; gap: var(--s-1); max-width: 38ch; text-align: end; }
.inventory-page .inventory-sync-status .meta { white-space: normal; overflow-wrap: anywhere; }
@media (max-width: 600px) {
  .inventory-page .inventory-sync-status { text-align: start; max-width: 100%; }
  .inventory-page .inventory-sync-status .button { min-height: 44px; }
}
.chassis-editor { margin-top: var(--s-4); }
.chassis-editor fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.chassis-editor .form-grid { grid-template-columns: repeat(3,minmax(0,1fr)); }
.chassis-editor h3 { font-size: var(--fs-body); margin: var(--s-4) 0 var(--s-3); }
.chassis-group-form { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: var(--s-2); padding: var(--s-3) 0; border-top: 1px solid var(--line); }
.chassis-row-actions { display: flex; gap: var(--s-1); }
.chassis-settings .panel-head { gap: var(--s-2); flex-wrap: wrap; }
.chassis-settings .data-table td { overflow-wrap: anywhere; }
.chassis-rack-unit { display: grid; grid-template-columns: 28px minmax(0,1fr); min-height: 28px; border-top: 1px solid var(--line); align-items: stretch; font-size: 12px; }
.chassis-rack-unit > span { display: grid; place-items: center; color: var(--text-muted); }
.chassis-rack-unit > div { display: flex; min-width: 0; }
.chassis-rack-unit > div > * { flex: 1; min-width: 0; height: auto; padding: var(--s-1) var(--s-2); white-space: normal; overflow-wrap: anywhere; }
.chassis-rack-unit .is-selected { color: var(--accent-text); background: var(--accent-soft); font-weight: 600; }

/* Inventory: location-first rack browsing, approved flat 2D elevations. */
.inventory-view-tabs { margin-bottom: var(--s-4); }
.inventory-racks { display: grid; grid-template-columns: 152px minmax(0,1fr); gap: var(--s-4); align-items: start; }
.ir-locations { position: sticky; top: calc(var(--topbar-h) + var(--s-4)); min-width: 0; border-right: 1px solid var(--divider); padding-right: var(--s-2); }
.ir-locations h2 { font-size: var(--fs-callout); margin: 0 0 var(--s-2); padding: var(--s-2); }
.ir-locations h3 { font-size: var(--fs-caption); font-weight: 500; color: var(--text-muted); margin: var(--s-4) 0 var(--s-1); padding: 0 var(--s-2); }
.ir-location { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); width: 100%; min-height: 36px; padding: var(--s-2); border: 0; border-radius: var(--radius); background: transparent; color: var(--text-secondary); font: var(--fs-callout) var(--sans); text-align: left; cursor: pointer; }
.ir-location span { min-width: 0; overflow-wrap: anywhere; }
.ir-location small { color: var(--text-muted); font-size: var(--fs-caption); font-variant-numeric: tabular-nums; }
.ir-location:hover { background: var(--surface-hover); }
.ir-location[aria-pressed='true'] { background: var(--surface-active); color: var(--text); font-weight: 600; }
.ir-wall { --rack-width: 62px; --rack-gap: var(--s-1); min-width: 0; }
.ir-wall[data-size='compact'] { --rack-width: 48px; --rack-gap: var(--s-2); }
.ir-wall[data-size='large'] { --rack-width: 82px; --rack-gap: var(--s-3); }
.ir-toolbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--s-3); border-bottom: 1px solid var(--divider); padding-bottom: var(--s-3); margin-bottom: var(--s-3); font-size: var(--fs-callout); }
.ir-size { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-caption); color: var(--text-secondary); }
.ir-legend { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); font-size: var(--fs-caption); color: var(--text-secondary); margin-bottom: var(--s-4); }
.ir-legend > span { display: inline-flex; align-items: center; gap: var(--s-1); }
.ir-legend i { width: 9px; height: 9px; border: 1px solid var(--border-strong); background: var(--surface); border-radius: 2px; }
.ir-legend .used { background: var(--n-300); border-color: var(--n-500); }
.ir-legend .reserved { background: var(--warn-soft); border-color: var(--warn); }
.ir-legend .unavailable { background: var(--n-500); }
.ir-legend .problem { background: var(--danger-soft); border-color: var(--danger); }
.ir-facility + .ir-facility { margin-top: var(--s-6); }
.ir-facility h2 { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0 0 var(--s-2); font-size: var(--fs-callout); font-weight: 500; color: var(--text-secondary); overflow-wrap: anywhere; }
.ir-facility h2 span { font-weight: 600; color: var(--text); }
.ir-rows { border: 1px solid var(--border); background: var(--surface); border-radius: var(--radius-lg); overflow: hidden; }
.ir-row + .ir-row { border-top: 1px solid var(--divider); }
.ir-row > summary { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-2) var(--s-3); min-height: 44px; cursor: pointer; font-size: var(--fs-caption); list-style: none; }
.ir-row > summary::-webkit-details-marker { display: none; }
.ir-row > summary::before { content: ''; flex: 0 0 6px; width: 6px; height: 6px; border-right: 1px solid var(--text-muted); border-bottom: 1px solid var(--text-muted); transform: rotate(-45deg); margin-right: var(--s-1); }
.ir-row[open] > summary::before { transform: rotate(45deg); }
.ir-row > summary:hover { background: var(--surface-hover); }
.ir-row > summary > span { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.ir-row > summary small { margin-left: auto; flex-shrink: 0; color: var(--text-muted); font-size: var(--fs-caption); }
.ir-strip { display: grid; grid-auto-flow: column; grid-auto-columns: calc(var(--rack-width) + 8px); grid-template-rows: auto auto auto; align-items: end; gap: var(--s-1) var(--rack-gap); overflow-x: auto; overscroll-behavior-x: contain; padding: var(--s-2) var(--s-4) var(--s-2) var(--s-2); scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
.ir-rack { flex: 0 0 calc(var(--rack-width) + 8px); display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: var(--s-1); width: calc(var(--rack-width) + 8px); min-width: 44px; padding: var(--s-1) 2px; border: 1px solid transparent; border-radius: var(--radius-sm); background: transparent; color: var(--text); cursor: pointer; font-family: var(--sans); }
.ir-rack:hover { border-color: var(--border-strong); background: var(--surface-hover); }
.ir-rack { display: grid; grid-row: span 3; grid-template-rows: subgrid; justify-items: center; }
.ir-rack b, .ir-rack small { align-self: start; }
.ir-rack.is-last { border-color: var(--accent); background: var(--accent-soft); }
.ir-rack svg { display: block; width: var(--rack-width); height: auto; flex: none; }
.ir-frame { fill: var(--n-200); stroke: var(--n-500); stroke-width: 1; }
.ir-bay { fill: var(--surface); }
.ir-grid { fill: none; stroke: var(--border); stroke-width: .3; }
.ir-ticks { fill: none; stroke: var(--n-400); stroke-width: .6; }
.ir-equipment { fill: var(--n-300); stroke: var(--n-500); stroke-width: .65; }
.ir-equipment.reserved { fill: var(--warn-soft); stroke: var(--warn); }
.ir-equipment.unavailable, .ir-equipment.absent, .ir-equipment.unknown { fill: var(--n-500); stroke: var(--border); }
.ir-equipment.unknown { fill: var(--warn-soft); stroke: var(--warn); }
.ir-legend .unknown { background: var(--warn-soft); border-color: var(--warn); }
.ir-equipment.problem { fill: var(--danger-soft); stroke: var(--danger); }
.ir-mark { fill: none; stroke: var(--surface); stroke-width: .55; }
.ir-question { fill: var(--text-secondary); font: 24px var(--sans); }
.ir-rack b { max-width: 100%; font-size: var(--fs-callout); font-weight: 600; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.ir-rack small { max-width: 100%; font-size: var(--fs-micro); color: var(--text-muted); overflow-wrap: anywhere; }
.ir-rack .ir-attention { color: var(--danger); }
.ir-caption { margin: var(--s-3) 0; font-size: var(--fs-caption); line-height: 1.6; color: var(--text-secondary); }
.ir-elevation { padding: 0 var(--s-4) var(--s-4); }
.ir-elevation table { width: 100%; table-layout: fixed; border-collapse: collapse; background: var(--surface); }
.ir-elevation th:first-child { width: 36px; }
.ir-elevation th { padding: var(--s-1); background: var(--surface-2); color: var(--text-secondary); font-size: var(--fs-caption); font-weight: 500; }
.ir-elevation tbody th { height: 28px; font-variant-numeric: tabular-nums; }
.ir-elevation td, .ir-elevation th { border: 1px solid var(--divider); }
.ir-elevation td { padding: 0; text-align: center; }
.ir-elevation td button { width: 100%; min-height: 28px; border: 0; background: var(--n-200); color: var(--text); padding: var(--s-2); cursor: pointer; font: var(--fs-caption) var(--sans); overflow-wrap: anywhere; }
.ir-elevation td button:hover { background: var(--n-300); }
.ir-elevation td.problem button { background: var(--danger-soft); }
.ir-elevation td span { display: block; padding: var(--s-1); font-size: var(--fs-micro); color: var(--text-secondary); overflow-wrap: anywhere; }
.ir-elevation td.reserved { background: var(--warn-soft); }
.ir-elevation td.unavailable, .ir-elevation td.absent, .ir-elevation td.unknown { background: var(--bg-sunken); }
.inventory-racks :is(button, summary, [tabindex]):focus-visible, .ir-elevation button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 900px) {
  .inventory-racks { grid-template-columns: minmax(0,1fr); gap: var(--s-3); }
  .ir-locations { position: static; border-right: 0; border-bottom: 1px solid var(--divider); padding: 0 0 var(--s-2); }
  .ir-locations h2 { padding: 0; }
  .ir-location-links { display: flex; align-items: center; gap: var(--s-1); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; padding: var(--s-1) 2px; }
  .ir-location-links h3 { margin: 0; flex: none; padding: 0 var(--s-2); }
  .ir-location { width: auto; flex: none; min-height: 44px; max-width: 240px; }
  .ir-location span { max-width: 190px; }
  .inventory-view-tabs button, .ir-size button, .ir-elevation td button { min-height: 44px; }
  .ir-elevation { padding: 0 var(--s-2) var(--s-2); }
}
@media (max-width: 900px) {
  .chassis-front { grid-template-columns: repeat(var(--chassis-cols),minmax(44px,1fr)); min-width: calc(var(--chassis-cols) * 48px + 12px); }
  .chassis-front.is-lff { --chassis-bay-h: 44px; }
  .chassis-front .parts-bay { min-width: 44px; min-height: 44px; }
}
@media (max-width: 600px) {
  .chassis-editor .form-grid, .chassis-group-form { grid-template-columns: minmax(0,1fr); }
  .chassis-assignment { align-items: stretch; }
  .chassis-assignment > .field { flex-basis: 100%; }
  .chassis-assignment .button, .chassis-settings .button, .chassis-rack .button, .chassis-port-group .button, .chassis-internal .button { min-height: 44px; }
}

/* Rack placement is a progressive Operations form, not an editable mirror. */
.rack-placement { margin-bottom: var(--s-4); scroll-margin-top: 80px; min-width: 0; }
.rack-placement .panel-head { flex-wrap: wrap; gap: var(--s-3); }
.rack-placement .form-actions { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0; }
.rack-placement .panel-body { display: grid; gap: var(--s-4); min-width: 0; }
.rack-placement :is(fieldset,dl,p) { margin: 0; }
.rack-placement fieldset { padding: 0; border: 0; min-width: 0; }
.rp-editor { gap: var(--s-4); }
.rp-fields { display: grid; grid-template-columns: minmax(130px,1fr) minmax(180px,2fr) repeat(2,minmax(120px,1fr)); gap: var(--s-3); }
.rp-fields .field { min-width: 0; }
.rp-fields :is(input,select) { width: 100%; min-width: 0; }
.rp-depth { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); margin-top: var(--s-3) !important; }
.rp-depth legend { font-size: var(--fs-caption); color: var(--text-secondary); margin-bottom: var(--s-2); }
.rp-depth label { display: inline-flex; gap: var(--s-2); align-items: center; min-height: 32px; }
.rp-depth input { accent-color: var(--accent); }
.rp-compare { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: var(--s-4); }
.rp-compare dt { font-size: var(--fs-caption); color: var(--text-secondary); margin-bottom: var(--s-2); }
.rp-compare dd { margin: 0; overflow-wrap: anywhere; line-height: 1.6; }
.rp-notice { padding: var(--s-3); background: var(--surface-2); color: var(--text-secondary); font-size: var(--fs-caption); line-height: 1.6; overflow-wrap: anywhere; }
.rp-notice.is-error { color: var(--danger); background: var(--danger-soft); }
.rp-elevation { max-height: 360px; overflow: auto; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; border: 1px solid var(--divider); }
.rp-elevation table { width: 100%; border-collapse: separate; border-spacing: 0; table-layout: fixed; font-size: var(--fs-caption); }
.rp-elevation th { font-weight: 500; color: var(--text-secondary); background: var(--surface-2); }
.rp-elevation thead th { position: sticky; top: 0; z-index: 1; }
.rp-elevation th:first-child { width: 42px; font-variant-numeric: tabular-nums; }
.rp-elevation :is(th,td) { padding: var(--s-2); border-bottom: 1px solid var(--divider); border-right: 1px solid var(--divider); overflow-wrap: anywhere; }
.rp-elevation td { color: var(--text-secondary); background: var(--surface); }
.rp-elevation td.is-occupied { color: var(--text); background: var(--surface-2); }
.rp-elevation td.is-target { color: var(--accent); background: var(--accent-soft); }
.rp-elevation td.is-conflict { color: var(--danger); background: var(--danger-soft); }
.rp-job { display: grid; gap: var(--s-3); padding-bottom: var(--s-4); border-bottom: 1px solid var(--divider); }
.rp-job h3, .rp-history h3 { margin: 0; font-size: var(--fs-body); }
.rp-reason { overflow-wrap: anywhere; white-space: pre-wrap; }
.rp-history { display: grid; gap: var(--s-3); }
.inventory-management { margin-bottom: var(--s-4); }
.inventory-management .panel-body { padding: var(--s-4); }
.inventory-management fieldset { border: 0; margin: 0; padding: 0; display: grid; gap: var(--s-4); min-width: 0; }
.inventory-management .form-grid { grid-template-columns: repeat(2,minmax(0,1fr)); align-items: end; }
.inventory-management .im-attributes { margin-top: var(--s-3); }
.inventory-management :is(input,select) { max-width: 100%; min-width: 0; }
.inventory-management select[multiple] { min-height: 120px; }
.inventory-management .im-depth { display: flex; flex-wrap: wrap; gap: var(--s-4); }
.inventory-management .im-depth label { display: flex; align-items: center; gap: var(--s-2); }
.inventory-management .im-history { margin-top: var(--s-6); border-top: 1px solid var(--divider); padding-top: var(--s-4); }
.inventory-management :is(td,code) { overflow-wrap: anywhere; }
.inventory-management td small { display: block; }
.inventory-management :is(button,summary,[tabindex]):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.im-detail-action { margin-block: var(--s-3); }
.asset-rack-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
}
.asset-rack-heading > div {
  min-width: 0;
}
.asset-rack-meta {
  margin-block: var(--s-2) 0;
  overflow-wrap: anywhere;
}
.asset-rack-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}
.asset-rack-actions .im-detail-action {
  margin: 0;
}
.asset-rack-page .asset-head-tags {
  margin-top: var(--s-3);
}
.asset-rack-page .asset-rack-layout {
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
}
.asset-rack-page .ir-elevation tbody th {
  height: 15px;
  padding: 0 var(--s-1);
  font-size: var(--fs-caption);
  line-height: 1;
}
.asset-rack-page .ir-elevation td {
  padding: 0;
  position: relative;
}
/* The complete 44px mounted list is the touch alternative to dense physical U blocks. */
.asset-rack-page .ir-elevation td button {
  position: absolute;
  inset: 0;
  height: 100%;
  min-height: 0;
  padding: 0 var(--s-1);
  font-size: var(--fs-caption);
  line-height: 1.1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.asset-rack-page .asset-mounted-row {
  min-height: 44px;
}
.asset-rack-page .asset-mounted-row > span:last-child {
  min-width: 0;
  overflow-wrap: anywhere;
}
.asset-rack-page .asset-mounted-row small {
  display: block;
  color: var(--text-muted);
  margin-top: var(--s-1);
}
.inventory-name-edit {
  display: inline;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
  overflow-wrap: anywhere;
}
.inventory-name-edit:hover {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
.inventory-name-edit:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
@media (max-width: 900px) {
  .asset-rack-heading {
    display: block;
  }
  .asset-rack-actions {
    margin-top: var(--s-3);
  }
  .asset-rack-actions .button {
    min-height: 44px;
  }
  .asset-rack-page .asset-rack-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .inventory-card-row .inventory-name-edit {
    min-height: 44px;
  }
}
/* Inventory operates in-place: one toolbar, protected side-sheet, complete mobile rows. */
.inventory-page-head {
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-3);
}
.inventory-page-head .inventory-sync {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
}
@media(min-width:901px) {
  .inventory-page-head { flex-wrap:nowrap; }
  .inventory-page-head .inventory-sync { flex-wrap:nowrap; flex-shrink:0; }
  .inventory-page-head > div:first-child { flex-wrap:nowrap; gap:var(--s-3); }
}
.inventory-register-reason { margin:0 0 var(--s-3); }
.taxonomy-spec-order { grid-column:1/-1; margin:0; padding-left:var(--s-5); }
.taxonomy-spec-order li { margin-top:var(--s-2); }
.taxonomy-spec-order .form-actions { display:inline-flex; margin-left:var(--s-2); }
.runbook-detail-head .page-meta { color:var(--text-muted); font-size:var(--fs-caption); }
@media(max-width:900px) {
  .account-page .panel-head { flex-wrap:wrap; gap:var(--s-3); }
  .account-page .panel-head .page-head-actions { flex-wrap:wrap; flex-shrink:1; min-width:0; max-width:100%; }
}
.inventory-page-head + .inventory-view-tabs {
  margin-top: 0;
}
.inventory-preservation,
.inventory-register,
.inventory-list-tools {
  position: relative;
}
.inventory-popover {
  position: absolute;
  z-index: 20;
  inset-inline-end: 0;
  top: calc(100% + var(--s-2));
  width: max-content;
  max-width: min(340px, calc(100vw - 32px));
  padding: var(--s-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: grid;
  gap: var(--s-2);
}
.inventory-popover .button {
  justify-content: flex-start;
  white-space: normal;
}
.inventory-popover p {
  margin: 0;
}
details:not([open]) > .inventory-popover {
  display: none;
}
.inventory-list-toolbar {
  gap: var(--s-2);
  flex-wrap: wrap;
}
.inventory-list-toolbar .search {
  flex: 1 1 260px;
  width: auto;
  min-width: 120px;
}
.inventory-list-toolbar .inventory-status-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  padding: 0;
}
.inventory-list-toolbar .inventory-totals {
  display: flex;
  flex-wrap: wrap;
  padding: 0;
  margin: 0;
  border: 0;
  gap: var(--s-2);
}
.inventory-list-toolbar .inventory-total {
  padding: var(--s-1);
  border: 0;
  background: transparent;
}
.inventory-list-toolbar .inventory-total strong {
  font-size: inherit;
}
.inventory-list-toolbar .inventory-list-tools {
  margin-left: 0;
}
.inventory-result-count {
  white-space: nowrap;
}
.inventory-mobile-filter,
.inventory-card-rows {
  display: none;
}
.inventory-conditions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-4);
}
.inventory-conditions .pick-chip {
  max-width: 100%;
  overflow-wrap: anywhere;
}
.inventory-archive-mark {
  display: inline-flex;
  margin-inline-start: var(--s-2);
  padding: 1px var(--s-1);
  border-radius: var(--radius);
  font-size: var(--fs-caption);
  color: var(--text-muted);
  background: var(--surface-hover);
  white-space: normal;
}
.inventory-archive-mark.is-conflict {
  color: var(--danger);
}
.inventory-empty-toggle {
  color: var(--text-muted);
  font-size: var(--fs-caption);
}
.inventory-sheet-backdrop {
  position: fixed;
  inset: 0;
  display: flex;
  justify-content: flex-end;
  align-items: stretch;
  padding: 0;
  z-index: 1200;
}
.inventory-sheet.modal {
  width: 520px;
  max-width: 100%;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  border-radius: var(--radius) 0 0 var(--radius);
  display: flex;
  flex-direction: column;
}
.inventory-sheet .modal-head {
  flex: 0 0 auto;
  align-items: flex-start;
}
.inventory-sheet .modal-head h2 {
  min-width: 0;
  overflow-wrap: anywhere;
}
.inventory-sheet .modal-body {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  padding: var(--s-4);
}
.inventory-sheet .modal-foot {
  flex: 0 0 auto;
  padding: var(--s-3) var(--s-4);
  padding-bottom: max(var(--s-3), env(safe-area-inset-bottom));
  align-items: center;
  gap: var(--s-3);
}
.inventory-sheet .modal-foot p {
  flex: 1;
  margin: 0;
}
.inventory-sheet .modal-foot .form-actions {
  margin: 0;
  flex-wrap: nowrap;
}
.inventory-sheet .im-history {
  margin: 0;
  padding: 0;
  border: 0;
}
.inventory-editor-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  padding: var(--s-2) var(--s-4);
  border-bottom: 1px solid var(--divider);
}
.inventory-sheet .inventory-editor-tabs .button.secondary[aria-selected='true'],
.inventory-sheet .inventory-kind-options .button.secondary[aria-checked='true'] {
  color: var(--accent-text);
  background: var(--accent-soft);
}
.inventory-kind-field {
  grid-column: 1 / -1;
}
.inventory-kind-options {
  display: flex;
  gap: var(--s-2);
}
.inventory-kind-options button {
  flex: 1;
}
.inventory-tag-picker {
  display: grid;
  gap: var(--s-2);
}
.inventory-tag-selection,
.inventory-tag-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
}
.inventory-tag-options {
  max-height: 150px;
  overflow-y: auto;
}
.inventory-tag-picker button {
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
}
.inventory-change-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.inventory-change-list li {
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--divider);
  overflow-wrap: anywhere;
}
.inventory-change-title {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-2);
}
.inventory-change-list .form-actions {
  flex-wrap: wrap;
}
.inventory-compare-list > div {
  padding-block: var(--s-3);
  border-bottom: 1px solid var(--divider);
}
.inventory-compare-list dt {
  font-weight: 600;
}
.inventory-compare-list dd {
  margin: var(--s-2) 0 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-1);
  overflow-wrap: anywhere;
}
@media (max-width: 900px) {
  .inventory-page-head {
    display: block;
  }
  .inventory-page-head .inventory-sync {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    width: 100%;
    margin-top: var(--s-3);
  }
  .inventory-page-head .inventory-preservation {
    grid-column: 1 / -1;
    grid-row: 2;
  }
  .inventory-page-head .inventory-sync > button {
    grid-column: 2;
    grid-row: 1;
  }
  .inventory-page-head .inventory-sync > #inventory-register,
  .ipam-page .inventory-page-head .inventory-sync > [data-action='ipam-network-create'] {
    grid-column: 1;
    grid-row: 1;
  }
  .inventory-popover {
    max-width: calc(100vw - 32px);
  }
  .inventory-page-head .inventory-preservation .inventory-popover {
    inset-inline: 0 auto;
  }
  .inventory-list-toolbar .search {
    flex-basis: 100%;
  }
  .inventory-list-toolbar .inventory-status-legend {
    flex: 1 1 100%;
  }
  .inventory-list-toolbar :is(button, summary),
  .inventory-page-head :is(button, summary) {
    min-height: 44px;
  }
  .inventory-mobile-filter {
    display: inline-flex;
  }
  .inventory-desktop-table {
    display: none;
  }
  .inventory-card-rows {
    display: block;
  }
  .inventory-card-row {
    display: block;
    text-align: start;
    width: 100%;
    color: var(--text);
    background: transparent;
    border: 0;
    border-top: 1px solid var(--divider);
    padding: var(--s-3) var(--s-4);
    min-height: 44px;
    font: inherit;
    cursor: pointer;
  }
  .inventory-card-row:hover {
    background: var(--surface-hover);
  }
  .inventory-card-row :is(strong, .subtext) {
    overflow-wrap: anywhere;
    white-space: normal;
  }
  .inventory-card-name {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-1);
  }
  .inventory-card-name .inventory-archive-mark {
    margin: 0;
  }
  .inventory-card-facts {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--s-2);
    margin-top: var(--s-2);
    font-size: var(--fs-caption);
  }
  .inventory-card-facts > span {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  .inventory-card-facts .inventory-status {
    flex-shrink: 0;
  }
  .inventory-rail {
    min-width: 0;
  }
  .inventory-empty-toggle {
    flex-shrink: 0;
  }
  .inventory-sheet.modal {
    width: 100%;
    border-radius: 0;
  }
  .inventory-sheet :is(button, summary, input:not([type='checkbox']), select) {
    min-height: 44px;
  }
  .inventory-sheet .modal-foot {
    flex-wrap: wrap;
  }
  .inventory-sheet .modal-foot p {
    flex-basis: 100%;
  }
  .inventory-sheet .modal-foot .form-actions {
    margin-left: auto;
  }
}
@media (max-width: 600px) {
  .inventory-management .form-grid { grid-template-columns: minmax(0,1fr); }
  .inventory-management :is(.button,input:not([type=checkbox]),select), .inventory-management .im-depth label { min-height: 44px; }
}
.rp-history details { padding: var(--s-3) 0; border-top: 1px solid var(--divider); }
.inventory-registration-groups { display:flex; gap:var(--s-1); margin:var(--s-3) var(--s-4) 0; padding:var(--s-1); background:var(--surface-2); border-radius:var(--radius); }
.inventory-registration-groups .button { flex:1; min-width:0; }
.inventory-sheet .inventory-registration-groups .button[aria-selected='true'],
.inventory-sheet .inventory-kind-options .button[aria-pressed='true'] { background:var(--accent-soft); color:var(--accent); border-color:var(--accent-border); box-shadow:inset 0 -2px 0 var(--accent); }
.inventory-operation-actions, .inventory-customer-chips { display:flex; flex-wrap:wrap; gap:var(--s-2); }
.inventory-sheet .im-problem-toggle { display:flex; align-items:center; gap:var(--s-2); min-height:44px; cursor:pointer; }
.inventory-tax-options { max-height:180px; overflow:auto; display:flex; flex-direction:column; gap:var(--s-1); scroll-padding:var(--s-2); }
.inventory-tax-options .button { text-align:left; justify-content:flex-start; white-space:normal; flex-wrap:wrap; }
.inventory-tax-options .button[hidden] { display:none; }
.inventory-tax-options[hidden] { display:none; }
.taxonomy-audit pre { max-width:100%; max-height:240px; overflow:auto; font-size:var(--fs-caption); }
.inventory-tax-options [aria-selected='true'] { background:var(--accent-soft); }
.inventory-tax-options :focus-visible { scroll-margin:var(--s-2); }
.inventory-sheet .field.inventory-kind-field { grid-column:1 / -1; }
.inventory-taxonomy .panel-head { padding-inline:0; }
.taxonomy-layout { display:grid; grid-template-columns:180px minmax(0,1fr); gap:var(--s-4); }
.taxonomy-nav { display:flex; flex-direction:column; gap:var(--s-1); }
.taxonomy-nav .button { display:flex; justify-content:space-between; text-align:left; }
.inventory-taxonomy .taxonomy-nav .button[aria-pressed='true'] { background:var(--accent-soft); color:var(--accent); border-color:var(--accent-border); box-shadow:inset 0 -2px 0 var(--accent); }
.taxonomy-content { min-width:0; }
.taxonomy-options { display:flex; flex-wrap:wrap; gap:var(--s-2) var(--s-4); grid-column:1 / -1; max-height:240px; overflow:auto; }
.taxonomy-options label { display:flex; align-items:center; gap:var(--s-1); }
.taxonomy-edit { max-width:720px; }
@media(max-width:900px) {
  .page-head .button, .page-head summary, .inventory-registration-groups .button,
  .taxonomy-nav .button, .inventory-tax-options .button, .inventory-taxonomy .button { min-height:44px; }
  .taxonomy-layout { grid-template-columns:minmax(0,1fr); }
  .taxonomy-nav { flex-direction:row; flex-wrap:wrap; }
  .taxonomy-nav .button { flex:1 1 auto; gap:var(--s-2); }
  .inventory-taxonomy .panel-head { flex-wrap:wrap; }
  .inventory-taxonomy .table-wrap { max-width:100%; }
}
@media(max-width:600px) {
  .inventory-sheet.parts-editor .parts-grid { grid-template-columns:minmax(0,1fr); }
}
.rp-history summary, .rp-receipt summary { cursor: pointer; overflow-wrap: anywhere; }
.rp-history details[open] > :not(summary), .rp-receipt[open] > :not(summary) { margin-top: var(--s-3); }
.rack-placement :is(button,summary,[tabindex]):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 1100px) { .rp-fields { grid-template-columns: repeat(2,minmax(0,1fr)); } }
@media (max-width: 600px) {
  .rp-fields, .rp-compare { grid-template-columns: minmax(0,1fr); }
  .rack-placement :is(.button,input:not([type=checkbox]),select), .rp-depth label, .rp-history summary, .rp-receipt summary { min-height: 44px; }
  .rack-placement .panel-head .form-actions { width: 100%; }
}

/* 등록 서랍 (2026-10-13): 구역마다 제목, 칸은 같은 폭 두 열, 긴 값은 칸 안에서 처리한다.
   전에는 칸 폭이 내용에 따라 달라지고 RackTables 사전 값이 칸 밖으로 삐져나왔다. */
.inventory-sheet.modal { width: 600px; }
.inventory-sheet .im-form > fieldset { display: grid; gap: 0; min-width: 0; border: 0; margin: 0; padding: 0; }
.inventory-sheet .im-section { display: grid; gap: var(--s-3); min-width: 0; padding: var(--s-4) 0; border-top: 1px solid var(--divider); }
.inventory-sheet .im-section:first-of-type { padding-top: 0; border-top: 0; }
.inventory-sheet .im-section > h3 { margin: 0; font-size: var(--fs-body); font-weight: 600; color: var(--text); }
.inventory-sheet .im-section .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.inventory-sheet .field :is(input:not([type='checkbox']), select) { width: 100%; min-width: 0; max-width: 100%; text-overflow: ellipsis; }
.inventory-sheet .inventory-customer-chips .button { height: auto; min-height: 32px; max-width: 100%; white-space: normal; text-align: left; overflow-wrap: anywhere; }
.inventory-sheet .im-disks .im-disk-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.inventory-sheet .im-disks > .button { justify-self: start; }
.inventory-sheet .modal-foot { justify-content: flex-end; }
@media (max-width: 600px) {
  .inventory-sheet .im-section .form-grid,
  .inventory-sheet .im-disks .im-disk-list { grid-template-columns: minmax(0, 1fr); }
}
/* 랙 그림에서 고르기: 등록 서랍 위에 뜨는 창. 랙 전면을 U 단위로 그리고 빈 칸만 누를 수 있다. */
.im-rack-pick-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.im-rack-pick-row > span { font-size: var(--fs-caption); color: var(--text-secondary); }
.im-rack-picker-backdrop { position: fixed; inset: 0; z-index: 1300; display: flex; align-items: center; justify-content: center; padding: var(--s-4); background: rgba(15, 23, 42, 0.5); }
.im-rack-picker.modal { width: 760px; max-width: 100%; max-height: calc(100dvh - 32px); display: flex; flex-direction: column; margin: 0; }
.im-rack-picker .modal-body { flex: 1 1 auto; min-height: 0; overflow: auto; display: grid; gap: var(--s-3); }
.im-rack-picker-fields { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.im-rack-picker-main { display: grid; grid-template-columns: minmax(0, 360px) minmax(0, 1fr); gap: var(--s-4); align-items: start; }
.im-rack-face .meta { margin: 0 0 var(--s-1); }
.im-rack-units { display: flex; flex-direction: column; gap: 2px; padding: 6px; border-radius: var(--radius); background: #1f2a37; max-height: 56dvh; overflow: auto; }
.im-rack-unit { display: flex; align-items: center; gap: var(--s-2); min-height: 20px; padding: 1px 8px 1px 4px; border: 1px dashed #435468; border-radius: 3px; background: #2b3a4a; color: #dbe4ee; font: inherit; font-size: 11px; text-align: left; cursor: pointer; }
.im-rack-unit .mono { width: 28px; flex: none; text-align: right; color: #8fa1b6; }
.im-rack-unit > span:last-child { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.im-rack-unit.is-taken { border-style: solid; border-color: #3a4a5c; background: #3a4a5c; cursor: not-allowed; }
.im-rack-unit.im-rack-block { --unit-h: 20px; min-height: calc(var(--units) * var(--unit-h) + (var(--units) - 1) * 2px); align-items: flex-start; padding-top: 3px; }
.im-rack-block em { font-style: normal; color: #a9b8c9; }
@media (max-width: 600px) { .im-rack-unit.im-rack-block { --unit-h: 28px; } }
.im-rack-unit.is-picked { border: 1px solid #f5b940; background: #f5b940; color: #18212c; font-weight: 600; }
.im-rack-unit.is-picked .mono { color: #18212c; }
.im-rack-unit.is-conflict { border: 1px solid #c2412d; background: #c2412d; color: #fff; }
.im-rack-unit:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.im-rack-pick-summary { display: grid; gap: var(--s-1); padding: var(--s-3); border: 1px solid var(--divider); border-radius: var(--radius); }
.im-rack-pick-summary > span { font-size: var(--fs-caption); color: var(--text-secondary); }
.im-rack-pick-summary b { font-size: 18px; overflow-wrap: anywhere; }
.im-rack-pick-summary p { margin: 0; font-size: var(--fs-caption); font-weight: 600; }
.im-rack-pick-summary .is-ok { color: var(--success, #15803d); }
.im-rack-pick-summary .is-danger { color: var(--danger, #b42318); }
@media (max-width: 600px) {
  .im-rack-picker-fields, .im-rack-picker-main { grid-template-columns: minmax(0, 1fr); }
  .im-rack-unit { min-height: 28px; }
}
.im-rack-picker .modal-foot .form-actions { border-top: 0; padding-top: 0; margin: 0; }
/* 패치패널 앞면: 모듈마다 줄을 나누고, 커넥터는 모양으로도 구분한다(LC 두 칸, SC 큰 사각, MPO 넓은 칸, RJ45 단자). */
.pp-face { display: grid; gap: var(--s-3); padding: var(--s-3); border-radius: var(--radius); background: #222a35; }
.pp-module > .meta { margin: 0 0 var(--s-1); color: #c3ccd8; }
.pp-ports { display: grid; grid-template-columns: repeat(auto-fill, minmax(36px, 1fr)); gap: 6px; }
.pp-port { position: relative; min-height: 40px; border: 1px solid #46505e; border-radius: 4px; background: #2c3542; color: #aeb8c5; font: inherit; font-size: 11px; cursor: pointer; display: flex; align-items: flex-end; justify-content: center; padding: 2px; }
.pp-port::before { content: ''; position: absolute; top: 6px; left: 50%; transform: translateX(-50%); border: 1px solid currentColor; opacity: .8; }
.pp-lc::before { width: 16px; height: 8px; border-radius: 2px; box-shadow: inset 7px 0 0 -6px currentColor; }
.pp-sc::before { width: 14px; height: 14px; border-radius: 2px; top: 4px; }
.pp-mpo::before { width: 20px; height: 6px; border-radius: 1px; }
.pp-rj45::before { width: 14px; height: 11px; border-radius: 1px 1px 4px 4px; }
.pp-port.is-used { background: #1f5fd1; border-color: #1f5fd1; color: #fff; }
.pp-port.is-through { background: #174aa6; border-color: #9cc0ff; color: #fff; }
.pp-port[aria-pressed='true'] { outline: 3px solid #f5b940; outline-offset: 1px; }
.pp-port:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pp-legend { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-2); font-size: var(--fs-caption); color: var(--text-secondary); }
.pp-legend span { display: inline-flex; align-items: center; gap: 6px; }
.pp-key { width: 14px; height: 14px; border-radius: 3px; background: #2c3542; border: 1px solid #46505e; }
.pp-key.is-used { background: #1f5fd1; border-color: #1f5fd1; }
.pp-key.is-through { background: #174aa6; border-color: #9cc0ff; }
.pp-picked { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); margin: var(--s-3) 0 0; }
.pp-picked dt { font-size: var(--fs-caption); color: var(--text-secondary); }
.pp-picked dd { margin: 0; overflow-wrap: anywhere; }
.pp-editor .pp-template, .pp-edit-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-2); align-items: end; }
.pp-edit-row { grid-template-columns: 24px repeat(3, minmax(0, 1fr)) auto; }
.pp-edit-row > .mono { align-self: center; font-weight: 600; }
.pp-editor > .button { justify-self: start; }
@media (max-width: 600px) {
  .pp-picked, .pp-edit-row { grid-template-columns: minmax(0, 1fr); }
  .pp-edit-row > .mono { align-self: start; }
}
.pp-suggestion { display: block; }
.pp-suggestion p { margin: 0 0 var(--s-1); }
.pp-suggestion ul { margin: 0; padding-left: 1.2em; display: grid; gap: 2px; }
/* 회선 경로: 패널 위치마다 한 칸, 사이에 케이블 글자, 끝은 장비 포트·모듈. 끊긴 곳은 글자로 말한다. */
.cp-leg + .cp-leg { margin-top: var(--s-3); }
.cp-leg > .meta { margin: 0 0 var(--s-1); }
.cp-path { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.cp-hop { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.cp-node { display: grid; gap: 2px; padding: var(--s-2) var(--s-3); border: 1px solid var(--divider); border-radius: var(--radius); background: var(--surface); overflow-wrap: anywhere; }
.cp-end .cp-node { border-color: var(--accent); }
.cp-cable { position: relative; padding: 0 var(--s-2); font-size: var(--fs-caption); color: var(--text-secondary); border-top: 3px solid #e0a12e; padding-top: 2px; }
.cp-broken { padding: var(--s-2) var(--s-3); border-radius: var(--radius); background: var(--danger-soft, #fde4e4); color: var(--danger, #9b1c1c); font-weight: 600; }
.pp-port.has-circuit::after { content: ''; position: absolute; top: 3px; right: 3px; width: 6px; height: 6px; border-radius: 50%; background: #f5b940; }
.pp-land dd { display: grid; gap: var(--s-2); }
/* 회선 케이지 뷰: 도면 좌표(mm) 위에 그린다. 선택 회선은 흐르는 파란 선, 지나는 랙은 노란 테두리. */
@keyframes cc-flow { to { stroke-dashoffset: -600; } }
@keyframes cc-pulse { 0%, 100% { stroke-opacity: 1; } 50% { stroke-opacity: .35; } }
.cc-glow { fill: none; stroke: #1f5fd1; stroke-opacity: .18; stroke-width: 260; stroke-linejoin: round; }
.cc-path { fill: none; stroke: #1f5fd1; stroke-width: 70; stroke-linejoin: round; stroke-dasharray: 260 180; animation: cc-flow 1.2s linear infinite; }
.cc-dot { fill: #f5b940; stroke: #fff; stroke-width: 20; }
.cc-rack { fill: none; stroke: #f5b940; stroke-width: 60; animation: cc-pulse 1.5s ease-in-out infinite; }
.cc-rack.is-device { stroke: #1f5fd1; }
.cc-label { font: 600 220px var(--mono); fill: var(--text); paint-order: stroke; stroke: var(--surface); stroke-width: 40; }
.cc-side { display: grid; gap: var(--s-2); margin-top: var(--s-3); }
.cc-side h3 { margin: 0; font-size: var(--fs-body); }
.cc-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-1); max-height: 260px; overflow: auto; }
.cc-item { width: 100%; display: grid; gap: 2px; text-align: left; padding: var(--s-2); border: 1px solid var(--divider); border-radius: var(--radius); background: var(--surface); color: var(--text); font: inherit; cursor: pointer; }
.cc-item[aria-pressed='true'] { border-color: var(--accent); box-shadow: inset 4px 0 0 var(--accent); }
.cc-item .meta { overflow-wrap: anywhere; }
.cc-detail { display: grid; gap: var(--s-2); padding-top: var(--s-2); border-top: 1px solid var(--divider); }
.cc-detail h3 { margin: 0; font-size: var(--fs-body); }
@media (prefers-reduced-motion: reduce) { .cc-path, .cc-rack { animation: none; } .cc-dot { display: none; } }
.im-cable { border: 0; padding: 0; margin: 0; min-width: 0; display: grid; gap: var(--s-2); }
.im-cable legend { padding: 0; font-size: var(--fs-caption); font-weight: 600; color: var(--text-secondary); }
.im-cable .meta { margin: 0; overflow-wrap: anywhere; }
.im-cable .is-danger { color: var(--danger, #b42318); font-weight: 600; }
.inventory-adopt .panel-head { flex-wrap: wrap; gap: var(--s-2); }
.inventory-adopt .adopt-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.inventory-adopt td .meta { overflow-wrap: anywhere; }
.inventory-adopt .badge.is-ok { background: var(--success-soft, #e3f1ea); color: var(--success, #15803d); }
.inventory-adopt .badge.is-danger { background: var(--danger-soft, #fde4e4); color: var(--danger, #b42318); }
.inventory-adopt .panel-body > .meta, .inventory-adopt .panel-body > [role] { margin: 0; padding: var(--s-3) var(--s-4); }
.inventory-adopt .button[aria-pressed='true'] { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-border); }
.inventory-adopt .adopt-search { display: flex; flex-wrap: wrap; align-items: end; gap: var(--s-2); padding: var(--s-3) var(--s-4) 0; }
.inventory-adopt .adopt-search label { flex-basis: 100%; }
.inventory-adopt .adopt-search input { flex: 1 1 240px; min-width: 0; }
.pp-editor .pp-template { grid-template-columns: minmax(0, 1fr) auto auto; }
@media (max-width: 600px) { .pp-editor .pp-template { grid-template-columns: minmax(0, 1fr); } }
/* 패치패널 앞면(panel-face.js): 19인치 × U 실제 비율. 크기는 모두 % 로 두어 폭이 바뀌어도 모양이 같다. */
.pf-face { position: relative; width: 100%; container-type: inline-size; background: linear-gradient(#2f3743, #262d37); border-radius: 3px; box-shadow: 0 1px 0 #3d4654 inset, 0 2px 6px rgba(15, 23, 42, .25); }
.pf-ear { position: absolute; top: 0; bottom: 0; width: 3.3%; background: #2b323d; }
.pf-screw { position: absolute; border-radius: 999px; background: #0f1319; }
.pf-pair { position: absolute; border-radius: 3px; background: rgba(37, 99, 201, .22); box-shadow: 0 0 0 1px rgba(147, 180, 240, .55); }
.pf-num { position: absolute; transform: translate(-50%, -100%); font: 600 min(13px, var(--pf-num, 1.45cqw)) var(--mono); color: #c9d2dd; line-height: 1; pointer-events: none; }
.pf-num.is-below { transform: translateX(-50%); }
.pf-port { position: absolute; padding: 0; border: 0; border-radius: 1.5px; cursor: pointer; }
span.pf-port { cursor: default; }
.pf-port > span { position: absolute; background: #11151c; }
.pf-empty { background: #161b22; box-shadow: inset 0 1px 2px rgba(0, 0, 0, .6), 0 0 0 1px #3c4553; }
.pf-empty > span { display: none; }
.pf-sc, .pf-scpair { background: #2563c9; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2); }
.pf-sc > span, .pf-scpair > span { inset: 27%; border-radius: 1px; }
.pf-lc, .pf-lcquad { background: #7a5cd6; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2); }
.pf-lcquad { background: #5b3fb8; }
.pf-lc > span, .pf-lcquad > span { left: 16%; right: 16%; top: 30%; bottom: 30%; background: linear-gradient(90deg, #11151c 0 44%, transparent 44% 56%, #11151c 56%); }
.pf-rj45 { background: #9a6a17; border-radius: 1px 1px 3px 3px; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2); }
.pf-rj45 > span { left: 18%; right: 18%; top: 22%; bottom: 14%; border-radius: 1px 1px 2px 2px; }
.pf-mpo { background: #0f766e; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2); }
.pf-mpo > span { left: 12%; right: 12%; top: 38%; bottom: 38%; }
.pf-port.is-picked { outline: 2px solid #f5b940; outline-offset: 2px; }
.pf-port.has-circuit::after { content: ''; position: absolute; top: -18%; right: -18%; width: 34%; height: 34%; border-radius: 50%; background: #f5b940; }
.pf-port:focus-visible { outline: 2px solid #f5b940; outline-offset: 2px; }
.pf-legend { display: flex; flex-wrap: wrap; gap: var(--s-3); font-size: var(--fs-caption); color: var(--text-secondary); }
.pf-legend span { display: inline-flex; align-items: center; gap: 6px; }
.pf-legend i { width: 12px; height: 12px; border-radius: 2px; display: inline-block; }
.pp-editbar, .pp-mounts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-bottom: var(--s-3); }
.pp-editbar select { min-width: 220px; }
.pp-controls { border: 0; padding: 0; margin: 0; min-width: 0; }
.adopt-comparison { max-width: min(60ch, 100%); }
.adopt-comparison pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 16rem; overflow: auto; }
.inventory-followups { padding: var(--s-3); }
.inventory-followups > div { max-height: 30vh; overflow: auto; }
.inventory-followup p { overflow-wrap: anywhere; }
.task-content-selected-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.task-content-selected-tools[hidden] { display: none; }
@media (max-width:900px) {
  .task-content-selected-tools .button { min-height:44px; }
}
.task-inline-media.is-selected, .task-inline-media:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pp-position { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-top: var(--s-3); }
.pp-position select { min-height: var(--control-height, 36px); min-width: 120px; }
.pp-mount i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; margin-right: 6px; }
.pf-legend { margin-top: var(--s-2); }
.pf-legend-empty { background: #161b22; box-shadow: 0 0 0 1px #3c4553; }
.pp-land dd { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.panel-templates .ptpl-body { display: grid; grid-template-columns: minmax(200px, 260px) minmax(0, 1fr); gap: var(--s-4); padding: var(--s-4); }
.ptpl-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-1); align-content: start; }
.ptpl-item { width: 100%; display: grid; gap: 2px; text-align: left; padding: var(--s-2) var(--s-3); border: 1px solid var(--divider); border-radius: var(--radius); background: var(--surface); color: var(--text); font: inherit; cursor: pointer; }
.ptpl-item:disabled { opacity: 0.5; cursor: not-allowed; }
.ptpl-item[aria-pressed='true'] { border-color: var(--accent); background: var(--accent-soft); }
.ptpl-frame { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s-4); }
.ptpl-choice { display: flex; gap: 4px; }
.ptpl-choice .button[aria-pressed='true'] { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-border); }
.ptpl-total { padding-bottom: 6px; }
@media (max-width: 760px) { .panel-templates .ptpl-body { grid-template-columns: minmax(0, 1fr); } }
/* 좁은 화면에서도 비율은 그대로: 포트를 누를 수 있는 크기 아래로는 줄이지 않고 가로로 민다. */
.pf-scroll { overflow-x: auto; padding: 4px 2px; }
.pf-scroll .pf-face { min-width: 680px; }
.inventory-adopt .adopt-tabs { display: flex; gap: var(--s-1); padding: var(--s-2) var(--s-4) 0; }
.inventory-adopt .adopt-tabs .button[aria-selected='true'] { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-border); }

/* 다시 그려진 같은 창은 여는 동작을 되풀이하지 않는다(app.js 의 is-reopened). */
.modal-backdrop.is-reopened,
.modal-backdrop.is-reopened .modal,
[data-motion-panel].is-reopened {
  animation: none;
}

/* 등록 서랍 정리(2026-10-14). 고르는 단추는 한 모양만 쓴다 — 부품 종류(디스크/CPU)에 쓰던 작은 묶음 단추.
   장비/부품/기타와 상태(사용 중/재고/장애)가 서랍 폭을 꽉 채운 큰 회색 칸이라 값인지 이동인지 구분이 안 됐고,
   세 글자짜리 선택이 한 줄을 통째로 차지했다. */
.inventory-sheet .inventory-registration-groups,
.inventory-sheet .inventory-kind-options {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  width: auto;
  max-width: 100%;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.inventory-sheet .inventory-registration-groups {
  align-self: flex-start;
  margin: var(--s-3) var(--s-4) 0;
}
.inventory-sheet .inventory-registration-groups .button,
.inventory-sheet .inventory-kind-options .button {
  flex: none;
  min-height: 30px;
  padding: var(--s-1) var(--s-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  box-shadow: none;
  color: var(--text-secondary);
  font-size: var(--fs-caption);
  font-weight: 500;
}
.inventory-sheet .inventory-registration-groups .button:hover,
.inventory-sheet .inventory-kind-options .button:hover {
  background: var(--surface-2);
  color: var(--text);
}
.inventory-sheet .inventory-registration-groups .button[aria-selected='true'],
.inventory-sheet .inventory-kind-options .button[aria-pressed='true'] {
  background: var(--accent-soft);
  color: var(--accent-text, var(--accent));
  border: 0;
  box-shadow: none;
  font-weight: 600;
}
.inventory-sheet .field.inventory-kind-field {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.inventory-sheet .inventory-kind-field > legend {
  padding: 0;
  margin-bottom: var(--s-1);
}
/* 부품 서랍도 장비 서랍과 같은 틀: 바깥 테두리·회색 바탕·안쪽 여백이 겹쳐 제목과 닫기 위치가 달랐다. */
.inventory-sheet.parts-editor {
  display: flex;
  gap: 0;
  padding: 0;
  border: 1px solid var(--border);
  background: var(--surface);
}
.inventory-sheet.parts-editor .inventory-intake-fields {
  display: grid;
  gap: var(--s-3);
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.inventory-sheet.parts-editor .parts-editor-head { justify-content: flex-start; }
/* 아래 단추 줄 위 선이 두 번(바닥 줄 + 단추 묶음) 그어졌다. */
.inventory-sheet .modal-foot .form-actions {
  border-top: 0;
  padding-top: 0;
}
@media (max-width: 900px) {
  .inventory-sheet .inventory-registration-groups .button,
  .inventory-sheet .inventory-kind-options .button {
    min-height: 44px;
    padding-inline: var(--s-4);
  }
}
.inventory-sheet .inventory-kind-options { width: fit-content; }
/* 위치·고객 후보: 회색 단추가 줄줄이 쌓여 고를 수 없는 줄도 같아 보였다. 목록 한 줄로 그리고,
   고를 수 없는 줄은 흐리게 둔다. */
.inventory-sheet .inventory-tax-options {
  gap: 0;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.inventory-sheet .inventory-tax-options .button {
  min-height: 34px;
  padding: var(--s-1) var(--s-2);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  box-shadow: none;
  font-weight: 400;
}
.inventory-sheet .inventory-tax-options .button:hover:not(:disabled) { background: var(--surface-2); }
.inventory-sheet .inventory-tax-options .button:disabled { opacity: 0.5; cursor: not-allowed; }
.inventory-sheet .inventory-tax-options [aria-selected='true'] { background: var(--accent-soft); color: var(--accent-text, var(--accent)); }
.inventory-sheet .inventory-tax-options:not(:has(*)) { display: none; }
.domain-pending-notice { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding: var(--s-3) var(--s-4); }

/* 케이지 입체 보기(cage-layout.js isoSvg, 2026-10-15). 평면과 같은 상태 색·글자를 쓰고, 옆면 두 장만
   명암을 달리해 높이를 보인다. 윗면은 평면의 랙 본체와 같은 클래스라 상태·사용률 색이 그대로 붙는다. */
.cage-iso .cage-iso-side { fill: var(--n-200); stroke: var(--n-400); stroke-width: 1; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.cage-iso .cage-iso-side.is-right { fill: var(--n-300); }
.cage-iso .cage-obj-rack .cage-rack-body { stroke-linejoin: round; }
.cage-iso .cage-rack-gauge { fill: var(--accent); opacity: 0.55; }
.cage-iso .cage-obj-rack.is-critical .cage-iso-side,
.cage-iso .cage-obj-rack.has-incident .cage-iso-side { stroke: var(--danger); }
.cage-iso .cage-iso-rack.is-picked .cage-rack-body,
.cage-iso .cage-iso-rack.is-picked .cage-iso-side,
.cage-iso .cage-iso-flat.is-picked polygon,
.cage-iso .cage-iso-solid.is-picked .cage-iso-top { stroke: var(--accent); stroke-width: 2; vector-effect: non-scaling-stroke; }
.cage-iso .cage-obj-aisle polygon { fill: var(--bg-sunken); stroke: var(--border); stroke-width: 10; stroke-dasharray: 80 60; }
.cage-iso .cage-obj-door polygon { fill: var(--surface); stroke: var(--text-muted); stroke-width: 14; }
.cage-iso .cage-obj-text polygon { fill: transparent; }
.cage-iso .cage-obj-wall .cage-iso-top { fill: var(--n-600); }
.cage-iso .cage-obj-wall .cage-iso-side { fill: var(--n-500); }
.cage-iso .cage-obj-facility .cage-iso-top { fill: var(--bg-sunken); stroke: var(--border-strong); stroke-width: 1; vector-effect: non-scaling-stroke; }
.cage-iso .cage-iso-tray polygon { fill: none; stroke: var(--n-400); stroke-width: 24; stroke-dasharray: 100 60; }
.cage-iso .cage-obj-rack:hover .cage-rack-body { stroke: var(--text); }
/* 회선을 고르면 그 회선이 지나지 않는 랙은 물러난다(평면·입체 공통). 지우지 않는 이유: 어디쯤인지는 남아야 한다. */
.cage-svg .cage-obj-rack.is-off-path { opacity: 0.32; }
@media (prefers-reduced-motion: no-preference) { .cage-svg .cage-obj-rack { transition: opacity 160ms ease; } }

/* 회선 경로를 노선도처럼: 위에서 아래로 한 줄, 정거장(패널·장비)마다 점, 그 사이에 케이블. 끊긴 곳은 점선. */
.cc-side .cp-path { display: grid; gap: 0; padding-left: 22px; }
.cc-side .cp-hop { position: relative; display: grid; gap: 0; align-items: start; }
.cc-side .cp-hop::before { content: ''; position: absolute; left: -14px; top: 0; bottom: 0; width: 2px; background: var(--accent); }
.cc-side .cp-hop:first-child::before { top: 14px; }
.cc-side .cp-end::before { bottom: calc(100% - 14px); }
.cc-side .cp-broken::before { background: repeating-linear-gradient(var(--danger) 0 5px, transparent 5px 10px); bottom: calc(100% - 14px); }
.cc-side .cp-node { position: relative; padding: 4px 0 2px; border: 0; border-radius: 0; background: none; }
.cc-side .cp-node::before { content: ''; position: absolute; left: -20px; top: 7px; width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--accent); background: var(--surface); }
.cc-side .cp-end .cp-node::before { background: var(--accent); }
.cc-side .cp-cable { border-top: 0; padding: 2px 0 10px; font-family: var(--mono); font-size: var(--fs-caption); color: var(--text-secondary); }
.cc-side .cp-broken { position: relative; margin-top: 2px; }

/* 케이지 «연결» 층 옆 칸(circuit-cage-ui.js, 사용자 시안 «케이지 전체 연결 · 다발과 정렬» 2026-10-16).
   묶음은 접어 두고 하나만 펼친다. 펼친 묶음은 한 줄에 연결 하나(상태 점 · 양끝 · 대역폭). */
.cn-side { gap: var(--s-2); }
.cn-side > h3 { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s-2); }
.cn-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cn-chip { display: inline-flex; align-items: center; gap: 6px; min-height: 30px; padding: 2px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--surface); color: var(--text-secondary); font: inherit; font-size: var(--fs-caption); cursor: pointer; }
.cn-chip[aria-pressed='true'] { background: var(--text); border-color: var(--text); color: var(--surface); }
.cn-chip i { width: 8px; height: 8px; border-radius: 50%; background: var(--n-400); }
.cn-chip.is-transit i { background: #e0a12e; }
.cn-chip.is-inter i { background: var(--accent); }
.cn-chip.is-intra i { background: #8b6cd9; }
.cn-controls { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.cn-sort.field { flex-direction: row; align-items: center; gap: var(--s-1); min-width: 0; margin: 0; }
.cn-sort > label { color: var(--text-secondary); white-space: nowrap; }
.cn-sort .select { width: 132px; max-width: 100%; min-width: 0; min-height: 30px; font-size: var(--fs-callout); }
.cn-seg { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 2px; justify-self: start; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.cn-seg button { min-height: 28px; padding: 2px 10px; border: 0; border-radius: var(--radius-sm); background: none; color: var(--text-secondary); font: inherit; font-size: var(--fs-caption); cursor: pointer; }
.cn-seg button[aria-pressed='true'] { background: var(--accent-soft); color: var(--accent-text, var(--accent)); font-weight: 600; }
.cn-groups, .cn-rows { list-style: none; margin: 0; padding: 0; }
.cn-groups { border: 0; border-radius: 0; max-height: 460px; overflow-y: auto; }
.cn-group + .cn-group { border-top: 1px solid var(--divider); }
.cn-group-head { width: 100%; display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 0 10px; border: 0; background: var(--surface); color: var(--text); font: inherit; font-weight: 600; font-size: var(--fs-caption); text-align: left; cursor: pointer; position: sticky; top: 0; z-index: 1; }
.cn-group-head[aria-expanded='true'] { background: var(--surface-2); }
.cn-chevron { width: 10px; color: var(--text-muted); }
.cn-group-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cn-group-count { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.cn-flag { flex: none; padding: 0 6px; border-radius: 999px; background: var(--danger-soft); color: var(--danger); font-size: 11px; font-weight: 600; }
.cn-row { width: 100%; display: flex; align-items: center; gap: 8px; min-height: 32px; padding: 0 10px 0 26px; border: 0; background: var(--surface); color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.cn-row:hover { background: var(--surface-2); }
.cn-row[aria-pressed='true'] { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
.cc-item.cn-row { display: flex; border: 0; border-radius: 0; padding: 0 10px 0 26px; }
.cn-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--ok); }
.cn-dot.is-flag { background: var(--danger); }
.cn-ends { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--mono); font-size: var(--fs-caption); }
.cn-arrow { color: var(--text-muted); }
.cn-speed { flex: none; font-family: var(--mono); font-size: 11px; color: var(--text-secondary); }
.cn-more { margin: 4px 10px 8px; }
.cn-detail .cn-end { display: grid; gap: 2px; padding: var(--s-2) var(--s-3); border: 1px solid var(--divider); border-radius: var(--radius); }
.cn-detail .cn-end b { font-family: var(--mono); overflow-wrap: anywhere; }
.cn-port { color: var(--warn); }
.cn-cable { justify-self: center; padding: 2px 10px; border-radius: 999px; background: var(--surface-2); font-size: var(--fs-caption); color: var(--text-secondary); }
.cage-link.cn-bundle.is-chosen { stroke-opacity: 0.85; }
.cn-chip.is-server i { background: var(--n-500); }

/* 데이터센터 회선 층: 연결 목록 · 도면/상세, 랙 선택 시 오른쪽 입면을 추가한다. */
.datacenter-page .cage-workspace { margin-top: 0; }
.dc-main { display: grid; grid-template-columns: minmax(300px, 360px) minmax(0, 1fr); gap: var(--s-3); align-items: start; }
.dc-list { min-width: 0; }
.dc-list .cn-side { margin-top: 0; padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.dc-list .cn-groups { max-height: min(62vh, 640px); }
.dc-center { display: grid; gap: var(--s-3); min-width: 0; }
.datacenter-page .dc-main { grid-template-columns: minmax(240px, 280px) minmax(0, 1fr); }
.datacenter-page .dc-main.has-rack-inspector { grid-template-columns: 240px minmax(0, 1fr) 280px; }
.datacenter-page .cn-tabs { flex-basis: 104px; }
.datacenter-page .cn-sort .select { width: 104px; }
.dc-inspector.cage-panel { min-width: 0; padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.dc-main.has-rack-inspector .dc-detail { grid-template-columns: minmax(0, 1fr); }
.cr-inspector { display: grid; gap: var(--s-2); min-width: 0; font-size: var(--fs-caption); }
.cr-header { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.cr-header h3 { flex: 1; min-width: 0; margin: 0; overflow-wrap: anywhere; font-size: var(--fs-body); }
.cr-inspector .meta { margin: 0; font-size: var(--fs-caption); }
.cr-link { padding: 0; border: 0; background: none; color: var(--accent-text); font: inherit; cursor: pointer; text-align: start; }
.cr-link:hover { text-decoration: underline; }
.cr-elevation-scroll { max-height: min(360px, 48dvh); overflow: auto; padding: var(--s-1); scrollbar-gutter: stable; }
.cr-elevation { --cr-pitch: max(22px, 1.17em); position: relative; display: grid; width: min(100%, 250px); margin-inline: auto; grid-template-columns: 26px 10px repeat(6, minmax(0, 1fr)) 10px; grid-template-rows: repeat(var(--cr-height), var(--cr-pitch)); padding-block: var(--s-1); isolation: isolate; }
.cr-elevation::before { content: ''; position: absolute; inset: 0 0 0 26px; border: var(--s-1) solid var(--n-700); z-index: -1; pointer-events: none; }
.cr-unit { grid-column: 1; display: flex; align-items: center; justify-content: flex-end; padding-right: var(--s-1); color: var(--text-secondary); font-size: var(--fs-micro); font-variant-numeric: tabular-nums; line-height: 1; }
.cr-rail { display: grid; place-items: center; background: var(--n-700); }
.cr-rail::after { content: ''; width: 3px; height: 3px; background: var(--n-200); }
.cr-slot, .cr-device { min-width: 0; min-height: 0; border: 0; border-radius: 0; box-shadow: inset 0 0 0 1px var(--divider); }
.cr-slot.is-free, .cr-slot.cr-bay-row { background: var(--surface); }
.cr-slot:not(.is-free) { overflow: hidden; font-size: var(--fs-caption); color: var(--text-secondary); white-space: nowrap; text-overflow: ellipsis; }
.cr-slot.is-unavailable, .cr-slot.is-absent, .cr-slot.is-unknown { background: var(--surface-2); z-index: 1; }
.cr-device { position: relative; z-index: 1; height: 100%; display: flex; align-items: center; padding: 0 var(--s-2); background: var(--bg-sunken); color: var(--text); text-align: start; font: inherit; font-size: var(--fs-caption); line-height: 1; font-weight: 600; cursor: pointer; scroll-margin-block: 80px; }
.cr-device > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr-device:hover { box-shadow: inset 0 0 0 1px var(--text-secondary); }
.cr-device.is-selected { background: var(--accent-soft); box-shadow: inset 0 0 0 2px var(--accent); color: var(--accent-text); }
.cr-device:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.cr-summary { border-top: 1px solid var(--divider); padding-top: var(--s-3); min-width: 0; }
.cr-device-heading { display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap; }
.cr-device-heading h4 { flex: 1; min-width: 0; margin: 0; font-size: var(--fs-caption); overflow-wrap: anywhere; }
.cr-summary dl { margin: var(--s-2) 0; }
.cr-summary dl > div { display: grid; grid-template-columns: 60px minmax(0, 1fr); gap: var(--s-2); padding: var(--s-1) 0; border-bottom: 1px solid var(--divider); }
.cr-summary dt { color: var(--text-secondary); }
.cr-summary dd { margin: 0; overflow-wrap: anywhere; }
.cr-addresses code { display: block; font-size: inherit; overflow-wrap: anywhere; }
.cr-links { display: flex; justify-content: space-between; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.cr-links a { color: var(--text-secondary); }
.cr-error { color: var(--text-secondary); }
.cr-error p { margin: var(--s-2) 0; }
@media (any-pointer: coarse) {
  .cr-elevation { --cr-pitch: max(44px, 1.17em); }
  .cr-header .button, .cr-header .cr-link, .cr-links > *, .cr-error .button { min-height: 44px; }
  .cr-header .cr-link { display: inline-flex; align-items: center; }
  .cr-links > * { display: inline-flex; align-items: center; }
}
@media (min-width: 1600px) {
  .datacenter-page .dc-main.has-rack-inspector { grid-template-columns: 280px minmax(0, 1fr) 280px; }
}
.dc-detail { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 300px); gap: var(--s-3); align-items: start; }
.dc-detail .cage-panel { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--s-3); background: var(--surface); }
.cn-detail-card { padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); min-width: 0; }
.cn-detail-card .cc-detail { border-top: 0; padding-top: 0; }
.cn-detail-card .cn-detail { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; }
.cn-detail-card .cn-detail > h3, .cn-detail-card .cn-detail > p { grid-column: 1 / -1; }
@media (max-width: 1100px) {
  .dc-main { grid-template-columns: minmax(0, 1fr); }
  .datacenter-page .dc-main, .datacenter-page .dc-main.has-rack-inspector { grid-template-columns: minmax(0, 1fr); }
  /* 좁은 화면: 도면 → 선택 랙 입면(있을 때) → 연결 목록 → 연결 상세. */
  .dc-center { display: contents; }
  .dc-center > .cage-canvas { order: 1; }
  .dc-list { order: 3; }
  .dc-inspector { order: 2; }
  .dc-center > .dc-detail { order: 4; }
  .dc-detail { grid-template-columns: minmax(0, 1fr); }
  .cn-detail-card .cn-detail { grid-template-columns: minmax(0, 1fr); }
}
/* 연결 한 줄 = 두 줄: 위 A쪽(장비 굵게 · 포트 고정폭) + 대역폭, 아래 ↳ B쪽. */
.cn-row { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; grid-template-rows: auto auto; column-gap: 8px; row-gap: 1px; align-items: center; min-height: 44px; padding: 5px 10px 5px 14px; }
.cn-row .cn-dot { grid-row: 1; }
.cn-row .cn-a, .cn-row .cn-b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--ops-record-name-size, 12.5px); }
.cn-row .cn-a { grid-column: 2; }
.cn-row .cn-speed { grid-column: 3; grid-row: 1; }
.cn-row .cn-b { grid-column: 2 / 4; color: var(--text-secondary); }
.cn-row .cn-dev { font-weight: 600; color: var(--text); }
.cn-row .cn-b .cn-dev { font-weight: 500; color: var(--text-secondary); }
.cn-row .cn-port { font-family: var(--mono); font-size: var(--fs-caption); color: var(--warn); }
.cn-row .cn-b .cn-arrow { margin-right: 4px; color: var(--text-muted); }
.cc-item.cn-row { display: grid; padding: 5px 10px 5px 14px; }
/* 도면 위 알약 숫자(다발 가닥 수 · 랙 안 연결 수). 도면 좌표(mm) 기준. */
.cn-pill rect { fill: var(--surface); stroke: var(--accent); stroke-width: 22; }
.cn-pill text { font: 700 150px var(--mono); fill: var(--text); }
.cn-pill.is-inside rect { stroke: #8b6cd9; }
.cn-pill.is-inside text { font: 600 130px var(--sans); fill: #5b3fb8; }
.cn-pill.is-chosen rect { fill: var(--accent); }
.cn-pill.is-chosen text { fill: var(--surface); }
.cage-link.cn-bundle { stroke-linecap: round; }

/* 연결 다발 색 = 대역폭(가장 빠른 가닥). 같은 파랑 하나라 다발끼리 구분이 안 됐다. 색만으로 말하지 않도록
   다발마다 알약 숫자와 title(랙 쌍 · 가닥 수)이 함께 있고, 대역폭 필터는 목록 아래에 둔다. */
.cn-side { --speed-1g: #c27c0e; --speed-10g: var(--accent); --speed-25g: #0e8f86; --speed-40g: #7c4dd8; --speed-unknown: var(--n-500); }
.cage-svg { --speed-1g: #c27c0e; --speed-10g: var(--accent); --speed-25g: #0e8f86; --speed-40g: #7c4dd8; --speed-unknown: var(--n-500); }
.cage-link.cn-bundle { stroke-opacity: 0.6; }
.cage-link.cn-bundle.is-1g { stroke: var(--speed-1g); }
.cage-link.cn-bundle.is-10g { stroke: var(--speed-10g); }
.cage-link.cn-bundle.is-25g { stroke: var(--speed-25g); }
.cage-link.cn-bundle.is-40g { stroke: var(--speed-40g); }
.cage-link.cn-bundle.is-unknown { stroke: var(--speed-unknown); }
.cage-link.cn-bundle.is-dim, .cn-pill.is-dim { opacity: 0.18; }
.cn-pill.is-1g rect { stroke: var(--speed-1g); }
.cn-pill.is-25g rect { stroke: var(--speed-25g); }
.cn-pill.is-40g rect { stroke: var(--speed-40g); }
.cn-pill.is-unknown rect { stroke: var(--speed-unknown); }
.cn-legend { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-2); padding-top: var(--s-1); border-top: 1px solid var(--divider); font-size: var(--fs-caption); color: var(--text-secondary); }
.cn-swatch { display: inline-flex; align-items: center; gap: 5px; }
.cn-swatch i { width: 18px; height: 4px; border-radius: 2px; background: var(--speed-unknown); }
.cn-swatch.is-1g i { background: var(--speed-1g); }
.cn-swatch.is-10g i { background: var(--speed-10g); }
.cn-swatch.is-25g i { background: var(--speed-25g); }
.cn-swatch.is-40g i { background: var(--speed-40g); }
/* 묶기·정렬: 한 줄에 작은 선택 칸 둘. */
/* 종류 칩은 작게, 한 줄에 몰아 둔다(필터이지 주인공이 아니다). */
.cn-side .cn-chips { gap: 4px; }
.cn-side .cn-chip { min-height: 28px; padding: 1px 5px; gap: 4px; font-size: var(--fs-caption); white-space: nowrap; }
@media (max-width: 900px) { .cn-side .cn-chip { min-height: 36px; } }

/* 케이지 보기 도구 줄(cage-layout.js viewToolbar): 묶음 이름표 + 묶음 단추. 단추 높이는 한 줄 30px,
   터치 화면에서도 36px — 44px 회색 단추가 줄지어 서 있던 것이 «너무 후지다» 는 지적의 큰 몫이었다. */
.cage-toolbar.is-view { gap: var(--s-2) var(--s-4); padding: 6px var(--s-3); }
.cage-seg-group { gap: 6px; }
.cage-seg-label { font-size: 11px; font-weight: 600; letter-spacing: 0.02em; color: var(--text-muted); }
.cage-seg { display: inline-flex; align-items: center; gap: 2px; padding: 2px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.cage-toolbar.is-view .cage-seg .button { min-height: 28px; min-width: 0; padding: 2px 10px; border: 0; border-radius: var(--radius-sm); background: none; box-shadow: none; color: var(--text-secondary); font-size: var(--fs-caption); font-weight: 500; }
.cage-toolbar.is-view .cage-seg .button:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
.cage-toolbar.is-view .cage-seg .button.is-on,
.cage-toolbar.is-view .cage-seg .button[aria-pressed='true'] { background: var(--accent-soft); color: var(--accent-text, var(--accent)); font-weight: 600; }
.cage-toolbar.is-view .cage-seg .button:disabled { opacity: 0.45; }
.cage-toolbar.is-view .cage-seg.is-zoom .cage-zoom-label { min-width: 44px; }
@media (any-pointer: coarse), (max-width: 767px) {
  .cage-toolbar.is-view .cage-seg .button { min-height: 36px; min-width: 36px; }
}
/* 케이지 머리: 제목(또는 케이지 고르는 칸) · 찾기 · 단추를 한 줄에. */
.cage-header-title { display: grid; gap: 2px; }
.cage-select.is-title { max-width: 320px; height: 36px; font-size: var(--fs-title, 17px); font-weight: 650; }
.cage-header-tools { flex-wrap: nowrap; }
.cage-header-tools .cage-find { width: 200px; flex: none; }
@media (max-width: 900px) {
  .cage-header-tools { flex-wrap: wrap; }
  .cage-header-tools .cage-find { width: 100%; flex: 1 1 100%; }
}
/* 공용 트레이 띠(circuit-cage-ui.js route): 다발이 지나는 트레이 구간을 옅은 띠로 깔아 «한 묶음» 으로 읽히게 한다.
   묶음째 흐리게 해 띠끼리 겹친 곳이 진해지지 않는다. */
.cn-trays { opacity: 0.35; }
.cn-tray { fill: none; stroke: var(--n-300, #cbd5e1); stroke-width: 200; stroke-linejoin: round; stroke-linecap: round; }
/* 묶음 보기와 정렬은 같은 조작 줄, 대역폭 필터는 목록 아래. 숫자·배지는 기존 밀도를 유지한다. */
.cn-tabs { flex: 1 1 124px; min-width: 0; display: grid; grid-template-columns: 1fr 1fr; padding: 2px; border-radius: var(--radius); background: var(--surface-2); }
.cn-tab { min-height: 30px; border: 0; border-radius: calc(var(--radius) - 2px); background: transparent; color: var(--text-secondary); font: inherit; font-size: var(--fs-callout); font-weight: 600; cursor: pointer; }
.cn-tab[aria-pressed='true'] { background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgb(15 23 42 / 0.12); }
.cn-legend .cn-swatch { min-height: 26px; padding: 0 8px; border: 1px solid transparent; border-radius: 999px; background: transparent; color: var(--text-secondary); font: inherit; font-size: var(--fs-caption); cursor: pointer; }
.cn-legend .cn-swatch:hover { border-color: var(--border); }
.cn-legend .cn-swatch[aria-pressed='false'] { color: var(--text-muted); text-decoration: line-through; }
.cn-legend .cn-swatch[aria-pressed='false'] i { opacity: 0.25; }
.cn-role { flex: none; min-width: 30px; padding: 1px 5px; border-radius: 4px; background: var(--surface-2); color: var(--text-secondary); font: 700 10.5px var(--mono); text-align: center; }
.cn-speed-dot { flex: none; width: 14px; height: 4px; border-radius: 2px; background: var(--speed-unknown); }
.cn-speed-dot.is-1g { background: var(--speed-1g); }
.cn-speed-dot.is-10g { background: var(--speed-10g); }
.cn-speed-dot.is-25g { background: var(--speed-25g); }
.cn-speed-dot.is-40g { background: var(--speed-40g); }
.cn-group-head .cn-speed { margin-left: auto; }
.cn-group-head .cn-speed + .cn-group-count { margin-left: 8px; }
@media (max-width: 900px) { .cn-tab, .cn-legend .cn-swatch { min-height: 36px; } }
@media (any-pointer: coarse) {
  .cn-side .cn-chip, .cn-tab, .cn-sort .select, .cn-legend .cn-swatch, .cn-group-head { min-height: 44px; }
}

/* Small filters stay dense with a mouse; touch needs a reliable hit area,
   even on a wide touchscreen. The search/period toolbar keeps its shared row. */
@media (any-pointer: coarse) {
  .tasks-page .task-filter-chip,
  .tasks-page .task-filter-pop-wrap > .button,
  .tasks-page .record-filter-options > .button,
  .personal-view-toolbar > .button,
  .tasks-page .personal-view-toolbar > .button,
  .personal-view-toolbar > .select,
  .topbar .global-search-trigger {
    min-width: 44px;
    min-height: 44px;
  }
}

/* Settings actions wrap within their own panel instead of being clipped when
   labels, translations or user-selected text sizes grow. */
.settings-page .panel-head { flex-wrap: wrap; gap: var(--s-2); }
.settings-page .panel-head > div { min-width: 0; overflow-wrap: anywhere; }
.settings-shift-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.settings-shift-actions .button { max-width: 100%; white-space: normal; height: auto; }
.settings-page .settings-row { flex-wrap: wrap; }
.settings-page .settings-row > div:first-child { min-width: 0; overflow-wrap: anywhere; }
.settings-page .settings-row > .button { flex-shrink: 0; }
.settings-page .workforce-planner { flex-wrap: wrap; }
.settings-page .workforce-toolbar { min-width: 0; max-width: 100%; }
.settings-page .workforce-toolbar .button { max-width: 100%; white-space: normal; height: auto; }

/* Explain an opening once, not every redraw. Defaults remain visible; no exit
   timer can delay focus, discard, saving or navigation. No retained transform. */
@keyframes ops-drawer-enter {
  from { opacity: .85; transform: translateX(var(--s-2)); }
}
@keyframes ops-feedback-enter {
  from { opacity: 0; }
}
@keyframes ops-feedback-reduced {
  from { opacity: .96; }
}
@media (prefers-reduced-motion: no-preference) {
  .inventory-sheet-backdrop:not(.is-reopened) > .inventory-sheet {
    animation: ops-drawer-enter var(--t);
  }
  .task-filter-pop:not(.is-reopened):not([hidden]) {
    animation: ds-drop var(--t-fast);
  }
  .modal-discard-prompt {
    animation: ops-feedback-enter var(--t-fast);
  }
}
@media (prefers-reduced-motion: reduce) {
  .inventory-sheet-backdrop:not(.is-reopened) > .inventory-sheet,
  .task-filter-pop:not(.is-reopened):not([hidden]),
  .modal-discard-prompt {
    animation: ops-feedback-reduced 80ms ease-out;
    animation-duration: 80ms !important;
  }
}
@media print {
  .inventory-sheet,
  .task-filter-pop,
  .modal-discard-prompt {
    animation: none !important;
  }
}
/* 인벤토리 «RackTables 연동» 펼침(2026-10-20): 방향별 두 묶음, 줄마다 «이름 : 값». 전에는 위 두 줄은 왼쪽,
   아래 네 줄은 오른쪽 정렬 문장이라 따로 놀았다. 할 일이 있는 값(보낼 변경·비교 필요·꺼짐·실패)만 주의 색. */
.inventory-popover.sync-card { width: min(340px, calc(100vw - 32px)); gap: var(--s-3); }
.sync-section { display: grid; gap: 6px; min-width: 0; }
.sync-section + .sync-section { padding-top: var(--s-3); border-top: 1px solid var(--divider); }
.sync-section h4 { margin: 0; font-size: var(--fs-caption); font-weight: 600; color: var(--text-secondary); }
.sync-rows { display: grid; gap: 4px; margin: 0; }
.sync-rows > div { display: grid; grid-template-columns: 7.5em minmax(0, 1fr); gap: var(--s-2); font-size: var(--fs-callout); line-height: 1.45; }
.sync-rows dt { color: var(--text-secondary); }
.sync-rows dd { margin: 0; color: var(--text); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.sync-rows .is-warn dd { color: var(--warn); font-weight: 600; }
.inventory-popover .inventory-sync-status { text-align: start; max-width: none; }
.inventory-preservation > summary.is-attention { color: var(--warn); }
