/* 화면 전체의 배치와 겉모습
 *
 * 파일이 넷으로 나뉜다. **불러오는 순서가 곧 우선순위**다.
 *
 *   tokens.css      색·간격·크기의 이름 (값은 여기서만 정한다)
 *   components.css  버튼·탭 같은 조각 (Figma 디자인 시스템)
 *   style.css       이 파일 — 화면 배치와 각 영역
 *   summary.css     요약 본문 (표·카드·출처 표시)
 *
 * 이 파일은 위에서 아래로 **바깥에서 안쪽** 순서다. 기본값 → 머리글 →
 * 3분할 레이아웃 → 각 패널 → 그 안의 기능들. 반응형은 한자리에 모아 두었다.
 *
 * 구획
 *   기본값 · 초기화
 *   머리글
 *   3분할 레이아웃
 *   왼쪽 — 업로드
 *   왼쪽 — 환자 목록
 *   가운데 — 요약 패널
 *   오른쪽 — 원본 뷰어
 *   바닥글
 *   요약 검색
 *   로딩 · 하이라이트
 *   반응형 — 화면 폭별 재정의
 *   알림 — OCR 오류
 *   요약 상태 — 비어 있음 · 추출 중 · 실패
 *   페이지 이동 · 확대
 *   임베드 모드 (EMR 안에서 열릴 때)
 *   뷰어 접기 · 펼치기 · 분할
 *   데모 무대 (이 저장소에서만 쓴다)
 *   편집 모드
 *   격자 보기
 *   요약 목차
 *   표 · 카드 편집
 *   토스트
 *   비밀번호 관문 (데모 전용)
 *
 * 색을 직접 적지 않는다 — `var(--color-*)` 를 쓴다. 없는 색이 필요하면
 * tokens.css 에 이름을 먼저 만든다. 그래야 브랜드를 갈아 끼울 수 있다.
 *
 * 화면 폭은 **두 가지 형태**만 있다. 새 기준점을 만들지 않는다 — 파일마다 다른
 * 값을 쓰면 어느 폭에서는 배치만 모바일이고 본문은 데스크톱인 상태가 된다
 * (실제로 요약 본문이 768px 을 쓰고 있어 769~900px 에서 그랬다).
 *
 *   max-width: 900px    데스크톱 → **모바일**. 3분할이 풀리고 시트로 열린다.
 *                       style.css · summary.css 가 같은 값을 쓴다.
 *   max-width: 480px    좁은 폰 보정. 형태는 그대로고 자리만 아낀다.
 *
 * 아래 셋은 형태를 바꾸지 않는다 — 데스크톱 안에서 크기만 단계적으로 준다.
 * 위 둘과 성격이 다르므로 같은 자리에 두지 않았다.
 *
 *   min-width: 1920px · max-width: 1600px · max-width: 1200px   왼쪽 패널 폭
 *   max-width: 1200px   버튼 글자 감추기
 *   max-width: 1024px   확대 버튼 감추기
 */

/* Pretendard 폰트 불러오기 */
/* 폰트는 로컬 파일 사용 (병원 내부망에서 CDN 접근 불가할 수 있음) */
@import url('../fonts/pretendard/pretendard.css');

/* 브랜드 색 기본값 (인하대병원).
 * 실제 값은 app/branding.py 가 <html style="..."> 로 덮어쓴다.
 * 여기 값은 템플릿 없이 CSS 만 볼 때의 폴백이다. */
:root {
    --brand-page-bg: #f5f5f5;
    --brand-surface: #f8f9fa;
    --brand-header: linear-gradient(135deg, #0072CE 0%, #004B87 100%);
    --brand-primary: #0770BB;
    --brand-primary-dark: #055a9a;
    --brand-primary-soft: #e8f4fc;
    --brand-primary-rgb: 7, 112, 187;
    --brand-accent-end: #055fa0;
}

/* ==========================================================================
 * 기본값 · 초기화
 * ========================================================================== */

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: var(--font-family-base);
    background-color: var(--brand-page-bg);
    color: var(--color-text-primary);
    line-height: 1.6;
    height: 100vh;
    overflow: hidden;
}

.container {
    width: 100%;  /* 전체 너비 사용 */
    margin: 0;
    background-color: white;
    height: 100vh;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
    display: flex;
    flex-direction: column;
}

/* ==========================================================================
 * 머리글
 * ========================================================================== */

.header {
    background: var(--brand-header);
    color: white;
    padding: 15px 20px;
    flex-shrink: 0;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.header-content {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0 15px;  /* 좌우 패딩 추가 */
}

.logo-section {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 14px;  /* 브랜드에 따라 로고가 2개 이상일 수 있다 */
}

/* 높이는 브랜드별로 다르므로 템플릿이 인라인으로 지정한다 */
.brand-logo {
    width: auto;
}

/* 컬러 로고를 어두운 헤더 위에서 흰색으로 반전 */
.brand-logo--invert {
    filter: brightness(0) invert(1);
}

.title-section {
    flex: 1;
    text-align: center;
    padding: 0 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.title-section h1 {
    font-size: var(--font-size-2xl);
    font-weight: 700;
    margin: 0 0 0 0;
    letter-spacing: -0.2px;
    white-space: nowrap;
}

.subtitle-en {
    font-size: var(--font-size-rem-16);
    color: rgba(255, 255, 255, 0.85);
    margin: -7px 0 0 0;
    font-weight: 300;
    /* font-style: italic; */
}

.powered-by {
    font-size: var(--font-size-rem-7);
    color: rgba(255, 255, 255, 0.9);
    margin: 10px 0 0 0;
    font-style: italic;
    opacity: 1;
    letter-spacing: 0.3px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.header-right {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
}

/* 화면 언어 선택 — 링크 둘 (KO · EN). 지금 언어는 채워서 보인다
 * 모양은 모든 브랜드가 같고 색만 브랜드 테마(--brand-chip-* · --brand-toggle-on-*)가 정한다.
 * 링크로 두는 이유 — 언어는 주소가 정하므로 JS 없이도 바뀌고 그 주소를 그대로 건넬 수 있다 */
.lang-switch {
    display: flex;
    gap: 2px;
    padding: 3px;
    border-radius: var(--radius-full);
    background: var(--brand-chip-bg, rgba(255, 255, 255, 0.2));
    /* 테두리는 안쪽 선으로 — 크기를 바꾸지 않아 토글과 배지가 같은 36px 다 */
    box-shadow: inset 0 0 0 1px var(--brand-chip-border, rgba(255, 255, 255, 0.55));
}

.lang-switch a {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-width: 44px;
    height: 30px;
    padding: 0 12px;
    border-radius: var(--radius-full);
    font-size: var(--font-size-control);
    font-weight: 700;
    line-height: 1;
    color: inherit;
    text-decoration: none;
}

.lang-switch a:hover {
    background: rgba(255, 255, 255, 0.15);
}

.lang-switch a[aria-current="true"] {
    background: var(--brand-toggle-on-bg, rgba(255, 255, 255, 0.9));
    color: var(--brand-toggle-on-fg, var(--brand-primary, #0770bb));
}

.lang-switch a:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

.hospital-info {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0;
    justify-content: center;
}

/* 버전 배지 — 언어 토글과 같은 바탕색. 모양은 모든 브랜드가 같다 */
.system-version {
    display: flex;
    align-items: center;
    box-sizing: border-box;
    height: 36px;
    padding: 0 14px;
    border-radius: var(--radius-full);
    font-size: var(--font-size-control);
    /* 토글과 같게 — 물려받은 줄 높이면 디센더 자리만큼 글자가 위로 뜬다 */
    line-height: 1;
    background: var(--brand-chip-bg, rgba(255, 255, 255, 0.2));
}

/* ==========================================================================
 * 3분할 레이아웃
 * ========================================================================== */

.main-content {
    display: grid;
    grid-template-columns: minmax(280px, 300px) 1fr;  /* 환자 목록 + 무대 */
    gap: 15px;
    padding: 15px;
    flex: 1;
    min-height: 0;
    overflow: visible;
    width: 100%;  /* 전체 너비 사용 */
}

/* 좌측 패널 */
.left-panel {
    background-color: var(--brand-surface);
    border-radius: var(--radius-lg);
    padding: 20px;
    border: var(--border-width) solid var(--color-border-strong);
    height: 100%;
    max-height: calc(100vh - 160px); /* 헤더와 footer 높이 고려 */
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* ==========================================================================
 * 왼쪽 — 업로드
 * ========================================================================== */

.upload-section {
    display: block;
    flex-shrink: 0;
    margin-bottom: 20px;
}

.upload-section h2 {
    font-size: var(--font-size-rem-15);
    margin-bottom: 10px;
    color: var(--color-text-heading);
    border-bottom: var(--border-width) solid var(--color-border-strong);
    padding-bottom: 5px;
}

/* 파일 선택 — 넓은 면을 진한 단색으로 채우면 값싸 보인다. 옅은 바탕 + 한 단계
 * 진한 테두리 + 진한 글씨로 층을 만든다. 그림자로 띄우지 않는다
 * (디자이너 원칙: 깊이감은 주목이 필요한 곳에만). */
.upload-btn {
    width: 100%;
    padding: 12px;
    background-color: var(--brand-primary-soft);
    color: var(--brand-primary-dark);
    border: var(--border-width) solid var(--brand-primary-border);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-rem-11);
    cursor: pointer;
    transition:
        background-color 0.15s ease,
        border-color 0.15s ease;
    margin-bottom: 10px;
    font-weight: 500;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
}

.btn-icon svg {
    width: 18px;
    height: 18px;
    display: block;
}

.upload-btn:hover {
    background-color: var(--brand-primary-tint-hover);
    border-color: var(--brand-primary);
}

/* ==========================================================================
 * 왼쪽 — 환자 목록
 * ========================================================================== */

.file-list-section {
    margin-top: 10px;
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

.file-list-section h3 {
    font-size: var(--font-size-rem-13);
    color: var(--color-text-neutral-strong);
    margin-bottom: 10px;
    border-bottom: var(--border-width) solid var(--color-border-strong);
    padding-bottom: 5px;
    flex-shrink: 0;
}

.file-list {
    list-style: none;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 0;
    margin: 0;
}

/* 환자 목록의 항목 — 사이드바 네비게이션이다.
 *
 * 카드마다 테두리를 두르고 그림자를 깔면 목록이 카드 더미가 된다. 여기서 고르는
 * 것은 '문서' 가 아니라 '지금 볼 환자' 라 목록은 조용해야 한다. 테두리 없이
 * 바탕만으로 상태(호버·선택)를 말한다.
 *
 * (upstage 에서만 이렇게 하고 있었다. 목록 모양은 브랜드가 정할 일이 아니다.) */
.file-item {
    background-color: transparent;
    border: none;
    border-radius: var(--radius-sm);
    padding: 10px;
    margin-bottom: var(--spacing-2xs);
    color: var(--color-text-primary);
    font-size: var(--font-size-rem-8);
    cursor: pointer;
    transition:
        background-color 0.15s ease,
        color 0.15s ease;
    display: flex;
    align-items: center;
    gap: 10px;
    /* 진행 막대가 아래 줄로 떨어지도록 (flex-basis: 100%) */
    flex-wrap: wrap;
}

/* 환자 수 배지 (섹션 제목 옆) */
.list-count {
    display: inline-block;
    min-width: 20px;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    background-color: var(--brand-primary-soft);
    color: var(--brand-primary);
    font-size: var(--font-size-rem-4);
    font-weight: 600;
    text-align: center;
    vertical-align: 2px;
}

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

/* 상태·삭제를 오른쪽 끝에 모아 한 줄의 균형을 잡는다 */
.file-trailing {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}

/* 처리 중일 때만 나오는 진행 막대 */
.file-progress {
    flex: 0 0 100%;
    height: 3px;
    margin-top: 8px;
    border-radius: var(--radius-full);
    background-color: var(--color-bg-pressed);
    overflow: hidden;
}

.file-progress span {
    display: block;
    height: 100%;
    border-radius: var(--radius-full);
    background-color: var(--brand-primary);
    transition: width 0.4s ease;
}

/* 다른 목록·표와 같은 규칙 — 바탕이 한 단계 어두워진다 */
.file-item:hover {
    background-color: var(--color-bg-muted);
}

/* 파일 아이템 내부 구조.
 * 아이콘은 맨 아이콘이 아니라 색 타일에 올린다 (Upstage 의 featured icon 방식).
 * 목록이 글자만 있을 때의 허전함을 없애고, 선택 상태의 기준점이 된다. */
.file-item .file-icon {
    width: 34px;
    height: 34px;
    border-radius: var(--radius-sm);
    background-color: var(--brand-primary-soft);
    color: var(--brand-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* 선 아이콘 (js/icons.js · 템플릿의 인라인 SVG).
 * 이모지와 달리 currentColor 를 따르므로 브랜드 색·선택 상태에 맞춰진다. */
.file-item .file-icon svg {
    width: 18px;
    height: 18px;
    display: block;
}

/* 상태 점 — 배지의 글자색을 그대로 따라간다 */
.status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: currentColor;
    display: inline-block;
    margin-right: 5px;
    vertical-align: 1px;
    flex-shrink: 0;
}

.file-item .file-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.file-item .file-name {
    font-weight: 500;
    color: var(--color-text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-bottom: 2px;
}

.file-item .file-details {
    font-size: var(--font-size-rem-4);
    color: var(--color-text-neutral);
    opacity: 0.8;
}

/* 상태는 **점과 글자**로만 말한다. 알약 배지로 두면 네 상태가 저마다 색 면을
 * 갖게 되고, 완료된 환자가 쌓일수록 목록이 알록달록해져 정작 봐야 할 '실패' 가
 * 묻힌다. (예전에는 upstage 에서만 이렇게 했는데, 배지 모양은 브랜드가 정할
 * 일이 아니라 공통으로 올렸다.) */
.file-item .ocr-status {
    display: inline-flex;
    align-items: center;
    margin-top: 3px;
    padding: 0;
    background: none;
    font-size: var(--font-size-2xs);
    font-weight: 600;
    letter-spacing: -0.22px;
    white-space: nowrap;
}

/* 상태 아이콘 — 색은 상태 글자색(currentColor)을 따른다 */
.ocr-status svg {
    width: 14px;
    height: 14px;
    margin-right: 4px;
    display: block;
    flex-shrink: 0;
}

/* 지금 벌어지는 일(처리 중)만 주색이다. 끝난 것과 기다리는 것은 회색으로
 * 물러나고, 실패만 오류색이다. */
.ocr-status.pending,
.ocr-status.completed {
    color: var(--color-text-neutral);
}

/* 완료 체크만 주색으로. 글자까지 물들이면 완료된 환자가 쌓일수록 목록 전체가
 * 주색이 되어 강조가 사라진다. */
.ocr-status.completed svg {
    color: var(--brand-primary);
}

.ocr-status.processing {
    color: var(--brand-primary);
}

/* 진행 중일 때는 배지 전체가 아니라 점만 깜빡인다 */
.ocr-status.processing .status-dot {
    animation: pulse 1.5s infinite;
}

.ocr-status.error {
    color: var(--color-status-error);
}

/* 고른 환자 — 꽉 찬 주색이 아니라 **옅은 바탕 + 주색 글씨**다.
 * 넓은 면을 진한 단색으로 채우면 목록에서 그 줄만 튀고, 그 안의 상태·진행
 * 표시가 전부 흰색으로 뒤집혀야 해서 규칙이 두 벌이 된다. */
.file-item.selected {
    background-color: var(--brand-primary-soft);
    color: var(--brand-primary);
}

.file-item.selected .file-icon,
.file-item.selected .file-name {
    color: var(--brand-primary);
    font-weight: 600;
}

/* 아이콘 타일은 한 단계 진하게 — 고른 줄 안에서 기준점이 된다 */
.file-item.selected .file-icon {
    background-color: var(--brand-primary-tint-hover);
}

.file-item.selected .file-details,
.file-item.selected .ocr-status,
.file-item.selected .ocr-status svg,
.file-item.selected .status-dot {
    color: var(--color-text-neutral-strong);
    opacity: 1;
}

.file-item.selected .file-progress {
    background-color: rgba(var(--brand-primary-rgb), 0.18);
}

.file-item.selected .file-progress span {
    background-color: var(--brand-primary);
}

/* 파일 삭제 버튼 */
.delete-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 5px;
    border-radius: var(--radius-2xs);
    font-size: var(--font-size-lg);
    /* 휴대폰에서도 눌러야 하므로 hover 로 숨기지 않고 흐리게만 둔다 */
    opacity: 0.35;
    transition: all 0.2s ease;
    margin-left: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    margin-left: 0;  /* .file-trailing 이 오른쪽 정렬을 맡는다 */
}

.delete-btn:hover {
    opacity: 1;
    background-color: var(--color-status-error);
    transform: scale(1.1);
}

.delete-btn:hover span {
    filter: brightness(0) invert(1);
}

.delete-btn:active {
    transform: scale(0.95);
}

.file-item.selected .delete-btn {
    opacity: 0.8;
    color: white;
}

.file-item.selected .delete-btn:hover {
    opacity: 1;
    background-color: var(--color-status-error);
}

/* 업로드 상태 스타일 */

@keyframes pulse {
    0% { opacity: 1; }
    50% { opacity: 0.5; }
    100% { opacity: 1; }
}

/* ==========================================================================
 * 가운데 — 요약 패널
 * ========================================================================== */

.center-panel {
    background-color: var(--color-bg-primary);
    border-radius: var(--radius-lg);
    /* 안쪽 여백을 변수로 둔다 — 편집 중 머리글 띠가 패널 가장자리까지 닿으려면
     * 이 값만큼 밖으로 밀어야 하고, 좁은 화면에서는 값이 달라진다. */
    --panel-pad: 20px;
    padding: var(--panel-pad);
    border: var(--border-width) solid var(--color-border-strong);
    height: 100%;
    max-height: calc(100vh - 160px); /* 헤더와 footer 높이 고려 */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* 요약 컨테이너 */
.summary-container {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
    background-color: var(--color-bg-primary);
    border-radius: var(--radius-sm);
    min-height: 0;
}

.summary-container .placeholder-message {
    text-align: center;
    padding: 40px;
    font-size: var(--font-size-control);
    line-height: var(--line-height-control);
    color: var(--color-text-neutral);
}

.panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--spacing-md);
    margin-bottom: 15px;
    padding-bottom: 10px;
    /* 옅은 한 겹이면 된다. 2px 주색은 화면에서 가장 강한 선이 되는데, 제목이
     * 이미 ExtraBold 18px 로 서 있어 그만한 무게가 필요 없다. */
    border-bottom: var(--border-width) solid var(--color-border-strong);
    /* 머리글을 가르는 선은 패널을 **가로질러야** 한다. 안쪽 여백 안에서 끝나면
     * 양옆에 흰 토막이 남아 선이 떠 보인다. 여백만큼 밖으로 밀고 그만큼을
     * 자기 여백으로 되돌려 받는다. */
    margin-left: calc(var(--panel-pad, 0px) * -1);
    margin-right: calc(var(--panel-pad, 0px) * -1);
    padding-left: var(--panel-pad, 0px);
    padding-right: var(--panel-pad, 0px);
}

/* 패널 제목 (요약 보고서 · 원본 문서) — 시안은 Pretendard ExtraBold 20px 이다.
 * 회색(#495057)이라 옆의 굵은 버튼 글자에 눌려 제목처럼 보이지 않았다. */
.panel-header h2 {
    flex-shrink: 0;
    margin: 0;
    font-size: var(--font-size-heading);
    font-weight: 800;
    letter-spacing: var(--letter-spacing-heading);
    color: var(--color-text-heading);
}

.view-controls {
    display: flex;
    gap: 8px;
}

.image-container {
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    flex: 1;
    min-height: 0;
    overflow: auto;
    background-color: var(--color-bg-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    user-select: none; /* 드래그 시 텍스트 선택 방지 */
}

.placeholder-message {
    text-align: center;
    color: var(--color-text-neutral);
}

/* `.control-btn` 의 생김새는 components.css 가 정한다 (Figma 버튼 체계).
 * 여기에는 이 화면에서만 필요한 것만 남긴다. */

/* 아이콘만으로는 무엇을 하는 버튼인지 읽히지 않는다. 자리가 있으면 이름을
 * 같이 보여주고, 좁아지면 아이콘만 남긴다. */
.btn-label {
    margin-left: 5px;
    font-size: var(--font-size-rem-6);
}

@media screen and (max-width: 1200px) {
    .btn-label {
        display: none;
    }
}

/* ==========================================================================
 * 오른쪽 — 원본 뷰어
 * ========================================================================== */

.right-panel {
    background-color: var(--color-bg-surface);
    border-radius: var(--radius-lg);
    --panel-pad: 20px;
    padding: var(--panel-pad);
    border: var(--border-width) solid var(--color-border-strong);
    height: 100%;
    max-height: calc(100vh - 160px); /* 헤더와 footer 높이 고려 */
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* 문서 뷰어 섹션 */
.document-viewer-section {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.document-viewer-section .panel-header {
    flex-shrink: 0;
}

.document-viewer-section .image-container {
    flex: 1;
    overflow: auto;
    min-height: 0;
}

/* 빨간색 하이라이트 박스 */

@keyframes highlight-pulse {
    0% {
        opacity: 0.8;
    }
    50% {
        opacity: 1;
    }
    100% {
        opacity: 0.8;
    }
}

/* ==========================================================================
 * 바닥글
 * ========================================================================== */

.footer {
    background-color: var(--color-bg-surface);
    color: var(--color-text-neutral);
    text-align: center;
    padding: 8px 15px;
    font-size: var(--font-size-rem-7);
    flex-shrink: 0;
    border-top: var(--border-width) solid var(--color-border-strong);
}

.footer p {
    margin: 0;
}

/* 이미지 스타일 */
.displayed-image {
    max-width: 100%;
    cursor: grab;
}

.displayed-image:active {
    cursor: grabbing;
}

/* ==========================================================================
 * 요약 검색
 * ========================================================================== */

.summary-search-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    /* 좁아지면 줄어야 한다. flex 항목의 기본 min-width 는 auto 라 내용보다
     * 작아지지 않는데, 안의 <input> 은 기본 폭(size=20)이 있어 그 폭에서
     * 버티다가 옆의 편집 버튼들을 아랫줄로 밀어냈다.
     * 다만 끝없이 줄면 글자를 넣을 수 없다. 안의 입력칸이 필요한 만큼은
     * 잡아 둔다 — 그보다 좁아지면 내용이 옆 버튼 아래로 삐져나가 검색
     * 버튼이 눌리지 않았다(모바일에서 실제로 그랬다). 자리가 없으면
     * 머리글이 두 줄로 접히는 편이 낫다. */
    min-width: 150px;
    max-width: 400px;
    margin-left: auto;
}

/* 검색창 — 시안은 돋보기와 지우기를 **입력칸 안에** 둔다 (`title-search-group`).
 * 바깥에 버튼을 늘어놓지 않으므로 머리글이 좁아져도 줄이 접히지 않는다.
 * 상자 자체(높이·반경·바탕·포커스 테두리)는 components.css 의 TextField 다. */
.searchfield {
    position: relative;
    /* 늘어나되 **안내 문구가 잘리지는 않는다**. 최소는 돋보기(12+16) + 글자(58)
     * + 오른쪽 여백(22) 이다. 고정 폭으로 두면 넓은 화면에서 남는 자리를 놀리고,
     * 최소를 안 두면 좁은 화면에서 문구가 잘린다. */
    flex: 1 1 auto;
    min-width: 108px;
}

/* 시안값 — 왼쪽 여백 12 + 돋보기 16 + 사이 4 = 글자가 32 에서 시작한다.
 * 오른쪽은 여백 8 + 지우기 원 14 = 22 를 비운다. */
.summary-search-input {
    width: 100%;
    padding-left: 32px;
    padding-right: 22px;
}

/* 검색어가 들어오면 글자는 검정 SemiBold 다 (시안). 안내 문구는 그대로 둔다 */
.summary-search-input:not(:placeholder-shown) {
    font-weight: 600;
}

/* 포커스는 테두리와 옅은 번짐으로만 알린다. 바탕은 그대로 둔다 —
 * 흰색으로 바꾸면 패널 바탕에 묻혀 입력칸이 사라진 것처럼 보인다. */
.searchfield .summary-search-input:focus {
    background: var(--color-bg-muted);
    box-shadow: 0 0 5px rgba(var(--brand-primary-rgb), 0.2);
}

.searchfield-icon,
.searchfield-clear {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}

.searchfield-icon {
    left: 12px;
    width: 16px;
    height: 16px;
    color: var(--color-icon-muted);
    transition: color 0.15s ease;
}

.searchfield-icon svg {
    width: 100%;
    height: 100%;
}

/* 검색어가 들어오면 돋보기가 주색이 된다 — 지금 무엇을 보고 있는지 알린다 */
.searchfield:has(.summary-search-input:not(:placeholder-shown)) .searchfield-icon {
    color: var(--brand-primary);
}

/* 지우기는 주색 원이다. 시안은 blue/500(#5b52ff) 을 칠한 아이콘 파일인데,
 * 그대로 쓰면 업스테이지 보라가 인하대 화면에도 박힌다. 원은 배경색으로,
 * ✕ 는 획으로 그려 브랜드를 따라가게 했다. */
.searchfield-clear {
    right: 8px;
    width: 14px;
    height: 14px;
    border-radius: var(--radius-full);
    background: var(--brand-primary);
    color: var(--color-text-inverse);
    transition: background-color 0.15s ease;
}

.searchfield-clear svg {
    width: 9px;
    height: 9px;
}

/* 원이 14px 이라 손가락으로는 못 누른다. 보이는 크기는 두고 누를 자리만 넓힌다 */
.searchfield-clear::before {
    content: "";
    position: absolute;
    inset: -9px;
}

.searchfield-clear:hover {
    background: var(--brand-primary-dark);
}

/* 결과 수는 입력칸 **밖** 오른쪽에 온다 (`1 / 35`) */
.search-result-info {
    flex: 0 0 auto;
    font-size: var(--font-size-control);
    letter-spacing: var(--letter-spacing-control);
    color: var(--color-text-neutral-strong);
    white-space: nowrap;
}

/* 검색 결과 — 글자색과 바탕을 **뒤집는다**.
 *
 * 노랑은 출처(근거 대조) 전용이라 검색이 쓸 수 없다. 그래서 파랑을 쓰되 면으로
 * 칠하고 글자를 희게 뒤집는다 — 글자색만 바꾸면 본문 속에서 눈에 덜 띈다.
 *
 * 지금 보고 있는 것과 나머지는 **같은 파랑의 농도**로 가른다 —
 * 지금 것이 blue/800(주색의 눌림 단계), 나머지가 blue/600(주색). */
.search-highlight {
    background: var(--brand-primary);
    color: var(--color-text-inverse);
}

.search-highlight.current {
    background: var(--brand-primary-active, var(--brand-primary-dark));
    color: var(--color-text-inverse);
}

/* 쪽 이동 묶음 (`pager-group` 2039:9907)
 *
 * `flex: 1` 이 있어 머리글의 남는 폭을 회색 바탕이 다 먹었다. 그래서 바탕만
 * 넓고 안의 `< 1 / 56 >` 은 가운데 몰려, 바탕과 내용이 따로 노는 것처럼 보였다.
 * 시안은 **내용만큼만** 차지한다. */
.panel-header .pdf-navigation {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    height: 40px;
    gap: var(--spacing-xs);
    padding: 0 var(--spacing-md);
    background: var(--color-bg-muted);
    border-radius: var(--radius-lg);
}

/* 이전·다음은 시안에서 **아이콘만** 이다 (버튼 껍데기가 없다).
 * 누를 자리는 있어야 하므로 크기만 주고 테두리·바탕은 비운다. */
.panel-header .pdf-nav-btn {
    width: 28px;
    height: 28px;
    padding: 0;
    border-color: transparent;
    border-radius: var(--radius-sm);
    color: var(--color-icon-secondary);
}

.panel-header .pdf-page-info {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    /* 전체 쪽수(`/ 56`) — 자간을 벌린 중간 회색이다. `#666` 은 디자이너가
     * 토큰을 걸지 않고 직접 쓴 값이라 그대로 둔다. */
    font-size: var(--font-size-md);
    font-weight: 500;
    letter-spacing: 1.12px;
    color: #666;
}

.panel-header .view-controls {
    display: flex;
    gap: 10px;
    flex-shrink: 0;
}

/* 에러 메시지용 스타일 - 이미지 위에 오버레이 */

/* ==========================================================================
 * 로딩 · 하이라이트
 * ========================================================================== */

.spinner {
    width: 50px;
    height: 50px;
    border: 4px solid var(--color-border-strong);
    border-top: 4px solid var(--brand-primary);
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin: 0 auto;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* 검색 결과 하이라이트 박스 */
/* 원본에서의 위치 표시.
 *
 * 요약 쪽 선택 표시와 **같은 색**을 쓴다. 예전에는 왼쪽이 연보라, 오른쪽이
 * 빨강이라 둘이 한 쌍이라는 것이 색으로 읽히지 않았다. 빨강은 이미
 * 검사 이상치(H)가 쓰고 있어 뜻이 겹치기도 했다. */
.highlight-box {
    position: absolute;
    /* `border` 가 아니라 `outline` 이다. 테두리는 상자 **안쪽**에 그려져 좌표가
     * 가리키는 글자의 가장자리를 덮는다 — 짚어 준 글자를 짚어 준 선이 가리는
     * 꼴이다. `outline` 은 상자 밖에 그려져 안쪽 내용을 건드리지 않는다. */
    outline: 3px solid var(--color-highlight-primary);
    background: none;
    pointer-events: none;
    z-index: 20;
    box-sizing: border-box;
}

/* 스크롤바 공통 스타일 */
.file-list::-webkit-scrollbar,
.image-container::-webkit-scrollbar {
    width: 8px;
}

.file-list::-webkit-scrollbar-track,
.image-container::-webkit-scrollbar-track {
    background: var(--color-bg-sunken);
    border-radius: var(--radius-2xs);
}

.file-list::-webkit-scrollbar-thumb,
.image-container::-webkit-scrollbar-thumb {
    background: var(--color-text-disabled);
    border-radius: var(--radius-2xs);
}

.file-list::-webkit-scrollbar-thumb:hover,
.image-container::-webkit-scrollbar-thumb:hover {
    background: var(--color-icon-muted);
}

/* 큰 화면 (1920px 이상) */
/* ==========================================================================
 * 반응형 — 화면 폭별 재정의
 * ========================================================================== */

@media screen and (min-width: 1920px) {
    .main-content {
        grid-template-columns: 320px 1fr;
        gap: 20px;
    }
}

@media screen and (max-width: 1600px) {
    .main-content {
        grid-template-columns: minmax(250px, 280px) 1fr;
    }
}

@media screen and (max-width: 1200px) {
    .main-content {
        grid-template-columns: 200px 1fr;
    }
}

/* =========================================================================
 * 모바일 (≤768px)
 *
 * 폰에서는 요약과 원본을 나란히 놓을 수 없다. 요약을 본 화면으로 두고,
 * 좌/우 패널을 아래에서 올라오는 바텀시트로 바꾼다. DOM 은 그대로다.
 *   · 상단 바의 환자 이름을 누르면  → 환자 목록 시트
 *   · 요약의 출처 항목을 누르면      → 문서 뷰어 시트 (해당 페이지 + 빨간 박스)
 *   · 손잡이를 끌어내리거나 배경을 누르면 닫힘
 *
 * 시트는 display 가 아니라 transform 으로 숨긴다. 닫혀 있어도 크기를 잴 수 있어
 * 문서 뷰어의 '전체 페이지에 맞추기' 계산이 처음부터 맞는다.
 * ====================================================================== */

/* 데스크톱에서는 모바일 전용 요소를 감춘다 */
.mobile-bar,
.sheet-handle,
.sheet-backdrop {
    display: none;
}

/* 데스크톱 헤더 — 높이는 100px 로 고정하고 제목은 페이지 정가운데에 둔다.
 * - 높이를 내용에 맡기면 언어를 바꿀 때 바뀐다 (영어는 부제목이 없어 한 줄)
 * - flex 로 두면 제목이 "로고와 오른쪽 사이" 의 가운데에 놓여, 양쪽 폭이 다른
 *   브랜드마다 치우친다. 양쪽을 1fr 로 묶으면 가운데 칸이 화면 가운데에 온다 */
@media screen and (min-width: 901px) {
    .header {
        box-sizing: border-box;
        min-height: 100px;
        padding: 0 32px;
        display: flex;
        align-items: center;
    }

    .header-content {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        align-items: center;
        padding: 0;
    }

    .logo-section {
        justify-self: start;
    }

    .header-right {
        justify-self: end;
    }
}

@media screen and (min-width: 901px) and (max-width: 1024px) {
    .title-section h1 {
        font-size: var(--font-size-xl);
    }

    /* 부제목도 제목과 같은 비율로 — 그대로 두면 제목보다 커 보인다 */
    .subtitle-en {
        font-size: var(--font-size-lg);
        margin-top: -4px;
    }
}

/* 로고는 홈 링크다 — 링크 모양(밑줄 · 글자 줄 높이)을 지운다 */
a.logo-section {
    line-height: 0;
    text-decoration: none;
}

@media screen and (max-width: 900px) {
    /* 모바일 브라우저의 100vh 는 주소창을 포함해 아래가 잘린다 */
    body,
    .container {
        height: 100dvh;
    }

    /* 헤더: 로고와 언어 토글만 남긴다 (디자이너 시안 — 높이 64 · 여백 16 · 로고 20) */
    .header {
        box-sizing: border-box;
        min-height: 64px;
        padding: 0 16px;
        display: flex;
        align-items: center;
    }

    .title-section {
        display: none;
    }

    .header-content {
        padding: 0;
        gap: 12px;
    }

    .brand-logo {
        height: 20px !important; /* 높이는 템플릿이 인라인으로 준다 */
    }

    .subtitle-en,
    .system-version,
    .powered-by {
        display: none;
    }

    /* 언어 선택은 모바일에서도 남긴다 — 이 화면은 휴대폰으로도 열린다.
     * 버전 표시는 감추므로 선택 링크만 오른쪽 끝에 남는다 */
    .hospital-info {
        margin-top: 0;
    }

    /* 현재 환자 바 */
    .mobile-bar {
        display: block;
        flex-shrink: 0;
        padding: 10px 14px 0;
    }

    .mobile-patient-btn {
        width: 100%;
        min-height: 46px;
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 10px 14px;
        background-color: var(--color-bg-primary);
        border: 1px solid var(--brand-primary-soft);
        border-radius: var(--radius-md);
        color: var(--brand-primary);
        font-size: var(--font-size-rem-10);
        font-weight: 600;
        font-family: inherit;
        cursor: pointer;
    }

    .mobile-patient-name {
        flex: 1;
        text-align: left;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .mobile-patient-btn .btn-icon svg {
        width: 18px;
        height: 18px;
        display: block;
    }

    .mobile-bar-chevron {
        opacity: 0.6;
    }

    /* 본문: 요약만 남기고 전체 폭을 쓴다 */
    .main-content {
        display: block;
        padding: 12px 14px 14px;
    }

    .center-panel {
        max-height: none;
        height: 100%;
        --panel-pad: 14px;
    }

    .center-panel .panel-header h2 {
        font-size: var(--font-size-rem-12);
    }

    .summary-container {
        padding: 4px 0 0;
    }

    /* 폰에서는 조회 전용 — 업로드는 데스크톱에서 한다 */
    .upload-section {
        display: none;
    }

    /* --------------------------------------------------- 바텀시트 */
    .left-panel,
    .right-panel {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        height: 88dvh;
        max-height: none;
        margin: 0;
        --panel-pad: 14px;
        padding: 0 var(--panel-pad) var(--panel-pad);
        border: none;
        border-radius: var(--radius-xl) var(--radius-xl) 0 0;
        background-color: var(--color-bg-primary);
        transform: translateY(100%);
        transition:
            transform 0.28s cubic-bezier(0.32, 0.72, 0, 1),
            box-shadow 0.28s ease;
        z-index: 60;
        will-change: transform;
    }

    /* 그림자는 열려 있을 때만.
     * 닫힌 시트는 화면 바로 아래(translateY(100%))에 있는데 그림자는 위로
     * 6px + 번짐 32px 이라, 요소는 안 보여도 그림자 띠가 화면 하단에 늘
     * 걸려 있었다. */
    .left-panel.sheet-open,
    .right-panel.sheet-open {
        transform: translateY(0);
        box-shadow: 0 -6px 32px rgba(10, 13, 20, 0.22);
    }

    /* 끌어내려 닫는 손잡이 — 터치 영역을 넉넉히 둔다 */
    .sheet-handle {
        display: block;
        flex-shrink: 0;
        height: 26px;
        margin: 0 -14px;
        position: relative;
        touch-action: none;
        cursor: grab;
    }

    .sheet-handle::after {
        content: '';
        position: absolute;
        top: 10px;
        left: 50%;
        transform: translateX(-50%);
        width: 40px;
        height: 4px;
        border-radius: 2px;
        background-color: var(--color-border-strong);
    }

    .sheet-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 50;
        background-color: rgba(10, 13, 20, 0.45);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.28s ease;
    }

    .sheet-backdrop.visible {
        opacity: 1;
        pointer-events: auto;
    }

    body.sheet-open {
        overflow: hidden;
    }

    /* 시트 안에서는 문서가 남은 높이를 꽉 쓰게 (손잡이 높이만큼 뺀다) */
    .right-panel .document-viewer-section {
        flex: 1;
        min-height: 0;
        height: auto;
    }

    .image-container {
        min-height: 260px;
    }

    /* 확대 후 손가락으로 밀어 보기 (드래그는 마우스 전용이라 기본 스크롤에 맡긴다) */
    .image-container.has-document {
        touch-action: pan-x pan-y pinch-zoom;
    }

    /* 뷰어 조작 버튼이 두 줄로 접혀도 눌리는 크기를 유지 */
    .document-viewer-section .panel-header {
        gap: 8px;
    }

    .panel-header .view-controls {
        flex: 1;
        justify-content: flex-end;
    }

    .control-btn {
        min-height: 38px;
    }

    .footer {
        padding: 6px 12px;
        font-size: var(--font-size-rem-4);
    }
}

/* 아주 좁은 화면 — 제목을 버리고 로고만 */
@media screen and (max-width: 480px) {
    .title-section {
        display: none;
    }

    .control-btn {
        padding: 0.5rem 0.75rem;
    }
}

/* 지금 짚고 있는 것 (요약에서 눌렀을 때)
 *
 * 안쪽을 옅게 채우지 않는다 — 스캔 글자 위에 색을 덮으면 그 글자가 읽기 나빠진다.
 * 원본은 판독 대상이지 배경이 아니다. 선을 한 단계 굵히는 것으로 충분하다. */
.highlight-box.emphasized {
    outline-width: 4px;
    animation: highlight-pulse 1.5s ease-in-out 3;
}

/* ==========================================================================
 * 알림 — OCR 오류
 * ========================================================================== */

.ocr-error-notification {
    position: relative;
    margin: 10px;
    padding: 12px 40px 12px 15px;
    /* 시안 팔레트에 노랑 계열이 없다. 그리고 노랑은 출처(근거 대조) 전용이라
     * 여기에 쓰면 뜻이 겹친다 — 알림은 오류색으로 낸다. */
    background: var(--color-status-error-light);
    border: var(--border-width) solid var(--color-status-error);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    gap: 10px;
    animation: slideDown 0.3s ease;
}

@keyframes slideDown {
    from {
        opacity: 0;
        transform: translateY(-10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.error-icon {
    font-size: var(--font-size-rem-17);
    flex-shrink: 0;
}

.error-content {
    flex: 1;
}

.error-title {
    font-weight: 600;
    color: var(--color-status-error);
    margin-bottom: 4px;
}

.error-message {
    font-size: var(--font-size-rem-9);
    color: var(--color-status-error);
    line-height: 1.4;
}

.error-close {
    position: absolute;
    top: 8px;
    right: 8px;
    background: transparent;
    border: none;
    font-size: var(--font-size-rem-14);
    color: var(--color-status-error);
    cursor: pointer;
    padding: 4px 8px;
    opacity: 0.7;
    transition: opacity 0.2s;
}

.error-close:hover {
    opacity: 1;
}

/* ==========================================================================
 * 요약 상태 — 비어 있음 · 추출 중 · 실패
 * ========================================================================== */

.file-item.empty {
    justify-content: center;
    color: var(--color-text-neutral);
    font-size: var(--font-size-rem-9);
    cursor: default;
}

.file-item.empty:hover {
    background-color: transparent;
    transform: none;
}

/* 상태 화면 — 요약이 아직 없거나 만들지 못했을 때 그 자리에 들어간다.
 * (불러오는 중 · 대기 중 · 요약하는 중 · 실패 · iframe 차단)
 *
 * 시안에 이 화면은 없다. 그래서 시안이 정한 것만 가져다 쓴다 — 제목 18px,
 * 본문 13px/1.8, 색은 토큰. 새 색이나 새 크기를 여기서 만들지 않는다.
 *
 * 글자 위계는 제목 > 설명 > 진행 순으로 한 단계씩 물러난다. */
.summary-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-md);
    padding: 60px 20px;
    text-align: center;
    color: var(--color-text-neutral-strong);
}

.summary-state .state-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--spacing-2xs);
    color: var(--color-icon-tertiary);
}

.state-glyph {
    width: 36px;
    height: 36px;
}

/* 실패했을 때만 오류색이다. 예전에는 상태와 무관하게 늘 빨간 제목이라
 * "대기 중입니다" 도 사고처럼 보였다. */
.summary-state.is-error .state-icon {
    color: var(--color-status-error);
}

.summary-state .state-title,
.summary-state h3 {
    margin: 0;
    font-size: var(--font-size-xl);
    font-weight: 700;
    letter-spacing: -0.36px;
    color: var(--color-text-primary);
}

.summary-state.is-error .state-title,
.summary-state.is-error h3 {
    color: var(--color-status-error);
}

.summary-state .state-message {
    max-width: 420px;
    margin: 0;
    font-size: var(--font-size-control);
    line-height: var(--line-height-control);
    letter-spacing: var(--letter-spacing-control);
    color: var(--color-text-neutral-strong);
}

/* 몇 쪽까지 됐는지 같은 곁들이 정보 — 한 단계 더 물러난다 */
.summary-state .state-progress {
    margin: 0;
    font-size: var(--font-size-xs);
    letter-spacing: -0.24px;
    color: var(--color-text-neutral);
}

/* ==========================================================================
 * 페이지 이동 · 확대
 * ========================================================================== */

.page-stage {
    position: relative;
    width: 100%;
    flex-shrink: 0;
    line-height: 0;
    /* 끌 때 페이지가 손을 따라 움직인다 (viewer.js 가 translateX 를 준다) */
    will-change: transform;
}

.page-stage .displayed-image {
    width: 100%;
    height: auto;
    display: block;
}

/* 문서가 표시되면 flex 중앙정렬을 끈다.
 * (중앙정렬 상태에서 페이지가 컨테이너보다 크면 위쪽이 잘리고 스크롤도 막힌다) */
.image-container.has-document {
    display: block;
}

/* 전체 보기(확대 안 함)에서는 가로 스크롤이 쓰일 일이 없다. 페이지가 이미
 * 화면에 맞기 때문이다. 그런데 넘기려고 붙여 둔 옆 페이지가 스크롤 영역을
 * 늘려서, 끄는 동안 가로 스크롤바가 잠깐 나타났다. 확대했을 때는 밀어서
 * 봐야 하므로 그때만 켠다. */
.image-container.has-document:not(.zoomed) {
    overflow-x: hidden;
}

.image-container.has-document .page-stage {
    margin: 0 auto;
}

.image-container.dragging {
    cursor: grabbing;
}

/* 쪽번호 칸 — 묶음 바탕(#f8f9fa) 위에 흰 칸으로 앉는다.
 * 테두리 한 겹이 있어야 회색 바탕에서 칸으로 읽힌다. */
.page-input {
    width: 52px;
    height: 28px;
    text-align: center;
    padding: 0;
    border: var(--border-width) solid var(--color-border-divider);
    border-radius: var(--radius-sm);
    background: var(--color-bg-primary);
    color: var(--color-text-heading);
    font-family: inherit;
    font-size: var(--font-size-control);
    font-weight: 600;
    letter-spacing: normal;
}

.pdf-nav-btn:hover:not(:disabled) {
    background: var(--color-bg-sunken);
}

.pdf-nav-btn:active:not(:disabled) {
    background: var(--color-bg-pressed);
}

.page-input:focus {
    outline: none;
    border-color: var(--brand-primary-focus, var(--color-border-strong));
}

/* =========================================================================
 * 브랜드 차이
 *
 * **색과 로고만이다.** 모양(테두리·반경·그림자·목록 짜임)은 두 브랜드가 같다 —
 * 그것은 시안이 정하는 것이지 병원이 정하는 것이 아니다.
 *
 * 한때 upstage 만 `--studio-*` 라는 제 이름의 토큰 한 벌을 들고 화면 절반을
 * 덧칠하고 있었다. 값을 대 보니 시안 토큰과 사실상 같은 것이었고(회색 단계 ·
 * 반경 8/12), 모양까지 달라져 같은 화면이 브랜드마다 두 벌이었다. 그쪽 모양이
 * 시안에 가까웠으므로 **공통으로 올리고 덧칠은 지웠다.**
 * ====================================================================== */

/* =========================================================================
 * EMR 임베드 화면 (/r/{key})
 *
 * 병원 EMR 안에 iframe 으로 들어간다. 헤더·환자목록·업로드가 없고
 * 요약과 원본만 나란히 놓인다. 높이는 부모 iframe 이 정하므로 100% 를 쓴다.
 * ====================================================================== */
/* 높이는 기본값(100vh)을 그대로 쓴다. iframe 안에서 vh 는 iframe 자신의
 * 높이라 부모가 정한 크기에 정확히 맞는다. `height: 100%` 로 바꾸면 html
 * 높이가 auto 라 백분율이 풀리지 않아 레이아웃이 무너진다. */
/* ==========================================================================
 * 임베드 모드 (EMR 안에서 열릴 때)
 * ========================================================================== */

body.embed {
    background-color: var(--brand-surface);
}

.embed-content {
    display: grid;
    position: relative; /* 되돌리기 손잡이의 기준 */
    /* 비율은 splitter.js 가 fr 로 넣는다. px 로 넣으면 창 크기가 바뀔 때마다
     * 다시 맞춰야 하는데, fr 이면 그리드가 알아서 따라간다. */
    grid-template-columns:
        var(--split-left, 55fr)
        6px
        var(--split-right, 45fr);
    gap: 12px;
    /* 바깥 여백은 두지 않는다 — 이 화면은 EMR 안 iframe 이고, 그 둘레 여백은
     * EMR 이 정할 몫이다. 우리가 또 두면 여백이 두 겹이 된다.
     * (`gap` 은 두 패널 **사이** 라 남긴다.) */
    height: 100%;
    min-height: 0;
    /* 원본을 접고 펼 때 트랙이 부드럽게 움직인다. fr 끼리는 브라우저가
     * 보간하므로 JS 로 폭을 계산해 넣을 필요가 없다. */
    transition: grid-template-columns 0.25s ease;
}

/* 원본 접힘 — 요약이 폭을 다 가져간다.
 * 손잡이로 맞춰 둔 --split-left/right 는 건드리지 않아 펼치면 그대로 돌아온다. */
body.is-viewer-collapsed .embed-content {
    grid-template-columns: 1fr 0 0fr;
    gap: 0;
}

body.is-viewer-collapsed .right-panel {
    overflow: hidden;
    padding: 0;
    border-width: 0;
    min-width: 0;
}

body.is-viewer-collapsed .split-handle {
    visibility: hidden;
}

/* 접기 버튼 — 두 패널의 경계선 위.
 *
 * 뷰어 머리글의 아이콘 하나로는 무엇을 접는다는 것인지 읽히지 않았고, 접는
 * 순간 그 자리로 '재요약' 이 밀려 들어와 두 번 누르면 재요약이 실행됐다.
 * 경계선 위에 두면 무엇을 접는지 위치가 말해 주고, 접고 나면 그 자리에
 * 아무 버튼도 없어 두 번째 클릭이 사고를 내지 않는다. */
/* ==========================================================================
 * 뷰어 접기 · 펼치기 · 분할
 * ========================================================================== */

.viewer-collapse {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 4;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 46px;
    padding: 0;
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background: var(--color-bg-surface);
    /* 회색으로 두면 분할선의 장식처럼 보인다. 브랜드 색이면 누르는 것임이
     * 읽히면서도, 크기가 작아 화면을 시끄럽게 하지 않는다. */
    color: var(--brand-primary);
    /* 누르면 접히고 끌면 비율이 바뀐다. 경계선 위에 있으니 끄는 쪽이 먼저
     * 떠오르는데, 커서까지 그렇게 두면 접을 수 있다는 것이 묻힌다. */
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(10, 13, 20, 0.1);
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.viewer-collapse[hidden] {
    display: none;
}

.viewer-collapse:hover {
    border-color: var(--brand-primary);
    background: var(--brand-primary-soft);
}

.viewer-collapse svg {
    width: 13px;
    height: 13px;
    display: block;
}

/* 끄는 중에는 버튼이 손을 방해하지 않게 */
.split-handle.is-dragging .viewer-collapse {
    opacity: 0;
    pointer-events: none;
}

/* 접힌 자리에 붙어 있는 되돌리기 손잡이 */
.viewer-restore {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    z-index: 5;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 14px 6px;
    border: var(--border-width) solid var(--color-border-strong);
    border-right: 0;
    border-radius: var(--radius-sm) 0 0 var(--radius-sm);
    background: var(--color-bg-primary);
    color: var(--brand-primary);
    cursor: pointer;
}

.viewer-restore[hidden] {
    display: none;
}

.viewer-restore:hover {
    background: var(--brand-primary-soft);
}

.viewer-restore-label {
    font-size: var(--font-size-rem-4);
    font-weight: 600;
    writing-mode: vertical-rl;
}

.viewer-restore .btn-icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

/* 두 패널 사이 손잡이. 선은 얇게 보이되 잡는 영역은 넉넉히 준다. */
.split-handle {
    position: relative;
    align-self: stretch;
    cursor: col-resize;
    touch-action: none;
}

.split-handle::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 2px;
    transform: translateX(-50%);
    border-radius: 1px;
    background-color: var(--color-border-strong);
    transition: background-color 0.15s ease, width 0.15s ease;
}

/* 잡기 쉽도록 실제 히트 영역을 좌우로 넓힌다 (보이는 선은 그대로) */
.split-handle::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: -6px;
    right: -6px;
}

.split-handle:hover::before,
.split-handle.is-dragging::before {
    width: 4px;
    background-color: var(--brand-primary);
}

body.embed .center-panel,
body.embed .right-panel {
    max-height: none;
    height: 100%;
    min-height: 0;
}

/* 상태 화면의 스피너는 아이콘 자리에 들어간다 */
.summary-state .state-icon .spinner {
    width: 36px;
    height: 36px;
    margin: 0;
    border-width: 3px;
    border-color: var(--color-border-strong);
    border-top-color: var(--brand-primary);
}

/* iframe 이 좁으면(EMR 창 분할·태블릿) 위아래로 쌓는다.
 * 데모의 바텀시트는 여기서 쓰지 않는다 — iframe 안에서는 화면 전체를 덮는
 * 시트가 부모 화면과 어긋나 보인다. */
/* 좁은 화면(태블릿 이하) — 요약이 화면을 다 쓰고, 원본은 출처를 눌렀을 때
 * 올라오는 바텀시트가 된다.
 *
 * 예전에는 769~900px 을 '상하 분할' 로 따로 두었는데, 그 구간에서는 원본이
 * 화면 아래에 늘 붙어 있어 요약과 원본 둘 다 어중간했다. 구간을 없애고
 * 900px 이하는 모두 같은 방식(시트)으로 다룬다.
 *
 * 전역 규칙이 .right-panel 을 `position: fixed` 시트로 바꾸면 그리드 흐름에서
 * 빠지므로, 행을 하나로 두어야 요약이 화면을 다 쓴다. */
@media screen and (max-width: 900px) {
    .embed-content {
        grid-template-columns: 1fr;
        grid-template-rows: minmax(0, 1fr);
        gap: 0;
    }

    /* 세로로 쌓이면 좌우 비율이라는 개념이 없다. 접기도 마찬가지 —
     * 오른쪽은 패널이 아니라 출처를 누르면 올라오는 바텀시트다. */
    .split-handle,
    .viewer-collapse,
    .viewer-restore {
        display: none;
    }

    body.embed .center-panel {
        --panel-pad: 14px;
    }

    /* 시트 높이를 되살린다.
     * 위 `body.embed .right-panel { height: 100% }` 이 특정성으로 전역 시트
     * 규칙을 덮어 시트가 화면을 꽉 채웠고, 그러면 배경을 눌러 닫을 영역이
     * 한 픽셀도 남지 않는다. 88dvh 는 답답해서 한 단계 낮췄고, 고정 px 대신
     * 비율로 두어 화면 크기가 달라져도 같은 느낌을 유지한다. */
    body.embed .right-panel {
        height: 78dvh;
    }

    /* 시트 안에서는 조작부를 가운데 한 덩어리로 모은다.
     * 데스크톱처럼 제목 왼쪽 · 페이지 가운데 · 버튼 오른쪽으로 흩어 놓으면
     * 좁은 폭에서 양끝으로 벌어져 손이 닿기 불편하다.
     * '원본 문서' 제목은 뺀다 — 시트를 올린 맥락상 무엇인지 이미 분명하다. */
    body.embed .right-panel .panel-header {
        justify-content: center;
        gap: 10px;
    }

    body.embed .right-panel .panel-header h2 {
        display: none;
    }

    body.embed .right-panel .panel-header .pdf-navigation,
    body.embed .right-panel .panel-header .view-controls {
        flex: 0 0 auto;
    }
}

/* =========================================================================
 * 해상도 미리보기 (데모 전용)
 *
 * 헤더 설정 아이콘 → 프리셋 선택 → 그 크기의 iframe 으로 보여준다.
 * 컨테이너만 줄이면 미디어 쿼리가 안 바뀌어 모바일 레이아웃을 볼 수 없다.
 * ====================================================================== */
/* ==========================================================================
 * 데모 무대 (이 저장소에서만 쓴다)
 * ========================================================================== */

.version-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: -5px;  /* 아래 문구(태그라인)와의 간격을 조인다 */
}

.session {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
}

/* 어두운 헤더 위 — 회색 테두리 버튼이면 글자가 묻힌다 */
.session .btn {
    height: var(--size-control-sm);
    color: inherit;
    border-color: currentColor;
}

/* 태그라인이 없는 브랜드 — 아래 줄이 없으니 조일 것도 없다. 한 줄이 헤더의 세로 가운데에 온다 */
.hospital-info--solo .version-row {
    margin-bottom: 0;
}

/* 무대 도구 막대 — 해상도 선택 · 현재 크기 · EMR 이식 주소를 한 상자에.
 * 각자 한 행씩 차지하면 정작 보여줘야 할 무대가 좁아진다. */
.stage-bar {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 10px;
    padding: 8px 12px;
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-bg-primary);
}

.stage-bar-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.stage-bar-label {
    flex: 0 0 auto;
    color: var(--color-text-neutral);
    font-size: var(--font-size-rem-4);
    font-weight: 600;
}

/* 해상도 프리셋 — 접어 두지 않고 늘어놓는다 (데모에서 보여줄 기능이다) */
.preview-options {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
}

.preview-option {
    padding: 4px 11px;
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    background: var(--color-bg-primary);
    color: var(--color-text-neutral-strong);
    font: inherit;
    font-size: var(--font-size-rem-5);
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.preview-option:hover {
    border-color: var(--brand-primary);
    color: var(--brand-primary);
}

.preview-option.is-active {
    border-color: var(--brand-primary);
    background: var(--brand-primary);
    color: var(--color-text-inverse);
    font-weight: 600;
}

/* =========================================================================
 * 무대 — 의사가 보는 화면(/r/{key})을 그대로 끼운 iframe
 *
 * 요약 보고서와 문서 뷰어를 데모가 다시 만들지 않는다. 같은 페이지를 끼워서
 * 데모가 상품을 실제로 보여주게 한다. 무대 위 도구 막대에서 고른 해상도가
 * 이 iframe 크기가 되고, 기본은 영역을 꽉 채우는 반응형이다.
 * ====================================================================== */
.stage-panel {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
    min-height: 0;
    height: 100%;
    max-height: calc(100vh - 160px);
}

/* 프리셋 바로 옆에 둔다 — 이 값은 프리셋 선택의 결과다. 원인 옆에 붙어야
 * 한 번에 읽히고, `사용자 지정` 으로 끌어서 바꿀 때 숫자가 실시간으로 변하는
 * 것을 눈이 왕복하지 않고 본다. */
.stage-size {
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    background: var(--brand-primary-soft);
    color: var(--brand-primary);
    font-size: var(--font-size-rem-4);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.stage-size[hidden] {
    display: none;
}

/* EMR 이식 주소 — 고른 해상도를 그대로 옮겨 갈 수 있게 보여준다.
 * 상담 자리에서 화면을 가리키며 "이 주소를 넣으시면 됩니다" 로 끝나야 한다. */
.embed-share {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-top: 8px;
    border-top: var(--border-width) solid var(--color-border-divider);
}

.embed-share[hidden] {
    display: none;
}

.embed-share-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.embed-share-label {
    flex: 0 0 auto;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: var(--brand-primary-soft);
    color: var(--brand-primary);
    font-size: var(--font-size-rem-2);
    font-weight: 600;
}

.embed-url {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--brand-primary);
    font-size: var(--font-size-rem-5);
    text-decoration: none;
}

.embed-url:hover {
    text-decoration: underline;
}

/* 복사할 것(한 줄) 바로 옆에 둔다. 주소 행에 있을 때는 주소를 복사하는
 * 것으로 읽혔고, 오른쪽 끝이라 눈에 들어오지도 않았다. */
.embed-snippet-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
    min-width: 0;
}

.embed-copy {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-xs);
    background: var(--color-bg-primary);
    color: var(--color-text-neutral-strong);
    font: inherit;
    font-size: var(--font-size-rem-4);
    white-space: nowrap;
    cursor: pointer;
}

.embed-copy .btn-icon svg {
    width: 14px;
    height: 14px;
    display: block;
}

.embed-copy:hover {
    border-color: var(--brand-primary);
    color: var(--brand-primary);
}

.embed-copy.is-done {
    border-color: var(--brand-primary);
    background: var(--brand-primary-soft);
    color: var(--brand-primary);
}

/* 실제로 붙여 넣을 한 줄. 주소만으로는 어디에 넣는지 모르는 사람이 있다. */
.embed-snippet {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    overflow-x: auto;
    padding: 6px 8px;
    border-radius: var(--radius-xs);
    background: var(--color-bg-muted);
    color: var(--color-text-neutral-strong);
    font-size: var(--font-size-rem-3);
    white-space: nowrap;
}

.stage-frame-wrap {
    position: relative;
    flex: 1;
    min-height: 0;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--brand-surface);
    border: var(--border-width) solid var(--color-border-strong);
}

/* 반응형(기본): 영역을 꽉 채운다 */
.stage-resizer {
    position: relative;
    width: 100%;
    height: 100%;
    min-width: 320px;
    min-height: 280px;
    overflow: hidden; /* resize 가 먹으려면 visible 이 아니어야 한다 */
    transform-origin: top center;
}

/* 무대의 iframe.
 *
 * 클래스를 붙이지 않는다 — 이 iframe 은 고객에게 건네는 한 줄과 **같은 것**
 * 이어야 해서, 데모 사정으로 붙인 표시가 하나라도 있으면 그만큼 달라진다.
 * 그래서 감싼 상자(.stage-resizer)를 기준으로 고른다. 그 안의 iframe 은
 * 하나뿐이라 이 선택자가 가리키는 대상은 분명하다. */
.stage-resizer > iframe {
    border: 0;
    display: block;
    background: var(--color-bg-primary);
}

/* 반응형일 때만 영역을 채운다. 크기를 골랐을 때는 iframe 의 width·height
 * 속성이 정하도록 **규칙 자체를 두지 않는다** — `width: auto` 로 덮어써도
 * 그게 속성보다 우선해 iframe 기본값(300×150)이 나온다. */
.stage-frame-wrap:not(.is-fixed) .stage-resizer > iframe {
    width: 100%;
    height: 100%;
}

.stage-resizer > iframe[hidden] {
    display: none;
}

/* 해상도를 고르면: 고정 크기 + 가운데. 영역보다 크면 JS 가 배율을 줄인다 */
.stage-frame-wrap.is-fixed {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 24px;
    background: var(--color-bg-sunken);
}

.stage-frame-wrap.is-fixed .stage-resizer {
    /* iframe 이 자기 크기를 정하므로 상자는 그것을 따라간다 */
    width: auto;
    height: auto;
    min-width: 0;
    min-height: 0;
    flex: 0 0 auto;
    max-width: none;
    max-height: none;
    border-radius: var(--radius-sm);
    box-shadow: 0 16px 40px rgba(10, 13, 20, 0.28);
}

.stage-placeholder {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-neutral);
    font-size: var(--font-size-rem-12);
    pointer-events: none;
}

.stage-placeholder[hidden] {
    display: none;
}

/* iframe 이 차단됐을 때의 안내 (브라우저 기본 오류 화면 대신) */
.stage-blocked {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 32px;
    text-align: center;
    background: var(--brand-surface);
}

.stage-blocked[hidden] {
    display: none;
}

/* `.summary-state.is-error` 가 이미 오류색을 준다 — 여기서 또 정하지 않는다 */

.stage-blocked .state-message {
    max-width: 460px;
    color: var(--color-text-neutral-strong);
    font-size: var(--font-size-rem-9);
}

.stage-blocked code {
    padding: 1px 5px;
    border-radius: var(--radius-2xs);
    background: rgba(10, 13, 20, 0.07);
    font-size: var(--font-size-code);
}

/* 확대/축소 버튼은 데스크톱에서만. 태블릿·폰은 손가락으로 하고,
 * 좁은 화면에서 조작부를 한 줄에 넣기 위해서도 필요하다. */
@media screen and (max-width: 1024px) {
    .control-btn.zoom-only {
        display: none;
    }
}

/* 넘기는 동안 따라 들어오는 옆 페이지.
 * .page-stage 안에 있으므로 stage 의 translateX 를 같이 탄다. */
.page-neighbor {
    position: absolute;
    top: 0;
    width: 100%;
    height: auto;
    display: block;
    box-shadow: 0 0 24px rgba(10, 13, 20, 0.15);
}

.page-neighbor[hidden] {
    display: none;
}

/* 좌우 위치는 viewer.js 가 뷰어 폭에 맞춰 px 로 넣는다.
 * 페이지 폭 기준(calc(100% + …))으로 두면 페이지가 뷰어보다 좁을 때
 * 두 장이 동시에 보인다. */

/* 모서리를 끌어 크기를 바꿀 수 있다는 표시.
 * 브라우저 기본 resize 손잡이는 iframe 에 가려 잘 안 보인다.
 * pointer-events 를 꺼서 실제 드래그는 네이티브 손잡이가 받게 둔다. */
/* 오른쪽 아래 모서리 손잡이 — 어떤 해상도에서도 끌어서 조절할 수 있다.
 *
 * CSS 의 `resize` 는 화면 좌표를 그대로 요소 크기에 더한다. 무대를 줄여서
 * 보여 주는 중(데스크톱 1920 처럼 영역보다 큰 경우)에는 그만큼 손과 어긋나
 * 예전에는 그럴 때 아예 꺼 뒀다. 직접 만들어 배율로 나눠 주면 언제나 손을
 * 따라온다. 손잡이 자신은 배율의 역수를 걸어 늘 같은 크기로 보인다. */
.stage-grip {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 22px;
    height: 22px;
    background: linear-gradient(135deg, transparent 45%, var(--brand-primary) 45%);
    opacity: 0.45;
    cursor: nwse-resize;
    touch-action: none;
    transform: scale(var(--grip-scale, 1));
    transform-origin: bottom right;
    transition: opacity 0.2s ease;
}

.stage-grip[hidden] {
    display: none;
}

.stage-grip:hover,
.stage-grip.is-dragging {
    opacity: 0.85;
}

/* '사용자 지정' 을 고른 직후 잠깐 강조 */
.stage-grip.is-highlight {
    opacity: 1;
    animation: grip-pulse 0.7s ease-in-out 3;
}

@keyframes grip-pulse {
    50% {
        transform: scale(calc(var(--grip-scale, 1) * 1.5));
    }
}

/* ==========================================================================
 * 편집 모드
 * ========================================================================== */

.summary-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    margin-left: auto;  /* 동작 버튼은 오른쪽 끝에 */
    /* 버튼이 한 줄에 다 들지 않는 폭(설문 버튼이 있는 영어 390px)에서는 넘치지 않고
     * 줄을 바꾼다. 들어가는 폭에서는 한 줄 그대로다. */
    flex-wrap: wrap;
    justify-content: flex-end;
    max-width: 100%;
}

/* 설문 버튼(설문을 켠 배포에만 있다) — 요약 문항을 끝내면 체크가 든 아이콘으로 바뀐다.
 * 모달의 스타일은 survey.css 가 맡고, 그 파일은 버튼을 누른 뒤에야 걸린다. */
#surveyBtn .survey-icon-done,
#surveyBtn[data-status="completed"] .survey-icon-open {
    display: none;
}

#surveyBtn[data-status="completed"] .survey-icon-done {
    display: block;
}

/* =========================================================================
 * 요약 편집
 *
 * 화면 구성을 바꾸지 않는 것이 원칙이다 — 진료 중인 의사가 "다른 화면이 떴다"
 * 고 느끼면 안 된다. 대신 지금이 편집 모드라는 것은 분명해야 한다.
 * ====================================================================== */
/* 편집 컨트롤 — 별도 행을 만들지 않고 머리글 행 안에 들어간다.
 * 행이 하나 더 생기면 그만큼 요약이 밀려 내려가고, 편집이 "다른 화면" 처럼
 * 느껴진다.
 *
 * 제목과 검색창은 **자리를 내준다** (시안 `title-search-group` 2042:10966 —
 * 편집 상태에는 제목이 없고 '편집 중' 부터 시작한다). 고치는 동안 검색은
 * 쓸 수 없고, 그 자리를 편집 컨트롤이 그대로 쓴다. */
body.is-editing .center-panel .panel-header > h2,
body.is-editing .summary-search-controls {
    display: none;
}
/* 편집 중에는 머리글 줄 전체가 옅은 주색 띠가 된다 —
 * "지금 고치는 중" 이 한눈에 보이게 하는 장치다.
 *
 * 선택자가 `.summary-header` 였는데 그런 클래스가 마크업에 없어 여태 아무 일도
 * 하지 않고 있었다. */
/* 편집 중에는 그 자리가 면이 된다. 좌우로 미는 것은 `.panel-header` 가 이미
 * 하고 있으므로 위쪽만 더 밀어 패널 모서리에 맞춘다. */
body.is-editing .center-panel .panel-header {
    margin-top: calc(var(--panel-pad) * -1);
    padding-top: var(--spacing-md);
    padding-bottom: var(--spacing-md);
    background: var(--brand-primary-soft);
    border-bottom: var(--border-width) solid var(--brand-primary-border);
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

/* 자리가 모자라면 다음 줄로 내린다. 감추면 무엇을 눌러야 할지 사라지지만,
 * 줄이 하나 늘어나는 것은 읽는 데 지장이 없다.
 * 저장·취소는 어느 줄에 있든 **오른쪽 끝**이다 (`#cancelBtn` 의 auto 여백). */
.edit-bar {
    display: flex;
    align-items: center;
    flex: 1;
    flex-wrap: wrap;
    row-gap: var(--spacing-xs);
    gap: var(--spacing-md);
    flex-shrink: 0;
    /* 제목이 비켜났으므로 왼쪽 끝에서 시작한다. 저장·취소는 오른쪽에 남는다 */
    margin-right: auto;
}

.edit-bar[hidden] { display: none; }

/* '편집 중' 배지 — 시안은 Pill 버튼과 같은 치수다 (h36 · px20 · r999) */
.edit-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    height: var(--size-control-md);
    padding: 0 var(--spacing-xl);
    border-radius: var(--radius-full);
    background: var(--brand-primary);
    color: var(--color-text-inverse);
    font-size: var(--font-size-control);
    font-weight: 700;
    letter-spacing: var(--letter-spacing-control);
    white-space: nowrap;
    cursor: help;
}

.edit-badge svg {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
}

/* 저장되는 서식은 굵게 하나뿐이라는 안내 (자세한 내용은 title 에) */
.edit-hint {
    color: var(--color-text-neutral);
    font-size: var(--font-size-rem-4);
    white-space: nowrap;
    cursor: help;
}

/* 키캡은 편집 바와 **같은 바탕**이다. 흰색으로 띄우면 키 두 개가 저장 버튼만큼
 * 눈에 들어오는데, 이건 안내지 눌러야 할 것이 아니다. 테두리만으로 충분하다. */
.edit-hint kbd {
    padding: 1px 4px;
    border: var(--border-width) solid var(--color-border-strong);
    border-bottom-width: 2px;
    border-radius: var(--radius-2xs);
    background: var(--brand-primary-soft);
    color: var(--color-text-neutral-strong);
    font-family: inherit;
    font-size: var(--font-size-rem-2);
}

/* 좁아졌다고 안내나 배지를 감추지 않는다 — 자리가 모자라면 `.edit-bar` 가
 * 다음 줄로 내린다. 감추면 무엇을 눌러야 할지가 사라지지만, 줄이 하나 늘어나는
 * 것은 읽는 데 지장이 없다. (이름 칸을 안내 문구 폭으로 고정한 뒤로는 웬만해선
 * 한 줄에 들어간다.) */

/* 변경 건수 — 시안은 11px SemiBold 회색이고 **숫자만** 오류색이다.
 * 고친 곳이 몇 군데인지가 저장 전 마지막 확인점이라 숫자를 따로 세운다. */
.edit-count {
    color: var(--color-text-neutral-strong);
    font-size: var(--font-size-2xs);
    font-weight: 600;
    letter-spacing: -0.22px;
    white-space: nowrap;
}

.edit-count b {
    color: var(--color-status-error);
    font-weight: 600;
}

/* 수정자 이름 — **안내 문구가 들어갈 만큼만** 잡는다.
 *
 * 검색창 자리를 물려받아 늘어나게 뒀더니, 태블릿 폭에서 이 칸이 남는 폭을 다
 * 먹고 저장 버튼이 머리글 밖으로 밀려났다(실측 1024px). 이름은 짧고, 길어도
 * 칸 안에서 스크롤되므로 넓을 이유가 없다.
 *
 * 테두리가 늘 파랑인 것은 시안 그대로다 — 지금 채워야 할 칸이 여기 하나뿐이라
 * 눈이 먼저 닿아야 한다. */
input.edit-who {
    flex: 0 0 auto;
    /* 안내 문구 "수정한 사람" 이 딱 들어가는 폭 (실측 84px) */
    width: 96px;
    height: var(--size-control-md);
    padding: 0 var(--spacing-md);
    border: var(--border-width) solid var(--brand-primary-focus);
    border-radius: var(--radius-lg);
    /* **쓸 수 있는 칸은 면을 채운다** (디자이너 요청). 흰 바탕 + 테두리로 두면
     * 바로 옆 취소 버튼(Secondary)과 생김새가 같아, 누르는 것인지 쓰는 것인지
     * 구별되지 않는다. 검색창과 같은 면을 써서 "여기는 입력칸" 을 한 언어로 말한다. */
    background: var(--color-bg-muted);
    font: inherit;
    font-size: var(--font-size-control);
    font-weight: 600;
}

/* 편집 중에는 인쇄·재요약·수정이 모두 숨는다. 그런데 그것을 담은 상자는
 * 남아서 오른쪽 끝을 한 뼘 차지했다 — 저장 버튼이 가장자리에 붙지 못한 이유다. */
body.is-editing .summary-actions {
    display: none;
}

/* 편집 바는 세 덩어리다 — 왼쪽(편집 중·단축키 안내) · 가운데(수정자·건수) ·
 * 오른쪽(취소·저장). 남는 폭은 그 사이에서 나뉜다. */
input.edit-who {
    margin-left: auto;
}

.edit-count {
    margin-right: auto;
}

/* 줄이 접혀도 오른쪽 끝을 지킨다 — 묶음이 통째로 다음 줄로 내려가고,
 * 그 줄에서도 `margin-left: auto` 가 왼쪽을 밀어낸다. */
.edit-actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    margin-left: auto;
}

input.edit-who::placeholder {
    color: var(--color-text-neutral);
    font-weight: 600;
}

/* 이름 없이 저장을 누르면 그때 오류색이 된다 (embed.js 가 `is-missing` 을 단다) —
 * 누가 고쳤는지 없이 저장되면 기록이 기록 구실을 못 한다. */
input.edit-who:focus {
    outline: none;
    background: var(--color-bg-primary);
    box-shadow: 0 0 5px rgba(var(--brand-primary-rgb), 0.2);
}

/* 앞단(EMR)이 `actor=` 로 알려 준 이름이라 **고칠 수 없다.**
 *
 * 같은 이유로 **면을 채우지 않는다** — 채운 면은 "여기에 쓸 수 있다" 는 뜻이고
 * 이 칸은 읽는 값이다 (디자이너 요청). 점선 테두리로 자리는 지키되 쓸 수 없다는
 * 것을 알린다. 무엇으로 정해졌는지는 `title` 이 말한다. */
input.edit-who.is-fixed {
    /* 이름이 길어도 잘리지 않게 — 읽는 값이라 스크롤할 일이 없다 */
    width: auto;
    min-width: 96px;
    background: none;
    border-style: dashed;
    border-color: var(--color-border-strong);
    color: var(--color-text-neutral-strong);
    cursor: default;
}

input.edit-who.is-fixed:focus {
    background: none;
    box-shadow: none;
}

input.edit-who.is-missing {
    border-color: var(--color-status-error);
    background: var(--color-status-error-light);
}

/* 사람이 고친 값.
 *
 * 의무기록에서 "AI 가 뽑은 그대로인가, 사람이 고쳤는가" 는 다른 정보다.
 * 지금까지는 metadata 에만 남아 화면에서는 알 수 없었다.
 * 색으로 칠하지는 않는다 — 빨강·파랑은 검사 이상치, 브랜드색은 선택 표시로
 * 이미 뜻이 있다. 밑줄과 툴팁으로 조용히 알린다. */
[data-edited] {
    text-decoration: underline dotted rgba(var(--brand-primary-rgb), 0.6);
    text-underline-offset: 3px;
    cursor: help;
}

/* ==========================================================================
 * 격자 보기
 * ========================================================================== */

.page-grid {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 10px;
    padding: 12px;
    background: var(--color-bg-muted);
    border-radius: var(--radius-sm);
}

.page-grid[hidden] {
    display: none;
}

/* 격자를 켜면 한 장 보기는 비켜 준다 (자리를 나눠 쓰지 않는다) */
.image-container.is-hidden {
    display: none;
}

.page-cell {
    position: relative;
    display: block;
    padding: 0;
    border: var(--border-width) solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background: var(--color-bg-surface);
    cursor: pointer;
    overflow: hidden;
    /* 높이를 직접 정한다. 비율(aspect-ratio)로 두면 그리드가 행 높이에
     * 반영하지 못해 칸끼리 겹친다(실측: 높이 196px 에 행 간격 58px).
     * 폭은 유동이라 비율이 조금 달라지는데, 그림은 contain 이라 찌그러지지
     * 않고 여백만 생긴다. */
    height: 190px;
    transition: border-color 0.15s ease;
}

.page-cell:hover {
    border-color: var(--brand-primary);
}

/* 보고 있던 쪽 */
.page-cell.is-current {
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 2px var(--brand-primary);
}

.page-cell.is-current .page-cell-no {
    background: var(--brand-primary);
}

.page-cell img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: var(--color-bg-primary);
}

/* 쪽 번호 — 축소본 위에 얹히는 표식이라 작고 조용해야 한다.
 * 시안의 Badge(28x28 검정)를 잠깐 입혔다가 되돌렸다. 격자는 그림을 고르는
 * 자리인데 번호가 그림만큼 존재감을 가지면 고르는 일을 방해한다.
 * (디자이너도 격자는 기존 그대로 두기로 했다.) */
.page-cell-no {
    position: absolute;
    right: 4px;
    bottom: 4px;
    padding: 1px 6px;
    border-radius: var(--radius-full);
    background: rgba(10, 13, 20, 0.62);
    color: var(--color-text-inverse);
    font-size: var(--font-size-rem-1);
    font-variant-numeric: tabular-nums;
}

/* 격자보기 버튼은 켜져 있든 아니든 **같은 모양**이다 (시안 확인).
 * 늘 Tinted 라 `.is-active` 로 색을 바꾸지 않는다 — 상태는 아이콘과
 * 툴팁('여러 장 한눈에 보기' ↔ '한 장씩 보기'), 그리고 오른쪽 패널이
 * 격자로 바뀌는 것으로 알린다.
 *
 * 클래스는 JS(pagegrid.js)가 계속 붙이므로 선택자만 남겨 둔다. */
.control-btn.is-active {
    /* 색은 기본과 같다 — 일부러 비워 둔다 */
}

/* 상태는 아이콘이 알린다 — 격자가 닫혀 있으면 '여러 장 보기'(네 칸),
 * 열려 있으면 '한 장씩 보기'(썸네일 목록). */
#gridBtn .grid-icon-on,
#gridBtn.is-active .grid-icon-off {
    display: none;
}

#gridBtn.is-active .grid-icon-on {
    display: block;
}

/* ==========================================================================
 * 요약 목차
 * ========================================================================== */

.summary-outline {
    position: relative;
    display: flex;
    gap: 4px;
    flex-shrink: 0;
    margin-bottom: 10px;
    padding-bottom: 8px;
    border-bottom: var(--border-width) solid var(--color-border-divider);
    overflow-x: auto;
    scrollbar-width: none;
    /* 세로 스크롤은 본문에 넘기고 가로만 받는다 */
    touch-action: pan-x;
    overscroll-behavior-x: contain;
    scroll-behavior: smooth;
    /* 잘린 쪽에 흐림을 얹어 "더 있다" 를 알린다. 스크롤바를 감춰 둬서
     * 이것 말고는 신호가 없다. */
    -webkit-mask-image: var(--outline-mask, none);
    mask-image: var(--outline-mask, none);
}

.summary-outline.has-more-right {
    --outline-mask: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}

.summary-outline.has-more-left {
    --outline-mask: linear-gradient(to right, transparent, #000 28px);
}

.summary-outline.has-more-left.has-more-right {
    --outline-mask: linear-gradient(
        to right,
        transparent,
        #000 28px,
        #000 calc(100% - 28px),
        transparent
    );
}

.summary-outline[hidden] {
    display: none;
}

.summary-outline::-webkit-scrollbar {
    display: none;
}

/* `.outline-item` 의 생김새는 components.css 의 Chip 이 정한다. */

/* 그룹 접기 — 제목을 누르면 접힌다. 처음에는 모두 펼쳐져 있다.
 * 표식(화살표)과 제목 생김새는 summary.css 가 정한다 — 시안이 CSS 로 그린
 * 꺾쇠가 아니라 20px 아이콘을 쓰기 때문이다. */

.summary-group.is-collapsed > *:not(.group-title) {
    display: none;
}

.summary-group.is-collapsed {
    margin-bottom: 12px;
}

/* 편집 중임을 패널 전체가 알린다 */
body.is-editing .center-panel {
    outline: 2px solid var(--brand-primary);
    outline-offset: -2px;
}

/* 고칠 수 있는 값만 표시된다. 라벨·표 머리글·섹션 제목은 그대로라
 * "여긴 못 고친다" 가 설명 없이 전달된다.
 *
 * 점선 테두리는 문단에 걸면 왼쪽에 선 하나로만 보여 어색했다. 옅은 배경으로
 * 면을 칠하는 편이 "여기를 누르면 고칠 수 있다" 를 훨씬 분명히 알린다. */
/* ⚠️ `.summary-container` 를 앞에 두는 이유 — 값 상자 규칙
 * (`.section-content > .section-body`, summary.css)이 특이도가 같고 뒤에
 * 로드돼, 그냥 `.is-editable` 로 두면 편집 색이 값 상자 색에 밀린다. */
body.is-editing .summary-container .is-editable {
    background: var(--brand-primary-soft);
    border-radius: var(--radius-sm);
    box-decoration-break: clone;
    cursor: text;
    transition:
        background-color 0.15s ease,
        border-color 0.15s ease,
        box-shadow 0.15s ease;
    /* 투명 테두리를 미리 깔아 둔다 — 고를 때 선이 생겨도 글자가 밀리지 않는다.
     * (`box-sizing: border-box` 라 폭도 그대로다.)
     *
     * `outline` 이 아니라 `border` 인 이유 — outline 은 `box-decoration-break`
     * 가 걸린 요소에서 위·아래 가로선을 그리지 않는다 (실측: 좌우 모서리 조각만
     * 남았다). 시안도 border 로 적혀 있다. */
    border: var(--border-width) solid transparent;
}

/* 표 칸은 `border` 를 못 쓴다 — `border-collapse: collapse` 라 이웃 칸과 선을
 * 합쳐 버려 행 구분선이 사라지고, 칸마다 둥근 모서리를 주면 칸 사이에 흰 쐐기가
 * 남는다(실측). 아래 구분선은 표가 긋던 대로 두고, 고르는 표시는 안쪽 그림자다. */
/* 표 칸도 다른 칸과 같이 **둥근 모서리(r8)** 를 갖는다 (시안). 표가
 * `border-collapse: separate` 인 덕에 모서리를 줄 수 있다.
 *
 * 다만 테두리는 못 쓴다 — 칸마다 네 면을 두르면 이웃과 선이 겹쳐 두 겹이 된다.
 * 안쪽 그림자로 그린다. 줄 사이 구분선은 표가 긋던 것을 그대로 둔다. */
/* 고칠 수 있는 칸은 **하나씩 둥근 상자**다 (시안). 칸끼리 붙어 있으면 둥근
 * 모서리 사이에 흰 쐐기가 남으므로, 편집 중에는 칸 사이를 벌린다
 * (`border-spacing`). 표 폭은 100% 라 그만큼 칸이 좁아질 뿐 넘치지 않는다. */
body.is-editing .summary-container .summary-table {
    border-spacing: var(--spacing-2xs) var(--spacing-2xs);
}

body.is-editing .summary-container td.is-editable {
    /* 구분선은 칸 사이 간격이 대신한다 */
    border-width: 0;
    border-radius: var(--radius-sm);
}

/* 고른 칸 — 흰 바탕에 blue/500 한 겹. 값 상자(blue/400)보다 한 단계 진하다.
 * 표는 칸이 촘촘해 같은 밝기로는 어느 칸을 고른 것인지 덜 읽힌다. */
/* 고른 칸 — 흰 바탕에 blue/500 한 겹. 값 상자(blue/400)보다 한 단계 진하다.
 * 표는 칸이 촘촘해 같은 밝기로는 어느 칸을 고른 것인지 덜 읽힌다. */
body.is-editing .summary-container td.is-editable:focus {
    box-shadow: inset 0 0 0 1px
        var(--brand-primary-focus-strong, var(--brand-primary));
}

body.is-editing .summary-container .is-editable:hover {
    background: var(--brand-primary-tint-hover, var(--brand-primary-soft));
}

/* 지금 고치고 있는 칸 — 면을 비우고 테두리로 바꾼다. 글을 쓰는 자리라
 * 바탕이 희어야 읽힌다. 선은 옅은 파랑(blue/400) 한 겹이면 충분하다. */
body.is-editing .summary-container .is-editable:focus {
    outline: none;
    border-color: var(--brand-primary-focus, var(--brand-primary));
    background: var(--color-bg-primary);
}

/* 행 삭제 — 키보드로는 지워지지 않고 이 버튼으로만 */
/* 삭제 칸 — 표마다 폭이 제각각이었다 (실측: 52 · 327 · 454 · 597px).
 * `width: 30px` 는 `table-layout: auto` 에서 **최소 힌트**일 뿐이라, 남는 폭이
 * 있으면 이 열도 같이 늘어난다. 열 수가 적은 표일수록 크게 벌어졌다.
 *
 * `width: 1%` + `nowrap` 은 "가능한 한 좁게, 단 내용은 한 줄에" 라는 뜻이라
 * 버튼 폭 + 여백에서 멈춘다 — 어느 표에서나 같은 값이 나온다. 값 열에 쓰는
 * 것과 같은 기법이다(`.col-narrow`). */
/* ==========================================================================
 * 표 · 카드 편집
 * ========================================================================== */

.row-remove-cell {
    width: 1%;
    padding-left: var(--spacing-xs);
    padding-right: var(--spacing-xs);
    white-space: nowrap;
    text-align: center;
}

.row-remove {
    border: none;
    background: transparent;
    color: var(--color-icon-muted);
    cursor: pointer;
    font-size: var(--font-size-rem-9);
    line-height: 1;
    padding: 2px 4px;
    border-radius: var(--radius-2xs);
}

.row-remove:hover {
    background: var(--color-status-error-light);
    color: var(--color-status-error);
}

/* 카드도 항목 하나다 — 표의 행과 같이 지울 수 있어야 한다.
 * 날짜 묶음은 항목이 아니라 묶음이지만, 통째로 잘못 붙었을 때 안의 행을
 * 하나씩 누르게 할 이유가 없어 같은 버튼을 준다.
 * 버튼은 모서리에 얹는다 (머리글 안에 넣으면 제목 값들 사이에 끼어 든다). */
.record-card,
.date-group {
    position: relative;
}

.card-remove {
    position: absolute;
    top: 10px;
    right: 10px;
}

/* 버튼 자리를 비워 제목이 그 아래로 파고들지 않게 */
body.is-editing .record-header,
body.is-editing .date-header {
    padding-right: 28px;
}

tr.is-removed,
.record-card.is-removed,
.date-group.is-removed {
    opacity: 0.4;
    text-decoration: line-through;
}

/* ==========================================================================
 * 토스트
 * ========================================================================== */

.toast {
    position: fixed;
    left: 50%;
    bottom: 28px;
    transform: translateX(-50%);
    z-index: 300;
    padding: 10px 18px;
    border-radius: var(--radius-pill);
    background: rgba(10, 13, 20, 0.88);
    color: var(--color-text-inverse);
    font-size: var(--font-size-rem-8);
}

.toast[hidden] { display: none; }

/* =========================================================================
 * 데모 업로드 문턱 (uploadgate.js)
 *
 * 공개된 주소를 우연히 연 사람이 파일을 올려 보는 일을 줄이는 자리다.
 * 잘못 넣었다고 겁줄 일이 아니라, 무엇을 하면 되는지만 말한다.
 * ====================================================================== */
/* ==========================================================================
 * 비밀번호 관문 (데모 전용)
 * ========================================================================== */

.gate-backdrop {
    position: fixed;
    inset: 0;
    z-index: 900;
    background: rgba(10, 13, 20, 0.35);
}

.gate-modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 901;
    width: min(360px, calc(100vw - 32px));
    padding: var(--spacing-xl);
    background: var(--color-bg-primary);
    border-radius: var(--radius-lg);
    box-shadow: 0 16px 40px rgba(10, 13, 20, 0.28);
}

.gate-title {
    margin: 0 0 var(--spacing-2xs);
    font-size: var(--font-size-xl);
    font-weight: 700;
    letter-spacing: -0.36px;
    color: var(--color-text-heading);
}

.gate-lead {
    margin: 0 0 var(--spacing-lg);
    font-size: var(--font-size-control);
    line-height: var(--line-height-control);
    letter-spacing: var(--letter-spacing-control);
    color: var(--color-text-neutral);
}

/* 쓸 수 있는 칸은 면을 채운다 (디자이너 원칙) */
.gate-input {
    width: 100%;
}

.gate-input:disabled {
    background: var(--color-bg-disabled);
}

/* 자리를 늘 잡아 둔다 — 안내가 나타날 때 버튼이 아래로 밀리지 않게 */
.gate-message {
    min-height: 1.8em;
    margin: var(--spacing-xs) 0 0;
    font-size: var(--font-size-xs);
    letter-spacing: -0.24px;
    color: var(--color-text-neutral);
}

.gate-message.is-error {
    color: var(--color-status-error);
}

.gate-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--spacing-xs);
    margin-top: var(--spacing-md);
}
