/* 프로젝트관리 모듈 전용 스타일. 화면 옆 .razor.css 로 옮기면 안 걸리는 규칙이 있다. */

/* ── 구역 제목 ─────────────────────────────────────────── */
/* 한 화면에 표가 둘 이상일 때 가른다. <h2> 를 두면 화면 제목과 크기가 같아진다. */

.pm-subhead {
  margin: 0.8rem 0 0.4rem;
  font-size: var(--jsini-fs-md);
  font-weight: 600;
}

/* ── 탭 안쪽 ─────────────────────────────────────────────── */
/* DevExpress 탭은 내용 높이를 스스로 정하지 않아, 안의 좌우 분할이 0 높이로 잡힌다. */

.pm-tab-body {
  min-height: 60vh;
  padding-top: 0.6rem;
}

/* ── 다이어그램 자리 ─────────────────────────────────────── */
/* 그림은 컨테이너 크기를 그대로 쓴다. 높이가 없으면 0 이 되어 빈 칸이 된다. */

.pm-diagram-host {
  position: relative;   /* 아래 「불러오는 중」 덮개의 기준 */
  width: 100%;
  height: min(70vh, 760px);
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  overflow: hidden;
}

/* 그림을 불러오는 동안 덮는다. 그 사이 옛 그림이 보이므로 덮개가 클릭을 막고 진행 중임을 말한다. */
.pm-diagram-loading {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--jsini-surface) 72%, transparent);
  color: var(--jsini-text-muted, #6b7280);
  font-size: var(--jsini-fs-sm);
}

/* 도는 표시. DevExpress 것은 부품 안에 있어 덮개에는 CSS 로 둔다. */
.pm-diagram-loading::before {
  content: "";
  width: 1.1rem;
  height: 1.1rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: pm-spin 0.8s linear infinite;
}

@keyframes pm-spin {
  to { transform: rotate(360deg); }
}

/* 움직임을 줄여 달라고 한 사람에게는 돌리지 않는다 — 자리만 지킨다. */
@media (prefers-reduced-motion: reduce) {
  .pm-diagram-loading::before { animation: none; }
}

/* ── 덧붙이는 말 ─────────────────────────────────────────── */
/* 읽어도 되고 안 읽어도 되는 줄. 본문과 같은 굵기·색이면 같은 무게로 읽힌다. */

.pm-muted {
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-md);
}

/* 바깥 화면 iframe(`pm-frame`) 규칙은 없다 — 셸의 공용 `jsini-embed` 한 벌을 쓴다. */

/* ── 쿼리 테스터의 위아래 분할 (`pm-query-splitter`) ────────── */
/* 화면 옆 .razor.css 에 두면 안 걸린다: DxSplitter 는 범위 표시(b-xxxxx)를 안 받는다. 높이는 부모가 줘야 한다. */

.jsini-shell__content:has(> .pm-query-splitter) {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* 조회부와 경고 줄은 제 높이만 갖는다. 안 적으면 flex shrink 로 조건 칸이 납작해진다. */
.jsini-shell__content:has(> .pm-query-splitter) > *:not(.pm-query-splitter) {
  flex: 0 0 auto;
}

.jsini-shell__content > .pm-query-splitter {
  flex: 1;
  min-height: 0;
}

/* 판 안쪽 여백은 규칙이 읽는 변수를 덮어 건다. 크기 모드마다 값이 달라 셀렉터를 겨누면 되돌아온다. */
.pm-query-splitter.dxbl-splitter {
  --dxbl-splitter-pane-padding-x: 0;
  --dxbl-splitter-pane-padding-y: 0;
}

/* 판은 기본이 min-height: fit-content 라 안쪽 내용보다 작아지지 않는다. 긴 표는 분할판 밖으로 나간다. */
.pm-query-splitter > .dxbl-splitter-pane {
  min-height: 0;
}

.pm-query-splitter > .dxbl-splitter-pane > .dxbl-splitter-pane-content {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

/* 위 판. 자리표시 줄(pm-editor__hint)은 편집기 밖이라 height: 100% 를 주면 그 줄만큼 넘친다. */
.pm-query {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

.pm-query > .pm-editor {
  flex: 1;
  min-height: 0;
}

/* 아래 판. CommCont 가 판 높이를 받고 표가 그 안을 채운다. */
.pm-query-splitter .commcont {
  flex: 1;
  min-height: 0;
}

.pm-query-splitter .commcont > .commcont__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* ── 좌우 분할 (`pm-split`) ─────────────────────────────────── */
/* 판 둘은 CommCont 여야 한다(높이 규칙이 .commcont 를 겨눈다). 세 번째 모듈이 쓰면 app.css 로 올린다. */

.pm-split {
  display: grid;
  grid-template-columns: 1fr;

  /* 판 사이는 본문 여백(24px)과 같은 값으로 띄운다. 붙으면 어디까지가 왼쪽인지 눈이 안 가른다. */
  gap: var(--jsini-sp-2xl);
  align-items: start;
}

@media (width >= 62rem) {
  .pm-split { grid-template-columns: minmax(320px, 34%) 1fr; }
}

.pm-split__side,
.pm-split__main {
  min-width: 0;
}

/* 나란히 서는 자료 판은 위아래 간격을 격자가 정한다. 공통 .commcont + .commcont 규칙은 여기서 끈다. */
.pm-split > .commcont + .commcont {
  margin-top: 0;
}

/* ── 끌 수 있는 좌우 분할 (`pm-splitpane` · `SplitPane.razor`) ───── */
/* 이름을 pm-split 로 주면 위 격자 규칙이 .dxbl-splitter 의 display 를 덮어 표가 사라진다. 규칙은 모듈 CSS 에 둔다. */
/* 높이는 본문 바로 아래면 :has 로 남은 높이를 먹이고, 탭 안처럼 그럴 수 없는 자리는 어림값을 쓴다. */

.pm-splitpane {
  /* 탭 안처럼 부모가 높이를 안 주는 자리의 바닥값. :has 가 걸리면 flex: 1 이 대신한다. */
  height: 62vh;
  min-height: 320px;
}

.jsini-shell__content:has(> .pm-splitpane) {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* 조회부와 경고 줄은 제 높이만 갖는다. 안 적으면 flex shrink 로 조건 칸이 납작해진다. */
.jsini-shell__content:has(> .pm-splitpane) > *:not(.pm-splitpane) {
  flex: 0 0 auto;
}

.jsini-shell__content > .pm-splitpane {
  flex: 1;
  height: auto;
  min-height: 0;
}

/* 판 안쪽 여백은 규칙이 읽는 변수를 덮어 건다. 크기 모드마다 값이 달라 셀렉터를 겨누면 되돌아온다. */
.pm-splitpane__ui.dxbl-splitter {
  --dxbl-splitter-pane-padding-x: 0;
  --dxbl-splitter-pane-padding-y: 0;
}

/* 판은 기본이 min-height: fit-content 라 안쪽 내용보다 작아지지 않는다. 긴 표는 분할판 밖으로 나간다. */
.pm-splitpane__ui > .dxbl-splitter-pane {
  min-height: 0;
}

.pm-splitpane__ui > .dxbl-splitter-pane > .dxbl-splitter-pane-content {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.pm-splitpane__first,
.pm-splitpane__second {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
  min-height: 0;
  overflow: auto;
}

/* 좌우로 섰을 때만 손잡이 옆에 숨을 준다. 위아래 좁은 화면에서 벌리면 판이 옆으로 밀린다. */
.dxbl-splitter-horizontal > .dxbl-splitter-pane > .dxbl-splitter-pane-content > .pm-splitpane__first {
  padding-right: var(--jsini-sp-lg);
}

.dxbl-splitter-horizontal > .dxbl-splitter-pane > .dxbl-splitter-pane-content > .pm-splitpane__second {
  padding-left: var(--jsini-sp-lg);
}

/* 판 안의 pm-tab-body 는 탭용 최소 높이(60vh)가 판을 넘기므로 판 높이를 그대로 받게 되돌린다. */
.pm-splitpane__first > .pm-tab-body,
.pm-splitpane__second > .pm-tab-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  padding-top: 0;
}

/* CommCont 가 판 높이를 받고 표가 채운다. 본문 규칙은 > 로 겨누므로 이 판에 대해 따로 적는다. */
.pm-splitpane .commcont {
  flex: 1;
  min-height: 0;
}

.pm-splitpane .commcont > .commcont__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* CommCont 없이 표만 놓인 판도 채운다. app.css 의 어림값 상한(58vh)은 판 높이와 무관해 넘치거나 빈다. */
.pm-splitpane .commgrd {
  flex: 1;
  min-height: 0;
}

.pm-splitpane .commgrd > .dxbl-grid {
  height: 100%;
  max-height: none;
}

/* ── 기준 세그먼트 (`pm-axis`) ────────────────────────────────── */
/* 두 칸짜리 세그먼트를 맨 단추로 그린다(DevExpress 에 없다). 글자 크기는 rem 이 아니라 사다리를 쓴다(web/CLAUDE.md). */

.pm-axis {
  display: inline-flex;
  border: 1px solid var(--jsini-border);
  border-radius: 0.375rem;
  overflow: hidden;
}

.pm-axis__btn {
  appearance: none;
  border: 0;
  background: var(--jsini-bg);
  color: var(--jsini-text-muted);
  font: inherit;
  font-size: var(--jsini-fs-sm);
  padding: 0.3rem 0.9rem;
  cursor: pointer;
}

.pm-axis__btn + .pm-axis__btn {
  border-left: 1px solid var(--jsini-border);
}

.pm-axis__btn:hover {
  background: color-mix(in srgb, currentcolor 7%, transparent);
  color: var(--jsini-text);
}

/* 고른 칸은 면으로 칠한다. 테두리를 두르면 그 칸만 키가 커져 세그먼트가 들썩인다. */
.pm-axis__btn[aria-pressed='true'] {
  background: var(--jsini-accent);
  color: #fff;
  font-weight: 600;
}

.pm-axis__btn:focus-visible {
  outline: 2px solid var(--jsini-accent);
  outline-offset: -2px;
}

/* 좌우 분할의 한쪽을 위아래로 쌓는다 (`pm-stack`). min-width: 0 이 있어야 안쪽 표가 칸을 넘지 않는다. */
.pm-stack {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 0;
}

/* 쌓인 판 사이 간격은 위 gap 이 정한다. 공통 규칙과 겹치면 두 배가 된다. */
.pm-stack > .commcont + .commcont {
  margin-top: 0;
}

/* 분할판 안에 쌓이면 판 높이를 받아야 한다. flex 가 없으면 flex: 1 이 기준 높이 0 이 되어 표와 편집기가 접힌다. */
.pm-splitpane .pm-stack {
  flex: 1;
  min-height: 0;
}

/* 표 안에서 여러 줄 값을 한 줄로 붙잡는다. 그대로 두면 줄 하나가 표를 세로로 늘린다. */
.pm-oneline {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 진척 차트의 여백만 정한다. 높이는 차트(240px)가 갖는다. 둘 다 여기서 정하면 화면마다 달라진다. */
.pm-chart {
    margin: 0.75rem 0;
}

/* 표 안에서 바로 고치는 칸. 칸을 꽉 채워야 옆 칸과 높이가 맞는다. */
.pm-cell-edit {
    width: 100%;
}

/* 코드 편집기를 받는 동안 자리를 지켜 화면이 아래로 밀리지 않게 한다. */
.pm-editor__loading {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--jsini-text-muted, #6b7280);
    font-size: var(--jsini-fs-sm);
}


/* ── ERD 상자 (`.pm-erd`) ──────────────────────────────────── */
/* 네모·테두리만 maxgraph 가 그리고 속은 HTML 라벨이라 여기서 정한다. 높이 값(HEAD_H · FIELD_LINE_H)은 JS 와 같아야 한다. */

.pm-erd {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  font-size: 11px;
  line-height: 1.35;
  text-align: left;
}

/* 칸을 안 펼친 상자는 이름만 가운데. 높이는 JS 의 PLAIN_H 와 함께 고친다. */
.pm-erd--plain {
  justify-content: center;
}

.pm-erd--plain .pm-erd__head {
  padding: 2px 8px;
  background: none;
  border-bottom: 0;
  text-align: center;
}

/* 머리띠 — 이름과 설명. 표 하나를 멀리서도 알아보게 하는 자리다. */
.pm-erd__head {
  padding: 4px 8px;
  background: #eef3f9;
  border-bottom: 1px solid #d9d9d9;
}

.pm-erd__title {
  font-weight: 700;
  color: #1f3a57;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pm-erd__desc {
  color: #6b7f93;
  font-size: 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pm-erd__body {
  padding: 3px 0;
}

/* 칸 한 줄 — 왼쪽에 이름, 오른쪽에 자료형. 자료형이 길어도 이름을 밀지 않는다. */
.pm-erd__row {
  display: flex;
  gap: 4px;
  align-items: baseline;
  padding: 0 8px;
  height: 18px;
}

.pm-erd__key {
  width: 8px;
  color: #c79a1f;
  font-size: 9px;
}

.pm-erd__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pm-erd__type {
  color: #8c8c8c;
  font-size: 10px;
  max-width: 45%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 열쇠 칸은 굵게 — 표를 이어 보는 눈이 제일 먼저 찾는 줄이다. */
.pm-erd__row--pk .pm-erd__name { font-weight: 700; }

/* ── 도구상자 (`.pm-palette`) ───────────────────────────────── */
/* 조회 영역 아래 한 줄. 캔버스에 겹치면 도형을 놓을 수 없고 좁은 화면에서 그림을 덮는다. */

.pm-palette {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  align-items: center;
  margin-bottom: 0.5rem;
}

.pm-palette__label {
  margin-right: 0.25rem;
  color: var(--jsini-text-muted, #6b7280);
  font-size: var(--jsini-fs-sm);
}


/* ── 도구상자 (`.pm-tools`) ───────────────────────────────────── */
/* 핀으로 꽂힘(그림 옆에 자리)과 뺌(그림 위에 뜸) 두 상태. 숨기면 손잡이만 남긴다 — 완전히 없애면 다시 여는 길이 없다. */

.pm-canvas {
  position: relative;
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
}

/* 꽂혀 있을 때만 그림이 자리를 나눈다. 떠 있을 때는 그림이 폭을 다 쓴다. */
.pm-canvas > .pm-diagram-host {
  flex: 1;
  min-width: 0;
}

.pm-tools {
  display: flex;
  flex-direction: column;
  width: 210px;
  max-height: min(70vh, 760px);
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  background: var(--jsini-surface);
  overflow: hidden;
}

/* 핀을 빼면 그림 위에 뜬다. 그림자를 줘야 위에 떠 있는 것으로 읽힌다. */
.pm-tools--float {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 3;
  box-shadow: 0 2px 10px rgb(0 0 0 / 18%);
}

.pm-tools__head {
  display: flex;
  gap: 0.25rem;
  align-items: center;
  padding: 0.25rem 0.5rem;
  border-bottom: 1px solid var(--jsini-border);
}

.pm-tools__title {
  flex: 1;
  font-size: var(--jsini-fs-sm);
  font-weight: 600;
}

.pm-tools__body {
  flex: 1;
  min-height: 0;      /* 안 주면 목록이 길 때 판을 밀고 나간다 */
  overflow-y: auto;
  padding: 0.4rem 0.5rem 0.6rem;
}

.pm-tools__group + .pm-tools__group {
  margin-top: 0.35rem;
}

/* 묶음 머리 — 누르면 접히고 펴진다(`<details>` 라 브라우저가 한다). */
.pm-tools__group-title {
  display: flex;
  gap: 0.3rem;
  align-items: center;
  padding: 0.2rem 0;
  color: var(--jsini-text-muted, #6b7280);
  font-size: var(--jsini-fs-2xs);
  font-weight: 600;
  cursor: pointer;
  user-select: none;
}

.pm-tools__group-title::-webkit-details-marker {
  display: none;      /* 기본 삼각형 대신 아래 것을 쓴다 */
}

.pm-tools__group-title::before {
  content: "▸";
  font-size: 0.7em;
  transition: transform 0.12s ease;
}

.pm-tools__group[open] > .pm-tools__group-title::before {
  transform: rotate(90deg);
}

/* 묶음 안의 도구 수. 접힌 채로도 어디에 몇 개가 있는지 보인다. */
.pm-tools__count {
  margin-left: auto;
  padding: 0 0.25rem;
  border-radius: 0.5rem;
  background: color-mix(in srgb, currentColor 12%, transparent);
  font-size: 0.9em;
  font-weight: 400;
}

.pm-tools__items {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

/* ── 도구 한 칸 ────────────────────────────────────────────── */
/* 모양은 maxgraph 가 그린 그림을 그대로 끼운다(이름만으론 모양을 알 수 없다). 칸은 모두 같은 크기이고 viewBox 가 비율을 지킨다. */

.pm-tool {
  padding: 0.2rem 0.45rem;
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  background: var(--jsini-surface);
  color: inherit;
  font-size: var(--jsini-fs-2xs);
  line-height: 1.5;
  cursor: pointer;
}

.pm-tool:hover {
  background: color-mix(in srgb, currentColor 8%, transparent);
}

/* 머리띠의 아이콘 단추. 글자를 쓰면 제목이 밀린다. */
.pm-tools__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 0.25rem;
  background: none;
  color: var(--jsini-text-muted, #6b7280);
  cursor: pointer;
}

.pm-tools__icon:hover {
  background: color-mix(in srgb, currentColor 10%, transparent);
}

/* 핀이 꽂혀 있는 상태를 색으로 알린다 — 아이콘이 같으므로 이것뿐이다. */
.pm-tools__icon--on {
  border-color: var(--jsini-border);
  color: var(--jsini-accent-text, #0f6cbd);
}

.pm-tools__icon [class^="jsini-icon-"] {
  width: 0.95rem;
  height: 0.95rem;
}

/* 숨겼을 때 남는 손잡이. absolute 라 자리를 차지하지 않는다. 흐름에 두면 숨긴 뒤에도 그림이 그만큼 좁아진다. */
.pm-tools-handle {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  background: var(--jsini-surface);
  color: var(--jsini-text-muted, #6b7280);
  box-shadow: 0 1px 4px rgb(0 0 0 / 15%);
  cursor: pointer;
}

.pm-tools-handle:hover {
  color: var(--jsini-accent-text, #0f6cbd);
}

.pm-tools-handle [class^="jsini-icon-"] {
  width: 1.1rem;
  height: 1.1rem;
}

/* 눈에는 안 보이고 낭독기에만 읽히는 글자. 아이콘만 있는 단추에 붙인다. */
/* ── 저장 안 한 변경 (`.pm-save--dirty`) ───────────────────────── */
/* 테두리 대신 box-shadow 고리를 둔다. 테두리는 단추 크기를 바꿔 옆 단추를 민다. 글자 • 는 색을 못 보는 눈을 위한 것이다. */

.pm-save--dirty {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--jsini-accent) 45%, transparent);
}

/* ── 그림 바탕 (격자·점) ─────────────────────────────────────── */
/* 무늬만 여기서 정하고 칸 크기·시작점은 diagram-viewer.js 의 paintBackground 가 정한다. 점의 안쪽 여백(1.5px)은 JS 의 DOT_INSET 과 같아야 한다. */

.pm-diagram--grid,
.pm-diagram--dots {
  /* 바탕이 진하면 그림이 묻힌다. 테두리 색을 옅게 섞는다. */
  --pm-grid-ink: color-mix(in srgb, var(--jsini-border) 80%, transparent);
}

.pm-diagram--grid {
  background-image:
    linear-gradient(to right, var(--pm-grid-ink) 1px, transparent 1px),
    linear-gradient(to bottom, var(--pm-grid-ink) 1px, transparent 1px);
}

.pm-diagram--dots {
  /* 점은 옅게 섞지 않고 테두리 색을 그대로 쓴다. 100% 를 넘기면 color-mix 가 무효가 되어 점이 안 찍힌다. */
  --pm-grid-ink: var(--jsini-border);

  background-image:
    radial-gradient(circle at 1.5px 1.5px, var(--pm-grid-ink) 1.4px, transparent 1.5px);
}

/* ── 미니맵 (`.pm-minimap`) ───────────────────────────────────── */
/* 그림이 화면보다 클 때 현재 위치를 보여 준다(maxgraph Outline). 자리는 부모 .pm-diagram-host 가 잡고, 층은 1 이라 불러오는 덮개(2)에 함께 덮인다. */

/* 켜기 전에는 자리를 차지하지 않는다. */
.pm-minimap {
  display: none;
}

.pm-minimap--on {
  position: absolute;
  right: 0.5rem;
  bottom: 0.5rem;
  z-index: 1;
  display: block;
  width: 220px;
  height: 160px;
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  background: var(--jsini-surface);
  box-shadow: 0 2px 10px rgb(0 0 0 / 18%);
  overflow: hidden;
}

/* 좁은 화면에서는 그림을 가린다. 그림이 안 보이면 미니맵도 쓸 데가 없다. */
@media (max-width: 767px) {
  .pm-minimap--on {
    width: 150px;
    height: 110px;
  }
}

/* 미니맵 단추 그림. app.css 의 jsini-icon-* 에 없어 여기 둔다. currentColor 로 칠해 테마를 따른다. */
.pm-icon-minimap {
  display: inline-block;
  width: var(--jsini-icon-size);
  height: var(--jsini-icon-size);
  vertical-align: middle;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1 2.5h14v11H1zm1.6 1.6v7.8h10.8V4.1z'/%3E%3Cpath d='M8.2 7.4h4.6v3.4H8.2z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1 2.5h14v11H1zm1.6 1.6v7.8h10.8V4.1z'/%3E%3Cpath d='M8.2 7.4h4.6v3.4H8.2z'/%3E%3C/svg%3E");
}

.pm-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* 도구상자의 찾는 칸. 목록이 많아 없으면 굴리다 지친다. */
/* 바탕 고르개(없음·격자·점). 고른 칸은 면으로 칠한다. */
.pm-tools__seg {
  display: flex;
  gap: 0.2rem;
  align-items: center;
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--jsini-border);
}

.pm-tools__seg-label {
  margin-right: 0.1rem;
  color: var(--jsini-text-muted, #6b7280);
  font-size: var(--jsini-fs-2xs);
}

.pm-tools__seg-btn {
  flex: 1;
  padding: 0.15rem 0.2rem;
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  background: var(--jsini-surface);
  color: inherit;
  font-size: var(--jsini-fs-2xs);
  cursor: pointer;
}

.pm-tools__seg-btn:hover {
  background: color-mix(in srgb, currentColor 8%, var(--jsini-surface));
}

.pm-tools__seg-btn--on {
  border-color: var(--jsini-accent);
  background: color-mix(in srgb, var(--jsini-accent) 14%, var(--jsini-surface));
  font-weight: 600;
}

.pm-tools__filter {
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--jsini-border);
}

.pm-tools__search {
  width: 100%;
  padding: 0.2rem 0.4rem;
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  background: var(--jsini-surface);
  color: inherit;
  font-size: var(--jsini-fs-2xs);
}

.pm-tools__empty {
  margin: 0.4rem 0;
  color: var(--jsini-text-muted, #6b7280);
  font-size: var(--jsini-fs-2xs);
}


/* 모양 칸. 글자 칸과 높이를 맞춘다. 작을수록 한 화면에 많이 든다. 무엇인지는 마우스를 올렸을 때 뜨는 큰 그림이 말해 준다. */
.pm-tool--shape {
  position: relative;   /* 덧붙이는 말의 기준 */
  width: 1.85rem;
  height: 1.85rem;
  padding: 0.1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: grab;         /* 끌어다 놓을 수 있다는 표시 */
}

.pm-tool--shape:active {
  cursor: grabbing;
}

.pm-tool__art {
  width: 100%;
  height: 100%;
  overflow: visible;    /* 테두리가 잘리지 않게 */
  pointer-events: none; /* 그림이 단추의 클릭을 먹지 않게 */
  font-size: 0.55rem;   /* 미리보기가 없을 때의 글자 */
}

/* 덧붙이는 말 — 큰 그림과 이름. title 을 쓰지 않는 까닭은 그림을 담을 수 없어서다. */
.pm-tool__tip {
  position: absolute;
  top: 50%;
  left: calc(100% + 0.4rem);
  z-index: 6;
  display: none;
  flex-direction: column;
  gap: 0.2rem;
  align-items: center;
  width: max-content;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  background: var(--jsini-surface);
  box-shadow: 0 2px 10px rgb(0 0 0 / 18%);
  transform: translateY(-50%);
  pointer-events: none;
}

.pm-tool--shape:hover .pm-tool__tip,
.pm-tool--shape:focus-visible .pm-tool__tip {
  display: flex;
}

/* 큰 그림도 **같은 상자**다 — 비율만 viewBox 가 지킨다. */
.pm-tool__tip-art {
  width: 5.5rem;
  height: 5.5rem;
  overflow: visible;
}

.pm-tool__tip-name {
  max-width: 9rem;
  color: inherit;
  font-size: var(--jsini-fs-2xs);
  text-align: center;
  word-break: break-word;
}


/* ── 마인드맵 (`.pm-mind`) ──────────────────────────────────── */
/* 도구상자가 없어 옆자리를 나누지 않고, 자판 초점이 캔버스에 가므로 그 표시를 보여 준다. */

.pm-mind-host {
  position: relative;   /* 「불러오는 중」 덮개의 기준 */
  width: 100%;
  height: min(70vh, 760px);
  border: 1px solid var(--jsini-border);
  border-radius: 0.25rem;
  overflow: hidden;
}

.pm-mind {
  width: 100%;
  height: 100%;

  /* 빈 자리를 끌면 그림이 움직인다. 커서로 알려 주지 않으면 끌 수 있다는 것을 알 길이 없다. */
  cursor: grab;
}

.pm-mind:active { cursor: grabbing; }

/* 캔버스가 자판을 받는다(Tab·Enter·F2·Delete). :focus 를 쓴다 — :focus-visible 은 마우스로 옮긴 초점에 테를 그리지 않아 단축키가 여기로 온다는 것을 알릴 길이 없다. */
.pm-mind:focus {
  outline: 2px solid var(--jsini-accent);
  outline-offset: -2px;
}

/* ── mermaid 글 칸 ───────────────────────────────────────────── */
/* 접어 둔다. 그림으로 그리는 사람에게는 안 보이는 편이 낫다. */

.pm-mind-text {
  margin-top: 0.6rem;
}

.pm-mind-text__toggle {
  padding: 0.2rem 0;
  border: 0;
  background: none;
  color: var(--jsini-text-muted, #6b7280);
  font-size: var(--jsini-fs-sm);
  cursor: pointer;
}

.pm-mind-text__toggle:hover { color: var(--jsini-text, #262626); }

/* 고정폭이라야 들여쓰기 층이 보인다. mermaid 는 들여쓰기로 층을 정한다. */
.pm-mind-text__area textarea {
  font-family: var(--jsini-font-mono, ui-monospace, "Cascadia Mono", "D2Coding", monospace);
  font-size: var(--jsini-fs-sm);
  white-space: pre;
}

/* ── 일정표의 주·일 보기 (`DxScheduler`) ───────────────────── */
/* 자기 키를 부모에서 받으므로 최소 키를 준다. 없으면 한 주 높이로 납작해진다. 범위 표시를 달 요소가 없어 화면 옆 CSS 로는 안 걸린다. */

.pm-sched {
  min-height: 620px;
}

/* ── 다중선택 고르개(CodeSelect Multiple) ──────────────────── */
/* 자기 너비를 정하지 않아 빈 상태에서 12px 로 쪼그라든다 — 조건줄에서 누를 수 없는 실선이 된다. 단일 고르개(DxComboBox)는 기본 너비가 있다. */

.pm-code-select--multi {
  min-width: 220px;
  max-width: 100%;
}

/* 좁은 화면에서는 최소 너비를 푼다. 안 그러면 조건줄이 화면 밖으로 나간다. */
@media (max-width: 767px) {
  .pm-code-select--multi {
    min-width: 0;
  }
}

/* 펼친 체크 목록. 키를 묶고 안쪽만 구르게 한다. 넘치면 아래 항목을 체크할 수 없다. */
.pm-code-checks {
  max-height: 280px;
  min-width: 200px;
}

/* ── AI 작업 (`pm-ai-*`) ─────────────────────────────────────── */
/* 상태 배지는 공통 jsini-badge 를 쓴다. 이 포털에는 부트스트랩 변수가 없어 --bs-* 로 만든 배지는 어두운 테마에서 흰 칩이 떠 버린다. */

/* 표에서 「없음」을 뜻하는 자리. 배지를 쓰면 없는 것이 있는 것처럼 보인다. */
.pm-ai-dim { color: var(--jsini-text-muted); }

/* ── 지시 탭 · 실행 탭 ─────────────────────────────────────── */
/* 오른쪽 판을 탭 둘로 가른다. 한 칸에 다 쌓으면 도는 것을 보려고 편집기를 지나야 한다. 높이는 픽셀이 아니라 화면을 따라간다. */

.pm-ai-write,
.pm-ai-watch { padding-top: var(--jsini-sp-lg); }

/* ── 설정 줄 (`pm-editform` · `pm-ai-opts`) ───────────────── */
/* 폼은 무엇을 시키나, 옵션 줄은 끝난 뒤에 무엇을 하나를 맡는다. 줄 높이(32px)는 건드리지 않는다 — 지시문이 가운데를 가져야 한다. */

.pm-editform .dxbl-fl-item {
  margin-bottom: var(--jsini-sp-md);
}

/* 마지막 줄 밑은 아래 옵션 줄의 여백이 맡는다. 겹치면 그 사이만 휑하다. */
.pm-editform .dxbl-fl-item:nth-last-child(-n + 4) {
  margin-bottom: 0;
}

/* 프로젝트 목록의 RAG 카테고리 칸이 잠겼을 때의 까닭. 고르개가 빈 것과 AI 서버를 못 읽은 것이 화면으로는 같아서 적어 준다. */
.pm-rag-warn {
  margin-top: var(--jsini-sp-xs);
  font-size: var(--jsini-fs-sm);
  color: var(--jsini-text-muted);
}

/* 끝난 뒤의 일. 체크 셋과 알림 칸은 한 줄이고, 좁아지면 접히되 순서(켠다 → 누구에게 → 언제)는 지킨다. */
.pm-ai-opts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--jsini-sp-sm) var(--jsini-sp-lg);
  align-items: center;
  margin-top: var(--jsini-sp-md);
}

/* 성격이 다른 두 묶음 사이의 선. 간격이 같으면 다섯 칸이 한 줄로 읽힌다. */
.pm-ai-opts__sep {
  width: 1px;
  align-self: stretch;
  min-height: 1.4rem;
  background: var(--jsini-border);
}

/* 칸에 붙는 이름. 폼 라벨과 달리 칸 왼쪽에 나란히 선다 — 한 줄에 칸 둘이 들어가 위에 얹을 자리가 없다. */
.pm-ai-opts__field {
  display: inline-flex;
  min-width: 0;
  align-items: center;
  gap: var(--jsini-sp-sm);
}

.pm-ai-opts__label {
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-sm);
  white-space: nowrap;
}

/* 칸 높이를 위 폼과 맞춘다. 폼 안 칸은 --jsini-field-h 를 받는데 이 줄은 폼 밖이라 그 규칙이 안 걸린다. */
.pm-ai-opts__field .dxbl-text-edit {
  width: 100%;
  min-height: var(--jsini-field-h);
}

/* 받는 사람은 주소, 보낼 때는 고르는 칸이라 폭을 각자 준다. 차례(nth-of-type)로 가르지 않는다 — 형제 DxCheckBox 의 뿌리 태그를 DevExpress 가 정해 번호가 밀린다. */
.pm-ai-opts__field--to { flex: 1 1 16rem; }
.pm-ai-opts__field--when { flex: 0 1 12rem; }

/* 편집기 자리. CodeEditor 의 Height 는 제 상자 style 에 들어가므로 이 판에 실제 높이가 있어야 100% 가 뜻을 갖는다(못 받으면 Monaco 가 5px 로 접힌다). */
/* 높이는 재지 않고 남은 자리를 받는다. 24rem 은 휴대폰·좁은 창의 값이고, 데스크탑 값은 pm-ai-page 절이 덮는다. 위에 선을 긋는다 — 설정과 지시문은 성격이 다르다. */
.pm-ai-editor {
  height: 24rem;
  margin: var(--jsini-sp-lg) 0;
  padding-top: var(--jsini-sp-lg);
  border-top: 1px solid var(--jsini-border);
}

.pm-ai-actions {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  gap: var(--jsini-sp-sm);
  padding-bottom: var(--jsini-sp-sm);
}

/* ── 편집기 머리줄 ───────────────────────────────────────────── */
/* 설정과 지시문을 가르는 선은 이 줄 위에 그어야 한다. 아래에 그으면 이름이 설정 묶음에 붙어 보인다. */
.pm-ai-editor__bar {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: var(--jsini-sp-sm);
  margin-top: var(--jsini-sp-lg);
  padding-top: var(--jsini-sp-lg);
  border-top: 1px solid var(--jsini-border);
}

.pm-ai-editor__label {
  font-weight: 600;
  font-size: var(--jsini-fs-sm);
  color: var(--jsini-text-muted);
}

/* 선을 머리줄에 넘겨준 편집기. 머리줄이 없는 쓰임을 위해 기본 규칙은 그대로 둔다. */
.pm-ai-editor__bar + .pm-ai-editor {
  margin-top: var(--jsini-sp-sm);
  padding-top: 0;
  border-top: 0;
}

/* ── AI 도우미 (`AiTaskWriteAssist`) ───────────────────────── */
/* 흘러내리던 판이 여기서는 창이다. 단추가 선 자리가 창 바닥 가까이라 위로 펼쳐도 탭 틀에 잘린다. 업무 모듈끼리 참조할 수 없어 헬프데스크 hd-ai 스타일을 복제했다. */
.pm-aiassist__btn {
  flex: 0 0 auto;
}

/* 무엇을 기다리는지 적는다. 로컬 LLM 은 십 초를 넘기므로 도는 표시만 있으면 멈춘 줄 알고 다시 누른다. */
.pm-aiassist__wait,
.pm-aiassist__hint {
  margin: 0;
  color: var(--jsini-text-muted);
}

.pm-aiassist__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 후보 사이의 가는 선이 「하나씩 고르는 것」을 말해 준다. 설명 줄을 따로 두지 않는다. */
.pm-aiassist__list > li + li {
  border-top: 1px solid var(--jsini-border);
}

.pm-aiassist__pick {
  display: block;
  width: 100%;
  padding: var(--jsini-sp-sm);
  background: none;
  border: 0;
  border-radius: var(--jsini-radius-md);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.pm-aiassist__pick:hover {
  background: var(--jsini-surface-hover, rgba(127, 127, 127, 0.12));
}

/* 이번 답을 만든 AI. **고르는 칸이 아니라 알려 주는 줄**이라 작고 흐리다. */
.pm-aiassist__model {
  margin: var(--jsini-sp-md) 0 0;
  font-size: var(--jsini-fs-sm);
  color: var(--jsini-text-muted);
}

/* ── 임시저장 목록 창 ──────────────────────────────────────── */
/* CommGrd 를 쓰지 않는다 — 조회·정렬이 아니라 고르기와 버리기 두 가지만 한다. */
.pm-ai-drafts {
  margin: var(--jsini-sp-md) 0 0;
  padding: 0;
  list-style: none;
}

.pm-ai-drafts__empty {
  margin: var(--jsini-sp-md) 0 0;
  color: var(--jsini-text-muted);
}

.pm-ai-drafts__row {
  display: flex;
  align-items: stretch;
  gap: var(--jsini-sp-xs, 0.25rem);
}

.pm-ai-drafts__row + .pm-ai-drafts__row {
  border-top: 1px solid var(--jsini-border);
}

/* 줄 전체가 「불러오기」다. 고르는 일이 버리는 일보다 훨씬 잦다. */
.pm-ai-drafts__pick {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  flex-direction: column;
  gap: 0.15rem;
  padding: var(--jsini-sp-sm);
  background: none;
  border: 0;
  border-radius: var(--jsini-radius-md);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.pm-ai-drafts__pick:hover {
  background: var(--jsini-surface-hover, rgba(127, 127, 127, 0.12));
}

/* 제목은 한 줄로 자른다. 임시본 제목은 본문 첫 줄일 수 있어 그대로 두면 창을 넘는다. */
.pm-ai-drafts__title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: 600;
}

.pm-ai-drafts__meta {
  font-size: var(--jsini-fs-sm);
  color: var(--jsini-text-muted);
}

.pm-ai-drafts__drop {
  flex: 0 0 auto;
  padding: 0 var(--jsini-sp-sm);
  background: none;
  border: 0;
  border-radius: var(--jsini-radius-md);
  color: var(--jsini-text-muted);
  cursor: pointer;
}

.pm-ai-drafts__drop:hover {
  color: var(--jsini-danger, #dc2626);
  background: var(--jsini-surface-hover, rgba(127, 127, 127, 0.12));
}

/* ── 편집기 높이 (`pm-editor__inner`) ────────────────────────── */
/* 여기 있으면 안 되는 규칙이다. 정본은 CodeEditor.razor.css 인데 셸이 범위 CSS 묶음을 안 실어 Monaco 가 5px 로 접힌다. 고치면 부품 여섯의 모양이 같이 바뀌어 따로 확인한다. */

.pm-editor {
  position: relative;
}

.pm-editor__inner,
.monaco-editor-container {
  height: 100%;
}

/* ── 편집기 「…」 메뉴 (`EditorActions`) ─────────────────────── */
/* 글자를 붙이지 않는다 — 편집기 위에 얹혀 코드를 가린다. --float 는 안 오른쪽 위에 뜨고 부모에 position: relative 가 필요하다. */
.pm-edact {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  user-select: none;
}

.pm-edact--float {
  position: absolute;
  top: 0.35rem;
  right: 0.5rem;
  z-index: 10;
  padding: 0.15rem 0.25rem;
  border-radius: 6px;
  background: var(--jsini-surface);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid var(--jsini-border);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
  opacity: 0.85;
  transition: opacity 0.15s ease, box-shadow 0.15s ease;
}

/* 떠 있는 줄은 가만히 있을 때 옅다. 늘 진하면 오른쪽 위 글자를 가리는 것으로 읽힌다. */
.pm-editor:hover .pm-edact--float,
.pm-edact--float:hover,
.pm-edact--float:focus-within {
  opacity: 1;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

/* 아이콘 단추 (줄바꿈 · 복사 공통) */
.pm-edact__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.55rem;
  height: 1.55rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  cursor: pointer;
  color: var(--jsini-text-muted);
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}

.pm-edact__btn:hover {
  color: var(--jsini-text);
  background: var(--jsini-surface-hover);
}

/* 줄바꿈 켜짐. 켜고 끈 것이 아이콘 색으로 바로 읽혀야 한다. */
.pm-edact__btn.is-active {
  color: var(--jsini-accent);
  background: rgba(0, 112, 204, 0.12);
  border-color: rgba(0, 112, 204, 0.28);
}

.pm-edact__btn.is-active:hover {
  background: rgba(0, 112, 204, 0.18);
}

/* 판이 펴진 동안에는 옅게 두지 않는다. backdrop-filter 가 걸리면 fixed 자식인 막이 이 작은 줄 안에 갇히므로 흐림을 걷는다. */
.pm-edact--float.is-open {
  opacity: 1;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* 바깥을 누르면 닫는 투명한 막. 판 바로 아래 층이다. */
.pm-edact__veil {
  position: fixed;
  inset: 0;
  z-index: 1000;
}

/* 「…」 아래로 펴지는 판. 단추의 오른쪽 끝에 맞춘다. */
.pm-edact__menu {
  position: absolute;
  top: calc(100% + 0.25rem);
  right: 0;
  z-index: 1001;
  display: flex;
  flex-direction: column;
  min-width: 11rem;
  padding: 0.25rem;
  border: 1px solid var(--jsini-border);
  border-radius: 6px;
  background: var(--jsini-surface);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
  font-size: var(--jsini-fs-sm);
  font-weight: 400;
}

.pm-edact__item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.4rem 0.5rem;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--jsini-text);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.pm-edact__item:hover,
.pm-edact__item:focus-visible {
  background: var(--jsini-surface-hover);
}

.pm-edact__item.is-copied {
  color: #10b981;
}

.pm-edact__icon {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  opacity: 0.8;
}

/* 줄 번호에는 마땅한 그림이 없어 글자 「1」을 그림 자리에 세운다. */
.pm-edact__icon--num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid currentColor;
  border-radius: 3px;
  font-size: 0.625rem;
  font-weight: 600;
  line-height: 1;
}

.pm-edact__label {
  flex: 1 1 auto;
}

/* 스위치 — 켜짐은 강조색 바탕에 동그라미가 오른쪽으로 간다. */
.pm-edact__switch {
  position: relative;
  flex: 0 0 auto;
  width: 1.9rem;
  height: 1.05rem;
  margin-left: 0.75rem;
  border-radius: 999px;
  background: rgba(107, 114, 128, 0.35);
  transition: background 0.15s ease;
}

.pm-edact__switch::after {
  content: "";
  position: absolute;
  top: 0.125rem;
  left: 0.125rem;
  width: 0.8rem;
  height: 0.8rem;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s ease;
}

.pm-edact__switch.is-on {
  background: var(--jsini-accent);
}

.pm-edact__switch.is-on::after {
  transform: translateX(0.85rem);
}

/* 자동 줄바꿈 아이콘 (text-wrap) */
.jsini-icon-wrap {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M2 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0 4a.5.5 0 0 1 .5-.5h7a2.5 2.5 0 0 1 0 5H6.707l1.147-1.146a.5.5 0 1 0-.708-.708l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L6.707 13H9.5a3.5 3.5 0 1 0 0-7H2.5a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M2 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0 4a.5.5 0 0 1 .5-.5h7a2.5 2.5 0 0 1 0 5H6.707l1.147-1.146a.5.5 0 1 0-.708-.708l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L6.707 13H9.5a3.5 3.5 0 1 0 0-7H2.5a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}


/* 「쓸 수 있는 AI」 체크칸. 값이 둘뿐이라 가로로 세운다 — 세로면 편집 창이 두 줄 더 길어진다. */
.pm-ai-kinds {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  align-items: center;
  min-height: 2rem;
}

/* ── 실행 이력 바 (탭 밖 상단) ──────────────────────────── */
/* 차수 선택을 따르는 것은 「처리 파일」과 「로그」뿐이다. 「지시와 결과」는 차수를 통째로 쌓아 보여 줘 이 띠를 안 본다. */
.pm-ai-runs-bar {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--jsini-border, #e3e5e8);
  border-radius: var(--jsini-radius-md, 6px);
  background: var(--jsini-surface, #f7f8fa);
}

.pm-ai-runs-bar__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.pm-ai-runs-bar__title {
  font-size: var(--jsini-fs-xs, 0.75rem);
  font-weight: 600;
  color: var(--jsini-text-muted, #6b7280);
}

.pm-ai-runs-bar__cur {
  font-size: var(--jsini-fs-xs, 0.75rem);
  color: var(--jsini-accent-text, #0070cc);
  font-weight: 500;
}

.pm-ai-run__seq {
  font-weight: 600;
}

.pm-ai-runs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.pm-ai-run {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--jsini-border, #e3e5e8);
  border-radius: 999px;
  background: transparent;
  font-size: var(--jsini-fs-xs);
  cursor: pointer;
}

/* 가동 시간. 초마다 바뀌어 옆 단추가 흔들리지 않게 고정폭 숫자를 쓴다. */
.pm-ai-elapsed {
  font-variant-numeric: tabular-nums;
  color: var(--jsini-text-muted);
}

/* 도는 중인 것만 진하게 — 끝난 것과 섞여도 지금 도는 것을 먼저 찾게 한다. */
.pm-ai-elapsed--on {
  color: var(--jsini-accent-text);
  font-weight: 600;
}

/* 고른 실행. 테마의 강조색을 쓴다 — 여기도 부트스트랩 변수는 없다. */
.pm-ai-run--on {
  border-color: var(--jsini-accent);
  box-shadow: inset 0 0 0 1px var(--jsini-accent);
}


/* 이어서 시킬 내용을 받는 칸. 한 줄짜리가 아니라 문단을 쓰는 자리다. */
.pm-ai-addition { width: 100%; }

/* 목록의 제목 칸. 「임시」 표가 붙을 수 있어 한 줄로 세우고, 줄이면 제목 쪽만 줄인다. */
.pm-ai-title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.pm-ai-title__text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── 작업 목록 한 줄 (`pm-ai-row`) ─────────────────────────── */
/* 판이 34% 라 칸을 다섯으로 늘어놓으면 제목이 서너 글자만 보인다. 제목이 한 줄을 차지하고 잔글씨는 아래 붙인다. */

.pm-ai-row {
  display: flex;
  flex-direction: column;

  /* 제목과 잔글씨 사이를 띄운다. 0.1rem 은 붙은 것과 다름없었다. */
  gap: var(--jsini-sp-2xs);
  padding: var(--jsini-sp-2xs) 0;
  min-width: 0;
}

.pm-ai-row__title {
  display: flex;
  gap: 0.35rem;
  align-items: center;
  min-width: 0;
  font-weight: 600;
}

.pm-ai-row__sub {
  display: flex;
  gap: 0.35rem;
  align-items: baseline;
  font-size: 0.85em;
  opacity: 0.75;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 상태와 요청여부를 한 칸에 나란히. 좁아져도 둘 다 보여야 한다(「취소를 눌렀는데 아직 돌고 있다」). */
.pm-ai-row__state {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
}

/* ── 상태 칸 다중 선택 필터 (`pm-ai-status-filter`) ─────────── */
/* 필터 행 셀 안의 TagBox. 팝업이 위로 열리므로 min-height 를 두지 않는다. */
.pm-ai-status-filter {
  width: 100%;
}

/* ── AI 작업 화면 머리·반응형 ─────────────────────────────── */
/* 첫 화면에서 「할 수 있는 것」과 「지금 상태」가 먼저 읽히게 정보 순서를 정리한다. 통계는 현재 조회 결과 기준이다. */

/* 머리줄 여백을 줄여 아낀 높이를 편집기와 로그에 준다. */
.pm-ai-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--jsini-sp-lg);
  align-items: center;
  margin-bottom: var(--jsini-sp-md);
  padding: var(--jsini-sp-lg) var(--jsini-sp-xl);
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-lg, 0.75rem);
  background:
    radial-gradient(circle at 100% 0, color-mix(in srgb, var(--jsini-accent) 12%, transparent), transparent 38%),
    var(--jsini-surface);
}

.pm-ai-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--jsini-accent-text);
  font-size: var(--jsini-fs-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
}

.pm-ai-eyebrow__dot,
.pm-ai-live__indicator {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--jsini-success, #1f9d65);
}

.pm-ai-hero__heading {
  display: flex;
  gap: var(--jsini-sp-lg);
  align-items: end;
  justify-content: space-between;
  margin-top: var(--jsini-sp-2xs);
}

.pm-ai-hero h1 {
  margin: 0;
  color: var(--jsini-text);
  font-size: var(--jsini-fs-2xl);
  line-height: 1.2;
}

.pm-ai-hero p {
  margin: 0.2rem 0 0;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-sm);
}

.pm-ai-live {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.4rem;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-xs);
  white-space: nowrap;
}

.pm-ai-live__indicator--busy {
  background: var(--jsini-accent);
  animation: pm-ai-pulse 1.2s ease-in-out infinite;
}

.pm-ai-list-stats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--jsini-sp-md);
  padding: 0.5rem var(--jsini-sp-md);
  background: var(--jsini-surface);
  border-bottom: 1px solid var(--jsini-border);
}

.pm-ai-list-stat {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  font-size: var(--jsini-fs-sm);
}

.pm-ai-list-stat__label {
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-muted);
}

.pm-ai-list-stat__value {
  font-weight: 700;
  color: var(--jsini-text);
}

.pm-ai-list-stat--accent .pm-ai-list-stat__value { color: var(--jsini-accent); }
.pm-ai-list-stat--success .pm-ai-list-stat__value { color: var(--jsini-success, #1f9d65); }
.pm-ai-list-stat--danger .pm-ai-list-stat__value { color: var(--jsini-danger, #d94b55); }

.pm-ai-list-stats .pm-ai-live {
  margin-left: auto;
}

.pm-ai-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(5.5rem, 1fr));
  gap: var(--jsini-sp-sm);
}

.pm-ai-stat {
  min-width: 0;
  padding: 0.45rem 0.7rem;
  border-left: 3px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md, 0.4rem);
  background: color-mix(in srgb, var(--jsini-bg) 72%, transparent);
}

.pm-ai-stat--accent { border-left-color: var(--jsini-accent); }
.pm-ai-stat--success { border-left-color: var(--jsini-success, #1f9d65); }
.pm-ai-stat--danger { border-left-color: var(--jsini-danger, #d94b55); }

.pm-ai-stat__label {
  display: block;
  overflow: hidden;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-xs);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pm-ai-stat__value {
  display: block;
  margin-top: 0.1rem;
  color: var(--jsini-text);
  font-size: var(--jsini-fs-xl);
  font-variant-numeric: tabular-nums;
}

.pm-ai-loading {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0 0 var(--jsini-sp-md);
  padding: 0.6rem 0.8rem;
  border: 1px solid color-mix(in srgb, var(--jsini-accent) 28%, var(--jsini-border));
  border-radius: var(--jsini-radius-md, 0.4rem);
  background: color-mix(in srgb, var(--jsini-accent) 7%, var(--jsini-surface));
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-sm);
}

.pm-ai-loading__spinner {
  width: 0.9rem;
  height: 0.9rem;
  border: 2px solid color-mix(in srgb, var(--jsini-accent) 25%, transparent);
  border-top-color: var(--jsini-accent);
  border-radius: 50%;
  animation: pm-spin 0.8s linear infinite;
}

.pm-ai-context {
  display: flex;
  gap: var(--jsini-sp-md);
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--jsini-sp-md);
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md, 0.4rem);
  background: color-mix(in srgb, var(--jsini-accent) 5%, var(--jsini-surface));
}

.pm-ai-context__main {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 0.15rem;
}

.pm-ai-context__main strong {
  word-break: keep-all;
  overflow-wrap: break-word;
}

.pm-ai-context__kicker {
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-xs);
}

.pm-ai-context__meta {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  gap: 0.25rem;
  justify-content: end;
}

.pm-ai-empty {
  display: grid;
  min-height: 22rem;
  place-content: center;
  justify-items: center;
  gap: 0.45rem;
  padding: var(--jsini-sp-xl);
  border: 1px dashed var(--jsini-border);
  border-radius: var(--jsini-radius-md, 0.4rem);
  text-align: center;
}

.pm-ai-empty__icon {
  display: grid;
  width: 2.5rem;
  height: 2.5rem;
  place-items: center;
  margin-bottom: 0.35rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--jsini-accent) 12%, transparent);
  color: var(--jsini-accent-text);
  font-size: 1.35rem;
}

.pm-ai-empty p {
  max-width: 28rem;
  margin: 0;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-sm);
}

.pm-ai-empty__hint {
  margin-top: 0.4rem;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-xs);
}

@keyframes pm-ai-pulse {
  50% { opacity: 0.35; transform: scale(0.75); }
}

@media (max-width: 74rem) {
  .pm-ai-hero {
    grid-template-columns: 1fr;
    align-items: stretch;
  }

  .pm-ai-stats { grid-template-columns: repeat(4, 1fr); }
}

@media (max-width: 62rem) {
  .pm-split { gap: var(--jsini-sp-lg); }
  .pm-ai-detail-panel { order: -1; }
  .pm-ai-list-panel { order: 1; }
}

@media (max-width: 42rem) {
  .pm-ai-hero {
    padding: var(--jsini-sp-lg);
  }

  .pm-ai-hero__heading {
    align-items: start;
    flex-direction: column;
    gap: var(--jsini-sp-md);
  }

  .pm-ai-stats {
    grid-template-columns: repeat(2, 1fr);
  }

  .pm-ai-context {
    align-items: start;
    flex-direction: column;
  }

  .pm-ai-context__meta { justify-content: start; }
  .pm-ai-empty { min-height: 16rem; }
}

@media (prefers-reduced-motion: reduce) {
  .pm-ai-live__indicator--busy,
  .pm-ai-loading__spinner { animation: none; }
}

/* ── 빠른 지시 (`pm-ask`) ───────────────────────────────────── */
/* 모바일이 주 화면이라 「AI 작업」과 반대로 한 줄로 세운다. 고정 폭은 두지 않는다 — 넓은 화면에서는 읽기 좋은 폭에서 멈춘다. */

/* 판 사이를 벌리지 않는다(gap: 0). 적는 자리와 목록은 한 장이라 맞붙는 테두리를 걷어 이음매를 지운다. */
.pm-ask {
  display: flex;
  flex-direction: column;
  gap: 0;
  max-width: 52rem;
  margin: 0 auto;
  width: 100%;
}

/* 대상과 AI 를 한 줄에. 좁아지면 각자 한 줄을 갖고, 가로로 구겨 넣지 않는다 — 손가락으로 누르는 칸이다. */
.pm-ask__where {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  margin-bottom: 0.75rem;
}

/* 바탕 너비를 좁게 잡아 휴대폰에서도 한 줄에 선다. 넓어지면 flex-grow 비율로 벌어져 대상 쪽이 넓어진다. */
.pm-ask__target { flex: 3 1 9rem; }
.pm-ask__kind { flex: 2 1 10rem; }

/* ── AI 고르개(`AiRunnerPick`) ─────────────────────────────── */
/* 네 화면이 같은 부품을 쓴다. 목록 칸 높이는 고정하지 않는다 — CLI 마다 한도 줄 수가 달라 못 박으면 긴 쪽이 잘린다. */
.pm-aipick__item {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.pm-aipick__head,
.pm-aipick__sel {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

/* 닫힌 칸 한 줄 — 칸을 꽉 채워야 배지가 오른쪽 끝에 붙는다. DevExpress 의 기본 min-width 를 풀어야 말줄임이 걸린다. */
.pm-aipick__sel {
  width: 100%;
}

.pm-aipick .dxbl-edit-cnt,
.pm-aipick .dxbl-edit-cnt > * {
  min-width: 0;
}

/* 이름이 길어도 배지를 밀어내지 않는다(배지가 밀리면 가장 볼 값이 목록 밖으로 나간다). min-width: 0 은 쓰지 않는다 — 좁은 칸에서 이름이 0 까지 줄어 AI 가 통째로 사라진다. */
.pm-aipick__name {
  flex: 1 1 auto;
  min-width: 3.25rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 펼친 목록은 넓어서 바닥이 필요 없다. 두면 짧은 이름 뒤에 빈 자리가 생겨 배지가 가운데로 뜬다. */
.pm-aipick__item .pm-aipick__name {
  min-width: 0;
}

.pm-aipick__head .jsini-badge,
.pm-aipick__sel .jsini-badge {
  flex: 0 0 auto;
  font-size: 0.75em;
  padding: 0.15em 0.4em;
}

/* 고른 줄은 강조색 바탕이라 흐린 글자가 안 읽힌다. 글자색은 DevExpress 것을 물려받고, 사용량 배지는 제 바탕이 있어 뺀다 — inherit 로 덮으면 고른 줄에서 한도가 안 보인다. */
.dxbl-list-box-item-selected .pm-aipick__head .jsini-badge:not([class*='jsini-badge--usage-']),
.dxbl-list-box-item-focused .pm-aipick__head .jsini-badge:not([class*='jsini-badge--usage-']),
li:hover > * > .pm-aipick__item .pm-aipick__head .jsini-badge:not([class*='jsini-badge--usage-']) {
  color: inherit;
  border-color: currentColor;
}


/* 글상자. 화면 세로의 30% 를 넘지 않게 해 모바일 자판이 올라와도 화면을 가리지 않게 한다. */
.pm-ask__text,
.pm-ask__text .dxbl-memo-scroll-container,
.pm-ask__text textarea {
  max-height: 30vh;
  max-height: 30dvh;
}

.pm-ask__text {
  width: 100%;
  border-radius: 0.75rem;
  border: 1px solid var(--jsini-border);
  background: var(--jsini-bg);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.pm-ask__text:focus-within {
  border-color: var(--jsini-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--jsini-accent) 22%, transparent);
}

/* 글자 크기는 서랍에서 고른 단계를 따른다(--jsini-fs-md). rem 으로 박지 않는다(web/CLAUDE.md). */
.pm-ask__text textarea {
  min-height: min(6.5rem, 30vh);
  font-size: var(--jsini-fs-md);
  line-height: 1.6;
  overflow-y: auto;
  border: none;
  background: transparent;
  padding: 0.75rem 0.9rem;
}

/* **손가락으로 쓰는 기기에서만 16px 바닥을 둔다.** */
@media (pointer: coarse) {
  .pm-ask__text textarea {
    font-size: max(var(--jsini-fs-md), 1rem);
  }
}

/* 임시저장 복원 안내 한 줄 */
.pm-ask__draft {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.5rem 0 0;
  padding: 0.4rem 0.85rem;
  font-size: 0.82rem;
  background: color-mix(in srgb, var(--jsini-accent) 8%, var(--jsini-surface));
  border: 1px solid color-mix(in srgb, var(--jsini-accent) 20%, transparent);
  border-radius: 999px;
}

.pm-ask__draft-text {
  color: var(--jsini-text-muted);
}

.pm-ask__draft-clear {
  padding: 0;
  background: none;
  border: none;
  color: var(--jsini-accent);
  cursor: pointer;
  text-decoration: underline;
  font-size: 0.9em;
  font-weight: 600;
}

.pm-ask__draft-clear:hover {
  opacity: 0.8;
}


/* ── 함께 보내는 파일 (`pm-ask__files`) ────────────────────── */
/* 고른 것이 없으면 이 판은 안 그려진다 — 상자만 두면 위 여백이 늘 서 있다. 자판이 올라온 화면에서 단추를 밀어내므로 높이는 인색하게 쓴다. */

.pm-ask__files {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0.6rem 0 0;
}

/* 임시 첨부가 만들어지기 전에도 파일을 골랐다는 사실과 이름을 보여 준다. */
.pm-ask__selected {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.5rem;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-sm);
  overflow-wrap: anywhere;
}

/* 붙인 것. 격자가 아니라 흐름이다 — 이름 길이가 제각각이라 칸을 맞추면 짧은 이름 옆이 빈다. */
.pm-ask__clips {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
}

/* 칩 한 개. 그림 · 이름 · 크기 · 떼기 넷이 한 줄이다. 폭을 묶지 않으면 긴 파일 이름 하나가 줄을 먹는다. */
.pm-ask__clip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  max-width: 16rem;
  padding: 0.25rem 0.3rem 0.25rem 0.25rem;
  border: 1px solid var(--jsini-border, rgba(0, 0, 0, 0.14));
  border-radius: 999px;
  font-size: 0.85em;
  line-height: 1.4;
}

/* 미리보기. 네모로 잘라 채운다(cover) — 비율대로 두면 세로·가로 사진이 섞일 때 칩 높이가 들쭉날쭉하다. */
.pm-ask__clipimg {
  width: 1.6rem;
  height: 1.6rem;
  flex: 0 0 auto;
  object-fit: cover;
  border-radius: 50%;
  background: var(--jsini-bg-subtle, rgba(0, 0, 0, 0.04));
}

/* 그림이 아닌 것. 글자 대신 클립 모양을 세운다 — 확장자를 적으면 같은 폭을 먹어 이름이 그만큼 잘린다. */
.pm-ask__clipicon,
.pm-peek__fileicon {
  width: 1.6rem;
  height: 1.6rem;
  flex: 0 0 auto;

  /* 바탕을 깔지 않는다. 마스크가 그림 밖을 잘라 내므로 둥근 바탕은 함께 잘린다. 색은 글자색을 받는다. */
  background: var(--jsini-text-muted, currentColor);
  mask: var(--jsini-clip-svg) center / 0.9rem 0.9rem no-repeat;
  -webkit-mask: var(--jsini-clip-svg) center / 0.9rem 0.9rem no-repeat;
}

/* 클립 그림 한 장. 파일로 두지 않는다 — 세 자리에만 쓴다. 조상이 아니라 쓰는 요소 자신에 두어야 탭으로 열었을 때도 그림이 남는다. */
.pm-ask__clipicon,
.pm-peek__fileicon,
.pm-ask__clipmark::before {
  --jsini-clip-svg: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48'/%3E%3C/svg%3E");
}

/* 이름. **꼬리를 자른다** — 앞이 잘리면 무슨 파일인지 알 수 없다. */
.pm-ask__clipname {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pm-ask__clipsize {
  flex: 0 0 auto;
  color: var(--jsini-text-muted);
  font-size: 0.9em;
}

/* 떼기. 칩이 촘촘히 붙어 있어 손가락이 겨누는 폭을 글자보다 크게 둔다. */
.pm-ask__clipx {
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  background: none;
  border: none;
  border-radius: 50%;
  color: var(--jsini-text-muted);
  font-size: 1.1em;
  line-height: 1;
  cursor: pointer;
}

.pm-ask__clipx:hover:not(:disabled) {
  background: var(--jsini-bg-subtle, rgba(0, 0, 0, 0.08));
  color: var(--jsini-danger, #c62828);
}

.pm-ask__clipx:disabled {
  opacity: 0.4;
  cursor: default;
}

/* ── 고르개는 아이콘 하나다 ───────────────────────────── */
/* 공용 FilePicker 의 끌어놓기 칸은 줄 폭을 다 쓰고 안내를 더해, 줄이 풀리고 보내기 단추가 자판 밑으로 내려간다. 그림은 DevExpress 의 올리기 그림을 쓰고 글자만 뗀다. */

.pm-ask__pick {
  flex: 0 0 auto;
  display: inline-flex;
}

/* 안내 줄을 껐으니(`ShowHint="false"`) 세로로 쌓을 것이 없다. */
.pm-ask__pick .jsini-picker {
  display: block;
  gap: 0;
}

/* 부품이 얹는 위 여백을 걷는다. 남기면 아이콘이 줄 위로 떠서 체크칸과 밑줄이 어긋난다. */
.pm-ask__pick .dxbl-upload {
  padding-top: 0;
}

/* 끌어놓기 칸의 줄 간격을 걷는다. 자릿수는 테마와 맞춘다 — 짧게 적으면 테마 규칙(0,3,0)에 져서 안 먹는다. */
.pm-ask__pick .dxbl-upload .dxbl-upload-container .dxbl-upload-panel {
  gap: 0;
}

/* 네모 단추 하나. 고르개가 제 아이콘 단추를 세우므로 이 줄에서만 치수가 다르다. 한 줄에 파란 덩이가 둘이면 보내는 단추가 안 갈리므로 눈이 맨 끝으로 가야 한다. */
.pm-ask__pick .jsini-picker__pick {
  min-width: 2.5rem;
  min-height: 2.25rem;
  padding-inline: 0.6rem;
}

/* DevExpress 파일 목록은 비었을 때만 감춘다 — 비어도 위 여백을 들고 있어 평소 단추 줄이 높아진다. 통째로 감추지는 않는다: 거절된 파일(100MB 초과)의 이유를 말하는 자리다. */
.pm-ask__pick .dxbl-upload .dxbl-upload-container .dxbl-upload-file-list-view:empty {
  display: none;
}

.pm-ask__pick:has(.dxbl-upload-file-list-view:not(:empty)) {
  flex: 1 1 100%;
}

/* 카드의 클립 표시. 개수만 적는다. */
.pm-ask__clipmark {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  color: var(--jsini-text-muted);
  font-size: 0.9em;
}

.pm-ask__clipmark::before {
  content: "";
  width: 0.75rem;
  height: 0.75rem;
  background: currentColor;
  mask: var(--jsini-clip-svg) center / contain no-repeat;
  -webkit-mask: var(--jsini-clip-svg) center / contain no-repeat;
}

/* 글상자 아래 한 줄. 첨부 아이콘은 왼쪽, 보내기 단추는 오른쪽 끝에 같은 라인으로 선다. */
.pm-ask__bar {
  display: flex;
  align-items: center;
  gap: 0.5rem 1rem;
  margin: 0.85rem 0 0;
}

/* 체크박스는 더 이상 쓰이지 않는다(호환용으로 남김). */
.pm-ask__opt {
  font-size: 0.9em;
  line-height: 1.5;
}

/* 보내기(올리기) 단추. 첨부 아이콘과 같은 라인 우측 끝에 배치 */
.pm-ask__go {
  min-height: 2.75rem;
  padding-inline: 1.5rem;
  margin-left: auto;
  font-weight: 600;
  font-size: 0.92rem;
  white-space: nowrap;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--jsini-accent);
  border: 1px solid var(--jsini-accent);
  color: #fff;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--jsini-accent) 28%, transparent);
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.pm-ask__go:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--jsini-accent) 38%, transparent);
}

.pm-ask__disclaimer {
  font-size: 0.75rem;
  color: var(--jsini-text-muted);
  text-align: center;
  margin-top: 0.75rem;
  line-height: 1.45;
  opacity: 0.85;
}


/* ── 판 안의 탭 줄 (`pm-ask__tabs`) ──────────────────────── */
/* 휴대폰에서는 포털 탭 줄이 감춰져 있어 이 판이 제 탭 줄을 갖는다. 붙박이(sticky)로 세워 긴 결과문에서도 갈아탈 수 있게 하고, 넘치면 옆으로 민다. */
.pm-ask__tabs {
  position: sticky;
  top: 0;
  z-index: 3;

  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem;
  background: var(--jsini-bg);
  border: 1px solid var(--jsini-border);
  border-radius: 999px;
  margin-bottom: 0.75rem;

  overflow-x: auto;
  scrollbar-width: none;
}

.pm-ask__tabs::-webkit-scrollbar { display: none; }

/* 칸 하나. 맨 앞 칸은 단추 하나뿐이고 나머지는 이름 단추와 닫기 단추를 안는다. flex: 0 0 auto 가 있어야 탭이 늘어도 이름이 한 글자씩 남지 않는다. */
.pm-ask__tab {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;

  max-width: 11rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-2xs);
  transition: all 0.15s ease;
}

/* 고른 칸은 면으로 칠한다. 테두리를 두껍게 하면 줄이 들썩인다. */
.pm-ask__tab--on {
  border-color: var(--jsini-accent);
  background: var(--jsini-accent);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--jsini-accent) 30%, transparent);
}

/* 맨 앞 칸은 상자 자신이 단추다. 안쪽 여백만 준다. */
.pm-ask__tabs > button.pm-ask__tab,
.pm-ask__tabgo {
  appearance: none;
  min-width: 0;
  padding: 0.25rem 0.5rem;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  line-height: 1.6;
  cursor: pointer;

  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 닫기는 이름 옆에 따로 둔다. 같은 자리면 갈아타려다 닫게 된다. */
.pm-ask__tabx {
  appearance: none;
  flex: 0 0 auto;
  min-width: 1.5rem;
  padding: 0.25rem 0.35rem 0.25rem 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  line-height: 1.6;
  opacity: 0.7;
  cursor: pointer;
}

.pm-ask__tabx:hover { opacity: 1; }

.pm-ask__tab:focus-within {
  outline: 2px solid var(--jsini-accent);
  outline-offset: 1px;
}

/* ── 상세를 여는 동안 적는 자리를 감춘다 ───────────────── */
/* 지우지 않는다 — 글을 붙드는 ask-draft.js 와 감지점이 이 마크업 안에 산다. 사라지면 셋이 함께 끊긴다. */
.pm-ask__pane--off { display: none; }

/* 상세 판은 화면 폭을 통째로 쓴다(52rem 상한은 그대로 받는다). 높이는 화면을 채워 단추가 바닥에 서게 한다. */
.pm-ask:has(> .pm-ask__view) {
  min-height: 100%;
}

.pm-ask__view {
  display: flex;
  flex-direction: column;
  flex: 1;
}

.pm-ask__view .commcont__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

/* ── 상단 입력부 고정 · 하단 목록 스크롤 ─────────────── */
/* 작업 지시 입력부는 고정되고 목록만 남은 높이로 구른다. 휴대폰에서 상세를 볼 때는 본문 전체가 구르도록 가른다. */
.jsini-shell__content:has(> .pm-ask:not(:has(> .pm-ask__view))),
.jsini-right-drawer__body:has(> .pm-ask:not(:has(> .pm-ask__view))) {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.pm-ask:not(:has(> .pm-ask__view)) {
  flex: 1 1 0;
  min-height: 0;
  height: 100%;
}

.pm-ask > .commcont + .commcont {
  margin-top: 0;
}

.pm-ask > .commcont {
  margin-bottom: 0;
}

.pm-ask > .pm-ask__tabs {
  flex: 0 0 auto;
}

/* 한 장의 윗동강. 아래 테두리와 둥근 귀, 그림자를 뗀다 — 두면 목록 판 윗선과 겹치거나 그늘 띠가 생긴다. */
.pm-ask__write {
  flex: 0 0 auto;
  background: var(--jsini-surface);
  border: 1px solid var(--jsini-border);
  border-bottom: 0;
  border-radius: 1rem 1rem 0 0;
  padding: 1.25rem 1.25rem 1rem;
  transition: border-color 0.2s ease;
}

/* 한 장의 아랫동강. 구르는 것은 .pm-ask__scroll 뿐이다. 맞붙는 윗선이 없으니 이음매에서 안쪽 여백만 좁힌다. */
.pm-ask__recent {
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
  background: var(--jsini-surface);
  border: 1px solid var(--jsini-border);
  border-radius: 0 0 1rem 1rem;
  padding: 0.75rem 1.25rem 1.25rem;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.04);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.pm-ask__recent > .commcont__body {
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  min-height: 0;
}

.pm-ask__scroll {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

/* 쓸어내려 새로고침 인디케이터. 카드 z-index(2)보다 앞 레이어(10)에 서고, 투명 배경에 묻히지 않게 독립 캡슐로 띄운다. */
.pm-ask__pull {
  position: relative;
  z-index: 10;
  --pm-ask-pull-y: 0px;
  --pm-ask-pull-ms: 0ms;

  height: var(--pm-ask-pull-y, 0px);
  max-height: 80px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  user-select: none;
  transition: height var(--pm-ask-pull-ms, 0ms) cubic-bezier(0.2, 0.8, 0.2, 1),
              opacity var(--pm-ask-pull-ms, 0ms) ease;
  opacity: 0;
}

.pm-ask__pull.pm-ask__pull--active,
.pm-ask__pull.pm-ask__pull--refreshing {
  opacity: 1;
}

/* 카드 및 리스트 전면에 입체적으로 떠 있는 플로팅 배지 캡슐 */
.pm-ask__pull-inner {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  background: var(--jsini-surface);
  border: 1px solid var(--jsini-border);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.04);
  font-size: var(--jsini-fs-2xs, 0.75rem);
  font-weight: 600;
  color: var(--jsini-text-muted);
  transform: scale(0.94);
  transition: transform 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.pm-ask__pull.pm-ask__pull--ready .pm-ask__pull-inner {
  transform: scale(1);
  border-color: var(--jsini-accent, #1677ff);
  color: var(--jsini-accent, #1677ff);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--jsini-accent, #1677ff) 20%, transparent);
}

.pm-ask__pull.pm-ask__pull--refreshing .pm-ask__pull-inner {
  transform: scale(1);
  border-color: var(--jsini-accent, #1677ff);
  color: var(--jsini-text);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--jsini-accent, #1677ff) 20%, transparent);
}

.pm-ask__pull-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  color: var(--jsini-accent, #1677ff);
}

.pm-ask__pull-arrow {
  display: inline-block;
  transition: transform 0.2s ease;
  transform: rotate(0deg);
}

.pm-ask__pull.pm-ask__pull--ready .pm-ask__pull-arrow {
  transform: rotate(180deg);
}

.pm-ask__pull-spinner {
  display: none;
  width: 14px;
  height: 14px;
  border: 2px solid var(--jsini-border, #e5e7eb);
  border-top-color: var(--jsini-accent, #1677ff);
  border-radius: 50%;
  animation: pm-ask-pull-spin 0.65s linear infinite;
}

.pm-ask__pull.pm-ask__pull--refreshing .pm-ask__pull-arrow {
  display: none;
}

.pm-ask__pull.pm-ask__pull--refreshing .pm-ask__pull-spinner {
  display: inline-block;
}

.pm-ask__pull-text {
  white-space: nowrap;
}

@keyframes pm-ask-pull-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* 목록 헤더: 좌측에 완료건 일괄확인, 우측에 단 수 조절. 이 줄을 inline-size 컨테이너로 삼아 단 수 고르개가 접힐지 펼칠지를 이 줄 폭으로 가른다. */
/* container-type 이 contain: layout 을 함께 걸어 fixed 자식의 기준이 되므로 판 전체가 아니라 이 줄에만 건다. */
.pm-ask__list-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;

  container-type: inline-size;
  container-name: pm-ask-head;
}

.pm-ask__list-left {
  display: inline-flex;
  align-items: center;
  min-width: 0;
}

/* 완료건 일괄 사용자확인 단추 */
.pm-ask__batch-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 1.85rem;
  padding: 0 0.65rem;
  border: 1px solid var(--jsini-border);
  border-radius: 999px;
  background: var(--jsini-bg);
  color: var(--jsini-text-muted);
  font: inherit;
  font-size: var(--jsini-fs-2xs);
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s ease;
}

.pm-ask__batch-btn:hover:not(:disabled) {
  border-color: var(--jsini-accent);
  color: var(--jsini-text);
  background: color-mix(in srgb, var(--jsini-accent) 8%, var(--jsini-surface));
}

.pm-ask__batch-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.pm-ask__batch-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--jsini-accent, #1677ff);
}

.pm-ask__batch-label {
  white-space: nowrap;
}

.pm-ask__batch-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  height: 1.15rem;
  padding: 0 0.3rem;
  border-radius: 999px;
  background: var(--jsini-accent, #1677ff);
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
}

@media (max-width: 480px) {
  .pm-ask__batch-label {
    display: none;
  }
}

/* 목록이 아니라 **카드**다. */
.pm-ask__list {
  --pm-ask-cols: 2;

  list-style: none;
  display: grid;
  grid-template-columns: repeat(var(--pm-ask-cols), minmax(0, 1fr));
  align-items: start;
  gap: 0.6rem;
  margin: 0;
  padding: 0;
}

/* 단 수 고르개. 좁으면 순환 아이콘 하나, 넓으면 캡슐형 세그먼트 넷으로 가른다(맨 아래 컨테이너 질의 참고). */
.pm-ask__cols {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--jsini-border);
  border-radius: 999px;
  background: var(--jsini-bg);
}

/* 좁은 쪽에서는 세그먼트를 display: none 으로 접는다 — 같은 일을 하는 단추가 둘로 읽히지 않게. */
.pm-ask__cols-label,
.pm-ask__col {
  display: none;
}

.pm-ask__col-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 1.85rem;
  padding: 0 0.65rem;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--jsini-text-muted);
  font: inherit;
  font-size: var(--jsini-fs-2xs);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
}

.pm-ask__col-btn:hover {
  background: color-mix(in srgb, currentcolor 8%, var(--jsini-surface));
  color: var(--jsini-text);
}

.pm-ask__col-btn:focus-visible {
  outline: 2px solid var(--jsini-accent);
  outline-offset: 1px;
}

.pm-ask__col-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--jsini-accent, #1677ff);
}

.pm-ask__col-num {
  font-size: var(--jsini-fs-2xs);
  font-weight: 600;
}

/* ── 넓은 쪽: 1·2·3·4 가 모두 선다 ─────────────────── */
/* 경계 420px 은 재어서 고른 값이다. 왼쪽 일괄확인(156px)과 세그먼트(157px)에 틈을 더하면 321px 이고, 그보다 좁으면 서로를 눌러 글자가 깨진다. 단추가 하나 늘면 값을 다시 잰다. */
@container pm-ask-head (min-width: 420px) {
  /* 세그먼트는 칸 사이에 틈이 있어야 눌린 칸이 캡슐로 보인다. */
  .pm-ask__cols {
    gap: 3px;
    padding: 3px;
  }

  .pm-ask__col-btn {
    display: none;
  }

  .pm-ask__cols-label {
    display: inline-block;
  }

  .pm-ask__col {
    display: inline-block;
  }
}

.pm-ask__cols-label {
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-2xs);
  padding-left: 0.35rem;
  padding-right: 0.15rem;
}

.pm-ask__col {
  appearance: none;
  min-width: 1.85rem;
  height: 1.65rem;
  padding: 0 0.5rem;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--jsini-text-muted);
  font: inherit;
  font-size: var(--jsini-fs-2xs);
  font-weight: 600;
  line-height: 1.65rem;
  cursor: pointer;
  transition: all 0.15s ease;
}

.pm-ask__col:hover {
  background: color-mix(in srgb, currentcolor 8%, var(--jsini-surface));
  color: var(--jsini-text);
}

.pm-ask__col[aria-pressed='true'] {
  border-color: var(--jsini-accent);
  background: var(--jsini-accent);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 6px color-mix(in srgb, var(--jsini-accent) 30%, transparent);
}

.pm-ask__col:focus-visible {
  outline: 2px solid var(--jsini-accent);
  outline-offset: 1px;
}

/* ── 빈 상태 (Empty States & Quick Prompts) ──────────────────── */
.pm-ask__empty-card {
  padding: 2.75rem 1.5rem;
  text-align: center;
  background: color-mix(in srgb, var(--jsini-surface) 60%, var(--jsini-bg));
  border: 1px dashed var(--jsini-border);
  border-radius: 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.pm-ask__empty-symbol {
  width: 3.8rem;
  height: 3.8rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--jsini-accent) 12%, var(--jsini-surface));
  color: var(--jsini-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  margin-bottom: 1rem;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--jsini-accent) 18%, transparent);
}

.pm-ask__empty-title {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--jsini-text);
  margin-bottom: 0.4rem;
}

.pm-ask__empty-desc {
  font-size: 0.85rem;
  color: var(--jsini-text-muted);
  max-width: 440px;
  margin-bottom: 1.35rem;
  line-height: 1.5;
}

.pm-ask__prompts {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 100%;
  max-width: 440px;
}

.pm-ask__prompt-btn {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.65rem 1rem;
  border-radius: 0.75rem;
  border: 1px solid var(--jsini-border);
  background: var(--jsini-surface);
  color: var(--jsini-text);
  font-size: 0.82rem;
  text-align: left;
  cursor: pointer;
  transition: all 0.2s ease;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.02);
}

.pm-ask__prompt-btn:hover {
  border-color: var(--jsini-accent);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--jsini-accent) 14%, transparent);
}

.pm-ask__prompt-icon {
  font-size: 1.1rem;
  flex-shrink: 0;
}

.pm-ask__prompt-text {
  flex: 1 1 auto;
  line-height: 1.4;
}

/* 상태를 카드의 색으로 말한다. 색은 공통 배지(jsini-badge--*) 값을 그대로 쓴다 — 화면만의 색을 만들면 같은 「완료」가 화면마다 다른 초록이 된다. 기본은 흐림(--off). */
.pm-ask__item {
  --pm-ask-tone: var(--jsini-text-muted);

  border: 1px solid var(--jsini-border);
  border-left: 4px solid var(--pm-ask-tone);
  border-radius: 0.75rem;
  background: var(--jsini-surface);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
  overflow: hidden;
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.pm-ask__item:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
  border-color: color-mix(in srgb, var(--jsini-accent) 35%, var(--jsini-border));
  border-left-color: var(--pm-ask-tone);
}

.pm-ask__item--on { --pm-ask-tone: #2e7d32; }
.pm-ask__item--warn { --pm-ask-tone: #b26a00; }
.pm-ask__item--err { --pm-ask-tone: #d32f2f; }
.pm-ask__item--off { --pm-ask-tone: var(--jsini-text-muted); }

/* ── 오른쪽으로 밀면 확인 완료 ─────────────────────── */
/* 움직이는 값은 인라인 사용자 지정 속성으로 받는다 — 목록이 5초마다 다시 그려져 Blazor 가 class 를 갈아 치우면 JS 가 붙인 클래스가 지워지고 카드가 밀린 자리에 굳는다. 대는 쪽은 js/ask-swipe.js. */
/* 미는 거리와 문턱은 카드 제 폭(clientWidth)에서 재므로 단 수와 무관하다. */
.pm-ask__item[data-swipe] {
  --pm-ask-swipe: 0px;
  --pm-ask-swipe-ms: 0ms;
  --pm-ask-ready: 0;
  --pm-ask-alive: 1;

  position: relative;
  opacity: var(--pm-ask-alive);
  transition: opacity 180ms ease;
}

/* 카드 왼쪽에서 열리는 띠. 가만히 있을 때 폭 0 이어야 한다 — 본문으로 덮는 방법은 바탕색이 테마마다 어긋나 못 쓰고, 여백을 주면 폭 0 이어도 초록 실오라기가 남는다. */
.pm-ask__ack {
  position: absolute;
  inset-block: 0;
  left: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.25rem;
  width: max(0px, var(--pm-ask-swipe));
  overflow: hidden;
  background: #2e7d32;
  color: #fff;
  font-size: var(--jsini-fs-2xs);
  white-space: nowrap;
  pointer-events: none;
  transition: width var(--pm-ask-swipe-ms) ease;
}

/* 문턱을 넘으면 ✓ 가 커진다. 손을 떼기 전에 「놓으면 처리된다」를 알려 주는 것이 이 둘의 일이다. */
.pm-ask__ack-mark {
  flex: 0 0 auto;
  margin-left: 0.5rem;
  font-size: var(--jsini-fs-sm);
  line-height: 1;
  transform: scale(calc(0.7 + (0.3 * var(--pm-ask-ready))));
  transition: transform 120ms ease;
}

.pm-ask__ack-text {
  opacity: calc(0.45 + (0.55 * var(--pm-ask-ready)));
  transition: opacity 120ms ease;
}

/* 카드 **오른쪽**에서 열리는 삭제 띠. 왼쪽으로 미는 만큼 넓어진다. */
.pm-ask__del {
  position: absolute;
  inset-block: 0;
  right: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.25rem;
  width: max(0px, calc(-1 * var(--pm-ask-swipe)));
  overflow: hidden;
  background: #c62828;
  color: #fff;
  font-size: var(--jsini-fs-2xs);
  white-space: nowrap;
  pointer-events: none;
  transition: width var(--pm-ask-swipe-ms) ease;
}

.pm-ask__del-mark {
  flex: 0 0 auto;
  margin-right: 0.5rem;
  font-size: var(--jsini-fs-sm);
  line-height: 1;
  transform: scale(calc(0.7 + (0.3 * var(--pm-ask-ready))));
  transition: transform 120ms ease;
}

.pm-ask__del-text {
  opacity: calc(0.45 + (0.55 * var(--pm-ask-ready)));
  transition: opacity 120ms ease;
}

/* 선택된 카드 강조 */
.pm-ask__item--picked {
  border-color: var(--jsini-accent);
  background: color-mix(in srgb, var(--jsini-accent) 7%, var(--jsini-bg));
}

/* 카드 전체가 누르는 자리다. 표 대신 단추 목록인 것은 모바일에서 표의 가로 스크롤이 최악이기 때문이다. 왼쪽은 지시자 얼굴, 오른쪽은 두 층이다. 손가락 겨누는 자리의 바닥(min-height)은 그대로 둔다. */
.pm-ask__head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  min-height: 2.75rem;
  padding: 0.5rem 0.6rem;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.pm-ask__head:hover {
  background: color-mix(in srgb, var(--jsini-text) 6%, transparent);
}

/* 밀 수 있는 카드의 본문. 띠 위에 놓이도록 z-index 를 주고, touch-action: pan-y 로 가로 끌기만 우리에게 넘긴다. 이 한 줄이 기능의 핵심이다. */
.pm-ask__item[data-swipe] > .pm-ask__head {
  position: relative;
  z-index: 2;
  touch-action: pan-y;
  transform: translateX(var(--pm-ask-swipe));
  transition: transform var(--pm-ask-swipe-ms) ease;
}

/* 움직임을 줄여 달라고 한 사람에게는 결과만 준다. 카드는 바로 사라지고 띠는 열리지 않는다. */
@media (prefers-reduced-motion: reduce) {
  .pm-ask__item[data-swipe],
  .pm-ask__item[data-swipe] > .pm-ask__head,
  .pm-ask__ack,
  .pm-ask__ack-mark,
  .pm-ask__ack-text,
  .pm-ask__del,
  .pm-ask__del-mark,
  .pm-ask__del-text {
    transition: none;
  }
}

/* ── 모바일 작업 목록 (`pm-ai-mobile-list`) ─────────────────── */
.pm-ai-mobile-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* 이 화면의 카드는 한 줄에 한 장이다(격자가 아니라 세로로 쌓는다). align-items: stretch 가 여기 있어야 한다 — 빠지면 가로가 제 글자 길이만큼만 되어 짧은 건은 쪼그라들고 긴 건은 삐져나간다. */
.pm-ai-mobile-list > .pm-ask__list {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 카드가 제 폭을 넘지 않게 두 번 못 박는다 — 줄바꿈 없는 긴 값이 있으면 flex 최소 너비(auto)가 카드를 밀어낸다. */
.pm-ai-mobile-list > .pm-ask__list > .pm-ask__item {
  min-width: 0;
  max-width: 100%;
}

.pm-ai-mobile-bar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0.25rem 0;
}

/* 두 층이 들어가는 칸. min-width: 0 이 있어야 안쪽 제목이 칸을 밀어내 얼굴이 카드 밖으로 밀리지 않는다. */
.pm-ask__rows {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

/* ── 사람의 얼굴 (`pm-face`) ───────────────────────────── */
/* 누가 시킨 건인지를 글자가 아니라 얼굴로 말한다. 동그라미 자체는 공용(jsini-face)이고 여기는 치수와 색만 둔다. 상태 띠 색을 쓰지 않는 것은 얼굴이 상태의 일부로 읽히기 때문이다. */
.pm-face {
  --jsini-face-size: 1.75rem;
  --jsini-face-bg: color-mix(in srgb, var(--jsini-text) 10%, transparent);
  --jsini-face-ink: color-mix(in srgb, var(--jsini-text) 80%, transparent);
  --jsini-face-initial-size: 0.75em;
}

/* 상세의 얼굴. 이름은 큰데 카드보다 작다 — 상세는 누구 것인지 이미 적혀 있어 표시로 족하다. */
.pm-face--lg {
  --jsini-face-size: 1.5rem;
}

/* 첫 층 — 상태와 총작업시간. 모자라면 접힌다(flex-wrap). 접지 않으면 넷 중 마지막 값이 overflow: hidden 에 소리 없이 잘린다. */
.pm-ask__line {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: baseline;
  justify-content: space-between;
}

/* 둘째 층 — 실행일시와 제목. 시각을 앞에 둬야 자리가 고정된다. 제목은 nowrap 으로 묶어 넘치면 … 로 자른다. */
.pm-ask__line--sub {
  flex-wrap: nowrap;
  gap: 0.35rem;
  align-items: center;
  justify-content: flex-start;
  min-width: 0;
}

/* 3단 및 4단에서 독립된 제목 줄 */
.pm-ask__line--title {
  display: block;
  min-width: 0;
  width: 100%;
}

/* 카드 두 층에 서는 공통 배지. 줄이지 않는다 — 최소 너비가 한 글자라 눌리면 두 글자가 세로로 쪼개진다. 줄어도 되는 것은 제목 쪽이다. */
.pm-ask__line > .jsini-badge {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* 처리차수 배지 — 2차 이상일 때 첫째 줄에 선다. */
.pm-ask__turn-badge {
  flex: 0 0 auto;
  font-size: 0.72em;
  font-weight: 700;
  padding: 0.05rem 0.35rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--jsini-accent) 45%, var(--jsini-border));
  background: color-mix(in srgb, var(--jsini-accent) 12%, transparent);
  color: var(--jsini-accent);
  line-height: 1.2;
  white-space: nowrap;
}

/* 상태 글자. 띠와 같은 색을 쓴다(`--pm-ask-tone`). */
.pm-ask__state {
  font-size: 0.8em;
  font-weight: 700;
  color: var(--pm-ask-tone);
  white-space: nowrap;
}

/* 총작업시간. 표제를 달지 않고 고정폭 숫자를 쓴다. 왼쪽 여백은 auto 로 민다 — space-between 만으론 상태가 가운데로 떠 배지와 갈라진다. */
.pm-ask__span {
  margin-left: auto;
  font-size: 0.85em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0.85;
}

/* ── 어느 AI 에게 간 건인가 (`pm-ai`) ─────────────────── */
/* 가르는 것은 글자가 아니라 색(AI 심볼색)이다. 상태 띠와 섞이지 않게 면을 칠한 칩으로 하고, flex: 0 0 auto 가 있어야 반 폭 카드에서 찌그러지지 않는다. 카드와 들여다보는 창이 같이 쓴다. */
.pm-ai {
  --pm-ai: var(--jsini-text-muted);
  --pm-ai-ink: #ffffff;

  flex: 0 0 auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  height: 1.15rem;
  padding: 0 0.2rem;
  border-radius: 0.3rem;
  background: var(--pm-ai);
  color: var(--pm-ai-ink);
  font-size: 0.7em;
  font-weight: 800;
  line-height: 1;
}

/* Claude — Anthropic 의 흙빛 주황. */
.pm-ai--claude { --pm-ai: #d97757; }

/* 안티그래비티 — 구글의 파랑. */
.pm-ai--antigravity { --pm-ai: #4285f4; }

/* Copilot — 깃허브의 먹빛. 어두운 테마에서는 바탕과 글자를 맞바꾼다 — 검은 칩이 어두운 판에 묻혀 배지가 사라진다. */
.pm-ai--copilot { --pm-ai: #24292f; }

:root[data-theme='dark'] .pm-ai--copilot {
  --pm-ai: #d0d7de;
  --pm-ai-ink: #16181d;
}

/* 공통코드에 새로 생긴 AI. 색을 정하지 않아 흐림으로 둔다 — 배지 자리가 비는 것보다 낫다. */
.pm-ai--etc { --pm-ai: var(--jsini-text-muted); }

/* 들여다보는 창의 머리띠 칩. 한 치수 크다(머리띠 글자가 카드보다 크다). em 이 아니라 rem 으로 적는다 — 머리띠에는 font-size 가 없어 em 이면 칩만 들쭉날쭉하다. */
.pm-ai--lg {
  min-width: 1.5rem;
  height: 1.5rem;
  padding: 0 0.3rem;
  border-radius: 0.35rem;
  font-size: var(--jsini-fs-xs);
}

/* 실행일시. 제목보다 한 단 흐리다 — 같은 굵기면 제목과 다툰다. */
.pm-ask__when {
  font-size: 0.8em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0.65;
}

/* 카드의 작업 대상 한 줄. 이름을 pm-ask__target 과 같게 두면 고르개 규칙이 덮인다. 상한 40%는 이름이 잘려도 지키는 값이다 — 전체 이름은 title 이 든다. */
.pm-ask__to {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 40%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8em;
  opacity: 0.75;
}

/* 아직 안 읽은 남긴말. 내가 올린 요청 카드에만 선다. 「AI 작업 요청」의 pm-req__new 와 같은 모양이다 — 색이 갈리면 같은 값을 둘로 읽는다. */
.pm-ask__new {
  flex: 0 0 auto;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  font-size: 0.75em;
  font-weight: 700;
  white-space: nowrap;
  color: #fff;
  background: #d32f2f;
}

/* 제목. 남은 폭을 다 쓰고 넘치면 … 로 자른다. 여기만 잘린다 — 앞머리는 남는다. */
.pm-ask__title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9em;
  font-weight: 600;
}

/* ── 단별 레이아웃 제어 (1단~4단) ─────────────────────────── */

/* 2단 이상 — 대상(TargetName) 숨김 (1단에서만 표시) */
.pm-ask__list[data-cols='2'] .pm-ask__to,
.pm-ask__list[data-cols='3'] .pm-ask__to,
.pm-ask__list[data-cols='4'] .pm-ask__to,
.pm-ask__item--cols-2 .pm-ask__to,
.pm-ask__item--cols-3 .pm-ask__to,
.pm-ask__item--cols-4 .pm-ask__to {
  display: none !important;
}

/* 3단 및 4단 — 1번줄의 처리시간 숨김 */
.pm-ask__list[data-cols='3'] .pm-ask__span,
.pm-ask__list[data-cols='4'] .pm-ask__span,
.pm-ask__item--cols-3 .pm-ask__span,
.pm-ask__item--cols-4 .pm-ask__span {
  display: none !important;
}

/* 4단 — 1번줄 모델배지와 상태만 표시 (차수배지 숨김) */
.pm-ask__list[data-cols='4'] .pm-ask__turn-badge,
.pm-ask__item--cols-4 .pm-ask__turn-badge {
  display: none !important;
}

/* 4단 — 1번줄(모델배지·상태) 줄바꿈 방지 */
.pm-ask__list[data-cols='4'] .pm-ask__rows > .pm-ask__line:first-child,
.pm-ask__item--cols-4 .pm-ask__rows > .pm-ask__line:first-child {
  flex-wrap: nowrap;
}

/* 4단 — 3번줄과 4번줄에 걸쳐서 제목을 2줄로 표현 */
.pm-ask__list[data-cols='4'] .pm-ask__title,
.pm-ask__item--cols-4 .pm-ask__title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  white-space: normal;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-all;
  line-height: 1.35;
  max-height: calc(1.35em * 2);
}

/* 3단 및 4단 — 카드가 3줄 이상이 되므로 헤더 아이템을 상단 정렬 */
.pm-ask__list[data-cols='3'] .pm-ask__head,
.pm-ask__list[data-cols='4'] .pm-ask__head,
.pm-ask__item--cols-3 .pm-ask__head,
.pm-ask__item--cols-4 .pm-ask__head {
  align-items: flex-start;
}

/* ── 차수가 2회 이상인 카드의 차수별 제목 목록 ─────────── */
/* 한 줄 대표 제목으로는 차수별로 무엇을 시켰는지 알 수 없어 차수 번호와 함께 줄줄이 세운다. */
.pm-ask__turns {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin-top: 0.15rem;
  min-width: 0;
}

.pm-ask__turn {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  min-width: 0;
}

.pm-ask__turn-no {
  flex: 0 0 auto;
  font-size: 0.72em;
  font-weight: 700;
  color: var(--jsini-accent);
  background: color-mix(in srgb, var(--jsini-accent) 12%, transparent);
  padding: 0.05rem 0.35rem;
  border-radius: 4px;
  line-height: 1.25;
  white-space: nowrap;
}

.pm-ask__turn-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.88em;
  font-weight: 600;
  color: var(--jsini-text);
}

/* 목록 아래 더보기 줄. 격자 밖이다 — 안에 넣으면 반 폭 칸 하나를 차지해 빈자리가 생긴다. */
.pm-ask__more {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.pm-ask__morego {
  flex: 1 1 auto;
  min-height: 2.75rem;
  padding-inline: 1.25rem;
  font-weight: 600;
  border-radius: 999px;
}

/* 접기. 더보기보다 흐리고 좁다 — 되돌리는 길이지 권하는 길이 아니다. */
.pm-ask__fold {
  flex: 0 0 auto;
  min-height: 2.5rem;
  opacity: 0.75;
  border-radius: 999px;
}

.pm-ask__more-sentinel {
  display: block;
  height: 1px;
  pointer-events: none;
}

@media (max-width: 640px) {
  .pm-ask__write,
  .pm-ask__recent {
    padding: 1rem;
    border-radius: 0.85rem;
  }
}

/* ── 가로로 눕힌 휴대폰 ─────────────────────────────── */
/* 눕히면 창 높이가 390px 뿐이라 적는 자리가 높이를 다 가져가 목록이 0px 로 눌린다. 그래서 짧은 가로 화면에서는 위아래가 아니라 왼쪽(적는 자리)·오른쪽(목록)으로 쪼갠다. 서랍과 좁은 기기는 쌓은 채로 둔다. */
/* max-height 로 가른다 — orientation 만 보면 눕힌 태블릿까지 걸린다. */
@media (orientation: landscape) and (max-height: 560px) {

  /* 적는 자리는 줄어들 수 있는 칸이다. 고르개 줄과 보내기 줄은 손가락 자리라 높이를 건드리지 않는다. */
  .pm-ask:not(:has(> .pm-ask__view)) > .pm-ask__write {
    flex: 0 1 auto;
    min-height: 0;
    padding: 0.55rem 0.8rem 0.6rem;
    display: flex;
    flex-direction: column;
  }

  .pm-ask:not(:has(> .pm-ask__view)) > .pm-ask__write > .commcont__body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
  }

  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__where {
    flex: 0 0 auto;
    margin-bottom: 0.4rem;
  }

  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__bar {
    flex: 0 0 auto;
    margin-top: 0.5rem;
  }

  /* 글상자. 세로의 30vh 상한은 눕히면 바닥처럼 굳어 안 줄어드므로 걷는다. 두 줄은 들어가도록 바닥만 남긴다. */
  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__text {
    flex: 1 1 auto;
    min-height: 2.5rem;
    max-height: none;
  }

  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__text .dxbl-memo-scroll-container {
    height: 100%;
    max-height: none;
  }

  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__text textarea {
    height: 100%;
    min-height: 0;
    max-height: none;
    padding: 0.4rem 0.7rem;
  }

  /* 목록이 제 몫을 먼저 떼어 간다. 쌓인 채 남는 자리(서랍·아주 좁은 기기)의 값이다 — min() 의 뒤가 천장이고, 없으면 보내기 단추가 화면 밖으로 밀린다. */
  .pm-ask:not(:has(> .pm-ask__view)) > .pm-ask__recent {
    min-height: min(10.5rem, 38%);
    padding: 0.5rem 0.8rem 0.6rem;
  }

  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__list-head {
    margin-bottom: 0.35rem;
  }

  /* 카드 사이와 안쪽을 줄인다. 누르는 자리의 바닥(min-height)은 그대로 둔다. */
  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__list {
    gap: 0.4rem;
  }

  .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__head {
    padding: 0.35rem 0.6rem;
  }
}

/* 화면으로 선 판만 좌우로 쪼갠다. 520px 은 눕힌 휴대폰이면 넘는 값이고, 그 아래는 쌓인 배치를 그대로 쓴다. */
@media (orientation: landscape) and (max-height: 560px) and (min-width: 520px) {

  .jsini-shell__content > .pm-ask:not(:has(> .pm-ask__view)) {
    flex-direction: row;
    max-width: none;
  }

  /* 한 장의 왼쪽. 맞붙는 쪽이 오른쪽으로 바뀌었으므로 테두리와 둥근 귀도 그쪽으로 옮긴다. */
  .jsini-shell__content > .pm-ask:not(:has(> .pm-ask__view)) > .pm-ask__write {
    flex: 0 0 min(26rem, 46%);
    min-width: 0;
    border-bottom: 1px solid var(--jsini-border);
    border-right: 0;
    border-radius: 1rem 0 0 1rem;
  }

  /* 반으로 쪼갠 왼쪽은 좁아 고르개 바탕 너비를 줄여 한 줄로 세운다. min-width: 0 이 함께 가야 DevExpress 의 min-content 에 걸리지 않는다. */
  .jsini-shell__content > .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__target {
    flex: 3 1 6rem;
    min-width: 0;
  }

  .jsini-shell__content > .pm-ask:not(:has(> .pm-ask__view)) .pm-ask__kind {
    flex: 2 1 6rem;
    min-width: 0;
  }

  /* 한 장의 오른쪽. 창 높이를 통째로 받으므로 위에서 뗀 min-height 는 필요 없다. */
  .jsini-shell__content > .pm-ask:not(:has(> .pm-ask__view)) > .pm-ask__recent {
    flex: 1 1 0;
    min-width: 0;
    border-radius: 0 1rem 1rem 0;
  }
}

/* ── AI 작업 요청 (`pm-req`) ─────────────────────────────────── */
/* 적어 두기만 하는 화면이라 「빠른 지시」와 클래스를 함께 쓰지 않는다 — 두 화면은 갈 방향이 다르다. */

.pm-req {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 56rem;
}

/* 칸 하나 — 이름과 입력이 위아래로 선다. 옆에 두면 열 줄짜리 글상자 옆의 이름이 허공에 뜬다. */
.pm-req__field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: 0.9rem;
}

.pm-req__label {
  font-size: 0.85em;
  font-weight: 600;
  color: var(--jsini-text-muted);
}

.pm-req__title {
  width: 100%;
}

/* 본문. 「빠른 지시」와 달리 높이를 조이지 않는다 — 앉아서 길게 적는 자리다. */
.pm-req__text {
  width: 100%;
}

.pm-req__text textarea {
  min-height: 12rem;
  font-size: var(--jsini-fs-md);
  line-height: 1.5;
}

/* 손가락으로 쓰는 기기에서만 16px 바닥을 둔다. (iOS 확대 방지) */
@media (pointer: coarse) {
  .pm-req__text textarea {
    font-size: max(var(--jsini-fs-md), 1rem);
  }
}

/* 단추 줄. 저장은 오른쪽 끝, 취소·거둬들이기는 왼쪽 — 되돌리기와 진행이 손가락 하나 거리에 붙지 않게. */
.pm-req__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

.pm-req__save {
  min-height: 2.6rem;
  padding-inline: 1.25rem;
  margin-left: auto;
  font-weight: 600;
}

.pm-req__cancel,
.pm-req__drop {
  min-height: 2.6rem;
}

/* 왜 못 고치는지 적는 한 줄. 회색 단추만 두면 「고장」으로 읽힌다. */
.pm-req__why {
  flex: 1 1 14rem;
  font-size: 0.9em;
  color: var(--jsini-text-muted);
}

@media (width <= 30rem) {
  .pm-req__save {
    flex: 1 1 100%;
    margin-left: 0;
  }
}

/* ── 내가 올린 것 ──────────────────────────────────────────── */

/* 줄로 쌓는다. 제목이 곧 「무엇을 부탁했나」라 잘리면 고를 수 없으므로 폭을 다 준다. */
.pm-req__list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
}

/* 왼쪽 띠가 단계를 말한다. 배지 글자와 같은 색을 쓴다. */
.pm-req__item {
  --pm-req-tone: var(--jsini-text-muted);

  border: 1px solid var(--jsini-border, rgba(0, 0, 0, 0.12));
  border-left: 0.35rem solid var(--pm-req-tone);
  border-radius: 6px;
  overflow: hidden;
}

.pm-req__item--on { --pm-req-tone: #2e7d32; }
.pm-req__item--warn { --pm-req-tone: #b26a00; }
.pm-req__item--err { --pm-req-tone: #d32f2f; }
.pm-req__item--off { --pm-req-tone: var(--jsini-text-muted); }

/* 줄 전체가 누르는 자리. `<button>` 이라 자판으로도 닿는다 — `<li>` 의 onclick 은 탭으로 못 간다. */
.pm-req__head {
  display: block;
  width: 100%;
  padding: 0.55rem 0.75rem;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
}

.pm-req__head:hover {
  background: var(--jsini-bg-subtle, rgba(0, 0, 0, 0.04));
}

/* 지금 위 판에 실려 있는 줄. 스크롤해 내려오면 위 판의 제목이 화면 밖이라 여기서 보여 준다. */
.pm-req__head--picked {
  background: var(--jsini-bg-subtle, rgba(0, 0, 0, 0.06));
  box-shadow: inset 0 0 0 1px var(--pm-req-tone);
}

.pm-req__rows {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.pm-req__line {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  min-width: 0;
}

.pm-req__line--sub {
  font-size: 0.95em;
}

/* 단계 글자. 띠와 같은 색을 쓴다. */
.pm-req__stage {
  flex: 0 0 auto;
  font-size: 0.85em;
  font-weight: 700;
  color: var(--pm-req-tone);
}

.pm-req__when {
  flex: 0 0 auto;
  font-size: 0.8em;
  color: var(--jsini-text-muted);
}

/* 제목. 한 줄에서 넘치면 꼬리를 자른다 — 전문은 눌러서 본다. */
.pm-req__title-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 더보기는 폭을 다 쓴다 — 남은 건수가 적히고 휴대폰에서 손가락이 닿는 넓이가 필요하다. 「빠른 지시」와 규칙이 같다. */
.pm-req__more {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.pm-req__morego {
  flex: 1 1 auto;
  min-height: 2.5rem;
}

/* 접기. 더보기보다 흐리고 좁다 — 되돌리는 길이지 권하는 길이 아니다. */
.pm-req__fold {
  flex: 0 0 auto;
  min-height: 2.5rem;
  opacity: 0.75;
}

/* 목록 줄의 남긴말 배지. 안 읽은 것은 채운 칩, 다 읽은 것은 흐린 곁글이다 — 색을 새로 만들지 않는다. */
.pm-req__new,
.pm-req__notes {
  flex: 0 0 auto;
  margin-left: 0.4rem;
  font-size: 0.75em;
  white-space: nowrap;
}

.pm-req__new {
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  font-weight: 700;
  color: #fff;
  background: #d32f2f;
}

.pm-req__notes {
  color: var(--jsini-text-muted);
}

/* 남긴 말 판. 위아래와 간격은 같되 왼쪽 띠를 둔다 — 「고른 건 하나에 딸린 것」이라 성격이 다르다. */
.pm-req__notepane {
  border-left: 0.2rem solid color-mix(in srgb, var(--jsini-accent) 55%, transparent);
  padding-left: 0.75rem;
}

/* ── 오간 남길말 (`pm-note`) ─────────────────────────────────── */
/* 요청 하나에 관리자와 올린 사람이 번갈아 남기는 말이다. 말풍선이고 왼쪽이 올린 사람이다 — 로그인한 사람으로 가르면 같은 대화가 두 화면에서 뒤집힌다. */

.pm-note {
  margin-top: 1rem;
}

.pm-note__head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.5rem;
  font-size: 0.95em;
  font-weight: 700;
}

.pm-note__count {
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  font-size: 0.8em;
  font-weight: 600;
  color: var(--jsini-text-muted);
  border: 1px solid var(--jsini-border);
}

.pm-note__empty {
  margin: 0 0 0.75rem;
  color: var(--jsini-text-muted);
}

.pm-note__list {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

/* 줄 하나. 얼굴과 말풍선이 가로로 서고, 관리자 줄은 **차례를 뒤집는다**. */
.pm-note__item {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  max-width: 100%;
}

.pm-note__item--admin {
  flex-direction: row-reverse;
}

/* 말풍선은 폭을 다 쓰지 않는다 — 좌우 차이가 보이려면 반대편에 빈자리가 있어야 한다. */
.pm-note__bubble {
  flex: 0 1 auto;
  max-width: 85%;
  padding: 0.45rem 0.65rem;
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md);
  background: color-mix(in srgb, var(--jsini-surface) 70%, transparent);
}

/* 관리자 줄은 옅게 칠한다. 테두리만으로 가르면 어두운 테마에서 둘이 같아진다. */
.pm-note__item--admin .pm-note__bubble {
  background: color-mix(in srgb, var(--jsini-accent) 10%, var(--jsini-surface));
}

.pm-note__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.2rem;
  font-size: 0.78em;
  color: var(--jsini-text-muted);
}

.pm-note__who {
  font-weight: 600;
  color: var(--jsini-text);
}

/* 아직 안 읽은 줄. **관리자 쪽에서 뜻이 있다** — 「내 말이 닿았나」에 답한다. */
.pm-note__unread {
  padding: 0.02rem 0.35rem;
  border-radius: 999px;
  font-weight: 700;
  color: #fff;
  background: #b26a00;
}

/* 본문. 적은 그대로 편다 — 상자 안이 구르지 않는다(`pm-peek__pre` 와 같은 규칙). */
.pm-note__text {
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.5;
  font-family: inherit;
  font-size: 0.92em;
  color: var(--jsini-text);
}

/* 적는 줄. 글상자가 남는 폭을 다 먹고 단추는 오른쪽 아래에 붙는다. */
.pm-note__write {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
}

.pm-note__box {
  flex: 1 1 auto;
  min-width: 0;
}

.pm-note__save {
  flex: 0 0 auto;
  min-height: 2.5rem;
}

/* 좁은 화면에서는 단추가 아래로 내려가 폭을 다 쓴다. */
@media (max-width: 40rem) {
  .pm-note__bubble {
    max-width: 92%;
  }

  .pm-note__write {
    flex-direction: column;
    align-items: stretch;
  }
}

/* ── 들여다보는 창 (`pm-peek`) ───────────────────────────────── */
/* 카드를 누르면 뜨는 창. 머리띠 → 처리 요약 → 탭 줄 순이고, 휴대폰에서는 화면을 꽉 채운다. */

/* 머리띠 — 상태 · AI · 지시자 · 시각. 가운데로 맞춘다: 밑줄 맞춤은 넷이 계단처럼 어긋나서 쓰지 않는다. 라벨은 시각 셋에만 붙는다. */
.pm-peek__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.9rem;
  margin-bottom: 0.6rem;
}

/* 창에서는 표제를 단다 — 값 둘이 나란히 서면 어느 쪽이 어느 것인지 한 번은 읽어야 한다. */
.pm-peek__cell {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
}

.pm-peek__label {
  font-size: var(--jsini-fs-2xs);
  opacity: 0.6;
}

/* 지시자 칸은 안쪽도 가운데 맞춤이다 — 동그라미와 이름을 밑줄로 맞추면 얼굴이 위로 솟는다. */
.pm-peek__cell--who {
  align-items: center;
  gap: 0.35rem;
}

.pm-peek__value {
  font-size: var(--jsini-fs-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 휴대폰에서는 머리띠 항목을 한 줄로 세우도록 간격을 좁힌다. */
@media (max-width: 767px) {
  .pm-peek__top {
    gap: 0.35rem 0.55rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .pm-peek__top::-webkit-scrollbar {
    display: none;
  }

  .pm-peek__top > * {
    flex-shrink: 0;
  }

  .pm-peek__cell {
    gap: 0.2rem;
  }

  .pm-peek__cell--who {
    gap: 0.25rem;
  }
}

.pm-peek__pane {
  padding-top: 0.6rem;
}

.pm-peek__dim {
  margin: 0 0 0.5rem;
  opacity: 0.7;
}

/* 글 상자에는 높이 상한을 두지 않는다(로그만 예외). 상자마다 구르는 자리가 생기면 긴 결과를 끝까지 읽었는지 알 수 없다. 길면 판이 길어진다. */
/* `<pre>` 는 Bootstrap 이 고정폭을 걸므로 화면 설정의 글꼴이 이기도록 한다. */
.pm-peek__pre {
  font-family: var(--tb-font);
  margin: 0 0 0.5rem;
  padding: 0.6rem 0.75rem;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.5;
  color: var(--jsini-text);
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md);
}

/* 지시는 사람이 읽는 글이라 바탕도 본문과 같게. 결과문은 번역 판(`.pm-xlat`)이 그리므로 --result 를 적지 않는다. */
.pm-peek__pre--ask {
  font-size: var(--jsini-fs-sm);
  background: var(--jsini-bg);
}

/* 지시문에 적힌 화면 주소. 글자는 그대로 두고 링크 모양만 입힌다. */
.pm-peek__ask-link {
  color: var(--bs-link-color, var(--tb-primary));
  text-decoration: underline;
  text-underline-offset: 2px;
  word-break: break-all;
}

/* 한 판 안의 칸 이름. 이어 서므로 어디서 어디까지인지 이 줄이 말한다. 크게 키우지 않는다 — 제목이 눈에 띄면 훑는 눈이 제목만 타고 내려간다. */
.pm-peek__head {
  margin: 0.9rem 0 0.35rem;
  font-size: var(--jsini-fs-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--jsini-text-muted);
}

/* 판의 첫 칸은 위 여백이 필요 없다. 탭 몸통이 이미 띄워 준다. */
.pm-peek__pane > .pm-peek__head:first-child,
.pm-peek__pane > .pm-peek__head-row:first-child {
  margin-top: 0;
}

/* 머리말과 보조 단추(음성 읽기 등)가 한 줄에 나란히 설 때 */
.pm-peek__head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.9rem 0 0.35rem;
}

.pm-peek__head-row > .pm-peek__head {
  margin: 0;
}

/* ── 접는 머리 (`pm-peek__fold`) ───────────────────────────────── */
/* 「처리 요약」 제목이 곧 접는 단추다 — 화살표만 따로 세우면 누를 자리가 손가락보다 작다. 단추처럼 보이지 않게 흐리게 둔다. */
.pm-peek__fold {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  user-select: none;
}

.pm-peek__fold:hover,
.pm-peek__fold:focus-visible {
  color: var(--jsini-text);
}

/* 화살표는 글자 하나를 돌려 쓴다 — ▸ ▾ 를 갈아 끼우면 글자폭이 달라 제목이 흔들린다. */
.pm-peek__fold-mark {
  display: inline-block;
  flex: 0 0 auto;
  width: 0.7rem;
  font-size: var(--jsini-fs-2xs, 0.75rem);
  line-height: 1;
  transition: transform 0.15s ease-in-out;
}

.pm-peek__fold-mark--open {
  transform: rotate(90deg);
}

/* ── 음성으로 읽어주기 단추 ─────────────────────────────────── */
/* 글자 없이 그림 하나다 — 글자가 머리줄을 먹고 휴대폰에서 두 줄을 만든다. 말은 title·aria-label 에 남긴다. */
.pm-peek__speech-btn {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  padding: 0.22rem;
  color: var(--jsini-accent, #0078d4);
  background: var(--jsini-surface, #fff);
  border: 1px solid var(--jsini-border, #d1d5db);
  border-radius: var(--jsini-radius-sm, 4px);
  cursor: pointer;
  line-height: 1;
  user-select: none;
  transition: all 0.15s ease-in-out;
}

.pm-peek__speech-btn:hover:not(:disabled) {
  background: var(--jsini-accent-soft, rgba(0, 120, 212, 0.1));
  border-color: var(--jsini-accent, #0078d4);
}

.pm-peek__speech-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.pm-peek__speech-btn--speaking {
  color: #fff;
  background: var(--jsini-danger, #d13438);
  border-color: var(--jsini-danger, #d13438);
  animation: pm-peek-pulse 1.5s infinite;
}

.pm-peek__speech-btn--speaking:hover {
  background: var(--jsini-danger-hover, #a80000);
  border-color: var(--jsini-danger-hover, #a80000);
}

/* 그림 크기는 여기서 다시 잡는다 — 뿌리의 --jsini-icon-size 는 제목보다 커 보인다. 색은 단추가 쥔다(currentColor). */
.pm-peek__speech-icon {
  --jsini-icon-size: 0.95rem;
}

@keyframes pm-peek-pulse {
  0% { box-shadow: 0 0 0 0 rgba(209, 52, 56, 0.4); }
  70% { box-shadow: 0 0 0 5px rgba(209, 52, 56, 0); }
  100% { box-shadow: 0 0 0 0 rgba(209, 52, 56, 0); }
}

/* ── 함께 보낸 파일 (`pm-peek__files`) ─────────────────────────── */
/* 지시와 결과 사이에 줄로 쌓는다 — 이름이 잘리면 안 된다. 그림은 크게 깔지 않는다: 사진 다섯 장이 펴지면 결과가 화면 밖으로 밀린다. */

.pm-peek__files {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0 0 0.5rem;
  padding: 0;
}

.pm-peek__file > a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--jsini-border, rgba(0, 0, 0, 0.12));
  border-radius: 4px;
  color: inherit;
  text-decoration: none;
}

.pm-peek__file > a:hover {
  background: var(--jsini-bg-subtle, rgba(0, 0, 0, 0.04));
}

/* 미리보기는 칩보다 크되 줄 높이를 지배하지 않을 만큼만. */
.pm-peek__fileimg {
  width: 2.5rem;
  height: 2.5rem;
  flex: 0 0 auto;
  object-fit: cover;
  border-radius: 3px;
  background: var(--jsini-bg-subtle, rgba(0, 0, 0, 0.04));
}

/* 이름이 자리를 다 쓰고 크기가 오른쪽 끝에 붙는다. */
.pm-peek__filename {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pm-peek__filesize {
  flex: 0 0 auto;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-xs);
}

/* 처리 요약은 머리띠와 탭 줄 사이에 선다 — 로그를 펴도 결론이 남아야 돌고 있는 건을 지켜볼 수 있다. 아래 여백은 머리띠가 탭 줄에 두던 값과 같다. */
.pm-peek__summary {
  margin-bottom: 0.6rem;
}

/* 첫 줄은 위 여백이 필요 없다 — 머리띠가 이미 띄워 준다. */
.pm-peek__summary > .pm-peek__head-row:first-child {
  margin-top: 0;
}

/* 처리 요약의 알맹이. 이 칸만 상자가 아니라 띠다 — 왼쪽 선으로 「원문이 아니라 정리한 말」임을 가른다. */
.pm-peek__sum {
  margin: 0 0 0.5rem;
  padding: 0.6rem 0.75rem;
  background: var(--jsini-accent-soft, var(--jsini-surface));
  border-left: 3px solid var(--jsini-accent);
  border-radius: 0 var(--jsini-radius-md) var(--jsini-radius-md) 0;
}

/* 결론 한 문장. 요약 안에서 이것만 굵다. */
.pm-peek__sum-line {
  margin: 0;
  font-size: var(--jsini-fs-sm);
  font-weight: 600;
  line-height: 1.5;
  color: var(--jsini-text);
}

.pm-peek__sum-list {
  margin: 0.4rem 0 0;
  padding-left: 1.1rem;
  font-size: var(--jsini-fs-sm);
  line-height: 1.55;
  color: var(--jsini-text);
}

.pm-peek__sum-list li + li {
  margin-top: 0.15rem;
}

/* 「확인할 것」은 사람이 이어서 할 일이라 색을 달리 준다 — 한 일 목록과 섞이면 그 칸이 있으나 마나다. */
.pm-peek__sum-label {
  margin: 0.6rem 0 0;
  font-size: var(--jsini-fs-2xs);
  font-weight: 600;
  color: var(--jsini-warning);
}

.pm-peek__sum-list--check {
  color: var(--jsini-text);
}

/* ── 차수 묶음 (`pm-peek__turn`) ────────────────────────────────── */
/* 차수마다 한 묶음. 상자로 두르지 않는다 — 셋이 서면 안쪽 글상자 테두리와 겹쳐 두 겹으로 읽힌다. 위에 그은 선 하나가 가른다. */

.pm-peek__turn + .pm-peek__turn {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--jsini-border);
}

/* 머리줄은 통째로 누를 자리다. 접힌 판에서 이 줄이 그 차수에 대해 말하는 전부다. */
.pm-peek__turn-head {
  margin: 0;
}

.pm-peek__turn-btn {
  width: 100%;
  gap: 0.4rem;
  padding: 0.2rem 0;
  text-align: left;
}

/* 「3차」 — 번호가 먼저 읽혀야 한다. */
.pm-peek__turn-no {
  flex: 0 0 auto;
  font-size: var(--jsini-fs-sm);
  font-weight: 600;
  color: var(--jsini-text);
}

/* 그 차수에 무엇을 시켰나. 한 줄에 못 들어가면 말줄임이다 — 모델이 글자 수를 늘 지키지 않아 넘치면 머리줄이 두 줄이 된다. 전문은 title 에 있다. */
.pm-peek__turn-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text);
}

/* 언제 얼마나 돌았나 — 오른쪽 끝에 서야 차수끼리 견줘진다. 제목이 없어도 margin-left: auto 로 민다. */
.pm-peek__turn-when {
  flex: 0 0 auto;
  margin-left: auto;
  padding-left: 0.4rem;
  text-align: right;
  font-size: var(--jsini-fs-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--jsini-text-muted);
  white-space: nowrap;
}

/* 펴진 묶음의 몸통은 머리줄 아래로 들여 쓴다 — 어디까지가 그 차수인지를 들여쓰기가 말한다. 휴대폰에서는 걷는다. */
.pm-peek__turn-body {
  padding-left: 1.1rem;
}

/* 머리줄이 없는 판(한 번만 돈 건)에서는 들여쓰지 않는다. :only-child 로 가리지 않는다 — 남긴 말이 형제로 함께 서기 때문이다. */
.pm-peek__turn--solo > .pm-peek__turn-body {
  padding-left: 0;
}

/* 묶음의 첫 칸 이름은 위 여백이 필요 없다. 머리줄이 띄워 준다. */
.pm-peek__turn-body > .pm-peek__head:first-child {
  margin-top: 0.2rem;
}

.pm-peek__turn--solo > .pm-peek__turn-body > .pm-peek__head:first-child {
  margin-top: 0;
}

/* 앞에 덧댄 글 보기. 본문이 아니라 각주라 글상자 바로 아래에 작게 둔다. */
.pm-peek__lead-btn {
  margin: 0 0 0.5rem;
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
}

/* 덧댄 글은 사람이 적은 글과 생김새를 달리한다(점선 테두리, 한 치수 작게). 기계가 지은 글이라 읽는 글이 아니라 대조하는 글이다. */
.pm-peek__pre--lead {
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
  background: var(--jsini-surface);
  border-style: dashed;
}

/* 좁은 화면에서는 들여쓰기를 걷는다 — 글상자가 그만큼 좁아지는 손해가 줄마다 쌓인다. 머리줄 화살표가 묶음의 시작을 말해 준다. */
@media (max-width: 767px) {
  .pm-peek__turn-body {
    padding-left: 0;
  }

  /* 머리줄의 제목은 제 줄로 내린다 — 휴대폰 폭에서 제목에 열 글자도 안 남으면 차수 가르기가 잘린다. 시각은 첫 줄 오른쪽 끝에 남아야 차수끼리 견줘진다. */
  .pm-peek__turn-btn {
    flex-wrap: wrap;
  }

  .pm-peek__turn-title {
    order: 1;
    flex: 1 1 100%;

    /* 화살표 너비와 사이만큼 들여 「1차」와 같은 세로줄에 세운다. */
    padding-left: 1.1rem;
  }
}

/* ── 처리 파일 (`pm-peek__chg`) ─────────────────────────────── */
/* 셋째 탭의 알맹이다. 요약처럼 왼쪽 선을 세우지 않는다 — 여기 적히는 것은 AI 가 고쳐 쓴 말이 아니라 git 이 센 사실이다. */

.pm-peek__chg {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin: 0 0 0.5rem;
  padding: 0;
}

.pm-peek__chg-row {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  min-width: 0;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--jsini-border, rgba(0, 0, 0, 0.12));
  border-radius: 4px;
  font-size: var(--jsini-fs-sm);
  line-height: 1.5;
  background: var(--jsini-surface);
}

/* 「외 N개」는 세어 둔 말이라 테두리를 빼고 흐리게 둔다. */
.pm-peek__chg-row--more {
  justify-content: center;
  border: 0;
  padding: 0.15rem 0;
  background: none;
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-xs);
}

/* 무엇을 당했나 — 색이 먼저 읽히고 글자가 확인한다. 너비를 고정해 경로의 시작점이 줄마다 어긋나지 않게 한다. */
.pm-peek__chg-mark {
  flex: 0 0 auto;
  min-width: 3.1rem;
  text-align: center;
  padding: 0.05rem 0.3rem;
  border-radius: 3px;
  font-size: var(--jsini-fs-2xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.pm-peek__chg-mark--add {
  color: var(--jsini-success, #2b8a3e);
  background: var(--jsini-success-soft, rgba(43, 138, 62, 0.12));
}

.pm-peek__chg-mark--mod {
  color: var(--jsini-accent, #0078d4);
  background: var(--jsini-accent-soft, rgba(0, 120, 212, 0.12));
}

.pm-peek__chg-mark--del {
  color: var(--jsini-danger, #c92a2a);
  background: var(--jsini-danger-soft, rgba(201, 42, 42, 0.12));
}

.pm-peek__chg-mark--move {
  color: var(--jsini-warning, #e8590c);
  background: var(--jsini-warning-soft, rgba(232, 89, 12, 0.12));
}

/* 「추정」 줄은 git 이 본 것이 아니라 AI 결과문에서 뽑은 것이다. 갈래 색을 쓰지 않고 회색 테두리 배지로 한 발 물러선다. 줄은 점선으로 「확인 안 된 것」을 말한다. */
.pm-peek__chg-mark--guess {
  color: var(--jsini-text-muted);
  background: none;
  border: 1px dashed var(--jsini-border, rgba(0, 0, 0, 0.25));
  font-weight: 600;
}

.pm-peek__chg-row--guess {
  border-style: dashed;
  background: none;
}

/* 경로는 자르지 않고 두 줄로 접는다. direction: rtl 로 앞을 접으면 양 끝의 / 와 ... 이 틀린 자리로 옮겨 붙는다(헤드리스로 확인). */
.pm-peek__chg-path {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.5;
}

/* 앞자리는 어디서 끊어도 된다 — 줄마다 되풀이되는 글자라 눈이 훑고 지나간다. */
.pm-peek__chg-dir {
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-xs);
  word-break: break-all;
}

/* 이름은 모자랄 때만 끊는다(anywhere). break-all 은 AiTaskFilesTab. / razor.cs 처럼 이름을 두 동강 낸다. */
.pm-peek__chg-name {
  font-weight: 600;
  color: var(--jsini-text);
  overflow-wrap: anywhere;
}

/* ── 경로를 재는 뿌리 (`pm-peek__chg-root`) ───────────────── */
/* 목록 맨 위에 한 번만 선다 — 줄마다 되풀이하면 뒷자리를 읽을 자리가 없어진다. */

.pm-peek__chg-root {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  margin: 0 0 0.4rem;
  min-width: 0;
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-muted);
}

.pm-peek__chg-root-label {
  flex: 0 0 auto;
  padding: 0.05rem 0.3rem;
  border: 1px solid var(--jsini-border, rgba(0, 0, 0, 0.12));
  border-radius: 3px;
  font-size: var(--jsini-fs-2xs);
  font-weight: 700;
  white-space: nowrap;
}

.pm-peek__chg-root-path {
  min-width: 0;
  word-break: break-all;
}

/* ── 그 파일이 없는 줄 (`--gone`) ───────────────────────────── */
/* 추정보다 강하게 틀린 것이다. 「그런 파일이 없다」는 사실을 지우지 않고 세워 둔다 — 그 어긋남이 목록보다 중요할 때가 있다. */

.pm-peek__chg-row--gone {
  border-style: dashed;
  border-color: var(--jsini-danger, #c92a2a);
  background: none;
}

.pm-peek__chg-row--gone .pm-peek__chg-dir,
.pm-peek__chg-row--gone .pm-peek__chg-name {
  color: var(--jsini-text-muted);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.pm-peek__chg-mark--gone {
  color: var(--jsini-danger, #c92a2a);
  background: none;
  border: 1px dashed var(--jsini-danger, rgba(201, 42, 42, 0.5));
  font-weight: 700;
}

.pm-peek__chg-warn {
  color: var(--jsini-danger, #c92a2a);
}

/* ── 처리 파일의 차수 묶음 (`pm-peek__chg-turn`) ─────────────── */
/* 「지시와 결과」 묶음과 같은 모양으로 가른다. 접지 않는다 — 한 줄에 파일 하나라 접으면 차수 수만큼 더 눌러야 한다. */

.pm-peek__chg-turn + .pm-peek__chg-turn {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--jsini-border);
}

/* 「2차 · 3개」 — 번호와 개수만 적는다. 상태·시각은 옆 탭 머리줄이 이미 말한다. */
.pm-peek__chg-turn-head {
  margin: 0 0 0.35rem;
  font-size: var(--jsini-fs-sm);
  font-weight: 600;
  color: var(--jsini-text);
}

/* 가지 · 몇 줄은 묶음 바로 아래에 붙인다 — 목록 전체의 설명과 섞이면 어느 차수 값인지 사라진다. */
.pm-peek__chg-turn-hint {
  margin-bottom: 0;
}

/* ── 휴대폰 상세 ─────────────────────────────────────────────── */
/* 휴대폰에서 상세가 판 안의 탭으로 서므로 창을 펼치는 규칙은 없다. 결과문은 상한 없이 판이 통째로 구른다. */
/* ── 일정표: 구글 캘린더 (`pm-gc-*`) ─────────────────────────── */
/* 휴대폰 판정은 화면이 한다(DxLayoutBreakpoint → _isPhone). 여기서 폭으로 또 가르면 두 곳이 어긋나 아무 규칙도 안 걸린 격자가 뜬다. 왼쪽 기둥의 위 이동만 @media 로 둔다. */

.pm-gc {
  /* 구글의 파랑. 오늘 동그라미 · 고른 보기 · 끌어 놓을 자리가 이 색이다. */
  --pm-gc-accent: #1a73e8;

  display: flex;
  flex-direction: column;
}

:root[data-theme='dark'] .pm-gc,
:root[data-bs-theme='dark'] .pm-gc {
  /* 어두운 바탕에서 #1a73e8 은 글자를 못 읽게 한다 — 구글도 다크에서 올린다. */
  --pm-gc-accent: #8ab4f8;
}

/* ── 머리줄 ──────────────────────────────────────────────── */

.pm-gc__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--jsini-sp-sm);
  padding: var(--jsini-sp-sm) 0;
}

.pm-gc__today {
  height: 2.125rem;
  padding: 0 var(--jsini-sp-lg);
  font: inherit;
  color: var(--jsini-text);
  cursor: pointer;
  background: transparent;
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-full);
}

.pm-gc__today:hover {
  background: color-mix(in srgb, var(--jsini-text) 6%, transparent);
}

.pm-gc__arrows {
  display: flex;
  gap: var(--jsini-sp-3xs);
}

.pm-gc__arrow,
.pm-gc-mini__nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--jsini-text-muted);
  cursor: pointer;
  background: transparent;
  border: 0;
  border-radius: var(--jsini-radius-full);
}

.pm-gc__arrow {
  width: 2rem;
  height: 2rem;
}

.pm-gc__arrow:hover,
.pm-gc-mini__nav:hover {
  background: color-mix(in srgb, var(--jsini-text) 8%, transparent);
}

/* 꺾쇠는 아래를 보는 것 하나뿐이다 — 돌려서 좌우로 쓴다(`app.css` 머리말). */
.pm-gc__chev--prev { transform: rotate(90deg); }
.pm-gc__chev--next { transform: rotate(-90deg); }

.pm-gc__title {
  margin: 0;
  font-size: var(--jsini-fs-2xl);

  /* 구글의 제목은 굵지 않다. 굵게 하면 그 옆 단추들이 다 눌려 보인다. */
  font-weight: 400;
  white-space: nowrap;
}

.pm-gc__views {
  display: flex;
  margin-left: auto;
  overflow: hidden;
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-full);
}

.pm-gc__view {
  height: 2rem;
  padding: 0 var(--jsini-sp-md);
  font: inherit;
  color: var(--jsini-text);
  white-space: nowrap;
  cursor: pointer;
  background: transparent;
  border: 0;
}

.pm-gc__view:hover {
  background: color-mix(in srgb, var(--jsini-text) 6%, transparent);
}

.pm-gc__view--on {
  font-weight: 600;
  color: var(--pm-gc-accent);
  background: color-mix(in srgb, var(--pm-gc-accent) 14%, transparent);
}

.pm-gc__add-btn {
  height: 2rem;
  padding: 0 var(--jsini-sp-md);
  white-space: nowrap;
}

/* 일정 메일 발송. 단추는 「추가」와 같은 높이로 선다. */
.pm-gc__mail-btn {
  height: 2rem;
  padding: 0 var(--jsini-sp-md);
  white-space: nowrap;
}

/* 미리보기는 메일 본문을 그대로 iframe 에 깐다 — 포털 CSS 가 섞이면 받는 쪽과 다르게 보인다. */
.pm-mail-preview {
  margin-top: var(--jsini-sp-md);
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md, 6px);
  overflow: hidden;
}

.pm-mail-preview__head {
  padding: var(--jsini-sp-xs, 4px) var(--jsini-sp-md);
  font-size: var(--jsini-fs-sm);
  color: var(--jsini-text-muted, #6b7785);
  border-bottom: 1px solid var(--jsini-border);
}

.pm-mail-preview__frame {
  display: block;
  width: 100%;
  height: 52vh;
  border: 0;
  background: #f3f5f8;
}

/* 주소 칸 옆의 「사람 찾기」. DevExpress 편집기는 min-width: 0 이 없으면 안 좁아지고 단추를 다음 줄로 민다. */
.pm-mail-addr {
  display: flex;
  align-items: center;
  gap: var(--jsini-sp-sm, 8px);
  width: 100%;
}

.pm-mail-addr > .dxbl-text-edit {
  flex: 1 1 auto;
  min-width: 0;
}

.pm-mail-addr > .dxbl-btn {
  flex: 0 0 auto;
}

.pm-mail-pick {
  display: flex;
  flex-direction: column;
  gap: var(--jsini-sp-sm, 8px);
}

.pm-mail-pick .commgrd {
  height: min(26rem, 55vh);
}

/* 조회 중 실선. 자리를 늘 차지하고 색만 켜진다 — 나타났다 사라지면 아래가 들썩인다. */
.pm-gc__busy {
  position: relative;
  height: 2px;
  overflow: hidden;
}

.pm-gc__busy--on {
  background: color-mix(in srgb, var(--pm-gc-accent) 22%, transparent);
}

.pm-gc__busy--on::after {
  position: absolute;
  inset: 0;
  width: 35%;
  content: '';
  background: var(--pm-gc-accent);
  animation: pm-gc-slide 1.1s linear infinite;
}

@keyframes pm-gc-slide {
  from { transform: translateX(-100%); }
  to { transform: translateX(320%); }
}

/* ── 몸통과 왼쪽 기둥 ────────────────────────────────────── */

.pm-gc__body {
  display: flex;
  align-items: flex-start;
  gap: var(--jsini-sp-lg);
}

.pm-gc__rail {
  flex: 0 0 16rem;
  width: 16rem;
}

.pm-gc__main {
  flex: 1 1 auto;
  min-width: 0;
  outline: none;
}

/* 단축키를 받으려면 촛점이 여기 있어야 한다 — 어디에 있는지 보여 준다. */
.pm-gc__main:focus-visible {
  border-radius: var(--jsini-radius-md);
  outline: 2px solid var(--pm-gc-accent);
  outline-offset: 2px;
}

/* 넓은 화면에서는 기둥을 늘 펴 둔다 — 여는 단추를 숨긴다. 달력이 세로로 남는 공간을 모두 활용하도록 화면을 채운다. */
@media (min-width: 768px) {
  .jsini-shell__content:has(> .pm-gc) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .pm-gc {
    flex: 1 1 auto;
    min-height: 0;
  }

  .pm-gc__body {
    flex: 1 1 auto;
    min-height: 0;
    align-items: stretch;
  }

  .pm-gc__rail {
    overflow-y: auto;
    max-height: 100%;
  }

  .pm-gc__main {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }

  .pm-gc-month {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    height: 100%;
    min-height: 0;
    overflow-y: auto;
  }

  .pm-gc-month__dow {
    flex: 0 0 auto;
  }

  .pm-gc-week {
    flex: 1 1 0;
  }

  .pm-gc__main .pm-sched {
    flex: 1 1 auto;
    height: 100%;
    min-height: 0;
  }

  /* 표 보기의 쓸기 받개. 높이를 표에 그대로 넘긴다. */
  .pm-gc__main > .pm-gc-swipe,
  .pm-gc__main > .pm-gc-swipe > .commcont {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .pm-gc__main > .pm-gc-swipe > .commcont > .commcont__body {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .pm-gc__main > .pm-gc-agenda {
    flex: 1 1 auto;
    height: 100%;
    min-height: 0;
    overflow-y: auto;
  }

  .pm-gc__rail > .pm-gc__rail-body {
    display: block !important;
  }

  .pm-gc__rail-summary {
    display: none;
  }

  /* 조건 판을 세로로 세운다. 판의 기본 모양(조건 옆에 단추)대로 두면 기둥 안에서 단추가 폭을 먼저 가져가 칸이 82px 로 눌린다. */
  .pm-gc .pm-gc__rail .commsch {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: var(--jsini-sp-md);
    padding: var(--jsini-sp-md);
  }

  .pm-gc .pm-gc__rail .commsch__fields {
    flex: none;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: var(--jsini-sp-md);
  }

  .pm-gc .pm-gc__rail .commsch__item {
    align-items: stretch;
  }

  .pm-gc .pm-gc__rail .commsch__item > :last-child {
    width: 100% !important;
    min-width: 0;
  }

  .pm-gc .pm-gc__rail .commsch__actions,
  .pm-gc .pm-gc__rail .commsch__run {
    align-self: stretch;
    margin-left: 0;
  }

  .pm-gc .pm-gc__rail .commsch__run,
  .pm-gc .pm-gc__rail .commsch__run .dxbl-btn {
    flex: 1 1 auto;
  }
}

@media (max-width: 767px) {
  /* align-items 를 같이 되돌린다 — 세로로 서면 flex-start 가 「내용만큼만 넓힌다」가 되어 달력 판이 폭을 못 받고 월 격자가 글자 하나 너비로 오그라든다. */
  .pm-gc__body {
    flex-direction: column;
    align-items: stretch;
  }

  .pm-gc__rail {
    flex: none;
    width: 100%;
    margin-bottom: var(--jsini-sp-sm);
    background: var(--jsini-surface-raised, var(--jsini-surface));
    border: 1px solid var(--jsini-border);
    border-radius: var(--jsini-radius-lg);
    box-shadow: var(--jsini-shadow-card, var(--jsini-shadow-sm));
  }

  /* 기본 삼각형을 지운다. list-style 만으로는 웹킷에서 안 지워져 가짜 요소까지 끈다. */
  .pm-gc__rail-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.85rem;
    font-weight: 600;
    list-style: none;
    cursor: pointer;
  }

  .pm-gc__rail-summary::-webkit-details-marker {
    display: none;
  }

  .pm-gc__rail-chevron {
    transition: transform 0.2s;
  }

  .pm-gc__rail[open] .pm-gc__rail-chevron {
    transform: rotate(180deg);
  }

  .pm-gc__rail-body {
    padding: 0 0.85rem 0.85rem;
  }

  /* 조건줄이 자기 테두리를 또 그리면 상자가 둘로 보인다. */
  .pm-gc__rail .commsch {
    padding-top: 0;
    margin-bottom: 0;
    border: none;
    box-shadow: none;
  }

  .pm-gc__title {
    font-size: var(--jsini-fs-xl);
  }

  .pm-gc__add-btn {
    margin-left: auto;
  }

  /* 메일발송이 앞에 서면 오른쪽으로 미는 일은 그쪽이 맡는다. */
  .pm-gc__mail-btn {
    margin-left: auto;
  }

  .pm-gc__mail-btn ~ .pm-gc__add-btn {
    margin-left: 0;
  }

  /* 보기 고르개는 제목 아래 한 줄을 통째로 갖는다 — 제목 옆에 끼면 둘 다 잘린다. */
  .pm-gc__views {
    order: 10;
    width: 100%;
    margin-left: 0;
    justify-content: space-between;
  }

  .pm-gc__view {
    flex: 1;
    padding: 0 var(--jsini-sp-sm);
  }
}

/* 구글의 「만들기」. 이 화면에서 가장 자주 누르는 단추라 기둥 맨 위에 둔다. */
.pm-gc__create {
  display: inline-flex;
  gap: var(--jsini-sp-sm);
  align-items: center;
  height: 2.5rem;
  padding: 0 var(--jsini-sp-xl);
  margin-bottom: var(--jsini-sp-lg);
  font: inherit;
  font-weight: 600;
  color: var(--jsini-text);
  cursor: pointer;
  background: var(--jsini-surface-raised, var(--jsini-surface));
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-full);
  box-shadow: var(--jsini-shadow-sm);
}

.pm-gc__create:hover {
  box-shadow: var(--jsini-shadow-md);
}

/* 색이 무엇을 뜻하는지 적어 둔 줄. */
.pm-gc__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--jsini-sp-xs) var(--jsini-sp-md);
  padding: 0;
  margin: var(--jsini-sp-md) 0 0;
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-muted);
  list-style: none;
}

.pm-gc__legend li {
  display: flex;
  gap: var(--jsini-sp-2xs);
  align-items: center;
}

.pm-gc__dot {
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--jsini-radius-full);
}

/* 상태 넷의 색. 화면(StateLabels)과 같은 값이어야 한다 — 주·일 보기는 부품이, 월 보기는 여기가 칠한다. */
.pm-gc__dot--READY,
.pm-gc-bar--READY { background: #f9ab00; }

.pm-gc__dot--RUNNING,
.pm-gc-bar--RUNNING { background: #1a73e8; }

.pm-gc__dot--OVER,
.pm-gc-bar--OVER { background: #d93025; }

.pm-gc__dot--COMP,
.pm-gc-bar--COMP { background: #80868b; }

/* 일요일 빨강 · 토요일 파랑. 요일 머리와 날짜 숫자가 함께 쓴다. */
.pm-gc__sun { color: #d93025; }
.pm-gc__sat { color: #1a73e8; }

/* ── 작은 달력 ───────────────────────────────────────────── */

.pm-gc-mini {
  margin-bottom: var(--jsini-sp-lg);
}

.pm-gc-mini__head {
  display: flex;
  gap: var(--jsini-sp-3xs);
  align-items: center;
  margin-bottom: var(--jsini-sp-2xs);
}

.pm-gc-mini__title {
  flex: 1;
  font-size: var(--jsini-fs-sm);
  font-weight: 600;
}

.pm-gc-mini__nav {
  width: 1.5rem;
  height: 1.5rem;
}

.pm-gc-mini__dow,
.pm-gc-mini__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.pm-gc-mini__dow > span {
  padding: var(--jsini-sp-3xs) 0;
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
  text-align: center;
}

.pm-gc-mini__day {
  aspect-ratio: 1;
  min-height: 2.125rem;
  padding: 2px 0 1px;
  font: inherit;
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text);
  cursor: pointer;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--jsini-radius-sm);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  position: relative;
  transition: background-color 0.15s, border-color 0.15s;
}

.pm-gc-mini__day-num {
  font-size: var(--jsini-fs-2xs);
  line-height: 1.1;
}

.pm-gc-mini__count-slot {
  height: 0.875rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pm-gc-mini__count {
  font-size: 0.58rem;
  line-height: 1;
  font-weight: 700;
  color: #fff;
  background: var(--pm-gc-accent);
  border-radius: var(--jsini-radius-full);
  min-width: 0.875rem;
  height: 0.875rem;
  padding: 0 2px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.pm-gc-mini__day:hover {
  background: color-mix(in srgb, var(--jsini-text) 10%, transparent);
}

.pm-gc-mini__day--out {
  color: var(--jsini-text-muted);
  opacity: 0.55;
}

/* 큰 달력이 지금 어디를 보고 있나. 옅게 깔아 둔다. */
.pm-gc-mini__day--in {
  background: color-mix(in srgb, var(--pm-gc-accent) 14%, transparent);
}

/* 일정이 있는 날 — 굵기, 은은한 배경과 테두리로 구분 */
.pm-gc-mini__day--has-events {
  font-weight: 600;
}

.pm-gc-mini__day--has-events:not(.pm-gc-mini__day--today):not(.pm-gc-mini__day--in) {
  background: color-mix(in srgb, var(--pm-gc-accent) 6%, transparent);
  border-color: color-mix(in srgb, var(--pm-gc-accent) 20%, transparent);
}

.pm-gc-mini__day--in.pm-gc-mini__day--has-events:not(.pm-gc-mini__day--today) {
  border-color: color-mix(in srgb, var(--pm-gc-accent) 35%, transparent);
}

/* 오늘이 맨 뒤다 — 보고 있는 구간 안의 오늘도 색상이 이겨야 한다. */
.pm-gc-mini__day--today {
  font-weight: 700;
  color: #fff;
  background: var(--pm-gc-accent);
  border-color: var(--pm-gc-accent);
}

.pm-gc-mini__day--today:hover {
  background: color-mix(in srgb, var(--pm-gc-accent) 85%, #000);
}

/* 오늘 날짜 안에 일정이 있을 때 카운트 뱃지 색 반전 */
.pm-gc-mini__day--today .pm-gc-mini__count {
  color: var(--pm-gc-accent);
  background: #fff;
}

/* 작은 달력에서 선택된 날 및 범위 */
.pm-gc-mini__day--selected:not(.pm-gc-mini__day--today) {
  font-weight: 700;
  color: #fff;
  background: var(--pm-gc-accent);
  border-color: var(--pm-gc-accent);
}

.pm-gc-mini__day--selected:not(.pm-gc-mini__day--today):hover {
  background: color-mix(in srgb, var(--pm-gc-accent) 85%, #000);
}

.pm-gc-mini__day--selected:not(.pm-gc-mini__day--today) .pm-gc-mini__count {
  color: var(--pm-gc-accent);
  background: #fff;
}

.pm-gc-mini__day--today.pm-gc-mini__day--selected {
  outline: 2px solid var(--pm-gc-accent);
  outline-offset: 1px;
}

.pm-gc-mini__day--range-mid:not(.pm-gc-mini__day--today):not(.pm-gc-mini__day--selected) {
  background: color-mix(in srgb, var(--pm-gc-accent) 18%, transparent);
}

/* ── 월 격자 ─────────────────────────────────────────────────── */
/* 칸 높이는 막대 줄 수와 한 몸이다 — 화면의 MaxLanes 를 고치면 여기 --pm-gc-cell 도 고친다. */

.pm-gc-month {
  --pm-gc-num: 1.625rem;
  --pm-gc-bar: 1.25rem;
  --pm-gc-gap: 2px;
  --pm-gc-cell: 7.25rem;

  overflow: hidden;
  background: var(--jsini-surface-raised, var(--jsini-surface));
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-lg);

  /* 세로 쓸기는 브라우저에 맡긴다 — 가로만 우리가 본다. */
  touch-action: pan-y;
}

.pm-gc-month--phone {
  --pm-gc-num: 1.375rem;
  --pm-gc-bar: 1rem;
  --pm-gc-cell: 5rem;
}

.pm-gc-month__dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.pm-gc-month__dow-cell {
  padding: var(--jsini-sp-xs) 0;
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
  text-align: center;
  letter-spacing: 0.06em;
}

.pm-gc-week {
  position: relative;
  min-height: var(--pm-gc-cell);
}

.pm-gc-week__days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  height: 100%;
  min-height: var(--pm-gc-cell);
}

.pm-gc-day {
  position: relative;
  min-width: 0;
  border-top: 1px solid var(--jsini-border);
  border-left: 1px solid var(--jsini-border);
}

.pm-gc-day:first-child {
  border-left: 0;
}

/* 이 달이 아닌 자투리 날. 지우지 않고 흐리게 둔다 — 달을 넘나드는 일이 이어져 보여야 한다. */
.pm-gc-day--out {
  background: color-mix(in srgb, var(--jsini-text) 4%, transparent);
}

/* 끌어 옮길 때 놓일 칸. 강조는 gc-month-drag.js 가 data 속성으로 단다 — Blazor 가 class 를 갈아 치워도 남는다. */
.pm-gc-day[data-drop] {
  background: color-mix(in srgb, var(--pm-gc-accent) 16%, transparent);
  box-shadow: inset 0 0 0 2px var(--pm-gc-accent);
}

/* 고른 날의 테두리. 안쪽에 그려야 칸 크기가 안 흔들린다. */
.pm-gc-day--on::after {
  position: absolute;
  inset: 0;
  pointer-events: none;
  content: '';
  border: 2px solid var(--pm-gc-accent);
}

/* 칸의 빈 자리 전체가 단추다 — 구글에서 빈 곳을 누르면 새 일정이 열린다. */
.pm-gc-day__fill {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  cursor: pointer;
  background: transparent;
  border: 0;
}

.pm-gc-day__fill:hover {
  background: color-mix(in srgb, var(--jsini-text) 5%, transparent);
}

/* 날짜 숫자는 오른쪽 상단에 작고 얇게 표시한다. 오늘은 동그라미로 도드라지게 한다. */
.pm-gc-day__num {
  position: relative;
  z-index: 1;
  display: block;
  width: calc(var(--pm-gc-num) - 0.25rem);
  height: calc(var(--pm-gc-num) - 0.25rem);
  padding: 0;
  margin: var(--jsini-sp-3xs) var(--jsini-sp-2xs) 0 auto;
  font: inherit;
  font-size: var(--jsini-fs-2xs);
  font-weight: 300;
  line-height: calc(var(--pm-gc-num) - 0.25rem);
  color: var(--jsini-text);
  text-align: center;
  cursor: pointer;
  background: transparent;
  border: 0;
  border-radius: var(--jsini-radius-full);
}

.pm-gc-day__num:hover {
  background: color-mix(in srgb, var(--jsini-text) 10%, transparent);
}

.pm-gc-day--sun .pm-gc-day__num { color: #d93025; }
.pm-gc-day--sat .pm-gc-day__num { color: #1a73e8; }
.pm-gc-day--out .pm-gc-day__num { opacity: 0.5; }

/* 오늘은 파란 동그라미. 구글에서 한 화면에 딱 하나뿐인 표시다. */
.pm-gc-day--today .pm-gc-day__num {
  font-weight: 600;
  color: #fff;
  background: var(--pm-gc-accent);
}

/* 막대판은 칸 위에 얹혀 칸 경계를 가로지른다(여러 날 일을 한 줄로 잇는 장치). 판은 눌리지 않고 막대만 눌린다 — 아니면 칸의 빈 자리를 덮어 새 일정을 못 연다. */
.pm-gc-week__bars {
  position: absolute;
  top: var(--pm-gc-num);
  right: 0;
  bottom: 2px;
  left: 0;
  display: grid;
  grid-auto-rows: var(--pm-gc-bar);
  grid-template-columns: repeat(7, 1fr);
  gap: var(--pm-gc-gap) 0;
  overflow: hidden;
  pointer-events: none;
}

.pm-gc-week__bars > * {
  pointer-events: auto;
}

.pm-gc-bar {
  min-width: 0;
  padding: 0 var(--jsini-sp-xs);
  margin: 0 2px;
  overflow: hidden;
  font: inherit;
  font-size: var(--jsini-fs-2xs);
  line-height: var(--pm-gc-bar);
  color: #fff;
  text-align: left;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  border: 0;
  border-radius: var(--jsini-radius-sm);
}

.pm-gc-bar:disabled {
  cursor: default;
}

.pm-gc-bar[data-dragging] {
  opacity: 0.45;
}

/* 노랑 위의 흰 글자는 안 읽힌다 — 이 하나만 글자색을 뒤집는다. */
.pm-gc-bar--READY {
  color: #3c2f00;
}

/* 주를 넘어가는 쪽은 모서리를 편다 — 잘린 끝이 둥글면 거기서 끝난 일로 보인다. */
.pm-gc-bar--clip-s {
  margin-left: 0;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.pm-gc-bar--clip-e {
  margin-right: 0;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.pm-gc-week__more {
  min-width: 0;
  padding: 0 var(--jsini-sp-sm);
  overflow: hidden;
  font: inherit;
  font-size: var(--jsini-fs-2xs);
  line-height: var(--pm-gc-bar);
  color: var(--jsini-text-muted);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  background: transparent;
  border: 0;
}

.pm-gc-week__more:hover {
  text-decoration: underline;
}

/* 휴대폰 한 칸은 50px 언저리라 좌우 여백이 막대의 글자를 먹는다. 글은 +N 으로 줄여 가운데에 놓는다. */
.pm-gc-month--phone .pm-gc-bar {
  padding: 0 3px;
}

.pm-gc-month--phone .pm-gc-week__more {
  padding: 0 2px;
  text-align: center;
}

/* 휴대폰은 막대·「+N」이 누름을 받지 않는다 — 아래 칸이 받아야 여러 날 막대의 어느 날을 눌렀는지 그대로 골라진다. */
.pm-gc-month--phone .pm-gc-week__bars > * {
  pointer-events: none;
}

/* ── 오른쪽 기둥: 월 격자에서 고른 날 ─────────────────────── */

.pm-gc__day {
  flex: 0 0 18rem;
  width: 18rem;
  min-width: 0;
  padding: var(--jsini-sp-md);
  background: var(--jsini-surface-raised, var(--jsini-surface));
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-lg);
}

.pm-gc__day-tools {
  display: flex;
  gap: var(--jsini-sp-xs, 0.25rem);
  align-items: center;
}

.pm-gc__day-close {
  width: 2rem;
  height: 2rem;
  padding: 0;
  font-size: var(--jsini-fs-lg, 1.125rem);
  line-height: 1;
  color: var(--jsini-text-muted);
  background: none;
  border: 0;
  border-radius: var(--jsini-radius-md);
  cursor: pointer;
}

.pm-gc__day-close:hover {
  background: var(--jsini-hover, rgba(0, 0, 0, 0.05));
}

/* 넓은 화면에서는 달력 옆 기둥으로 서서 제 안에서만 구른다. */
@media (min-width: 768px) {
  .pm-gc__day {
    overflow-y: auto;
    max-height: 100%;
  }
}

/* 태블릿 폭에서는 세 기둥이 달력 몫을 다 먹지 않게 좁힌다. */
@media (min-width: 768px) and (max-width: 1199px) {
  .pm-gc__day {
    flex-basis: 14rem;
    width: 14rem;
  }
}

/* 좁은 화면에서는 달력 아래로 내려선다. */
@media (max-width: 767px) {
  .pm-gc__day {
    flex: none;
    width: 100%;
  }
}

/* ── 일정 목록 ───────────────────────────────────────────────── */
/* 세 자리(일정 보기 · 휴대폰 격자 아래 · 월 보기 오른쪽 기둥)가 같은 줄을 쓴다. */

.pm-gc-agenda--under {
  margin-top: var(--jsini-sp-lg);
}

.pm-gc-agenda__head {
  display: flex;
  gap: var(--jsini-sp-sm);
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--jsini-sp-sm);
}

.pm-gc-agenda__title {
  font-weight: 600;
}

.pm-gc-agenda__empty {
  padding: var(--jsini-sp-xl);
  margin: 0;
  color: var(--jsini-text-muted);
  text-align: center;
}

.pm-gc-agenda__day {
  display: flex;
  gap: var(--jsini-sp-md);
  padding: var(--jsini-sp-sm) 0;
  border-top: 1px solid var(--jsini-border);
}

.pm-gc-agenda__date {
  flex: 0 0 3.5rem;
  text-align: center;
}

.pm-gc-agenda__dnum {
  display: block;
  font-size: var(--jsini-fs-xl);
  line-height: 1.2;
}

.pm-gc-agenda__day--today .pm-gc-agenda__dnum {
  font-weight: 700;
  color: var(--pm-gc-accent);
}

.pm-gc-agenda__dow,
.pm-gc-agenda__month {
  display: block;
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
}

.pm-gc-agenda__items {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--jsini-sp-2xs);
  min-width: 0;
  padding: 0;
  margin: 0;
  list-style: none;
}

.pm-gc-agenda__item {
  min-width: 0;
}

/* 고칠 수 없는 사람에게도 줄은 보인다 — 누르는 것만 막는다(disabled). */
.pm-gc-agenda__btn {
  display: block;
  width: 100%;
  padding: var(--jsini-sp-sm) var(--jsini-sp-md);
  font: inherit;
  color: var(--jsini-text);
  text-align: left;
  cursor: pointer;
  background: var(--jsini-surface-raised, var(--jsini-surface));
  border: 1px solid var(--jsini-border);
  border-left: 4px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md);
}

.pm-gc-agenda__btn:disabled {
  cursor: default;
}

.pm-gc-agenda__item--READY .pm-gc-agenda__btn { border-left-color: #f9ab00; }
.pm-gc-agenda__item--RUNNING .pm-gc-agenda__btn { border-left-color: #1a73e8; }
.pm-gc-agenda__item--OVER .pm-gc-agenda__btn { border-left-color: #d93025; }
.pm-gc-agenda__item--COMP .pm-gc-agenda__btn { border-left-color: #80868b; }

.pm-gc-agenda__top {
  display: flex;
  gap: var(--jsini-sp-sm);
  align-items: center;
  justify-content: space-between;
}

.pm-gc-agenda__name {
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pm-gc-agenda__sub {
  display: block;
  margin-top: var(--jsini-sp-3xs);
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-muted);
}

/* 묻는 창의 AI 고르개는 한 줄이다 — 한도는 고르개 칸 안에 있고 라벨은 두지 않는다(화면에 AI 이름이 이미 있다). */
.pm-peek__field {
  display: flex;
  gap: var(--jsini-sp-sm);
  align-items: center;
  margin-top: var(--jsini-sp-sm);
}

/* 상세 보기의 항목 이름. 묻는 창에서는 라벨을 쓰지 않는다 — 고르개에 AI 이름이 이미 있다. */
.pm-peek__label {
  flex: 0 0 auto;
  font-size: var(--jsini-fs-sm);
  color: var(--jsini-text-muted);
}

.pm-peek__kind {
  flex: 1 1 auto;
  min-width: 0;
}

/* 지난 회차 자국. 「이번에 어디로 가나」(jsini-hint)와 갈라 인용 조각으로 둔다. 두 줄까지만 보이게 묶는다 — 실행기 글은 길이를 가늠할 수 없어 안 묶으면 단추 줄이 자판 밑으로 내려간다. */
.pm-peek__status {
  margin: var(--jsini-sp-2xs) 0 0;
  padding: var(--jsini-sp-2xs) var(--jsini-sp-xs);
  border-left: 2px solid var(--jsini-border);
  border-radius: 0 var(--jsini-radius-sm) var(--jsini-radius-sm) 0;
  background: var(--jsini-surface-muted);
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-muted);
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

/* 단추 글자는 휴대폰에서 짧은 쪽이 선다 — 긴 글이 넷이 서는 줄에서 혼자 한 줄을 먹는다. */
.pm-peek__btn-text--full { display: inline; }
.pm-peek__btn-text--short { display: none; }

@media (max-width: 767px) {
  .pm-peek__btn-text--full { display: none; }
  .pm-peek__btn-text--short { display: inline; }
}

/* ── AI 작업: 쪽이 통째로 구르지 않는다 (`pm-ai-page`) ───────── */
/* 데스크탑에서는 본문 높이 안에서 끝난다 — 구르는 것은 왼쪽 목록과 오른쪽 탭 안쪽뿐이다. calc 로 뺀 높이는 위에 줄이 늘면 아래가 잘려 맞는 순간이 없었다. 좁은 창은 쪽이 구른다. */

@media (width >= 62rem) {
  /* 본문을 세로 flex 로 바꾼다. 이 화면일 때만 건다 — 본문은 모든 화면이 함께 쓴다. */
  .jsini-shell__content:has(> .pm-ai-page) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .pm-ai-page {
    display: flex;
    flex: 1;

    /* 없으면 flex 자식이 내용만큼 부풀어 본문을 넘는다. */
    min-height: 0;
    flex-direction: column;
  }

  /* 조건줄은 제 높이만큼. .commsch 를 직접 겨눈다 — 안 그러면 조회판이 flex 기본값으로 늘어나 아래 두 판의 높이를 먹는다. */
  .pm-ai-page > .commsch,
  .pm-ai-page > .pm-ai-loading {
    flex: 0 0 auto;
  }

  /* 두 판이 남은 높이를 다 먹고 끝까지 같은 키로 선다 — align-items: start 를 풀어야 아래 끝이 맞는다. */
  .pm-ai-page > .pm-splitpane {
    flex: 1;
    min-height: 0;
    align-items: stretch;
  }


  /* 왼쪽 표는 판이 준 높이를 쓰고 줄만 안에서 구른다 — 칸 머리와 아래 띠는 제자리에 남는다. */

  /* 탭 위의 줄들은 줄어들지 않는다 — 모자라면 탭 안쪽이 줄어야 한다. */
  .pm-ai-detail-panel > .commcont__body > * {
    flex: 0 0 auto;
  }

  /* 오른쪽 탭이 남은 높이를 다 먹는다. */
  .pm-ai-detail-panel > .commcont__body > .pm-ai-tabs,
  .pm-ai-tabs {
    display: flex;
    flex: 1;
    min-height: 0;
    flex-direction: column;
  }

  /* DevExpress 의 상자 둘은 min-height: auto 라 안쪽보다 작아지지 않는다 — 로그가 길면 단추 줄이 판 밖으로 나간다(포털관리의 ad-roletabs 와 같은 자리). */
  .pm-ai-tabs > .dxbl-tabs-content-panel,
  .pm-ai-tabs .dxbl-tabs-content {
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }

  /* 탭 안쪽은 공용의 60vh 바닥을 끈다 — 남은 높이를 받는 자리에서는 그 바닥이 판을 밀어낸다. */
  .pm-ai-tabs .pm-tab-body {
    display: flex;
    height: 100%;
    min-height: 0;
    flex-direction: column;
  }

  /* 작성 탭: 설정과 단추 줄은 제 높이만큼, 편집기가 남은 자리를 다 먹는다. 새 줄을 넣을 때마다 여기 이름을 더한다 — 빠지면 그 줄이 편집기 몫을 가져간다. */
  .pm-ai-write > .pm-editform,
  .pm-ai-write > .pm-ai-editor__bar,
  .pm-ai-write > .pm-ai-opts {
    flex: 0 0 auto;
  }

  /* 편집기가 더 줄 수 없는 데까지 줄고도 남으면 구른다 — 잘라 내면 편집기와 저장 줄이 사라져 보인다(1600×1000 에서 확인). 들어가는 날에는 막대가 안 뜬다. */
  .pm-ai-tabs .pm-ai-write {
    overflow-y: auto;
  }

  .pm-ai-write > .pm-ai-editor {
    flex: 1;
    height: auto;
    min-height: 10rem;
  }

  /* ── 끼워 담은 공통 탭 ─────────────────────────────────────── */
  /* 탭 알맹이가 쪽이 구르는 화면의 판이라 높이가 없다 — 여기서 준다. 안 주면 overflow: hidden 이 긴 결과와 로그를 말없이 자른다. */
  .pm-ai-tabs .pm-peek__pane {
    height: 100%;
    min-height: 0;
    overflow-y: auto;
  }

  /* 아무것도 안 고른 자리. 22rem 을 깔아 두면 판보다 커질 수 있다. */
  .pm-ai-detail-panel .pm-ai-empty {
    flex: 1;
    min-height: 0;
  }
}

/* ── 탭 줄은 휴대폰에서 가로로 구르지 않는다 (`pm-tabfit`) ────────── */
/* 탭 이름이 숫자를 달아 넷이 360px 에 안 들어간다. 기본 Auto 는 탭을 감추고 쓸어 넘기게 하므로 함께 건다: NoScroll(모자라면 다음 줄로) · 틈은 column-gap(마지막 뒤 20px 제거) · 좌우 안쪽 여백 축소. */
/* 탭 알맹이가 제 칸보다 커서 NoScroll 이면 고른 탭의 파란 줄이 본문 위로 흘러내리므로 box-sizing 을 넓은 화면에도 건다. 선택자를 .dxbl-tabs 로 겹쳐 적는 것은 tabler.css 와 자릿수가 같으면 지기 때문이다. */
.dxbl-tabs.pm-tabfit .dxbl-tabs-item {
  box-sizing: border-box;
}

@media (max-width: 767px) {
  .dxbl-tabs.pm-tabfit {
    --dxbl-tabs-tab-padding-x: 0.125rem;
  }

  .dxbl-tabs.pm-tabfit .dxbl-tabs-tablist ul {
    column-gap: 0.625rem;
    row-gap: 0;
  }

  .dxbl-tabs.pm-tabfit .dxbl-tabs-item {
    margin-right: 0;
  }
}

/* ── AI 작업: 좁은 화면에서는 위아래로 쌓는다 ───────────────────── */
/* 상자만 지워(display: contents) 두 판이 쌓이고 쪽이 구른다. 마크업을 화면 크기마다 갈아 끼우면 편집 상태와 조회가 다시 만들어지므로 상자만 없앤다. */
@media (max-width: 62rem) {
  .pm-ai-page > .pm-splitpane,
  .pm-ai-page > .pm-splitpane > .pm-splitpane__ui,
  .pm-ai-page > .pm-splitpane > .pm-splitpane__ui > .dxbl-splitter-pane,
  .pm-ai-page > .pm-splitpane > .pm-splitpane__ui > .dxbl-splitter-pane > .dxbl-splitter-pane-content {
    display: contents !important;
  }

  .pm-ai-page > .pm-splitpane > .pm-splitpane__ui > .dxbl-splitter-separator {
    display: none !important;
  }

  .pm-ai-page .pm-splitpane__first,
  .pm-ai-page .pm-splitpane__second {
    display: block;
    overflow: visible;
    flex: none;
    padding: 0 !important;
  }

  .pm-ai-page .pm-splitpane__second {
    margin-top: var(--jsini-sp-lg);
  }

  .pm-ai-page .pm-splitpane .commcont {
    height: auto;
    min-height: 0;
  }
}

.pm-ai-page--phone > .pm-splitpane,
.pm-ai-page--phone > .pm-splitpane > .pm-splitpane__ui,
.pm-ai-page--phone > .pm-splitpane > .pm-splitpane__ui > .dxbl-splitter-pane,
.pm-ai-page--phone > .pm-splitpane > .pm-splitpane__ui > .dxbl-splitter-pane > .dxbl-splitter-pane-content {
  display: contents !important;
}

.pm-ai-page--phone > .pm-splitpane > .pm-splitpane__ui > .dxbl-splitter-separator {
  display: none !important;
}

.pm-ai-page--phone .pm-splitpane__first,
.pm-ai-page--phone .pm-splitpane__second {
  display: block;
  overflow: visible;
  flex: none;
  padding: 0 !important;
}

.pm-ai-page--phone .pm-splitpane__second {
  margin-top: var(--jsini-sp-lg);
}

.pm-ai-page--phone .pm-splitpane .commcont {
  height: auto;
  min-height: 0;
}

/* ── 탭으로 펼쳐 보는 지시 한 건 (`pm-taskview`) ───────────────── */
/* 쪽 페이지(AiTaskViewPage)의 머리줄과 단추 줄만 정한다 — 속은 창과 같은 부품이다. */

.pm-taskview {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

.pm-taskview > .commcont,
.pm-taskview > .commcont > .commcont__body {
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* 제목과 「다시 읽기」는 한 줄이다 — 줄을 갈라 쓰면 단추가 제목 위에 제 줄을 차지한다. */
.pm-taskview__head {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

/* 제목은 남는 폭을 다 쓰고 제 칸 안에서 줄바꿈한다 — 한 줄로 자르면 무엇을 시킨 건인지가 잘린다. */
.pm-taskview__title {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  font-size: var(--jsini-fs-lg);
  font-weight: 600;
  line-height: 1.4;
  word-break: break-word;
}

/* 「다시 읽기」는 제목이 여러 줄이 되어도 첫 줄 오른쪽 끝에 남는다. */
.pm-taskview__head .pm-taskview__reload {
  flex: 0 0 auto;
  height: calc(var(--jsini-fs-lg) * 1.4);
  padding-block: 0;
  margin-inline-start: auto;
  color: var(--jsini-text-muted);
}

.pm-taskview__reload:hover:not(:disabled) {
  color: var(--jsini-text);
}

/* 읽는 동안 돈다 — 단추가 꺼지기만 하면 누른 것이 먹었는지 안 갈린다. 아이콘 이름을 그대로 적는다: DxButton 이 그리는 칸은 class 순서가 달라 [class^=] 로 안 잡힌다. */
.pm-taskview__reload.is-busy .jsini-icon-refresh {
  animation: pm-taskview-spin 0.9s linear infinite;
}

@keyframes pm-taskview-spin {
  to { transform: rotate(360deg); }
}

/* 움직임을 줄여 달라고 한 사람에게는 돌리지 않는다 — 꺼진 단추로도 「읽는 중」은 전해진다. */
@media (prefers-reduced-motion: reduce) {
  .pm-taskview__reload.is-busy .jsini-icon-refresh {
    animation: none;
  }
}

/* 단추 줄은 바닥에 붙박여(sticky) 내용이 길어도 보인다. 휴대폰 빠른 지시의 상세도 같은 줄을 쓴다. 폭은 버튼만큼만 차지한다. */
.pm-taskview__acts,
.pm-ask__viewacts {
  position: sticky;
  bottom: 0;
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-self: flex-end;
  width: fit-content;
  max-width: 100%;
  gap: 0.5rem;
  margin-top: auto;
  margin-inline-start: auto;
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none;
}

@media (max-width: 767px) {
  /* 띠 몫은 본문이 이미 비워 둔다 — 여기서 또 피하면 두 번 센 셈이다. 떠다니는 단추가 올라설 거리는 --jsini-actbar-height 로 맞추고, 줄은 아래끝을 같은 토큰으로 받친다. 휴대폰에서는 줄을 내리지 않는다(nowrap). */
  .pm-taskview__acts,
  .pm-ask__viewacts {
    bottom: 0.5rem;
    margin-bottom: 0.5rem;
    min-height: auto;
    padding: 0;

    /* 오른쪽 모음은 justify-content 가 아니라 첫 단추의 왼쪽 여백이 한다 — flex-end 는 넘치면 시작 모서리 밖으로 밀려 영영 못 본다. */
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
  }

  /* 단추는 줄이지도 줄바꿈하지도 않는다 — 글자가 두 줄로 갈리면 줄 높이가 52px 을 넘어 떠다니는 단추의 거리가 틀린다. 넘치는 것은 overflow-x 로 민다. */
  .pm-taskview__acts > *,
  .pm-ask__viewacts > * {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .pm-taskview__acts > :first-child,
  .pm-ask__viewacts > :first-child {
    margin-inline-start: auto;
  }
}

/* ── AI 작업 현황 (AiDashboard.razor) ─────────────────────────── */
/* 읽는 차례를 자리로 고정한다: 지금 → 머리 숫자 → 전망 → 한도 → 추세 → 빈도 → 순위 → 최근 실행. 좁아지면 한 칸으로 접힌다. */

.pm-aidash {
  display: flex;
  flex-direction: column;
  gap: var(--jsini-sp-lg);
}

/* 「지금」 띠 — 기간을 타지 않는 값만 둔다. 화면이 그 사실을 말해야 지난달 조회에서 「실행 중 0건」을 오해하지 않는다. */
.pm-aidash__now {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--jsini-sp-xs) var(--jsini-sp-sm);
}

.pm-aidash__now-label {
  font-size: var(--jsini-fs-sm);
  font-weight: 600;
  color: var(--jsini-text-muted);
}

/* 「언제 기준인가」 — 숫자 옆의 작은 글자라 색을 죽인다. 숫자만큼 진하면 숫자가 안 보인다. */
.pm-aidash__stamp {
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
}

/* 갱신 시각 옆의 「얼마 남았나」는 절대 시각보다 먼저 읽히게 진하되, 퍼센트 숫자보다 작게 둔다 — 이 줄이 숫자만큼 진해지면 막대가 안 보인다. */
.pm-aidash__remain {
  color: var(--jsini-text);
  font-weight: 600;
}

.pm-aidash__remain::before {
  content: "·";
  margin: 0 0.25rem;
  color: var(--jsini-text-muted);
  font-weight: 400;
}

/* 타일 아래 한 줄 — 큰 숫자로 못 하는 말(중앙값 · 근거 · 내역)을 여기서 한다. */
.pm-aidash__sub {
  display: block;
  margin-top: var(--jsini-sp-2xs);
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
}

.pm-aidash__tiles .jsini-stat {
  align-items: flex-start;
}

/* 나란한 판. minmax(0, …) 가 요점이다 — 안 주면 차트가 내용만큼 넓어져 칸이 화면 밖으로 밀린다. */
.pm-aidash__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
  gap: var(--jsini-sp-lg);
  align-items: start;
}

.pm-aidash__panel {
  min-width: 0;
}

.pm-aidash__chart {
  min-width: 0;
}

/* ── 한도 계량기 ────────────────────────────────────────────── */
/* 차트가 아니라 계량기다 — 값이 하나뿐인 비율은 막대 하나가 가장 정확하다. */

.pm-aidash__meters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: var(--jsini-sp-md);
}

.pm-aidash__meter-card {
  display: flex;
  flex-direction: column;
  gap: var(--jsini-sp-xs);
  padding: var(--jsini-sp-md);
  background: var(--jsini-surface);
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md);
}

.pm-aidash__meter-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--jsini-sp-2xs) var(--jsini-sp-xs);
}

.pm-aidash__meter-label {
  display: flex;
  justify-content: space-between;
  gap: var(--jsini-sp-xs);
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-muted);
}

.pm-aidash__meter-track {
  height: 0.5rem;
  overflow: hidden;
  background: var(--jsini-bg);
  border-radius: var(--jsini-radius-full);
}

/* 끝쪽만 둥글다 — 양끝을 다 둥글리면 0 에 가까운 값이 실제보다 커 보인다. */
.pm-aidash__meter-fill {
  display: block;
  height: 100%;
  border-radius: 0 var(--jsini-radius-full) var(--jsini-radius-full) 0;
}

.pm-aidash__meter-error {
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-muted);
}

/* 로그인이 끊겼을 때는 흐리게 두지 않는다 — 사람이 장비에 붙어 풀어야 끝나는 고장이다. */
.pm-aidash__auth {
  padding: var(--jsini-sp-xs);
  border: 1px solid var(--jsini-danger, #d63939);
  border-radius: var(--jsini-radius-sm);
  background: color-mix(in srgb, var(--jsini-danger, #d63939) 10%, transparent);
  font-size: var(--jsini-fs-xs);
  line-height: 1.5;
}

.pm-aidash__auth > strong {
  color: var(--jsini-danger, #d63939);
}

.pm-aidash__auth code {
  padding: 0 var(--jsini-sp-3xs, 2px);
  border-radius: var(--jsini-radius-xs, 3px);
  background: var(--jsini-surface-2, rgba(0, 0, 0, 0.06));
}

.pm-aidash__tokens {
  font-size: var(--jsini-fs-sm);
}

/* CLI 출력 원문은 접어 둔다 — 형식이 바뀐 날에만 단서가 된다. */
.pm-aidash__raw > summary {
  font-size: var(--jsini-fs-2xs);
  color: var(--jsini-text-muted);
  cursor: pointer;
}

.pm-aidash__raw pre {
  max-height: 12rem;
  margin: var(--jsini-sp-2xs) 0 0;
  padding: var(--jsini-sp-xs);
  overflow: auto;
  font-size: var(--jsini-fs-2xs);
  white-space: pre-wrap;
  word-break: break-all;
  background: var(--jsini-bg);
  border-radius: var(--jsini-radius-md);
}

/* ── 순위 표 ──────────────────────────────────────────────────── */
/* 막대가 아니라 표다 — 이름이 길다. 이름 아래 얇은 막대로 순위를 먼저 읽게 한다. */

.pm-aidash__rank {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--jsini-fs-sm);
}

.pm-aidash__rank th,
.pm-aidash__rank td {
  padding: var(--jsini-sp-xs) var(--jsini-sp-2xs);
  text-align: left;
  border-bottom: 1px solid var(--jsini-border);
}

.pm-aidash__rank th {
  font-size: var(--jsini-fs-2xs);
  font-weight: 600;
  color: var(--jsini-text-muted);
}

/* 숫자 칸은 오른쪽으로 모으고 자릿수를 고정한다 — 아니면 큰 수와 작은 수를 비교할 수 없다. */
.pm-aidash__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.pm-aidash__rank td:first-child {
  position: relative;
  min-width: 8rem;
  padding-bottom: calc(var(--jsini-sp-xs) + 0.25rem);
}

/* 이름 아래 얇은 띠는 순위를 훑기 위한 것이라 색을 죽인다. 숫자를 대신하지 않는다. */
.pm-aidash__bar {
  position: absolute;
  left: var(--jsini-sp-2xs);
  bottom: 0.35rem;
  height: 0.2rem;
  max-width: calc(100% - var(--jsini-sp-sm));
  background: var(--jsini-accent);
  opacity: 0.35;
  border-radius: var(--jsini-radius-full);
}

@media (max-width: 767px) {
  /* 좁은 화면에서는 한 칸씩 쌓는다 — 차트를 둘씩 넣으면 가로축 글자가 겹친다. */
  .pm-aidash__row {
    grid-template-columns: 1fr;
  }
}

/* ── WBS 대시보드 (사내망에서 옮겨 온 화면) ───────────────────── */

/* 표 칸 안의 진행 막대. 숫자를 대신하지 않는다 — 여러 줄을 훑을 때만 쓴다. 칸 높이에 맞춰 눕혀 줄 높이가 늘지 않게 한다. */
.pm-bar {
  position: relative;
  height: 1.15rem;
  min-width: 6rem;
  background: var(--jsini-surface-2);
  border-radius: var(--jsini-radius-sm);
  overflow: hidden;
}

.pm-bar__fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--jsini-accent);
  opacity: 0.35;
}

/* 실적 막대만 색을 달리한다 — 계획과 같은 색이면 어느 쪽이 밀렸는지 안 보인다. */
.pm-bar--done .pm-bar__fill {
  background: var(--jsini-success, var(--jsini-accent));
  opacity: 0.45;
}

.pm-bar__text {
  position: relative;
  display: block;
  text-align: center;
  font-size: var(--jsini-fs-xs);
  font-variant-numeric: tabular-nums;
  line-height: 1.15rem;
}

/* 날짜가 들어간 요약 타일은 기간이 두 줄로 접히도록 글자를 줄인다. */
.pm-stat--dates {
  font-size: var(--jsini-fs-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ── 사람 × 기간 매트릭스 ──────────────────────────────────── */

/* 칸이 자료에 따라 정해져 표 부품을 못 쓴다. 기간이 늘어나므로 판만 가로로 구른다 — 쪽이 구르면 이름 칸이 밖으로 나간다. */
.pm-heat-wrap {
  overflow-x: auto;
  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md);
  background: var(--jsini-surface);
}

.pm-heat {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--jsini-fs-sm);
}

.pm-heat th,
.pm-heat td {
  border: 1px solid var(--jsini-border);
  padding: var(--jsini-sp-2xs) var(--jsini-sp-xs);
  text-align: center;
  white-space: nowrap;
}

.pm-heat thead th {
  background: var(--jsini-surface-2);
  font-weight: 600;
}

/* 이름 칸은 구르는 동안에도 붙어 있어야 누구 줄인지 안다. */
.pm-heat__name {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--jsini-surface);
  text-align: left;
  min-width: 8rem;
}

.pm-heat thead .pm-heat__name {
  background: var(--jsini-surface-2);
}

.pm-heat__cell {
  cursor: pointer;
  min-width: 3.5rem;
}

.pm-heat__cell.is-empty {
  cursor: default;
}

.pm-heat__cnt {
  display: block;
  font-variant-numeric: tabular-nums;
}

/* 완료 건수는 작게 둔다 — 같은 크기면 배정과 완료 중 어느 쪽인지 다시 생각하게 된다. */
.pm-heat__done {
  display: block;
  font-size: var(--jsini-fs-xs);
  opacity: 0.7;
  font-variant-numeric: tabular-nums;
}

.pm-heat__total {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  background: var(--jsini-surface-2);
}

/* 창 안의 구역 제목. 탭으로 나누면 안의 표가 탭 상자보다 커져 아래 단추가 밀려난다 — 그래서 세로로 쌓는다. */
.pm-section {
  margin: var(--jsini-sp-md) 0 var(--jsini-sp-xs);
  font-size: var(--jsini-fs-sm);
  font-weight: 600;
  color: var(--jsini-text-2);
}

/* 붙여넣는 칸은 줄바꿈을 두고 고정폭으로 본다 — 잘렸는지는 괄호 짝으로만 안다. */
.pm-paste textarea {
  font-family: var(--jsini-font-mono);
  font-size: var(--jsini-fs-xs);
  white-space: pre;
}

/* 공유 문서 본문. 담긴 것이 HTML 이라 그대로 그리고, 안쪽 여백만 준다. */
.pm-doc {
  padding: var(--jsini-sp-sm);
  line-height: 1.7;
  overflow-x: auto;
}

.pm-doc img {
  max-width: 100%;
}

.pm-doc-editor {
  min-height: 24rem;
}

/* 계정 발급 현황 열한 칸. 라벨을 칸마다 붙이면 창이 두 배로 길어져 자리표시 글이 라벨 노릇을 한다. */
.pm-account-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--jsini-sp-2xs);
}

/* ── Git 모니터링 (`pm-gitmon`) ─────────────────────────────── */
/* 판을 덩어리로 감싸 .commcont 규칙에 안 걸리게 한다 — 판이 일곱이 쌓이면 flex 로 나눠 가져 넘친 것을 굴려 볼 수 없다. 쪽이 구른다. */

.pm-gitmon {
  display: flex;
  flex-direction: column;
  gap: var(--jsini-sp-lg);
}

/* 판 사이 간격은 위 gap 이 정한다 — 공통 규칙과 겹치면 두 배가 된다. */
.pm-gitmon > .commcont + .commcont {
  margin-top: 0;
}

/* 깨진 단계 목록은 고정폭이다 — 같은 잡의 단계들이 눈에 묶인다. */
.pm-failsteps {
  margin: 0;
  padding-left: var(--jsini-sp-md);
  font-family: var(--jsini-font-mono);
  font-size: var(--jsini-fs-sm);
  line-height: 1.8;
}

/* 상세 모드의 제목 — 구역이 다섯이라 내려가면 어느 건을 고치는지 잊는다. */
.pm-detail-title {
  font-weight: 600;
  font-size: var(--jsini-fs-md);
  margin-left: var(--jsini-sp-xs);
}

/* ── 개발자 정보 — 목차와 문서 ────────────────────────────── */

/* 목차는 제목만 세운다 — 두 줄로 흐르면 쪽이 많을 때 목차가 본문만큼 길어진다. */
.pm-toc {
  display: flex;
  flex-direction: column;
  gap: var(--jsini-sp-3xs, 2px);
}

.pm-toc__item {
  display: block;
  width: 100%;
  padding: var(--jsini-sp-2xs) var(--jsini-sp-xs);
  border: 0;
  border-radius: var(--jsini-radius-sm);
  background: transparent;
  color: var(--jsini-text);
  font-size: var(--jsini-fs-sm);
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}

.pm-toc__item:hover {
  background: var(--jsini-surface-2);
}

/* 고른 쪽은 색만으로 가르지 않고 굵기도 준다. */
.pm-toc__item.is-on {
  background: var(--jsini-surface-2);
  color: var(--jsini-accent-text);
  font-weight: 600;
}

/* 문서 머리 줄 — 제목 · 고친 때 · 단추들이 한 줄에 앉는다. */
.pm-doc-head {
  display: flex;
  align-items: center;
  gap: var(--jsini-sp-xs);
  margin-bottom: var(--jsini-sp-sm);
}

.pm-doc-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: var(--jsini-fs-md);
  font-weight: 600;
}

.pm-doc-when {
  font-size: var(--jsini-fs-xs);
  color: var(--jsini-text-2);
  white-space: nowrap;
}

/* ── 대상 git 상태 ────────────────────────────────────────────── */
/* 기계가 만든 글자와 사람이 쓴 글자를 눈으로 가른다 — 같은 글꼴이면 커밋 제목과 가지 이름이 한 덩어리로 읽힌다. */
.pm-gitmono {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: var(--jsini-fs-xs);
}

/* 배지가 값 옆에 붙을 때의 사이. 붙여 두면 가지 이름의 일부로 읽힌다. */
.pm-git__tag {
  margin-left: 0.375rem;
}

/* 커밋 제목은 곁글이다. 한 줄로 붙잡지 않으면 표를 세로로 늘린다(pm-oneline 과 함께). */
.pm-git__subject {
  margin-left: 0.375rem;
  color: var(--jsini-text-muted);
}

/* 오래된 시각은 지운 것이 아니라 흐리게 둔다 — 값이 멈춘 것이 알아채기 어려워 색으로 말한다. */
.pm-git__stale {
  color: var(--jsini-text-muted);
  font-style: italic;
}

/* ── 「자세히」 판 ──────────────────────────────────────────── */
/* 이름과 값을 두 단으로 세운다. 좁아지면 위아래로 접는다 — 긴 값을 두 단으로 고집하면 값이 글자 서넛 폭이 된다. */
.pm-git {
  display: grid;
  grid-template-columns: 7rem 1fr;
  gap: 0.5rem 1rem;
  margin: 0;
  align-items: baseline;
}

.pm-git > dt {
  color: var(--jsini-text-muted);
  font-size: var(--jsini-fs-sm);
}

.pm-git > dd {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* 사람이 봐야 하는 줄. 배지가 아니라 줄로 둔다 — 한 줄짜리 설명이 배지에 안 담긴다. */
.pm-git__bad {
  color: #d32f2f;
}

/* 정리 안 된 파일 목록. git 이 찍은 것이라 고정폭이고, 스무 줄까지만 온다. */
.pm-git__files {
  margin: 0.5rem 0 0;
  padding: 0.5rem 0.75rem;
  max-height: 14rem;
  overflow: auto;
  background: var(--jsini-surface);
  border: 1px solid var(--jsini-border);
  border-radius: 4px;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: var(--jsini-fs-xs);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 767px) {
  .pm-git {
    grid-template-columns: 1fr;
    gap: 0.125rem;
  }

  /* 한 단이 되면 이름과 값이 붙어야 한 짝으로 읽힌다 — 짝 사이만 벌린다. */
  .pm-git > dd + dt {
    margin-top: 0.625rem;
  }
}
.pm-ai-drafts-badge {
    background: none;
    border: none;
    color: var(--jsini-color-primary, #007bff);
    font-weight: 600;
    cursor: pointer;
    padding: 0 0.5rem;
}
.pm-ai-drafts-badge:hover { text-decoration: underline; }

.pm-usage-week-val {
    font-size: 1.15em;
    font-weight: 800;
}

.pm-usage-reset {
    font-size: 0.85em;
    font-weight: normal;
    opacity: 0.9;
    margin-left: 0.25rem;
}

/* AI 사용량 띠 — 0~100% 스물한 칸. 밝기를 단조로 떨어뜨려(색조만으로는 70%와 95%가 같아 보였다) 색을 못 가리는 눈에도 짙을수록 많이 쓴 것으로 읽힌다. */
/* 값은 OKLCh 로 뽑았다 — 바꾸면 AiUsageBadgePaletteTests 를 다시 돌린다. 색띠는 세 벌이고 실제로 이기는 것은 맨 뒤의 tabler.css 다. */
.jsini-badge--usage-0   { background: #affbdd; color: #0a0600; }
.jsini-badge--usage-5   { background: #a5f4cc; color: #0a0600; }
.jsini-badge--usage-10  { background: #9cedb6; color: #0a0600; }
.jsini-badge--usage-15  { background: #9de499; color: #0a0600; }
.jsini-badge--usage-20  { background: #a4da77; color: #0a0600; }
.jsini-badge--usage-25  { background: #b2cc53; color: #0a0600; }
.jsini-badge--usage-30  { background: #bdbe26; color: #0a0600; }
.jsini-badge--usage-35  { background: #c6af00; color: #0a0600; }
.jsini-badge--usage-40  { background: #c8a200; color: #0a0600; }
.jsini-badge--usage-45  { background: #cd9200; color: #0a0600; }
.jsini-badge--usage-50  { background: #cf8400; color: #0a0600; }
.jsini-badge--usage-55  { background: #d37200; color: #0a0600; }
.jsini-badge--usage-60  { background: #d85c01; color: #0a0600; }
.jsini-badge--usage-65  { background: #d54c25; color: #0a0600; }
.jsini-badge--usage-70  { background: #cd4030; color: #ffffff; }
.jsini-badge--usage-75  { background: #c43534; color: #ffffff; }
.jsini-badge--usage-80  { background: #b92e38; color: #ffffff; }
.jsini-badge--usage-85  { background: #ad2640; color: #ffffff; }
.jsini-badge--usage-90  { background: #a12049; color: #ffffff; }
.jsini-badge--usage-95  { background: #931c54; color: #ffffff; }
.jsini-badge--usage-100 { background: #821d5e; color: #ffffff; }

/* 어두운 테마에 따로 주지 않는다 — 바탕이 불투명하고 글자색이 그 바탕에 맞춰 고른 값이다. 밝게 덮으면 밝은 바탕에서 안 읽힌다. */


/* ── 로그 — 줄을 눌러 옮기는 판 (`LogTranslateView`) ───────────── */
/* 「AI 작업」 상세의 로그 탭 그 자체다. 칸은 하나다 — 좌우 비교 편집기는 원문을 두 번 보여 걷었다. */

.pm-xlat {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0 0 0.5rem;
}

/* 머리띠 — 줄바꿈 · 되돌리기 · 옮긴 줄 수. 좁은 화면에서는 줄바꿈으로 흘러내리게 둔다 — 가로로 구르면 단추 절반이 밖에 남는다. */
.pm-xlat__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
}

.pm-xlat__stat {
  font-size: var(--jsini-fs-xs);
  opacity: 0.75;
}

/* 칸 이름은 「번역 · 한국어」 하나다 — 둘이던 것을 비교 편집기를 걷으며 줄였다. */
.pm-xlat__heads {
  display: flex;
  margin: 0 0 -0.25rem;
  font-size: var(--jsini-fs-xs);
  font-weight: 600;
  opacity: 0.8;
}

/* 이름표 — 이름은 왼쪽, 복사 아이콘은 글이 끝나는 자리 오른쪽에 선다. 테두리까지 이 폭 안이다(box-sizing) — 저장소에 기본 규칙이 없어 안 적으면 여백이 폭에 더해진다. */
.pm-xlat__head {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  box-sizing: border-box;
  flex: 1 1 100%;
  min-width: 0;
  padding: 0 0.5rem;
}

.pm-xlat__head-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 아이콘을 오른쪽 끝으로 민다. */
.pm-xlat__head .pm-edact {
  margin-left: auto;
}

/* 펴진 단추 판이 아래 편집기에 덮이지 않게, 펴진 동안만 이름표 줄을 위로 올린다. */
.pm-xlat__heads:has(.pm-edact.is-open) {
  position: relative;
  z-index: 20;
  opacity: 1;
}

/* 이름표 단추를 글자 높이에 맞춘다 — 그대로 두면 이름표 줄만 두 배로 두꺼워진다. */
.pm-xlat__head .pm-edact__btn {
  width: 1.25rem;
  height: 1.25rem;
}

/* 진행과 누가 답했는지. 남는 폭을 먹어 오른쪽 끝에 선다. */
.pm-xlat__stat {
  margin-left: auto;
  text-align: right;
}

/* 로그가 설 틀. 넓은 화면은 여기서 높이를 준다 — Monaco 는 부모 높이를 재서 그리므로 없으면 줄이 하나도 안 보인다. 휴대폰 목록은 높이를 안 받는다. */
.pm-xlat__editor {
  height: 30rem;

  /* 테두리를 높이 밖에 둔다 — 부트스트랩의 border-box 에서는 적어 준 높이에서 테두리 2px 을 빼고 서서, 내용을 재서 준 자리에 3px 막대와 잘린 마지막 줄이 생긴다. */
  box-sizing: content-box;

  border: 1px solid var(--jsini-border);
  border-radius: var(--jsini-radius-md);
  overflow: hidden;
}

.pm-xlat__inner {
  width: 100%;
  height: 100%;
}

/* ── 휴대폰 — 틀에 높이를 주지 않는다 ─────────────────────────── */
/* 틀이 제 안에서 구르면 쪽과 로그 상자 둘이 구르는 자리가 된다 — 긴 로그를 상자 안에서 보면 어디까지 읽었는지 안 보인다. 쪽 하나가 구른다. 그릴 줄 상한은 AiTaskView.DrawMax 다. */
@media (max-width: 767px) {
  .pm-xlat__editor {
    height: auto;
  }
}

/* ── 휴대폰 — 줄을 그대로 그린 목록 ──────────────────────────── */
/* Monaco 대신 줄을 그린다 — 굴림을 브라우저(합성기)에 돌려주려고. 쪽이 구르고 바닥 여백은 걷는다(고정 띠 아래 로그 끝이 가려지지 않게 쪽이 민다). touch-action 도 걷는다: pan-y 는 손가락 확대를 막는다. */
.pm-xlat__list {
  font-family: var(--tb-font);
  font-size: var(--jsini-fs-sm);
  line-height: 1.45;
}

/* 줄 하나. 빈 줄도 자리를 갖는다 — 빠지면 토막이 붙어 어디서 끊겼는지 안 보인다. */
.pm-xlat__row {
  display: flex;
  gap: 0.5rem;
  padding: 0 0.5rem;
  min-height: 1.45em;
  cursor: pointer;
}

/* 줄 번호는 고르기에서 뺀다 — 끌어 복사할 때 번호가 딸려 오면 붙여 넣은 로그를 못 쓴다. */
.pm-xlat__rownum {
  flex: 0 0 auto;
  min-width: 2.5em;
  text-align: right;
  color: var(--jsini-text-muted);
  user-select: none;
}

/* 반복 구간 뱃지 — 브라우저 개발자 도구 콘솔의 반복 회수 표시 스타일 */
.pm-xlat__repeat-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.4em;
  height: 1.35em;
  padding: 0 0.4em;
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1;
  color: #ffffff !important;
  background-color: var(--jsini-accent);
  border-radius: 9999px;
  user-select: none;
  flex: 0 0 auto;
  align-self: center;
  letter-spacing: -0.02em;
}

/* Monaco 편집기 안의 인라인 반복 뱃지 */
.monaco-editor .pm-xlat__repeat-badge {
  display: inline-block;
  padding: 1px 5px;
  font-size: 0.75em;
  font-weight: 700;
  line-height: 1.2;
  color: #ffffff !important;
  background-color: var(--jsini-accent);
  border-radius: 9999px;
  vertical-align: 1px;
}

/* 글은 줄바꿈을 켜고 시작한다 — 짝이 없는 자리라 끈 채로 두면 로그 한 줄이 화면 폭의 몇 배다. */
.pm-xlat__rowtext {
  flex: 1 1 auto;
  min-width: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* 줄바꿈을 끄면 가로로만 구른다. 세로는 쪽이 받는다. */
.pm-xlat__list--nowrap {
  overflow-x: auto;
}

.pm-xlat__list--nowrap .pm-xlat__row {
  width: max-content;
  min-width: 100%;
}

.pm-xlat__list--nowrap .pm-xlat__rowtext {
  white-space: pre;
  overflow-wrap: normal;
}

/* 누른 줄은 넓은 화면 편집기의 불과 같은 색이다 — 폭이 바뀌어도 같은 색이어야 한 화면으로 읽힌다. */
.pm-xlat__row--hit {
  background: color-mix(in srgb, var(--jsini-accent, #0054a6) 22%, transparent);
  box-shadow: inset 2px 0 0 var(--jsini-accent, #0054a6);
}

.pm-xlat__row--hit .pm-xlat__rownum {
  color: var(--jsini-accent, #0054a6);
  font-weight: 700;
}

/* 옮기는 중인 줄. 로컬 LLM 왕복이 몇 초라 표시가 없으면 눌러도 아무 일이 없는 것으로 보인다. */
.pm-xlat__row--redo {
  background: color-mix(in srgb, var(--jsini-warning, #f0a500) 26%, transparent);
  animation: pm-xlat-redo 1.1s ease-in-out infinite;
}

.pm-xlat__row--redo .pm-xlat__rownum {
  color: var(--jsini-warning, #f0a500);
  font-weight: 700;
}

.pm-xlat__loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  font-size: var(--jsini-fs-xs);
  opacity: 0.7;
}

/* ── 커서가 선 줄에 켜는 불 ──────────────────────────────────── */
/* Monaco 의 지금 줄 표시를 끄고 이것으로 대신한다 — 짚은 줄과 옮기는 줄이 한 자에서 갈린다. !important 는 편집기 테마의 바탕과 겨루므로 그대로 둔다. */
.pm-xlat .pm-xlat__hit {
  background: color-mix(in srgb, var(--jsini-accent, #0054a6) 22%, transparent) !important;
  box-shadow: inset 2px 0 0 var(--jsini-accent, #0054a6);
}

/* 줄 번호도 함께 짙게 — 번호로 짚어 말할 때 눈에 먼저 들어와야 한다. */
.pm-xlat .pm-xlat__hit-num {
  color: var(--jsini-accent, #0054a6) !important;
  font-weight: 700;
}

/* 옮기는 줄 — 표시가 없으면 눌러도 아무 일이 없는 것으로 보인다. 머리띠 글자는 눈이 가 있는 자리에서 멀다. */
.pm-xlat .pm-xlat__redo {
  background: color-mix(in srgb, var(--jsini-warning, #f0a500) 26%, transparent) !important;
  animation: pm-xlat-redo 1.1s ease-in-out infinite;
}

.pm-xlat .pm-xlat__redo-num {
  color: var(--jsini-warning, #f0a500) !important;
  font-weight: 700;
}

@keyframes pm-xlat-redo {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

/* 움직임을 반기지 않는 사람에게는 깜박임 대신 색만 남긴다. */
@media (prefers-reduced-motion: reduce) {
  .pm-xlat .pm-xlat__redo,
  .pm-xlat__row--redo {
    animation: none;
  }
}

/* ── AI 일정 메모 (`ScheduleNote.razor`) ── 오른쪽 본문 칸이 판 높이를 다 채운다. */
.pm-snote__bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--jsini-sp-sm, 0.5rem);
  padding: var(--jsini-sp-md, 0.75rem) var(--jsini-sp-lg, 1rem);
}

.pm-snote__write .commcont__body {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.pm-snote__memo {
  flex: 1;
  min-height: 240px;
}

.pm-snote__memo textarea {
  height: 100% !important;
  resize: none;
}

/* ── 일정표: 표 보기 인라인 수정 (`pm-inline-*`) ──────────────── */
.pm-inline-edit {
  width: 100%;
  color: var(--tb-text, var(--jsini-text, inherit));
}

.pm-inline-edit.dxbl-text-edit,
.pm-inline-edit.dxbl-combobox,
.pm-inline-edit.dxbl-date-edit {
  min-height: 28px;
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  font-size: 0.84375rem;
  color: var(--tb-text, var(--jsini-text, inherit));
  --dxbl-text-edit-color: var(--tb-text, var(--jsini-text, inherit));
  --dxbl-text-edit-btn-color: var(--tb-text, var(--jsini-text, inherit));
  transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out;
}

.pm-inline-edit.dxbl-text-edit:hover,
.pm-inline-edit.dxbl-combobox:hover,
.pm-inline-edit.dxbl-date-edit:hover {
  background: var(--tb-input-bg, var(--jsini-surface, #fff));
  border-color: var(--tb-border, var(--jsini-border, #d1d5db));
}

.pm-inline-edit.dxbl-text-edit:focus-within,
.pm-inline-edit.dxbl-combobox:focus-within,
.pm-inline-edit.dxbl-date-edit:focus-within {
  background: var(--tb-input-bg, var(--jsini-surface, #fff));
  border-color: var(--pm-gc-accent, #1a73e8);
  box-shadow: 0 0 0 1px var(--pm-gc-accent, #1a73e8);
}

.pm-inline-edit input {
  padding-top: 0.2rem;
  padding-bottom: 0.2rem;
  color: inherit;
}

/* 다크 모드: 입력박스의 배경과 글자색 대비 보장 (흰 배경에 흰 글자 방지) */
:root[data-theme='dark'] .pm-inline-edit,
:root[data-bs-theme='dark'] .pm-inline-edit {
  color: var(--tb-text, var(--jsini-text, #dee2e6));
}

:root[data-theme='dark'] .pm-inline-edit.dxbl-text-edit,
:root[data-theme='dark'] .pm-inline-edit.dxbl-combobox,
:root[data-theme='dark'] .pm-inline-edit.dxbl-date-edit,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-text-edit,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-combobox,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-date-edit {
  color: var(--tb-text, var(--jsini-text, #dee2e6));
  --dxbl-text-edit-color: var(--tb-text, var(--jsini-text, #dee2e6));
  --dxbl-text-edit-btn-color: var(--tb-text, var(--jsini-text, #dee2e6));
}

:root[data-theme='dark'] .pm-inline-edit.dxbl-text-edit:hover,
:root[data-theme='dark'] .pm-inline-edit.dxbl-combobox:hover,
:root[data-theme='dark'] .pm-inline-edit.dxbl-date-edit:hover,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-text-edit:hover,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-combobox:hover,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-date-edit:hover {
  background: var(--tb-input-bg, var(--jsini-surface, #1e2128));
  border-color: var(--tb-border, var(--jsini-border, #404040));
  color: var(--tb-text, var(--jsini-text, #dee2e6));
}

:root[data-theme='dark'] .pm-inline-edit.dxbl-text-edit:focus-within,
:root[data-theme='dark'] .pm-inline-edit.dxbl-combobox:focus-within,
:root[data-theme='dark'] .pm-inline-edit.dxbl-date-edit:focus-within,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-text-edit:focus-within,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-combobox:focus-within,
:root[data-bs-theme='dark'] .pm-inline-edit.dxbl-date-edit:focus-within {
  background: var(--tb-input-bg, var(--jsini-surface, #1e2128));
  border-color: var(--pm-gc-accent, #8ab4f8);
  box-shadow: 0 0 0 1px var(--pm-gc-accent, #8ab4f8);
  color: var(--tb-text, var(--jsini-text, #dee2e6));
}

:root[data-theme='dark'] .pm-inline-edit input,
:root[data-bs-theme='dark'] .pm-inline-edit input {
  color: var(--tb-text, var(--jsini-text, #dee2e6));
}

.pm-inline-state-wrapper {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.pm-inline-state.dxbl-combobox {
  min-width: 68px;
  max-width: 82px;
}

.pm-inline-over-badge {
  font-size: 0.75rem;
  padding: 0.1rem 0.35rem;
  flex-shrink: 0;
}

/* ── AI 일정 메모 공통 팝업 (`ScheduleNotePopup.razor`) ───── */
.pm-snote-popup__memo textarea {
  min-height: 200px;
  resize: vertical;
}

/* ──────────────── WBS 상세 목록(/projmng/wbs/rows) ──────────────── */
/* 칸에서 바로 고치는 것(체크 · 사람 · 우선순위)과 일감·첨부 배지. 색은 공통 강조·경고 변수를 쓴다. */
.pm-wbs-link { color: inherit; text-decoration: none; }
.pm-wbs-link:hover { color: var(--bs-primary, #206bc4); text-decoration: underline; }
.pm-wbs-noid { color: #b26a00; border: 1px dashed #b26a00; border-radius: 4px; padding: 0 5px; font-size: var(--jsini-fs-sm, 0.75rem); }

.pm-wbs-menu { display: flex; align-items: center; gap: 4px; min-width: 0; }
.pm-wbs-menu__t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm-wbs-menu__edit { flex: none; border: 1px solid transparent; background: none; padding: 0 5px; line-height: 1.3;
    color: var(--jsini-text-muted); border-radius: 4px; cursor: pointer; opacity: .45; }
.dxbl-grid-table tr:hover .pm-wbs-menu__edit { opacity: 1; }
.pm-wbs-menu__edit:hover { color: var(--bs-primary, #206bc4); border-color: var(--bs-primary, #206bc4); }

.pm-wbs-late { color: #b26a00; font-weight: 600; }
.pm-wbs-late sup { font-size: 0.6em; margin-left: 2px; font-weight: 400; }

.pm-wbs-rate { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.pm-wbs-rate__bar { width: 44px; height: 6px; border-radius: 3px; overflow: hidden;
    background: color-mix(in srgb, var(--jsini-text-muted) 20%, transparent); }
.pm-wbs-rate__bar i { display: block; height: 100%; background: var(--bs-primary, #206bc4); }
.pm-wbs-rate__bar i.full { background: #2e7d32; }
.pm-wbs-rate__pct { font-size: var(--jsini-fs-sm, 0.75rem); color: var(--jsini-text-muted); }

.pm-wbs-check { display: inline-flex; justify-content: center; width: 100%; padding: 2px 0; border-radius: 4px; }
.pm-wbs-check input { cursor: pointer; accent-color: #2e7d32; }
.pm-wbs-check--recheck { background: color-mix(in srgb, #b26a00 14%, transparent); }
.pm-wbs-check--recheck input { accent-color: #b26a00; }
.pm-wbs-busy { opacity: .45; }

.pm-wbs-person { display: inline-flex; gap: 5px; align-items: baseline; min-width: 90px; min-height: 1.4em;
    cursor: pointer; border-radius: 4px; padding: 0 3px; white-space: nowrap; }
.pm-wbs-person:hover { background: color-mix(in srgb, var(--bs-primary, #206bc4) 10%, transparent); }
.pm-wbs-person small { color: var(--jsini-text-muted); font-size: 0.8em; }
.pm-wbs-person--none { background: repeating-linear-gradient(-45deg, transparent, transparent 5px,
    color-mix(in srgb, var(--jsini-text-muted) 12%, transparent) 5px, color-mix(in srgb, var(--jsini-text-muted) 12%, transparent) 10px); }
.pm-wbs-pick { width: 100%; min-width: 120px; font: inherit; padding: 1px 4px; border-radius: 4px;
    border: 1px solid var(--bs-primary, #206bc4); background: var(--bs-body-bg, #fff); color: inherit; }
.pm-wbs-pick--sm { min-width: 64px; }

.pm-wbs-trg { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm-wbs-trg--none { color: var(--jsini-text-muted); }
.pm-wbs-trg--warn { color: #b26a00; }
.pm-wbs-trg--fire { color: var(--bs-primary, #206bc4); font-weight: 600; }

.pm-wbs-badge { min-width: 46px; padding: 1px 7px; border-radius: 10px; border: 1px solid var(--bs-border-color, #dce1e7);
    background: transparent; color: var(--jsini-text-muted); font-size: var(--jsini-fs-sm, 0.75rem);
    font-variant-numeric: tabular-nums; cursor: pointer; }
.pm-wbs-badge:hover { border-color: var(--bs-primary, #206bc4); color: var(--bs-primary, #206bc4); }
.pm-wbs-badge--open { border-color: var(--bs-primary, #206bc4); color: var(--bs-primary, #206bc4); font-weight: 600;
    background: color-mix(in srgb, var(--bs-primary, #206bc4) 10%, transparent); }
.pm-wbs-badge--done { border-color: #2e7d32; color: #2e7d32; font-weight: 600; background: color-mix(in srgb, #2e7d32 10%, transparent); }

.pm-wbs-chip { display: inline-block; padding: 1px 7px; border-radius: 10px; font-size: var(--jsini-fs-sm, 0.75rem);
    font-weight: 600; border: 1px solid transparent; text-decoration: none; white-space: nowrap; }
.pm-wbs-chip:hover { text-decoration: underline; }
.pm-wbs-chip--done { color: #2e7d32; border-color: #2e7d32; background: color-mix(in srgb, #2e7d32 10%, transparent); }
.pm-wbs-chip--review { color: #b26a00; border-color: #b26a00; background: color-mix(in srgb, #b26a00 10%, transparent); }
.pm-wbs-chip--dev { color: var(--bs-primary, #206bc4); border-color: var(--bs-primary, #206bc4);
    background: color-mix(in srgb, var(--bs-primary, #206bc4) 10%, transparent); }
.pm-wbs-chip--todo, .pm-wbs-chip--none { color: var(--jsini-text-muted); border-color: var(--bs-border-color, #dce1e7); font-weight: 400; }

.pm-wbs-cols { margin-bottom: 12px; }
.pm-wbs-cols__head { display: flex; align-items: center; gap: 8px; font-size: var(--jsini-fs-md, 0.875rem); font-weight: 600;
    margin: 0 0 6px; padding-bottom: 4px; border-bottom: 1px solid var(--bs-border-color, #dce1e7); }
.pm-wbs-cols__all { border: 1px solid var(--bs-border-color, #dce1e7); border-radius: 4px; background: none;
    padding: 1px 8px; font-size: var(--jsini-fs-sm, 0.75rem); font-weight: 600; cursor: pointer; color: inherit; }
.pm-wbs-cols__all--full { border-color: var(--bs-primary, #206bc4); color: var(--bs-primary, #206bc4);
    background: color-mix(in srgb, var(--bs-primary, #206bc4) 10%, transparent); }
.pm-wbs-cols__list { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 4px 12px; }

/* 칸 고르기 창: 왼쪽 고르기 · 오른쪽 차례. 창이 화면보다 길어지지 않게 두 판이 각자 구른다. */
.pm-wbs-colbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 10px; }
.pm-wbs-colbar__gap { flex: 1; }
.pm-wbs-colpick { display: grid; grid-template-columns: 1.35fr 1fr; gap: 14px; }
.pm-wbs-colpick__pane { display: flex; flex-direction: column; min-width: 0; }
.pm-wbs-colpick__title { margin: 0 0 6px; font-size: var(--jsini-fs-sm, 0.75rem); font-weight: 600; color: var(--jsini-text-muted); }
.pm-wbs-colpick__groups, .pm-wbs-colorder { height: min(56vh, 520px); overflow: auto; }
.pm-wbs-colorder { list-style: none; margin: 0; padding: 4px; border: 1px solid var(--bs-border-color, #dce1e7); border-radius: 6px; }
.pm-wbs-colorder li { display: flex; align-items: center; gap: 6px; padding: 3px 6px; margin-bottom: 2px;
    border: 1px solid transparent; border-radius: 5px; font-size: var(--jsini-fs-sm, 0.75rem); cursor: grab; }
.pm-wbs-colorder li:hover { border-color: var(--bs-border-color, #dce1e7); }
.pm-wbs-colorder li.is-dragging { opacity: 0.4; }
.pm-wbs-colorder li.is-over { border-color: var(--bs-primary, #206bc4);
    background: color-mix(in srgb, var(--bs-primary, #206bc4) 10%, transparent); }
.pm-wbs-colorder__no { width: 20px; text-align: right; color: var(--jsini-text-muted); font-variant-numeric: tabular-nums; }
.pm-wbs-colorder__grip { color: var(--jsini-text-muted); }
.pm-wbs-colorder__lb { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm-wbs-colorder__tag { color: var(--jsini-text-muted); font-size: var(--jsini-fs-xs, 0.6875rem); }
.pm-wbs-colorder__mv { border: 1px solid transparent; border-radius: 4px; background: none; padding: 0 5px;
    line-height: 18px; font-size: 0.625em; color: var(--jsini-text-muted); cursor: pointer; }
.pm-wbs-colorder__mv:hover:not(:disabled) { border-color: var(--bs-primary, #206bc4); color: var(--bs-primary, #206bc4); }
.pm-wbs-colorder__mv--off:hover:not(:disabled) { border-color: #d63939; color: #d63939; }
.pm-wbs-colorder__mv:disabled { opacity: 0.25; cursor: default; }
.pm-wbs-colorder li.pm-wbs-colorder__empty { color: var(--jsini-text-muted); cursor: default; padding: 10px 6px; }
@media (max-width: 767px) {
    .pm-wbs-colpick { grid-template-columns: 1fr; }
    .pm-wbs-colpick__groups, .pm-wbs-colorder { height: auto; max-height: 40vh; }
    .pm-wbs-colorder__mv { padding: 2px 8px; font-size: 0.8em; }
}

/* 표시 칸 · 일감 칸의 칸별 검색 고르개 */
.pm-wbs-fsel { width: 100%; min-width: 0; font-size: var(--jsini-fs-sm, 0.75rem); padding: 2px 4px;
    border: 1px solid var(--bs-border-color, #dce1e7); border-radius: 4px; background: var(--bs-body-bg, #fff); color: inherit; }
.pm-wbs-fsel--on { border-color: var(--bs-primary, #206bc4); color: var(--bs-primary, #206bc4); font-weight: 600; }

.pm-wbs-files { list-style: none; margin: 0 0 12px; padding: 0; }
.pm-wbs-files__row { display: flex; align-items: center; gap: 10px; padding: 4px 0;
    border-bottom: 1px solid var(--bs-border-color, #dce1e7); }
.pm-wbs-files__row a { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pm-wbs-task__add { border: 1px solid var(--bs-border-color, #dce1e7); border-radius: 6px; padding: 8px; margin-bottom: 10px; }
.pm-wbs-task__addhead { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.pm-wbs-task__addhead .spacer { flex: 1; }
.pm-wbs-task__filter { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 8px; }
.pm-wbs-task__list { list-style: none; margin: 0; padding: 0; }
.pm-wbs-task__row { display: grid; grid-template-columns: 28px 64px minmax(0, 1fr) 118px auto; gap: 8px; align-items: start;
    padding: 6px 0; border-bottom: 1px solid var(--bs-border-color, #dce1e7); }
.pm-wbs-task__row--done .pm-wbs-task__html { opacity: .6; }
.pm-wbs-task__check input { cursor: pointer; accent-color: #2e7d32; margin-top: 4px; }
.pm-wbs-task__div { font-weight: 600; font-size: var(--jsini-fs-sm, 0.75rem); padding-top: 2px; }
.pm-wbs-task__html { overflow-wrap: anywhere; }
.pm-wbs-task__html img { max-width: 100%; height: auto; }
.pm-wbs-task__html p { margin: 0 0 4px; }
.pm-wbs-task__at { font-size: var(--jsini-fs-sm, 0.75rem); padding-top: 2px; }
@media (max-width: 767px) {
    .pm-wbs-task__row { grid-template-columns: 28px minmax(0, 1fr) auto; }
    .pm-wbs-task__div, .pm-wbs-task__at { grid-column: 2; }
}
