/* public/css/ui-primitives.css */

/* --------------------------------------------------
 * Shared surfaces
 * -------------------------------------------------- */
.ui-surface-panel{
  background: var(--color-surface-panel);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel);
}

.ui-surface-menu{
  background: var(--color-surface-menu);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-menu);
}

.ui-surface-dialog{
  background: var(--color-surface-dialog);
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-dialog);
}

/* --------------------------------------------------
 * Buttons
 * -------------------------------------------------- */
.ui-btn{
  appearance:none;
  border: 1px solid var(--color-border);
  background: var(--color-surface-elevated);
  color: var(--color-text);
  border-radius: var(--radius-md);
  height: 30px;
  padding: 0 10px;
  font: inherit;
  line-height: 1;
  cursor:pointer;
  transition:
    background 120ms ease,
    border-color 120ms ease,
    color 120ms ease,
    box-shadow 120ms ease;
}

.ui-btn:hover{
  background: var(--color-hover);
  border-color: var(--color-border-strong);
}

.ui-btn:focus-visible{
  outline: none;
  box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.ui-btn:active{
  background: var(--color-active);
}

.ui-btn:disabled,
.ui-btn.is-disabled{
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}

.ui-btn--primary{
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--ui-btn-active-color);
}

.ui-btn--primary:hover{
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
}

.ui-btn--ghost{
  background: transparent;
}

.ui-btn--danger{
  background: var(--color-danger-soft);
  border-color: var(--color-danger-border);
  color: var(--color-danger-text);
}

/* --------------------------------------------------
 * Inputs / selects
 * -------------------------------------------------- */
.ui-input,
.ui-select,
.pm-input{
  width:100%;
  min-width:0;
  height:30px;
  box-sizing:border-box;
  padding:4px 8px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-input-border);
  background: var(--color-input-bg);
  color: var(--color-input-text);
  font-size: var(--font-size-sm);
  outline:none;
}

.ui-input::placeholder{
  color: var(--color-input-placeholder);
}

.ui-input:hover,
.ui-select:hover,
.pm-input:hover{
  background: var(--color-input-bg-hover);
}

.ui-input:focus,
.ui-select:focus,
.pm-input:focus{
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.ui-select{
  appearance:none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--color-text-muted) 50%),
    linear-gradient(135deg, var(--color-text-muted) 50%, transparent 50%);
  background-position:
    calc(100% - 14px) calc(50% - 2px),
    calc(100% - 9px) calc(50% - 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat:no-repeat;
  padding-right: 28px;
}

/* --------------------------------------------------
 * Tabs
 *
 * 탭 계열은 아래 3개가 전부다. 신규 `.xxx-tab` 정의를 만들지 않는다.
 *   - 폴더형   `.ui-tabs-folder` / `.ui-tab-folder` : 창·패널 최상위 탭
 *   - 세그먼트형 `.ui-tabs-seg` / `.ui-tab-seg`     : Project Browser형 pill 탭
 *   - 언더라인형 `.ui-panel-tabs` / `.ui-panel-tab` : 표·트리 헤더 위 서브탭
 * 패널은 hook 클래스(`.mw-tab` 등)를 앞에, 프리미티브를 뒤에 병기하고
 * hook 쪽에는 레이아웃(grid/열수/gap/@media)만 남긴다. 상태 클래스는 `is-active` 단일.
 * 이 파일은 4개 HTML 전부에서 로드되는 유일한 CSS이자 가장 먼저 로드되므로,
 * hook 쪽에 시각 선언이 남아 있으면 아래 프리미티브가 조용히 덮인다.
 *
 * 아래 `.ui-tabs`/`.ui-tab`은 사용처가 없으나 같은 셀렉터 그룹의 `.pm-tab`이
 * pipe 패널에서 살아 있어 분리 없이는 지울 수 없다(후속 slice).
 * -------------------------------------------------- */
.ui-tabs,
.pm-tabs{
  display:flex;
  gap: var(--space-2);
}

.ui-tab,
.pm-tab{
  appearance:none;
  border: 1px solid var(--color-border);
  background: var(--color-surface-elevated);
  color: var(--color-text-muted);
  border-radius: var(--radius-md);
  padding: 6px 10px;
  cursor:pointer;
  font: inherit;
  transition:
    background 120ms ease,
    border-color 120ms ease,
    color 120ms ease;
}

.ui-tab:hover,
.pm-tab:hover{
  background: var(--color-hover);
  color: var(--color-text);
}

.ui-tab.is-active,
.pm-tab.active{
  background: var(--color-accent-soft);
  color: var(--color-text);
  border-color: var(--color-accent);
}

.ui-panel-tabs{
  display:flex;
  gap:2px;
  padding:0 4px;
  border-bottom:1px solid var(--color-divider);
  background: var(--color-surface-3);
  flex-wrap:wrap;
}

.ui-panel-tab{
  appearance:none;
  border:0;
  border-bottom:2px solid transparent;
  margin-bottom:-1px;
  padding:10px 14px;
  background:transparent;
  color: var(--color-text-muted);
  font-size:12px;
  font-weight:700;
  cursor:pointer;
  display:inline-flex;
  align-items:center;
  gap:6px;
}

.ui-panel-tab:hover{
  color: var(--color-text);
}

.ui-panel-tab.is-active{
  border-bottom-color: var(--color-accent-hover);
  color: var(--color-accent-hover);
}

.ui-panel-tab__count{
  padding:1px 6px;
  border-radius:999px;
  background: var(--color-surface-elevated);
  color: var(--color-text-muted);
  font-size:11px;
  font-weight:700;
}

.ui-panel-tab.is-active .ui-panel-tab__count{
  background: var(--color-accent-soft);
  color: var(--color-accent-hover);
}

/* 폴더형 — 창·패널 최상위 탭. 탭바 배경은 소비처가 정한다(패널 본문색과 맞춰야 함). */
.ui-tabs-folder{
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 4px;
  padding: var(--ui-tabs-pad-y, 8px) var(--ui-tabs-pad-x, 8px) 0;
  border-bottom: 1px solid var(--color-divider);
}

/* 탭이 탭바 폭을 균등분할해야 하는 패널용(창 최상위 탭은 내용폭이 기본). */
.ui-tabs-folder--fill > .ui-tab-folder{
  flex: 1 1 0;
}

.ui-tab-folder{
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--color-border);
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  white-space: nowrap;
  cursor: pointer;
}

.ui-tab-folder:hover{
  background: var(--color-hover);
  color: var(--color-text);
}

.ui-tab-folder.is-active{
  background: var(--color-accent-soft);
  border-color: var(--color-active-border);
  color: var(--color-text);
}

/* 세그먼트형 — Project Browser형 pill. 열 수/균등분할은 소비처가 정한다. */
.ui-tabs-seg{
  flex: 0 0 auto;
  display: flex;
  gap: 4px;
  padding: var(--ui-tabs-pad-y, 8px) var(--ui-tabs-pad-x, 8px);
  border-bottom: 1px solid var(--color-divider);
}

.ui-tab-seg{
  height: 28px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: transparent;
  color: var(--color-text);
  font-size: var(--font-size-xs);
  cursor: pointer;
}

.ui-tab-seg:hover{
  background: var(--color-hover);
}

.ui-tab-seg.is-active{
  background: var(--color-accent-soft);
  border-color: var(--color-active-border);
  color: var(--color-text);
}

/* --------------------------------------------------
 * Tree primitives
 * -------------------------------------------------- */
.ui-tree{
  --ui-tree-indent-step: 16px;
  --ui-tree-row-height: 28px;
  --ui-tree-row-gap: 4px;
  --ui-tree-row-margin-inline: 4px;
  --ui-tree-row-padding-inline: 8px;
  --ui-tree-actions-width: auto;
  --ui-tree-row-hover-bg: var(--color-hover);
  --ui-tree-row-selected-bg: var(--color-selected);
  display:flex;
  flex-direction:column;
  gap:2px;
  min-width:0;
}

.ui-tree__branch{
  display:block;
  min-width:0;
}

.ui-tree__children{
  display:grid;
  gap:2px;
}

.ui-tree__branch.is-collapsed > .ui-tree__children{
  display:none;
}

.ui-tree__row{
  position:relative;
  display:flex;
  align-items:center;
  gap:var(--ui-tree-row-gap);
  width:100%;
  min-height:var(--ui-tree-row-height);
  margin:1px var(--ui-tree-row-margin-inline);
  padding-right:4px;
  border-radius: var(--radius-sm);
  transition: background 120ms ease, box-shadow 120ms ease;
}

.ui-tree__main{
  display:flex;
  align-items:center;
  gap:6px;
  flex:1 1 auto;
  min-height:inherit;
  width:100%;
  padding:0 var(--ui-tree-row-padding-inline) 0 calc(var(--ui-tree-row-padding-inline) + (var(--tree-depth, 0) * var(--ui-tree-indent-step)));
  border:0;
  border-radius: inherit;
  background:transparent;
  color: var(--color-text);
  text-align:left;
  cursor:pointer;
}

.ui-tree__row:hover{
  background: var(--ui-tree-row-hover-bg);
}

.ui-tree__row.is-selected{
  background: var(--ui-tree-row-selected-bg);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-accent) 40%, transparent);
}

.ui-tree__twist{
  width:16px;
  height:16px;
  flex:0 0 16px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  border:0;
  padding:0;
  background:transparent;
  color: var(--color-text-muted);
  cursor:pointer;
  transition: transform 120ms ease;
}

.ui-tree__twist.is-open{
  transform: rotate(90deg);
}

.ui-tree__twist.is-leaf{
  visibility:hidden;
}

.ui-tree__icon{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:16px;
  height:16px;
  flex:0 0 16px;
  color: var(--color-accent);
}

.ui-tree__icon.is-secondary{
  color: #059669;
}

.ui-tree__label{
  min-width:0;
  flex:1 1 auto;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
  font-size:13px;
  font-weight:600;
}

.ui-tree__count{
  flex:0 0 auto;
  color: var(--color-text-muted);
  font-size:11px;
  font-variant-numeric: tabular-nums;
}

.ui-tree__row:hover .ui-tree__count,
.ui-tree__row.is-selected .ui-tree__count{
  display:none;
}

.ui-tree__actions{
  display:inline-flex;
  align-items:center;
  gap:2px;
  min-width:var(--ui-tree-actions-width);
  justify-content:flex-end;
  visibility:hidden;
}

.ui-tree__row:hover .ui-tree__actions,
.ui-tree__row.is-selected .ui-tree__actions,
.ui-tree__row:focus-within .ui-tree__actions{
  visibility:visible;
}

/* 터치 입력 대응. **이 규칙은 반드시 이 파일에 있어야 한다** — 소비처 CSS(home 등)에 두면
   같은 특이도인데 `ui-primitives.css` 가 나중에 로드되는 페이지에서 조용히 무효가 된다
   (2026-08-20 에 `#panel-system-manage .pm-body` 가 그렇게 죽어 있었다).
   hover 가 없는 기기에서는 위 세 조건 중 hover 가 영영 성립하지 않아 액션에 닿을 수 없다.

   **조건이 둘인 이유**(쉼표는 OR 다). 어느 하나로도 부족하다.
   · `hover: none` 단독 — 마우스를 주로 쓰는 **터치 노트북**은 `hover: hover` 라 거짓이 되고,
     손가락으로 다가온 사용자는 액션이 계속 숨겨진 채다. 행은 `<div>` 라 포커스도 안 되고
     액션은 `visibility:hidden` 이라 `:focus-within` 도 못 탄다 — 탭→선택 경로에만 매달린다.
   · `any-pointer: coarse` 단독 — 터치스크린이 **없는데** `hover: none` 인 기기가 실재한다
     (이 저장소 개발 PC 가 그렇다: `pointer: fine` + `hover: none` + `any-pointer: coarse` 거짓).
   실패 비용이 비대칭이라 합집합을 택한다 — 못 닿으면 **못 쓰고**, 늘 보이면 조금 시끄러울 뿐이다.
   레일 폭은 이미 예약돼 있어 노출이 켜져도 **레이아웃은 움직이지 않는다.** */
@media (hover: none), (any-pointer: coarse) {
  .ui-tree__actions{
    visibility:visible;
  }
}

/* 히트 영역은 **토큰으로 적는다** — 아래 기본값이 곧 `--hit-target` 이다.
   종전에는 이 위에 `@media (pointer: coarse)` 블록을 두었는데, 같은 특이도인 아래 규칙이
   **뒤에 와서 24px 로 되돌려** 죽은 규칙이었다(PR #174 리뷰). 토큰은 그 겨룸이 없다 —
   값이 바뀌는 것이지 규칙이 다투는 것이 아니다.
   fine 에서는 `--hit-target` 이 24px 이라 **종전과 완전히 같다.**
   노출(`visibility`)은 위의 `hover: none` 축이고 이건 굵기 축이다 — 둘은 별개다. */
.ui-tree__action-btn{
  min-width:var(--hit-target);
  min-height:var(--hit-target);
  padding:0 6px;
  border:0;
  border-radius:6px;
  background:transparent;
  color: var(--color-text-muted);
  cursor:pointer;
}

.ui-tree__action-btn:hover{
  background: var(--color-surface-elevated);
  color: var(--color-text);
}

.ui-tree--grid{
  --ui-tree-col-name: 54%;
  --ui-tree-col-unit: 18%;
  --ui-tree-col-info: 28%;
  --ui-tree-actions-width: 68px;
}

.ui-tree__head{
  display:grid;
  grid-template-columns: 14px minmax(0, 1fr) var(--ui-tree-actions-width);
  gap: var(--ui-tree-row-gap);
  margin: 0 var(--ui-tree-row-margin-inline);
  padding: 8px 0;
  border-bottom: 1px solid var(--color-divider);
  background: var(--color-surface-3);
  color: var(--color-text-muted);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
}

.ui-tree__head-main,
.ui-tree__main--grid{
  display:grid;
  grid-template-columns: minmax(0, var(--ui-tree-col-name)) minmax(90px, var(--ui-tree-col-unit)) minmax(120px, var(--ui-tree-col-info));
  align-items:center;
  gap: 0;
  min-width:0;
}

.ui-tree__head-spacer,
.ui-tree__head-actions{
  display:block;
}

.ui-tree__head-cell{
  position:relative;
  display:flex;
  align-items:center;
  min-height:18px;
  width:100%;
  box-sizing:border-box;
}

.ui-tree__head-cell > span:first-child{
  display:block;
  width:100%;
  padding:0 12px;
  box-sizing:border-box;
}

.ui-tree__head-cell + .ui-tree__head-cell{
  border-left: 1px solid color-mix(in srgb, var(--color-divider) 72%, transparent);
}

.ui-tree__row--grid{
  display:grid;
  grid-template-columns: 14px minmax(0, 1fr) var(--ui-tree-actions-width);
  align-items:center;
}

.ui-tree__main--grid{
  padding: 0;
  gap: 0;
}

.ui-tree__namecell,
.ui-tree__unit,
.ui-tree__info{
  min-width:0;
  padding: var(--space-2) 12px;
}

.ui-tree__namecell{
  display:flex;
  align-items:center;
  gap:8px;
  padding-left: calc(12px + var(--tree-depth, 0) * var(--ui-tree-indent-step));
}

.ui-tree__unit,
.ui-tree__info{
  border-left: 1px solid color-mix(in srgb, var(--color-divider) 72%, transparent);
  color: var(--color-text-muted);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ui-tree__icon-wrap{
  width: 13px;
  height: 13px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  color: var(--color-text-muted);
}

.ui-tree__twist-icon,
.ui-tree__icon-wrap svg{
  width:13px;
  height:13px;
  display:block;
}

.ui-tree__meta{
  display:inline-flex;
  align-items:center;
  gap:8px;
  min-width:0;
}

.ui-tree__main--grid .ui-tree__label{
  font-size: 13px;
  font-weight: 600;
}

@media (max-width: 980px) {
  .ui-tree__head{
    display:none;
  }

  .ui-tree__row--grid{
    grid-template-columns: 14px minmax(0, 1fr);
  }

  .ui-tree__main--grid{
    display:flex;
    align-items:center;
    gap:8px;
    padding: 0 var(--ui-tree-row-padding-inline) 0 calc(var(--ui-tree-row-padding-inline) + (var(--tree-depth, 0) * var(--ui-tree-indent-step)));
  }

  .ui-tree__unit,
  .ui-tree__info,
  .ui-tree__head-actions,
  .ui-tree__head-spacer{
    display:none;
  }
}

/* --------------------------------------------------
 * Shared text helpers
 * -------------------------------------------------- */
.ui-text-muted{ color: var(--color-text-muted); }
.ui-text-dim{ color: var(--color-text-dim); }
.ui-help-text{
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ==================================================
 * Overlay / modal shell
 * ================================================== */
.ui-overlay-backdrop{
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: var(--color-backdrop);
}

/* 이 파일에는 다이얼로그 규칙이 **한 벌만** 있어야 한다. 2026-09-01 이전에는 위쪽에 거의 같은
   블록이 하나 더 있었고(공백만 달랐다), 그 상태에서는 한쪽만 고쳐도 알 수 없었다 —
   실제로 상한을 그 위쪽 블록에 넣었다가 **여기에 `display:` 가 추가되는 순간 죽는 자리**임을
   알고 합쳤다. 규칙을 더할 때 사본을 새로 만들지 말 것. */
.ui-dialog{
  width: min(520px, 95vw);
  background: var(--color-surface-dialog);
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-dialog);
  overflow: hidden;
  font-family: var(--font-ui);

  /* 낮은 화면에서 **footer 버튼에 도달할 수 없던** 문제를 닫는다([OPEN_ISSUES 34]-3).
     종전에는 `max-height` 가 없어 내용이 길면 다이얼로그가 뷰포트를 넘겼고, 백드롭이
     `align-items:center` 라 위아래가 **똑같이** 잘려 확인/취소가 화면 밖으로 나갔다.
     상한은 백드롭의 `padding: 20px`(위아래 합 40) 과 safe-area 를 뺀 만큼이다.
     **넓고 높은 화면에서는 내용이 이 상한에 닿지 않으므로 렌더가 변하지 않는다.**

     `dvh` 를 쓰는 이유: 모바일 브라우저는 주소창이 접히며 뷰포트 높이가 변하는데 `vh` 는 그
     **최대값에 고정**돼 실제보다 큰 값을 준다. `dvh` 를 모르는 브라우저를 위해 `vh` 를 먼저
     적어 폴백으로 둔다(같은 속성은 나중 선언이 이긴다). */
  max-height: calc(100vh - 40px - var(--safe-t) - var(--safe-b));
  max-height: calc(100dvh - 40px - var(--safe-t) - var(--safe-b));

}

/* **상한은 모든 변형에 걸지만, "어디가 스크롤하는가" 는 구조가 정한다.**
   `.ui-dialog` 를 쓰는 변형은 셋이고 마크업이 갈린다:
     · `confirm3.js` — `__header`/`__body`/`__footer` 를 쓴다(구조화)
     · `notice.js`(`.ui-notice`) · `project-browser-project-tab.js`(`.pb-move-confirm`)
       — `__body` 없이 **직접 자식**을 붙인다(비구조)
   비구조 변형에 `display:flex` + `overflow:hidden` 만 걸면 스크롤 소유자가 없어 **내용이 잘리고
   버튼이 상자 밖으로 밀린다** — 상한을 걸기 전보다 나을 것이 없다(PR #181 리뷰). */

/* 구조화: 헤더·footer 는 고정하고 **본문만** 늘고 줄게 한다. 이 선언이 없으면 `max-height` 가
   걸려도 본문이 남은 공간을 차지하지 못해 footer 가 밀려 나간다. */
.ui-dialog:has(.ui-dialog__body){
  display: flex;
  flex-direction: column;
}

/* 비구조: 직접 자식을 스크롤 소유자로 지정할 방법이 없으므로 **창 전체가 스크롤한다.**
   제목·본문·버튼이 함께 굴러가지만 **버튼에 도달할 수 있다** — 이 slice 가 지키려는 것이 그것이다.
   변형이 나중에 `__body` 를 쓰도록 바뀌면 위 규칙으로 자동 승격된다. */
.ui-dialog:not(:has(.ui-dialog__body)){
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* 헤더·footer 는 줄어들지 않는다 — 줄어들면 **닫기·확인 버튼이 먼저 사라진다.** */
.ui-dialog__header,
.ui-dialog__footer{
  flex: 0 0 auto;
}

.ui-dialog__header{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 12px 14px;
  border-bottom: 1px solid var(--color-divider);
  background: var(--color-surface-elevated);
}

.ui-dialog__title{
  font-weight: 800;
  color: var(--color-text);
}

/* **스크롤 소유자는 본문 하나뿐이다.** 중간 컨테이너에 `overflow:auto` 를 겹치면 키보드
   화살표·휠이 먹지 않고 스크롤바 드래그만 되는데, login 반응형에서 실제로 밟은 함정이다
   ([DECISIONS] 2026-07-20 스크롤 소유자 계약). `.ui-dialog` 가 `overflow:hidden` 이고 본문만
   `auto` 라 소유자가 하나다. */
.ui-dialog__body{
  padding: 14px;
  line-height: 1.5;
  color: var(--color-text);

  flex: 1 1 auto;
  min-height: 0;      /* flex 자식 기본값 `min-height:auto` 가 축소를 막아 스크롤이 안 생긴다 */
  overflow-y: auto;
  overscroll-behavior: contain;  /* 본문 끝에서 뒤 페이지로 스크롤이 새지 않게 한다 */
}

.ui-dialog__footer{
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: 12px 14px;
  border-top: 1px solid var(--color-divider);
  background: var(--color-surface-elevated);
}

.ui-dialog__close{
  width: 30px;
  min-width: 30px;
  padding: 0;
  font-size: 18px;
  line-height: 1;
}

/* 단일 확인 알림 모달(notice.js) — .ui-overlay-backdrop/.ui-dialog 재사용, 버튼 1개 */
.ui-notice{
  min-width: 260px;
  max-width: 90vw;
  padding: 18px 20px;
}

.ui-notice__title{
  font-weight: 800;
  font-size: 14px;
  margin-bottom: 10px;
  color: var(--color-text);
}

.ui-notice__msg{
  font-size: 14px;
  margin-bottom: 14px;
}

.ui-notice__actions{
  display: flex;
  justify-content: flex-end;
}

/* ==================================================
 * Card / editor blocks
 * ================================================== */
.ui-card{
  padding: 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface-elevated);
  margin-bottom: 10px;
}

.ui-card__title{
  font-weight: 800;
  margin-bottom: 8px;
  color: var(--color-text);
}

.ui-stack{
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ui-inline{
  display: flex;
  align-items: center;
  gap: 8px;
}

.ui-wrap{
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.ui-grow{
  flex: 1 1 auto;
}

/* ==================================================
 * Generic layout primitives
 * - reusable inside panel bodies and feature sections
 * ================================================== */

.ui-stack{
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}

.ui-row{
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.ui-row-between{
  justify-content: space-between;
}

.ui-controls-row{
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 8px;
  align-items: center;
  min-width: 0;
}

.ui-controls-row > *{
  min-width: 0;
}

.ui-list{
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 2px;
}

.ui-list-item{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--color-border, var(--ui-border));
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface-panel, var(--ui-bg));
}

.ui-list-item.selected,
.ui-list-item.is-selected{
  border-color: var(--color-accent, var(--primary-color));
  box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.ui-list-meta{
  flex: 1 1 auto;
  min-width: 0;
}

.ui-list-meta > *{
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ui-list-actions{
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}

.ui-input-xs{
  width: 56px;
  min-width: 56px;
}

/* ==================================================
 * Property table
 * ================================================== */
.ui-props-table{
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.ui-props-table td{
  vertical-align: top;
  padding: 4px 6px;
  border-bottom: 1px solid var(--color-divider);
  color: var(--color-text);
  word-break: break-word;
}

.ui-props-table__key{
  width: 40%;
  font-weight: 600;
  color: var(--color-text-muted);
}

/* ==================================================
 * Form rows
 * ================================================== */
.ui-field{
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ui-field__label{
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.ui-field__hint{
  font-size: var(--font-size-sm);
  color: var(--color-text-dim);
}

/* ==================================================
 * Special controls
 * ================================================== */
.ui-color-input{
  width: 35px;
  height: 35px;
  padding: 0;
  border: 1px solid var(--color-input-border);
  border-radius: var(--radius-md);
  background: transparent;
}

.ui-range-row{
  display: flex;
  gap: 8px;
  align-items: center;
}

.ui-range-row .ui-input{
  width: 90px;
  flex: 0 0 auto;
}

.ui-segment-3{
  display: flex;
  gap: 6px;
}

.ui-segment-3 > .ui-input{
  width: 33.333%;
}

/* 상태/역할 표시 pill — 공용 UI 프리미티브.
   시스템관리(user-manage 역할 pill / data-manage 태그 pill)와 home이 함께 쓰므로,
   home.css가 아닌 공용 ui-primitives.css에 둔다(home·viewer 모두 로드). */
.ui-state-pill {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 0 10px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
}

.ui-state-pill.is-active {
  color: var(--color-success-text);
  border-color: var(--color-success-border);
  background: var(--color-success-soft);
}

.ui-state-pill.is-inactive {
  color: var(--color-danger-text);
  border-color: var(--color-danger-border);
  background: var(--color-danger-soft);
}

.ui-state-pill.is-role {
  color: var(--color-info-text);
  border-color: var(--color-info-border);
  background: var(--color-info-soft);
}