/* Lim portal migrated surfaces
 *
 * design-system.css가 값과 공통 primitive를 소유하고, 이 파일은 화면 역할 사이의
 * 관계만 소유한다. app.css는 이행 전 화면의 호환층이므로 여기서는 새 색/글자 크기를
 * 만들지 않는다. `.page-*` 없는 선택자는 오직 shell contract에만 적용한다. */

/* ── v1 어휘를 새 의미 토큰에 잇는 임시 다리 ─────────────────────────── */
.ui-v2 {
  --sheet: var(--ui-bg-surface);
  --rule: var(--ui-border-default);
  --rule-2: var(--ui-border-default);
  --ink: var(--ui-fg-strong);
  --ink-2: var(--ui-fg-default);
  --ink-3: var(--ui-fg-muted);
  --brand: var(--ui-brand);
  --ok: var(--ui-success-default);
  --seal: var(--ui-accent-receipt);
  --seal-2: var(--ui-accent-receipt);
  --seal-bg: var(--ui-danger-soft);
  --t-micro: var(--ui-type-caption);
  --t-meta: var(--ui-type-caption);
  --t-ui: var(--ui-type-label);
  --t-body: var(--ui-type-body);
  --t-head: var(--ui-type-card-title);
  --label: var(--ui-font-weight-bold) var(--ui-type-label) / var(--ui-line-tight) var(--ui-font-sans);
  --label-track: var(--ui-track-label);
}

.ui-v2 :is(.mono, code, pre) {
  font-family: var(--ui-font-mono);
}

/* ── workbench / reading 공통 셸 ───────────────────────────────────────── */
.ui-v2:is(.shell-workbench, .shell-reading) main.ui-page {
  min-width: 0;
}

.ui-v2:is(.shell-workbench, .shell-reading) .pagehead {
  display: flex;
  align-items: baseline;
  gap: var(--ui-space-3);
  margin: 0 0 var(--ui-space-8);
}
.ui-v2:is(.shell-workbench, .shell-reading) .pagehead h1 {
  margin: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-page-title);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
}
.ui-v2:is(.shell-workbench, .shell-reading) .pagehead .count {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}

/* 아직 markup이 옮겨지는 중인 card/sect도 같은 surface 결과를 낸다. 새 markup은
 * ui-surface를 직접 쓴다. */
.ui-v2:is(.shell-workbench, .shell-reading) :is(.card, .sect) {
  min-width: 0;
  border: 0;
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-surface);
}
.ui-v2:is(.shell-workbench, .shell-reading) .card + .card {
  margin-top: var(--ui-space-5);
}
.ui-v2:is(.shell-workbench, .shell-reading) :is(.card__head, .sect__head) {
  display: flex;
  align-items: baseline;
  gap: var(--ui-space-3);
  margin: 0;
  padding: var(--ui-space-5) var(--ui-space-6) 0;
  border: 0;
}
.ui-v2:is(.shell-workbench, .shell-reading) :is(.card__head, .sect__head) :is(h2, h3) {
  margin: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-card-title);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
}
.ui-v2:is(.shell-workbench, .shell-reading) :is(.card__head, .sect__head) .count,
.ui-v2:is(.shell-workbench, .shell-reading) .right {
  margin-left: auto;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}
.ui-v2:is(.shell-workbench, .shell-reading) .card__body {
  padding: var(--ui-space-5) var(--ui-space-6) var(--ui-space-6);
}
.ui-v2:is(.shell-workbench, .shell-reading) .sect {
  margin: 0 0 var(--ui-space-5);
  overflow: hidden;
}
.ui-v2:is(.shell-workbench, .shell-reading) .sect__box {
  min-width: 0;
  border: 0;
  background: transparent;
  overflow-x: auto;
}

/* 알림은 장식선이 아니라 상태 surface다. */
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare) .note {
  padding: var(--ui-space-4) var(--ui-space-5);
  border: 0;
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
  box-shadow: none;
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare) .note--ok {
  background: var(--ui-success-soft);
  color: var(--ui-success-default);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare) .note--bad {
  background: var(--ui-danger-soft);
  color: var(--ui-danger-default);
}
.ui-v2:is(.shell-workbench, .shell-reading) .note + * {
  margin-top: var(--ui-space-5);
}

/* 폼과 조작. session의 ui-button은 여기서 제외된다. */
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn):not(.ui-button) {
  min-height: var(--ui-control-default);
  height: auto;
  padding: 0 var(--ui-space-4);
  border: 0;
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
  color: var(--ui-fg-strong);
  font-family: var(--ui-font-sans);
  font-size: var(--ui-type-control);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  box-shadow: inset 0 0 0 var(--ui-border-width) var(--ui-border-default);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn):not(.ui-button):hover {
  border: 0;
  background: var(--ui-action-primary-soft);
  color: var(--ui-action-primary-hover);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn).btn--primary:not(.ui-button) {
  background: var(--ui-action-primary);
  color: var(--ui-fg-inverse);
  box-shadow: none;
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn).btn--primary:not(.ui-button):hover {
  background: var(--ui-action-primary-hover);
  color: var(--ui-fg-inverse);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn).btn--danger:not(.ui-button) {
  background: transparent;
  color: var(--ui-danger-default);
  box-shadow: inset 0 0 0 var(--ui-border-width) var(--ui-border-default);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn).btn--danger:not(.ui-button):hover {
  background: var(--ui-danger-soft);
  color: var(--ui-danger-hover);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn).btn--sm:not(.ui-button) {
  min-height: var(--ui-control-compact);
  padding-inline: var(--ui-space-3);
  font-size: var(--ui-type-label);
}
/* 상태는 모든 시각 variant 뒤에서 이긴다. primary/danger가 링을 지우면 안 된다. */
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(button, .btn):not(.ui-button):focus-visible {
  outline: 0;
  box-shadow: var(--ui-focus-ring);
}

.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(input[type="text"], input[type="email"], input[type="password"], input[type="date"],
      input[type="search"], input[type="file"], select, textarea) {
  width: 100%;
  min-height: var(--ui-control-default);
  height: auto;
  padding: 0 var(--ui-space-3);
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
  color: var(--ui-fg-strong);
  font-family: var(--ui-font-sans);
  font-size: var(--ui-type-body);
}
/* 위 입력 규칙은 :is() 안의 input[type="…"] 때문에 (0,3,1) 이고 padding 을 「0 …」으로 준다 — 이 규칙이 textarea 만으로 (0,2,1) 이던 동안
   한 번도 이기지 못해 포털의 모든 textarea 가 위아래 여백 0 이었다(첫 줄이 테에 붙고 아랫줄이 반쯤 잘림 · 2026-09-28 질문 화면 최종 검증 실측).
   :not([hidden]) 로 같은 (0,3,1) 에 올려 뒤에 선 이 규칙이 이기게 한다. */
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare) :where(main, .auth) textarea:not([hidden]) {
  padding-block: var(--ui-space-3);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare)
  :where(main, .auth) :is(input, select, textarea):focus-visible {
  outline: 0;
  border-color: var(--ui-action-primary);
  box-shadow: var(--ui-focus-ring);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare) :where(main, .auth) label {
  margin: 0 0 var(--ui-space-2);
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
  letter-spacing: var(--ui-track-label);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare) :where(main, .auth) .field__hint {
  margin-top: var(--ui-space-2);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  line-height: var(--ui-line-body);
}
.ui-v2:is(.shell-workbench, .shell-reading, .shell-bare) :where(main, .auth) input[type="checkbox"] {
  accent-color: var(--ui-action-primary);
}

/* 데이터는 좁아졌다고 의미를 버리지 않는다. 부모 surface가 가로 스크롤을 소유한다. */
.ui-v2:is(.shell-workbench, .shell-reading) table {
  min-width: max-content;
  border-collapse: separate;
  border-spacing: 0;
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
}
.ui-v2:is(.shell-workbench, .shell-reading) thead th {
  padding: var(--ui-space-3) var(--ui-space-4);
  border: 0;
  background: var(--ui-bg-subtle);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-bold);
  letter-spacing: var(--ui-track-label);
}
.ui-v2:is(.shell-workbench, .shell-reading) tbody td {
  padding: var(--ui-space-3) var(--ui-space-4);
  border: 0;
  box-shadow: inset 0 calc(var(--ui-border-width) * -1) 0 var(--ui-border-default);
}
.ui-v2:is(.shell-workbench, .shell-reading) tbody tr:last-child td {
  box-shadow: none;
}
.ui-v2:is(.shell-workbench, .shell-reading) tbody tr:hover > td {
  background: var(--ui-bg-subtle);
  box-shadow: inset 0 calc(var(--ui-border-width) * -1) 0 var(--ui-border-default);
}
.ui-v2:is(.shell-workbench, .shell-reading) :is(thead th, tbody td):nth-child(n) {
  display: table-cell;
}
.ui-v2:is(.shell-workbench, .shell-reading) .empty {
  padding: var(--ui-space-12) var(--ui-space-6);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-body);
  text-align: center;
}

.ui-v2 .chip {
  gap: var(--ui-space-2);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}
.ui-v2 .chip::before {
  width: var(--ui-size-status-dot);
  height: var(--ui-size-status-dot);
  background: var(--ui-fg-muted);
}
.ui-v2 .chip--ok::before {
  background: var(--ui-success-default);
}
.ui-v2 .chip--warn::before {
  background: var(--ui-warning-default);
}
/* 알림 벨 — 칩 옷을 입은 **조작**이다(상태 점 대신 아이콘+이름). 탭과 같은 알약 치수로
   같은 줄에 서고, 읽지 않은 것이 있을 때만 글자가 진해진다. */
.ui-v2 .topbar .notice-bell {
  min-height: var(--ui-control-default);
  padding: 0 var(--ui-space-3);
  gap: var(--ui-space-2);
  justify-content: flex-start; /* 전역 button 규칙(center)을 되돌린다 — 접힌 메뉴에서 칩/탭과 같은 왼쪽 정렬 */
  border-radius: var(--ui-radius-md);
  font-size: var(--ui-type-control);
  font-weight: var(--ui-font-weight-medium);
  color: var(--ui-fg-muted);
  transition: color var(--ui-motion-fast) ease, background var(--ui-motion-fast) ease;
}
.ui-v2 .topbar .notice-bell:hover {
  background: var(--ui-bg-subtle);
  color: var(--ui-fg-strong);
}
.ui-v2 .topbar .notice-bell.is-on {
  color: var(--ui-fg-strong);
}
.ui-v2 .topbar .notice-bell:focus-visible {
  outline: 0;
  box-shadow: var(--ui-focus-ring);
}
.ui-v2 .seal {
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-danger-soft);
  color: var(--ui-accent-receipt);
  box-shadow: none;
}
.ui-v2 .danger {
  border: 0;
  border-radius: var(--ui-radius-md);
  background: var(--ui-danger-soft);
  color: var(--ui-fg-default);
}
.ui-v2 .danger__head {
  color: var(--ui-danger-default);
}

/* ── 보고서가 없는 상태 ─────────────────────────────────────────────── */
.page-reports-empty main.ui-page {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--ui-space-6);
}
.page-reports-empty :is(.pagehead, .note) {
  grid-column: 1 / 5;
}
.page-reports-empty .reports-empty {
  grid-column: 5 / -1;
  align-self: start;
  overflow: hidden;
}

/* ── 관리 workbench ─────────────────────────────────────────────────── */
.page-admin .admin {
  display: grid;
  grid-template-columns: minmax(14rem, 3fr) minmax(0, 9fr);
  gap: var(--ui-space-6);
  align-items: start;
}
.page-admin .admin > *,
.page-admin .admin-focus,
.page-admin .tnav__list,
.page-admin .sect {
  min-width: 0;
  max-width: 100%;
}
.page-admin .tnav {
  position: sticky;
  top: var(--ui-space-4);
  min-width: 0;
  padding: var(--ui-space-3);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-surface);
}
.page-admin .tnav__label {
  margin: 0;
  padding: var(--ui-space-2) var(--ui-space-3) var(--ui-space-3);
  display: flex;
  justify-content: space-between;
  gap: var(--ui-space-2);
  border: 0;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
}
.page-admin .tnav__limit {
  margin: 0;
  padding: 0 var(--ui-space-3) var(--ui-space-3);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  line-height: var(--ui-line-body);
}
.page-admin .tnav__list {
  display: grid;
  gap: var(--ui-space-1);
  border: 0;
  background: transparent;
}
.page-admin .tnav__item {
  padding: var(--ui-space-3);
  border: 0;
  border-radius: var(--ui-radius-md);
  color: var(--ui-fg-default);
  box-shadow: none;
}
.page-admin .tnav__item:hover {
  background: var(--ui-bg-subtle);
  box-shadow: none;
}
.page-admin .tnav__item[aria-current] {
  background: var(--ui-action-primary-soft);
  color: var(--ui-action-primary-hover);
  box-shadow: var(--ui-selected-ring);
}
.page-admin .tnav__name {
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
  overflow-wrap: anywhere;
}
.page-admin .tnav__name .dot {
  width: var(--ui-size-status-dot);
  height: var(--ui-size-status-dot);
  background: var(--ui-accent-receipt);
}
.page-admin .tnav__matrix {
  gap: var(--ui-space-3);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.page-admin .tnav__add {
  min-height: var(--ui-control-default);
  margin-top: var(--ui-space-2);
  padding: 0 var(--ui-space-3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ui-space-2);
  border: 0;
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
  color: var(--ui-action-primary-hover);
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
}
.page-admin .tnav__pager {
  margin-top: var(--ui-space-3);
  padding: 0 var(--ui-space-1);
}
.page-admin .focus__head {
  display: flex;
  align-items: center;
  gap: var(--ui-space-4);
  margin: 0 0 var(--ui-space-6);
  padding: 0;
  border: 0;
}
.page-admin .focus__title {
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
  font-size: var(--ui-type-section-title);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
}
.page-admin .focus__meta {
  gap: var(--ui-space-3);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}
.page-admin .focus__actions {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ui-space-2);
}
.page-admin .focus__actions > :is(details, form) {
  margin: 0;
}
.page-admin :is(.admin-action-launcher, .admin-disclosure > summary) {
  width: auto;
  white-space: nowrap;
}
.page-admin .sect__head {
  flex-wrap: wrap;
}
.page-admin .sect__head :is(h2, h3) {
  flex: none;
  white-space: nowrap;
}
.page-admin .admin-create {
  max-inline-size: 42ic;
  overflow: hidden;
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-surface);
}
.page-admin .admin-disclosure {
  /* 패널은 개별 launcher가 아니라 action group 아래에 놓는다.
   * 두 줄로 접힌 경계에서 앞 패널이 다음 launcher를 덮지 않는다. */
  position: static;
  display: inline-block;
}
.page-admin .admin-disclosure > summary {
  min-height: var(--ui-control-default);
  height: auto;
  padding: 0 var(--ui-space-4);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ui-space-2);
  border: 0;
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
  color: var(--ui-action-primary-hover);
  font-family: var(--ui-font-sans);
  font-size: var(--ui-type-control);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  cursor: pointer;
  box-shadow: inset 0 0 0 var(--ui-border-width) var(--ui-border-default);
}
.page-admin .admin-disclosure > summary:hover,
.page-admin .admin-disclosure:not(.admin-disclosure--primary)[open] > summary {
  background: var(--ui-action-primary-soft);
}
.page-admin .admin-disclosure--primary > summary {
  background: var(--ui-action-primary);
  color: var(--ui-fg-inverse);
  box-shadow: none;
}
.page-admin .admin-disclosure--primary > summary:hover {
  background: var(--ui-action-primary-hover);
}
.page-admin .admin-disclosure > summary:focus-visible {
  box-shadow: var(--ui-focus-ring);
}
.page-admin .admin-disclosure__panel {
  position: absolute;
  z-index: var(--ui-layer-popover);
  inset-block-start: calc(100% + var(--ui-space-2));
  inset-inline-end: 0;
  width: min(36ic, calc(100vw - var(--ui-space-10)));
  padding: var(--ui-space-5);
  border: 0;
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-overlay);
}
.page-admin .admin-disclosure__panel form {
  display: grid;
  gap: var(--ui-space-4);
}
.page-admin .linkrow {
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ui-space-3);
  padding: var(--ui-space-3) var(--ui-space-4);
  border: 0;
  box-shadow: inset 0 calc(var(--ui-border-width) * -1) 0 var(--ui-border-default);
}
.page-admin .linkrow__who {
  min-width: 12ch;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
  overflow-wrap: anywhere;
}
.page-admin .t-title {
  overflow-wrap: anywhere;
}
.page-admin .linkrow__meta {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.page-admin .linkrow--new {
  background: var(--ui-action-primary-soft);
}
.page-admin .linkrow--new .linkrow__who {
  color: var(--ui-action-primary-hover);
}
.page-admin .admin-section {
  margin-block-end: var(--ui-space-5);
  overflow: hidden;
}
.page-admin .admin-section__header {
  flex-wrap: wrap;
}
.page-admin .admin-section__header .count,
.page-admin .admin-close {
  margin-inline-start: auto;
}
.page-admin .admin-section__body {
  min-width: 0;
  padding-top: var(--ui-space-4);
}
.page-admin .admin-section__body--padded {
  display: grid;
  gap: var(--ui-space-6);
}
.ui-v2 .report-pager {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
}
.ui-v2 .report-pager__status {
  min-width: 0;
  flex: 1;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  text-align: center;
  white-space: nowrap;
}
.ui-v2 .report-pager [aria-disabled="true"] {
  pointer-events: none;
}
/* ── 번호 쪽나눔(2026-08-25) ────────────────────────────────────────────────
   이전/다음만으로는 14쪽짜리 목록의 9쪽에 못 간다(사용자 실측 지적). 상태는 왼쪽,
   이동 컨트롤은 오른쪽 — Whop·Squarespace 관리 화면의 배치. 번호 알약과 현재 쪽
   채우기는 Mercor. (mobbin 실물 참조, 지어낸 배치가 아니다.) */
.ui-v2 .report-pager__nav {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
}
.ui-v2 .report-pager__pages {
  display: flex;
  align-items: center;
  gap: var(--ui-space-1);
}
.ui-v2 .report-pager__num {
  min-width: var(--ui-control-compact);
  height: var(--ui-control-compact);
  padding: 0 var(--ui-space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ui-radius-sm);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  transition: background-color var(--ui-motion-fast) var(--ui-ease-standard),
              color var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 a.report-pager__num:hover { background: var(--ui-bg-subtle); color: var(--ui-fg-strong); }
.ui-v2 a.report-pager__num:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
/* 지금 쪽은 주 색으로 채운 표지라 같은 색 안쪽 테가 안 보인다 — 흰 틈 뒤 바깥 테(오너 결정 2 (2026-09-29) · 인용 칩과 같은 처방). */
.ui-v2 .report-pager__num--on {
  color: var(--ui-fg-inverse);
  background: var(--ui-action-primary);
  font-weight: var(--ui-font-weight-medium);
  box-shadow: var(--ui-selected-ring-outer);
}
/* 「…」는 자리를 말할 뿐 누를 수 없다 — 눌릴 것처럼 보이면 안 된다. */
.ui-v2 .report-pager__gap {
  min-width: var(--ui-space-5);
  text-align: center;
  color: var(--ui-fg-muted);
  user-select: none;
}
/* 상태는 왼쪽에 붙는다(예전엔 flex:1 로 가운데였다 — 번호가 생기면서 자리를 내준다). */
.ui-v2 .report-pager:has(.report-pager__nav) .report-pager__status {
  flex: 0 0 auto;
  text-align: start;
}
@media (max-width: 560px) {
  /* 좁은 폭에서는 번호를 접고 이전/다음만 남긴다 — 14개 알약이 줄을 넘긴다. */
  .ui-v2 .report-pager__pages { display: none; }
}
.page-admin :is(.admin-report-pager, .admin-collection-pager) {
  justify-content: flex-end;
  padding: 0 var(--ui-space-4) var(--ui-space-4);
}
.page-admin :is(.admin-report-pager, .admin-collection-pager) .report-pager__status {
  flex: 0 0 auto;
}
.page-admin .admin-report-region {
  margin-top: 0;
}
.page-admin .admin-table {
  width: 100%;
}
.page-admin :is(.admin-col-date, .admin-col-hits, .admin-col-talk) {
  inline-size: 8ch;
}
.page-admin :is(.admin-col-viewers, .admin-col-status) {
  inline-size: 10ch;
}
.page-admin :is(.admin-col-last-view, .admin-col-first-view, .admin-col-last-login) {
  inline-size: 14ch;
}
.page-admin .admin-col-receipt {
  inline-size: 18ch;
}
.page-admin .admin-col-read-count {
  inline-size: 16ch;
}
.page-admin .admin-report-meta {
  margin-top: var(--ui-space-1);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ui-space-2);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.page-admin .admin-row-actions {
  flex-wrap: nowrap;
  white-space: nowrap;
}
.page-admin :is(.admin-form-actions, .admin-meta) {
  margin-top: var(--ui-space-3);
}
.page-admin .admin-meta,
.page-admin .admin-unavailable {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.page-admin .admin-unavailable {
  align-self: center;
}
.page-admin .admin-inline-form {
  display: inline-flex;
}
.page-admin .admin-link-list {
  display: grid;
}
.page-admin .linkrow > .ui-input {
  min-width: 24ch;
  flex: 1 1 36ch;
}
.page-admin .linkrow__tail {
  margin-inline-start: auto;
}
.page-admin .admin-danger-zone {
  margin-block-start: var(--ui-space-6);
  display: grid;
  gap: var(--ui-space-4);
}
.page-admin .admin-danger-zone__title {
  margin: 0;
  color: var(--ui-danger-default);
  font-size: var(--ui-type-card-title);
  line-height: var(--ui-line-tight);
}
.page-admin .admin-danger-action {
  align-items: center;
}
.page-admin .admin-danger-action .ui-button {
  flex: none;
}

/* ── 계정: 개인 설정은 좁게, 팀 권한은 가용 폭을 쓴다 ───────────────── */
.page-account main.ui-page {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--ui-space-5) var(--ui-space-6);
  align-items: start;
}
.page-account :is(.pagehead, .ui-notice) {
  grid-column: 1 / -1;
  margin-bottom: 0;
}
.page-account .account-profile {
  grid-column: 1 / 5;
}
.page-account .account-members {
  grid-column: 5 / -1;
  overflow: hidden;
}
.page-account .account-members__body {
  padding: var(--ui-space-5) var(--ui-space-6) var(--ui-space-6);
}
.page-account .account-member-list {
  display: grid;
  gap: var(--ui-space-3);
}
.page-account .account-member {
  min-width: 0;
  padding: var(--ui-space-4);
  display: grid;
  gap: var(--ui-space-4);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
}
.page-account .account-member__header {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: start;
  gap: var(--ui-space-3);
}
.page-account .account-member__identity {
  min-width: 0;
}
.page-account .account-member__identity h3,
.page-account .account-member__email,
.page-account .account-member__last-login {
  margin: 0;
}
.page-account .account-member__identity h3 {
  font-size: var(--ui-type-body);
  line-height: var(--ui-line-tight);
  overflow-wrap: anywhere;
}
.page-account .account-member__identity h3 span,
.page-account .account-member__email,
.page-account .account-member__last-login {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.page-account .account-member__email {
  margin-top: var(--ui-space-1);
  overflow-wrap: anywhere;
}
.page-account .account-member__last-login {
  display: grid;
  gap: var(--ui-space-1);
  text-align: right;
}
.page-account .account-member__last-login time {
  color: var(--ui-fg-default);
  font-family: var(--ui-font-mono);
  white-space: nowrap;
}
.page-account .account-member__body {
  min-width: 0;
}
.page-account .account-member__permissions {
  display: grid;
  grid-template-columns: minmax(9ic, 1fr) minmax(0, 3fr) auto;
  align-items: end;
  gap: var(--ui-space-3);
}
.page-account .account-member__tenants {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
.page-account .account-member__tenants legend {
  margin-bottom: var(--ui-space-2);
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
  letter-spacing: var(--ui-track-label);
}
.page-account .account-member__choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-1) var(--ui-space-3);
}
.page-account .account-member__save {
  align-self: end;
}
.page-account .account-member__actions {
  justify-content: flex-end;
}
.page-account .account-members__help {
  margin-top: var(--ui-space-4);
  padding-top: var(--ui-space-4);
}
.page-account .account-members__help p {
  max-inline-size: 62ic;
}
/* 메일 알림 절(#notice-mail)은 메일 속 「메일 알림 설정」 링크와 수신 거부 쪽 「내 계정으로」가 내려앉는 자리다(DESIGN-chat-rooms.md 3.1).
   셸의 고정 메뉴 단추(workspace.css .ws-burger — 880px 이하 · 위 10px · 44px)가 서는 폭에서 여백이 0 이면 제목이 단추 밑에 반쯤 깔렸다
   (390 실측 — 제목 글자 y 20–45 · x 40–118, 단추 y 10–54 · x 10–54). 단추 44px(--ui-control-default) + 그 아래 틈 space-6 은
   ask.css 의 같은 문턱 · 같은 값이다(단추 위 10px 까지 더해도 14px 가 남는다). 넓은 폭은 위를 덮는 것이 없어 0 그대로. */
@media (max-width: 880px) {
  .page-account #notice-mail { scroll-margin-top: calc(var(--ui-control-default) + var(--ui-space-6)); }
}

/* ── 설정: 상태 객체의 최소 정보 폭으로 열이 늘어난다 ───────────────── */
.page-settings .settings-layout {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 30ic), 1fr));
  gap: var(--ui-space-5);
  align-items: start;
}
.page-settings .settings-layout > .settings-card {
  margin: 0;
  overflow: hidden;
}
.page-settings .settings-copy {
  margin: 0;
  line-height: var(--ui-line-relaxed);
}
.page-settings .settings-hint {
  margin: 0;
}
.page-settings .settings-hint--flush {
  margin: 0;
}
.page-settings .settings-actions {
  gap: var(--ui-space-2);
}
.page-settings .settings-action {
  flex: none;
}
.page-settings .settings-device-label {
  margin: 0 0 var(--ui-space-2);
  font-size: var(--ui-type-label);
}
.page-settings .settings-device-code {
  margin: 0 0 var(--ui-space-3);
  font-size: var(--ui-type-section-title);
  letter-spacing: var(--ui-track-label);
}
.page-settings .settings-usage-empty {
  margin: 0;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}
.page-settings .settings-freshness {
  margin: 0;
}
.page-settings .settings-eof-preview {
  margin: 0;
  overflow: hidden;
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
  box-shadow: inset 0 0 0 var(--ui-border-width) var(--ui-border-default);
}
.page-settings .settings-eof-image {
  display: block;
  width: 100%;
  height: auto;
}
.page-settings .settings-card-submit {
  margin: 0;
}
.page-settings .settings-card .ui-surface__body > .ui-copy {
  max-inline-size: 58ic;
}
.page-settings .settings-facts {
  font-size: var(--ui-type-label);
}
.page-settings .usage {
  margin-top: var(--ui-space-4);
  padding-top: var(--ui-space-4);
  border: 0;
}

/* ── 위키 workbench / 문서 reading ─────────────────────────────────── */
.page-wiki-index .wiki-workbench {
  display: grid;
  gap: var(--ui-space-5);
}
.page-wiki-index .wiki-intro {
  display: grid;
  gap: var(--ui-space-3);
  max-inline-size: 62ic;
}
.page-wiki-index .wiki-intro h1 {
  margin: 0;
  font-size: var(--ui-type-page-title);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
}
.page-wiki-index .wiki-intro p {
  margin: 0;
  color: var(--ui-fg-muted);
}
.page-wiki-index .wiki-tenants {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 38ic), 1fr));
  gap: var(--ui-space-5);
  align-items: start;
}
.page-wiki-index .wiki-tenant {
  min-width: 0;
  container: wiki-tenant / inline-size;
  overflow: hidden;
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-surface);
}
.page-wiki-index .wiki-tenant__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ui-space-3);
  margin: 0;
  padding: var(--ui-space-5) var(--ui-space-5) var(--ui-space-3);
}
.page-wiki-index .wiki-tenant__identity {
  min-width: 0;
  flex: 1 1 20ic;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--ui-space-1) var(--ui-space-3);
}
.page-wiki-index .wiki-tenant__head h2 {
  margin: 0;
  overflow-wrap: anywhere;
  font-size: var(--ui-type-card-title);
  line-height: var(--ui-line-tight);
}
.page-wiki-index .wiki-tenant__meta {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.page-wiki-index .wiki-tenant__action {
  flex: none;
  margin: 0;
}
.page-wiki-index .wiki-tenant__insights {
  margin-inline-start: auto;
}
.page-wiki-index .wiki-reset[open] {
  width: 100%;
  min-width: 0;
  flex: 1 0 100%;
  display: block;
}
.page-wiki-index .wiki-reset[open] > summary {
  display: flex;
  width: max-content;
  margin-block-end: var(--ui-space-3);
  margin-inline-start: auto;
}
.page-wiki-index .wiki-reset__label--close {
  display: none;
}
.page-wiki-index .wiki-reset[open] > summary .wiki-reset__label--open {
  display: none;
}
.page-wiki-index .wiki-reset[open] > summary .wiki-reset__label--close {
  display: inline;
}
.page-wiki-index .wiki-reset__panel {
  width: 100%;
  min-width: 0;
  margin: 0;
  padding: var(--ui-space-5);
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--ui-space-6);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-danger-soft);
  color: var(--ui-fg-default);
}
.page-wiki-index :is(.wiki-reset__intro, .wiki-reset__controls) {
  min-width: 0;
  display: grid;
  align-content: start;
  gap: var(--ui-space-3);
}
.page-wiki-index .wiki-reset__eyebrow {
  margin: 0;
  color: var(--ui-danger-default);
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-bold);
  letter-spacing: var(--ui-track-label);
}
.page-wiki-index .wiki-reset__intro h3 {
  margin: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-section-title);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
  overflow-wrap: anywhere;
}
.page-wiki-index .wiki-reset__facts {
  max-inline-size: 54ic;
  margin: 0;
  padding-inline-start: var(--ui-space-5);
  display: grid;
  gap: var(--ui-space-1);
  color: var(--ui-fg-default);
  line-height: var(--ui-line-body);
}
.page-wiki-index .wiki-reset__controls {
  gap: var(--ui-space-4);
}
.page-wiki-index .wiki-reset__error {
  background: var(--ui-bg-surface);
}
.page-wiki-index .wiki-reset__rebake {
  min-height: var(--ui-control-default);
  align-items: start;
}
.page-wiki-index .wiki-reset__rebake > span {
  display: grid;
  gap: var(--ui-space-1);
}
.page-wiki-index .wiki-reset__rebake small {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-regular);
  line-height: var(--ui-line-body);
}
.page-wiki-index .wiki-reset__actions {
  justify-content: flex-end;
}
.page-wiki-index .wiki-tenant__body {
  min-width: 0;
  container: wiki-tenant / inline-size;
}
.page-wiki-index .wiki-tenants > .wiki-empty-state {
  grid-column: 1 / -1;
}
.page-wiki-index .wiki-section {
  min-width: 0;
  display: grid;
  gap: var(--ui-space-3);
}
.page-wiki-index .wiki-section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ui-space-3);
}
.page-wiki-index .wiki-section__head h3 {
  margin: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-card-title);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
}
.page-wiki-index .wiki-section__count {
  flex: none;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-bold);
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-list {
  display: grid;
  gap: var(--ui-space-3);
}
/* 검토 소절 머리 — **종류 하나가 판단 단위**다(2026-09-01, 오너 판정 뒤).
   ⚠ 새 색·새 크기를 안 만든다(design-system.css:3-7) — 종류 이름은 옆의 `.wiki-review-kind`
     그대로, 건수는 caption, 일괄 문은 text 버튼.
   ⚠ 카드가 아니라 **줄**이다: 배경(--ui-bg-subtle)을 주면 아래 항목 카드와 같은 무게가 되어
     머리가 아니라 또 하나의 항목으로 읽힌다. 밑줄 하나로 층을 만든다. */
:is(.page-wiki-index, .page-tenant-home) .wiki-review-group {
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: var(--ui-space-2);
  padding-inline: var(--ui-space-1);
  padding-bottom: var(--ui-space-2);
  border-bottom: var(--ui-border-width) solid var(--ui-border-default);
}
/* 소절 사이에만 숨을 준다 — 첫 머리는 절 머리 바로 아래라 그대로 붙는다. */
:is(.page-wiki-index, .page-tenant-home) .wiki-review-item + .wiki-review-group {
  margin-top: var(--ui-space-4);
}
/* 확신도 — **분류**다(확실·그럴듯함·약함). 사유 앞에 산문으로 붙어 있던 것을 떼어 제목
   앞에 세운다. 알약을 안 만든다: 목록에서 가장 큰 물체가 누를 수 없는 것이면 안 된다
   (같은 판단을 항목 목록에서 이미 했다 — `.ui-kind`). 색은 **예외에만** — 「확실」만 짙다. */
:is(.page-wiki-index, .page-tenant-home) .wiki-review-conf {
  flex: none;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-label);
  white-space: nowrap;
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-conf--strong {
  color: var(--ui-fg-strong);
}
/* 물음 — 답(단추) 바로 옆에 서는 라벨이다. 문단이 아니라 라벨이라 caption·muted. */
:is(.page-wiki-index, .page-tenant-home) .wiki-review-group__ask {
  flex: none;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  line-height: var(--ui-line-tight);
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-group__count {
  flex: none;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  line-height: var(--ui-line-tight);
  font-variant-numeric: tabular-nums;
}
/* 일괄 문은 오른쪽 끝 — 읽는 것(이름·건수)과 하는 것(닫기)이 한 덩어리로 안 뭉친다. */
:is(.page-wiki-index, .page-tenant-home) .wiki-review-group .wiki-review-bulk {
  margin: 0 0 0 auto;
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-item {
  min-width: 0;
  padding: var(--ui-space-3) var(--ui-space-4);
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content;
  align-items: start;
  gap: var(--ui-space-4);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-copy {
  min-width: 0;
  max-inline-size: 62ic;
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-heading {
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--ui-space-1) var(--ui-space-3);
}
/* ★ **제목은 한 줄**(2026-09-01). 운영 제목은 길다 — 「다른 소속처의 것으로 보이는 장 13건 —
   이 위키의 다수는 …」. 꺾이게 두면 폭 1280 에서 2줄, 390 에서 3줄이 되어 행이 99·210px 로
   부푼다(실측). 전문은 `title=` 이 진다 — 일 항목 목록에서 쓴 것과 같은 처방이다. */
:is(.page-wiki-index, .page-tenant-home) .wiki-review-heading :is(h3, h4) {
  min-width: 0;
  margin: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-body);
  line-height: var(--ui-line-body);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  overflow: hidden;
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-kind {
  flex: none;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-label);
  white-space: nowrap;
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-kind--warning {
  color: var(--ui-warning-default);
}
/* ★ **행은 세 줄을 안 넘는다**(2026-09-01, 오너 판정 「지식탭 너무 뭘 하기가 어렵게 되어있네」).
   실측: 한 행 128px × 18행 = 2,624px — 목록 하나를 보려고 2.6 화면을 굴려야 했고, 그 사이
   단추가 54개 서 있었다. 근거를 **지우지는 않는다**(조용한 결손) — 한 줄로 눕히고 전문은
   `title=` 이 진다. 같은 처방을 일 항목 목록에서 이미 썼다(work-items: 85.7px → 17.9px). */
:is(.page-wiki-index, .page-tenant-home) .wiki-review-description,
:is(.page-wiki-index, .page-tenant-home) .wiki-review-pages {
  margin-top: var(--ui-space-1);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  overflow: hidden;
}
/* 넓으면 근거와 경로가 **한 줄에 나란히** 선다 — 두 줄이 한 줄이 된다. */
@media (min-width: 60rem) {
  :is(.page-wiki-index, .page-tenant-home) .wiki-review-copy {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, auto);
    align-items: baseline;
    column-gap: var(--ui-space-3);
  }
  :is(.page-wiki-index, .page-tenant-home) .wiki-review-heading { grid-column: 1 / -1; }
  :is(.page-wiki-index, .page-tenant-home) .wiki-review-pages { justify-self: end; text-align: end; }
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-actions {
  align-self: center;
  flex-wrap: nowrap;
  justify-content: flex-end;
}
:is(.page-wiki-index, .page-tenant-home) .wiki-review-actions form {
  margin: 0;
}
.page-wiki-index .wiki-job-status {
  overflow-wrap: normal;
  white-space: nowrap;
}
.page-wiki-index .wiki-job-result {
  min-width: 32ic;
  max-width: 60ic;
  overflow-wrap: anywhere;
}
.page-wiki-index .wiki-cell-actions {
  text-align: end;
  white-space: nowrap;
}
.page-wiki-index .wiki-job-actions {
  flex-wrap: nowrap;
  justify-content: flex-end;
}
/* 행 안 동작 — DESIGN-portal-ui.md 「표 행 안 동작」. wrapper div 가 flex 를 갖고 form 은 형제다. */
.page-wiki-index .wiki-job-actions form {
  margin: 0;
}
/* 파괴로 가는 launcher 는 색만 아니라 자리로도 갈라 선다 — gap 8 + 8. */
.page-wiki-index .wiki-job-actions .ui-button--danger-ghost {
  margin-inline-start: var(--ui-space-2);
}
/* 검토 행의 ⋯ 와 그 region — session.css 의 인계 손잡이·패널과 같은 토큰. [hidden] 은 design-system.css 가 처리. */
.page-wiki-index .wiki-review-more__toggle {
  color: var(--ui-fg-muted);
}
.page-wiki-index .wiki-review-more__toggle[aria-expanded="true"] {
  background: var(--ui-action-primary-soft);
  color: var(--ui-action-primary-hover);
}
.page-wiki-index .wiki-review-more {
  grid-column: 1 / -1;
  min-width: 0;
  display: grid;
  gap: var(--ui-space-3);
  padding: var(--ui-space-4);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
}
.page-wiki-index .wiki-col-status {
  inline-size: 12ch;
}
.page-wiki-index :is(.wiki-col-ref, .wiki-col-attempts, .wiki-col-number) {
  inline-size: 9ch;
}
.page-wiki-index .wiki-col-date {
  inline-size: 14ch;
}
.page-wiki-index .wiki-decision-help {
  margin-block-end: var(--ui-space-2);
}
.page-wiki-index .wiki-col-decision-status {
  inline-size: 10ch;
}
.page-wiki-index .wiki-col-decision-owner {
  inline-size: 20ch;
}
.page-wiki-index .wiki-decision-note {
  margin-block-start: var(--ui-space-1);
}

@container wiki-tenant (max-width: 48rem) {
  .page-wiki-index .wiki-reset__panel {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ui-space-5);
  }
  .page-wiki-index .wiki-reset__actions {
    justify-content: flex-start;
  }
}

@container wiki-tenant (max-width: 36rem) {
  .page-wiki-index .wiki-tenant__identity {
    flex-basis: 100%;
  }
  .page-wiki-index .wiki-tenant__insights {
    margin-inline-start: 0;
  }
  :is(.page-wiki-index, .page-tenant-home) .wiki-review-item {
    grid-template-columns: minmax(0, 1fr);
  }
  :is(.page-wiki-index, .page-tenant-home) .wiki-review-actions {
    justify-content: flex-start;
    flex-wrap: wrap;
  }
}

.page-wiki-document main.ui-page {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
}
.page-wiki-document .wiki-document {
  grid-column: 3 / 11;
  min-width: 0;
}
.page-wiki-document .wiki-document__crumb {
  margin: 0 0 var(--ui-space-4);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}
.page-wiki-document .wiki-document__surface {
  overflow: hidden;
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-surface);
}
.page-wiki-document .wiki-document__head {
  padding: var(--ui-space-5) var(--ui-space-6) 0;
}
.page-wiki-document .wiki-document__head h1 {
  margin: 0;
  overflow-wrap: anywhere;
  font-size: var(--ui-type-section-title);
  line-height: var(--ui-line-tight);
}
/* 가까운 일 물음(2026-09-21) — 한글 낱말이 줄 끝에서 쪼개지지 않게 한다(「간 / 트」 실측). 긴 열쇠는 붙임표에서 꺾인다.
   같은 결: codex-settings.css 의 .cx-panel · access-pages.css 의 제목들. */
.page-wiki-document .wiki-near {
  word-break: keep-all;
  overflow-wrap: anywhere;
}
.page-wiki-document .wiki-document pre {
  max-inline-size: 82ic;
  margin: 0;
  padding: var(--ui-space-5) var(--ui-space-6) var(--ui-space-6);
  background: transparent;
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
  line-height: var(--ui-line-relaxed);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ── bare: 진입·결정·상태는 같은 배경, 다른 내용 밀도를 쓴다 ───────── */
.shell-bare {
  border: 0;
  background: var(--ui-bg-canvas);
  color: var(--ui-fg-strong);
  font-family: var(--ui-font-sans);
  font-size: var(--ui-type-body);
}
.shell-bare :is(.bare, .auth) {
  position: relative;
  min-height: 100dvh;
  padding: var(--ui-space-6);
  display: grid;
  place-items: center;
  background: var(--ui-bg-canvas);
}
.shell-bare .bare__ambient {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 13.75rem;
  pointer-events: none;
  opacity: 0.18;
  -webkit-mask-image: linear-gradient(to bottom, transparent, var(--ui-fg-strong) 60%);
  mask-image: linear-gradient(to bottom, transparent, var(--ui-fg-strong) 60%);
}
.shell-bare .bare__ambient--top {
  top: 0;
  bottom: auto;
  height: 9.375rem;
  opacity: 0.12;
  -webkit-mask-image: linear-gradient(to top, transparent, var(--ui-fg-strong) 60%);
  mask-image: linear-gradient(to top, transparent, var(--ui-fg-strong) 60%);
}
/* 로그인은 브랜드 진입점이다. Renderer가 이미 낮은 alpha와 방향 mask로 농도를
   제어하므로 여기서 다시 감쇠하지 않고, 상단 잔향만 약 2/3 강도로 낮춘다. */
.page-login .bare__ambient {
  opacity: 1;
}
.page-login .bare__ambient--top {
  opacity: 0.67;
}
.page-login .bare__logo img {
  display: block;
  margin-inline: auto;
}
.shell-bare .bare__box {
  position: relative;
  z-index: 1;
}
.shell-bare :is(.bare__box, .auth__box) {
  width: min(100%, 27rem);
  max-width: none;
}
.shell-bare :is(.bare__logo, .auth__logo) {
  margin-bottom: var(--ui-space-8);
}
.shell-bare :is(.bare__logo, .auth__logo) img {
  width: min(100%, 12rem);
  height: auto;
}
.shell-bare :is(.bare__kicker, .auth__sub) {
  margin: 0 0 var(--ui-space-4);
  padding: 0;
  border: 0;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-medium);
}
.shell-bare .auth .card,
.shell-bare .bare-panel {
  border: 0;
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-overlay);
}
.shell-bare .auth .card__body,
.shell-bare .bare-panel__body {
  padding: var(--ui-space-6);
}
.shell-bare :is(.bare, .auth) button[type="submit"],
.shell-bare :is(.bare, .auth) .btn--sso,
.shell-bare .switch__actions .btn {
  min-height: var(--ui-control-default);
  height: auto;
}
.shell-bare .auth__ambient {
  opacity: 0.18;
}
.shell-bare .bare-header {
  display: grid;
  gap: var(--ui-space-2);
  margin-bottom: var(--ui-space-4);
}
.shell-bare .bare__box > .ui-notice + :is(.ui-notice, .bare-panel) {
  margin-top: var(--ui-space-3);
}
.shell-bare .bare-pending-copy {
  margin-block: var(--ui-space-4);
}
.shell-bare .bare-header__title {
  margin: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-card-title);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
}
.shell-bare .bare-header__lead {
  margin: 0;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
  line-height: var(--ui-line-body);
}
.shell-bare .bare-identity {
  padding: var(--ui-space-4);
  display: grid;
  gap: var(--ui-space-2);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
}
.shell-bare .bare-identity__primary,
.shell-bare .bare-identity__meta {
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
}
.shell-bare .bare-identity__primary {
  color: var(--ui-fg-strong);
  font-family: var(--ui-font-mono);
  font-size: var(--ui-type-label);
}
.shell-bare .bare-identity__meta {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.shell-bare .bare-form {
  display: grid;
  gap: var(--ui-space-3);
}
.shell-bare .bare-form .ui-button {
  width: 100%;
}

/* 로그인 handoff — 로그인 surface의 컴팩트한 척도는 유지하고, 상태가 바뀔 때만
   공개 코드·주행동·현재 상태의 위계를 한 장 안에서 또렷하게 만든다. */
.page-login .bare__box {
  width: min(100%, 30rem);
}
.page-login .bare-login-notice,
.page-login .login-flow__choice {
  width: min(100%, 27rem);
  margin-inline: auto;
}
.page-login .login-flow {
  width: 100%;
}
.page-login .login-flow[data-login-state="pairing"] {
  overflow: hidden;
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-overlay);
}
.page-login .login-handoff:focus {
  outline: 0;
}
.page-login .login-handoff__body {
  padding: var(--ui-space-6);
  display: grid;
  gap: var(--ui-space-5);
}
.page-login .login-handoff__header {
  display: grid;
  gap: var(--ui-space-2);
}
.page-login .login-handoff__title,
.page-login .login-handoff__lead,
.page-login .login-handoff__code-line,
.page-login .login-flow__status {
  margin: 0;
}
.page-login .login-handoff__title {
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-section-title);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-tight);
}
.page-login .login-handoff__lead {
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
  line-height: var(--ui-line-body);
}
.page-login .login-handoff__ready {
  display: grid;
  gap: var(--ui-space-4);
}
.page-login .login-handoff__code-card {
  min-width: 0;
  padding: var(--ui-space-4);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--ui-space-3);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-action-primary-soft);
}
.page-login .login-handoff__code-mark {
  width: var(--ui-control-default);
  height: var(--ui-control-default);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-bg-surface);
  color: var(--ui-fg-default);
  box-shadow: inset 0 0 0 var(--ui-border-width) var(--ui-border-default);
}
.page-login .login-handoff__code-icon {
  width: var(--ui-space-5);
  height: var(--ui-space-5);
  stroke-width: 1.25;
}
.page-login .login-handoff__code-copy {
  min-width: 0;
  display: grid;
  gap: var(--ui-space-1);
}
.page-login .login-handoff__code-label {
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
}
.page-login .login-handoff__code-line {
  min-width: 0;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
}
.page-login .login-handoff__code {
  color: var(--ui-action-primary-hover);
  font-family: var(--ui-font-mono);
  font-size: var(--ui-type-card-title);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  letter-spacing: var(--ui-track-label);
  overflow-wrap: anywhere;
}
.page-login .login-handoff__code:focus-visible {
  outline: 0;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-focus-ring);
}
.page-login .login-handoff__code-divider,
.page-login .login-handoff__code-meta {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.page-login .login-handoff__code-button {
  color: var(--ui-fg-default);
  white-space: nowrap;
}
.page-login .login-handoff__primary {
  width: 100%;
  min-height: var(--ui-control-large);
  padding-block: 0;
  font-size: var(--ui-type-label);
}
.page-login .login-handoff__primary .i {
  width: var(--ui-space-5);
  height: var(--ui-space-5);
}
.page-login .login-handoff__recovery {
  padding: var(--ui-space-4);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
}
.page-login .login-handoff__back {
  justify-self: center;
}
.page-login .login-handoff__back .i {
  width: var(--ui-space-5);
  height: var(--ui-space-5);
}
.page-login .login-flow__status {
  min-height: var(--ui-control-default);
  padding: var(--ui-space-4) var(--ui-space-6);
  display: flex;
  align-items: flex-start;
  gap: var(--ui-space-3);
  border-top: var(--ui-border-width) solid var(--ui-border-default);
  color: var(--ui-fg-default);
  font-size: var(--ui-type-label);
  line-height: var(--ui-line-body);
}
.page-login .login-flow__status-icon {
  width: var(--ui-space-5);
  height: var(--ui-space-5);
  margin-top: var(--ui-space-1);
}
.page-login .login-flow__status[data-tone="success"] {
  color: var(--ui-success-default);
}
.page-login .login-flow__status[data-tone="danger"] {
  color: var(--ui-danger-default);
}
.page-login .login-flow[data-login-state="choice"] > .login-flow__status {
  width: min(100%, 27rem);
  min-height: 0;
  margin: var(--ui-space-3) auto 0;
  padding: 0;
  border-top: 0;
  font-size: var(--ui-type-caption);
}
.shell-bare .bare-footnote {
  margin: var(--ui-space-4) 0 0;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  line-height: var(--ui-line-body);
  text-align: center;
}
.shell-bare .bare-footnote a {
  color: inherit;
}
.shell-bare .stop__sub {
  align-items: center;
}
.shell-bare .stop__actions {
  gap: var(--ui-space-2);
  margin-top: var(--ui-space-4);
}

/* ── immersive: 100dvh/72px 연쇄는 보존하고 chrome만 같은 제품으로 ── */
.shell-immersive {
  border: 0;
  background: var(--ui-bg-canvas);
  color: var(--ui-fg-strong);
  font-family: var(--ui-font-sans);
}
.shell-immersive .topbar {
  position: relative;
  z-index: 60;
  flex: none;
  border: 0;
  background: var(--ui-bg-canvas);
}
.shell-immersive .topbar__in--wide {
  height: 4.5rem;
  min-height: 4.5rem;
  padding: var(--ui-space-2) var(--ui-space-4);
  gap: var(--ui-space-3);
  border: 0;
  background: transparent;
}
.shell-immersive .topbar__doc {
  padding-left: var(--ui-space-3);
  border: 0;
}
.shell-immersive .topbar__doctitle {
  font-size: var(--ui-type-label);
  font-weight: var(--ui-font-weight-bold);
}
.shell-immersive .topbar__docmeta {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.ui-v2 .document-dates {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--ui-space-3);
  row-gap: var(--ui-space-1);
  font-family: var(--ui-font-sans);
  font-variant-numeric: tabular-nums;
}
.ui-v2 .document-dates > span { white-space: nowrap; }
/* Creation dates remain discoverable when document tools wrap on small screens. */
.shell-immersive .topbar--dated .topbar__in--wide {
  height: auto;
  flex-wrap: wrap;
}
.shell-immersive .topbar--dated .topbar__doc {
  display: flex;
  flex: 1 1 18rem;
}
.shell-immersive .topbar--dated .topbar__docmeta { line-height: 1.4; }
.shell-immersive .topbar--dated .topbar__docmeta.mono {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.shell-immersive .doc-action-error {
  flex: 1 0 100%;
  margin: 0;
  color: var(--ui-danger-default);
  font-size: var(--ui-type-caption);
  overflow-wrap: anywhere;
}
.shell-immersive .topbar :is(button, .btn):not(.topbar__toggle) {
  min-height: var(--ui-control-compact);
  height: auto;
  padding-inline: var(--ui-space-3);
  border: 0;
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
  color: var(--ui-fg-strong);
  box-shadow: inset 0 0 0 var(--ui-border-width) var(--ui-border-default);
}
.ui-v2.shell-immersive .topbar__in[data-nav-ready].is-nav-compact {
  flex-wrap: nowrap;
}
/* 패널은 nav 안에 살지만(패널의 기준점이 벨) 항목은 메뉴가 아니다 —
   `.ui-v2 .topbar nav a` 알약 규칙(inline-flex·44px·패딩)이 입혀지면 본문이 안 늘어나
   읽지 않음 점이 오른쪽 끝에 정렬되지 않는다(2026-08-24 실측; /notices 는 nav 밖이라 정상). */
.ui-v2 :is(.topbar, .ws-sb) nav .notice-panel a {
  display: flex; width: auto; min-height: 0;
  padding: 10px 12px; border-radius: 0; color: var(--ui-fg-default);
}
.ui-v2 :is(.topbar, .ws-sb) nav .notice-panel a.notice-item.is-new { color: var(--ui-fg-strong); }
.ui-v2 :is(.topbar, .ws-sb) nav .notice-panel a:hover { background: var(--ui-bg-subtle); color: var(--ui-fg-strong); }
.ui-v2 :is(.topbar, .ws-sb) nav .notice-panel a.notice-panel__all {
  display: inline-flex; padding: 4px 0; font-size: var(--ui-type-caption); color: var(--ui-fg-muted);
}
.ui-v2 :is(.topbar, .ws-sb) nav .notice-panel a.notice-panel__all:hover {
  background: none; color: var(--ui-fg-strong); text-decoration: underline;
}

/* ── 알림 KRDS 스킨 — 부품을 KRDS 이름으로 지목하고 값은 이 포털 토큰으로(저장소 규율:
   DESIGN-portal-ui.md:46 의 「KRDS Button/… 에 대응하는 실제 ui-button」 그 방식).
   app.css 의 알림 블록은 v1 바탕이고, 여기가 v2 화면의 옷이다. */

/* Badge / counter — 벨의 맨숫자를 배지로. */
.ui-v2 .topbar .notice-bell b {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.125rem; height: 1.125rem; padding: 0 0.3125rem;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-action-primary); color: var(--ui-color-white);
  font-size: var(--ui-type-caption); font-weight: var(--ui-font-weight-medium); line-height: 1;
}

/* Layer Popup — 패널 표면. 몰입 오버레이 메뉴와 같은 옷(radius-lg·overlay 그림자). */
.ui-v2 :is(.topbar, .ws-sb) .notice-panel {
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-overlay);
  overflow: hidden;                 /* 둥근 모서리를 항목 hover 가 뚫지 않게 */
}
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__head {
  padding: var(--ui-space-3) var(--ui-space-4);
  border-bottom: var(--ui-border-width) solid var(--ui-border-default);
}
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__title {
  font-size: var(--ui-type-label); font-weight: var(--ui-font-weight-bold);
  color: var(--ui-fg-strong);
}
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__group {
  padding: var(--ui-space-3) var(--ui-space-4) var(--ui-space-1);
  font-size: var(--ui-type-caption); color: var(--ui-fg-muted); letter-spacing: 0.02em;
}
.ui-v2 :is(.topbar, .ws-sb) nav .notice-panel a.notice-item {
  padding: var(--ui-space-3) var(--ui-space-4); gap: var(--ui-space-3);
  border-bottom: 0;                 /* 괘선 대신 리듬으로 가른다 — 줄이 많으면 창살이 된다 */
}
.ui-v2 :is(.topbar, .ws-sb) .notice-item__title { font-size: var(--ui-type-label); }
.ui-v2 :is(.topbar, .ws-sb) .notice-item__time { font-size: var(--ui-type-caption); }
.ui-v2 :is(.topbar, .ws-sb) .notice-item.is-new .notice-item__dot { background: var(--ui-action-primary); }
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__none { padding: var(--ui-space-6) var(--ui-space-4); }
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__more {
  padding: var(--ui-space-3) var(--ui-space-4);
  border-bottom: 0; border-top: var(--ui-border-width) solid var(--ui-border-default);
  color: var(--ui-fg-default);
}
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__more:hover { background: var(--ui-bg-subtle); color: var(--ui-fg-strong); }
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__foot {
  border-top: var(--ui-border-width) solid var(--ui-border-default);
}
.ui-v2 :is(.topbar, .ws-sb) .notice-panel__toggle { padding: var(--ui-space-3) var(--ui-space-4); }

/* Toggle Switch / small / labeled — 손잡이는 **궤도 요소 안**에 있다(버튼 기준 절대배치 금지).
   전에는 손잡이를 버튼 오른쪽 기준으로 놓았다가, 전역 표면 규칙
   (.ui-v2 :is(button):not(.ui-button) — 흰 pill·패딩 16px)이 버튼에 입혀지는 화면에서
   손잡이가 궤도를 16px 이탈해 **꺼짐이 켜짐 자리로 보였다**(2026-08-24 사용자 반려).
   궤도 안에 있으면 버튼이 어떤 옷을 입어도 기하가 안 어긋난다. */
.ui-v2 :is(.shell-workbench, .shell-reading, .shell-bare, .shell-immersive)
  :is(button.notice-panel__filter, button.notices-bar__filter) {
  background: none; padding: var(--ui-space-1) 0; border-radius: 0; box-shadow: none; min-height: 0;
}
.ui-v2 :is(.notice-panel__filter, .notices-bar__filter) {
  display: inline-flex; align-items: center; gap: var(--ui-space-2);
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: var(--ui-type-caption); color: var(--ui-fg-default);
}
.ui-v2 .notice-switch {
  position: relative; flex: none; width: 2.25rem; height: 1.25rem;
  border-radius: var(--ui-radius-pill); background: var(--ui-border-default);
  transition: background var(--ui-motion-fast) ease;
}
.ui-v2 .notice-switch::before {
  content: ""; position: absolute; top: 0.125rem; left: 0.125rem;
  width: 1rem; height: 1rem; border-radius: 50%; background: var(--ui-color-white);
  box-shadow: 0 0.0625rem 0.1875rem rgb(23 32 51 / 0.25);
  transition: left var(--ui-motion-fast) ease;
}
.ui-v2 :is([aria-checked="true"], [aria-pressed="true"]) > .notice-switch { background: var(--ui-action-primary); }
.ui-v2 :is([aria-checked="true"], [aria-pressed="true"]) > .notice-switch::before { left: calc(100% - 1.125rem); }
.ui-v2 :is(.notice-panel__filter[aria-checked="true"], .notices-bar__filter[aria-pressed="true"]) { color: var(--ui-fg-strong); }
.ui-v2 :is(.notice-panel__filter, .notices-bar__filter):focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); border-radius: var(--ui-radius-sm); }

/* /notices — 카드도 같은 옷. */
.ui-v2 .notices-box {
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-lg); overflow: hidden;
}
.ui-v2 .notices-box .notice-item { border-bottom: var(--ui-border-width) solid var(--ui-border-default); }
.ui-v2 .notices-box li:last-child .notice-item { border-bottom: 0; }
.ui-v2 .notices-box .notice-item.is-new .notice-item__dot { background: var(--ui-action-primary); }
.ui-v2 .notices-bar__filter { border-bottom: 0; }
.ui-v2 .notices-more { display: flex; justify-content: center; padding: var(--ui-space-3); }

/* ── 알림 양판(/notices — 좌 목록 + 우 상세, 2026-08-29) ─────────────────────
   배치 원전: Linear Inbox·Plane(미선택 「선택하면 보입니다」 빈 상태)·Square(상세=본문+메타
   필드 표) — Mobbin. 골격은 admin 2판(.admin)의 재사용이고, 좌판을 admin(3fr)보다 넓게 둔
   이유는 알림 행이 이름표가 아니라 제목 문장이라서다(Linear ≈1:2).
   재는 자는 뷰포트가 아니라 셸이다(@container portal-shell — design-system.css 의 main.wrap). */
.page-notices .notices-split {
  display: grid;
  grid-template-columns: minmax(18rem, 5fr) minmax(0, 7fr);
  gap: var(--ui-space-6);
  align-items: start;
}
.page-notices .notices-split > * { min-width: 0; }
/* app.css:1247 의 640px 상한 해제 — 양판에서는 격자가 폭을 정한다(안 풀면 좌판이 반쪽). */
.page-notices .notices-box { max-width: none; }
/* 긴 목록을 내려도 상세가 남는다 — admin 좌판(tnav)의 sticky 를 반대편에 쓴 것. */
.page-notices .notices-pane--detail { position: sticky; top: var(--ui-space-4); }
/* 선택 행 — admin .tnav__item[aria-current] 와 같은 값(선택의 어휘를 화면마다 새로 짓지 않는다).
   고른 상태는 채움에 **테를 더한다**(2026-09-21 `.talk__item.is-current` — WCAG 1.4.11 로 채널이 둘 필요했다). 이 줄과 admin tnav 도
   같은 테다 — 오너가 그 어휘를 포털 전체로 넓혔다(오너 결정 2 (2026-09-29) · DESIGN-portal-ui.md 「반복 규칙」의 고른 상태 줄). */
.page-notices .notice-item[aria-current] {
  background: var(--ui-action-primary-soft);
  color: var(--ui-action-primary-hover);
  box-shadow: var(--ui-selected-ring);
}
/* 폴더 소속 표에서 고른 폴더(folders.php ?b= · tr aria-current) — 보이는 표지가 하나도 없었다. 같은 선택 행의 옷을 행 전체에 두른다.
   이 표는 줄 선과 손 얹음 바탕을 칸이 그려(위 .ui-v2 … tbody td) 행의 채움·테를 덮으므로 고른 행에서는 칸의 것을 걷는다. */
.page-folders .folders-table tbody tr[aria-current] {
  background: var(--ui-action-primary-soft);
  box-shadow: var(--ui-selected-ring);
}
.page-folders .folders-table tbody tr[aria-current] > td,
.page-folders .folders-table tbody tr[aria-current]:hover > td {
  background: transparent;
  box-shadow: none;
}
.page-notices .notices-detail__back { display: none; }
/* ui-surface__header 는 가로 flex 다 — 상세 머리는 종류→제목→시각 세로 쌓임이 맞다(Square 형). */
.page-notices .notices-detail__head { display: flex; flex-direction: column; align-items: flex-start; gap: var(--ui-space-1); }
.page-notices .notices-detail__head h2 { margin: var(--ui-space-2) 0 0; font: var(--ui-type-card-title); }
.page-notices .notices-detail__kind {
  margin: 0; display: flex; align-items: center; gap: var(--ui-space-2);
  font: var(--ui-type-label); color: var(--ui-fg-muted);
}
.page-notices .notices-detail__meta { margin: var(--ui-space-1) 0 0; font: var(--ui-type-caption); color: var(--ui-fg-muted); }
.page-notices .notices-detail__excerpt { margin: 0 0 var(--ui-space-4); line-height: var(--ui-line-body); }
.page-notices .notices-detail__pre {
  margin: 0 0 var(--ui-space-4); padding: var(--ui-space-3);
  background: var(--ui-bg-subtle); border-radius: var(--ui-radius-md);
  overflow-x: auto; white-space: pre-wrap; word-break: break-word;
}
.page-notices .notices-detail__links-title { margin: var(--ui-space-4) 0 var(--ui-space-2); font: var(--ui-type-label); color: var(--ui-fg-muted); }
.page-notices .notices-detail__links { display: flex; flex-direction: column; gap: var(--ui-space-1); margin: 0 0 var(--ui-space-4); padding: 0; }
.page-notices .notices-detail__actions { margin-top: var(--ui-space-4); }

@container portal-shell (max-width: 55rem) {
  /* 1열 — sel 유무로 목록↔상세를 전환한다(서버 렌더 「← 목록으로」가 되돌아가는 문, JS 0). */
  .page-notices .notices-split { grid-template-columns: minmax(0, 1fr); }
  .page-notices .notices-pane--detail { position: static; }
  .page-notices .notices-split.has-sel .notices-pane--list { display: none; }
  .page-notices .notices-split:not(.has-sel) .notices-pane--detail { display: none; }
  .page-notices .notices-detail__back { display: inline-flex; margin-bottom: var(--ui-space-2); }
}

/* ── 문서함 — 폴더(테넌트) 카드와 자산 목록. KRDS 지목: 카드=Card(ui-surface) ·
   목록=List · 조작=ui-button. 새 옷을 만들지 않고 있는 부품으로 조립한다. */
.ui-v2 .docs-crumb { margin: 0 0 var(--ui-space-2); font-size: var(--ui-type-caption); }
.ui-v2 .docs-crumb a { color: var(--ui-fg-muted); text-decoration: none; }
.ui-v2 .docs-crumb a:hover { color: var(--ui-fg-strong); text-decoration: underline; }
.ui-v2 .docs-folders {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--ui-space-3);
}
.ui-v2 .docs-folder {
  display: flex; align-items: center; gap: var(--ui-space-3);
  padding: var(--ui-space-4); text-decoration: none; color: inherit;
}
.ui-v2 .docs-folder:hover { border-color: var(--ui-action-primary); }
.ui-v2 .docs-folder__brand {
  flex: none; width: 2.5rem; height: 2.5rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--ui-radius-md); background: var(--ui-bg-subtle); overflow: hidden;
}
.ui-v2 .docs-folder__logo { max-width: 100%; max-height: 100%; }
.ui-v2 .docs-folder__mono {
  font-weight: var(--ui-font-weight-bold); color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}
.ui-v2 .docs-folder__body { min-width: 0; }
.ui-v2 .docs-folder__name {
  display: block; font-weight: var(--ui-font-weight-medium); color: var(--ui-fg-strong);
  overflow-wrap: anywhere;
}
.ui-v2 .docs-folder__meta { display: block; font-size: var(--ui-type-caption); color: var(--ui-fg-muted); }

.ui-v2 .docs-section { margin-top: var(--ui-space-6); max-width: 52rem; }
.ui-v2 .docs-section__head h2 { display: flex; align-items: baseline; gap: var(--ui-space-2); }
.ui-v2 .docs-count { color: var(--ui-fg-muted); font-weight: var(--ui-font-weight-regular); font-size: var(--ui-type-label); }
.ui-v2 .docs-list {
  margin: 0; padding: 0; list-style: none;
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-lg); overflow: hidden; background: var(--ui-bg-surface);
}
.ui-v2 .docs-item {
  display: flex; align-items: center; gap: var(--ui-space-3);
  padding: var(--ui-space-3) var(--ui-space-4);
  color: var(--ui-fg-default); text-decoration: none;
  border-bottom: var(--ui-border-width) solid var(--ui-border-default);
}
.ui-v2 .docs-list li:last-child > .docs-item { border-bottom: 0; }
.ui-v2 a.docs-item:hover, .ui-v2 .docs-item a.docs-item__body:hover { background: var(--ui-bg-subtle); }
.ui-v2 .docs-item .i { flex: none; }
.ui-v2 .docs-item__body {
  flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem;
  color: inherit; text-decoration: none;
}
.ui-v2 .docs-item__title { color: var(--ui-fg-strong); overflow-wrap: anywhere; }
.ui-v2 .docs-item__meta { font-size: var(--ui-type-caption); color: var(--ui-fg-muted); }
.ui-v2 .docs-item__acts { display: flex; align-items: center; gap: var(--ui-space-2); flex: none; }
.ui-v2 .docs-item__acts form { margin: 0; }
.ui-v2 .docs-pager { margin-top: var(--ui-space-3); display: flex; align-items: center; gap: var(--ui-space-2); }
.ui-v2 .docs-note { font-size: var(--ui-type-caption); color: var(--ui-fg-muted); }

/* ── 고객사 홈(page-tenant-home) — `?t=N` ────────────────────────────────────
   본문 탐색기를 걷고(2026-08-25) 그 자리에 「다음에 할 일」이 선다. 목록은 사이드바
   나무가 갖고 여기는 밀린 일을 갖는다.

   ⚠ 이 절은 **배치만** 만든다. 알맹이(패널·표·알약·빈 상태·쪽나눔·검토 행)는 전부
     기존 부품이다 — .ui-surface · .admin-table · .ui-badge · .ui-empty-state ·
     .report-pager · .wiki-review-*. 여기서 그것들을 다시 그리면 두 번째 디자인
     시스템이 생긴다(시안 목업의 .panel/.d/.kind 를 **한 줄도 안 옮긴** 이유).
   ⚠ 값은 전부 --ui-* 토큰. 날 색·날 px 금지. */

/* 지표 넉 장 — 순서가 곧 우선순위다(실측: 확인할 지식 ≫ 문서 수). */
.ui-v2 .th-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--ui-space-3);
  margin-bottom: var(--ui-space-5);
}
/* 카드의 바탕·모서리·그림자는 **.ui-surface 가 준다**(마크업에서 같이 입힌다).
   여기서는 안쪽 배치만 정한다 — 손으로 다시 그리면 포털에서 이 넷만 납작해진다.

   .th-today__card 는 "오늘" 카드의 뿌리 이름이다(2026-09-02, KPI 벤토 심화) —
   lib/ui.php 의 ui_metric_tile(root_class) 가 낸다. 자식 요소(.th-metric__*)는
   뿌리와 상관없이 그대로 물려받으므로 여기서는 **뿌리 규칙만** 셀렉터를 나란히
   적어 공유한다 — 두 계열이 시각적으로 한 벤토처럼 보이는 이유가 이것이다. */
.ui-v2 .th-metric,
.ui-v2 .th-today__card {
  min-width: 0;
  padding: var(--ui-space-4);
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-2);
  transition: box-shadow var(--ui-motion-fast) var(--ui-ease-standard),
              transform var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 .th-metric:hover,
.ui-v2 .th-today__card:hover { box-shadow: var(--ui-shadow-overlay); transform: translateY(-1px); }
/* 밀린 일이 **있을 때만** 강조된다 — 0인 칸까지 물들면 강조가 신호를 잃는다.
   테두리 색 대신 왼쪽 강조 바로 준다: .ui-surface 의 그림자와 겹쳐 탁해지지 않는다. */
.ui-v2 .th-metric--hot,
.ui-v2 .th-today__card--hot { box-shadow: var(--ui-shadow-surface), inset 3px 0 0 0 var(--ui-action-primary); }
.ui-v2 .th-metric--hot:hover,
.ui-v2 .th-today__card--hot:hover { box-shadow: var(--ui-shadow-overlay), inset 3px 0 0 0 var(--ui-action-primary); }
.ui-v2 .th-metric__label {
  font-size: var(--ui-type-caption);
  color: var(--ui-fg-muted);
  letter-spacing: var(--ui-track-label);
}
.ui-v2 .th-metric__value {
  font-size: var(--ui-type-page-title);
  line-height: var(--ui-line-tight);
  color: var(--ui-fg-strong);
}
.ui-v2 .th-metric__value .ui-mono { font-size: inherit; }
.ui-v2 .th-metric__foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ui-space-2);
  font-size: var(--ui-type-caption);
  color: var(--ui-fg-muted);
}
.ui-v2 .th-metric__foot > span { min-width: 0; overflow-wrap: anywhere; }

/* 0 은 「0」이 아니라 「없음」으로 말한다 — 0표본이 성공처럼 보이면 안 된다. */
.ui-v2 .th-none { color: var(--ui-fg-muted); font-size: var(--ui-type-body); }

/* ── 추세 스파크(2026-09-02, 시안 C+D) — 값 옆에 붙는 손톱만한 막대 + 배지 ──────────
   `ui_trend_spark()`(lib/ui.php)가 이미 지은 HTML을 그대로 받는다. :has() 로 값 칸을
   조건부 flex 로 바꾼다 — trend 를 안 보내는 호출자(audit.php)는 이 규칙을 한 줄도 안 받는다.
   ⚠ 배지 색은 **방향(▲/▼)에 화행(좋다/나쁘다)을 안 싣는다** — 「발행 문서」는 ▲가 좋고
     「확인할 지식·안 답한 회신」은 ▲가 나쁘다. 한 함수가 세 화행을 다 맞히려면 지표별로
     길·흉을 아는 매개변수가 필요한데, 이번 시안은 그것까지는 묻지 않았다(추세의 유무·모양만
     본다). 그래서 화살표는 **방향만** 말하고 색은 중립(--ui-fg-muted)에 둔다 — 잘못된 신호를
     내는 것보다 신호를 하나 덜 내는 쪽이 안전하다. */
.ui-v2 .th-metric__value:has(.th-spark__wrap) {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
}
.ui-v2 .th-spark__wrap {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-1);
}
.ui-v2 .th-spark {
  display: block;
  inline-size: 2.9375rem; /* 47px = 7일 × (5+2)px − 2px — ui_trend_spark() 의 SVG 폭과 같다 */
  block-size: 1.375rem;   /* 22px = 그 SVG 의 viewBox 높이 */
  overflow: visible;
}
.ui-v2 .th-spark__bar { fill: var(--ui-border-default); }
.ui-v2 .th-spark__bar--now { fill: var(--ui-action-primary); }
.ui-v2 .th-spark__badge {
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-medium);
  color: var(--ui-fg-muted);
  white-space: nowrap;
}

/* ── 지표 3단 깊이(2026-09-02, 시안 C+D) — 「확인할 지식」만 독립된 줄에 세운다 ──────
   .th-kpis 가 그 줄(hero)과 나머지 셋(.th-metrics)을 세로로 쌓는다. 넉 장이 다시 한 줄로
   합쳐지는 축소 화면에서도(880px 아래, :2198) 순서만 유지하면 되므로 별도 처리가 없다.

   오늘 카드(.th-today__card)도 같은 3단 어휘를 쓴다(2026-09-02, KPI 벤토 심화) — 뿌리
   이름만 다르고(th-metric vs th-today__card) 규칙은 같아서, hero·hot 조합 셀렉터를
   두 뿌리로 나란히 적는다(위 :1996 주석과 같은 결). tier2 는 KPI 전용(아래)이다. */
.ui-v2.page-tenant-home .th-kpis {
  display: flex;
  flex-direction: column;
  gap: var(--ui-space-3);
}
/* `.th-metric.th-metric--hero` 로 겹쳐 쓴다 — 뒤(:2828)의 얇은판 처방과 명시도를
   맞세워 **선언 순서에 안 기댄다**(둘 다 클래스 3~4개, 순서가 바뀌면 뒤집힐 수 있었다). */
.ui-v2.page-tenant-home .th-metric.th-metric--hero,
.ui-v2.page-tenant-home .th-today__card.th-today__card--hero {
  padding: var(--ui-space-6);
  gap: var(--ui-space-3);
  box-shadow: var(--ui-shadow-overlay);
}
.ui-v2.page-tenant-home .th-metric.th-metric--hero .th-metric__label,
.ui-v2.page-tenant-home .th-today__card.th-today__card--hero .th-metric__label {
  font-size: var(--ui-type-label);
}
.ui-v2.page-tenant-home .th-metric.th-metric--hero.th-metric--hot,
.ui-v2.page-tenant-home .th-metric.th-metric--hero.th-metric--hot:hover,
.ui-v2.page-tenant-home .th-today__card.th-today__card--hero.th-today__card--hot,
.ui-v2.page-tenant-home .th-today__card.th-today__card--hero.th-today__card--hot:hover {
  box-shadow: var(--ui-shadow-overlay), inset 4px 0 0 0 var(--ui-action-primary);
}
/* 2단째(tier2, 2026-09-02) — 히어로보다는 낮지만 나머지 평판(.th-metrics 안 두 장)보다는
   도드라진다. KPI 「진행 중인 작업」전용(index.php) — .th-metrics 는 이미 grid(:1989)라
   열을 두 칸 접어 가로로 넓힌다. 글자 크기는 안 건든다(--ui-type-page-title 가 이미
   최댓값 토큰이라 더 못 키운다, 위 3단 깊이 규율 그대로). */
.ui-v2.page-tenant-home .th-metric--tier2 {
  grid-column: span 2;
  box-shadow: var(--ui-shadow-surface);
}

/* ── 패널을 격자에 **타일링**한다 (2026-08-25 사용자 「한 화면에 다 안 보인다」) ────
   전에는 2열(2fr 1fr)이라 좌열에 검토+세포가 쌓여 1,482px 이 됐고, 그 탓에 「일하고 있는
   세포」가 첫 화면 밖이었다(실측: 문서 4,283px → 검토 6줄로 줄여도 1,848px, 8/9).
   레퍼런스(Navattic 2열 6패널 · Asana 2×2 위젯)는 **쌓지 않고 탄다** — 폭이 남으면 열이
   늘어난다. auto-fit 이라 2560px 에서 셋, 좁아지면 둘, 더 좁으면 하나. */
.ui-v2 .th-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--ui-space-4);
  align-items: start;
}
.ui-v2 .th-col { min-width: 0; display: grid; gap: var(--ui-space-4); }

.ui-v2 .th-panel { padding-bottom: var(--ui-space-5); }
.ui-v2 .th-panel__head { align-items: baseline; }
.ui-v2 .th-panel__count { color: var(--ui-fg-muted); font-size: var(--ui-type-label); }
.ui-v2 .th-panel__more { margin-inline-start: auto; }
.ui-v2 .th-panel .ui-empty-state,
.ui-v2 .th-panel .ui-list,
.ui-v2 .th-panel .admin-table,
.ui-v2 .th-panel .th-chips,
.ui-v2 .th-panel .report-pager,
.ui-v2 .th-panel .docs-note { margin-inline: var(--ui-space-6); }
.ui-v2 .th-panel .ui-list,
.ui-v2 .th-panel .admin-table { margin-top: var(--ui-space-4); }
.ui-v2 .th-panel .report-pager,
.ui-v2 .th-panel .docs-note { margin-top: var(--ui-space-3); }

/* 갈래로 좁히기 — .ui-badge 를 **링크로** 쓴다(새 알약을 만들지 않는다). */
.ui-v2 .th-chips {
  margin-top: var(--ui-space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
}
.ui-v2 .th-chips .ui-badge { text-decoration: none; cursor: pointer; }
.ui-v2 .th-chips .ui-badge:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
/* 고른 갈래 — 주 색 채움이라 같은 색 안쪽 테가 안 보여 바깥 테다(오너 결정 2 (2026-09-29) · 인용 칩과 같은 처방).
   초점이 오면 위 초점 규칙(특이도가 높다)의 링이 같은 바깥 자리를 쓴다 — 핀 번호의 정적 채널과 같은 순서. */
.ui-v2 .th-chip--on {
  color: var(--ui-fg-inverse);
  background: var(--ui-action-primary);
  border-color: var(--ui-action-primary);
  box-shadow: var(--ui-selected-ring-outer);
}

/* 표는 관리 화면과 같은 자(.admin-table)를 쓰고, 여기서는 폭만 정한다. */
.ui-v2 .th-table { width: 100%; }
.ui-v2 .th-table__r { text-align: right; white-space: nowrap; }
.ui-v2 .th-who { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 정체(2026-09-10) — 업무 칸은 이름이 먼저, 식별번호는 뒤의 작은 회색 mono(원문은 title). 부제는 상태 알약 뒤 한 줄. */
.ui-v2 .th-ident { display: inline-flex; align-items: baseline; gap: var(--ui-space-1); min-width: 0; max-width: 100%; }
.ui-v2 .th-ident__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ui-v2 .th-ident__id { color: var(--ui-fg-muted); font-size: var(--ui-type-caption); flex: none; }
.ui-v2 .th-ident__sub { color: var(--ui-fg-muted); font-size: var(--ui-type-caption); }

.ui-v2 .th-latest {
  display: inline-block;
  color: var(--ui-fg-strong);
  font-weight: var(--ui-font-weight-medium);
  overflow-wrap: anywhere;
}

/* ── 표의 열 맞추기(2026-08-25 사용자 「열 안맞음」 지적) ──────────────────
   두 가지가 겹쳐 있었다.
   ① `table-layout: fixed` 를 **전 폭**에 걸어 2560px 에서 두 열이 50/50 이 됐다 —
      이름 뒤로 363px 빈 골이 생기고 날짜는 오른쪽 끝에 붙어 「안 맞은」 것으로 읽힌다.
      그 선언의 원래 목적은 390px 넘침이었으므로 **좁은 폭 전용**으로 내린다(아래 미디어).
   ② 셀이 패널 안쪽 여백 위에 **제 여백을 또** 얹어, 같은 패널의 .ui-facts 보다 오른쪽에서
      시작했다. 양 끝 여백을 걷어 패널의 왼쪽·오른쪽 선을 그대로 쓴다.
   그리고 날짜 열은 **내용 폭**으로 — fixed 아래에서 `2026.08.2` 처럼 잘리고 있었다(실측). */
/* ⚠ `auto` 로 풀면 안 된다 — 표가 max-content 로 부풀어 **10,030px** 이 됐다(실측).
   `fixed` 는 유지하되, 문제였던 「폭을 안 정하면 균등분할」을 **폭을 정해서** 없앤다:
   날짜·시각 열은 내용에 맞춘 고정 폭, 나머지는 첫 열이 가진다. */
.ui-v2 .th-panel .admin-table { table-layout: fixed; }
.ui-v2 .th-panel .admin-table :is(td, th) { overflow-wrap: anywhere; }
.ui-v2 .th-panel .admin-table :is(td, th):first-child { padding-inline-start: 0; }
.ui-v2 .th-panel .admin-table :is(td, th):last-child {
  padding-inline-end: 0;
  width: 7.5rem;             /* `2026.08.25` 가 안 잘리는 폭 — fixed 아래서 잘리고 있었다 */
  white-space: nowrap;
}
.ui-v2 .th-panel .admin-table .th-who { width: 7rem; }
/* 사람 × 일 표(2026-09-10) — 「진행 중인 작업」 절 아래. 같은 .admin-table 자를 쓰고 여기서는 위 여백만 준다. */
.ui-v2 .th-people { margin-block-start: var(--ui-space-4); }

/* ── AI 점검(077) — 마지막 칸을 날짜 폭에 못박지 않는다 ──────────────────────
   위 `:last-child { width: 7.5rem; white-space: nowrap }` 는 **날짜 칸**을 위해 만든 규칙인데
   `.th-panel` 안의 모든 표에 걸린다. 점검 화면의 마지막 칸은 날짜가 아니라 경로·절 목록·배지라
   120px 에 묶이면 넘친다 — 실측(2026-08-27, 390/880/1440/2560 네 폭 훑기): 「가리키는 문서가
   없는 연결」 표가 **2560px 에서도 103px 넘쳤다.** 본문 가로 스크롤은 그릇(.ui-data-region)이
   막아 0이었지만, 넓은 화면에서 굳이 옆으로 밀어 읽게 할 이유가 없다.
   폭만 풀고 `table-layout: fixed` 와 첫 칸 규칙은 그대로 둔다. */
.ui-v2.page-audit .th-panel .admin-table :is(td, th):last-child {
  width: auto;
  white-space: normal;
}
/* 표 행도 손이 닿는 곳이면 반응한다(마이크로인터랙션). */
.ui-v2 .th-panel .admin-table tbody tr {
  transition: background-color var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 .th-panel .admin-table tbody tr:hover { background: var(--ui-bg-subtle); }

/* ── AI 점검 밀도판(077) — 배치만 만든다. 알맹이는 전부 기존 부품
   (.th-split/.th-col :1964-1972 · .th-chips+.ui-badge :1986-1994 · .ui-status · ui_facts).
   ⚠ body 에 .ui-v2 와 .page-audit 이 나란히 붙는다 — «.ui-v2 .page-audit …» 자손꼴은
     죽은 선택자다. 접두는 .page-audit 하나.
   레퍼런스: 2열 카드 격자 = Supabase Observability(mobbin 704ea722-33ea-44f5-ba70-03005b33a9f9) ·
   추이 3열 = Vercel Analytics(mobbin 3e9a83fd-47b4-4968-88e0-6b0c1cb16b39) ·
   판정 먼저 상세 나중 = OpenAI Service health(mobbin d605f83d-3869-4ecc-8874-b913e09e2930). */

/* 지표 띠를 얇게 — tenant-home 처방과 동형, 스코프만 이 화면. */
.page-audit .th-metrics { margin-bottom: var(--ui-space-4); }
.page-audit .th-metric { padding: var(--ui-space-3) var(--ui-space-4); gap: var(--ui-space-1); }

/* 점프 띠 — 패널 밖(카드 아래)에 서므로 위 여백을 걷고 아래만 준다(기본 :1988 은 margin-top). */
.page-audit .th-chips { margin: 0 0 var(--ui-space-4); }

/* 패널 안 소제목은 패널 제목과 급이 달라야 위계가 선다(기본 design-system.css:473 은 card-title 급). */
.page-audit .th-panel h3.ui-section__title {
  font-size: var(--ui-type-label);
  color: var(--ui-fg-muted);
}

/* 추이 셋을 옆으로 — 좁으면 auto-fit 이 스스로 접는다(:2082-2085 의 규칙, 열 수 수동 금지). */
.page-audit .audit-trend {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--ui-space-4);
}

/* 판정 폼 — audit.php 인라인 style 의 이사. gap 은 .ui-actions 기본(design-system.css:553)이 준다. */
.page-audit .th-panel td .ui-actions { display: inline-flex; }

/* 사실 목록을 좁은 셸에서 한 열로 — 기존 낙하(:2097)는 .page-tenant-home 스코프라 여기 안
   미친다(감사의 긴 라벨이 390px 에서 값 칸을 짓누른다). 재는 자는 뷰포트가 아니라 셸이다
   (@container portal-shell — design-system.css:212 main.wrap). */
@container portal-shell (max-width: 36rem) {
  .page-audit .ui-facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .page-audit .ui-facts dd { margin-bottom: var(--ui-space-3); }
}

/* ── 마이크로인터랙션(2026-08-25 사용자 지적) ──────────────────────────────
   토큰은 이미 있었는데(--ui-motion-* · --ui-ease-*) 이 화면의 부품이 하나도 안 썼다.
   손이 닿는 곳은 닿았다고 말한다 — hover 는 바탕, 키보드는 초점 링. 값은 전부 토큰. */
/* 검토 행은 이미 바탕이 --ui-bg-subtle 이라 같은 색으로 hover 하면 **아무 일도 안 일어난다**.
   그래서 반대로 **떠오르게** 한다 — 서피스 색 + 얕은 그림자. */
.ui-v2.page-tenant-home .wiki-review-item {
  transition: background-color var(--ui-motion-fast) var(--ui-ease-standard),
              box-shadow var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2.page-tenant-home .wiki-review-item:hover {
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-surface);
}
.ui-v2.page-tenant-home .ui-facts dd { transition: color var(--ui-motion-fast) var(--ui-ease-standard); }
.ui-v2 .th-latest {
  transition: color var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 .th-latest:hover { color: var(--ui-action-primary); text-decoration: underline; }
.ui-v2 .th-latest:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); border-radius: var(--ui-radius-sm); }
.ui-v2 .th-panel__more { transition: color var(--ui-motion-fast) var(--ui-ease-standard); }

/* ── 카드 진입(2026-09-02, KPI 벤토 심화) — `lim-title-reveal`(session.css:2212)과
   같은 조합(opacity+translateY), `lim-card-in`(session.css:1238)과 같은 nth-child
   스태거 — 둘 다 JS 없이 페이지 로드와 함께 그대로 재생된다(animation-fill-mode:both
   가 첫 프레임부터 「from」 상태를 보장해 깜빡임·순간노출이 없다). 이 화면 소유의 새
   키프레임 **하나**만 늘렸다.

   오늘 그리드와 KPI 그리드는 서로 다른 부모라 전역 한 셈으로 못 센다 — 그래서 두
   그룹이 **각자** 0ms 부터 스태거한다(오늘 최대 4장 · KPI 히어로+나머지 3장). 항목
   수가 가변(0~4)인 오늘 쪽에 고정 오프셋을 주면 KPI 진입이 억지로 늦어지는 문제라
   하나로 안 잇는다 — 두 계단이어도 화면은 위→아래로 읹으므로 자연스럽다. */
.ui-v2.page-tenant-home :is(.th-metric, .th-today__card) {
  animation: th-kpi-in var(--ui-motion-enter) var(--ui-ease-enter) both;
}
.ui-v2.page-tenant-home .th-today__grid > .th-today__card:nth-child(2),
.ui-v2.page-tenant-home .th-kpis__rest > .th-metric:nth-child(1) { animation-delay: var(--ui-motion-stagger); }
.ui-v2.page-tenant-home .th-today__grid > .th-today__card:nth-child(3),
.ui-v2.page-tenant-home .th-kpis__rest > .th-metric:nth-child(2) { animation-delay: calc(var(--ui-motion-stagger) * 2); }
.ui-v2.page-tenant-home .th-today__grid > .th-today__card:nth-child(4),
.ui-v2.page-tenant-home .th-kpis__rest > .th-metric:nth-child(3) { animation-delay: calc(var(--ui-motion-stagger) * 3); }
@keyframes th-kpi-in {
  from { opacity: 0; transform: translateY(0.25rem); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── 스파크라인 hover 분해(2026-09-02) — Layer Popup 계보(workspace.css:428 의
   `.ws-row__menu.is-popup` 표면 — border·radius·표면색·그림자를 그대로 물려받는다)를
   입힌다. 스파크라인은 지금도 aria-hidden 이고 같은 정보가 title 로 이미 나가 있다
   (ui_trend_spark() 의 wrap) — 이 말풍선은 마우스 보강일 뿐 접근성 필수 경로가
   아니다(th-kpis.js 가 연다). */
.th-spark__tip {
  position: fixed;
  z-index: 60;
  padding: var(--ui-space-1) var(--ui-space-2);
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-sm);
  background: var(--ui-bg-surface);
  color: var(--ui-fg-default);
  box-shadow: var(--ui-shadow-overlay);
  font-size: var(--ui-type-caption);
  white-space: nowrap;
  pointer-events: none;
}

/* 움직임을 원치 않는 사람에게는 움직이지 않는다. 상태 변화(색·링)는 남는다. */
@media (prefers-reduced-motion: reduce) {
  .ui-v2 :is(.th-metric, .th-today__card, .th-latest, .th-panel__more, .report-pager__num,
             .page-tenant-home .wiki-review-item, .th-panel .admin-table tbody tr) {
    transition-duration: 0s;
  }
  .ui-v2 :is(.th-metric, .th-today__card):hover { transform: none; }
  .ui-v2.page-tenant-home :is(.th-metric, .th-today__card) { animation: none; }
}

@media (max-width: 880px) {
  /* 여기서 열 수를 손으로 정하지 않는다 — `auto-fit` 이 폭에 맞춰 스스로 접는다.
     손으로 1열을 강제하면 880px 에서 자리가 남아도 한 줄로 떨어진다(실측). */
}
@media (max-width: 560px) {
  /* 좁은 폭에서는 고정 폭이 본문을 먹는다 — 날짜 열을 좁히고 줄바꿈을 허용한다. */
  .ui-v2 .th-panel .admin-table :is(td, th):last-child { width: 5.5rem; white-space: normal; }
  .ui-v2 .th-panel .admin-table .th-who { width: 5rem; }
  /* 좁은 폭에서는 안쪽 여백이 본문을 다 먹는다 — 줄이고, 속성 목록은 한 열로 쌓는다. */
  .ui-v2 .th-panel .ui-empty-state,
  .ui-v2 .th-panel .ui-list,
  .ui-v2 .th-panel .admin-table,
  .ui-v2 .th-panel .th-chips,
  .ui-v2 .th-panel .report-pager,
  .ui-v2 .th-panel .docs-note { margin-inline: var(--ui-space-4); }
  .ui-v2.page-tenant-home .ui-facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .ui-v2.page-tenant-home .ui-facts dd { margin-bottom: var(--ui-space-3); }
  .ui-v2 .th-metric__foot { flex-wrap: wrap; }
}

.ui-v2 .docs-upload { padding: var(--ui-space-4); margin-bottom: var(--ui-space-3); }
.ui-v2 .docs-upload__label {
  display: block; font-size: var(--ui-type-caption); color: var(--ui-fg-muted);
  margin-bottom: var(--ui-space-2);
}
.ui-v2 .docs-upload__row { display: flex; align-items: center; gap: var(--ui-space-2); flex-wrap: wrap; }
.ui-v2 .docs-upload__state {
  margin: var(--ui-space-2) 0 0; min-height: 1.2em;
  font-size: var(--ui-type-caption); color: var(--ui-fg-muted);
}
.ui-v2 .docs-upload__state.is-error { color: var(--ui-danger-default); }

/* ── 만들기 모달 · 드롭존 · 파일 카드 (2026-08-25) ──────────────────────────
   사용자 지적: 「안눌러봤으면 큰일날 뻔. 밀도 개판이네. 첨부된 사진 수준의 밀도는 되어야
   되는 게 정상이야.」 그 사진(파일 가져오기 모달)의 배치를 따른다 — 파선 드롭존에 아이콘과
   **받는 형식·상한**, 고른 뒤에는 이름·크기·지우기와 **진행률 막대**. 우리에게 없는 것
   (URL 가져오기·여러 파일)은 안 만든다. */
/* 폭은 **dialog** 가 갖는다(`.ui-modal[open] { inline-size: min(--ui-modal-inline-max, …) }`).
   표면에 width 를 주면 dialog 밖으로 삐져나가 잘린다(실측: 오른쪽 90px 가 잘렸다).
   그래서 시스템의 손잡이를 그대로 돌린다. */
.ui-v2 .ui-modal--create { --ui-modal-inline-max: 34rem; }
/* 제목과 닫기가 한 줄에 — 기본 헤더는 블록이라 ✕ 가 아래로 떨어진다. */
.ui-v2 .ui-modal--create .ui-modal__header {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  padding-block-end: var(--ui-space-2);
}
.ui-v2 .ws-tree__close {
  all: unset;
  margin-inline-start: auto;
  width: var(--ui-control-compact);
  height: var(--ui-control-compact);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ui-radius-sm);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-card-title);
  cursor: pointer;
  transition: background-color var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 .ws-tree__close:hover { background: var(--ui-bg-subtle); color: var(--ui-fg-strong); }
.ui-v2 .ws-tree__close:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }

/*
 * 드롭존 — label 이 존 전체를 덮어 어디를 눌러도 파일 창이 열린다.
 *
 * 2026-09-01 재작업: GPT Image 2 로 뽑은 시안을 **참고가 아니라 목표**로 다시 잡는다
 * (사용자 지적 — 「참고용으로 뽑자는 게 아니었음」). 그 시안과 견줘 이 존이 실제로
 * 갖던 것은 여백이 촘촘한 **한 줄짜리** 아이콘+이름이었다. 시안은 갈래마다
 * 아이콘이 **위**, 이름이 **아래**로 쌓인 두 줄짜리 칸이고, 전체 여백도 훨씬 넉넉하다.
 * 아래가 그 구조로 다시 짠 것이다 — gap·padding 값은 이 디자인 시스템의 토큰 중
 * 시안의 비례에 가장 가까운 것을 고른 것이지 시안의 픽셀을 그대로 옮긴 것은 아니다
 * (이 모달은 폭이 고정이라 그 안에서 늘릴 수 있는 것은 안쪽 여백·글자 크기뿐이다).
 */
.ui-v2 .docs-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ui-space-4);
  padding: var(--ui-space-8) var(--ui-space-5);
  border: 2px dashed var(--ui-border-default);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--ui-motion-fast) var(--ui-ease-standard),
              background-color var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 .docs-drop:hover,
.ui-v2 .docs-drop.is-over {
  border-color: var(--ui-action-primary);
  background: var(--ui-bg-surface);
}
/* 시안의 크고 또렷한 화살표 — 기본 14px 로는 이 존의 첫 시선을 못 붙잡는다. */
.ui-v2 .docs-drop__icon { color: var(--ui-action-primary); }
.ui-v2 .docs-drop__icon .i { width: var(--ui-space-8); height: var(--ui-space-8); }
.ui-v2 .docs-drop__lead { color: var(--ui-fg-strong); font-size: var(--ui-type-body); }
.ui-v2 .docs-drop__lead b { color: var(--ui-action-primary); }
/* 받는 형식과 상한을 **그 자리에서** 말한다 — 전에는 data-* 로만 갖고 있어
   사람이 시도해 실패한 뒤에야 알았다. */
.ui-v2 .docs-drop__hint { display: flex; flex-direction: column; align-items: center; gap: var(--ui-space-3);
  color: var(--ui-fg-muted); font-size: var(--ui-type-caption); }
/* 형식 갈래 — 갈래마다 아이콘이 **위**, 이름이 **아래**(시안의 두 줄 칸). */
.ui-v2 .docs-drop__kinds {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start;
  gap: var(--ui-space-5);
}
.ui-v2 .docs-drop__kind {
  display: flex; flex-direction: column; align-items: center; gap: var(--ui-space-2);
  position: relative;
  color: var(--ui-fg-muted); font-size: var(--ui-type-label);
}
.ui-v2 .docs-drop__kind .i { width: var(--ui-space-5); height: var(--ui-space-5); }
/* 칩 사이 세로 구분선 — 시안에서 가져온 것. gap 정가운데에 오도록 반값을 왼쪽으로 뺀다. */
.ui-v2 .docs-drop__kind + .docs-drop__kind::before {
  content: ''; position: absolute; left: calc(var(--ui-space-5) / -2); top: 0; bottom: 0;
  width: var(--ui-border-width); background: var(--ui-border-default);
}
.ui-v2 .docs-upload__input:focus-visible + .docs-drop { outline: 0; box-shadow: var(--ui-focus-ring); }

/* 고른 파일 카드 */
.ui-v2 .docs-file {
  margin-top: var(--ui-space-3);
  padding: var(--ui-space-3);
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
}
.ui-v2 .docs-file__icon { flex: none; color: var(--ui-fg-muted); }
.ui-v2 .docs-file__body { min-width: 0; flex: 1; display: grid; gap: var(--ui-space-1); }
.ui-v2 .docs-file__name {
  min-width: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-label);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-v2 .docs-file__meta { color: var(--ui-fg-muted); font-size: var(--ui-type-caption); }
.ui-v2 .docs-file__bar {
  height: var(--ui-space-2);
  border-radius: var(--ui-radius-pill);
  background: var(--ui-bg-subtle);
  overflow: hidden;
}
.ui-v2 .docs-file__fill {
  display: block;
  height: 100%;
  background: var(--ui-action-primary);
  transition: width var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 .docs-file__pct { flex: none; color: var(--ui-fg-muted); font-size: var(--ui-type-caption); }
.ui-v2 .docs-file__x {
  all: unset;
  flex: none;
  width: var(--ui-control-compact);
  height: var(--ui-control-compact);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ui-radius-sm);
  color: var(--ui-fg-muted);
  cursor: pointer;
  transition: background-color var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 .docs-file__x:hover { background: var(--ui-bg-subtle); color: var(--ui-danger-default); }
.ui-v2 .docs-file__x:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }

/* 「또는」 — 두 길(올리기 / 새 폴더)을 가르는 선. 레퍼런스의 그 구분자다. */
.ui-v2 .ws-tree__or {
  margin: var(--ui-space-5) 0 var(--ui-space-4);
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.ui-v2 .ws-tree__or::before,
.ui-v2 .ws-tree__or::after {
  content: '';
  flex: 1;
  height: var(--ui-border-width);
  background: var(--ui-border-default);
}
.ui-v2 .ui-modal--create .ws-tree__newdir { display: flex; gap: var(--ui-space-2); }
.ui-v2 .ui-modal--create .ws-tree__newdir .ui-input { flex: 1; min-width: 0; }

/*
 * 행 메뉴의 이름 바꾸기·새 폴더 제출 단추 — 화면엔 안 보이지만 탭으로는 닿는다(2026-09-01).
 * 입력 하나짜리 이 폼은 Enter 로 이미 나간다(popup.js 머리말·docs-drive.test.mjs 의 성공
 * 절이 클릭이 아니라 Enter 를 쓰는 것이 그 증거). `.ui-visually-hidden` 하나만 얹으면
 * 안 먹는다 — `.ui-button--compact` 의 min-height·padding 이 **더 뒤에** 있어 그 뒤에
 * 이긴다(실측: 얹었더니 면적이 0 이 아니라 864 였다). 그래서 이 자리에서 그 둘을 다시 죽인다.
 */
.ui-v2 .ws-row__rename button[type="submit"].ui-visually-hidden {
  width: 1px !important; height: 1px !important;
  min-width: 0 !important; min-height: 0 !important;
  padding: 0 !important; border: 0 !important; gap: 0 !important;
}

@media (prefers-reduced-motion: reduce) {
  .ui-v2 :is(.docs-drop, .docs-file__fill, .docs-file__x, .ws-tree__close) { transition-duration: 0s; }
}

/* 레일 속 문서함 — 파일 절은 레일 안에 산다(별도 페이지 금지). 좁은 폭 전용 결. */
.ui-v2 .rail__scope {
  display: block; font-size: var(--ui-type-caption);
  color: var(--ui-fg-strong); font-weight: var(--ui-font-weight-medium);
}
.ui-v2 .docs-files {
  margin-top: var(--ui-space-3); padding: var(--ui-space-2) var(--ui-space-1) 0;
  border-top: var(--ui-border-width) solid var(--ui-border-default);
  /* 레일 머리는 grid — 자식이 min-width:auto 로 부풀면 긴 파일명 하나가 레일을 621px 로
     밀어 올리기·✕·페이저가 화면 밖으로 죽는다(거시 검토 실측). */
  min-width: 0; max-width: 100%;
}
.ui-v2 .docs-file { min-width: 0; }
.ui-v2 .docs-files__head {
  margin: 0 0 var(--ui-space-2); display: flex; align-items: baseline; gap: var(--ui-space-1);
  font-size: var(--ui-type-caption); color: var(--ui-fg-muted);
  font-weight: var(--ui-font-weight-medium);
  cursor: pointer; list-style: none;
}
.ui-v2 .docs-files__head::-webkit-details-marker { display: none; }
/* 표지는 공용 셰브런(.ui-chevron — 오너 결정 5, 2026-09-29). 이 머리는 flex 라 제 틈(space-1)이 있다 — 끝 여백을 그만큼
   덜어 질문 화면의 간격(여백 + 틈 = space-3)에 맞춘다. */
.ui-v2 .docs-files__head::before { margin-inline-end: var(--ui-space-2); }
.ui-v2 .docs-files__head:hover { color: var(--ui-fg-strong); }
.ui-v2 .docs-files__none { margin: 0 0 var(--ui-space-2); font-size: var(--ui-type-caption); color: var(--ui-fg-muted); }
.ui-v2 .docs-files__list {
  list-style: none; margin: 0; padding: 0;
  /* sticky 머리 안에 살므로 제 키를 가진다 — 파일 16개면 문서 목록이 매장되던 것(실측). */
  max-height: 9.5rem; overflow-y: auto;
}
.ui-v2 .docs-file { display: flex; align-items: center; gap: var(--ui-space-1); }
.ui-v2 .docs-file__body {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: var(--ui-space-2);
  padding: var(--ui-space-1); border-radius: var(--ui-radius-sm);
  color: var(--ui-fg-default); text-decoration: none;
}
.ui-v2 .docs-file__body:hover { background: var(--ui-bg-subtle); color: var(--ui-fg-strong); }
.ui-v2 .docs-file__body .i { flex: none; }
.ui-v2 .docs-file__name {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--ui-type-caption);
}
.ui-v2 .docs-file__meta { flex: none; font-size: var(--ui-type-caption); color: var(--ui-fg-muted); }

/* 문서함 파일 미리보기 — 링크가 file.php 로 앱을 떠나지 않고, main#content 안에 선다. */
.ui-v2 .docs-preview {
  min-width: 0;
  overflow: hidden;
}
.ui-v2 .docs-preview__head {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  padding: var(--ui-space-5) var(--ui-space-6);
  border-bottom: var(--ui-border-width) solid var(--ui-border-default);
}
.ui-v2 .docs-preview__icon {
  flex: none;
  color: var(--ui-fg-muted);
}
.ui-v2 .docs-preview__title {
  min-width: 0;
  flex: 1 1 auto;
  display: grid;
  gap: var(--ui-space-1);
}
.ui-v2 .docs-preview__title h1 {
  margin: 0;
  overflow: hidden;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-card-title);
  font-weight: var(--ui-font-weight-bold);
  line-height: var(--ui-line-tight);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-v2 .docs-preview__meta {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.ui-v2 .docs-preview__body {
  min-height: min(70vh, 52rem);
  background: var(--ui-bg-subtle);
}
.ui-v2 .docs-preview__frame {
  display: block;
  width: 100%;
  height: min(74vh, 56rem);
  border: 0;
  background: var(--ui-bg-surface);
}
.ui-v2 .docs-preview__image {
  display: block;
  max-width: 100%;
  max-height: min(74vh, 56rem);
  margin: 0 auto;
  object-fit: contain;
}
.ui-v2 .docs-preview__empty {
  min-height: min(58vh, 34rem);
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--ui-space-3);
  padding: var(--ui-space-8);
  text-align: center;
}
.ui-v2 .docs-preview__empty-icon {
  color: var(--ui-fg-muted);
}
.ui-v2 .docs-preview__empty h2 {
  margin: 0;
  color: var(--ui-fg-strong);
  font-size: var(--ui-type-card-title);
}
.ui-v2 .docs-preview__empty p {
  max-width: 28rem;
  margin: 0;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-label);
}
.ui-v2 .docs-file__del { margin: 0; }
.ui-v2 .docs-file__x {
  border: 0; background: none; cursor: pointer; padding: var(--ui-space-1);
  color: var(--ui-fg-muted); font-size: var(--ui-type-label); line-height: 1;
  border-radius: var(--ui-radius-sm);
}
.ui-v2 .docs-file__x:hover { color: var(--ui-danger-default); background: var(--ui-bg-subtle); }
.ui-v2 .rail .docs-upload { padding: 0 0 var(--ui-space-2); margin: 0; }
/* 한 줄 grid — [파일 선택][이름(줄임)][올리기]. flex wrap 은 올리기를 아랫줄로 떨궜다. */
.ui-v2 .rail .docs-upload__row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--ui-space-2);
}
/* 파일 입력은 숨긴다 — 보이는 것은 ui-button 라벨과 선택된 이름뿐(기본 Choose File 금지). */
.ui-v2 .docs-upload__input {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.ui-v2 .docs-upload__input:focus-visible + label { outline: 0; box-shadow: var(--ui-focus-ring); }
.ui-v2 .docs-upload__row label { cursor: pointer; }
.ui-v2 .docs-upload__name {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--ui-type-caption); color: var(--ui-fg-muted);
}

/* 리더 레일의 문서함 손잡이 — 목록 항목과 같은 결, 방향은 위로. */
.ui-v2 .rail__home {
  display: inline-flex; align-items: center; gap: var(--ui-space-1);
  font-size: var(--ui-type-caption); color: var(--ui-fg-muted); text-decoration: none;
  margin-bottom: var(--ui-space-1);
}
.ui-v2 .rail__home:hover { color: var(--ui-fg-strong); text-decoration: underline; }
/* 몰입 셸은 topbar 의 모든 버튼에 도구 상자 옷을 입힌다(위 :is(button,.btn) 규칙) —
   알림 패널 **안** 버튼은 패널의 부품이지 도구가 아니므로 벗긴다. */
.ui-v2.shell-immersive .topbar .notice-panel :is(button, .btn) {
  min-height: 0; height: auto; padding-inline: 12px;
  border-radius: 0; background: none; box-shadow: none; color: var(--ui-fg-default);
}
/* 스위치(거르개)는 제 패딩을 지킨다 — 오른쪽 패딩이 붙으면 손잡이가 궤도에서 어긋난다. */
.ui-v2.shell-immersive .topbar .notice-panel .notice-panel__filter { padding: var(--ui-space-1) 0; }
/* 특이도를 design-system.css 의 접힘 규칙(width:100%)보다 한 단 높인다 — 낮으면 폭이 100vw 가
   되어 메뉴가 왼쪽으로 16px 넘친다(390px 실측: left −16). */
.ui-v2.shell-immersive .topbar__in[data-nav-ready].is-nav-compact nav[data-collapsible] {
  position: absolute;
  top: calc(100% + var(--ui-space-2));
  right: var(--ui-space-4);
  width: min(28rem, calc(100vw - var(--ui-space-8)));
  max-height: min(70dvh, 32rem);
  overflow-y: auto;
  padding: var(--ui-space-2);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-overlay);
}
.shell-immersive .reader {
  min-height: 0;
  gap: var(--ui-space-2);
  padding: 0 var(--ui-space-2) var(--ui-space-2);
  background: var(--ui-bg-canvas);
}
.shell-immersive .rail,
.shell-immersive .stage,
.shell-immersive .talk:not([hidden]) {
  border: 0;
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface);
  box-shadow: var(--ui-shadow-surface);
  overflow: hidden;
}
.shell-immersive .rail {
  overflow-y: auto;
}
.shell-immersive .rail__head {
  padding: var(--ui-space-3);
  border: 0;
  background: var(--ui-bg-surface);
  color: var(--ui-fg-muted);
}
.shell-immersive .rail__range {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  font-weight: var(--ui-font-weight-regular);
  letter-spacing: 0;
}
.shell-immersive .rail__pager {
  width: 100%;
}
.shell-immersive .stage:focus-visible {
  outline: 0;
  box-shadow: var(--ui-focus-ring);
}
.shell-immersive .rail__item {
  margin: 0 var(--ui-space-2);
  padding: var(--ui-space-3);
  border: 0;
  border-radius: var(--ui-radius-md);
}
.shell-immersive .rail__item:hover {
  background: var(--ui-bg-subtle);
  box-shadow: none;
}
.shell-immersive .rail__item[aria-current] {
  background: var(--ui-action-primary-soft);
  color: var(--ui-action-primary-hover);
  box-shadow: var(--ui-selected-ring);
}
.shell-immersive .rail__group {
  color: var(--ui-fg-muted);
}
.shell-immersive .talk:not([hidden]) {
  border: 0;
}
.shell-immersive .talk__head {
  border: 0;
}

/* ── 나란히 보기(2026-09-08) — 같은 문서를 오른쪽 자리에 한 번 더 ──────────────────
 * 배치 원전(Mobbin): v0 「Splitting an editor」(같은 파일 두 자리·50/50·1px 선+가운데 손잡이) ·
 * Obvious 「Open in split view」(새 내용은 오른쪽, 왼쪽은 그대로) · Mistral Document Intelligence
 * (자리마다 제 머리·제 스크롤) · Perplexity 「Adjusting a layout」(끌어서 폭). 자리 머리는 셸이
 * 세우지 않는다 — 문서 자신의 sticky 64px 머리띠(PART·절)가 자리마다 이미 있고, 셸은 sandbox 라
 * 자리 안을 못 읽는다(적으면 거짓 띠). app.css 는 동결 — `.stage{position:relative}`(app.css) 는
 * 그대로 두고 자리에 position:relative 를 줘서 arriving 의 `.stage__doc--next`(absolute; inset:0) 가
 * **그 자리만** 덮게 한다. 상태 클래스 `.is-split`·`.is-resizing` 의 소비자는 이 절뿐이다. */
.shell-immersive .stage__pane {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* 숨김은 design-system.css 의 `.ui-v2 [hidden]{display:none!important}` 가 처리한다 — 이 두 줄은 .ui-v2
   밖(옛 셸 클래스)에서도 위의 display:flex 가 [hidden] 을 이기지 못하게 하는 대비다. */
.shell-immersive .stage__pane[hidden],
.shell-immersive .stage__split[hidden] { display: none; }
.shell-immersive .stage.is-split {
  flex-direction: row;          /* app.css 의 .stage 는 column — 자리가 둘일 때만 가로 */
  --stage-split: 50;            /* 왼쪽 자리 몫(%) — split.js 가 덮어쓴다 */
}
.shell-immersive .stage.is-split .stage__pane--a {
  flex: 0 0 calc((100% - 0.625rem) * var(--stage-split) / 100);
}
.shell-immersive .stage.is-split .stage__pane--b { flex: 1 1 0; }
/* 상호참조가 오른쪽 자리로 갔음을 눈에 알린다 — iframe 이 자리를 다 덮으므로 위에 얹은 가짜 요소의
   안쪽 테두리가 한 번 빛난다(split.js jumpB 가 .is-jump 를 단다). 포인터는 안 막는다. */
.shell-immersive .stage__pane--b::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  box-shadow: inset 0 0 0 3px var(--ui-action-primary);
  opacity: 0;
}
.shell-immersive .stage__pane--b.is-jump::after { animation: split-jump var(--ui-motion-feedback) var(--ui-ease-standard); }
@keyframes split-jump { 0% { opacity: 1; } 100% { opacity: 0; } }
/* 움직임 줄임: 빛나지 않고 정지 테두리가 머문다(split.js 가 520ms 뒤 .is-jump 를 뗀다). */
@media (prefers-reduced-motion: reduce) { .shell-immersive .stage__pane--b.is-jump::after { animation: none; opacity: 1; } }

/* 분할선 — .work-gantt-nav__resize(session.css) 계보: 10px 히트영역 · 2px 선 · 가운데 짧은 손잡이. */
.shell-immersive .stage__split {
  position: relative;
  flex: none;
  inline-size: 0.625rem;
  background: transparent;
  cursor: col-resize;
  touch-action: none;
}
.shell-immersive .stage__split::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(50% - 0.0625rem);
  inline-size: 0.125rem;
  background: var(--ui-border-default);
}
.shell-immersive .stage__split::after {
  content: "";
  position: absolute;
  top: 50%;
  inset-inline-start: calc(50% - 0.125rem);
  inline-size: 0.25rem;
  block-size: 2rem;
  margin-top: -1rem;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-border-default);
}
.shell-immersive .stage__split:hover::before,
.shell-immersive .stage__split:hover::after,
.shell-immersive .stage__split:focus-visible::before,
.shell-immersive .stage__split:focus-visible::after,
.shell-immersive .stage.is-resizing .stage__split::before,
.shell-immersive .stage.is-resizing .stage__split::after {
  background: var(--ui-action-primary);
}
.shell-immersive .stage__split:focus-visible {
  outline: 0;
  box-shadow: var(--ui-focus-ring);
}
/* 끄는 동안 iframe 이 포인터를 삼키지 않게 — 자리 안은 다른 문서다(포인터 캡처와 이중 방어). */
.shell-immersive .stage.is-resizing { user-select: none; }
.shell-immersive .stage.is-resizing .stage__doc { pointer-events: none; }

/* 단추 상태 — 켜짐은 레일 aria-current 의 옷. 자리가 모자라면 남되 눌리지 않는다.
   도구 단추의 테는 inset box-shadow 라(위 .topbar :is(button,.btn)) 켜짐에서 그 테를 action 색으로 바꾼다(오너 결정 2 (2026-09-29) · 「문장 고르기」 눌림과 같은 수). */
.shell-immersive .topbar__tools #splitToggle[aria-expanded="true"] {
  background: var(--ui-action-primary-soft);
  color: var(--ui-action-primary-hover);
  box-shadow: var(--ui-selected-ring);
}
.shell-immersive .topbar__tools #splitToggle[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
.shell-immersive .topbar__tools #splitToggle[disabled]:hover { transform: none; }

@media (max-width: 880px) {
  /* 레일(app.css)·회신(comments.js)·간트 손잡이(session.css)와 같은 문턱. 반쪽이 183–428px 라
     문서가 못 읽힌다(183 실측: 가로 넘침 71px). split.js 는 이 display 를 물어 「좁음」을 안다 —
     880 을 JS 에 다시 적지 않는다(layout.php 의 레일과 같은 태도). */
  .shell-immersive #splitToggle { display: none; }
  .shell-immersive .stage.is-split { flex-direction: column; }
  .shell-immersive .stage__pane--b,
  .shell-immersive .stage__split { display: none !important; }
}

@media print {
  /* 인쇄는 왼쪽 자리 하나 — app.css 의 .talk·.sum 숨김과 같은 줄. 인쇄 정본은 「새 창에서 열기」다. */
  .shell-immersive .stage__pane--b,
  .shell-immersive .stage__split,
  #splitToggle, .tour { display: none !important; }
  .shell-immersive .stage.is-split { flex-direction: column; }
  .shell-immersive .stage.is-split .stage__pane--a { flex: 1 1 auto; }
}

/* ── 첫 사용 안내(2026-09-08) — 스포트라이트 투어(split.js 가 세운다, 한 번만) ─────────────────
 * 원전: codepen yaphi1/wvbzMrL 「spotlight with svg masking and rounded corners」 — 화면 전체를 덮는
 * SVG 의 마스크(흰 바탕 + 검은 둥근 사각형)로 구멍을 뚫고, 그 구멍이 다음 자리로 미끄러진다.
 * 덮개는 포인터를 막지 않는다(비모달 코치마크) — 카드만 눌린다. 층은 핵심 요약(.sum)과 같다. */
.tour {
  position: fixed;
  inset: 0;
  z-index: calc(var(--ui-layer-modal) + var(--ui-layer-popover));
  pointer-events: none;
}
.tour__veil { position: absolute; inset: 0; width: 100%; height: 100%; }
.tour__bg { fill: var(--ui-fg-strong); fill-opacity: 0.55; }
.tour__hole {
  transition: x var(--ui-motion-enter) var(--ui-ease-standard), y var(--ui-motion-enter) var(--ui-ease-standard),
    width var(--ui-motion-enter) var(--ui-ease-standard), height var(--ui-motion-enter) var(--ui-ease-standard);
}
.tour__card {
  position: absolute;
  pointer-events: auto;
  width: min(22rem, calc(100vw - 2rem));
  padding: var(--ui-space-5);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-surface);
  color: var(--ui-fg-strong);
  box-shadow: var(--ui-shadow-overlay);
}
.tour__step { margin: 0 0 var(--ui-space-2); font-size: var(--ui-type-caption); color: var(--ui-fg-muted); font-variant-numeric: tabular-nums; }
.tour__title { margin: 0 0 var(--ui-space-2); font-size: var(--ui-type-card-title); font-weight: var(--ui-font-weight-bold); }
.tour__body { margin: 0 0 var(--ui-space-4); font-size: var(--ui-type-body); line-height: var(--ui-line-body); word-break: keep-all; overflow-wrap: anywhere; }
.tour__foot { display: flex; justify-content: flex-end; gap: var(--ui-space-2); }
@media (prefers-reduced-motion: reduce) { .tour__hole { transition: none; } }

/* 관계가 실제로 접히는 경계. 페이지 폭 상한이나 읽기 폭 토큰은 아니다.
 * 셸 자신은 자기 container query의 대상이 될 수 없으므로 viewport 관계로 선언한다. */
@media (max-width: 60rem) {
  .page-reports-empty main.ui-page,
  .page-account main.ui-page {
    display: block;
  }
  .page-reports-empty :is(.pagehead, .note, .reports-empty),
  .page-account :is(.pagehead, .ui-notice, .account-profile, .account-members) {
    width: 100%;
  }
  .page-account .account-profile + .account-members,
  .page-reports-empty .reports-empty {
    margin-top: var(--ui-space-5);
  }
  .page-wiki-document .wiki-document {
    grid-column: 1 / -1;
  }
}

@media (max-width: 48rem) {
  .page-account .account-member__permissions {
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
  }
  .page-account .account-member__save .ui-button {
    width: 100%;
  }
}

@media (max-width: 55rem) {
  .page-admin .admin {
    grid-template-columns: minmax(0, 1fr);
  }
  .page-admin .tnav {
    position: static;
  }
  .page-admin .tnav__list {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr));
  }
  .page-admin .focus__head {
    align-items: flex-start;
    flex-direction: column;
  }
  .page-admin .focus__actions {
    width: 100%;
    margin-left: 0;
  }
  .page-admin .admin-disclosure {
    position: static;
    width: auto;
    display: inline-block;
  }
  .page-admin .admin-disclosure[open] {
    flex: 1 0 100%;
    width: 100%;
  }
  .page-admin .admin-disclosure__panel {
    position: static;
    width: 100%;
    margin-top: var(--ui-space-2);
    box-shadow: var(--ui-shadow-surface);
  }
}

@media (max-width: 40rem) {
  .ui-v2:is(.shell-workbench, .shell-reading) .row {
    flex-direction: column;
  }
  .ui-v2:is(.shell-workbench, .shell-reading) :is(.card__head, .sect__head),
  .ui-v2:is(.shell-workbench, .shell-reading) .card__body {
    padding-inline: var(--ui-space-4);
  }
  .shell-bare :is(.bare, .auth) {
    padding: var(--ui-space-4);
  }
  .page-login .login-handoff__body {
    padding: var(--ui-space-6);
    gap: var(--ui-space-5);
  }
  .page-login .login-handoff__header {
    gap: var(--ui-space-2);
  }
  .page-login .login-handoff__title {
    font-size: var(--ui-type-section-title);
  }
  .page-login .login-handoff__lead {
    font-size: var(--ui-type-body);
  }
  .page-login .login-handoff__ready {
    gap: var(--ui-space-4);
  }
  .page-login .login-handoff__code-card {
    padding: var(--ui-space-4);
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--ui-space-3);
  }
  .page-login .login-handoff__code {
    font-size: var(--ui-type-card-title);
  }
  .page-login .login-handoff__code-button {
    width: 100%;
    grid-column: 1 / -1;
  }
  .page-login .login-flow__status {
    padding: var(--ui-space-4) var(--ui-space-6);
  }
  .page-account .account-members__body {
    padding-inline: var(--ui-space-4);
  }
  .page-account .account-member__header {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  .page-account .account-member__last-login {
    grid-column: 1 / -1;
    grid-template-columns: max-content minmax(0, 1fr);
    text-align: left;
  }
  .page-account .account-member__actions {
    justify-content: flex-start;
  }
  .shell-immersive .brand__copy,
  .shell-immersive #railToggle span,
  .shell-immersive .topbar__toggle span {
    display: none;
  }
  .shell-immersive .brand__mark,
  .shell-immersive .brand__tenant-logo {
    max-width: 5rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ui-v2 :is(button, .btn, input, select, textarea) {
    transition: none;
  }
}

/* ── 이 문서를 만든 세션(070) — `.talk` 의 자리를 나눠 쓰는 패널 ───────────────
 *
 * 레이아웃(21rem·flex·모바일 전환)은 `.talk` 가 이미 갖고 있다(app.css:600-708).
 * 그 파일은 동결된 호환 시스템이라(DESIGN-portal-ui.md:172) 새 규칙을 그 옆에 안 쓰고,
 * 마크업이 두 클래스를 함께 달아 **차이만** 여기서 준다.
 *
 * 죽음은 **색을 뺀다** — 경고색을 안 쓴다(session.css:675-684 의 `--gone` 과 같은 태도).
 * 「이어가는 중」이 아닌 것은 사고가 아니라 정상이다(창을 닫는 것은 사고가 아니다).
 */
.cells__list { padding: var(--ui-space-3); }
.cells__ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--ui-space-2); }

.cells__row {
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-md);
  padding: var(--ui-space-3);
  background: var(--ui-bg-surface);
}
.cells__row--quiet { background: var(--ui-bg-subtle); }
.cells__row--quiet .cells__title { color: var(--ui-fg-muted); }

.cells__head { display: flex; align-items: center; gap: var(--ui-space-2); flex-wrap: wrap; }
/* 열쇠는 uuid, 표시는 앞 8자 — 이름은 재사용되는 별칭이라 충돌한다(DESIGN-mail.md:177-186).
 * 전체 값은 title 속성에 남는다. */
.cells__id { font-size: var(--ui-type-label); color: var(--ui-fg-default); }

.cells__title {
  margin: var(--ui-space-2) 0 0;
  font-size: var(--ui-type-label);
  line-height: 1.5;
  /* 긴 제목·경로는 surface 안에서 줄바꿈한다(DESIGN-portal-ui.md:186). */
  overflow-wrap: anywhere;
}
.cells__untitled { color: var(--ui-fg-muted); }
.cells__who { color: var(--ui-fg-muted); font-size: var(--ui-type-caption); }

.cells__note {
  margin: var(--ui-space-2) 0 0;
  font-size: var(--ui-type-caption);
  color: var(--ui-fg-muted);
}
.cells__unknown { margin: var(--ui-space-3) 0 0; }

/* ── 확인할 지식을 **전폭 가로 카드 격자**로 ────────────────────────────────
   2026-08-26 사용자 「Peec AI 배치도가 좋아보였음」.

   전에는 검토가 .th-split 의 한 열이었다. 운영 자료 모양으로 재면 그 열이 **1,466px** 로
   나머지 둘(534·870)의 **2.7배**가 되어 격자 바닥 1,755px — 뷰포트 1,334px 를 421px 뚫었고,
   나머지 두 열 아래는 511px·175px 가 빈 채였다(실측 2267×1334).

   ⚠ **폭을 넓히는 것만으로는 안 줄어든다.** 전폭 3열이어도 카드 하나는 여전히 ~600px 라
   전과 같다(574px). 줄어드는 것은 **글자 예산**에서 온다 — 설명 2줄 · 경로 1줄 · 발치 한 줄.
   레퍼런스: Peec AI(카드 가로 격자 + 실선 아래 조치 한 줄).                            */
.ui-v2.page-tenant-home .th-reviews {
  /* 21rem 으로 두면 2267px 에서 **5열**이 되어 6장이 5+1 로 앉는다(외톨이 한 장).
     Peec AI 는 3열이다 — 30rem 이면 넓은 폭에서 3열, 좁아지면 2열·1열로 접힌다.
     `min(100%, …)` 이라 390px 에서도 격자가 뷰포트를 안 넘는다. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 30rem), 1fr));
  gap: var(--ui-space-3);
  align-items: stretch;
}
/* 조치가 옆이 아니라 **발치**로 갔으므로 카드는 한 열이다. */
.ui-v2.page-tenant-home .wiki-review-item {
  grid-template-columns: minmax(0, 1fr);
  grid-auto-rows: max-content;
  gap: var(--ui-space-2);
  align-items: stretch;
}
.ui-v2.page-tenant-home .wiki-review-copy { max-inline-size: none; }

/* 설명은 **2줄까지**. 서버가 140자로 자르지만 폭에 따라 3줄이 될 수 있어 여기서 한 번 더
   막는다 — 카드 높이가 자료에 따라 들쭉날쭉하면 격자가 어긋난 것처럼 읽힌다. */
.ui-v2.page-tenant-home .wiki-review-description {
  margin-top: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

/* 발치 — 경로(왼쪽, 한 줄 말줄임) · 조치(오른쪽). 실선 하나로 본문과 가른다. */
.ui-v2.page-tenant-home .wiki-review-foot {
  margin-top: auto;
  padding-top: var(--ui-space-2);
  border-top: var(--ui-border-width) solid var(--ui-border-default);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ui-space-3);
  min-width: 0;
}
.ui-v2.page-tenant-home .wiki-review-pages {
  margin-top: 0;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: var(--ui-space-2);
  overflow-wrap: normal;
}
.ui-v2.page-tenant-home .wiki-review-pages__one {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-v2.page-tenant-home .wiki-review-pages__more {
  flex: none;
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
}
.ui-v2.page-tenant-home .wiki-review-actions {
  flex: none;
  align-self: auto;
}

/* ── 곁 정보 표의 밀도 ───────────────────────────────────────────────────
   66px/행이었다(세포 표 399px ÷ 6). 레퍼런스(Relevance AI)의 큐 표는 ~30px 이다.
   훑는 표는 읽는 표가 아니다 — 세로 여백을 줄인다. */
.ui-v2 .th-panel .admin-table :is(td, th) { padding-block: var(--ui-space-2); }
.ui-v2 .th-panel .admin-table tbody td { line-height: var(--ui-line-tight); }

/* ── 지표 넉 장을 얇게 ───────────────────────────────────────────────────
   154px 이었다. 값과 딸린 한 줄은 그대로 두고 **세로 여백만** 줄인다 —
   카드 자체를 없애면 .ui-surface 정합(그림자·모서리)을 잃는다.

   오늘 카드(.th-today__card)도 같이 얇힌다(2026-09-02) — 두 계열이 밀도까지
   같아야 한 벤토처럼 보인다(위 :1996 「두 계열 공유」 규율의 연장). */
.ui-v2.page-tenant-home .th-metrics { margin-bottom: var(--ui-space-4); }
.ui-v2.page-tenant-home .th-today__grid { margin-bottom: var(--ui-space-4); }
.ui-v2.page-tenant-home .th-metric,
.ui-v2.page-tenant-home .th-today__card {
  padding: var(--ui-space-3) var(--ui-space-4);
  gap: var(--ui-space-1);
}

/* 움직임을 원치 않는 사람에게는 움직이지 않는다. */
@media (prefers-reduced-motion: reduce) {
  .ui-v2.page-tenant-home :is(.wiki-review-item, .wiki-review-actions .ui-button) {
    transition-duration: 0s;
  }
}

/* 비어도 머리행은 선다 — 빈 본문 한 행(uibowl 실측: 컬리 1:1 문의 · MS Clarity 퍼널).
   회색 한 줄이지 빈 상태 상자가 아니다 — 상자를 쓰면 표의 열 구조가 사라진다. */
.ui-v2 .th-panel .admin-table .th-table__empty td {
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  padding-block: var(--ui-space-5);
  text-align: center;
  white-space: normal;
  width: auto;
}
.ui-v2 .th-panel .admin-table .th-table__empty:hover { background: transparent; }

/* ── 표가 패널 밖으로 24px 나가 날짜가 잘리던 것 ─────────────────────────────
   2026-08-26 실측: 패널폭 622 · 표폭 622 인데 **표오른쪽 950 vs 패널오른쪽 926**.
   `.th-table { width:100% }` 와 `.th-panel .admin-table { margin-inline: --ui-space-6 }`
   이 겹쳐, 표가 왼쪽으로 24px 밀린 채 폭은 그대로 100% 라 오른쪽이 24px 넘쳤다.
   패널은 `overflow: visible` 이라 잘리진 않지만 **옆 패널이 그 위에 앉아** 날짜가
   `2026.08.2` 로 보였다 — 사용자가 맨 처음 지적한 그 화면이다.

   ⚠ 내 이전 처방(셀 여백 0)과 관문(첫셀x === 제목x)은 **왼쪽만** 봤다. 왼쪽은 맞고
     오른쪽이 틀린 자리라 초록인 채 지나갔다. 관문에 오른쪽 변을 더한다.

   폭에서 양쪽 여백을 빼면 margin 과 합쳐 정확히 100% 가 된다. */
.ui-v2 .th-panel .admin-table {
  width: calc(100% - 2 * var(--ui-space-6));
}

/* ── 지표 띠의 값은 **같은 크기**로 선다 ─────────────────────────────────────
   실측 2026-08-26: 값 크기가 `40px · 20px · 40px · 20px` 이었다. 「없음」 칸만 절반이라
   네 칸짜리 띠의 가로 리듬이 깨졌다(컨셉 대조에서 드러남).

   원래 의도(「0 을 성공처럼 보이지 않게 한다」)는 지킨다 — 다만 **크기가 아니라 색으로** 죽인다.
   크기를 줄이면 「없음」이 약해지는 게 아니라 **띠가 망가진다**. 색은 칸을 안 건드린다. */
/* ⚠ 이 선택자의 규칙은 **하나뿐이어야 한다.** 전에는 :1909 에 같은 특이도로
   `font-size: var(--ui-type-card-title)`(20px) 가 또 있었고, 이 규칙이 이기는 이유가
   「파일에서 더 뒤라서」뿐이었다 — 한 쪽을 위로 옮기면 조용히 뒤집힌다. 낡은 쪽을 지웠다. */
.ui-v2 .th-metric__value .th-none {
  font-size: inherit;
  color: var(--ui-fg-muted);
}

/* ── 검토 카드에 경계를 준다 ────────────────────────────────────────────────
   실측: 카드 테두리 `0px` · 그림자 `none` · 바탕 `#f8fafd` 인데 패널 바탕이 `#fff` 이다.
   흰 위에 흰-회색이라 카드가 카드로 안 읽힌다 — 「밋밋함」의 남은 절반이다.
   그림자를 얹지 않는다(패널 안의 카드라 겹치면 탁해진다). 1px 선 하나면 된다. */
.ui-v2.page-tenant-home .wiki-review-item {
  border: var(--ui-border-width) solid var(--ui-border-default);
}

/* ── 홈의 목록 행은 **데이터와 무관하게** 한 줄이다 ─────────────────────────
   고객사 홈은 「한 화면에 선다」가 계약이다(사용자 결정 2026-08-26, 관문
   tools/dashboard-regression.mjs 「★★ 한 화면에 통째로 들어간다」 — 뷰포트 1334px).
   그런데 두 목록 표(진행 중인 작업 6행 · 최근 열람 5행)는 **제목 길이에 따라 자란다**:
   위 `.th-panel .admin-table :is(td, th) { overflow-wrap: anywhere }` 가 긴 제목을 접어
   행을 52px → 76px 로 키운다. 실측(2026-08-31): 패널 바닥 1073px 이라 여유는 261px 인데,
   두 표의 11행이 다 접히면 **+264px** — 한 번에 넘는다. 실제로 넘었다: 파이프라인 직후엔
   16/0 초록(문서 1334px)이던 관문이, 데이터가 불어난 뒤엔 「문서 1424px」로 빨갰다.
   그러면 「한 화면」을 정하는 것은 디자인이 아니라 **그날 DB 에 무엇이 들어 있었나**가 된다.
   높이를 못박아 그 우연을 없앤다 — 넘치는 제목은 말줄임으로 자르고, 전문은 패널 머리의
   「…화면」 링크가 진다. ⚠ 빈 상태 행은 제외한다(한 문장이 통째로 잘리면 안내가 사라진다). */
.ui-v2.page-tenant-home .th-panel .admin-table tbody tr:not(.th-table__empty) td {
  overflow-wrap: normal;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 0;                 /* table-layout:fixed 아래서 말줄임이 서려면 폭 기준이 필요하다 */
}

/* ══ 드래그 오버레이(076 문서함) — 세션 나무의 그 모양을 중립 이름으로 ═══════
 * session-drop-ring/outdent 는 군체 화면 소유라 이름을 빌리지 않고 옷만 같게 입는다. */
.ui-drop-ring {
  position: fixed; z-index: 40; display: none; pointer-events: none;
  border-radius: var(--ui-radius-md);
  box-shadow: inset 0 0 0 var(--ui-border-width) var(--ui-action-primary);
  background: var(--ui-action-primary-soft);
}
.ui-drop-ring.is-on { display: block; }
.ui-drop-ring.is-settling { transition: all 260ms var(--ui-ease-nav-out); }
.ui-drop-badge {
  position: fixed; z-index: 42; display: none; align-items: center; gap: var(--ui-space-1);
  padding-inline: var(--ui-space-2); block-size: var(--ui-space-8);
  border: var(--ui-border-width) solid var(--ui-border-default);
  border-radius: var(--ui-radius-pill);
  background: var(--ui-bg-surface); color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption); font-weight: var(--ui-font-weight-bold);
  white-space: nowrap; box-shadow: var(--ui-shadow-overlay);
  pointer-events: none;
}
.ui-drop-badge.is-on { display: inline-flex; }
.ui-drop-badge.is-ready { color: var(--ui-fg-default); border-color: var(--ui-action-primary); }

/* 휴지통 화면(view=trash) — ui-list 한 벌.
 * 2026-09-08 오너: 「선택 지우기·전체 지우기가 있어야 함 · 행의 복구·영구 삭제는 기본적으로 보이면 안 되고 UX 밀도에 집중」.
 * 배치는 Google Drive Bin(행 고르기 + 위 띠의 동작 · 행 동작은 hover 에서)과 Zoho CRM Recently Deleted(머리 체크박스 +
 * 「Delete all permanently」)에서 왔다. 부품은 있는 것만 — KRDS 체크박스(input 기본 + accent), .ui-actions, .ui-button. */
.page-tenant-trash .tr-bulk {
  display: flex; align-items: center; gap: var(--ui-space-3); flex-wrap: wrap;
  min-height: var(--ui-control-default); margin-block-end: var(--ui-space-2);
  padding-inline: var(--ui-space-2);
}
.page-tenant-trash .tr-bulk__pick {
  display: inline-flex; align-items: center; gap: var(--ui-space-2); flex: none;
  font-size: var(--ui-type-label); color: var(--ui-fg-muted); min-height: var(--ui-control-compact);
}
.page-tenant-trash .tr-bulk__pick input[type="checkbox"] { margin: 0; }
.page-tenant-trash .tr-bulk__acts { display: inline-flex; align-items: center; gap: var(--ui-space-2); }
.page-tenant-trash .tr-bulk__all { margin-inline-start: auto; }
.page-tenant-trash .tr-row {
  display: flex; align-items: center; gap: var(--ui-space-3);
  min-height: var(--ui-control-default); padding: var(--ui-space-1) var(--ui-space-2);
  border-radius: var(--ui-radius-sm);
}
.page-tenant-trash .tr-row:hover { background: var(--ui-bg-subtle); }
.page-tenant-trash .tr-row.is-picked { background: var(--ui-action-primary-soft); }
.page-tenant-trash .tr-row__pick { display: flex; align-items: center; flex: none; }
.page-tenant-trash .tr-row__pick input[type="checkbox"] { margin: 0; }
.page-tenant-trash .tr-row__main {
  display: flex; align-items: center; gap: var(--ui-space-2); min-width: 0; flex: 1 1 auto;
}
.page-tenant-trash .tr-row__name { font-weight: var(--ui-font-weight-medium); }
.page-tenant-trash .tr-row__meta { white-space: normal; }
/* 행의 동작(복구·영구 삭제)은 있어야 알 수 있는 것 — 탐색기의 ⋯(workspace.css) 와 같은 규율: hover·focus-within·
 * 고른 행·터치(coarse)에서만 보인다. visibility 로 감춘다(자리는 지켜 행 높이가 안 흔들리고, 초점은 늘 받는다). */
.page-tenant-trash .tr-row__acts { flex: none; margin-inline-start: auto; visibility: hidden; }
.page-tenant-trash .tr-row:hover .tr-row__acts,
.page-tenant-trash .tr-row:focus-within .tr-row__acts,
.page-tenant-trash .tr-row.is-picked .tr-row__acts { visibility: visible; }
@media (pointer: coarse) { .page-tenant-trash .tr-row__acts { visibility: visible; } }
/* 좁은 폭(390 실측): 감춘 동작이 자리를 쥐고 있어 이름이 한 글자씩 꺾였다(행 107px). 좁으면 동작을 **아래 줄**로 내리고
 * 고른 행·초점·터치에서만 세운다(자리를 안 쥔다) · 이름은 한 줄, 메타는 그 아래. 넓은 폭은 위 규칙 그대로(44px 행). */
@media (max-width: 640px) {
  .page-tenant-trash .tr-row { flex-wrap: wrap; row-gap: var(--ui-space-1); }
  /* 체크박스와 같은 줄에 선다 — basis 0 이라 남은 폭만큼 줄어든다(auto 면 내용 폭을 고집해 다음 줄로 떨어졌다, 390 실측). */
  .page-tenant-trash .tr-row__main { flex: 1 1 0; min-width: 0; flex-wrap: wrap; row-gap: 0; }
  .page-tenant-trash .tr-row__name { flex: 1 1 auto; min-width: 0; }
  .page-tenant-trash .tr-row__meta { flex: 1 1 100%; }
  .page-tenant-trash .tr-row__acts { display: none; flex: 1 1 100%; justify-content: flex-end; margin-inline-start: 0; }
  .page-tenant-trash .tr-row:focus-within .tr-row__acts,
  .page-tenant-trash .tr-row.is-picked .tr-row__acts { display: flex; }
  @media (pointer: coarse) { .page-tenant-trash .tr-row__acts { display: flex; } }
}

/* ── 결정을 적는 문 (078) ────────────────────────────────────────────────
   기본 모양으로 두면 「엉성함」의 원인이 된다 — details/summary·입력칸 전부.
   부품은 새로 만들지 않고 이미 있는 것을 쓴다(.ui-disclosure · .ui-button · .ui-field).
   여기서 정하는 것은 **배치뿐**이다. */
.page-wiki-index .wiki-decision-new {
  margin-block-start: var(--ui-space-4);
}
.page-wiki-index .wiki-decision-new[open] > summary {
  margin-block-end: var(--ui-space-4);
}
.page-wiki-index .wiki-decision-new__form {
  /* ⚠ 폭을 안 잡으면 2560px 에서 한 줄이 화면을 가로지른다 — 읽는 자가 아니게 된다. */
  max-inline-size: 56rem;
  min-width: 0;
  margin: 0;
  padding: var(--ui-space-5);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--ui-space-4) var(--ui-space-5);
  border-radius: var(--ui-radius-lg);
  background: var(--ui-bg-subtle);
  border: var(--ui-border-width) solid var(--ui-border-default);
}
/* 긴 칸은 줄 전체를 쓴다 — 제목·무엇을·왜·다시 여는 조건. */
.page-wiki-index .wiki-decision-new__form > .ui-field:not(.wiki-decision-new__short) {
  grid-column: 1 / -1;
}
.page-wiki-index .wiki-decision-new__form > .ui-actions {
  grid-column: 1 / -1;
  margin: 0;
}
@container wiki-tenant (max-width: 48rem) {
  .page-wiki-index .wiki-decision-new__form {
    grid-template-columns: minmax(0, 1fr);
    padding: var(--ui-space-4);
  }
}

/* ── 결정 상태 알약 ──────────────────────────────────────────────────────
   `ui-badge--warn` 은 화면이 **부르고 있었는데 규칙이 어디에도 없었다**(2026-08-27 실측:
   design-system.css·portal-pages.css·session.css 전부 0곳). 그래서 「열림」이 알약이
   아니라 맨 글자로 나왔고, 폭이 좁은 칸에서 「열 / 림」으로 갈라졌다. 토큰 grep 은
   이런 것을 못 잡는다 — 부르는 이름이 없는 것이지 값이 틀린 게 아니기 때문이다.

   ⚠ 여기 두는 이유: 이것은 아직 **이 화면의 어휘**다. 다른 화면이 같은 셋을 쓰기 시작하면
   그때 design-system.css 로 올린다(먼저 올리면 쓰는 데 없는 부품이 는다). */
.page-wiki-index .ui-badge {
  white-space: nowrap;
  background: var(--ui-bg-subtle);
  color: var(--ui-fg-muted);
}
.page-wiki-index .ui-badge--warn {
  background: var(--ui-warning-soft);
  color: var(--ui-warning-default);
}
/* 「모름」 — 경고도 종결도 아니다. 눈에 덜 띄되 **읽히기는 해야** 한다. */
.page-wiki-index .ui-badge--muted {
  background: var(--ui-bg-subtle);
  color: var(--ui-fg-muted);
  font-weight: var(--ui-font-weight-regular, 400);
}

/* ── 오늘(사람의 첫 화면, M-B · 2026-08-28) ───────────────────────────────
   배치 원전: Asana Home·Rox Focus·ClickUp Home(Mobbin) — 확인할 것 목록이 전면.
   부품은 기존 th-panel/ui-surface 를 입고, 여기는 목록 행 기하만 더한다. */
/* 오늘 그리드(2026-09-02, KPI 벤토 심화) — `<ul class="th-today__list">` 줄 목록을
   걷었다. 카드는 이제 `ui_metric_tile()` 이 낸다(root_class="th-today__card") — 자식
   셀렉터(.th-metric__*)·뿌리 셀렉터(.th-today__card)는 위 지표 카드 절이 이미 공유
   한다. 여기서는 **그리드 배치만** 정한다. 항목 0~4개를 열 수 고정 없이 접는다
   (.th-metrics 관례와 동일, auto-fit — 개수가 매번 달라지는 목록이라 더 중요하다). */
.ui-v2 .th-today__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--ui-space-3);
}
.ui-v2 .th-today__recent { margin-top: var(--ui-space-4); }
.ui-v2 .th-today__recent-title { margin: 0 0 var(--ui-space-2); font: var(--ui-type-label); color: var(--ui-fg-muted); }
.ui-v2 .th-today__recent-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--ui-space-1); }

/* ── 검토 회신 핀·멘션(2026-09-08) ──────────────────────────────────────────
   오너: 「Figma 처럼 핀 달아서 해당 부분에 회신 · 멘션도」. 문서(iframe)는 한 바이트도 안 바뀐다 —
   핀은 왼쪽 자리(.stage__pane--a, position:relative 는 위 나란히 절) 위 셸 층(.talk-pins)에 절대배치되고,
   문서 안 하이라이트는 iframe 창의 CSS Custom Highlight API 로 그린다(assets/talk-pins.js). 여기는 셸 쪽만.
   배치 원전(Mobbin): Figma·Sketch·Air·ClickUp = 번호 핀 + 스레드 · Notion·Craft·Slite = 하이라이트 ↔ 카드 ·
   Dropbox = 작성란 「@」 사람 목록. 부품: KRDS Button/secondary(자리 집기) · Badge(핀 번호) · 콤보박스 목록(@).
   app.css 는 동결 — 검토 회신의 새 규칙은 전부 여기 얹는다. */
.talk-pins { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 5; }
.talk-pin {
  position: absolute; pointer-events: auto;
  min-width: 1.5rem; height: 1.5rem; padding: 0 var(--ui-space-2); box-sizing: border-box;
  border: 2px solid var(--ui-bg-surface);
  /* 물방울 — 왼쪽 아래 모서리만 세워 「이 자리」를 가리킨다(Figma·Mural 핀의 그 모양). */
  border-radius: var(--ui-radius-pill) var(--ui-radius-pill) var(--ui-radius-pill) var(--ui-radius-sm);
  background: var(--ui-action-primary); color: var(--ui-fg-inverse);
  font-weight: var(--ui-font-weight-bold); font-size: var(--ui-type-caption); line-height: 1.25rem;
  text-align: center; cursor: pointer; box-shadow: var(--ui-shadow-surface);
  transition: transform var(--ui-motion-fast) var(--ui-ease-standard), box-shadow var(--ui-motion-fast) var(--ui-ease-standard);
}
.talk-pin:hover { transform: scale(1.1); background: var(--ui-action-primary-hover); }
.talk-pin.is-current { transform: scale(1.12); box-shadow: 0 0 0 3px var(--ui-action-primary-soft), var(--ui-shadow-surface); }
.talk-pin:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
/* 히트영역 44px(계약 §10) — 보이는 것은 24px, 누르는 것은 그 둘레까지. 집는 동안은 손을 안 받는다(문장 클릭을 안 가로챈다). */
.talk-pin::after { content: ""; position: absolute; inset: -10px; border-radius: inherit; }
.stage__pane--a.is-picking .talk-pin { pointer-events: none; }
/* 집는 중 — 자리 테두리가 한 겹 선다(나란히의 .is-jump 와 같은 그리기 층, 포인터는 안 막는다). */
.stage__pane--a.is-picking::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 4;
  box-shadow: inset 0 0 0 2px var(--ui-action-primary);
}
/* 좁은 화면 — 서랍을 비킨 동안 문서 아래에 한 줄 띠. */
.talk-pickbar {
  position: absolute; left: var(--ui-space-3); right: var(--ui-space-3); bottom: var(--ui-space-3); z-index: 6;
  display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-3);
  padding: var(--ui-space-2) var(--ui-space-3);
  border-radius: var(--ui-radius-md); background: var(--ui-bg-emphasis); color: var(--ui-fg-inverse);
  font-size: var(--ui-type-label); box-shadow: var(--ui-shadow-overlay);
}

/* ── 선택 위 알약(2026-09-21) — 끌어 고른 글 위의 「메모 달기」 ──────────────────────────────────
   앞 판에는 이 길이 없었다: 끌어 고른 글은 패널이 닫혀 있으면 아무 일도 안 났고, 붙어도 21rem 패널 안 인용 칩만 바뀌어
   문서를 보던 사람 눈에는 아무 일도 안 일어난 화면이었다(assets/talk-pins.js 「선택 위 알약」 절).
   ⚠ 층은 `.talk-pins`(overflow:hidden) **밖**이다 — 그 안에 넣으면 고른 글이 자리 맨 위일 때 알약이 통째로 잘린다.
   층 자체는 손을 안 받고(pointer-events:none) 띠만 받는다 — 문서의 글자·링크가 그대로 눌린다.
   ★ `--ui-layer-popover`(30)를 쓰지 않는다 — 그 값은 자리 **밖**까지 덮는다. 같은 자리 위 띠(.talk-pickbar)와 같은 6 이다. */
.talk-cta { position: absolute; inset: 0; overflow: visible; pointer-events: none; z-index: 6; }
.talk-cta__bar {
  position: absolute; display: flex; align-items: center; gap: var(--ui-space-1); padding: var(--ui-space-1);
  pointer-events: auto;
  border: var(--ui-border-width) solid var(--ui-border-default); border-radius: var(--ui-radius-pill);
  background: var(--ui-bg-surface); box-shadow: var(--ui-shadow-overlay);
  word-break: keep-all;
  transition: opacity var(--ui-motion-fast) var(--ui-ease-standard);
}
/* 칸 안 단추는 **새로 안 만든다** — design-system 의 compact 보조 단추 그대로다. 여기서 정하는 것은 알약 안에서의 모양뿐:
   테는 띠가 이미 두르고 있어 한 겹 더 두면 두 줄이 된다(자리 집기 띠의 「취소」와 같은 부품·같은 높이는 그대로 둔다). */
.ui-v2 .talk-cta__btn { border-color: transparent; box-shadow: none; }
.ui-v2 .talk-cta__btn:hover { background: var(--ui-bg-subtle); }
.ui-v2 .talk-cta__btn .i { width: 0.875rem; height: 0.875rem; }
@media (prefers-reduced-motion: reduce) { .talk-cta__bar { transition: none; } }

/* 작성란 — 집은 자리의 인용(blockquote)이 글상자 위에 선다. 먹선 하나, 배경 없음(셸의 규칙). */
/* 고른 자리의 인용 — **글이 주인공이고 표식은 곁말**이다(2026-09-21 사용자 픽 「이것도 디자인이.. 좀 이상함」).
   앞 판은 3px 파란 먹선 + 파란 핀 아이콘 + 큰 × 가 짧은 인용 한 줄을 세 방향에서 눌렀다. 지금은 먹선 2px, 표식은 무채색,
   글자는 본문색, 상자는 subtle 바탕으로 **작성란 안의 한 칸**처럼 앉는다(레퍼런스 Fabric·Cofounder 의 인용 칩과 같은 무게). */
.talk__quote {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: start; gap: var(--ui-space-2);
  margin: 0 0 var(--ui-space-2); padding: var(--ui-space-2);
  border-left: 2px solid var(--ui-action-primary); border-radius: var(--ui-radius-sm);
  background: var(--ui-bg-subtle); color: var(--ui-fg-default);
  font-size: var(--ui-type-caption); line-height: var(--ui-line-body);
}
.talk__quote-k { display: inline-flex; color: var(--ui-fg-muted); }
.talk__quote-k .i { width: 0.875rem; height: 0.875rem; }
.talk__quote-text { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; word-break: keep-all; }
/* 풀기(×) — 보이는 것은 24px, **누르는 것은 이웃 「자리 집기」·「남기기」와 같은 compact(36px)** 다(2026-09-21). 앞 판은 가로 24 ×
   세로 32(셸 초기화 button{height:32px} 유출)라 이 저장소의 누름 영역 규칙(DESIGN-portal-ui.md — 기본 44·밀도 36)과 같은 패널 머리의
   ×(.talk__x, 44px)보다 작았다. 수법은 핀(.talk-pin::after)과 같고, height:auto 는 인용 단추(.talk__pinq)처럼 그 유출을 끊는다.
   position:relative 가 빠지면 ::after 가 바깥 상자를 기준으로 번져 글상자를 덮는다 — 쓰려고 누를 때마다 자리가 풀린다.
   두 작성란(#talkUnpick·#notesUnpick) 한 벌이다. */
.ui-v2 .talk__quote-x {
  position: relative; height: auto;
  min-width: var(--ui-space-6); min-height: var(--ui-space-6); padding: 0; border: 0; border-radius: var(--ui-radius-sm);
  background: transparent; color: var(--ui-fg-muted); font-size: var(--ui-type-lead); line-height: 1; cursor: pointer;
}
.ui-v2 .talk__quote-x::after { content: ""; position: absolute; inset: calc((var(--ui-space-6) - var(--ui-control-compact)) / 2); }
.ui-v2 .talk__quote-x:hover { background: var(--ui-bg-subtle); color: var(--ui-fg-strong); }
.ui-v2 .talk__quote-x:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
.talk__pickhint { margin: var(--ui-space-2) 0 0; color: var(--ui-fg-muted); font-size: var(--ui-type-caption); line-height: var(--ui-line-body); word-break: keep-all; }
/* 패널의 상태 문구(빈·불러오는 중·못 불러옴)도 낱말 가운데서 안 끊는다 — 390 에서 「에이 / 전트」·「고객에 / 게는」으로 잘렸다
   (2026-09-21 실측). 이 집의 한글 규율이 keep-all 이다(요약 카드 절 참조). 부품은 app.css(동결)에 있어 여기서 더한다. */
.talk__state-copy { word-break: keep-all; }
/* 두 패널(검토 회신·첨삭 메모)은 **뿌리에서** 낱말 경계로만 끊는다(2026-09-21). 앞 판은 keep-all 을 위 두 부품(안내·상태 문구)에만
   붙여, 같은 화면의 작성란 글상자는 「근거 / 를」처럼 음절 가운데서 끊겼다(읽기 1440·880·390·2560, 편집 1440 다섯 장 실측).
   뿌리에 주면 글상자·오류·잃은 묶음 머리·「문서 전체」·상태 낱말이 상속으로 덮인다(선례: 아래 요약 카드 뿌리 .ui-v2 .sum ·
   codex-settings.css .cx-panel). overflow-wrap: anywhere 가 짝이다 — keep-all 은 긴 영문·주소를 안 끊는다.
   카드 본문(.talk__text)은 app.css 가 word-break: break-word 를 **명시**해 상속이 안 닿는다 — 그 값은 한글에선 normal 로 돌아
   폭이 모자라면 음절에서 끊는다. 그래서 따로 이기고, break-word 에 들어 있던 anywhere 를 짝으로 적는다.
   만든 세션 패널(.cells)도 .talk 라 .ui-v2 .talk 로 넓히지 않는다(이번 범위 밖) — 그래서 위 두 부품 규칙도 남긴다. */
.ui-v2 .notes, .ui-v2 #talk { word-break: keep-all; overflow-wrap: anywhere; }
.ui-v2 :is(.notes, #talk) .talk__text { word-break: keep-all; overflow-wrap: anywhere; }
/* 「자리 집기」 — 발의 왼쪽(오른쪽은 「남기기」). 누르고 있는 동안(aria-pressed) 채우고 **테를 action 색으로** 바꾼다.
   ⚠ 이 단추의 테는 border 가 아니라 보조 단추의 inset box-shadow 다(design-system.css `.ui-button--secondary`). 2026-09-08 판부터
   여기 적힌 `border-color` 는 죽은 선언이라, 눌림 표시가 옅은 채움 하나(작성란 바탕 대비 1.07:1)뿐이었다 — 이름이 늘 「자리 집기」로
   고정된 뒤로는(2026-09-21) 단추에서 상태를 볼 길이 사실상 없었다(스킨 훑기 실측). 같은 속성이라 초점 링과는 함께 적는다. */
.ui-v2 .talk__pick { margin-right: auto; display: inline-flex; align-items: center; gap: var(--ui-space-1); }
.ui-v2 .talk__pick .i { width: 1rem; height: 1rem; }
.ui-v2 .talk__pick[aria-pressed="true"] {
  background: var(--ui-action-primary-soft); color: var(--ui-action-primary-hover);
  box-shadow: var(--ui-selected-ring);
}
.ui-v2 .talk__pick[aria-pressed="true"]:focus-visible { box-shadow: var(--ui-focus-ring), var(--ui-selected-ring); }

/* ── 카드의 조용한 도구(2026-09-21 사용자 픽 「디자인이 엉성한데?」) ─────────────────────────────
 *
 * 앞 판은 카드마다 「답글·반영함·수정·삭제」 네 글자 단추가 **늘** 서 있어 링크 넉 줄이 쌓였다. 레퍼런스(Obvious Comment detail ·
 * Slite Comments · Notion Comments — 모두 옆 패널의 댓글 카드)는 쉴 때 동작이 0개고, 손을 올리면 머리 오른쪽에 아이콘 묶음
 * (해결 ✓ · 더 보기 ⋯)이 뜨며 답글만 카드 아래 한 줄로 남는다.
 * ⚠ 숨김은 **opacity** 다 — display:none 이면 Tab 이 못 가고(키보드로는 영영 못 쓴다), visibility:hidden 이면 초점도 못 받는다.
 *   자리는 늘 차지해 시각이 안 밀리고, 보이기만 늦는다. 손이 없는 기기(hover:none)·좁은 폭에서는 늘 보인다.
 */
.ui-v2 :is(.notes, #talk) .talk__tools {
  flex: none; display: inline-flex; align-items: center; gap: var(--ui-space-1); margin-left: var(--ui-space-2);
  opacity: 0; transition: opacity var(--ui-motion-fast) var(--ui-ease-standard);
}
.ui-v2 :is(.notes, #talk) .talk__item:hover .talk__tools,
.ui-v2 :is(.notes, #talk) .talk__item:focus-within .talk__tools,
.ui-v2 :is(.notes, #talk) .talk__item.is-current .talk__tools { opacity: 1; }
@media (hover: none) { .ui-v2 :is(.notes, #talk) .talk__tools { opacity: 1; } }
@media (max-width: 880px) { .ui-v2 :is(.notes, #talk) .talk__tools { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .ui-v2 :is(.notes, #talk) .talk__tools { transition: none; } }
/* 아이콘 단추 — 보이는 것은 아이콘 하나, 누르는 것은 이 집의 밀도(36px compact). 이름은 aria-label 이 진다. */
.ui-v2 :is(.notes, #talk) .talk__tool {
  inline-size: var(--ui-control-compact); min-inline-size: var(--ui-control-compact);
  block-size: var(--ui-control-compact); min-block-size: var(--ui-control-compact);
  height: auto; padding: 0; color: var(--ui-fg-muted);
}
.ui-v2 :is(.notes, #talk) .talk__tool:hover { color: var(--ui-action-primary-hover); }
.ui-v2 :is(.notes, #talk) .talk__tool .i { width: 1rem; height: 1rem; }
/* 더 보기 — 문서 도구줄의 메뉴(.document-tools-menu, document-workspace.css)와 같은 해부: details + summary, 겹판은 절대배치.
   새 부품을 안 짓는다. 패널이 좁아 오른쪽 끝에 붙여 연다. */
.ui-v2 :is(.notes, #talk) .talk__menu { position: relative; flex: none; margin: 0; }
.ui-v2 :is(.notes, #talk) .talk__menu > summary { list-style: none; cursor: pointer; }
.ui-v2 :is(.notes, #talk) .talk__menu > summary::-webkit-details-marker { display: none; }
.ui-v2 :is(.notes, #talk) .talk__menu[open] > summary { background: var(--ui-bg-subtle); color: var(--ui-fg-strong); }
.ui-v2 :is(.notes, #talk) .talk__menu > div {
  position: absolute; z-index: 2; inset-block-start: calc(100% + var(--ui-space-1)); inset-inline-end: 0;
  inline-size: max-content; min-inline-size: 8rem;
  display: grid; gap: var(--ui-space-1); padding: var(--ui-space-2);
  border-radius: var(--ui-radius-lg); background: var(--ui-bg-surface); box-shadow: var(--ui-shadow-overlay);
}
.ui-v2 :is(.notes, #talk) .talk__menu:not([open]) > div { display: none; }
.ui-v2 :is(.notes, #talk) .talk__menu > div > button { justify-content: flex-start; width: 100%; }
/* 카드 머리는 **한 줄**이다(2026-09-22) — 도구는 쉴 때도 opacity 로만 숨어 폭(36+4+36+8px)을 늘 차지하는데, 머리 줄
   (app.css `.talk__by`)은 flex 이고 이름·시각에 nowrap 이 없었다. 그래서 「반영함」 곁말까지 선 카드는 이름 「로컬 편집자」와
   시각 「09-22 00:30」이 낱말 경계에서 꺾여 머리가 두 줄이 됐다(네 폭 스킨 훑기 ⓓ 실측 — 고른 상태 탓이 아니라 반영한 카드
   전부의 일이고, 도구를 넣은 오늘 들어간 회귀다). 줄어드는 것은 **이름 하나**뿐이다: 시각과 갈래 곁말(「에이전트」·「반영함」)은
   제 폭을 지키고 이름만 말줄임으로 준다. 두 패널 한 규칙이다. */
.ui-v2 :is(.notes, #talk) .talk__by > .talk__name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ui-v2 :is(.notes, #talk) .talk__by > :is(.talk__when, .ui-kind) { flex: none; white-space: nowrap; }
/* 폼의 발 — 짝 단추는 오른쪽에 나란히(취소 → 주 단추). 앞 판은 주 단추가 왼쪽, 취소가 글자 단추라 짝으로 안 읽혔다.
   ⚠ `flex-basis:100%` 가 없으면 발이 폼(flex-wrap) 안에서 제 너비만 차지해 **왼쪽에 붙는다** — 오른쪽 정렬이 헛돈다(실측). */
.ui-v2 :is(.notes, #talk) .talk__formfoot {
  flex: 1 1 100%;
  display: flex; justify-content: flex-end; align-items: center; gap: var(--ui-space-2); margin-top: var(--ui-space-2);
}

/* 카드(오너 2026-09-08 「디자인 다시」) — Figma 댓글 카드의 순서를 그대로 **세로로만** 쌓는다: 번호 배지(아바타 자리) · 이름 · 시각 →
   인용(먹선 한 줄, 두 줄까지) → 상태 한 줄 → 본문 → 동작. 격자를 쓰지 않는다 — 인용이 접히는 순간 옆 칸이 글 위로 올라앉았다. */
.talk__pinn {
  flex: none; display: inline-block; min-width: var(--ui-space-6); height: var(--ui-space-6); padding: 0 var(--ui-space-1); box-sizing: border-box;
  border-radius: var(--ui-radius-pill) var(--ui-radius-pill) var(--ui-radius-pill) var(--ui-radius-sm);
  background: var(--ui-action-primary); color: var(--ui-fg-inverse);
  font-size: var(--ui-type-caption); font-weight: var(--ui-font-weight-bold); line-height: var(--ui-space-6); text-align: center;
}
.talk__item.is-lost .talk__pinn { background: var(--ui-fg-muted); }
.ui-v2 .talk__pinq {
  /* ★ 셸 초기화의 button{height:32px} 가 여기까지 온다 — 높이를 내용에 맡기지 않으면 두 줄 인용이 상자 밖으로 흘러 본문을 덮는다. */
  height: auto; min-height: 0;
  display: block; width: 100%; margin: 0 0 var(--ui-space-2); padding: var(--ui-space-1) var(--ui-space-2) var(--ui-space-1) var(--ui-space-3);
  border: 0; border-left: 3px solid var(--ui-action-primary); border-radius: 0;
  background: transparent; color: var(--ui-fg-muted); text-align: left; cursor: pointer;
  font: inherit; font-size: var(--ui-type-caption); line-height: var(--ui-line-body); white-space: normal;
}
.ui-v2 .talk__pinq:hover { background: var(--ui-action-primary-soft); color: var(--ui-fg-strong); }
.ui-v2 .talk__pinq:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
.talk__item.is-lost .talk__pinq { border-left-color: var(--ui-border-default); }
.talk__pinq-text {
  quotes: none; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  white-space: normal; word-break: keep-all; overflow-wrap: anywhere;
}
.talk__pinstate { display: block; margin-top: var(--ui-space-1); color: var(--ui-warning-default); font-size: var(--ui-type-caption); }
/* 고른 카드 — 바탕 하나로는 **색 말고 채널이 없었다**(2026-09-21 실측: 흰 패널과 1.12:1 · 손 올린 이웃과 1.07:1 ·
   box-shadow·outline·border 전부 none). WCAG 1.4.11(상태 식별 3:1)·1.4.1(색만으로 말하지 말 것) 둘 다 걸렸고,
   `aria-current="true"` 는 인용 단추에 서 있었지만 그 속성에 걸린 시각 규칙은 0개였다. 안쪽 테 한 겹을 더한다 —
   테:soft 4.05:1 · 테:흰 4.55:1 · 테:hover바탕 6.54:1 로 세 이웃 모두 3:1 을 넘는다(조사 실측).
   ⓐ 같은 패널의 「문장 고르기」 눌림(위 .ui-v2 .talk__pick[aria-pressed="true"])이 **같은 값·같은 이유**로 이미 테를 얻었다 —
      고른 상태의 어휘를 화면마다 새로 짓지 않는다(점·굵기 같은 다른 표식을 이 카드에만 지어내지 않는 까닭).
   ⓑ soft 토큰 자체를 짙게 하는 길은 **산술로 불가** — 흰 바탕 3:1 을 넘기려면 그 위에 얹힌 --ui-action-primary-hover
      글자가 6.09:1 → 2.07:1 로 떨어져 1.4.3 을 깬다. 같은 블록에서 soft 바탕 + hover 글자를 쓰는 규칙이
      이 저장소 CSS 전수로 27곳이다(2026-09-21 내가 센 값) — 하나를 올리면 스물일곱이 내려간다.
   ⓒ 레일이 왼쪽 막대(app.css 의 .rail__item[aria-current] inset 3px)를 걷은 결정과 안 어긋난다 — 그것은 hover·current 가 다투던
      한 속성을 비운 것이다. 레일의 현재 항목도 이 테를 두른다(오너 결정 2 (2026-09-29) — 전에는 제목 700 을 둘째 채널로 셌다).
   ⚠ .ws-row.is-selected(document-tabs.css:19)에는 이 어휘를 넓히지 않는다 — tests/document-workspace.test.mjs 가
      테·줄무늬 없음을 단언한 **별도 결정**이다(지금 읽는 문서 행도 같은 나무의 행이라 오너 결정 2 가 남긴 예외다). */
.talk__item.is-current {
  background: var(--ui-action-primary-soft);
  box-shadow: var(--ui-selected-ring);
}
/* 강제색(고대비)에서는 바탕도 그림자도 시스템이 지운다 — 거기서는 **형태**가 말한다(수법은 session.css 간트 띠 절과 같다:
   forced-color-adjust: none 을 쓰지 않고 팔레트를 존중하며 시스템 색 키워드만 쓴다). outline 을 음수 offset 으로 접어
   카드 폭을 안 늘린다(안쪽 테와 같은 자리). 두 패널(검토 회신·첨삭 메모)과 이 시트의 고른 자리 전부가 한 규칙이다(오너 결정 2
   (2026-09-29)). 키보드 초점을 브라우저 outline 이 그리는 자리는 초점이 선 동안 비킨다 — 같은 속성이라 덮으면 초점이 안 보인다. */
@media (forced-colors: active) {
  .talk__item.is-current,
  .ui-v2 .talk__pick[aria-pressed="true"],
  .talk__mention-item.is-active,
  .page-admin .tnav__item[aria-current]:not(:focus-visible),
  .page-notices .notice-item[aria-current]:not(:focus-visible),
  .page-folders .folders-table tbody tr[aria-current],
  .shell-immersive .rail__item[aria-current]:not(:focus-visible),
  .shell-immersive .topbar__tools #splitToggle[aria-expanded="true"]:not(:focus-visible),
  .ui-v2 .th-chips .ui-badge.th-chip--on,
  .ui-v2 .report-pager__num--on {
    box-shadow: none;
    outline: var(--ui-border-width) solid Highlight;
    outline-offset: calc(var(--ui-border-width) * -1);
  }
}
/* 카드 동작 줄의 「삭제」 — 파괴로 가는 launcher 는 색(danger-ghost)만 아니라 **자리로도** 갈라 선다: 같은 줄의 끝, 한 칸 더 떨어져
   (DESIGN-portal-ui.md 「표 행과 목록 행 안의 동작」 · 선례 .wiki-job-actions). 두 패널(회신·첨삭 메모) 한 벌이다(2026-09-21 —
   앞 판은 「반영함」·「답글」과 같은 파랑 글자 단추라 확인창에 가서야 붉었다). */
.talk__acts .ui-button--danger-ghost { margin-inline-start: var(--ui-space-2); }

/* 멘션 — 본문의 `@이름` 표식과 작성란 **위** 사람 목록(role=listbox, comments.js 가 글상자 앞에 세운다). */
.talk__mention { color: var(--ui-action-primary-hover); font-weight: var(--ui-font-weight-bold); }
.talk__mention-list {
  margin: 0 0 var(--ui-space-1); padding: var(--ui-space-1); list-style: none;
  border: var(--ui-border-width) solid var(--ui-border-default); border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface); box-shadow: var(--ui-shadow-surface); max-height: 14rem; overflow-y: auto;
}
/* 답글·수정 폼 안의 목록은 **흐름 밖 덮개**다 — 흐름 안(flex 항목)에 세우면 내용 폭으로 줄고(실측 172~240px vs
   글상자 296px), 열릴 때마다 글상자가 목록 높이만큼 튄다(실측 236px). 기본은 글상자 위, 위에 자리가 없으면
   아래(.is-below — comments.js place() 가 판정). 폭은 글상자와 같다. app.css 는 동결이라 여기에. */
.talk__reply, .talk__edit { position: relative; }
.talk__reply .talk__mention-list, .talk__edit .talk__mention-list {
  position: absolute; left: 0; right: 0; bottom: 100%; z-index: 2; margin: 0 0 var(--ui-space-1);
}
.talk__reply .talk__mention-list.is-below, .talk__edit .talk__mention-list.is-below {
  top: 100%; bottom: auto; margin: var(--ui-space-1) 0 0;
}
.talk__mention-item {
  display: flex; align-items: center; gap: var(--ui-space-2);
  padding: var(--ui-space-1) var(--ui-space-2); border-radius: var(--ui-radius-sm); cursor: pointer;
  font-size: var(--ui-type-label); color: var(--ui-fg-strong);
}
.talk__mention-item.is-active, .talk__mention-item:hover { background: var(--ui-action-primary-soft); }
/* 키보드로 고른 사람 칸(aria-selected · comments.js)은 손 얹은 칸과 채움이 같다 — 테가 둘을 가른다(오너 결정 2 (2026-09-29)). */
.talk__mention-item.is-active { box-shadow: var(--ui-selected-ring); }
.talk__mention-role { margin-left: auto; color: var(--ui-fg-muted); font-size: var(--ui-type-caption); }

@media (max-width: 880px) {
  /* 서랍이 덮는 동안은 핀을 안 그린다 — 눌러도 서랍이 받는다. 집는 동안은 서랍이 비켜 있어 보인다.
     알약은 ≤880 에서 **아예 안 선다**(부르는 쪽이 setCtaEnabled 로 끈다 — 그 폭에서는 서랍이 대화상자라 바탕이 inert 다).
     이 한 줄은 그 결정이 어긋났을 때의 그물이다 — 열린 서랍 아래 알약은 눌러도 서랍이 받는다. */
  .reader--talk .talk-pins, .reader--talk .talk-cta { display: none; }
}
/* 움직임 줄이기 — 핀의 전이와 확대를 지운다. ⚠ 그 `transform: scale(1.12)` 가 「지금 고른 핀」의 **눈에 보이는 채널**이었다:
   지우면 남는 것은 soft 링 하나(흰 문서 위 1.12:1)라, 움직임 줄임을 켠 사람에게는 고른 핀이 나머지 핀과 구별되지 않았다 —
   카드에는 테를 세우고(.talk__item.is-current) 그 카드를 가리키는 핀은 못 알아보는 비대칭이었다(2026-09-22).
   지운 채널을 **정적 채널로 갈음한다**: 핀의 2px 흰 border 바깥에 action 색 링이 한 겹 선다(카드와 같은 어휘 · 새 토큰·새 부품 없음).
   초점이 온 핀은 그대로 초점 링이 진다 — 같은 특이도라 이 규칙이 뒤에서 이기므로 `:not(:focus-visible)` 로 비킨다. */
@media (prefers-reduced-motion: reduce) {
  .talk-pin, .talk-pin:hover, .talk-pin.is-current { transition: none; transform: none; }
  .talk-pin.is-current:not(:focus-visible) {
    box-shadow: 0 0 0 calc(var(--ui-border-width) * 3) var(--ui-action-primary), var(--ui-shadow-surface);
  }
}
@media print { .talk-pins, .talk-pickbar, .talk-cta { display: none !important; } }

/* ── 첨삭 메모 — `.talk` 의 자리를 나눠 쓰는 패널 (2026-09-18) ────────────────
 *
 * 오너 반려 둘: 「개판임. 목업임? MVP임?」 · 「미시적으로 할 거면 안 하는 게 베스트」.
 *
 * 앞 판은 이 패널을 `lib/doc_canvas.php` 안 인라인 `<style>` 50줄로 **다시 그렸다.** 머리·라벨·개수·닫기·
 * 목록·작성란·오류의 해부가 `.talk` 와 1:1 인데, 한쪽은 토큰으로 서고 이쪽은 맨손 색 열 가지로 섰다.
 * 게다가 `var(--ui-bg, #fff)`·`var(--ui-line, #d8d8d8)` 처럼 **없는 토큰**을 불러 대체값이 그려졌고,
 * `position: fixed; top: 0` 이라 문서와 상단 바를 덮었다 — 회신 패널은 무대의 형제로 서서 문서를 좁힐 뿐이다.
 * 색만 토큰으로 바꾸면 **생김새가 같고 규칙이 다른 패널이 두 벌로 굳는다.** 그래서 부품을 쓴다.
 *
 * 레이아웃(21rem·flex·모바일 전환)은 `.talk` 가 이미 갖고 있다(app.css). 마크업이 두 클래스를 함께 달고
 * **차이만** 여기서 준다 — 「만든 세션」(`.cells`)과 같은 방식이다.
 */
/* 「고객에게 안 보임」 — 이 패널의 정체. **제목 곁의 곁말**이지 두 번째 제목이 아니다(2026-09-21 사용자 픽 「이것만 좀 UI 별로다」).
   앞 판은 굵게·자간 벌림으로 × 옆에 오른쪽 정렬돼 제목과 같은 무게로 읽혔다. 지금은 자물쇠 표식 + 보통 굵기로 개수 뒤에 서고,
   빈칸(margin-right:auto)이 ×를 끝으로 민다. 알약(.ui-status)으로 바꾸지 않는다 — 갈래를 알약으로 쓰지 말라는 결정이 있다
   (design-system.css .ui-kind 머리 주석 · 36px 알약이 그 줄에서 가장 큰 물체가 된다, 2026-08-31 실측). */
.ui-v2 .notes__only {
  flex: none; margin-right: auto; display: inline-flex; align-items: center; gap: var(--ui-space-1);
  color: var(--ui-fg-muted); font-weight: var(--ui-font-weight-medium); letter-spacing: normal;
}
/* 개수의 `margin-right:auto`(app.css .talk__count)는 이 패널에서 **표식이 진다** — 둘 다 auto 면 빈칸을 나눠 가져
   표식이 머리 한가운데로 밀린다(2026-09-21 실측). 개수는 제목에 붙고, 표식이 × 를 끝으로 민다. */
.ui-v2 .notes .talk__count { margin-right: var(--ui-space-2); }
.ui-v2 .notes__only .i { width: 0.875rem; height: 0.875rem; }

/* 알림 한 줄(#notesStatus, 작성란 아래) — 2026-09-21 부터 **눈에도 보인다**. 앞 판은 `ui-visually-hidden` 이라 계산값이
   `width:1px · clip:rect(0,0,0,0)` 였고(실측), 반영·지움·남김이 일어나도 사람 눈에 남는 단서는 입구의 개수 하나뿐이었다.
   모양은 같은 셸의 저장 상태 줄(document-workspace.css `.document-save-status`)을 그대로 베낀다 — muted 캡션 한 줄.
   왼쪽 여백은 space-5 다: 작성란이 바깥 space-2 + 안 space-3 이라, 그 안의 글과 **같은 세로선**에 선다.
   비면 **여백만** 걷는다 — 줄은 접근성 트리에 남는다(2026-09-22). 빈 줄이 남으면 목록 상자가 그만큼 작아진 채로 서고 말할
   때마다 화면이 들썩이므로 자리는 걷어야 하는데, 앞 판(같은 날)은 그것을 `display:none` 으로 했다: 그러면 비는 동안 이 요소가
   트리에서 **사라져**, announce 가 글을 넣는 순간 「없던 live region 이 내용을 갖고 나타나는」 꼴이 되어 화면 읽기가 대부분
   안 읽는다(삽입 시점의 초기 내용은 알림 대상이 아니다). 지우는 손이 셋(패널 누름 capture·글상자 입력·apply)이라 거의 모든
   알림이 그 상태에서 시작했다 — 보이게 만들면서 이 줄의 **원래 유일한 목적**을 깼던 것이다.
   여백만 걷어도 자리는 그대로 사라진다: 이 span 은 `.talk` 의 flex 아이템이라 블록화되고, 빈 블록 상자는 line box 가 없어
   **높이가 이미 0** 이다(관문의 `empty.h === 0`(offsetHeight)이 그 사실을 문다 — 남는 것은 margin-bottom 12px 뿐이었다). */
.ui-v2 .notes .talk__status {
  flex: none;
  margin: 0 var(--ui-space-5) var(--ui-space-3);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption);
  line-height: var(--ui-line-body);
  word-break: keep-all;
}
.ui-v2 .notes .talk__status:empty { margin-bottom: 0; }

/* 카드(2026-09-21) — 카드 전체가 눌림 대상이던 앞 판을 걷었다(키보드로는 자리로 갈 길이 없었고, 「반영함」을 빗맞히면
   문서가 튀었다). 자리로 가는 것은 **인용 단추**(.talk__pinq — 검토 회신과 같은 부품)다. 바탕은 짧게 물든다. */
/* 전이에 테를 함께 태운다(2026-09-21) — 바탕만 물들고 테는 **한 칸에 튀어나오면** 같은 상태 변화가 두 속도로 읽힌다.
   아래 prefers-reduced-motion 절의 `transition: none` 이 이 규칙을 통째로 끄므로 거기는 더 적을 것이 없다. */
.ui-v2 .notes .talk__item {
  transition: background-color var(--ui-motion-fast) var(--ui-ease-standard),
              box-shadow var(--ui-motion-fast) var(--ui-ease-standard);
}
/* 반영된 메모는 **지우지 않고 가라앉힌다** — 무엇을 이미 고쳤는지가 기록이다. 가라앉힘은 **그 메모의 글자에만** 건다(2026-09-21).
   앞 판은 카드 통째에 opacity .55 를 걸어 켜진 「되돌리기」·「삭제」·인용 단추와 초점 링까지 흐려졌다(토큰 합성 대비 2.66:1 —
   14px 굵은 글자는 4.5:1 이 필요하다, WCAG 1.4.3). 원전: 요약의 지운 줄(app.css .sum__change--removed > p)·형제의 지운 회신
   (.talk__gone)·공용 비활성(design-system.css — opacity 1 + muted). 자식 결합자라 그 밑 에이전트 답글에는 줄이 안 그어진다 —
   반영한 것은 사람의 메모이지 에이전트의 답이 아니다. 묶음은 목록 끝의 .notes__donegroup(notes.js doneGroup)이다. */
.ui-v2 .notes .talk__item.is-done > .talk__text {
  color: var(--ui-fg-muted); text-decoration: line-through; text-decoration-thickness: 1px;
}
/* 방금 남긴 메모 — 제자리에서 불투명도로만 선다(오너 결정 6, 2026-09-29 — 목록에 새 항목이 서는 일은 질문 화면의 새 턴과 한 사건이다).
   값은 interactions.js PortalMotion.reveal 그대로(.65 → 1 · --ui-motion-nav · --ui-ease-nav-in). 앞 판은 한 칸 아래에서 떠올랐다 — 이동 0 은 관문(reader-notes)이 잰다. */
.ui-v2 .notes .talk__item.is-new { animation: notes-in var(--ui-motion-nav) var(--ui-ease-nav-in) both; }
@keyframes notes-in { from { opacity: .65; } }
/* 자리가 없는 메모 — 인용 단추와 같은 자리·같은 먹선이되 **누를 것이 없다**는 것을 무채색으로 말한다. */
.notes__whole {
  margin: 0 0 var(--ui-space-2); padding: var(--ui-space-1) var(--ui-space-2) var(--ui-space-1) var(--ui-space-3);
  border-left: 3px solid var(--ui-border-default);
  color: var(--ui-fg-muted); font-size: var(--ui-type-caption); line-height: var(--ui-line-body);
}
@media (prefers-reduced-motion: reduce) {
  .ui-v2 .notes .talk__item { transition: none; }
  .ui-v2 .notes .talk__item.is-new { animation: none; }
}
/* 비어 있어 못 누르는 주 단추(「남기기」·「저장」) — 공용 비활성 규칙은 바탕을 `--ui-bg-subtle` 로 까는데 작성란 바탕도,
   카드 hover 바탕(app.css .talk__item:hover)도 같은 색이라 **테가 사라져 글자만 남았다**(2026-09-21 실측 1440·390).
   바탕을 한 단 짙은 회색으로 **채운다** — 원전은 홈 질문 작성란의 비활성 보내기(home.css .home-ask__toolbar button:disabled),
   테두리 토큰을 채움으로 쓴 선례는 app.css .sum__seg::before·codex-settings.css meter 다. 글자는 공용 비활성 그대로(--ui-fg-muted, 약 4.3:1).
   앞 판(같은 날)은 흰 바탕+테 한 줄이었다 — 그것은 이 화면에서 **켜진** 보조 단추의 옷(design-system .ui-button--secondary · 머리
   도구줄)이라, 옆의 파란 글자 「자리 집기」가 도리어 주 단추로 읽혔다. 두 패널(메모·회신)·세 폼 한 규칙이다(작성란 규칙을 형제에 —
   판정은 notes.js syncSend·comments.js syncSubmit). 초점을 받을 수 있는 aria-disabled 는 초점 링(box-shadow)을 지우지 않는다. */
.ui-v2 :is(.talk__new, .talk__reply, .talk__edit) .ui-button--primary:is(:disabled, [aria-disabled="true"]:not(:focus-visible)) {
  background: var(--ui-border-default);
  box-shadow: none;
  color: var(--ui-fg-muted);
}

/* 편집기에서 메모 패널이 열린 동안 — 빌더의 hover 상자와 태그 이름표(「.snSPAN」)를 가린다. 빌더는 집기를 멈춰도
   (notes.js holdCanvas · isPreview) 그 상자를 마우스를 따라 계속 옮긴다. 인라인 display 를 빌더가 쓰므로 !important. */
#vvveb-builder.is-noting #highlight-box { display: none !important; }
/* 편집기에서 「자리 집기」 중 — 읽기 화면의 `.stage__pane--a.is-picking` 과 같은 테두리 한 겹(포인터는 안 막는다). */
#iframe-wrapper.is-picking::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 4;
  box-shadow: inset 0 0 0 2px var(--ui-action-primary);
}

/* 자리를 잃은 묶음 — 경고의 낱말이지 오류가 아니다. 카드마다의 상태 낱말은 인용 단추 안(.talk__pinstate)에 선다. */
.notes__lost:not(:empty) {
  margin-bottom: var(--ui-space-2); padding-bottom: var(--ui-space-2);
  border-bottom: var(--ui-border-width) dashed var(--ui-border-default);
}
.notes__losthead {
  margin: var(--ui-space-1) var(--ui-space-3); color: var(--ui-warning-default);
  font-size: var(--ui-type-caption); line-height: var(--ui-line-body);
}
/* 반영 뒤 되돌리기 줄(2026-09-21 · 사용자 승인 · notes.js undoLine) — 앞 판은 반영하면 카드가 목록 끝 접힌 묶음으로 들어가
   무르는 길이 「묶음을 펼쳐 ✓ 찾기」뿐이었다. 새 부품이 아니다: 결은 패널 상태 칸(app.css .talk__state — subtle 바탕 · md 모서리 ·
   muted 글자)을 **한 줄로 접은 것**이고, 단추는 카드의 글자 단추(「되돌리기」)와 머리 도구(×)를 그대로 쓴다.
   자리는 목록 상자 **위**(스크롤 상자 밖)다 — 목적지로 굴러가도 안 밀려난다. 좌우는 목록의 안쪽 여백(space-2)과 같은 선,
   글은 카드 글과 같은 안쪽(space-3)에서 시작한다. 높이는 compact 단추 하나다 — 390 실측으로 목록이 415 → 379px(8.7%),
   요구는 12% 미만(두 줄로 접히면 그만큼 더 먹는다 · 글은 caption 이라 21rem 에 한 줄로 든다 — 네 폭 모두 글 188px/줄 320px). 위아래 여백은 안 둔다:
   머리(44px)가 이미 숨을 두고, 아래는 목록 상자의 안쪽 여백이 띄운다. 들어올 때는 방금 남긴 카드와 같은 모션(notes-in)을 한 번 탄다. */
.ui-v2 .notes__undo {
  flex: none;
  display: flex; align-items: center; gap: var(--ui-space-1);
  min-height: var(--ui-control-compact);
  margin: 0 var(--ui-space-2);
  padding-inline-start: var(--ui-space-3);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-subtle);
  color: var(--ui-fg-muted);
  font-size: var(--ui-type-caption); line-height: var(--ui-line-body);
  animation: notes-in var(--ui-motion-nav) var(--ui-ease-nav-in) both;
}
.notes__undo-text { flex: 1 1 auto; min-width: 0; }
@media (prefers-reduced-motion: reduce) { .ui-v2 .notes__undo { animation: none; } }
/* 반영한 메모 — 목록 끝의 접힌 묶음(2026-09-21, notes.js doneGroup). 부품은 design-system 의 .ui-disclosure(표지 걷기·초점 링)와
   .ui-chevron(여닫기 표지)이고 여기서 정하는 것은 **배치뿐**이다. 가름줄은 위 잃은 자리 묶음과 같은 한 줄(앞에 카드가 있을 때만), 머리는
   잃은 자리 머리와 같은 들여쓰기·글자 크기에 무채색 — 경고가 아니라 지난 일이다. 누를 자리라 높이는 compact 단추만큼, 펼침 표지는
   포털 공용의 선 셰브런 하나를 머리 글 앞에 둔다(오너 결정 5, 2026-09-29 — 제자리 여닫기라 → 에서 ↓), hover 는 요약의 출처
   펼침(app.css .sum__src > summary)과 같다. */
.ui-v2 .notes__donegroup:not(:first-child) {
  margin-top: var(--ui-space-2); padding-top: var(--ui-space-2);
  border-top: var(--ui-border-width) dashed var(--ui-border-default);
}
.ui-v2 .notes__donegroup > summary {
  display: flex; align-items: center; min-height: var(--ui-control-compact); padding: 0 var(--ui-space-3);
  color: var(--ui-fg-muted); font-size: var(--ui-type-caption); line-height: var(--ui-line-body); cursor: pointer;
}
.ui-v2 .notes__donegroup > summary:hover { color: var(--ui-fg-strong); }

/* 편집기 화면에는 무대의 형제로 설 자리가 없다(캔버스 하나뿐) — 그 화면에서만 떠 있는다.
   읽기 화면에서는 이 변형을 안 붙이고 회신 패널과 나란히 서서 문서를 좁힌다.
   `top: 0` 은 스크립트 전의 값일 뿐이다 — 편집기 셸(lim-shell.js seat())이 상단바를 실측해 캔버스와 **같은 좌석**에
   앉힌다(2026-09-21 · 앞 판은 그대로 top:0 이라 열면 「저장」·「발행」을 덮었다). 높이를 여기서 숫자로 빼지 않는다. */
.notes--float {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: var(--ui-layer-popover);
  width: min(21rem, calc(100vw - var(--ui-space-8)));
  border-left: var(--ui-border-width) solid var(--ui-border-default);
}
/* 편집기의 떠 있는 입구 — 이름과 남은 수는 읽기 화면 도구줄의 입구와 같다(「첨삭 메모」 + [data-n], doc_canvas.php · 2026-09-21).
   앞 판은 이 화면만 「메모」라 불러 같은 패널을 여는 단추가 화면마다 이름이 달랐다(WCAG 3.2.4). */
.ui-v2 .notes__toggle {
  position: fixed; right: var(--ui-space-4); bottom: var(--ui-space-4);
  z-index: calc(var(--ui-layer-popover) + 1);
}
/* 열려 있는 동안에는 이 단추가 없다 — 떠 있는 패널의 오른쪽 아래가 **작성란의 보내기 단추**(지금은 「남기기」,
   2026-09-18 판에는 「새 메모」) 자리라 둘이 겹쳤다(실측 1440·편집기). 닫는 길은 패널 안 × 이고, 그 × 가 초점을 이 단추로 돌려준다
   (notes.js 가 aria-expanded 를 먼저 false 로 되돌리므로 초점이 갈 때는 이미 서 있다). */
.ui-v2 .notes__toggle[aria-expanded="true"] { display: none; }

/* ── 핵심 요약 — 카드의 한글 줄바꿈과 단추의 제자리 (2026-09-18) ──────────────
 *
 * 사용자 지적: 「css 집중 안하지? 제대로 안보는 것 같은데?」 — 브라우저에서 집은 자리가
 * `#sumBtn` 과 요약 본문의 목록이었다. 재 보니 둘 다 실재하는 결함이었다.
 *
 * ① **한글이 낱말 가운데서 잘렸다.** 운영 실측(2026-09-18 · 실문서): 「기능정의서를 시 /
 *    험판 산식에」 · 「33%의 이용 / 자 값이」 · 「지방을 줄이라고 안 / 내되는 상황」 ·
 *    「현행보다 크게 튀 / 는 상황」. CJK 의 기본값이 **글자 아무 데서나 끊기**라 그렇다.
 *    이 집의 규율은 이미 `keep-all` 이고(access-pages·install·home·document-workspace 등
 *    9파일 26곳 · install.css:751-769 는 다섯 값을 재 본 기록까지 남겼다), **요약 카드만
 *    통째로 빠져 있었다**(app.css 에 keep-all 0곳). 뿌리 `.sum` 하나에 주면 상속으로
 *    다이얼로그·미니 카드(.sum--mini)·파일 화면까지 한 번에 덮는다 — 세 표면이 같은
 *    부분틀(lib/summary_view.php)을 쓰기 때문이다.
 *    `overflow-wrap: anywhere` 를 짝으로 둔다 — keep-all 은 긴 영문·URL 을 안 끊어서,
 *    없으면 이번엔 가로로 넘친다(install.css 가 같은 짝을 쓴다).
 *
 * ② **단추가 혼자 형광 연두였다.** app.css 의 옛 알약 판이 죽고 `#sumBtn` 배경 한 줄만
 *    id 선택자로 살아남은 잔해였다(그 자리 주석 참조). 「이 화면에서 먼저 눌러야 할
 *    단추」라는 뜻은 유지하되, **으뜸(편집 · 진한 파랑) 아래 급**으로 읽히게 연한 강조로
 *    쓴다. 그래서 값은 전부 `--ui-*` 에서 온다 — 맨손 색 0.
 */
.ui-v2 .sum { word-break: keep-all; overflow-wrap: anywhere; }

/* 제목은 줄 길이를 고르게 — 40px 표제가 마지막 줄에 한 낱말만 남기면 그것도 어긋나 보인다. */
.ui-v2 .sum__headline, .ui-v2 .sum__h2 { text-wrap: balance; }

/* ⚠ **「핵심 요약」의 라임은 잔해가 아니라 의도다**(오너 2026-09-18 「기존 색이었던 형광으로 바꿔」).
   내가 한 번 지웠다가 되돌렸다 — 옛 알약 판이 죽은 것을 보고 **짝인 라임까지 시체로 읽은 것**이
   틀렸다. 죽은 것은 알약 기하이고, 라임은 「이 화면에서 먼저 눌러야 할 단추」라는 살아 있는 결정이다.
   그 규칙은 app.css 의 `.topbar__tools #sumBtn` 에 그대로 있다 — 여기서 덮지 않는다.
   ★ 다음 사람에게: **안 쓰이는 것처럼 보이는 색이 결정일 수 있다.** 기하가 죽었다고 색까지 죽은 것이 아니다. */

/* ── 한 부품은 어느 셸에 놓여도 같아야 한다 (2026-09-19) ─────────────────────
 *
 * 사용자 지적: 「이거 border 는 왜 붙어 있는 거야?? 관보에서의 핵심요약과 css 가 일부 다르네」.
 * 재 보니 **테두리가 아니었다** — 이 파일 위쪽의 일반 단추 규칙
 *   `.ui-v2:is(.shell-workbench,.shell-reading,.shell-bare) :where(main,.auth) :is(button,.btn):not(.ui-button)`
 * 이 걸음 단추에 `box-shadow: inset 0 0 0 1px var(--ui-border-default)` 과 흰 배경·좌우 16px·
 * 굵은 글씨를 입힌 것이다(운영 실측: `rgb(214,223,233) 0 0 0 1px inset`).
 *
 * 왜 관보에서는 안 그런가: 그 화면의 셸은 `shell-immersive` 라 위 선택자가 **안 걸린다**
 * (dev 실측 — 읽기 화면 body = `ui-v2 shell-immersive fill page-report-reader`). 즉 같은 부품이
 * **놓인 셸에 따라 다르게 생겼다.** 부품은 제 모양을 스스로 정해야지 그릇에 따라 변하면 안 된다.
 *
 * 왜 선을 지우는가(디자인 판단): 이 목록은 이미 **번호 배지**로 항목이 갈린다. 거기에 흰 상자와
 * 1px 선을 더하면 한 목록에 구분 장치가 셋이고, 그 상자는 다시 바깥 카드 안에 들어가 상자가 세 겹이
 * 된다 — 읽는 눈에는 목록이 아니라 **표**로 보인다. 관보 쪽이 옳고 이 화면이 틀렸다.
 *
 * 값을 다시 적지 않고 **컴포넌트가 원한 자리로 되돌린다**(`.ui-v2 .sum__jump` 가 app.css 에 있다).
 * `#sum` 으로 묶어 특정도를 id 한 칸으로 이긴다 — 위 일반 규칙은 (0,4,0) 이라 클래스만으로는 못 이긴다.
 */
/* ⚠ **한 번 통째로 껐다가 물렸다.** `#sum` 안 모든 단추에 `height: auto` 를 주자 걸음 막대
   (`.sum__seg` — 글자 없이 app.css 가 `height: var(--ui-space-5)` 로 세우는 조각)가 0×0 으로
   접혀 **눌 수 없게** 됐다(관문 reader-summary 가 「보이지 않는다」로 잡았다). 그래서 기하는
   **자기 값을 가진 부품에서 손을 뗀다** — 아래는 걸음 단추 하나와, 누구도 원한 적 없는 그림자뿐이다. */
.ui-v2 #sum .sum__jump {
  min-height: 0;
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
}
/* 그림자는 카드 안 어느 부품도 선언한 적이 없다 — 셸이 얹은 것이라 전부에서 걷는다. */
.ui-v2 #sum :is(button, .btn):not(.ui-button) { box-shadow: none; }
/* 닫기 단추의 바탕도 셸이 흰색으로 덮었다(app.css 는 `--ui-bg-subtle` 을 원한다) — 그 한 값만 되돌린다. */
.ui-v2 #sum .sum__x { background: var(--ui-bg-subtle); }

/* 리드는 **두 문장이 한 단락**이었다 — 「무엇인가」와 「주의」가 한 줄로 흘러 끝 줄에 낱말 하나만
   남았다(운영 실측: 「주세요.」). 문장을 나누는 것은 **줄이지 말이 아니다** — 글자는 한 자도 안 바꾼다
   (이 카드의 글자는 오너 결정 자리다 · summary_view.php 머리말 참조). 주의 줄은 한 단 낮춰 읽힌다. */
.ui-v2 #sum .sum__desc + .sum__desc {
  margin-top: var(--ui-space-1);
  color: var(--ui-fg-muted);
}

/* ── 관보 영상 조작 판(2026-09-23) — 문서 밖, 셸이 소유한 층 ──────────────────────────────────────
   오너: 「seekbar 를 유저가 직접 드래그해서 시점을 옮기고 싶다 — 기본형이라 툭툭 끊긴다」. 문서(iframe)는 한 바이트도
   안 바뀐다 — 판은 왼쪽 자리(.stage__pane--a) 위 셸 층(.vdeck-layer)에 절대배치되고 영상 아래 가장자리 안쪽에 붙는다
   (assets/reader-video.js). 기본 컨트롤은 iframe 창의 구성 시트로 감춘다. 여기는 셸 쪽만. 핀(.talk-pins)과 같은 z 층(5).
   app.css 는 동결 — 새 규칙은 전부 여기 얹는다. */
.vdeck-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 5; }
.vdeck {
  position: absolute; pointer-events: auto; box-sizing: border-box;
  display: flex; align-items: center; gap: var(--ui-space-2);
  padding: var(--ui-space-1) var(--ui-space-2);
  border-radius: var(--ui-radius-md);
  background: var(--ui-bg-emphasis); color: var(--ui-fg-inverse);
  box-shadow: var(--ui-shadow-surface);
  font-size: var(--ui-type-caption); line-height: 1.25rem;
}
.vdeck[hidden] { display: none; }
/* 단추 — 보이는 것은 2rem, 누르는 것은 44px(계약 §10). 스프라이트는 fill:none·stroke(app.css:426)라 색만 준다. */
.vdeck__btn {
  position: relative; flex: none; width: 2rem; height: 2rem; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--ui-radius-pill); background: transparent; color: inherit; cursor: pointer;
}
.vdeck__btn::after { content: ""; position: absolute; inset: -6px; border-radius: inherit; }
.vdeck__btn .i { width: 1rem; height: 1rem; }
.vdeck__btn:hover { background: rgba(255, 255, 255, .14); }
.vdeck__btn:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
/* 시크바 — 끌어서 옮기는 것이 이 판의 본체다. 손잡이 44px 높이 안에서 잡힌다. */
.vdeck__seek {
  flex: 1 1 auto; min-width: 0; height: 1.5rem; margin: 0; padding: 0;
  cursor: pointer; accent-color: var(--ui-action-primary); background: transparent;
}
.vdeck__seek:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); border-radius: var(--ui-radius-pill); }
.vdeck__time { flex: none; font-variant-numeric: tabular-nums; white-space: nowrap; opacity: .9; }
/* 미리보기 — 시크바 위, 손끝 자리에 그 시점의 그림(발행 때 구운 스프라이트 한 장을 잘라 쓴다). 판이 기준이라 left 만
   스크립트가 준다. 손을 가로채지 않는다(pointer-events: none). 판이 없는 영상에는 이 요소 자체가 없다. */
.vdeck__peek {
  position: absolute; left: 0; bottom: calc(100% + var(--ui-space-2)); transform: translateX(-50%);
  pointer-events: none; display: flex; flex-direction: column; align-items: center; gap: var(--ui-space-1);
  padding: var(--ui-space-1); border-radius: var(--ui-radius-sm);
  background: var(--ui-bg-emphasis); color: var(--ui-fg-inverse); box-shadow: var(--ui-shadow-surface);
  font-size: var(--ui-type-caption); line-height: 1rem; font-variant-numeric: tabular-nums;
}
.vdeck__peek[hidden] { display: none; }
.vdeck__peek-img { flex: none; background-repeat: no-repeat; background-color: #000; border-radius: calc(var(--ui-radius-sm) - 2px); }
/* 좁은 화면 — 서랍이 열려 문서를 덮는 동안은 핀과 같이 사라진다. 인쇄에는 재생기가 없다. */
.reader--talk .vdeck-layer { display: none; }
@media print { .vdeck-layer { display: none; } }

/* ── 관보 도해 뷰어 입구(2026-10-02, DESIGN-gazette-diagrams.md 10 의 3번) — 문서 밖, 셸이 소유한 층 ─────────────────
   굽은 그림(figure.plate.diagram[data-dgx]) 오른쪽 위 안쪽에 「뷰어로 열기」 링크(assets/reader-diagram.js). 문서(iframe)는
   한 바이트도 안 바뀐다. 누르면 셸 대화상자(.dgxv-dialog) 안 같은 출처 iframe 으로 Archify 뷰어(diagram.php)를 연다.
   영상 판 · 핀과 같은 z 층(5). 입구는 <a> 라 main 안 맨 button 규칙(위 「폼과 조작」)에 안 걸린다. 대화상자는 body 에 붙어
   main 밖이므로 그 단추는 app.css 의 맨 button 리셋(높이 · 가운데 · 테두리 · hover 테두리)만 겨룬다 — 그 속성을 다 선언한다.
   app.css 는 동결 — 새 규칙은 전부 여기 얹는다. */
.dgxv-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 5; }
.dgxv-open {
  position: absolute; pointer-events: auto; box-sizing: border-box;
  display: inline-flex; align-items: center; gap: var(--ui-space-1);
  min-height: 2rem; padding: 0 var(--ui-space-2); margin: 0;
  border: 0; border-radius: var(--ui-radius-pill);
  background: var(--ui-bg-emphasis); color: var(--ui-fg-inverse); box-shadow: var(--ui-shadow-surface);
  font: inherit; font-size: var(--ui-type-caption); line-height: 1.25rem; white-space: nowrap;
  text-decoration: none; cursor: pointer;
}
.dgxv-open[hidden] { display: none; }
.dgxv-open::after { content: ""; position: absolute; inset: -6px; border-radius: inherit; }   /* 누르는 자리 44px(계약 §10) */
.dgxv-open .i { width: 1rem; height: 1rem; }
.dgxv-open:hover { background: var(--ui-fg-strong); color: var(--ui-fg-inverse); }
.dgxv-open:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
/* 좁은 자리(휴대폰 · 600px 미만 — reader-diagram.js COMPACT_PX)에서는 아이콘만: 글자 알약(94×32)이 그림 오른쪽 위의 글자를 덮었다
   (2026-10-02 검토 실측 — 390 폭 데이터 흐름도의 셋째 칸 머리). 이름은 aria-label 이 그대로 진다. 누르는 자리는 ::after 로 44px. */
.dgxv-layer--compact .dgxv-open { width: 2rem; padding: 0; justify-content: center; }
.dgxv-layer--compact .dgxv-open__text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* 대화상자 — 뷰어가 자리를 다 쓰도록 크게(휴대폰은 화면 전체). 닫히면 스크립트가 iframe 을 걷어 뷰어를 내린다. */
.dgxv-dialog {
  width: min(96vw, 1600px); height: min(92dvh, 1100px); max-width: none; max-height: none;
  margin: auto; padding: 0; border: 0; border-radius: var(--ui-radius-md);
  background: var(--ui-bg-surface); color: var(--ui-fg-default); box-shadow: var(--ui-shadow-overlay);
  display: flex; flex-direction: column; overflow: hidden;
}
.dgxv-dialog:not([open]) { display: none; }
.dgxv-dialog::backdrop { background: var(--ui-bg-scrim); }
.dgxv-dialog__head {
  flex: none; display: flex; align-items: center; gap: var(--ui-space-2);
  padding: var(--ui-space-2) var(--ui-space-3); border-bottom: var(--ui-border-width) solid var(--ui-border-default);
}
.dgxv-dialog__title {
  flex: 1 1 auto; min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--ui-type-label); font-weight: 600; color: var(--ui-fg-strong);
}
.dgxv-dialog__btn {
  flex: none; position: relative; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--ui-space-1);
  height: auto; min-height: 2rem; padding: 0 var(--ui-space-2); margin: 0;
  border: 0; border-radius: var(--ui-radius-pill); background: transparent; color: inherit;
  font: inherit; font-size: var(--ui-type-caption); white-space: nowrap; text-decoration: none; cursor: pointer;
}
.dgxv-dialog__btn::after { content: ""; position: absolute; inset: -6px; border-radius: inherit; }
.dgxv-dialog__btn .i { width: 1rem; height: 1rem; }
.dgxv-dialog__btn:hover { border: 0; background: var(--ui-bg-subtle); color: inherit; }
.dgxv-dialog__btn:focus-visible { outline: 0; box-shadow: var(--ui-focus-ring); }
.dgxv-frame { flex: 1 1 auto; width: 100%; min-height: 0; border: 0; background: #fff; }
.dgxv-frame[hidden] { display: none; }
/* 뷰어가 틀 안에 못 선 때(로그인 화면이 틀을 막는 경우 등) — 대화상자 몸 가운데에 사유와 새 창 길. */
.dgxv-blocked {
  flex: 1 1 auto; margin: 0; padding: var(--ui-space-6) var(--ui-space-4);
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--ui-space-1);
  text-align: center; font-size: var(--ui-type-body); color: var(--ui-fg-default);
}
.dgxv-blocked[hidden] { display: none; }
@media (max-width: 600px) {
  .dgxv-dialog { width: 100vw; height: 100dvh; border-radius: 0; }
}
@media (forced-colors: active) {
  .dgxv-open, .dgxv-dialog__btn { border: 1px solid ButtonText; }
}
/* 좁은 화면에서 서랍이 열려 문서를 덮는 동안만 사라진다 — 핀과 같은 문턱(≤880, 위 「검토 회신」). 넓은 화면에서는 회신 패널이
   문서 옆에 서므로 입구가 남는다(문턱 없이 두었더니 넓은 화면에서도 회신을 여는 동안 입구가 다 숨었다 — 2026-10-02 검토). 인쇄에는 없다. */
@media (max-width: 880px) { .reader--talk .dgxv-layer { display: none; } }
@media print { .dgxv-layer, .dgxv-dialog { display: none; } }
