 .section-heading-inline{display:flex;align-items:center;gap:8px;padding-block:4px}.section-heading-inline h2{margin:0}.section-heading-inline .section-summary{margin-left:0;white-space:nowrap}.request-summary-grid .section-heading-inline{padding-block:4px}.request-layout-root .panel{padding-block:10px}.request-layout-root .request-summary-grid{padding-block:5px}.request-layout-box>.request-summary-grid{gap:0;padding:0!important}.request-layout-box>.request-summary-grid>.section-heading-inline{margin:0;padding:0 0 2px}.species-select-native{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.species-selector{display:inline-flex;align-items:center;gap:4px;margin-left:4px}.species-option{display:grid;place-items:center;width:32px;height:32px;min-height:32px;padding:3px;border:1px solid transparent;border-radius:6px;background:transparent;color:#cbd5e1}.species-option[aria-pressed="true"]{border-color:var(--blue);background:#eaf3f8;color:var(--blue)}.species-option svg{width:24px;height:24px;fill:currentColor;stroke:currentColor;stroke-width:7.2;stroke-linecap:round;stroke-linejoin:round}

/* .conditional-check가 곧 label이라 `> label input`은 영영 안 맞았다 — 체크해도 상세 입력이 계속 숨었다.
   (CT/MR `기타 부위`가 그래서 입력 자체가 불가능했다.) 자기 안의 체크박스를 그대로 본다. */
 .request-layout-root .conditional-check:not(:has(input:checked)) .conditional-content{display:none}

/* `기타` 박스는 체크박스 없이 자유 입력만 받는다. 입력창 폭은 설정값(--request-text-input-width)이 아니라
   박스 폭을 그대로 쓴다. 배치 엔진(snapLayoutWidths)이 항목에 인라인 width를 박으므로 !important로 덮는다. */
.catalog-group[data-layout-group="기타"] {
  flex: 1 1 100%;
}

.catalog-group[data-layout-group="기타"] .catalog-items,
.catalog-group[data-layout-group="기타"] .catalog-item,
.catalog-group[data-layout-group="기타"] .conditional-content {
  width: 100% !important;
  flex: 1 1 auto !important;
}

.catalog-group[data-layout-group="기타"] input[type="text"] {
  width: 100%;
  max-width: 100%;
}

/* ==========================================
   1. Base & Design System Custom Properties
   ========================================== */
:root {
  --navy: #17324d;
  --blue: #286f9b;
  --bg: #f3f6f8;
  --line: #d7e0e7;        /* 내부 구분선 */
  --line-strong: #9fb3c0; /* 영역 경계 (3.2:1) */
  --text: #1b2730;
  --muted: #60717d;
  --danger: #b42318;
  --warning: #a15c00;
  --success: #147a4b;
  --surface-alt: #e7edf2;      /* 주문 박스·경고 배지 배경 */
  --surface-subtle: #eef2f5;   /* 검사 종료 후·상태 배지 배경 */
  --divider-subtle: #e4e8eb;   /* 완료 목록 내부 행 구분선 */
  --border-control: #bdcbd5;   /* 입력창·상태 메뉴 팝업 테두리 */
  --classification-default-border: #a9a9a9; /* 분류 테두리 기본값(응급 제외) */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
}

.schedule-page-heading { align-items: center; }
.schedule-page { --schedule-panel-width: calc(var(--schedule-day-width, 120px) * 7 + 42px); }
.schedule-page .staff-calendar-panel { width: min(var(--schedule-panel-width), 100%); margin-inline: auto; }
.schedule-page .staff-calendar-weekdays, .schedule-page .staff-calendar-grid { grid-template-columns: repeat(7, var(--schedule-day-width, 120px)); }
.schedule-page .staff-calendar-weekdays span { text-align: center; border: 1px solid var(--line); }
.schedule-page .staff-calendar-day { text-align: center; }
.schedule-page .staff-calendar-day { padding: var(--schedule-day-padding-y, 8px) var(--schedule-day-padding, 8px); }
.schedule-page .staff-calendar-weekdays span { font-size: calc(12px * var(--schedule-day-scale, 1)); font-weight: var(--schedule-day-weight, 700); color: var(--schedule-day-color, var(--muted)); }
.schedule-page .staff-calendar-day time { font-size: calc(13px * var(--schedule-day-scale, 1)); font-weight: var(--schedule-day-weight, 700); color: var(--schedule-day-color, var(--text)); }
.schedule-page .staff-row { display: flex; justify-content: space-between; text-align: left; font-size: calc(13px * var(--schedule-staff-scale, 1)); font-weight: var(--schedule-staff-weight, 500); color: var(--schedule-staff-color, var(--text)); white-space: nowrap; }
.schedule-page .staff-row.status-off { font-size: calc(13px * var(--schedule-off-scale, 1)); font-weight: var(--schedule-off-weight, 800); color: var(--schedule-off-color, var(--danger)); }
.schedule-page .staff-row.status-annual { font-size: calc(13px * var(--schedule-annual-scale, 1)); font-weight: var(--schedule-annual-weight, 500); color: var(--schedule-annual-color, #6b7280); }
.schedule-page .staff-row.status-half { font-size: calc(13px * var(--schedule-half-scale, 1)); font-weight: var(--schedule-half-weight, 500); color: var(--schedule-half-color, var(--warning)); }
.schedule-page .weekly-off-settings { width: min(var(--schedule-panel-width), 100%); margin-inline: auto; }
.schedule-page .weekly-off-form, .schedule-page .weekly-off-form label, .schedule-page .weekday-picker, .schedule-page .weekday-picker label, .schedule-page .day-schedule-grid label { white-space: nowrap; }
.schedule-page select { height: 28px; min-height: 28px; padding: 0; line-height: 28px; text-align: center; text-align-last: center; }
.schedule-page .day-schedule-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.schedule-page .day-schedule-row label { display: flex; align-items: center; gap: 6px; width: 100%; }
.schedule-page .day-schedule-row select { flex: 1; min-width: 0; }
.monthly-leave-panel { width: min(var(--schedule-panel-width, 882px), 100%); margin: 8px auto 0; }.monthly-leave-panel h2 { margin: 0 0 8px; font-size: 16px; }.monthly-leave-panel table { width: 100%; border-collapse: collapse; }.monthly-leave-panel th,.monthly-leave-panel td { padding: 5px 8px; border: 1px solid var(--line); text-align: left; }.monthly-leave-entry { min-height: 0; padding: 0; border: 0; border-radius: 0; background: transparent; color: inherit; text-decoration: underline; }
.schedule-layout-fab { position: fixed; right: 18px; bottom: 18px; z-index: 45; }.schedule-layout-fab>summary { cursor: pointer; list-style: none; width: 44px; height: 44px; padding: 0; display: grid; place-items: center; border-radius: 999px; background: var(--navy); color: #fff; box-shadow: 0 4px 12px #0003; }.schedule-layout-fab>summary::-webkit-details-marker { display: none; }.schedule-layout-fab>summary .tabler-icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }.schedule-layout-fab>form { position: absolute; right: 0; bottom: 52px; display: grid; gap: 8px; width: min(360px, calc(100vw - 20px)); padding: 12px; border: 1px solid var(--line); border-radius: 10px; background: #fff; box-shadow: 0 8px 24px #0003; }.schedule-layout-fab h2 { margin: 0; font-size: 16px; }.schedule-layout-fab fieldset { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 5px; margin: 0; padding: 7px; }.schedule-layout-fab label { display: grid; gap: 3px; font-size: 12px; }.schedule-layout-fab .schedule-padding-row { display: flex; align-items: center; gap: 6px; font-size: 12px; white-space: nowrap; }.schedule-layout-fab .schedule-padding-row label { display: flex; align-items: center; gap: 4px; }.schedule-layout-fab .schedule-padding-row input { width: 30px; }.schedule-layout-hint { margin: 0; font-size: 11px; color: var(--muted); }.schedule-layout-fab input,.schedule-layout-fab select { width: 70px; min-width: 0; height: 28px; min-height: 28px; padding: 0 4px; }
.month-nav, .weekly-off-form, .weekday-picker, .dialog-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.month-nav .button { padding: 5px 8px; }
.weekly-off-settings summary { cursor: pointer; font-weight: 700; }
.weekly-off-form { margin-top: 8px; }
.weekly-off-form label, .weekday-picker label { display: inline-flex; align-items: center; gap: 4px; margin: 0; }
.staff-calendar-panel { padding: 8px; }
.staff-calendar-scroll { overflow-x: auto; }
.staff-calendar-weekdays, .staff-calendar-grid { display: grid; grid-template-columns: repeat(7, minmax(120px, 1fr)); }
.staff-calendar-weekdays span { padding: 4px 8px; font-size: 12px; font-weight: 700; color: var(--muted); }
.staff-calendar-day { display: block; padding: 7px 8px; border: 1px solid var(--line); border-radius: 0; background: #fff; color: inherit; text-align: left; cursor: pointer; }
.staff-calendar-day:active { background: #f8fafc; }
.staff-calendar-day time { display: block; margin-bottom: 6px; font-weight: 800; }
.staff-calendar-day.outside { color: #9ca3af; background: #f8fafc; }
.staff-calendar-day.today { box-shadow: inset 0 0 0 2px #2563eb; }
.staff-row { display: block; margin: 3px 0; font-size: 13px; line-height: 1.25; }
.status-annual { color: #6b7280; text-decoration: none; }
.status-off { color: var(--danger); font-weight: 800; }
.schedule-dialog { width: min(720px, calc(100vw - 24px)); max-height: calc(100vh - 24px); border: 1px solid var(--border); border-radius: 8px; padding: 14px; color: inherit; }
.schedule-dialog::backdrop { background: rgb(15 23 42 / .35); }

/* 공통-2 (2): 팝업 진입. <dialog>는 display:none↔block 전환이라 일반 transition이 안 먹는다.
   @starting-style로 "막 렌더되기 시작한 순간"의 값을 정의해 그 값에서 아래 상태로 전환되게 한다.
   transform-origin은 기본값(center)을 그대로 둔다 — 모달은 트리거 위치에 종속되지 않는다. */
.confirm-dialog, .slot-edit-dialog, .schedule-dialog {
  opacity: 1;
  transform: scale(1);
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
}
@starting-style {
  .confirm-dialog[open], .slot-edit-dialog[open], .schedule-dialog[open] {
    opacity: 0;
    transform: scale(0.97);
  }
}
.dialog-heading { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.dialog-heading h2 { margin: 0; font-size: 18px; }
.day-schedule-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 12px 0; }
.day-schedule-row { min-width: 0; }
@media (max-width: 700px) { .staff-calendar-weekdays, .staff-calendar-grid { min-width: 840px; } }

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 system-ui, -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
}

a {
  color: var(--blue);
  text-decoration: none;
}

.skip-link {
  position: fixed; left: 12px; top: -60px; z-index: 100;
  padding: 8px 12px; border-radius: 6px; background: #fff;
  color: var(--navy); font-weight: 700; transition: top .15s;
}
.skip-link:focus { top: 8px; outline: 2px solid var(--blue); }

button, .button, input, select, textarea {
  font: inherit;
}

button, .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 7px 13px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  color: var(--text);
  cursor: pointer;
  transition: transform 160ms var(--ease-out);
}

/* B-1: 상태 변경이 POST → 리다이렉트라 왕복 동안 화면이 무반응이다. 누른 느낌으로 최소한의 응답을 준다.
   FAB 여는 <summary>들과 모바일 하단 바 항목도 누르는 요소라 같이 넣는다. */
button:active, .button:active,
.dummy-fab > summary:active, .typography-fab > summary:active, .menu-fab > summary:active,
.simple-layout-fab > summary:active, .schedule-layout-fab > summary:active,
.board-nav-item:active {
  transform: scale(0.97);
}

.dummy-fab > summary, .typography-fab > summary, .menu-fab > summary,
.simple-layout-fab > summary, .schedule-layout-fab > summary,
.board-nav-item {
  transition: transform 160ms var(--ease-out);
}

/* B-1: 제출 중(select 자동 전송·form submit 진행 중) 표시. app.js가 붙인다. */
.is-submitting {
  opacity: .6;
}

/* 막힌 버튼은 눌러도 아무 일이 없다 — 커서와 명도로 그것을 미리 알린다.
   (전에는 `.board-nav-item:disabled` 한 곳만 흐려져서 나머지는 눌리는 것처럼 보였다.) */
button:disabled, .button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

button:disabled:active, .button:disabled:active {
  transform: none;
}

/* B-5: 순번 위/아래 버튼. 드래그 앤 드롭은 터치·키보드에서 동작하지 않아 이것이 유일한 경로다.
   HTML이 form 중첩을 허용하지 않아 버튼마다 폼이 따로라, 그 폼들을 한 줄로 세운다. */
.slot-reorder-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  /* h2(검사 정보)와 같은 계산식을 써서 아이콘이 --request-section-scale을 따라 함께 커지고 작아진다.
     둘 다 .section-heading-inline의 직계 자식이라 상속받는 1em 기준값이 같다. */
  font-size: calc(1em * var(--request-section-scale, 1));
}

.slot-reorder-actions .slot-reorder-form {
  display: contents;
}

/* B-5: 아이콘 전용 버튼. 기본 button 스타일(테두리·배경·13px 패딩)은 아이콘 하나엔 과하다.
   테두리·배경을 걷어내되 히트 영역은 44px 규칙(기존 모바일 min-height 규칙)에 얹혀 유지한다. */
.slot-reorder-button {
  min-height: 44px;
  min-width: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--request-section-color, #1f2937);
}

/* 텍스트 크기(검사 정보 h2)에 맞춘다 — px이 아니라 em이라 위 --request-section-scale 변화를 그대로 따라간다. */
.reorder-icon {
  width: 1.1em;
  height: 1.1em;
}

/* B-2: 모바일 터치 타깃 44px. 밀도용으로 26/28/30px를 명시한 버튼(더미 일괄 작업, 완료 목록 상태 메뉴,
   설정 패널 버튼, 계정 관리 버튼 등)은 클래스로 한정된 선택자라 특이도가 이겨 이 규칙의 영향을 받지 않는다. */
@media (max-width: 900px) {
  button, .button {
    min-height: 44px;
  }
}

.primary {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
}

.success {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

.danger-button {
  color: var(--danger);
  border-color: #f2b8b5;
}

input, select, textarea {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--border-control);
  border-radius: 7px;
  background: #fff;
}

input[type=checkbox] {
  width: auto;
}

/* ==========================================
   2. Menu Sidebar & Layout Structure
   ========================================== */
/* 상단바를 없애고 좌측 하단 플로팅 버튼으로 여는 사이드바로 대체했다.
   다른 FAB(더미·설정)과 같은 details/summary 구조라 열림 상태 관리가 필요 없다. */
.menu-fab {
  position: fixed;
  left: 18px;
  bottom: 18px;
  z-index: 60;
}

.menu-fab > summary {
  cursor: pointer;
  list-style: none;
  width: 44px;
  height: 44px;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--navy);
  color: #fff;
  box-shadow: 0 4px 12px #0003;
}

.menu-fab > summary::-webkit-details-marker {
  display: none;
}

.menu-fab > summary .tabler-icon {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

.sidebar {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  width: 220px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 14px;
  overflow-y: auto;
  background: var(--navy);
  color: #fff;
  box-shadow: 2px 0 14px #0018;
}

.brand {
  font-size: 19px;
  font-weight: 800;
  color: #fff;
  white-space: nowrap;
}

.sidebar nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.sidebar nav a {
  padding: 8px 9px;
  font-size: 14px;
  border-radius: 6px;
  color: #e8f1f7;
}

.sidebar nav a.current {
  background: #fff;
  color: var(--navy);
  font-weight: 800;
}

/* 아이디·로그아웃·화면 권한은 사이드바 하단에 붙인다. */
.userbox {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: auto;
  padding-top: 10px;
  border-top: 1px solid #ffffff24;
  font-size: 13px;
}

.userbox-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.userbox form {
  margin: 0;
}

.link-button {
  min-height: auto;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  text-decoration: underline;
}

.container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 24px;
}

.container.wide {
  max-width: 1500px;
}

.page-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 18px;
}

.page-heading h1, .page-heading h2 {
  margin: 0;
}

.muted {
  color: var(--muted);
}

.panel, .patient-row, .login-card, .empty {
  background: #fff;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  padding: 20px;
  box-shadow: 0 2px 7px #17324d0b;
}

.message {
  margin-bottom: 14px;
  padding: 11px 14px;
  border-radius: 8px;
  background: #dbeaf4;
}

.message.error {
  background: #fee4e2;
  color: var(--danger);
}

.message.success {
  background: #dcfae6;
  color: var(--success);
}

/* 스크린리더 전용 텍스트. 시각적으로는 감추되 콘텐츠는 남긴다(.species-select-native와 같은 clip 방식). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* A-2: 갱신이 멈춘 것을 알리는 신호. 무인 벽걸이라 화면 면적을 카드에서 빼앗지 않아야 해서
   토스트가 아니라 뷰포트 테두리로 표시한다. 클릭을 막지 않는다. */
.refresh-warning {
  position: fixed;
  inset: 0;
  z-index: 90;              /* 하단 바(50)·상태 메뉴(80)보다 위 */
  border: 6px solid var(--danger);
  pointer-events: none;
}

.refresh-warning[hidden] {
  display: none;
}

.login-card {
  max-width: 420px;
  margin: 12vh auto;
  padding: 32px;
}

.stack {
  display: grid;
  gap: 16px;
}

/* ==========================================
   3. Density System
   ========================================== */
.role-switcher {
  display: flex;
  align-items: center;
  gap: 5px;
}

.role-switcher label {
  font-size: 12px;
  color: #cfe0eb;
}

.role-switcher select {
  width: auto;
  min-height: 30px;
  padding: 3px 25px 3px 7px;
  border-color: #ffffff55;
  background: #fff;
  color: var(--text);
}

.density-page {
  --d-outer: 12px;
  --d-gap: 7px;
  --d-panel: 10px;
  --d-control-y: 5px;
  --d-control-x: 7px;
  --d-control-h: 31px;
  --d-cell-y: 5px;
  --d-cell-x: 7px;
  --d-radius: 7px;
  --d-cols: 4;
  max-width: 1500px;
  padding: var(--d-outer);
  font-size: 14px;
}

.density-1 { --d-outer: 24px; --d-gap: 16px; --d-panel: 20px; --d-control-y: 9px; --d-control-x: 10px; --d-control-h: 38px; --d-cell-y: 10px; --d-cell-x: 10px; --d-radius: 12px; --d-cols: 3; --d-title: 28px; font-size: 15px; }
.density-2 { --d-outer: 18px; --d-gap: 12px; --d-panel: 16px; --d-control-y: 7px; --d-control-x: 9px; --d-control-h: 35px; --d-cell-y: 8px; --d-cell-x: 9px; --d-radius: 10px; --d-cols: 3; --d-title: 25px; }
.density-3 { --d-outer: 14px; --d-gap: 9px; --d-panel: 12px; --d-control-y: 6px; --d-control-x: 8px; --d-control-h: 33px; --d-cell-y: 6px; --d-cell-x: 8px; --d-radius: 8px; --d-cols: 4; --d-title: 23px; }
.density-4 { --d-outer: 10px; --d-gap: 6px; --d-panel: 8px; --d-control-y: 4px; --d-control-x: 6px; --d-control-h: 29px; --d-cell-y: 4px; --d-cell-x: 6px; --d-radius: 6px; --d-cols: 5; --d-title: 21px; }
.density-5 { --d-outer: 7px; --d-gap: 4px; --d-panel: 5px; --d-control-y: 2px; --d-control-x: 5px; --d-control-h: 26px; --d-cell-y: 2px; --d-cell-x: 5px; --d-radius: 4px; --d-cols: 5; --d-title: 19px; font-size: 13px; }

.density-page .page-heading h1 { font-size: var(--d-title, 22px); }

.request-layout-root{display:grid;gap:var(--d-gap,8px)}.request-layout-row{display:flex;gap:var(--d-gap,8px);align-items:flex-start}.request-layout-box{display:flex;gap:var(--d-gap,8px);min-width:0;max-width:100%;padding:var(--d-panel,8px);border:1px solid var(--line);border-radius:var(--d-radius,6px);background:#fff}.request-layout-box>[data-request-component]{width:100%;min-width:0}.request-layout-box>.panel,.request-layout-box>[data-request-component]>.panel{margin:0;padding:0;border:0;border-radius:0;box-shadow:none}.request-layout-box>.request-summary-grid{width:100%}.request-layout-root input:not([type=checkbox]):not([type=radio]),.request-layout-root select,.request-layout-root textarea{box-sizing:border-box;height:var(--request-control-height,28px);min-height:var(--request-control-height,28px);padding:0 var(--request-control-padding-x,6px);font-size:var(--request-control-font-size,13px);line-height:normal}.request-layout-root textarea{resize:none}.request-layout-fab{position:fixed;right:18px;bottom:70px;z-index:45}.request-layout-fab>summary{cursor:pointer;list-style:none;width:44px;height:44px;padding:0;display:grid;place-items:center;border-radius:999px;background:var(--navy);color:#fff;box-shadow:0 4px 12px #0003}.request-layout-fab>summary::-webkit-details-marker{display:none}.request-layout-fab>summary .tabler-icon{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.request-layout-fab>form{position:absolute;right:0;bottom:42px;display:grid;gap:8px;width:min(430px,calc(100vw - 20px));max-height:calc(100vh - 130px);overflow:auto;padding:12px;border:1px solid var(--line);border-radius:10px;background:#fff;box-shadow:0 8px 24px #0003}.request-layout-fab textarea{width:100%;font-family:ui-monospace,monospace;font-size:12px}.request-layout-fab p{margin:0;font-size:11px;color:var(--muted)}.request-layout-fab fieldset{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}.request-layout-fab fieldset label{display:grid;grid-template-columns:1fr 70px;align-items:center;gap:4px;font-size:12px}.request-layout-fab input{min-width:0}@media(max-width:700px){.request-layout-row,.request-layout-box{display:grid;grid-template-columns:minmax(0,1fr)}.request-layout-row{width:100%;min-width:0}.request-layout-box>[data-request-component]{width:100%}}
.request-summary-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:var(--d-gap,4px)}.request-summary-grid>.section-heading{grid-column:1/-1}.request-summary-grid>.warning-field{min-width:0}.catalog-items{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:var(--d-gap,4px)}@media(max-width:700px){.request-summary-grid,.catalog-items{grid-template-columns:1fr}}
.request-summary-grid.layout-managed,.catalog-items.layout-managed{grid-template-columns:1fr}.request-layout-block-row{display:flex;flex-wrap:wrap;align-items:flex-start;gap:var(--d-gap,4px);min-width:0;max-width:100%}.request-layout-block{display:grid;flex:1 1 auto;width:max-content;max-width:100%;gap:var(--d-gap,4px);min-width:0}.request-summary-grid .request-layout-block,.catalog-grid>.request-layout-block-row>.request-layout-block,.catalog-grid>.request-layout-block-row>.catalog-group{padding:var(--d-panel,5px);border:1px solid var(--line);border-radius:var(--d-radius,4px)}.catalog-grid.layout-managed{display:grid;gap:var(--d-gap,4px)}.catalog-grid.layout-managed>.request-layout-block-row>.catalog-group{flex:1 1 auto;width:max-content;max-width:100%;margin:0}.request-layout-line{display:flex;flex-wrap:wrap;align-items:center;gap:var(--request-item-gap,5px);min-width:0}.request-layout-line>[data-layout-item]{flex:0 0 auto;width:max-content;max-width:100%;margin:0;white-space:nowrap}.request-field-pair,.catalog-item,.warning-field,.slot-inputs [data-layout-item],.check,.catalog-item>span{display:inline-flex;align-items:center;gap:2px}.request-field-pair input{width:14ch;max-width:100%}.request-field-pair select,.slot-inputs select,.catalog-grid .request-layout-block select{width:auto;max-width:100%}.slot-inputs textarea,.catalog-grid .request-layout-block textarea{width:24ch;max-width:100%}.slot-inputs input[type=text],.catalog-grid .request-layout-block input[type=text]{width:16ch;max-width:100%}.catalog-item input[type=checkbox],.check input[type=checkbox]{flex:0 0 auto;width:auto;margin:0}
.request-layout-root{color:var(--request-text-color,#1f2937);font-size:var(--request-control-font-size,13px)}.request-layout-root .required{color:var(--request-required-color,#dc2626)}.request-layout-root input[type=text],.request-layout-root textarea{width:var(--request-text-input-width,160px);max-width:100%}.request-layout-root select:not(.species-select-native){width:var(--request-select-width,96px);max-width:100%}.catalog-grid .request-layout-block [data-layout-item]{display:inline-flex;align-items:center;gap:2px}.catalog-group legend{font-size:calc(1em * var(--request-group-scale,1));font-weight:var(--request-group-weight,600);color:var(--request-group-color,#1f2937)}[data-purpose-input] .required,[data-examiner-input] .required,[data-post-exam-input] .required{visibility:hidden}[data-purpose-input].is-required .required,[data-examiner-input].is-required .required,[data-post-exam-input].is-required .required{visibility:visible}.catalog-section-ultrasound [data-purpose-input] textarea,.catalog-section-ultrasound [data-classification~="EMERGENCY"] input,.catalog-section-ultrasound [data-classification~="OUTPATIENT_PRIORITY"] input{width:calc(var(--request-text-input-width,160px) * 1.2)!important;max-width:100%}.catalog-collapse>summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:3px}.catalog-collapse>summary::-webkit-details-marker{display:none}.catalog-collapse>summary h2{display:inline}.caret-icon{width:18px;height:18px;flex:0 0 18px;color:var(--request-section-color,#1f2937)}.catalog-collapse>summary .caret-open{display:none}.catalog-collapse[open]>summary .caret-open{display:inline-block}.catalog-collapse[open]>summary .caret-closed{display:none}.section-heading h2{font-size:calc(1em * var(--request-section-scale,1));font-weight:var(--request-section-weight,700);color:var(--request-section-color,#1f2937)}
.form-actions{display:flex;justify-content:center;gap:8px}
.request-layout-box{width:var(--request-component-width,560px)}
.reading-request-check{margin-left:auto;display:inline-flex;align-items:center;gap:4px;font-size:13px;white-space:nowrap}
.reading-request-check small{color:var(--muted);font-weight:400}
.layout-error{margin:0;font-size:12px;color:var(--danger)}
.order-box{width:fit-content;max-width:100%;margin-inline:auto;padding:var(--order-box-padding,18px);border:1px solid var(--line-strong);border-radius:var(--order-box-radius,16px);background:var(--order-box-color,var(--surface-alt));display:grid;gap:16px}
.color-field{position:relative;display:inline-block;vertical-align:middle}
.color-field>summary{list-style:none;width:16px;height:16px;padding:0;border:1px solid var(--line);border-radius:999px;cursor:pointer}
.color-field>summary::-webkit-details-marker{display:none}
.color-field .color-popup{position:fixed;z-index:80;display:flex;align-items:center;gap:4px;padding:6px;border:1px solid var(--line);border-radius:8px;background:#fff;box-shadow:0 4px 12px #0003}
.color-field .color-popup input[type=color]{width:32px;height:26px;min-height:26px;padding:0;border:0;background:none}
.color-field .color-popup input[type=text]{width:84px;min-width:0}
.badge{display:inline-flex;align-items:center;padding:1px 7px;border-radius:999px;background:var(--line);font-size:12px;font-weight:600;white-space:nowrap}
.slot-edit-dialog{width:max-content;max-width:calc(100vw - 24px);max-height:calc(100vh - 40px);overflow:auto;border:0;background:transparent;padding:0}
.slot-edit-dialog::backdrop{background:rgb(15 23 42 / .35)}

/* ==========================================
   4. Status Board Workspace & Column Grid
   ========================================== */
.container.board-container {
  max-width: none;
  padding: 0;
}

.board-workspace {
  min-height: calc(100vh - 62px);
  padding: 18px 22px;
  background: var(--board-bg, var(--bg));
  overflow-x: hidden;
}

.board-toolbar {
  display: none;
}

/* Desktop Hides Tabs - Pinned Rule */
.board-tabs {
  display: none !important;
}

.worklist-board {
  display: grid;
  grid-template-columns: var(--xray-width, 1fr) var(--floor1-width, 1fr) var(--floor3-width, 1fr);
  /* A4: 트랙 폭 합이 화면보다 좁으면 가운데로 모은다. safe를 안 붙이면 트랙 합이 화면보다 넓어져
     가로 스크롤이 생길 때 center 정렬이 왼쪽 끝을 잘라낸다(overflow가 양쪽에 걸쳐 분배되기 때문). */
  justify-content: safe center;
  align-items: stretch;
  min-width: 0;
}

/* 완료 목록을 뷰포트 하단에 띄우려면 position:sticky가 붙잡을 스크롤 컨테이너가 필요하다.
   컬럼이 남은 높이를 정확히 채우고 카드만 그 안에서 스크롤한다(페이지 자체는 스크롤하지 않는다).
   상단 바 높이는 뷰포트 폭에 따라 달라지므로 픽셀로 빼지 않고 flex가 계산하게 둔다. */
body:has(.board-container) {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

body:has(.board-container) > .board-container {
  flex: 1 1 auto;
  /* min-width를 0으로 풀지 않으면 워크리스트 폭 합이 화면보다 넓을 때 컨테이너가 같이 늘어나
     .worklist-board의 overflow-x가 작동하지 않는다.
     .container의 `margin: 0 auto`도 같이 풀어야 한다 — flex 교차축에서 auto 마진은 stretch를 끄고
     내용 크기(fit-content)로 만들어서 컨테이너가 화면 밖으로 넓어진다. */
  min-width: 0;
  margin: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.board-workspace {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.worklist-board {
  flex: 1 1 auto;
  min-height: 0;
  /* 워크리스트 폭 합이 화면보다 넓으면 가로로 스크롤한다(세로는 컬럼이 각자 맡는다). */
  overflow-x: auto;
  overflow-y: hidden;
}

.kanban-column {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow-y: auto;
  /* overflow-y만 지정하면 overflow-x가 auto로 계산돼 컬럼마다 가로 스크롤바가 생기고,
     그 높이(15px)만큼 완료 목록이 바닥에서 떠 보인다. 가로 스크롤은 .worklist-board가 맡는다. */
  overflow-x: hidden;
  position: relative;
  border-left: var(--divider-width, 1px) solid var(--divider-color, var(--blue));
  padding: 0 16px;
  min-width: 0;
}

.kanban-column:first-child {
  border-left: 0;
}

.worklist-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text);
  font-size: 18px;
  font-weight: 800;
  margin-bottom: 12px;
}

.worklist-heading.inactive {
  color: var(--muted);
}

.worklist-heading b {
  display: grid;
  place-items: center;
  min-width: 28px;
  height: 28px;
  border: 1px solid #738391;
  border-radius: 50%;
  font-size: 13px;
}

.kanban-empty {
  padding: 24px;
  color: var(--muted);
  border: 1px dashed #53616b;
  border-radius: 10px;
  text-align: center;
  font-size: 16px;
}

/* ==========================================
   5. Kanban Card Layout (3-Row Layout)
   ========================================== */
.kanban-card {
  /* 컬럼이 flex 세로 컨테이너라 기본값(flex-shrink:1)이면 카드가 남은 높이에 맞춰 찌그러진다.
     실측: 카드 12장일 때 높이 34px로 눌리고 내용이 106px 밖으로 넘쳤다.
     높이는 내용과 여백 설정으로만 정해지고, 넘치는 만큼 컬럼이 스크롤한다. */
  flex: 0 0 auto;
  padding: var(--card-padding-top, 10px) var(--card-padding-right, 14px) var(--card-padding-bottom, 10px) var(--card-padding-left, 14px);
  /* 테두리 색을 변수 하나로 모은다 — 순번 배경(.queue-num)이 같은 변수를 읽어 테두리색과 동기화된다. */
  --card-edge: var(--classification-default-border);
  border: 2px solid var(--card-edge);
  border-radius: var(--card-radius, 16px);
  background: #fff;
  color: #111;
  margin-bottom: 12px;
  cursor: pointer;
  min-width: 0;
  position: relative;
}

/* 진행 중 카드의 형태 인코딩. 테두리 전체가 원뿔 그라디언트이고 그 각도가 돈다.
   border를 투명하게 두고 배경 두 장을 겹치는 방식이다: 안쪽(padding-box)은 카드 배경,
   바깥(border-box)은 그라디언트 — 그래서 테두리 자리에만 그라디언트가 남는다.
   앞서 시도한 두 방식을 버린 이유를 남긴다:
   (1) <rect> + pathLength — pathLength가 <rect>에 적용되지 않아 dasharray가 px로 해석됐다.
   (2) 회전 정사각형 / 사각 경로를 도는 선 — 선 한 조각이 카드 안쪽을 지나 내용 위를 덮었고,
       경로 방식은 JS로 경로를 다시 그려야 했다(ResizeObserver는 display:none 전환에서 울리지 않는다).
   지금 방식은 순수 CSS다. 색은 설정값 하나에서 세 톤을 파생해 한 곳만 바꾸면 전부 따라온다. */
@property --gradient-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}


@keyframes card-border-rotate {
  to { --gradient-angle: 360deg; }
}

/* 상태는 색 단독이 아니라 형태로도 구분한다 — 거리·시야각에서 색보다 먼저 무너지지 않도록.
   opacity로 "흐리게"는 텍스트 대비를 기준 아래로 떨어뜨려 쓰지 않는다(완료/취소는 배경·장식으로 대체).
   진행 중은 이 solid 테두리가 바탕이고, 위쪽 @supports 블록이 그 위에 회전 그라디언트를 얹는다. */
.kanban-card.status-in_progress { --card-edge: var(--classification-in_progress-border, #d39834); }
.kanban-card.status-completed { --card-edge: #4b9a72; background: #f0f7f3; }
/* 취소는 물러나야 한다. opacity를 걷어내면서 빨강을 그대로 두면 응급 대기와 같은 세기로 외친다
   — 벽걸이에서 무의미한 카드가 가장 시급한 카드처럼 보인다. 빨강은 응급 전용으로 남기고,
   취소는 회색 + 취소선(형태)으로 표시한다. */
.kanban-card.status-canceled { --card-edge: var(--muted); }
.kanban-card.status-canceled .board-text-name { text-decoration: line-through; }
.kanban-card.status-hold { --card-edge: #6b7880; border-style: dashed; }
.kanban-card.status-attending { --card-edge: #6941c6; }

/* conic-gradient와 color-mix를 못 쓰는 브라우저에서는 이 블록이 통째로 무시되고
   위의 solid 테두리(설정 색)가 그대로 남는다 — 테두리가 사라지지 않는다. */
@supports (background: conic-gradient(from 0deg, red, blue)) and (color: color-mix(in oklab, red, blue)) {
  .kanban-card.status-in_progress {
    /* 설정에서 정한 진행 카드 테두리 색 하나가 기준이다(관리자가 바꾸면 세 톤이 함께 바뀐다). */
    --trace-color: var(--classification-in_progress-border, #d39834);
    --trace-dark: color-mix(in oklab, var(--trace-color) 62%, var(--navy));
    --trace-bright: color-mix(in oklab, var(--trace-color) 55%, #ffffff);
    border-color: transparent;
    background-image:
      linear-gradient(#fff, #fff),
      conic-gradient(
        from var(--gradient-angle),
        var(--trace-dark) 0deg,
        var(--trace-color) 60deg,
        var(--trace-bright) 90deg,
        var(--trace-color) 120deg,
        var(--trace-dark) 180deg,
        var(--trace-color) 240deg,
        var(--trace-bright) 270deg,
        var(--trace-color) 300deg,
        var(--trace-dark) 360deg
      );
    background-clip: padding-box, border-box;
    background-origin: padding-box, border-box;
    animation: card-border-rotate 5s linear infinite;
  }
}

/* 분류 테두리색은 대기 상태일 때만 적용한다(다른 상태색이 항상 우선).
   응급만 기본값을 danger 계열로 분리한다 — 나머지 대기 분류와 기본 설정에서도 구분되도록. */
.kanban-card.status-waiting.classification-appointment { --card-edge: var(--classification-appointment-border, var(--classification-default-border)); }
.kanban-card.status-waiting.classification-outpatient { --card-edge: var(--classification-outpatient-border, var(--classification-default-border)); }
.kanban-card.status-waiting.classification-outpatient_priority { --card-edge: var(--classification-outpatient_priority-border, var(--classification-default-border)); }
.kanban-card.status-waiting.classification-inpatient { --card-edge: var(--classification-inpatient-border, var(--classification-default-border)); }
.kanban-card.status-waiting.classification-inpatient_priority { --card-edge: var(--classification-inpatient_priority-border, var(--classification-default-border)); }
.kanban-card.status-waiting.classification-emergency { --card-edge: var(--classification-emergency-border, var(--danger)); }

/* Row 1: Primary Header Row */
.card-primary {
  display: flex !important;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
  min-width: 0;
  overflow: hidden;
  padding-bottom: 5px;
  padding-left: var(--row1-padding-left, 0px);
  padding-right: var(--row1-padding-right, 0px);
  border-bottom: 1px solid #aaa;
}

.card-primary > * {
  flex: 0 0 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.card-primary .queue-num {
  display: grid;
  place-items: center;
  min-width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--card-edge, var(--navy));
  color: #fff;
}

.card-primary .species-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  overflow: visible;
}

.card-primary .species-icon svg {
  width: 24px;
  height: 24px;
}

.card-primary a {
  color: #111;
  font-size: 24px;
  font-weight: 700;
  white-space: nowrap;
}

.card-primary .board-text-attending {
  max-width: 110px;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-left: auto;
  text-align: right;
}

/* Row 2: Secondary Exam Items Row (50px Padding) */
.card-secondary {
  display: flex !important;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
  min-width: 0;
  overflow: hidden;
  padding-top: 5px !important;
  padding-bottom: 2px !important;
  padding-left: var(--row2-padding-left, 50px) !important;
  padding-right: var(--row2-padding-right, 0px) !important;
  border-bottom: 0 !important;
}

.card-secondary .card-items {
  flex: 1 1 auto;
  max-width: none;
  /* min-width 기본값(auto)이면 항목 이름이 길 때 줄어들지 않아 우측 대기 시간이 밖으로 밀려 잘린다. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0 !important;
  font-size: var(--item-px, 18px) !important;
  font-weight: var(--item-weight, 500) !important;
  color: var(--item-color, #111) !important;
}

/* Row 3: Tertiary Purpose & Warnings Row (50px Padding) */
.card-tertiary {
  display: flex !important;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex-wrap: nowrap;
  min-width: 0;
  overflow: hidden;
  padding-top: 2px !important;
  padding-bottom: 5px !important;
  padding-left: var(--row3-padding-left, 50px) !important;
  padding-right: var(--row3-padding-right, 0px) !important;
  border-top: 0 !important;
  border-bottom: 0 !important;
}

/* 검사 목적이 있으면 왼쪽에 붙이고 나머지(경고 박스·검사 종료 후)는 justify-content로 우측 정렬한다. */
.card-tertiary .card-purpose {
  margin-right: auto;
}

.card-purpose {
  font-size: var(--purpose-px, 14px) !important;
  font-weight: var(--purpose-weight, 400) !important;
  color: var(--purpose-color, #333) !important;
}

/* Typography Custom Variables Dynamic Classes */
/* 탭은 모바일에서만 보이지만 규칙은 여기 함께 둔다(모바일 규칙보다 뒤에 오면 !important끼리 충돌한다). */
.board-text-tab { font-size: var(--tab-px) !important; font-weight: var(--tab-weight) !important; color: var(--tab-color) !important; }
/* 검사 수 <b>는 UA 기본 bold라 설정한 굵기를 덮는다(감염/보정 라벨과 같은 문제). */
.board-text-tab b { font-weight: inherit; }
.board-text-queue { font-size: var(--queue-px) !important; font-weight: var(--queue-weight) !important; color: var(--queue-color) !important; }
.board-text-status { font-size: var(--status-px) !important; font-weight: var(--status-weight) !important; color: var(--status-color) !important; }
.board-text-classification { font-size: var(--classification-px) !important; font-weight: var(--classification-weight) !important; color: var(--classification-color) !important; }
.board-text-name { font-size: var(--name-px) !important; font-weight: var(--name-weight) !important; color: var(--name-color) !important; }
.board-text-attending { font-size: var(--attending-px) !important; font-weight: var(--attending-weight) !important; color: var(--attending-color) !important; }
.board-text-estimated { font-size: var(--estimated-px) !important; font-weight: var(--estimated-weight) !important; color: var(--estimated-color) !important; }
.board-text-purpose { font-size: var(--purpose-px) !important; font-weight: var(--purpose-weight) !important; color: var(--purpose-color) !important; }
.board-text-species { font-size: var(--species-px) !important; font-weight: var(--species-weight) !important; color: var(--species-color) !important; }
.board-text-breed { font-size: var(--breed-px) !important; font-weight: var(--breed-weight) !important; color: var(--breed-color) !important; }
.board-text-infection { font-size: var(--infection-px) !important; font-weight: var(--infection-weight) !important; color: var(--infection-color) !important; }
.board-text-restraint { font-size: var(--restraint-px) !important; font-weight: var(--restraint-weight) !important; color: var(--restraint-color) !important; }
.board-text-oxygen { font-size: var(--oxygen-px) !important; font-weight: var(--oxygen-weight) !important; color: var(--oxygen-color) !important; }
.board-text-purpose_text { font-size: var(--purpose_text-px) !important; font-weight: var(--purpose_text-weight) !important; color: var(--purpose_text-color) !important; }
.board-text-item { font-size: var(--item-px) !important; font-weight: var(--item-weight) !important; color: var(--item-color) !important; }
.board-text-us { font-size: var(--us-px) !important; font-weight: var(--us-weight) !important; color: var(--us-color) !important; }
.board-text-reading { font-size: var(--reading-px) !important; font-weight: var(--reading-weight) !important; color: var(--reading-color) !important; }
.board-text-ctmr { font-size: var(--ctmr-px) !important; font-weight: var(--ctmr-weight) !important; color: var(--ctmr-color) !important; }
.board-text-post_exam { font-size: var(--post_exam-px) !important; font-weight: var(--post_exam-weight) !important; color: var(--post_exam-color) !important; }
.board-text-wait { font-size: var(--wait-px) !important; font-weight: var(--wait-weight) !important; color: var(--wait-color) !important; }

/* 감염/보정/산소 라벨은 <b>라 UA 기본 bold가 설정한 weight를 덮어썼다. 상속으로 되돌려 설정이 먹히게 한다. */
.warn-box b { font-weight: inherit; }

/* 대기 시간은 2열 우측. .card-items가 flex:1이라 자동으로 밀린다. 표시 여부는 설정이 --wait-display로 내린다. */
/* 카드 안 라벨을 아이콘으로 바꿨다(대기 시간=모래시계, 검사 목적=과녁). 크기는 그 자리의
   글자 크기를 따라가야 한다 — 폰트가 설정값이라 px로 박으면 설정을 바꿀 때마다 어긋난다. */
.card-inline-icon {
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.2em;
  flex: 0 0 auto;
}

/* 아이콘 크기는 설정(px)이 있으면 그 값을, 없으면 글자 크기를 따라간다(1.15em). */
.card-wait .card-inline-icon { width: var(--wait-icon-size, 1.15em); height: var(--wait-icon-size, 1.15em); }
.card-purpose .card-inline-icon { width: var(--purpose-icon-size, 1.15em); height: var(--purpose-icon-size, 1.15em); }

/* align-items:center로 아이콘과 hh:mm를 수직 중앙에 맞춘다(고정 높이 svg가 stretch면 위로 붙는다). */
.card-wait { display: var(--wait-display, inline-flex); align-items: center; gap: 4px; flex: 0 0 auto; white-space: nowrap; }

/* 방사선 카드는 3열이 없어 주의 마커·검사 종료 후가 2열 우측에 붙는다. .card-items가 flex:1이라 자동으로 밀린다. */
.card-secondary .warn-box { flex: 0 0 auto; white-space: nowrap; }

/* 감염/보정 박스는 뒤에 주의 문구가 붙으므로 inline·줄바꿈 허용 그대로 둔다. 칩(US·판독)만 한 줄로 고정한다. */
.warn-box { padding: 2px 9px; }
.warn-box-us, .warn-box-reading, .warn-box-ctmr, .warn-box-post_exam { display: inline-flex; align-items: center; white-space: nowrap; }
.warn-box-oxygen { background: var(--warn-oxygen-bg, #eaf3f8); border-radius: var(--warn-oxygen-radius, 999px); }
.warn-box-infection { background: var(--warn-infection-bg, #fdecea); border-radius: var(--warn-infection-radius, 999px); }
.warn-box-restraint { background: var(--warn-restraint-bg, #fff4e5); border-radius: var(--warn-restraint-radius, 999px); }
.warn-box-us { background: var(--warn-us-bg, var(--surface-alt)); border-radius: var(--warn-us-radius, 999px); }
.warn-box-reading { background: var(--warn-reading-bg, var(--surface-alt)); border-radius: var(--warn-reading-radius, 999px); }
.warn-box-ctmr { background: var(--warn-ctmr-bg, var(--surface-alt)); border-radius: var(--warn-ctmr-radius, 999px); }
.warn-box-post_exam { background: var(--warn-post_exam-bg, var(--surface-subtle)); border-radius: var(--warn-post_exam-radius, 999px); }

/* Status Dropdown Sync with Typography Settings */
/* 실측 자동폭 108.67px의 절반으로 고정(카드 실측 기준, 값 임의 확대 금지). */
.board-status-form select.board-text-status {
  font-size: var(--status-px) !important;
  font-weight: var(--status-weight) !important;
  color: var(--status-color) !important;
  min-height: auto;
  width: 54px;
  padding: 2px 2px;
  border: 1px solid currentColor;
  border-radius: 999px;
  background: #fff;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==========================================
   6. Completed List Floating Bar (Pinned at Bottom)
   ========================================== */
.completed-list {
  /* 컬럼 스크롤 컨테이너의 아래쪽에 붙는다. 카드가 넘치는 동안에는 카드 위에 떠 있고,
     끝까지 내리면 흐름상 제자리(마지막 카드 아래)에 놓여 카드를 가리지 않는다. */
  position: sticky;
  bottom: 0;
  z-index: 15;
  margin-top: auto;
  padding: 8px 0;
  background: var(--board-bg, var(--bg));
}

/* 머리글과 목록은 테두리·그림자를 이 박스 하나로만 그린다(예전에는 두 박스로 보였다). */
.completed-box {
  display: grid;
  grid-template-rows: auto 1fr;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 4px 14px rgba(23, 50, 77, 0.12);
  transition: grid-template-rows 200ms var(--ease-drawer);
}

/* C6: 3단계 순환의 "전부 접힘". display:none은 전환이 불가능해 grid 트랙을 0fr로 접는 방식으로 바꿨다.
   .completed-rows가 두 번째 트랙의 유일한 자식이라 트랙이 접히면 그 폭만큼 같이 접힌다. */
.completed-list.collapsed .completed-box {
  grid-template-rows: auto 0fr;
}

/* 0fr 트랙도 항목의 최소 크기는 남긴다 — 여백 12px + 테두리 1px이 빈 띠로 보였다(실측 13px).
   접힐 때 그것까지 없애야 머리글만 남는다. 여백은 레이아웃 속성이라 전환 없이 즉시 바꾼다. */
.completed-list.collapsed .completed-rows {
  padding-block: 0;
  border-top-width: 0;
}

.completed-list > .completed-box > button {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 12px;
  border: 0;
  border-radius: 0;
  background: #fff;
  color: var(--text);
  font-size: 13px;
  font-weight: 700;
  text-align: left;
}

/* 접힘 단계(기본 -> 전부 접힘 -> 전부 펼침)를 캐럿 모양으로 알린다. 지금 단계의 아이콘만 남긴다. */
.completed-caret {
  display: none;
  width: 16px;
  height: 16px;
  color: var(--muted);
}

.completed-list:not(.collapsed):not(.expanded) .completed-caret[data-completed-icon="default"],
.completed-list.collapsed .completed-caret[data-completed-icon="collapsed"],
.completed-list.expanded .completed-caret[data-completed-icon="expanded"] {
  display: block;
}

.completed-list > .completed-box > button b {
  display: grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #e8f2e8;
  color: #237346;
  font-size: 11px;
}

.completed-rows {
  max-height: 180px;
  min-height: 0;
  overflow: auto;
  padding: 6px 10px;
  border-top: 1px solid var(--divider-subtle);
  background: #fff;
}

.completed-list .completed-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  margin: 0;
  padding: 3px;
  border-bottom: 1px solid var(--divider-subtle);
  font-size: 12px;
}

.completed-list .completed-row > span {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.completed-patient {
  font-weight: 700;
}

/* C3: form은 select 하나만 감싸는데도 남는 폭을 다 먹었다 — 실측: flex-basis가 auto인 상태에서
   select의 width:100%가 부모(form)의 hypothetical main size 계산에 쓰여 폭이 요동친다.
   form을 내용 크기로 고정하면 select도 자기 내용 폭(약 50~60px)만 차지한다. */
.completed-list .completed-row form.board-status-form {
  flex: 0 0 auto;
}

.completed-species-icon {
  display: inline-grid;
  place-items: center;
  width: 14px;
  height: 14px;
  vertical-align: -3px;
}

.completed-species-icon svg {
  width: 14px;
  height: 14px;
}

/* 영상 담당자 미만은 상태를 읽기만 한다. 폭을 고정해야 뒤따르는 종·분류·이름·주치의가
   행마다 같은 x에서 시작한다("주치의 스캔"처럼 긴 값이 뒤 내용을 밀어내지 않게 한다).
   `.completed-row > span`이 특이도에서 이기므로 같은 깊이로 써야 flex가 먹는다. */
.completed-list .completed-row > .completed-status {
  flex: 0 0 74px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 12px;
}

.completed-list .completed-row > .completed-main {
  flex: 1 1 auto;
  text-align: left;
}

.completed-list .completed-row:last-child {
  border-bottom: 0;
}

.completed-list .completed-row select {
  height: 26px;
  min-height: 26px;
  padding: 0 4px;
}

/* C7: 완료 목록 상태 메뉴. 네이티브 select 팝업 대신 위로 열리도록 직접 띄운다(app.js). */
.status-menu {
  position: fixed;
  z-index: 80;
  display: flex;
  flex-direction: column;
  min-width: 94px;
  padding: 4px;
  border: 1px solid var(--border-control);
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 6px 18px rgba(23, 50, 77, 0.22);
}

.status-menu[hidden] {
  display: none;
}

.status-menu button {
  min-height: 30px;
  padding: 4px 10px;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--text);
  font-size: 12px;
  text-align: left;
  white-space: nowrap;
}

.status-menu button:active {
  background: #eef3f7;
}

.status-menu button[aria-selected="true"] {
  background: var(--navy);
  color: #fff;
}

/* 검사 종료 후 액션은 행 우측 끝에 붙인다. 폭을 고정해야 행마다 같은 x에서 시작한다
   (auto로 두면 "입원실"과 "처치실 대기"의 시작 위치가 달라 들쭉날쭉해 보인다). */
.completed-list .completed-row > .completed-post-exam {
  flex: 0 0 76px;
  white-space: nowrap;
  text-align: right;
}

.completed-list .completed-extra {
  display: none !important;
}

/* C7: display:block으로 되돌리면 행이 flex를 잃어 select가 flex 항목이 아니게 되고
   기본 규칙의 width:100%가 살아나 드롭다운이 행 전체를 먹었다. flex로 펼쳐야 한다. */
.completed-list.expanded .completed-extra {
  display: flex !important;
}

/* ==========================================
   7. Floating Action Buttons (FABs)
   ========================================== */
/* 우측 하단 3행: 위에서부터 더미 / 개 의뢰 / 고양이 의뢰. 44px 버튼 + 14px 간격. */
.dummy-fab {
  position: fixed;
  right: 18px;
  bottom: 134px;
  z-index: 40;
}

.dummy-fab > summary {
  cursor: pointer;
  list-style: none;
  width: 44px;
  height: 44px;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--navy);
  color: #fff;
  box-shadow: 0 4px 12px #0003;
}

.dummy-fab > summary::-webkit-details-marker {
  display: none;
}

.dummy-fab > summary .tabler-icon {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.request-fabs {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 40;
  display: grid;
  gap: 14px;
}

.request-fab {
  width: 44px;
  height: 44px;
  min-height: 44px;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 999px;
  background: var(--navy);
  color: #fff;
  box-shadow: 0 4px 12px #0003;
}

.request-fab svg {
  width: 26px;
  height: 26px;
}

.dummy-fab form {
  position: absolute;
  right: 0;
  bottom: 52px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  width: 300px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 4px 12px #0002;
}

.dummy-fab:not([open]) form {
  display: none;
}

.dummy-fab form label {
  font-size: 12px;
}

.dummy-fab fieldset {
  display: contents;
}

.dummy-fab fieldset label {
  display: flex;
  justify-content: center;
  white-space: nowrap;
}

.dummy-count-label {
  grid-column: 1 / -1;
  display: flex !important;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  font-size: 12px;
}

/* 생성 개수 드롭다운은 한 자리 숫자뿐이라 좁혀도 된다 — 넓으면 라벨이 줄바꿈된다. */
.dummy-count-label select, .dummy-count-label input {
  flex: 0 0 auto;
  width: 52px;
  min-height: 26px;
  padding: 2px 4px;
}

/* 생성/삭제/완료를 한 줄에. 패널 폭 300px 기준 버튼 하나가 약 1/4(=패널의 1/3 - 여백)이다. */
.dummy-bulk-actions {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
}

.dummy-bulk-actions button {
  width: 100%;
  min-height: 30px;
  padding: 0 4px;
  font-size: 12px;
}

.typography-fab {
  position: fixed;
  left: 18px;
  bottom: 76px;
  z-index: 30;
}

.typography-fab > summary {
  cursor: pointer;
  list-style: none;
  width: 44px;
  height: 44px;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--navy);
  color: #fff;
  box-shadow: 0 4px 12px #0003;
}

.typography-fab > summary::-webkit-details-marker {
  display: none;
}

.typography-fab > summary .tabler-icon {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.typography-fab .typography-panel {
  position: absolute;
  left: 0;
  bottom: 42px;
  display: grid;
  gap: 7px;
  width: 420px;
  max-height: calc(100vh - 120px);
  overflow: auto;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 4px 12px #0002;
}

.typography-fab form {
  display: grid;
  gap: 7px;
}

.typography-fab:not([open]) .typography-panel {
  display: none;
}

.board-time-actions {
  display: flex;
  gap: 6px;
}

.board-time-actions button {
  min-height: 30px;
  font-size: 12px;
}

.typography-fab .typography-row,
.typography-fab .layout-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  border: 0;
}

/* 항목명·크기·굵기·글자색·배경색·라운드가 행마다 같은 x좌표에 서도록 고정폭 격자로 세운다
   (flex-wrap은 라벨 길이에 따라 어긋난다). 배경/라운드가 없는 항목은 뒤 두 칸이 비어 정렬만 유지된다. */
.typography-fab .typography-row {
  display: grid;
  grid-template-columns: 92px 50px 70px 20px 20px 50px;
  justify-content: start;
}

.typography-fab .settings-section-title {
  margin: 4px 0 0;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
}

/* C-4: 고급 섹션 <details>. 패널 전체가 이미 overflow:auto라(위 .typography-panel) 펼쳐져 길어져도
   그 안에서 스크롤된다 — 별도 max-height가 필요 없다. summary는 위 .settings-section-title 규칙을
   클래스로 그대로 물려받으므로(같은 글자 스타일) 여기서는 커서만 더한다. */
.typography-fab .typography-advanced {
  margin: 4px 0 0;
  /* 안의 필드셋들이 폼의 grid(gap:7px)에서 한 단 더 들어가며 간격을 잃는다 — 여기서 같은 gap을 다시 준다. */
  display: grid;
  gap: 7px;
}

.typography-fab .typography-advanced > summary {
  cursor: pointer;
}

.typography-fab .typography-row .row-legend,
.typography-fab .typography-row legend,
.typography-fab .layout-row legend {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 600;
  padding: 0;
}

.typography-fab .typography-row label,
.typography-fab .layout-row label {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  white-space: nowrap;
}

.typography-fab .typography-row input,
.typography-fab .typography-row select,
.typography-fab .layout-row input,
.typography-fab .layout-row select {
  height: 26px;
  min-height: 26px;
  width: 70px;
  padding: 0 4px;
}

.typography-fab input[type="number"] {
  width: 50px;
}

.typography-fab .queue-order-row .queue-order-input,
.typography-fab .queue-order-row input {
  width: 100%;
}

.typography-fab .queue-order-row {
  flex-wrap: nowrap;
}

.typography-fab .typography-hint {
  margin: 0;
  font-size: 11px;
  color: var(--muted);
}

/* 모바일 하단 네비게이션 바. 데스크톱은 양측 하단 플로팅 버튼을 그대로 쓰므로 감춘다.
   기본 규칙이 미디어쿼리보다 뒤에 오면 모바일에서도 계속 숨겨지므로 반드시 여기(앞)에 둔다. */
.board-nav {
  display: none;
}

/* ==========================================
   8. Responsive Media Queries (@media <= 900px)
   ========================================== */
@media (max-width: 900px) {
  .brand {
    font-size: 18px;
  }

  .sidebar {
    width: min(260px, 82vw);
  }

  .sidebar nav a {
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  /* Mobile Board View & Tabs */
  .board-workspace {
    padding: 10px;
  }

  .board-tabs {
    display: grid !important;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    position: sticky;
    top: 0;
    z-index: 20;
    margin-bottom: 10px;
    padding: 4px;
    background: var(--warn-tab-bg, #dfe8ee);
    border-radius: var(--warn-tab-radius, 999px);
  }

  .board-tabs button {
    /* B-2: 모바일에서 가장 많이 눌리는 컨트롤(컬럼 전환)이다. 42px였던 것을 최소 터치 타깃에 맞춘다.
       화면 상단이라 2px 늘어나도 아래 컬럼 높이만 그만큼 줄고 겹치는 것은 없다. */
    min-height: 44px;
    padding: 5px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: #425466;
    font-size: 12px;
    font-weight: 700;
  }

  .board-tabs button[aria-selected="true"] {
    background: #fff;
    color: var(--navy);
    box-shadow: 0 1px 5px #0002;
  }

  .worklist-board {
    display: block;
  }

  .kanban-column {
    display: none;
    min-height: 0;
    border-left: 0;
    border-top: 0;
  }

  .kanban-column.active {
    display: flex;
  }

  .card-primary, .card-secondary, .card-tertiary {
    flex-wrap: nowrap !important;
  }

  .card-primary > * {
    flex: 0 0 auto;
  }

  .card-primary .board-text-attending {
    max-width: 90px;
  }

  .card-secondary, .card-tertiary {
    padding-left: 0 !important;
  }

  /* 모바일도 데스크톱과 같은 3행 순서를 지킨다: 더미 / 개 / 고양이. 좌우 여백만 10px로 좁힌다. */
  /* 하단 네비게이션 바. 좌측에 컬럼 이동·검사 의뢰, 우측에 설정·메뉴·더미가 선다.
     설정/메뉴/더미는 base.html과 board.html에 흩어져 있어 바 안으로 옮길 수 없다 —
     대신 바와 같은 높이에 고정 좌표로 세워 한 줄처럼 보이게 한다. */
  .board-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    /* 배치는 설정값(균등/넓게/가운데/왼쪽)이 곧 justify-content다.
       버튼 수는 권한마다 다르지만 flex가 남는 폭을 나눠 항상 같은 간격이 된다. */
    justify-content: var(--nav-align, space-between);
    gap: 2px;
    height: 56px;
    padding: 0 6px;
    border-top: 1px solid var(--line);
    background: var(--nav-bg-color, var(--navy));
    box-shadow: 0 -2px 10px #17324d1a;
  }

  /* 자리표시자는 옮겨올 버튼의 DOM 위치만 알려준다. flex 항목으로 남으면 폭이 0이어도
     justify-content가 그 자리에도 간격을 나눠 줘 버튼 간격이 들쭉날쭉해진다. */
  .nav-slot {
    display: none;
  }

  /* 버튼 수는 권한과 화면마다 다르다. grow 없이 shrink만 허용해 두면
     자리가 남을 때는 배치 설정(justify-content)이 정하고, 모자랄 때는 고르게 줄어든다. */
  .board-nav-item {
    flex: 0 1 44px;
    display: grid;
    place-items: center;
    min-width: 0;
    width: 44px;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--nav-icon-color, #ffffff);
  }

  .board-nav-item svg {
    width: var(--nav-icon-size, 28px);
    height: var(--nav-icon-size, 28px);
    max-width: 100%;
  }

  /* 양 끝 탭에서는 이동할 곳이 없다 — 흐리게 해서 막혔다는 것을 보여준다. */
  .board-nav-item:disabled {
    opacity: 0.35;
  }

  /* 바로 옮겨진 버튼들(사이드바·더미·설정)은 흐름 안의 항목이 된다. */
  .board-nav .dummy-fab, .board-nav .typography-fab, .board-nav .menu-fab {
    position: relative;
    left: auto;
    right: auto;
    bottom: auto;
    flex: 0 1 44px;
    min-width: 0;
  }

  .board-nav > .in-nav > summary {
    width: 100%;
    max-width: 44px;
    height: 44px;
    background: transparent;
    color: var(--nav-icon-color, #ffffff);
    box-shadow: none;
  }

  .board-nav > .in-nav > summary .tabler-icon {
    width: var(--nav-icon-size, 28px);
    height: var(--nav-icon-size, 28px);
    max-width: 100%;
  }

  /* 바 안에서 열리는 패널은 버튼 위로 띄운다. */
  .board-nav .dummy-fab form {
    right: auto;
    left: 50%;
    transform: translateX(-50%);
    max-width: calc(100vw - 16px);
  }

  /* 검사 의뢰 버튼은 바 안으로 들어갔으므로 플로팅 버전은 감춘다. */
  .request-fabs {
    display: none;
  }

  /* 바에 자리가 없는 사이드바 버튼(화면 권한이 관리자가 아닐 때)은 모바일에서 아예 감춘다.
     떠 있는 채로 두면 바 위에 겹쳐 뜬다. */
  .menu-fab:not(.in-nav) {
    display: none;
  }

  /* 설정 패널은 420px라 버튼 기준으로 열면 화면을 넘긴다. 화면 폭에 맞춰 띄운다. */
  .board-nav .typography-fab .typography-panel {
    position: fixed;
    left: 8px;
    right: 8px;
    bottom: 62px;
    width: auto;
    max-height: calc(100vh - 140px);
  }


  /* 바에 가리지 않도록 워크리스트와 완료 목록을 위로 올린다. */
  .board-workspace {
    padding-bottom: 62px;
  }

  /* 컬럼 자체가 이미 하단 바 높이만큼 위에서 끝난다(.board-workspace의 padding-bottom).
     여기서 또 56px를 띄우면 그만큼 카드 볼 자리가 사라진다 — 스크롤 끝에 딱 붙인다. */
  .completed-list {
    bottom: 0;
    padding-bottom: 0;
  }

  /* 일정 화면의 마지막 박스라 하단 바에 그대로 깔린다. 바 높이만큼 아래를 비운다. */
  .weekly-off-settings {
    margin-bottom: 62px;
  }
}

/* B1/B2: 모바일에서는 카드/완료 목록 좌우 여백을 8px로 좁히고 워크리스트 헤딩을 감춘다.
   카드 안쪽 여백(--card-padding-*)은 설정값이라 건드리지 않고, 카드를 담는 컬럼의 좌우 패딩만 줄인다.
   .board-workspace가 위 900px 쿼리에서 이미 10px 좌우 패딩을 갖고 있어 그대로 두면 10+8=18px가 되므로 여기서 0으로 비운다.
   이 블록은 900px 쿼리보다 뒤에 와야 한다(동일 특이도에서는 소스 순서가 이긴다). */
@media (max-width: 700px) {
  .board-workspace {
    padding-left: 0;
    padding-right: 0;
  }

  .kanban-column {
    padding-left: 10px;
    padding-right: 10px;
  }

  /* 모바일은 한 컬럼만 보이므로 px 폭 설정 대신 화면 폭에 맞춘다. */
  .worklist-board {
    grid-template-columns: minmax(0, 1fr);
    overflow-x: hidden;
  }

  .worklist-heading {
    display: none;
  }
}

.calendar-month-nav .tabler-icon{width:16px;height:16px}

.calendar-header-centered .calendar-month-label{position:absolute;left:50%;transform:translateX(-50%)}.calendar-month-nav .tabler-icon{width:20px;height:20px}

.catalog-settings-form{width:min(800px,100%);margin-inline:auto}.catalog-settings-group{width:100%}.catalog-duration-grid{display:grid;gap:6px;margin-top:8px}.duration-grid-3{grid-template-columns:repeat(3,minmax(0,1fr))}.duration-spaced{column-gap:30px}.duration-item{display:grid;grid-template-columns:minmax(0,1fr) 50px;align-items:center;gap:5px;min-width:0;white-space:nowrap}.duration-item>span{overflow:hidden;text-overflow:ellipsis}.catalog-settings-form .minutes{width:50px;height:26px;padding:0 4px;text-align:center;-moz-appearance:textfield}.catalog-settings-form .minutes::-webkit-inner-spin-button,.catalog-settings-form .minutes::-webkit-outer-spin-button{margin:0;-webkit-appearance:none}@media(max-width:700px){.duration-grid-3{grid-template-columns:repeat(2,minmax(0,1fr))}}

.request-layout-root{justify-items:center}.request-layout-row{justify-content:center;justify-items:center;width:100%}.calendar-header{position:relative;display:flex;align-items:center;justify-content:center;min-height:28px;margin-bottom:5px}.calendar-month-label{font-size:17px;font-weight:700}.calendar-month-nav{position:absolute;right:0;display:inline-flex;align-items:center;gap:3px}.calendar-month-nav a{display:inline-flex;align-items:center;justify-content:center;min-width:28px;height:28px;padding:0 5px;color:inherit;text-decoration:none;border:1px solid var(--line);border-radius:4px}.calendar-month-nav .tabler-icon{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
/* ==========================================
   9. 검사 로그 필터·선택 삭제
   ========================================== */
/* input의 기본 width:100%가 라벨마다 줄바꿈을 만든다. 조회 조건은 한 줄에 세운다. */
.filter-grid {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.filter-grid label {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.filter-grid input, .filter-grid select {
  width: auto;
  min-width: 0;
}

.log-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

.log-table .log-select {
  width: 34px;
  text-align: center;
}

/* 로그 표는 컬럼이 많아 자연 폭이 화면보다 넓다. 두 박스를 한 래퍼에 넣고 래퍼가
   표의 자연 폭을 따라가게 해서 조회 조건 박스와 리스트 박스의 가로폭을 붙여 둔다. */
.log-page {
  display: grid;
  gap: 12px;
  width: min(var(--log-panel-width, 1400px), 100%);
  margin-inline: auto;
}

.log-page > * {
  width: 100%;
  min-width: 0;
}

/* 표는 컬럼이 많아 좁은 화면에서 넘친다. 감싸는 칸 안에서 가로로 밀리게 해야
   페이지 자체가 넓어지지 않는다(넓어지면 하단 바가 화면 밖까지 늘어난다). */
.table-wrap {
  overflow-x: auto;
}

.log-table {
  width: 100%;
  border-collapse: collapse;
}

.log-table th, .log-table td {
  padding: 6px 5px;
  border: 1px solid var(--line);
  white-space: nowrap;
}

.log-table th {
  background: #f4f7f9;
  text-align: left;
}

/* ==========================================
   11. 계정 관리
   ========================================== */
/* 계정 생성 박스는 입력 3개뿐이라 화면 폭을 다 쓸 이유가 없다. 목록과 같은 행에 세운다. */
.accounts-page {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) minmax(0, 2fr);
  align-items: start;
  gap: 12px;
}

.accounts-page .account-create-grid {
  display: grid;
  gap: 8px;
}

.accounts-table {
  width: 100%;
  border-collapse: collapse;
}

.accounts-table th, .accounts-table td {
  padding: 6px 5px;
  border: 1px solid var(--line);
  text-align: left;
}

.account-actions {
  display: grid;
  gap: 6px;
  margin-top: 6px;
}

.account-actions .inline {
  display: flex;
  align-items: center;
  gap: 6px;
}

.account-actions input, .account-actions select {
  width: auto;
  min-width: 0;
}

.account-manage > summary {
  cursor: pointer;
}

@media (max-width: 900px) {
  .accounts-page {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ==========================================
   10. 카드 영상실 이동(드래그 앤 드롭)
   ========================================== */
.kanban-card[draggable="true"] {
  cursor: grab;
}

/* 드래그 중 원본 카드는 자리만 흐리게 남긴다. */
.kanban-card.dragging {
  opacity: 0.55;
}

/* 실제 드래그 프리뷰. 화면 밖에 두고 setDragImage로 쓴다 — 복제본이라 컬럼에 잘리지 않아
   카드 네 변이 모두 보이고, 투명도 30%가 그대로 프리뷰에 찍힌다. */
.kanban-card.drag-ghost {
  position: fixed;
  top: -3000px;
  left: -3000px;
  opacity: 0.3;
  border: 1px solid var(--divider-color, var(--blue));
  border-radius: var(--card-radius, 26px);
  background: #fff;
  pointer-events: none;
}

/* 순번 드롭 위치 표시 */
.kanban-card.drop-before {
  box-shadow: inset 0 3px 0 var(--navy);
}

.kanban-card.drop-after {
  box-shadow: inset 0 -3px 0 var(--navy);
}

.kanban-column.drop-target {
  outline: 2px dashed var(--navy);
  outline-offset: -4px;
}

/* 대기/진행 배경 박스. 영상 담당자 미만은 텍스트라 배경+라운드를 다 받고,
   드롭다운은 라운드만 공유한다(배경을 칠하면 네이티브 화살표가 묻힌다). */
.warn-box-status { background: var(--warn-status-bg, var(--surface-subtle)); border-radius: var(--warn-status-radius, 999px); }
.board-status-form select.board-text-status { border-radius: var(--warn-status-radius, 999px); }

/* 검사 로그: 내용이 짧은 열은 폭을 내용에 맞춘다. 환자·검사만 남는 폭을 나눠 갖는다. */
.log-table th, .log-table td { width: 1%; }
.log-table th.patient-column, .log-table td.patient-column,
.log-table th:nth-child(5), .log-table td:nth-child(5) { width: auto; }
.log-table td:nth-child(5) { white-space: normal; }

/* 계정 관리: 입력 높이 20px, 생성 박스 입력 폭 1/3, 셀 상단 정렬 */
.accounts-page input, .accounts-page select {
  height: 20px;
  min-height: 20px;
  padding: 0 4px;
  font-size: 12px;
}

.accounts-page .account-create-grid input, .accounts-page .account-create-grid select {
  width: 33%;
  min-width: 90px;
}

.accounts-page .account-create-grid label {
  display: grid;
  gap: 3px;
  font-size: 12px;
}

.accounts-table th, .accounts-table td {
  vertical-align: top;
}

.account-actions label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  white-space: nowrap;
}

.account-actions button, .accounts-page .account-create-grid button {
  min-height: 24px;
  padding: 0 8px;
  font-size: 12px;
}

/* 우측 하단 단일값 설정 FAB(검사 로그·계정 관리). 일정 설정 FAB과 같은 모양이다. */
.simple-layout-fab { position: fixed; right: 18px; bottom: 18px; z-index: 45; }
.simple-layout-fab > summary { cursor: pointer; list-style: none; width: 44px; height: 44px; padding: 0; display: grid; place-items: center; border-radius: 999px; background: var(--navy); color: #fff; box-shadow: 0 4px 12px #0003; }
.simple-layout-fab > summary::-webkit-details-marker { display: none; }
.simple-layout-fab > summary .tabler-icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.simple-layout-fab > form { position: absolute; right: 0; bottom: 52px; display: grid; gap: 8px; width: min(280px, calc(100vw - 20px)); padding: 12px; border: 1px solid var(--line); border-radius: 10px; background: #fff; box-shadow: 0 8px 24px #0003; }
.simple-layout-fab h2 { margin: 0; font-size: 15px; }
.simple-layout-fab label { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; white-space: nowrap; }
.simple-layout-fab input { width: 80px; height: 26px; min-height: 26px; padding: 0 4px; }

/* 계정 관리 텍스트 입력칸 폭은 설정값을 따른다. */
.accounts-page input[type="text"], .accounts-page input[type="password"] {
  width: var(--account-input-width, 150px);
  max-width: 100%;
}

/* 로그아웃 확인 팝업 */
.confirm-dialog {
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
}

.confirm-dialog::backdrop {
  background: #17324d55;
}

.confirm-dialog form {
  display: grid;
  gap: 14px;
  padding: 20px;
}

.confirm-dialog p {
  margin: 0;
  font-size: 15px;
  text-align: center;
}

.confirm-dialog .dialog-actions {
  justify-content: center;
}

/* 모바일에서는 연도 이동 버튼과 겹치므로 월 표기를 좌측에 붙인다(데스크톱은 가운데 그대로).
   가운데 정렬 규칙이 파일 뒤쪽 압축 블록에 있어 이 규칙도 그보다 뒤에 있어야 이긴다. */
@media (max-width: 900px) {
  .calendar-header-centered .calendar-month-label {
    position: static;
    left: auto;
    transform: none;
    margin-right: auto;
  }
}

/* 공통-2 (4): prefers-reduced-motion. 0으로 죽이지 않는다 — 이동(transform)만 없애고 opacity 전환은 남긴다.
   파일 맨 끝에 둬서 특이도가 같은 위 규칙들을 소스 순서로 확실히 이긴다. */
@media (prefers-reduced-motion: reduce) {
  button:active, .button:active,
  .dummy-fab > summary:active, .typography-fab > summary:active, .menu-fab > summary:active,
  .simple-layout-fab > summary:active, .schedule-layout-fab > summary:active,
  .board-nav-item:active,
  .staff-calendar-day:active, .status-menu button:active {
    transform: none;
  }

  /* 팝업: opacity 전환은 유지하고 scale 전환만 뺀다(값 자체는 바뀌지만 애니메이션 없이 즉시 반영된다). */
  .confirm-dialog, .slot-edit-dialog, .schedule-dialog {
    transition: opacity 200ms var(--ease-out);
  }

  /* 접기/펼치기: 전환 제거(즉시 토글). */
  .completed-box {
    transition: none;
  }

  /* 진행 중 카드 테두리 선: 애니메이션만 끄면 18% 조각이 좌상단에 멈춰 오류처럼 보인다.
     대신 끊김 없는 실선 테두리로 바꿔 형태 인코딩(진행 중 = 선이 두른다)은 유지한다. */
  /* 회전만 멈춘다. 그라디언트 테두리 자체는 남아 진행 중이라는 형태 인코딩을 유지한다. */
  .kanban-card.status-in_progress {
    animation: none;
  }
}
