/* TheSevenSimulationRPG — 화면 목업 스타일
   팔레트는 형제 프로젝트(TheSevenRPG / TheSevenSimulation)와 공유 */

:root {
    /* ── 표면 계단 [2026-09-14] ── 밝기 순 사다리 하나. 배경 · hover · 선택이 전부 여기서 값을 받는다.
       리터럴로 흩어져 있던 여덟 단계를 모은 것이다 — 같은 역할인데 값이 제각각이면 테마를 못 바꾼다.
       ⚙ 개발용 RGB 피커(`ui/devpalette.js`)는 이 여덟 개만 갈아 끼운다 → 화면 전체가 따라온다 */
    --surface-0: #000000;
    --surface-1: #040404;
    --surface-2: #050505;
    --surface-3: #070707;
    --surface-4: #0c0c0c;
    --surface-5: #0d0d0d;
    --surface-6: #0e0e0e;
    --surface-7: #141414;
    /* 채널 변수 — `rgba()` 는 hex 를 알파와 못 섞는다. 투명하게 깔리는 표면은 여기서 받는다 */
    --surface-0-rgb: 0, 0, 0;   /* 탭 열 · 상단바 · 패널 · 배경 아트 오버레이 */
    --veil-rgb: 6, 6, 6;        /* 아트 위에 덮는 어두운 베일 */
    --shadow-rgb: 0, 0, 0;      /* 그림자는 테마와 무관하게 검정이다 — 피커가 안 건드린다 */
    --tint-rgb: 255, 255, 255;  /* 빈 칸 · 채운 칸에 얹는 흰 기운 */

    /* 투명도 [2026-09-14] - 배경 아트가 UI 뒤로 얼마나 비치나. 세 축이 따로 논다:
       아트 자체 · 그 위 패널의 불투명도 · 가장자리를 누르는 비네트.
       'rgba(...)' 의 알파 자리는 calc() 를 받으므로 비네트는 배율 하나로 다섯 단을 한꺼번에 민다 */
    --art-opacity: .07;        /* body::before - 거점 아트(town.webp) */
    --vignette: 1;             /* body::after - 1 = 원래대로, 0 = 비네트 없음 */
    --chrome-alpha: .90;       /* 탭 열 · 상단바 · 브랜드 · 선술집 판 윗단 */
    --panel-alpha: .93;        /* 패널 */
    --panel-alpha-soft: .92;   /* 자원 줄 판 */
    --panel-alpha-deep: .96;   /* 선술집 판 아랫단 */

    /* 의미 이름은 사다리를 가리킨다 — 어느 단을 쓰는지가 한 줄로 읽힌다 */
    --bg-primary: var(--surface-0);
    --bg-secondary: var(--surface-0);
    --bg-tertiary: var(--surface-1);
    --bg-card: var(--surface-0);
    --bg-input: var(--surface-0);
    --border-primary: #343434;
    --border-secondary: #4e4e4e;
    --border-highlight: #707070;
    --border-dark: #1e1e1e;
    --text-primary: #ffffff;
    --text-secondary: #e3e3e3;
    --text-muted: #aaaaaa;
    --text-accent: #e03030;
    --color-success: #40d870;
    --color-warning: #f8b830;
    --color-error: #f04040;
    --color-info: #40a0f8;

    /* ── 의미색 [2026-09-14] ── 화면 곳곳에 리터럴로 흩어져 있던 것을 역할 이름으로 모았다.
       값은 옮기기 전과 **한 개도 안 바뀌었다** — 표현만 토큰이 됐다.
       위 상태색 4종 · 죄종 7색(`mock.js:SINS`)은 별개 축이라 여기 없다 */

    /* 주 행동 버튼 — 브랜드 빨강 계열 */
    --btn-primary-bg: #3a1414;
    --btn-primary-bg-hover: #4a1a1a;
    --btn-primary-line: #7a2a2a;
    --btn-primary-fg: #ffb0b0;

    /* 되돌릴 수 없는 행동 — 해고 · 분해 (§3 「두 번 누르게 한다」) */
    --danger-bg: #2a1414;
    --danger-bg-hover: #3a1a1a;
    --danger-line: #6a2a2a;
    --danger-fg: #f0a0a0;
    --danger-cell-hover: #2e1616;
    --danger-veil-rgb: 42, 20, 20;

    /* 적 · 보스 · 전투불능 · 피해 */
    --enemy-line: #7a3030;
    --enemy-fill: #b06030;
    --boss-line: #7a2a2a;
    --boss-bg: #1f1416;
    --downed-line: #5a2424;
    --hp-fill: #c03030;
    --dmg-out: #ffd0d0;
    --dmg-in: #ff8080;
    --accent-rgb: 224, 48, 48;  /* = --text-accent 의 채널. 보스 초상 글로우가 쓴다 */

    /* 정예 · 패시브 · 경고 — 금색 계열 */
    --elite-line: #6a4a1a;
    --elite-line-soft: #6a4a2a;
    --elite-bg: #1d1710;
    --elite-bg-unit: #1f1a16;
    --elite-fg: #d09040;
    --fire-bg: #3a2c14;
    --warn-line: #5a4a1a;
    --warn-bg: #1d1a10;

    /* 아군 · 정보 · 경험치 — 푸른 계열 */
    --ally-line: #3060a0;
    --xp-fill: #6060c0;
    --info-fg: #8fb8ff;
    --info-fg-soft: #cfe0ff;
    --info-line: #46639e;
    --info-line-rgb: 70, 99, 158;
    --note-line: #1f4a6a;
    --note-bg: #101a24;

    /* 회복 · 완료 · 켜짐 — 초록 계열 */
    --heal-fg: #8fe6a8;
    --done-line: #3a5a3a;
    --done-bg: #16201a;
    --toggle-bg: #14301c;
    --toggle-line: #2a6a3a;
    --toggle-fg: #a0f0b0;

    /* 등급색 — **SSOT 는 `data/hero_tier.csv` · `ui/mock.js:RARITY`**. 여기 값은 그 사본이다 (하나를 바꾸면 셋 다) */
    --rarity-normal: #D8D8D8;
    --rarity-magic: #4169E1;
    --rarity-rare: #FFD700;
    --rarity-unique: #FF8C00;
    --rarity-unique-rgb: 255, 140, 0;

    /* 2026-08-27 — 하이브리드 폰트. 본문은 가독성 우선(Pretendard),
       브랜드 워드마크(.brand)만 장르 분위기를 위해 Galmuri를 유지한다 */
    --font-main: 'Pretendard', 'Malgun Gothic', sans-serif;
    --font-display: 'Galmuri14', 'Galmuri11', 'Malgun Gothic', monospace;
    /* 2026-08-27 — 전체 확대(+약 20%). 장시간 응시하는 화면이라 판독성이 우선 */
    /* 2026-09-03 — 칸 안 초소형 라벨 한 단(약어 배지 · 마스터리 칸 · 페이퍼돌 라벨 · 라운드 트랙 …).
       9px 와 10px 리터럴이 열 군데 흩어져 있던 것을 **하나로 모았다** — 같은 역할인데 크기가 달랐다 */
    --fs-2xs: 9px;
    --fs-xs: 12px;
    --fs-sm: 13px;
    --fs-md: 15px;
    --fs-lg: 18px;
    --fs-xl: 24px;
    /* 진형 보드 (2026-09-09 · SCREEN_DESIGN §4-1) — `--fm-slot` 은 칸 한 변이고
       영웅 띠 카드 하한(.hs-card min-width)과 같은 값이다: 빈 칸이 「영웅이 들어갈 자리」로 크기만으로 읽혀야 한다.
       **보드 높이는 랭크 최대(둘) 기준으로 고정**이라 템플릿을 바꿔도 패널이 안 흔들린다
       (「패널 크기는 상태에 흔들리지 않는다」 2026-08-28). 한 줄짜리(3)는 그 안에서 가운데에 선다.
       ⚠ 옛 경고(「키우면 보내기 버튼이 접힌다」)는 **패널이 탭 안에 있던 시절** 것이다 — 창이 된 뒤(ADR-0084)로는
         스테이지 목록·챕터 줄과 세로를 다투지 않는다. 이 값은 적 칸(4개)과 진형 축(3칸)이 **같이** 읽는다.
       **1600×800 한 장 기준 고정값**이다 (ADR-0087) */
    --fm-slot: 118px;
    --fm-board-h: calc(var(--fm-slot) * 2 + 7px);
    /* 칸이 놓이는 **축의 폭** — 정원 최대(3칸)만큼 늘 잡아 둔다 (2026-09-09).
       랭크마다 칸 수가 달라도 이 폭 안에서 **가운데 정렬**되므로 2·1 이면 뒤 하나가 앞 둘 사이에 온다 —
       관전 아레나가 「수가 적은 랭크를 가운데」로 세우는 것(ADR-0053)과 같은 그림이 편성에서도 보인다 */
    --fm-axis: calc(var(--fm-slot) * 3 + 14px);

    /* 2026-09-01 — 초상 축소 보간. **스타일이 정한다**: 초상은 어디서나 원본보다 작게 그려지는데
       (구성 칩 26px ~ 시작 후보 카드 152px), 줄이는 방법이 스타일마다 달라야 한다.
       기본값은 손그림 쪽(보간 켬) — 신호(`<html data-face>`)가 아직 없어도 안전한 쪽으로 떨어진다.
       SCREEN_DESIGN §5 · 신호는 `mock.js:applyDocumentFace` 가 단다 */
    --face-render: auto;
}
/* 도트그래픽 스타일 — 보간하면 도트가 뭉갠다. 손그림에 이걸 걸면 반대로 픽셀을 건너뛰며
   샘플링해 선이 끊긴다(512를 26px 칸에 넣으면 20픽셀 중 1픽셀만 남는다).
   ⚠ 배경 아트(body::before · .arena.has-bg · .panel.town-bg)의 `pixelated` 는 여기와 무관하다 —
      그쪽은 스타일과 상관없이 늘 픽셀아트다. **단 `.ex-map`(탐험 지도)은 예외** — 같은 폴더에 있어도
      계승이 아니라 신규 카툰 아트라 보간을 켠다 (2026-09-04) */
:root[data-face="pixel16"] { --face-render: pixelated; }

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

/* ───────── 게임 화면 기본기 ─────────
   문서가 아니라 게임 UI다. 클릭했을 때 글자 입력 커서(캐럿)·드래그 선택·포커스 링이
   뜨면 안 된다. 셋은 원인이 각각 달라서 따로 꺼야 한다. 스크롤바도 그리지 않는다(④). */

body {
    /* ① 드래그 선택 — 클릭·드래그로 글자가 파랗게 잡히는 것 */
    -webkit-user-select: none;
    user-select: none;
    /* ② 캐럿 — Edge 의 캐럿 브라우징(F7)이 켜지면 깜빡이는 입력 커서가 생긴다.
          입력 요소가 없어도 뜨므로 색을 투명으로 죽인다 */
    caret-color: transparent;
}

/* ③ 포커스 링 — 마우스 클릭에는 그리지 않되, 키보드 이동(Tab)에는 남긴다.
      :focus 를 통째로 없애면 키보드로 화면을 못 읽는다 */
:focus { outline: none; }
:focus-visible { outline: 1px solid var(--border-highlight); outline-offset: 1px; }

/* ④ 스크롤바 — **게임 어디에도 그리지 않는다** [2026-09-11 사용자 지시 · ADR-0097]. 스크롤은 휠이 한다.
      ⚠ 규칙 안에 `scrollbar-width` 를 따로 적지 않는다 — 클래스 선택자가 이 전체 선택자를 이겨 막대가 되살아난다 */
* { scrollbar-width: none; }

/* 실제로 눌리는 것에만 손가락 커서 — 안 눌리는 카드까지 주면 거짓 신호가 된다 */
summary { cursor: pointer; -webkit-tap-highlight-color: transparent; }

body {
    background: var(--bg-primary);
    color: var(--text-primary);
    font-family: var(--font-main);
    font-size: var(--fs-md);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

/* 전역 배경 = 계승 거점 아트(town.webp). 패널 뒤에 깔리고 여백에서만 보인다.
   경로는 이 CSS 파일 기준 상대경로 (src/ui/ → src/assets/)
   **읽는 것은 워터마크 띠를 잘라 낸 사본이다** (`backgrounds_clean/` · 2026-09-11 사용자 지시) — 원본은 오른쪽 아래에 생성기 ✦ 가 박혀 있어
   창 비율에 따라 드러났다. 레시피 · 근거는 src/assets/art/README.md 「backgrounds_clean/」 */
body::before {
    content: ''; position: fixed; inset: 0; z-index: -2;
    background: url('../assets/art/backgrounds_clean/town.webp') center top / cover no-repeat;
    image-rendering: pixelated;
    opacity: var(--art-opacity);
}
/* 가장자리·하단을 눌러 본문 대비를 지킨다 — 그림은 남기고 글자만 살린다 */
body::after {
    content: ''; position: fixed; inset: 0; z-index: -1; pointer-events: none;
    background:
        radial-gradient(ellipse at 50% 22%, rgba(var(--surface-0-rgb),calc(.10 * var(--vignette))) 0%, rgba(var(--surface-0-rgb),calc(.68 * var(--vignette))) 72%),
        linear-gradient(180deg, rgba(var(--surface-0-rgb),calc(.18 * var(--vignette))) 0%, rgba(var(--surface-0-rgb),calc(.55 * var(--vignette))) 55%, rgba(var(--surface-0-rgb),calc(.90 * var(--vignette))) 100%);
}

button { font-family: inherit; font-size: inherit; color: inherit; cursor: pointer; }

/* ───────── 셸 ───────── */

/* 한 장 (2026-09-10 · ADR-0087) — 화면은 **1600×800 한 장**이다. 크기의 SSOT 는 아래 `#stage` 한 곳이고
   `app.js:fitStage` 가 창에 맞춰 통째로 줄이고 늘린다(`transform`). 그래서 **창 크기를 읽는 단위(vw · vh · 미디어 쿼리)를 안 쓴다** —
   그것들은 한 장이 아니라 실제 창을 봐서 창마다 한 장 안의 크기가 흔들린다. 정책은 src/ui/README.md 「화면 크기 정책」.
   nav 폭 330 은 **메인이 줄어든 만큼**이다(아래 `.main` 의 zoom · ADR-0090) — 영어 라벨("Expedition")이 드는 하한 188 을 넉넉히 넘는다. */
html, body { height: 100%; overflow: hidden; }
#stage { position: absolute; left: 0; top: 0; width: 1600px; height: 800px; transform-origin: 0 0; }
#app {
    display: grid;
    grid-template-columns: 330px 1fr;
    grid-template-rows: 48px 1fr;
    grid-template-areas: "brand topbar" "nav main";
    height: 100%;
}

.brand {
    grid-area: brand;
    display: flex; align-items: center; padding: 0 16px;
    background: rgba(var(--surface-0-rgb), var(--chrome-alpha));
    border-right: 1px solid var(--border-primary);
    border-bottom: 1px solid var(--border-primary);
    /* 브랜드 워드마크만 비트맵 픽셀 폰트 유지 — 안티에일리어싱을 꺼야 픽셀이 또렷하다.
       본문(Pretendard)은 body 의 antialiased 를 그대로 받는다 */
    font-family: var(--font-display);
    -webkit-font-smoothing: none;
    font-size: var(--fs-md); letter-spacing: 1px;
}
.brand b { color: var(--text-accent); }

.topbar {
    grid-area: topbar;
    display: flex; align-items: center; justify-content: space-between;
    gap: 24px; padding: 0 20px;
    background: rgba(var(--surface-0-rgb), var(--chrome-alpha));
    border-bottom: 1px solid var(--border-primary);
}
.topbar .crumb { color: var(--text-secondary); font-size: var(--fs-sm); }
/* 탭 세그먼트 — crumb 바로 오른쪽 · 탭 안의 화면 전환 (2026-09-11 · ADR-0094). 비면 자리를 안 잡아 자원 줄은 오른쪽 끝 그대로다 */
.tab-seg { margin-right: auto; }
.tab-seg:empty { display: none; }
.tab-seg .segmented { flex-wrap: nowrap; }
.resources { display: flex; gap: 18px; font-size: var(--fs-sm); }
.resources span b { color: var(--text-primary); margin-left: 6px; }
.resources span { color: var(--text-muted); }
/* 언어 토글 — 리소스 줄 끝에 붙는다 */
.lang-btn { margin-left: 4px; min-width: 46px; }

.nav {
    grid-area: nav;
    background: rgba(var(--surface-0-rgb), var(--chrome-alpha));
    border-right: 1px solid var(--border-primary);
    padding: 12px 0;
    display: flex; flex-direction: column; gap: 2px;
}
.nav button {
    background: none; border: 0; border-left: 3px solid transparent;
    padding: 10px 16px; text-align: left; color: var(--text-secondary);
}
.nav button:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.nav button.on {
    background: var(--bg-tertiary); color: var(--text-primary);
    border-left-color: var(--text-accent);
}
.nav .tag {
    float: right; font-size: var(--fs-xs); color: var(--bg-primary);
    background: var(--color-warning); padding: 0 5px; border-radius: 2px;
}

.main { grid-area: main; overflow-y: auto; padding: 20px; }
/* 메인은 한 번 더 줄인다 (2026-09-10 · ADR-0090) — 칸(1270×752) 안에서 내용이 1411×836 으로 레이아웃되고 90% 로 선다.
   **모든 탭이 같은 비율**이고 줄어든 폭은 위 `#app` 첫 열(nav)이 갖는다. 배율은 세로가 정한다 — 752 ÷ 가장 긴 탭(캐릭터 834).
   `transform` 이 아니라 `zoom` — 칸 폭 안에서 레이아웃이 설계 크기로 돈다. 메인 안에는 마우스 좌표 코드가 없다(툴팁 = 한 장 직속 · 진형 드래그 = #modal).
   내비가 없는 화면(pregame — 시작 · 프롤로그)은 안 줄인다. 값과 대가는 src/ui/README.md 「화면 크기 정책」 */
#app:not(.pregame) > .main { zoom: .9; }
/* 탭 내용은 박스다 [2026-09-11 사용자 지시 · ADR-0097 · SCREEN_DESIGN §2 「박스」] — 탭 루트에 `.page` 가 붙으면 메인은 스크롤을 멈추고
   루트가 남는 세로를 다 먹는다. 박스 아랫변 = 탭 내비 「새 게임」 아랫변(한 장 788) — 내비 아래 여백 12 는 배율을 안 타므로 메인 아래 여백이 12 / .9 다.
   넘치는 내용은 박스 **안**이 받는다: 머리 아래 본문(`.box-body`) · 쌓인 판의 마지막(`.page-stack > .fill`) · 탭마다의 자리(리포트 상세 · 가방 칸 · 단계 목록).
   플래시 · 재접속 알림은 루트의 형제로 제 높이를 쓰고, 박스가 그만큼 준다 */
.main:has(> .page) { display: flex; flex-direction: column; overflow: hidden; padding-bottom: calc(12px / .9); }
.main > .page { flex: 1 1 0; min-height: 0; }
.panel.page, .page-stack { display: flex; flex-direction: column; }
.page-stack > * { flex: none; }
.page-stack > .fill { flex: 1 1 0; min-height: 0; overflow-y: auto; }
.box-body { flex: 1 1 0; min-height: 0; overflow-y: auto; }

/* ───────── 공통 조각 ───────── */

/* 패널은 살짝 비쳐서 배경 텍스처가 숨쉬되, 글자 대비는 유지한다 */
.panel {
    background: rgba(var(--surface-0-rgb), var(--panel-alpha));
    border: 1px solid var(--border-primary);
    padding: 10px 16px 11px;   /* 2026-09-01 세로 압축 — 가로 여백은 그대로 (읽기 폭은 안 건드린다) */
}

/* 선술집 = 거점 아트를 그대로 쓰는 자리 (town.webp 안에 상인 좌판과 7색 깃발이 있다) — 전역 배경과 같은 사본(`backgrounds_clean/`) */
.panel.town-bg {
    background:
        linear-gradient(rgba(var(--surface-0-rgb),var(--chrome-alpha)), rgba(var(--surface-0-rgb),var(--panel-alpha-deep))),
        url('../assets/art/backgrounds_clean/town.webp') center 34% / cover no-repeat;
    image-rendering: pixelated;
    border-color: var(--border-secondary);
}
.panel + .panel { margin-top: 14px; }
/* ⚠ 위 규칙은 **세로로 쌓을 때**의 여백이다. 격자(.cols) 안에서는 둘째 칸부터 위로 14px 밀려
   **첫 칸(장비)만 높이 서는** 어긋남이 생긴다 — 격자의 간격은 `gap` 이 이미 든다 (2026-09-01 사용자 지시) */
.cols > .panel + .panel { margin-top: 0; }
.panel > h2 {
    font-size: var(--fs-md); font-weight: normal; color: var(--text-secondary);
    letter-spacing: 1px; margin-bottom: 8px;
    border-bottom: 1px solid var(--border-dark); padding-bottom: 6px;
    display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
}
.panel > h2 small { text-align: right; }
.panel > h2 small { color: var(--text-muted); font-size: var(--fs-xs); letter-spacing: 0; }

.cols { display: grid; gap: 14px; }
.cols.c2 { grid-template-columns: 1fr 1fr; }
/* minmax 로 최소만 보장하고 나머지는 흐르게 — 영어에서 라벨이 길어져도 안 깨진다 */
.cols.c-side { grid-template-columns: minmax(300px, 24%) 1fr; }

.muted { color: var(--text-muted); }
.dim { color: var(--text-secondary); }
.right { text-align: right; }
.center { text-align: center; }
.up { color: var(--color-success); }
.down { color: var(--color-error); }

.btn {
    background: var(--bg-tertiary); border: 1px solid var(--border-secondary);
    padding: 7px 14px; color: var(--text-secondary);
}
.btn:hover { border-color: var(--border-highlight); background: var(--surface-4); }
.btn.primary { background: var(--btn-primary-bg); border-color: var(--btn-primary-line); color: var(--btn-primary-fg); }
.btn.primary:hover { background: var(--btn-primary-bg-hover); border-color: var(--text-accent); }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn.sm { padding: 3px 8px; font-size: var(--fs-sm); }

/* 기본은 **무채색**이다 (2026-09-03 사용자 지시) — 영웅의 죄종 칩에서 색을 걷었기 때문(SCREEN_DESIGN §5).
   챕터 줄 · 리포트의 정예 죄종은 여전히 인라인으로 죄종 색을 덮는다 — 그쪽은 「어느 죄종의 것인가」라는 다른 축이다 */
.sin-chip {
    display: inline-block; font-size: var(--fs-xs); padding: 0 6px;
    border: 1px solid currentColor; border-radius: 2px; line-height: 16px;
    color: var(--text-secondary);
    white-space: nowrap;   /* 영어 죄종명이 접히면 칩 모양이 무너진다 */
}

/* 영웅 2층 구조 — 유니크/레어 배지 (아이템 희귀도와 같은 계단).
   **죄종 칩과 같은 규격이다** (2026-09-03 사용자 지적) — 이름 줄에 나란히 서는 같은 층의 정체성인데
   9px / 12px 로 갈려 있어 한쪽이 덜 중요해 보였다. 크기 · 줄높이 · 여백을 죄종 칩에 맞춘다 */
.tier-chip {
    display: inline-block; font-size: var(--fs-xs); padding: 0 6px; line-height: 16px;
    border: 1px solid currentColor; border-radius: 2px;
}

/* 전투불능 — 방치형 계약의 언어("사망" 아님). 클래스 이름의 injury 는 옛 어휘가 남은 것이다 [09-06] */
.injury-chip {
    display: inline-block; font-size: var(--fs-xs); color: var(--color-error);
    border: 1px solid currentColor; padding: 0 5px; line-height: 15px; margin-top: 3px;
}
.party-slot.downed { opacity: .6; border-color: var(--downed-line); }
/* ~~.injury-box~~ (리포트의 전투불능 상자) 는 2026-09-10 삭제 — 기여 표의 영웅 줄이 **초상 회색**으로 든다 (ADR-0086) */

/* 고유 패시브 = 영웅 Implicit (유니크 전용) */
.passive-box {
    border: 1px solid var(--elite-line); background: var(--elite-bg); padding: 8px 10px; margin-bottom: 12px;
}
.passive-box .t { font-size: var(--fs-xs); color: var(--elite-fg); letter-spacing: 1px; margin-bottom: 3px; }
.passive-box .n { font-size: var(--fs-sm); color: var(--text-primary); }

/* 몬스터 얼굴 — 128×128 정사각 PNG. 원형 마스크는 CSS가 하고 파일에는 굽지 않는다. 원형은 몬스터 전용 — 영웅은 .hero-face(네모) */
.face {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; flex: 0 0 auto;
    background: var(--bg-input); border: 1px solid var(--border-secondary);
    border-radius: 50%; overflow: hidden; vertical-align: middle;
}
/* 칸 안에는 그림 하나뿐이다 — **밑에 아무것도 깔지 않는다** (2026-09-06 사용자 지시).
   옛 판은 이니셜을 깔고 이미지를 위에 덮었는데, 몬스터 그림도 배경 투명 PNG 라 여백 사이로 글자가 비쳤다 */
.face img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; image-rendering: var(--face-render); }
/* 아트가 없는 몬스터 — **빈 원**. 죄종 색 배경·테두리만 JS가 인라인으로 준다 (글자 없음) */
.face.boss { border-color: var(--text-accent); box-shadow: 0 0 0 1px rgba(var(--accent-rgb),.25); }

/* 영웅 초상 — 네모 박스 (2026-08-27). 관전 유닛 카드의 .sprite 와 같은 그림이다: 영웅의 생김새는 어디서나 같다.
   원형(.face)은 몬스터 전용. 죄종 색은 카드 상단 테두리가 든다 — 초상은 색을 갖지 않는다.
   **아트가 없으면 빈 칸이다** (2026-09-03 사용자 지시 — 직업 글리프 폐지. 그림이 배경 투명 PNG 라 밑에 깔면 비친다).
   기본 크기 64px. 크기는 담는 카드가 정한다 — 시작 화면 후보 카드는 키우고(.ng-head, 2026-08-31) 선술집 명단은 줄이며(.tv-cands),
   영웅 띠·관전 유닛 카드는 카드 전체로 키운다(아래 「카드를 채우는 초상」) */
.hero-face {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
    width: 64px; height: 64px;
    background: var(--bg-input); border: 1px solid var(--border-secondary);
    overflow: hidden; vertical-align: middle;
}
/* 그림은 칸을 통째로 덮는다. 그 스타일에 영웅 그림이 없으면 `onerror` 로 img 가 빠지고 **빈 칸**이 남는다
   (2026-08-30 영웅 초상 연결 · 2026-09-03 밑에 깔던 글리프 폐지) */
.hero-face img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }

/* 카드를 채우는 초상 — 영웅 띠 카드(.hs-card .hero-face) (2026-08-27, SCREEN_DESIGN §5).
   정사각으로 카드 전체를 채운다. 아트가 없으면 빈 칸이다 (2026-09-03 글리프 폐지).
   (관전 유닛 카드는 같은 얼굴 그림을 쓰되 구성이 가로형이라 여기 안 낀다 — 전투 관전 절의 .unit .sprite) */
.hs-card .hero-face {
    display: flex; align-items: center; justify-content: center;
    width: 100%; height: auto; aspect-ratio: 1; border: 0;
    background: var(--bg-input); overflow: hidden;
}
/* 카드 위칸 — 초상 위에 얹는 반투명 띠. 왼쪽 = 상태 · 오른쪽 = 이름. 안 들어가면 두 줄로 접힌다 (고정 px 없음) */
/* ⚠ `z-index` 가 없어 **띠가 초상 밑에 깔려 안 보였다** (2026-09-03 발견 · 이름과 「하는 일」이 화면에서 통째로 사라져 있었다).
   `.hs-band` 는 DOM 에서 초상보다 **앞**인데 `.hero-face` 도 위치 지정 요소라 뒤에 오는 쪽이 이긴다.
   초상 여백을 걷기 전에는 그림 위쪽이 투명해 「가려도 티가 안 나던」 것이라 더 늦게 드러났다 (SCREEN_DESIGN §5) */
.hs-band {
    position: absolute; top: 0; left: 0; right: 0; z-index: 1;
    /* **한 줄 고정** [2026-09-09 사용자 지시] — wrap 이 켜져 있어 `On expedition` 이 이름을 아랫줄로 밀었다.
       줄바꿈 대신 **「하는 일」만 말줄임**된다 — **이름은 안 줄어든다**(`flex-shrink:0`). 이름은 카드를 고르는 키이고,
       상태는 색(주황=원정 중)이 이미 말하므로 글자가 잘려도 뜻이 안 사라진다. 이름이 카드보다 길면 `max-width:100%` 가 받는다 */
    display: flex; flex-wrap: nowrap; align-items: baseline; justify-content: space-between; gap: 1px 6px;
    padding: 4px 7px 5px;
    background: color-mix(in srgb, var(--bg-primary) 78%, transparent);
    border-bottom: 1px solid var(--border-dark);
}
/* 위칸의 이름 — 오른쪽 정렬(접혀도 오른쪽), 넘치면 생략표 */
.hs-name {
    margin-left: auto; min-width: 0; max-width: 100%; flex: 0 0 auto;   /* 이름은 절대 안 줄어든다 (2026-09-09) */
    font-size: var(--fs-sm); font-weight: normal; line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}


.bar { height: 6px; background: var(--bg-input); border: 1px solid var(--border-dark); }
.bar > i { display: block; height: 100%; background: var(--color-info); }
.bar.xp > i { background: var(--xp-fill); }
.bar.hp > i { background: var(--hp-fill); }

/* ───────── 원정 ───────── */

/* 행 높이는 **못박는다** [2026-09-10 사용자 지시 · ADR-0080] — 접이식 「구성 보기」를 걷었다고 행이 짧아지면 안 된다.
   109 = 접이식이 있던 시절의 실측 높이(제목 줄 피치 117 − 아래 여백 8). 걷어낸 것이 그 안에서 차지하던 자리는
   요약 줄 20 + 격자 행 간격 12 + 위 여백 2 로 **38px** 였다.
   ⚠ 이 값이 없으면 행이 71px 로 줄어 **배경 아트가 그만큼 잘린다** — 행의 그림은 스테이지를 알아보는 단서다.
   `align-items: center` 라 남는 세로는 글 위아래로 고르게 퍼진다 */
.zone {
    display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: center;
    min-height: 109px;
    padding: 11px 12px; background: var(--bg-tertiary);
    border: 1px solid var(--border-dark); border-left: 3px solid var(--border-secondary);
    margin-bottom: 8px;
}
/* 69.3% = 잘라 낸 사본(2752×1360)에서 원본(×1536)의 60% 와 **같은 띠**가 보이는 값 — 행 그림은 안 바뀐다 (2026-09-11 · 아래 `.arena.has-bg`) */
.zone.has-bg { background-size: cover; background-position: center 69.3%; image-rendering: pixelated; }
.zone.locked { opacity: .45; }
.zone.boss { border-left-color: var(--text-accent); }
.zone .title { display: flex; align-items: center; gap: 8px; }
.zone .meta { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 2px; }
/* 행 클릭 = 고른다 (2026-08-27, SCREEN_DESIGN §4-1) — 출발은 위에 열리는 편성 패널이 든다.
   커서는 실제로 눌리는 행에만 준다. 잠긴 행은 눌러도 플래시뿐이라 안 준다 */
.zone:not(.locked) { cursor: pointer; }
.zone:not(.locked):hover { border-color: var(--border-highlight); }
.zone.on { border-color: var(--border-highlight); background-color: var(--bg-card); margin-bottom: 0; }
/* 픽셀아트 배경 위에 얹히므로 제 배경을 갖는다 — 글자 그림자만으로는 불타는 배경에서 안 읽힌다 */
.zone-pick {
    font-size: var(--fs-sm); color: var(--text-secondary); white-space: nowrap;
    padding: 4px 10px; background: rgba(var(--veil-rgb),.74); border: 1px solid var(--border-dark);
}
.zone.on .zone-pick { color: var(--text-primary); background: var(--surface-6); border-color: var(--border-highlight); }

/* ───────── 출정 창 (SCREEN_DESIGN §4-1 · ADR-0084 · ADR-0088) ─────────
   스테이지 행을 누르면 **탭 위에 겹쳐 뜨는 창**이다 — 접이식 전진 패널(`.form-panel` · 2026-08-28~2026-09-10)을 걷었다.
   껍데기(어두운 판 · 가운데 · 정사각 X)는 셸의 창(.modal-layer/.modal-box)을 **그대로** 쓰고 여기서는 크기만 정한다 —
   로그 창(.bw-box)이 같은 자리에서 쓰는 장치다.
   **폭을 못박는 이유**는 판 크기를 내용에 맡기면 상태가 크기를 흔들기 때문이다: 경고 줄의 글자가 있고 없고에 따라
   출정 칸 폭이 바뀌면 창이 통째로 넓어졌다 좁아졌다 한다(「크기는 상태에 흔들리지 않는다」 · 2026-08-28 사용자 지시).
   폭은 1180 → 1280 → **1520** [2026-09-10 사용자 지시 — 「탭 자체를 더 키워라」]. 판 여백은 창 공통(12/14)보다 넉넉하게 준다 — 칸이 넷이다.
   **높이는 칸이 아니라 간격 · 여백으로 키웠다** [2026-09-10 사용자 지시 · ADR-0088] — 칸을 키우면 가로가 같이 커진다.
   ⚠ **선택자가 `.modal-box.depart-box` 인 것이 기능이다** — `.depart-box` 한 단이면 뒤에 선언된 창 공통 `.modal-box` 와 명시도가 같아
     여백이 그쪽(12/14/14)에 덮여 안 먹었다(옛 16/20/20 도). 이 창에서만 한 단 올린다 — `.modal-box` 자체는 안 건드린다 */
/* **배율 .9** [2026-09-11 사용자 지시 · ADR-0099] — 창의 배율은 **창마다 정한다**(창은 한 장 직속이라 메인 배율을 안 물려받는다).
   출정 창은 띠 카드가 **캐릭터 탭 띠와 같은 크기**로 보이게 줄인다 — 메인과 같은 값이지만 묶지 않는다(메인이 바뀌어도 이 창은 제 값).
   폭 1520 · 칸 118 · 여백은 **설계 크기**이고 화면에는 90% 로 선다. 배율 아래서는 보이는 폭과 `offsetWidth` 가 갈린다 —
   진형 드래그 고스트가 그 차를 보정한다(`app.js:bindFormDrag`) */
/* **높이를 한 번 더 키운다** [2026-09-14 사용자 지시 — 「너무 답답해 보인다」] — 이번에도 칸이 아니라 간격으로:
   판 위아래 여백 22/26 → 36/40 · 머리와 속 사이 10 → 24(창 공통 `gap` 을 이 창에서만 덮는다) · 줄 사이 · 칸 이름 아래는 아래 규칙.
   **가로 여백 24 는 그대로다** — 늘리면 아래 줄 왼쪽 칸(진형 + 출정 방식 · ADR-0105)에 남는 폭이 없어 넘친다 */
.modal-box.depart-box { width: min(1520px, 100%); padding: 36px 24px 40px; gap: 24px; zoom: .9; }
/* 속은 **칸 넷이 격자 하나에 2×2** 다 [2026-09-10 사용자 지시 · ADR-0088]
     위 줄   = 캐릭터 선택(띠) ↔ 적 구성 — 누구를 보내나 ↔ 누구와 싸우나(마주 선다)
     아래 줄 = 진형 → 출정 방식(한 칸에 나란히) ↔ 이야기 — 어떻게 세우나 → 갈까 ↔ 어떤 곳인가 [2026-09-14 · ADR-0105]
   열 폭은 오른쪽 = 적 구성 내용 폭(`auto`) · 왼쪽 = 남는 폭이고, 이야기는 그 오른쪽 열 폭을 받는다(글이 열을 안 넓힌다 — `.dw-story`).
   칸 넷이 **격자의 직접 자식**이라 세로 구분선이 두 줄을 관통한다. `align-items` 는 기본(stretch) —
   구분선이 줄 높이 전체에 서고, 칸 안 내용은 위 정렬 그대로다 */
.dw-body { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
/* 가림막 · 여백 — 칸마다 오른쪽 · 아래 여백을 두고, 오른쪽 열(`.dw-c2`)은 왼쪽에 세로선 · 아래 줄(`.dw-r2`)은 위에 가로선을 세운다 */
/* 줄 사이 28 + 28 → **48 + 48** [2026-09-14 사용자 지시 — 「답답해 보인다」 · 위 `.depart-box` 와 같은 날] — 가로선 위아래가 같은 폭이라 선이 두 줄 사이 가운데에 선다 */
.dw-body > * { padding-right: 26px; padding-bottom: 48px; }
.dw-body > .dw-c2 { padding-right: 0; padding-left: 26px; border-left: 1px solid var(--border-secondary); }
.dw-body > .dw-r2 { padding-bottom: 0; padding-top: 48px; border-top: 1px solid var(--border-secondary); }
/* 칸 하나 — 이름 + 내용. 지금 이 껍데기를 쓰는 것은 캐릭터 선택(띠) 하나다(나머지 셋은 제 상자가 있다) */
.dw-block { min-width: 0; }
/* ⚠ **띠 카드는 공통 규격 그대로다** [2026-09-10 사용자 지시 — 같은 날의 `max-width: 160px` 특례를 철회] —
   창이 커진 몫은 **적 구성 · 진형 칸**(`--fm-slot`)이 받는다. 띠는 캐릭터 탭과 같은 카드여야 같은 부품으로 읽힌다(§5) */
/* 창 머리 = **고른 스테이지의 신원**. 접이식이던 시절엔 바로 위 행이 말하던 것이라 패널에 머리가 없었는데,
   창은 목록에서 떨어져 뜨므로 여기가 그 자리를 이어받는다. 잔글씨(위험도·소요·원소)는 스테이지 행이 찍는 것과 같은 값 */
.dw-title { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
.dw-title small { font-size: var(--fs-sm); font-weight: 400; color: var(--text-muted); }
/* 진형 목업 (SCREEN_DESIGN §4-1) — 랭크 줄은 **항상 3줄**이고, 2랭크 템플릿의 셋째 줄은 빈 줄로 남는다.
   그 빈 줄의 높이를 `min-height` 가 잡는다 — 안 잡으면 템플릿을 바꿀 때 패널이 커졌다 작아져
   「패널 크기는 상태에 흔들리지 않는다」(2026-08-28)가 깨진다.
   라벨 칸에 고정 px 를 안 쓴다 — 영어(Front/Mid/Back)가 한국어보다 길다 */
/* 상자는 **내용에 딱 맞는다** [2026-09-09 사용자 지시 · ADR-0060] — 여백도 구분선도 제목 줄도 없다.
   ⚠ 옛 값(`margin-top`·`padding-top`·`border-top`)은 띠가 이 상자 **위**에 있던 시절 그것과 가르던 선이고,
     띠가 탭 최상단으로 올라가면서(ADR-0055) 위에 아무것도 없게 됐다. 그때 넣었던 `.form-panel > .fm-box:first-child`
     예외는 ADR-0059 로 상자가 `.fp-row` 안으로 들어가며 **선택자가 안 맞게 됐다** — 규칙째 걷는 쪽으로 닫는다.
   ~~`.fm-head`(「진형」 제목 줄)~~ 도 같이 삭제 — 아이콘 셋과 전열/후열 라벨이 이미 무엇인지 말한다 */
/* 상자는 **제 이름을 단다** [2026-09-10 사용자 지시 · ADR-0079 가 ADR-0060 을 대체].
   가림막은 상자가 아니라 **격자가 세운다**(`.dw-body > .dw-r2` · ADR-0088) — 칸 넷이 같은 규칙으로 갈린다 */
.fm-box {
    margin: 0;
    flex: 0 0 auto;
}
/* 왼쪽 = 템플릿 아이콘 · 오른쪽 = 보드. 덩어리는 **패널 왼쪽에 붙는다**
   [재개정 2026-09-09 사용자 지시 · ADR-0059 — 같은 날의 「가운데로」(ADR-0057)를 물렸다]:
   비어 있던 오른쪽 자리를 **출발 칸**이 받으므로 진형은 왼쪽에 서는 것이 맞다.
   ⚠ 옛 판은 아이콘을 **세로 가운데**에 뒀다(「위로 붙이면 아이콘 아래가 텅 빈다」) — 2026-09-10 에 걷었다:
     그 열이 이제 **이름 + 아이콘**을 들고, 이름은 옆 칸(출정 방식)의 이름과 **같은 줄**에 서야 한다.
     가운데 정렬이면 열 전체가 내려가 두 이름이 어긋난다 (ADR-0080) */
.fm-main { display: flex; align-items: flex-start; gap: 20px; }

/* 템플릿 = 정사각 아이콘, **가로 배치** (2026-09-09 사용자 지시 — 옛 세로 기둥 폐기).
   보드 옆에 두어 세로 비용이 0 이다 — 머리줄에 얹으면 아이콘 높이가 패널에 더해져 보내기가 접힌다(실측).
   글자가 없다 — 모양(점)이 곧 뜻이라 언어 중립이고 i18n 키가 없다.
   셋 중 하나를 고르는 것이라 .toggle(초록 ON/OFF)이 아니라 .on(고른 것)을 쓴다 */
.fm-tpls { display: flex; gap: 7px; }
.fm-tpl {
    width: 46px; height: 46px; padding: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
}
.fm-tpl.on { border-color: var(--border-highlight); background: var(--surface-6); }
.fm-tpl i { display: flex; gap: 4px; }
.fm-tpl b { width: 7px; height: 7px; background: var(--text-muted); border-radius: 1px; }
.fm-tpl.on b { background: var(--text-accent); }

/* 보드 — **높이가 고정**이라 템플릿을 바꿔도 「보내기」의 자리가 안 움직인다 (2026-08-28).
   랭크 최대가 둘(2·1 · 1·2)이므로 두 줄분으로 못박고, 한 줄짜리(3)는 그 안에서 **가운데**에 선다.
   줄 높이는 칸 한 변으로 고정 — 줄 수가 칸 크기를 바꾸지 않는다(칸은 언제나 얼굴 크기다).
   라벨 칸에 고정 px 를 안 쓴다 — 영어(Front/Back)가 한국어보다 길다 */
.fm-board {
    display: flex; flex-direction: column; justify-content: center;
    gap: 7px; min-width: 0; height: var(--fm-board-h);
}
.fm-row { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; height: var(--fm-slot); }
/* 라벨은 **칸 쪽으로 붙인다**(오른쪽 정렬) — 칸이 가운데로 모이면서 왼쪽에 떨어져 있으면 어느 줄의 이름인지 눈이 안 잇는다.
   폭은 `em` 이라 영어(Front/Back)가 길어져도 안 깨진다 (고정 px 금지) */
.fm-label {
    flex: 0 0 auto; min-width: 3.6em; text-align: right;
    font-size: var(--fs-xs); color: var(--text-secondary); white-space: nowrap;
}
/* 칸은 **정원 최대(3칸) 폭의 축 위에서 가운데 정렬**된다 (2026-09-09 · ADR-0057) —
   2·1 이면 앞 둘이 양옆, 뒤 하나가 그 사이에 와서 **진형이 모양으로 읽힌다**(관전 아레나와 같은 그림 · ADR-0053).
   폭을 늘 3칸으로 잡아 두므로 템플릿을 바꿔도 축이 안 흔들린다 */
.fm-cells { display: flex; justify-content: center; gap: 7px; width: var(--fm-axis); height: 100%; }

/* 칸은 정사각이고 높이를 줄에서 받는다 — 영웅 띠 카드와 같은 크기라
   빈 칸이 「여기에 영웅을 놓는다」로 크기만으로 읽힌다 */
.fm-cell {
    /* 폭은 aspect-ratio 가 높이에서 뽑는다 — flex 가 줄이지 못하게 0 0 auto 로 못박는다(안 그러면 칸이 납작해진다) */
    flex: 0 0 auto; height: 100%; aspect-ratio: 1; position: relative; overflow: hidden;
    border: 1px dashed var(--border-secondary); background: var(--bg-secondary);
}
.fm-cell.filled {
    border: 1px solid var(--border-dark); border-top: 3px solid var(--border-secondary);
    background: var(--bg-tertiary);
    /* 드래그가 이 칸의 동사다 · touch-action 을 끊어야 포인터 이동이 스크롤로 안 샌다 */
    cursor: grab; touch-action: none;
}
.fm-cell.filled:hover { border-color: var(--border-highlight); }
.fm-cell.drag { opacity: .35; cursor: grabbing; }
.fm-cell .hero-face { width: 100%; height: 100%; border: 0; background: var(--bg-input); }
/* 이름은 초상 위 반투명 띠 — 영웅 띠 카드(.hs-band)와 같은 문법이되 이름 하나뿐이라 따로 둔다 */
.fm-nm {
    position: absolute; top: 0; left: 0; right: 0; z-index: 1;
    padding: 2px 5px; font-size: var(--fs-xs); line-height: 1.25;
    text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    background: color-mix(in srgb, var(--bg-primary) 72%, transparent);
}
/* 드래그 고스트 — 커서를 따라다니는 **감싸개**이고 안에 클론 하나가 든다 [2026-09-11]. 놓을 자리 판정(elementFromPoint)을 가리면 안 되므로 클릭을 안 받는다.
   위치 규칙은 감싸개에만 건다 — 클론에 달면 뒤에 선언된 `.hs-card { position: relative }` 가 이겨 띠에서 끈 고스트가 한 장 밖으로 떨어진다(`app.js:bindFormDrag`).
   툴팁(z-index 50)보다는 아래 */
.fm-ghost { position: fixed; z-index: 45; pointer-events: none; cursor: grabbing; opacity: .9; }

/* 같은 크기 버튼 둘 — 반복 원정 / 보내기 */
/* 칸 이름 — **왼쪽 위 · 같은 규격**으로 칸 넷에 선다 [2026-09-10 사용자 지시 · ADR-0079].
   `--fs-xs`(속 라벨 크기)에서 `--fs-md` 로 올렸다: 이건 칸 안의 잔글씨가 아니라 **칸의 이름**이라 층이 다르다.
   아래 여백 9 → 12 [2026-09-10 · ADR-0088] → **20** [2026-09-14 사용자 지시 — 「답답해 보인다」] — 창 높이를 칸이 아니라 간격으로 키운 몫 */
.foe-h, .fm-h, .dw-h {
    font-size: var(--fs-md); color: var(--text-secondary); letter-spacing: .5px;
    margin-bottom: 20px; line-height: 1.2; white-space: nowrap;
}
/* 진형의 이름은 **왼쪽 열 맨 위**다 [2026-09-10 사용자 지시 · ADR-0080] — 상자 위에 얹으면 그 줄 높이가
   패널에 그대로 더해져 창이 세로로 커졌다. 이 열(템플릿 아이콘 셋)은 보드보다 한참 짧아 위가 비어 있으므로
   거기 얹으면 **세로 비용이 0** 이고 이름이 보드와 같은 줄에 선다 */
/* 위 정렬 — 「출정 방식」과 **같은 줄**에 서야 두 이름이 한 줄로 읽힌다.
   아이콘 셋은 이름 바로 밑에 붙고, 이 열의 남는 아래쪽은 비운다(오른쪽이 보드라 빈 자리가 안 보인다) */
.fm-side { display: flex; flex-direction: column; justify-content: flex-start; }
/* **가로 한 줄** — 넷이 나란히 선다 [2026-09-10 사용자 지시]. 세로로 쌓은 판을 걷었다:
   칸이 진형보다 높아져 패널을 통째로 늘렸는데, 정작 이 칸이 쓰라고 비어 있던 자리는 **가로**였다.
   칸 사이는 진형과 같은 7px — 두 덩어리가 같은 리듬으로 서야 마주 놓인 것으로 읽힌다 */
/* **자리는 늘 넷만큼 잡는다** [2026-09-11 · ADR-0098] — 보통 스테이지는 일반 셋 + 보스 하나지만 챕터보스 스테이지는 보스 칸 하나뿐이다.
   칸 수에 폭을 맡기면 오른쪽 열(= 세로 구분선의 자리 · ADR-0088)이 스테이지마다 줄었다 늘었다 해서 그 선에 붙은 「보내기」가 옮겨 다닌다 (104 ↔ 105 실측) */
.foe-list { display: flex; align-items: center; gap: 7px; min-width: calc(var(--fm-slot) * 4 + 7px * 3); }
/* 칸은 **진형 칸과 같은 크기·같은 정사각**이다 [2026-09-10 사용자 지시] — `--fm-slot` 을 그대로 읽으므로
   진형 칸이 커지면 이 칸도 같이 커진다(두 값이 갈라지면 「마주 놓는다」가 깨진다).
   생김새도 `.fm-cell.filled` 를 따른다: 얇은 테두리 + **윗변 3px** · 그림이 칸을 통째로 덮는다.
   ⚠ 원형(`.face`)이 아니다 — 몬스터를 정사각으로 그리는 자리는 관전 유닛 카드가 이미 있다(ADR-0022).
      도감 · 접이식 「구성 보기」의 원형은 그대로다 */
/* 윗변 = **일반 몬스터의 등급 색** — 영웅 · 장비의 일반과 **같은 밝은 회색**이다 [2026-09-14 사용자 지시].
   같은 「일반」이 짙은 회색(몬스터) · 흰색(영웅 · 장비)으로 갈려 있었다. 공용 토큰 `--border-secondary` 를 바꾸지 않고
   이 칸에만 준다(그 토큰은 다른 테두리도 쓴다). 값은 `data/hero_tier.csv:normal` · `ui/mock.js:RARITY.normal` 과 **같다 — 하나를 바꾸면 셋 다** */
.foe-cell {
    position: relative; overflow: hidden; flex: 0 0 auto;
    width: var(--fm-slot); height: var(--fm-slot);
    background: var(--bg-tertiary);
    border: 1px solid var(--border-dark); border-top: 3px solid #D8D8D8;
}
.foe-cell img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
/* 보스는 **윗변 색**이 든다 — 등급을 윗변이 말하는 것은 관전 카드와 같은 문법이다 (ADR-0021) */
.foe-cell.boss { border-top-color: var(--text-accent); }
/* **초상만** 선다 — 이름은 안 적고 호버(`title`)가 든다 [2026-09-10 사용자 지시].
   덕분에 칸 폭이 몬스터 이름에 안 매인다: 이름을 적던 판은 Ch7-4 `Grand Gargoyle Thronekeeper`(27자)가
   한 줄로 뻗어 하한 1280 에서 **보내기 버튼을 화면 밖으로 밀고 가로 스크롤을 만들었다** (실측).
   칸 크기는 아래 `.foe-cell` 이 진형에서 받아 온다 */
/* 아래 줄 왼쪽 칸 = **진형 → 출정 방식이 나란히** [2026-09-14 사용자 지시 · ADR-0105] — 진형 보드 오른쪽이 절반 넘게 비어 있었다.
   진형은 칸 왼쪽에 붙고 출정 방식은 **칸 오른쪽 끝**(세로 구분선 바로 왼쪽)에 선다. **위 정렬** — 두 칸 이름이 한 줄에 선다 (ADR-0080) */
.dw-prep { display: flex; align-items: flex-start; justify-content: space-between; gap: 26px; }
/* **출정 방식** — 이름 + 위험도 + 경고 + 버튼 둘. **폭은 못박는다** — 옛 자리에서는 열(적 구성 내용 폭)이 정했는데,
   제 폭이 없으면 경고 줄의 글자가 폭을 흔들어 버튼이 옆으로 옮겨 다닌다(「크기는 상태에 흔들리지 않는다」 · 2026-08-28).
   라벨이 드는 칸이라 고정 px 가 아니라 `clamp()` — 상한은 진형 옆에 남는 폭이다 */
.fp-side { display: flex; flex-direction: column; align-items: stretch; gap: 10px; flex: 0 0 clamp(240px, 20em, 300px); }
/* 이 칸의 이름은 아래 여백을 **flex `gap`(10) 만큼 덜** 준다 — 옆 칸 이름 아래(20)와 합이 같아야 내용의 윗선이 옆 칸과 맞는다 */
.fp-side .dw-h { margin-bottom: 10px; }
/* 위험도 줄 — 출정 방식 칸 맨 위 (SCREEN_DESIGN §4-1 · ADR-0104). 윗줄 라벨 + 범위 · 아랫줄 버튼 넷 + 지금 레벨.
   못 올리는 상태에서도 줄은 그대로 서고 버튼만 흐려진다 — 창 크기가 상태에 안 흔들린다 */
.lv-box { display: flex; flex-direction: column; gap: 4px; }
.lv-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.lv-h { font-size: var(--fs-sm); color: var(--text-secondary); white-space: nowrap; }
.lv-range { font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* 버튼 넷과 숫자는 **한 무리로 가운데에 모인다** — 숫자가 칸 폭을 먹으면 `‹` `›` 가 양끝으로 벌어져 한 조절기로 안 읽힌다 */
.lv-row { display: flex; align-items: center; justify-content: center; gap: 4px; }
.lv-btn { flex: 0 0 auto; min-width: 2.2em; text-align: center; }
.lv-val { flex: 0 0 auto; min-width: 3em; text-align: center; font-size: var(--fs-lg); color: var(--text-primary); font-variant-numeric: tabular-nums; }
/* 올린 레벨 — 출정 창의 숫자 · 창 머리 · 스테이지 목록 행이 같은 강조색을 쓴다 */
.lv-val.up, .lv-up { color: var(--text-accent); }
/* 세로로 쌓이던 시절의 윗 여백을 걷는다 — 이제 제 칸 안에서 경고 줄 바로 밑이다 */
/* 버튼 둘은 **세로로 쌓는다** [2026-09-10 사용자 지시] — 가로로 나란하던 것을 세웠다.
   `stretch` 라 둘의 폭이 저절로 같아진다(옛 `min-width: 148px` 는 가로 배치에서 크기를 맞추던 값이라 하한으로만 남긴다) */
.form-actions { display: flex; flex-direction: column; align-items: stretch; gap: 8px; }
.form-actions .btn.lg { flex: 0 0 auto; min-width: 148px; text-align: center; }
/* 아래 줄 오른쪽 = **이야기** [2026-09-14 사용자 지시 · ADR-0105] — 이 스테이지의 입장 텍스트. 읽는 자리라 클릭이 없다.
   **크기 격리**(`contain: size`) — 글이 긴 스테이지가 열을 넓히거나 줄을 키우지 않는다: 폭은 적 구성이 정한 열 폭,
   높이는 진형이 정한 줄 높이를 격자의 stretch 로 받는다. 넘치는 글은 잘린다 */
.dw-story { contain: size; overflow: hidden; }
.dw-story-text { margin: 0; font-size: var(--fs-md); line-height: 1.7; color: var(--text-primary); word-break: keep-all; }

.running {
    background: linear-gradient(var(--bg-tertiary), var(--bg-card));
    border: 1px solid var(--border-secondary);
    padding: 14px 16px; margin-bottom: 14px;
}
.running .head { display: flex; justify-content: space-between; margin-bottom: 10px; }

.party-slot {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 10px; background: var(--bg-tertiary);
    border: 1px solid var(--border-dark); margin-bottom: 6px;
}
.party-slot.empty { justify-content: center; color: var(--text-muted); border-style: dashed; }
/* "Archer · Lv.8" 이 중간에서 접히면 가운뎃점만 앞줄에 남는다 — 통째로 넘긴다 */
.party-slot .lv { font-size: var(--fs-sm); color: var(--text-muted); white-space: nowrap; }

/* ───────── 로스터 ───────── */

/* (선술집 로스터 격자 .hero-grid/.hero-card 는 2026-08-26 공통 영웅 띠로 대체 — 삭제) */

/* ───────── 장비 ───────── */

.slot-row {
    /* 죄종 칩 열은 고정폭이면 영어 "Gluttony" 가 잘린다 — 내용에 맞춰 늘어나게 */
    display: grid; grid-template-columns: minmax(44px, auto) minmax(0, 1fr); gap: 9px; align-items: center;
    padding: 7px 9px; background: var(--bg-tertiary);
    border: 1px solid var(--border-dark); margin-bottom: 5px;
}
.slot-row.on { border-color: var(--border-highlight); }
.slot-row .slot-label { font-size: var(--fs-sm); color: var(--text-muted); }
.slot-row .item-name { font-size: var(--fs-sm); word-break: keep-all; }
.slot-row.vacant .item-name { color: var(--text-muted); }

.stat-table { width: 100%; font-size: var(--fs-sm); border-collapse: collapse; }
.stat-table td { padding: 3px 0; }
.stat-table td:last-child { text-align: right; color: var(--text-primary); }
.stat-table td:first-child { color: var(--text-secondary); }
.stat-table tr.sep td { border-top: 1px solid var(--border-dark); padding-top: 8px; }

/* 접사 죄종 태그 — 세트포인트가 아니다 (세트효과 보류, item_design §4). 수는 죄종 접사 수 */
.sin-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.sin-tag {
    font-size: var(--fs-xs); padding: 1px 7px; border: 1px solid currentColor;
    display: inline-flex; align-items: center; gap: 5px;
}
.sin-tag b { font-weight: normal; }

.inv-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 7px; }
.inv-item {
    background: var(--bg-tertiary); border: 1px solid var(--border-dark);
    padding: 8px 10px; cursor: pointer; position: relative;
}
.inv-item:hover { border-color: var(--border-highlight); background: var(--surface-3); }
.inv-item .n { font-size: var(--fs-sm); word-break: keep-all; }
.inv-item .s { font-size: var(--fs-xs); color: var(--text-muted); margin-top: 2px; }

/* 비교 툴팁 — 장비 게임의 핵심 UI */
/* ⚠ **`pointer-events: none` 이 기능이다** [2026-09-10 버그 수정] — 툴팁은 z-index 50 으로 **드래그 고스트(45)보다도 위**라,
   이게 없으면 진형 드래그의 놓을 자리 판정(`app.js:bindFormDrag` 의 `elementFromPoint`)이 **툴팁을 먼저 집는다**.
   증상이 자리마다 갈렸던 이유는 `moveTip` 이 커서 오른쪽 아래(+16,+16)에 띄우다가 **화면 아래에 닿으면 위로 접기** 때문이다 —
   접힌 순간에만 툴팁이 커서 지점을 덮어서 그 자리에서만 드롭이 죽었다. 툴팁은 읽는 것이지 누르는 것이 아니다 */
.tooltip {
    position: fixed; z-index: 50; display: none; pointer-events: none;
    background: var(--bg-secondary); border: 1px solid var(--border-secondary);
    padding: 0; box-shadow: 0 6px 24px rgba(var(--shadow-rgb),.75);
    max-width: 640px;
}
.tooltip.show { display: flex; }
.tip-card { width: 304px; padding: 11px 13px; font-size: var(--fs-sm); }
.tip-card + .tip-card { border-left: 1px solid var(--border-dark); background: var(--bg-input); }
.tip-card .tip-head { font-size: var(--fs-xs); color: var(--text-muted); margin-bottom: 5px; letter-spacing: 1px; }
.tip-card .tip-name { font-size: var(--fs-md); word-break: keep-all; margin-bottom: 3px; }
.tip-card .tip-sub { font-size: var(--fs-xs); color: var(--text-muted); margin-bottom: 8px; }
/* **메인 옵션(밑수)** [개정 2026-09-10 사용자 지시 · ADR-0081] — ~~`.tip-implicit` 한 줄~~ 을 대체한다.
   본문(`--fs-sm`)보다 **한 단 큰 값**이 이름 오른쪽에 선다: 아이템을 고르는 첫 판단이 이 두세 줄이고,
   접사 목록(`--fs-xs`)과 크기로 층이 갈려야 「밑수 ↔ 굴린 옵션」이 눈에 먼저 들어온다.
   값은 **오른쪽 정렬** — 두 카드가 나란히 서는 비교 툴팁에서 같은 x 에 값이 모여야 대조가 된다 */
.tip-card .tip-base { margin-bottom: 8px; }
.tip-card .tip-base .r {
    display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
    padding: 1px 0;
}
.tip-card .tip-base .n { font-size: var(--fs-sm); color: var(--text-secondary); word-break: keep-all; }
/* 원소는 마법 무기 **개체**가 든 값이라 이름의 주석으로 붙는다 — 영웅 툴팁의 약어(`.tip-stat .n i`)와 같은 문법 */
.tip-card .tip-base .n i { font-style: normal; color: var(--text-muted); font-size: var(--fs-xs); margin-left: 5px; }
.tip-card .tip-base b { font-size: var(--fs-md); font-weight: normal; color: var(--color-info); white-space: nowrap; }
/* ~~`.tip-up`~~ (강화 줄) 삭제 2026-09-08 — 툴팁이 강화를 말하지 않는다 (SCREEN_DESIGN §6) */
/* 영웅 툴팁 — 기본 능력치 7 (2026-08-28). 이름 왼쪽 · 값 오른쪽, 두 칸으로 접어 세로를 줄인다 */
.tip-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 14px; margin-top: 2px; }
.tip-stat { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: var(--fs-xs); }
.tip-stat .n { color: var(--text-secondary); }
.tip-stat .n i { font-style: normal; color: var(--text-muted); margin-left: 4px; }
.tip-stat b { font-weight: normal; color: var(--text-primary); }
/* 스킬 툴팁 — 이름 앞 아이콘 · 설명 문단 */
/* 그림이 들어오면서 인라인 블록이 된다 (2026-09-03 · SCREEN_DESIGN §2) — 이름 줄의 baseline 을 흔들지 않게 가운데 정렬 */
.tip-sk-ico { margin-right: 7px; display: inline-block; width: 22px; height: 22px; vertical-align: middle; }
.tip-sk-ico img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
.tip-desc { font-size: var(--fs-sm); color: var(--text-secondary); line-height: 1.55; word-break: keep-all; }
/* 담은 스킬 [신설 2026-09-09 · 자리 개정 2026-09-10 ADR-0081] — 무기가 액티브 한 칸을 통째로 정하므로 툴팁이 그것을 말한다.
   자리는 **카드 바닥**이다(접사 목록 아래). 윗선 하나로 「아이템의 수치」와 「무기가 데려오는 것」을 가른다 —
   아랫선은 안 긋는다: 힌트 줄(`.tip-sins`)이 자기 윗선을 들고 있어 두 줄이 붙어 선다.
   문장(`.ln`)은 액티브 줄(`.act-slot .ln`)과 같은 함수가 낸 것이라 크기도 같은 단으로 맞춘다 */
.tip-card .tip-skill {
    margin: 9px 0 0; padding: 7px 0 0;
    border-top: 1px solid var(--border-dark);
}
.tip-card .tip-skill .hd { display: flex; align-items: center; gap: 6px; }
.tip-card .tip-skill .ico { width: 22px; height: 22px; flex: 0 0 auto; }
.tip-card .tip-skill .ico img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
.tip-card .tip-skill b { font-size: var(--fs-sm); }
.tip-card .tip-skill .cd { font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; }
/* 라벨은 **오른쪽 끝**으로 민다 — 이름이 먼저 읽혀야 하고 라벨은 「이게 무슨 줄인가」만 답한다 */
.tip-card .tip-skill .lb { margin-left: auto; font-size: var(--fs-2xs); color: var(--text-muted); letter-spacing: 1px; }
.tip-card .tip-skill .ln { margin-top: 4px; font-size: var(--fs-xs); color: var(--text-secondary); line-height: 1.35; word-break: keep-all; }
.tip-card .tip-skill.empty { color: var(--text-muted); font-size: var(--fs-xs); }
.tip-card ul { list-style: none; }
.tip-card li { color: var(--info-fg); }
/* 옵션 출처 태그 (SCREEN_DESIGN §6 · ADR-0100) — 접사 줄 **앞**에 선다. 셋이다: 고정 · 죄종 이름 · 랜덤.
   고정 · 랜덤은 줄마다 반복되므로 **값보다 약하게** 둔다: 읽히되 접사 이름·수치를 밀어내지 않는 밝기다.
   **죄종 칸만 색을 받는다** — 글자색은 렌더러가 `SINS` 색을 인라인으로 넣고 테두리가 그 색을 따른다 (2026-09-11 R78) */
.tip-src {
    font-style: normal; font-size: var(--fs-2xs); color: var(--text-muted);
    border: 1px solid var(--border-dark); padding: 0 4px; margin-right: 6px;
    vertical-align: middle;
}
.tip-src.sin { border-color: currentColor; }
/* 하단 태그 줄 — 죄종 태그 + 힌트(반지 칸 · 착용 중 없음). 둘 다 없으면 렌더러가 줄째 안 낸다(구분선만 남으면 안 된다).
   간격은 `gap` 이 든다 — 옛 판은 태그마다 인라인 `margin-right` 였고 힌트는 그 규칙 밖이었다 (2026-09-08) */
.tip-card .tip-sins {
    margin-top: 8px; padding-top: 7px; border-top: 1px solid var(--border-dark);
    display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
}
.tip-card .tip-empty { color: var(--text-muted); }

/* ───────── 리포트 ───────── */

.report-head {
    display: flex; align-items: baseline; gap: 14px; padding-bottom: 12px;
    border-bottom: 1px solid var(--border-dark); margin-bottom: 12px;
}
.report-head .verdict { font-size: var(--fs-xl); }
.report-head .verdict.clear { color: var(--color-success); }

/* 획득 줄 — 여섯 칸의 **자리가 고정**이다 (ADR-0086). 내용 폭에 맡기면 「없음」↔「3명」 같은 값 글자에 옆 칸이 밀린다.
   몫은 그 칸이 흔히 드는 글자 길이를 따른다(빗나감 `12 / 261 (5%)` · 영어 `Codex cards 2 cards` 가 길다).
   하한이 `max-content` 라 몫을 넘는 값은 잘리지 않고 칸을 민다 — 값은 항상 찍는다 */
.gain-row {
    display: grid; column-gap: 12px; margin-bottom: 14px; font-size: var(--fs-sm); white-space: nowrap;
    grid-template-columns:
        minmax(max-content, .8fr) minmax(max-content, 1fr) minmax(max-content, .8fr)
        minmax(max-content, .9fr) minmax(max-content, 1.4fr) minmax(max-content, 1.3fr);
}
.gain-row div span { color: var(--text-muted); margin-right: 7px; }

/* 런 목록 — 왼쪽 열. 한 줄 = 한 런이고 클릭이 오른쪽 상세를 바꾼다 (ADR-0063)
   **두 열의 높이는 박스가 정한다** (ADR-0097) — 목록은 `contain: size` 라 격자 행 높이에 안 들어가고, 받은 높이를 채운 뒤
   넘치는 줄은 안에서 스크롤한다. 줄은 [balance.csv:report_keep] 까지 쌓이므로 목록이 높이를 정하면 런이 쌓일수록 화면이 늘어난다 */
.rep-runs { display: flex; flex-direction: column; }
.rep-list {
    display: flex; flex-direction: column; gap: 4px;
    flex: 1 1 0; min-height: 0; contain: size;
    overflow-y: auto;
}
/* 리포트는 박스다 (ADR-0097) — 두 열이 박스 세로를 다 쓰고, 상세는 넘치면 상세 안에서 스크롤한다 */
.cols.c-side.page { grid-template-rows: minmax(0, 1fr); }
.c-side.page > .rep-detail { overflow-y: auto; }
.rep-run {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 9px; align-items: center;
    padding: 7px 9px; background: var(--bg-tertiary);
    border: 1px solid var(--border-dark); cursor: pointer;
}
.rep-run:hover { border-color: var(--border-highlight); }
.rep-run.on { background: var(--bg-input); border-color: var(--border-highlight); }
/* 판정은 점 하나로만 — 줄이 좁아 글자를 더 못 넣는다. 색 어휘는 상세의 판정 글자와 같다 */
.rep-run .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-muted); }
.rep-run .dot.clear { background: var(--color-success); }
.rep-run .dot.retreat { background: var(--color-warning); }
.rep-run .dot.lose { background: var(--color-error); }
.rep-run .dot.running { background: var(--color-info); }   /* 진행 중인 원정 — 라운드를 이길 때마다 보상이 찬다 (R89) */
.rep-run .n { font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rep-run .s { font-size: var(--fs-xs); }
.rep-run .r { text-align: right; white-space: nowrap; }
.rep-run .g { font-size: var(--fs-sm); color: var(--color-warning); }

/* 재생 중 배지 — 기여 머리 오른쪽. 표가 「지금 차는 중」임을 말한다 (ADR-0072) */
.rep-live:empty { display: none; }
.rep-live { font-size: var(--fs-xs); color: var(--color-info); letter-spacing: 0; }

/* 절 구분선 — **덩어리가 끝나는 자리**에 긋는다(획득 줄 · 장비 격자 · 기여 표).
   표 안의 줄 구분(`--border-dark`)보다 한 단계 진해야 「줄 사이」와 「절 사이」가 갈린다 */
.rep-detail .rep-cut { padding-bottom: 13px; border-bottom: 1px solid var(--border-secondary); }

/* 상세 — 절 머리가 여럿이라 첫 줄만 붙여 놓는다 */
.rep-detail > h2 { margin-top: 18px; }
.rep-detail > h2:first-of-type { margin-top: 0; }
.rep-note { font-size: var(--fs-xs); margin-bottom: 8px; }
.rep-contrib { margin-bottom: 4px; }
/* 상세는 **어느 런을 골라도 같은 크기**다 (ADR-0086) — 있을 때만 그리는 줄을 두지 않는다.
   `.void` 는 **자리만 잡고 안 그린다**: 장비가 없는 런의 분해 모드 버튼 · 기여 집계가 없는 옛 리포트의 표 */
.rep-detail .void { visibility: hidden; }
/* 머리 줄 오른쪽 — 버린 수 · 분해 모드. 버린 수가 따로 줄을 세우면 버린 런만 상세가 한 줄 길어진다 */
.rep-h-tail { display: flex; align-items: center; gap: 10px; }
.rep-detail > h2 .rep-h-tail small.down { color: var(--color-error); }
/* 장비 격자 — **한 줄 높이로 못박힌다**. 「없음」도 그 높이 안에 서고, 한 줄을 넘치는 런만 칸 안에서 스크롤한다 */
.rep-drops { --rep-cell: 44px; }
.rep-drops > .inv-cells.wide {
    grid-template-columns: repeat(auto-fill, var(--rep-cell));
    height: var(--rep-cell); overflow-y: auto;
}
.rep-drops > .rep-note { height: var(--rep-cell); display: flex; align-items: center; margin: 0; }
/* 도감 카드 — **줄은 늘 선다**(없으면 「없음」) · 한 줄에서 끊고 전체는 호버(`title`)가 든다 */
.rep-cards { font-size: var(--fs-sm); margin-top: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* 기여 표 — 견주는 값이라 칸으로 세운다 (ADR-0069 · ADR-0070).
   「가한」·「받은」은 **같은 폭 · 같은 모양**이고, 막대는 각자 **자기 칸의 최대**를 기준으로 그 칸 배경에 깔린다 */
.rep-ct { font-size: var(--fs-sm); margin-bottom: 4px; }
.rep-ct .ct-row {
    display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(150px, 2fr) minmax(150px, 2fr) minmax(56px, .6fr);
    gap: 10px; align-items: center; border-bottom: 1px solid var(--border-dark);
}
.rep-ct .ct-row.head { font-size: var(--fs-xs); color: var(--text-muted); letter-spacing: 1px; padding-bottom: 5px; }
.rep-ct .ct-row.head span { padding: 0 7px; text-align: right; }
.rep-ct .ct-row.head span:first-child { padding-left: 0; text-align: left; }
/* 이름 칸 — 초상 + 오른쪽에 이름. 초상 크기는 담는 칸이 정한다(§5).
   **영웅에게 일어난 일도 여기 붙는다** (ADR-0086) — 이름 아래 레벨업 · 쓰러졌으면 초상이 회색.
   줄 높이는 초상(52)이 정하고 이름 두 줄은 그 안에 들어가서, 표시가 붙어도 줄이 안 자란다 */
.rep-ct .n { display: flex; align-items: center; gap: 11px; min-width: 0; padding: 4px 0; }
.rep-ct .n b { font-weight: normal; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rep-ct .n .hero-face { width: 52px; height: 52px; }
.rep-ct .nm { display: flex; flex-direction: column; min-width: 0; }
.rep-ct .nm > em { font-style: normal; font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rep-ct .nm > em.xp { color: var(--text-muted); }   /* 받은 경험치 — 레벨업(.up)은 같은 줄 끝에 초록으로 붙는다 (R89) */
/* 전투불능 — 관전의 쓰러진 카드(`.unit.dead`)와 같은 문법. 카드가 아니라 초상 하나라 같은 값이면 빈 칸으로 읽혀 한 단 덜 흐리다.
   ⚠ 클래스를 `.down` 으로 두면 전역 `.down`(붉은 글자)이 **이름까지 붉게** 칠한다 — 표시는 초상 회색 하나다 */
.rep-ct .n.dead .hero-face { filter: grayscale(1); opacity: .45; }
/* 빈자리 — 파티 정원까지 **줄만 잡는다**. 초상 칸이 줄 높이를 정하므로 칸은 두되 안 그린다 */
.rep-ct .ct-row.pad .hero-face { visibility: hidden; }
/* 값 칸 — 막대가 칸을 채우는 배경, 수치는 그 위에 선다 */
.rep-ct .d { position: relative; display: flex; align-items: center; justify-content: flex-end; gap: 8px; padding: 5px 7px; align-self: stretch; }
.rep-ct .d > i { position: absolute; left: 0; top: 4px; bottom: 4px; background: var(--color-info); opacity: .3; }
.rep-ct .d.taken > i { background: var(--color-error); opacity: .26; }   /* 두 칸을 색으로 가른다 — 형태가 같아서 */
.rep-ct .d > b { position: relative; font-weight: normal; }
.rep-ct .d > em { position: relative; font-style: normal; font-size: var(--fs-xs); color: var(--text-muted); min-width: 34px; text-align: right; }
.rep-ct .v { color: var(--text-secondary); white-space: nowrap; text-align: right; padding: 5px 7px; }
/* 합계 — 줄이 아니라 기준선이라 테두리를 지우고 이름만 흐리게 */
.rep-ct .ct-row.total { border-bottom: none; }
.rep-ct .ct-row.total .n > b { color: var(--text-muted); }
/* 가방을 떠난 드롭 — **있었다는 사실만** 남긴다. 분해했으면 정의가 없어 빈 칸이고, 착용 중이면 그림째 흐리다 */
.inv-cell.gone { opacity: .38; cursor: default; }
.inv-cell.gone:hover { background: var(--bg-tertiary); }


.verdict-upgrade { color: var(--color-success); }
.verdict-sidegrade { color: var(--color-warning); }
.verdict-junk { color: var(--text-muted); }

/* ───────── 전투 관전 ─────────
   상하 대치: 적(위) / 파티(아래)
   진영 안에서는 유닛이 가로로 나란히. 유닛 카드는 위칸(이름) + 가로형 본문 */

/* 헤드는 **한 줄** [재개정 2026-09-04 사용자 지시] — 라운드 수치·시계를 걷은 자리로 컨트롤 줄이 통째로 올라왔다.
     화면 전환 · 스테이지 이름 · 라운드 트랙 ─── (밀어내기) ─── 배속 · 일시정지 · 건너뛰기 │ 배치 · 로그 · 누적
   「라운드 n / 총 · 종류 · 경과 시계」는 삭제됐다 — 몇 라운드인지는 트랙의 `.now` 가, 종류는 칸 색이,
   경과 시각은 로그 줄 머리의 타임스탬프가 이미 든다.
   ⚠ **한 줄에 넣으려고 컨트롤 문구를 줄였다** — 하한 폭 1280 의 메인 칸은 1006 인데 옛 문구(`1배속` · `건너뛰고 리포트만`)
     로는 1148 이라 안 들어간다. 배속은 `×1`(ko·en 동일) · 건너뛰기는 `건너뛰기 / Skip` 으로 줄이고
     줄 간격(12 → 10)과 버튼 간격(5 → 4)을 한 단씩 좁혀 맞췄다. 남는 넘침은 스테이지 이름이 말줄임으로 받는다.
   `flex-wrap` 은 두지 않는다 — 접히면 2줄로 돌아가 이 개정의 목적(가방이 잘리던 것)이 사라진다 */
.battle-head {
    display: flex; flex-direction: column; align-items: stretch;
    padding-bottom: 9px; margin-bottom: 10px;
    border-bottom: 1px solid var(--border-dark);
}
.bh-top { display: flex; align-items: center; gap: 8px; min-width: 0; flex-wrap: nowrap; }
.bh-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 컨트롤 — 줄 오른쪽 끝. 재생(배속·일시정지·건너뛰기)과 판 고르기(배치·로그·누적)를 `.ctrl-div` 가 가른다 */
.battle-ctrl { flex: 0 0 auto; margin-left: auto; display: flex; gap: 4px; flex-wrap: nowrap; }
/* 한 줄에 여덟 개가 서야 해서 좌우 패딩을 한 단 좁힌다 (다른 화면의 `.btn.sm` 은 그대로) */
.battle-ctrl .btn.sm { padding: 3px 6px; }
.ctrl-div { align-self: stretch; width: 1px; margin: 0 4px; background: var(--border-primary); }
.btn.sm.on { border-color: var(--border-highlight); background: var(--surface-6); }

/* ── 배치 둘 [2026-09-03 사용자 지시] — 컨트롤의 버튼 하나가 오간다 (SCREEN_DESIGN §4-2)
   기본(클래스 없음) = **넓게**: 아레나 판 전폭(ADR-0095) · 로그/누적은 창
   `.split`          = **나눔**: 좌 아레나(열을 뺀 폭 · 넓게와 같은 높이 · 같은 카드 · ADR-0097) / 우 로그 열 (ADR-0093)
   ⚠ 두 배치가 **같은 뼈대**를 쓴다 — 판(.pane) DOM 은 하나뿐이고 JS 가 집만 옮긴다(쌓인 로그를 안 버리려고) */
.battle-body.split {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 25%); grid-template-rows: minmax(0, 1fr); gap: 14px; align-items: stretch;
}
/* 나눔 배치 — 폭은 격자 칸이 정하고 높이는 **넓게와 같은 남는 세로**다(비를 안 지킨다 · ADR-0097 — 비 2.33 이면 가방이 박스 끝에 못 닿는다).
   카드 · 진형 간격은 넓게와 같다 (ADR-0093) */
/* 우측 딜미터 열 — 높이 예산은 아레나와 같다. 판은 그 안에서만 스크롤한다
   ⚠ `display:flex` 는 브라우저 기본 `[hidden]{display:none}` 을 **이긴다** — 아래 한 줄이 없으면 넓게 배치에서도 빈 열이 자리를 먹는다
      (.modal-layer 와 같은 함정이다) */
/* 높이는 격자의 `align-items: stretch` 가 준다 — 아레나와 **정확히** 같은 높이가 된다.
   옛 `max-height: clamp(280px,38vh,360px)` 은 아레나보다 짧게 끊겨 아랫변이 어긋났다 */
.battle-side { display: flex; flex-direction: column; min-height: 0; }
.battle-side[hidden] { display: none; }

/* 관전 화면 한 장 [2026-09-11 사용자 지시 · ADR-0095 · ADR-0097] — 전투 판 + 가방(`.bt-page` — 박스 `.page`)이 박스 세로를 채운다.
   **두 배치가 같은 뼈대다** — 전투 판 → `.battle-body` → 아레나가 **남는 세로**를 넘겨받고 가방은 제 높이로 맨 아래(박스 끝)에 선다.
   나눔 배치는 그 세로를 아레나와 로그 열이 나눠 갖는다(위 `.battle-body.split` 격자). 박스 아랫변과 아래 여백은 셸 절 */
/* 전투 판과 보관 사이 = **캐릭터 탭의 단 사이와 같은 14** [2026-09-14 사용자 지시] — 전투 판 아랫변이 캐릭터 탭 네 칸의 아랫변과 같은 높이에 선다.
   ⚠ 보관이 두 칸(`.bag-row` — 패널이 아닌 격자)이 된 09-11 부터 `.panel + .panel` 마진이 안 붙어 **전투 판이 보관에 달라붙어 있었다**
      (1600×800 실측 — 전투 판 아랫변 596.3 · 캐릭터 탭 네 칸 583.7). 간격은 `gap` 이 들고, 한 칸(재료 탭 · `.panel.bag`)에 붙던 마진은 걷는다 — 안 걷으면 28 */
.bt-page { display: flex; flex-direction: column; gap: 14px; }
.bt-page > .panel + .panel { margin-top: 0; }
.bt-page > .battle-panel { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
.battle-panel > .battle-body { flex: 1 1 0; min-height: 0; }
.battle-panel > .battle-body:not(.split) { display: flex; flex-direction: column; }
/* 가방은 칸 · 그림이 한 단 크다 — **관전과 캐릭터 탭이 같은 크기**다(`.bag` = `itemsPanel` 의 패널 · ADR-0097).
   **보관은 두 칸이다** [2026-09-11 사용자 확정] — 왼쪽 창고 · 오른쪽 인벤토리가 나란히 서고 **각각 12열 × 3줄**이다.
   열 수를 `auto-fill` 이 아니라 **12 로 박는다** — 칸 수(`stash_cap` · `inventory_cap`)가 줄 수를 정하고 폭은 칸이 나눠 갖는다.
   판 안 1337 을 두 칸이 나누면(사이 14) 한 칸 661 · 12열 + 간격 11 → **한 변 약 51.5** 로 09-11 이전(52)과 같다 */
/* 두 칸은 **윗변 · 칸 줄 · 아랫변이 맞는다** [2026-09-14 사용자 지시] — 도구 줄에 버튼(갈래 탭 · 분해 모드)이 서는 것은 인벤토리 쪽뿐이라
   창고 쪽 도구 줄이 글자 높이만큼 낮고, `align-items: start` 였던 창고 패널이 약 3px 짧았다. 두 패널을 행 높이로 늘리고 **모자란 높이는 도구 줄이 받는다** —
   칸 격자는 두 칸이 같은 높이라 아래에 붙어 칸 줄까지 맞는다. 버튼 높이를 px 로 박지 않는다(글꼴이 바뀌면 다시 어긋난다) */
.bag-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: stretch; }
.bag-row > .bag { display: flex; flex-direction: column; }
.bag-row > .bag > .items-tools { flex: 1 0 auto; }
/* ⚠ 격자 안의 둘째 패널에도 `.panel + .panel` 의 세로 마진이 붙는다 — 열이 나란한데 **위 마진이 행 높이에 더해져**
   관전(flex 부모)은 227, 캐릭터 탭(grid 부모)은 눌려 218.9 로 **두 화면 크기가 갈렸다**(ADR-0097 「두 탭이 같은 크기」 위반 · 09-11 실측).
   `.cols` 가 이미 같은 예외를 갖고 있다 — 새 컨테이너에도 같은 줄이 필요하다 */
.bag-row > .panel + .panel { margin-top: 0; }
.bag .inv-cells.wide { grid-template-columns: repeat(12, minmax(0, 1fr)); }
.bag .inv-icon { width: 40px; height: 40px; }
/* 칸 이름 — 「창고」 / 「인벤토리」. 도구 줄 맨 왼쪽에 서고 나머지(탭 · 분해 모드 · 칸 수)가 그 오른쪽이다 */
.items-name { font-size: var(--fs-sm); color: var(--text-secondary); margin-right: 2px; white-space: nowrap; }

.arena {
    /* 적(위) / 파티(아래) 상하 대치 — 가로형 카드가 진영마다 한 줄로 나란히 (2026-08-27 좌우 대치를 시도했다가 사용자 지시로 상하 복귀) */
    display: flex; flex-direction: column; justify-content: center;
    /* 메인 칸 전폭 · **높이 420 고정** (2026-09-03 사용자 지시 · SCREEN_DESIGN §4-2) — 로그가 창으로 빠지며 우측 열이 쓰던 자리를 받는다.
       ⚠ **화면비 고정(`aspect-ratio: 2/1`)은 같은 날 넣었다가 걷었다** — 폭이 688 → 1002 로 +46% 늘면 비를 지킨 높이도 345 → 500 이 되어
       세로가 같이 부푼다. 「지금 화면비 그대로」가 노린 건 박스의 비가 아니라 **지금 보이는 높이**였다.
       420 = 내용(카드 두 줄 + 구분선 345) 위아래로 배경이 약 37px 씩 더 보이는 값이고, 헤드까지 더해도 세로 예산 700 안에서 아래 가방의 도구 줄이 남는다.
       늘어난 **가로** 자리는 카드가 아니라 배경이 받는다 — 카드 크기는 「몬스터·영웅·보스 전부 같은 고정값」이라 안 커진다.
       `min-height` 는 바닥이다 — 카드 줄이 자라면(창 뱃지) 잘리는 대신 상자가 따라 커져야 한다.
       **높이는 화면비 2.33 : 1 이 정한다** [개정 2026-09-03 사용자 지시] — 나눔 배치가 실제로 서는 비(689 × 296)를 넓게에도 그대로 옮겼다.
       ⚠ 폭을 따라 높이도 커진다: 1280 창 1001 × 430 · 1600 창 1340 × 575. 09-03 오전에 같은 이유로 `aspect-ratio` 를 걷었던 적이 있다 —
         그때 문제는 비 자체가 아니라 「높이가 같이 커지는 것」이었고, 이번엔 그걸 알고 택했다.
       옛 `clamp(280px, 38vh, 360px)` 의 뷰포트 비례는 안 되살렸다 — 폭이 전폭으로 정해진 마당에 세로만 창 높이를 따라가면 아레나가 창마다 흔들린다 */
    padding: 14px 12px; min-height: 350px;
    /* **판 전폭 · 남는 세로** [2026-09-11 사용자 지시 · ADR-0095 가 ADR-0091(폭 1184 · 가운데)을 대체] — 넓게 배치는 **비를 안 지킨다**.
       높이는 세로 flex 인 `.battle-body` 가 넘겨 주는 나머지다(아래 「관전 화면 한 장」) — 헤드나 가방이 자라면 아레나가 받는다.
       나눔 배치도 같은 높이를 받고 폭만 로그 열을 뺀 나머지다(ADR-0097). 위 주석의 420 · 2.33 은 이 줄 이전 이야기다 (src/ui/README.md 크기 정책) */
    flex: 1 1 0;
    background: radial-gradient(ellipse at center, var(--surface-0) 0%, var(--bg-input) 100%);
    border: 1px solid var(--border-dark);
    position: relative;
}
/* 스테이지 배경 = TheSevenRPG 계승 픽셀아트에서 **아래 워터마크 띠를 잘라 낸 사본** (2752×1360 · `backgrounds_clean/`). 없는 스테이지는 위 그라디언트로 폴백
   [2026-09-11 사용자 지시] 원본(2752×1536)은 오른쪽 아래에 생성기 ✦ 가 박혀 있다. 넓게 보기(비 약 2.66)는 `cover` 가 아래를 12% 잘라
   우연히 가렸고, 나눔 보기(약 1.97)는 3% 만 잘려 드러났다 — CSS 로 가리지 않고 그림에서 뺐다 (src/assets/art/README.md 「backgrounds_clean/」) */
.arena.has-bg {
    background-size: cover;
    background-position: center 95.2%;      /* = 원본의 62% 와 같은 띠 — 넓게 보기 구도는 그대로다. 나눔 보기는 사본의 세로가 다 보인다 */
    image-rendering: pixelated;             /* 픽셀아트라 보간하면 뭉갠다 */
    border-color: var(--border-secondary);
}
/* 가장자리를 어둡게 눌러 유닛 카드가 배경에서 떠 보이게 한다 */
.arena.has-bg::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: radial-gradient(ellipse at center, transparent 42%, rgba(var(--veil-rgb),.72) 100%);
}
.arena > * { position: relative; z-index: 1; }

/* 진영 = 가로 한 줄 (수가 많으면 줄바꿈) — 카드를 VS 쪽으로 붙인다 */
.side { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: center; gap: 8px; }
.side-enemy { align-items: flex-end; }
.side-party { align-items: flex-start; }

/* 진형이 카드를 **살짝** 위아래로 민다 — **양 진영 다** (⚠ 목업 · 2026-09-09 사용자 지시 · SCREEN_DESIGN §4-1·§4-2).
   전열은 제자리, 후열은 VS 반대쪽으로 — 「누가 앞에 섰나」를 자리가 든다. 랭크가 어디서 오는지만 진영마다 다르다
   (파티 = 편성 진형 · 적 = `monster.csv:role`). 전투 계산은 어느 쪽도 진형을 모른다.
   ⚠ **랭크 2 규칙은 지금 안 선다** — `formation.csv` 도 `monster_role.csv` 도 랭크가 **0·1 뿐**이라 깊이는 언제나 1 이나 2 다.
     세 번째 랭크가 발행되면 그날 바로 서라고 남겨 둔 줄이고, 규칙이 깊이를 안 보므로 값도 안 고친다.
   ⚠ **방향이 진영마다 뒤집힌다** — 「전열 = VS 쪽」은 하나인데 파티는 아래 진영이고 적은 위 진영이라, 같은 랭크 0 이
     파티에선 **위로**, 적에선 **아래로** 간다. 이 뒤집힘이 없으면 적의 전열이 뒤로 물러선 그림이 된다.
   ⚠ **`top` 이지 `margin`/`transform` 이 아니다** — 칸은 이미 `position: relative` 라 흐름을 안 건드리고(줄 높이가 그대로다),
     `transform` 과 달리 새 컨테이닝 블록도 안 만든다(카드 안 팝업 · 툴팁이 쓰던 기준이 그대로 남는다).
   ⚠ **전열은 안 밀린다 — 물러서는 것은 후열뿐이다** [개정 2026-09-10 사용자 지적 · ADR-0083].
     그래서 **전열 ↔ VS 거리가 양 진영 언제나 같다**(1280 창 47.5px = 여백 38 + VS 상자 반 9.5).
     ⚠ 옛 규칙은 「랭크 묶음을 그 진영의 무게중심 기준으로 대칭으로」였고, 그게 **깊이가 다르면 어긋나는 원인**이었다 —
       깊이 2 는 전열이 `step/2` 만큼 당겨지는데 깊이 1(한 랭크에 다 몰림)은 아무도 안 밀려서, 실측 **54.5 vs 40.5px** 로 갈렸다
       (`monster_role.csv` 는 전열/후열 둘뿐이라 두 진영의 깊이가 다른 조합이 흔하다).
     ⚠ **깊이 선택자가 사라졌다** — 랭크 하나가 자기 자리를 혼자 정하므로 `[data-depth]` 를 안 본다(규칙 8 → 4).
       `battle.js` 는 여전히 `data-depth` 를 찍지만 **읽는 CSS 는 없다** — 진형 깊이를 눈으로 볼 수 있게 남긴 표시다.
   ⚠ **상한이 있다 — 창 뱃지 줄이 아레나를 넘는 지점** (1280×700 실측 · 2026-09-10 재측):
     후열이 혼자 물러서므로 봉투는 `여백 + step` 이 정한다 — **`여백 + step ≤ 59.5`**(= 아레나 반높이 214 − VS 상자 반 9.5 − 카드 116 − 뱃지 줄 29).
     지금 값 38 + 21 = 59 → 여유 **0.5px**. step 을 올리려면 여백을 같은 만큼 내려야 하고, 그러면 간격이 그 두 배로 좁아진다. */
/* 40 → 28 → **21px** (2026-09-10 사용자 지시·지적) — 두 번 깎였다. 한 번은 간격을 벌리는 값으로,
   한 번은 **전열을 한 선에 세우는 값**으로. 후자가 더 먹는다: 옛 규칙에서 후열은 `step/2` 만 물러섰는데 이제 `step` 을 통째로 물러서므로
   같은 봉투에 들어가는 step 이 절반이 된다. 21 은 그 제약 아래에서 **간격 95px 을 지키는 최대값**이다
   (`여백 38 + step 21 = 59 ≤ 59.5`). ⚠ 신설 당시 값은 18 이었다 — 아직 그보다 크다. */
.side { --form-step: 21px; }
/* 전열(랭크 0)은 규칙이 없다 = `top: 0`. 후열만 **VS 반대쪽으로** 물러선다 — 방향은 진영이 뒤집는다 */
.side-party .unit-slot[data-rank="1"] { top: var(--form-step); }                    /* 아래 진영 → 아래로 */
.side-party .unit-slot[data-rank="2"] { top: calc(var(--form-step) * 2); }
.side-enemy .unit-slot[data-rank="1"] { top: calc(var(--form-step) * -1); }         /* 위 진영 → 위로 */
.side-enemy .unit-slot[data-rank="2"] { top: calc(var(--form-step) * -2); }

/* VS 선 — **두 진영 사이의 간격을 이 여백이 정한다** (2026-09-08 사용자 지시 · SCREEN_DESIGN §4-2).
   아레나가 내용을 세로 가운데 정렬하므로 이 한 값이 **VS 선을 축으로 위아래를 대칭으로** 민다.
   12 → 40 → 45 → **38px** (2026-09-10 사용자 지시·지적): 전열이 안 밀리게 되며(ADR-0083) 이 여백이 **곧 전열의 자리**가 됐다 —
   전열 ↔ VS 거리 = `38 + 9.5` = **47.5px**, 두 진영 전열 사이 = 그 두 배 **95px**. 옛 값 45 는 전열이 `step/2` 당겨지는 걸 전제한 값이라
   같이 내렸다(간격은 그대로 95 — 당겨지는 몫이 없어진 만큼 여백에서 뺐다).
   ⚠ **아레나 높이가 상한을 정한다** — 높이는 화면비가 정한 고정값(1280 창 430px)이라 가운데가 먹는 만큼 위아래 여백이 준다.
     창 뱃지 줄(`.buff-row` 26 + 3px)이 **흐름 밖**으로 그 여백에 얹혀서, 봉투 식은 위 `.side` 주석의 **`여백 + step ≤ 59.5`** 하나다.
     여기서 더 벌리려면 **아레나 높이**를 손대야 하고 세로 예산 700 · 아래 가방 자리에 걸린다 */
.divider {
    display: flex; align-items: center; gap: 12px;
    margin: 38px 0; font-size: var(--fs-xs); letter-spacing: 2px;
}
.divider::before, .divider::after {
    content: ''; flex: 1; height: 1px;
    background: linear-gradient(90deg, transparent, var(--border-secondary), transparent);
}

/* 유닛 카드 — 위칸 + 가로형 본문 (2026-08-27 개편 · 참고: Lootun 카드, SCREEN_DESIGN §4-2):
   위칸은 영웅 띠(.hs-band)와 같은 배치 — 왼쪽 태그 / 오른쪽 이름. 본문은 왼쪽 초상(§5 얼굴 규격) · 오른쪽에 HP 바 / 행동 게이지 / 스킬 쿨 3줄.
   **크기는 몬스터·영웅·보스가 전부 같은 고정값** (2026-08-27 사용자 지시) — 진영마다 카드 수가 달라도, 정예 특성 줄이 붙어도,
   보스여도 같은 박스다. 본문 높이를 초상 칸에 못박고(.unit-body height) 넘치는 내용은 자른다 — 그래야 위아래 두 진영이 같은 격자로 읽힌다.
   폭 고정 200px 은 화면 폭 정책(라벨 칸 고정 px 금지)의 **의도된 예외**다: 한 진영 최대 3장(party_size_max=3 · wave_monster_max=3)이라
   하한 폭 1280 의 아레나(약 660px)에 3×200 + 여백이 들어간다. 긴 이름은 위칸에서 말줄임된다 */
/* 칸 = 카드 + 그 아래 창 뱃지 줄 (2026-08-31 사용자 지시). 폭 고정은 카드에서 이 칸으로 올라왔다 —
   .side 의 flex item 은 이제 카드가 아니라 칸이다. 카드는 창이 걸리든 말든 **옛 크기 그대로**다 */
/* 폭 200 → **226** (2026-09-03 사용자 지시) — 초상이 카드 높이를 통째로 쓰게 키우면(76 → 101) 정사각이라 가로도 같이 커진다.
   오른쪽 수치 열의 폭(약 104)을 그대로 지키려고 칸을 그만큼만 늘렸다 — 「살짝」의 실제 값이 26px 다 */
/* 칸 = 카드 뿐이다 (2026-09-03 사용자 지시) — 뱃지 줄은 아래에서 **흐름 밖**(absolute)으로 나갔다.
   줄이 흐름에 있으면 창이 없을 때도 26px 를 잡아, 카드가 그 띠 위에 **떠 보였다**(적 진영은 아래 정렬이라 VS 에서 더 밀려났다) */
.unit-slot { flex: 0 0 226px; width: 226px; position: relative; display: flex; flex-direction: column; }

.unit {
    /* 이름 띠 + 본문 (2026-09-03 사용자 지시로 위칸 재도입 — SCREEN_DESIGN §4-2) */
    display: flex; flex-direction: column;
    width: 100%; padding: 5px 6px 6px;
    background: var(--bg-tertiary);
    /* 윗변 3px = 등급 색의 집 (2026-09-03 띠 아랫변으로 옮겼다가 같은 날 복귀 · 사용자 지시) —
       영웅 띠 카드·후보 카드와 같은 문법이다. 색 자리가 카드마다 다르면 같은 뜻으로 안 읽힌다 */
    border: 1px solid var(--border-dark); border-top: 3px solid var(--border-secondary);
    position: relative; text-align: left;   /* overflow 는 주지 않는다 — 피해 팝업이 카드 밖으로 떠오른다 */
    transition: opacity .3s;
}
/* 이름 + 신원 = **오른쪽 열의 첫 줄 하나** (2026-09-03 사용자 지시 · SCREEN_DESIGN §4-2) — 위칸(띠)은 완전히 폐기됐다.
   왼쪽에 무채색 신원(`Lv.n · 직업` / 정예·보스 라벨) · **이름은 오른쪽 끝**(옛 위칸의 「왼쪽 태그 / 오른쪽 이름」 배치).
   일반 몬스터는 이름뿐이라 이름만 오른쪽에 선다. 넘치면 **이름이** 말줄임된다(신원은 고정 조각) */
/* 이름 줄은 **HP 바 바로 위**다 (재개정 2026-09-04 사용자 지시 — 전날의 「초상 윗변」(margin-bottom: auto) 을 물렸다).
   열이 바닥 정렬(flex-end)이라 이름·HP·게이지·스킬이 한 묶음으로 초상 아랫변에 붙고, 남는 세로는 전부 이름 위에 쌓인다 —
   이름을 윗변에 떼어 두면 수치 묶음과 붕 떠서 두 덩어리로 읽혔다 (SCREEN_DESIGN §4-2) */
/* 신원·이름 = **두 줄** (개정 2026-09-07 사용자 지시 — 09-03 「한 줄」 폐기 · SCREEN_DESIGN §4-2) —
   한 줄 합침은 좁은 열(~104px)에서 신원(고정 조각)이 줄을 먼저 먹어 이름이 짜부라졌다.
   윗줄(신원)은 빈 채도 자리를 잡는다(min-height) — 일반 몬스터와 영웅의 이름·HP 가 같은 높이에 선다 */
/* 두 줄 다 **오른쪽 정렬** (재개정 2026-09-07 사용자 지시 — 같은 날 아침의 「둘 다 왼쪽 정렬」을 물렸다).
   카드의 `text-align: left` 를 이 블록에서만 덮는다 — **양 진영 같다**(몬스터의 이름·정예 라벨도 같은 변에 선다) */
.unit-id { width: 100%; min-width: 0; display: flex; flex-direction: column; line-height: 1.2; text-align: right; }
.unit-ident {
    max-width: 100%; min-height: 1.2em;
    font-size: var(--fs-xs); color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 이름은 신원보다 **한 단 큰 글씨** (2026-09-07 사용자 지시 — `--fs-sm` → `--fs-md`) —
   두 줄이 같은 크기면 어느 쪽이 이름인지 색(무채색/본문색)으로만 갈렸다. 카드 높이는 안 변한다(열이 바닥 정렬 · 남는 세로는 이름 위) */
.unit-name {
    min-width: 0;
    font-size: var(--fs-md); color: var(--text-primary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 본문 — 왼쪽 초상, 오른쪽 수치 열. 높이는 초상 칸에 못박는다 = 모든 카드가 같은 높이 */
/* 높이 101 = 옛 띠(20) + 옛 간격(4) + 옛 본문(76). 위칸이 사라져도 **카드 크기는 그대로 둔다** —
   「몬스터·영웅·보스가 전부 같은 고정값」이 크기의 근거지, 위칸의 유무가 아니다 (2026-09-03) */
.unit-body { display: flex; flex-direction: row; align-items: center; gap: 7px; min-width: 0; height: 101px; overflow: hidden; }
/* 윗변 색 = **등급** (2026-09-03 사용자 지시 · SCREEN_DESIGN §5) — 죄종은 색을 갖지 않는다.
   순서가 규칙이다: 진영 기본 → 영웅 등급. 정예·보스는 아래의 **전체 테두리** 규칙(.unit.elite / .unit.boss)이 덮는다 */
.unit.enemy { border-top-color: var(--enemy-line); }
.unit.party { border-top-color: var(--ally-line); }
/* 영웅 등급 — 색은 `data/hero_tier.csv:color_hex` 가 든다(아이템 희귀도의 같은 계단이라 화면에서 같은 뜻으로 읽힌다) */
.unit.tier-rare { border-top-color: var(--rarity-rare); }
.unit.tier-unique { border-top-color: var(--rarity-unique); }
/* 등급 = **테두리 색** [개정 2026-09-03 사용자 지시] — 죄종 칩·정예 태그가 카드에서 걷혔으므로 「정예인가」를 이제 테두리 혼자 든다.
   그래서 옛 갈색(#6a4a2a)을 걷고 눈에 띄는 노랑으로 올린다. 배경 색조는 그대로 — 색이 둘 다 바뀌면 정예가 다른 카드로 보인다 */
.unit.elite { border-color: var(--color-warning); background: var(--elite-bg-unit); }
.unit.dead { opacity: .26; filter: grayscale(1); }
/* ⚠ **`.unit.buffed` 의 테두리·발광은 걷었다** (2026-09-03 사용자 지시) — 창이 켜지면 카드 전체에 파란 안쪽 선 +
   바깥 글로우를 두르던 자리다. 카드 테두리는 이미 **등급**을 말하고 있어(일반/정예/보스) 거기에 창까지 얹으면
   같은 변이 두 가지를 말한다. 「무언가 걸려 있다」도 아래 뱃지 줄이 이미 든다 — 줄이 곧 개수이자 종류다.
   ⚠ 클래스 자체는 `battle.js` 가 계속 단다(`refreshUnit`) — 다른 표시를 붙일 자리로 남긴다 */
/* 창 뱃지 줄 — 카드 전체가 「무언가 걸려 있다」를, 이 줄이 「무엇이 걸려 있나」를 든다 (SCREEN_DESIGN §4-2, 2026-08-31).
   자리는 **카드 밖 · 카드 바로 아래** (2026-08-31 사용자 지시) — 카드 안에 두면 그만큼 박스가 커진다.
   ⚠ 창이 없어도 **높이를 그대로 둔다** — 개수를 따라 흔들리면 칸 높이가 변해 카드가 위아래로 뛴다 */
/* 칩 16 → **24px** (2026-09-03 사용자 지시) — 칩이 이모지에서 **그림**으로 바뀌면서
   16px 은 무슨 스킬인지 못 읽는 크기가 됐다(스킬 쿨 칸은 32px 다).
   ⚠ **줄은 흐름 밖이다** (2026-09-03 사용자 지시) — 옛 판은 칸의 둘째 행이라 창이 없어도 26px 를 잡았고,
   그래서 카드가 빈 띠 위에 떠 보였다. `absolute` 라 **칸 높이 = 카드 높이**이고 창 개수가 카드를 못 흔든다
   (「높이를 그대로 둔다」가 지키려던 것 — 카드가 위아래로 안 뛰는 것 — 을 자리를 안 잡는 쪽으로 지킨다).
   자리는 **카드의 바깥쪽**이다: 아래 진영(파티)은 카드 밑, 위 진영(적)은 카드 위 — 양쪽 다 VS 쪽 간격을 안 벌린다 */
.buff-row {
    position: absolute; left: 0; right: 0; top: 100%; margin-top: 3px;
    display: flex; flex-direction: row; align-items: center; gap: 3px; height: 26px; overflow: hidden;
}
.side-enemy .buff-row { top: auto; bottom: 100%; margin: 0 0 3px; justify-content: flex-end; }
.buff-chip {
    flex: 0 0 auto; width: 24px; height: 24px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: var(--fs-xs); line-height: 1; background: var(--bg-input); border: 1px solid;
}
/* 칩도 그림을 든다 (2026-09-03 · SCREEN_DESIGN §2) — 칸을 여백 없이 꽉 채운다 */
.buff-chip img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
/* 이로운 창 = 초록 · 해로운 창 = 빨강. 가르는 것은 창의 값 부호다 (재생기 refreshBuffs) */
.buff-chip.good { border-color: var(--color-success); color: var(--color-success); }
.buff-chip.bad { border-color: var(--color-error); color: var(--color-error); }
/* 오른쪽 정보 열 — 위에서부터 (정예 특성) / HP / 행동 게이지 / 스킬 쿨 */
/* 오른쪽 정보 열 — HP / 행동 게이지 / 스킬 쿨.
   **아래로 붙인다** (2026-09-03 사용자 지시) — 옛 판은 가운데 정렬이라 스킬 칸의 아랫변이 초상 아랫변보다 위에 떠서
   두 열의 바닥이 어긋났다. `align-self: stretch` 로 열이 본문 높이를 통째로 쓰고 `flex-end` 로 내용을 바닥에 붙이면,
   **스킬 칸 아랫변 = 초상 아랫변**이 된다 (본문 높이를 초상이 정하므로) */
.unit-info { flex: 1 1 0; min-width: 0; align-self: stretch; display: flex; flex-direction: column; justify-content: flex-end; gap: 2px; }
/* 위칸(.unit-band · .unit-name)은 2026-09-03 사용자 지시로 폐기 — 이름·죄종 칩·정예/보스 태그가 카드에서 사라졌다 (SCREEN_DESIGN §4-2) */

/* 초상 — 정사각 한 칸. 그림 규격은 공통 조각 .hero-face 와 같다(네모 박스). 보스는 한 단 크다 */
.unit .sprite {
    position: relative;
    /* 76 → **101** (2026-09-03 사용자 지시) — 카드 높이(본문 101)를 통째로 쓴다. 정사각이라 가로도 101 이 되고, 그만큼 칸을 226 으로 넓혔다 */
    flex: 0 0 auto; width: 101px; height: 101px; align-self: center;
    display: flex; align-items: center; justify-content: center;
    background: var(--bg-input); border: 1px solid var(--border-secondary); overflow: hidden;
}
/* 보스도 같은 크기다 — 카드 크기를 진영·등급 무관 고정으로 못박았다 (2026-08-27). 보스 표시는 태그와 테두리가 든다 */
/* 얼굴 이미지가 있는 유닛 — **없으면 양쪽 다 빈 칸**이다 (영웅 2026-09-03 · 몬스터 2026-09-06 사용자 지시) */
.sprite.has-face { background: radial-gradient(circle at 50% 38%, var(--surface-6) 0%, var(--bg-input) 100%); }
.sprite.has-face img {
    position: absolute; inset: 0;      /* 칸을 통째로 쓴다 — 밑에 깔린 것이 없다 (.face 와 같은 규칙) */
    width: 100%; height: 100%; object-fit: contain;
    image-rendering: var(--face-render);
    filter: drop-shadow(0 1px 2px rgba(var(--shadow-rgb),.8));
}
/* 아트 없는 몬스터의 폴백 = **이니셜 한 글자**뿐 [2026-09-03 사용자 지시]. 옛 죄종 색 원판 규칙은 폐기했다 —
   원형도 색도 몬스터만 달라서 「카드 형태를 똑같이」와 「죄종 안 보이게」 둘 다에 걸렸다. 칸은 영웅과 같은 빈 네모다 */

.unit .bar { width: 100%; }
/* HP 바 — 수치는 바 가운데 (2026-08-27). 바를 글자 높이만큼 키운다 */
.hp-row { position: relative; width: 100%; }
/* 15 → 18 → **20** (2026-09-04 사용자 지시 — 한 단 더) — 본문 101 예산 안이다(이름 16 + 20 + 8 + 32 + 여백 ≈ 94) */
.hp-row .bar.hp { height: 20px; }
.hp-text {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    font-size: var(--fs-xs); line-height: 1; color: var(--text-primary); text-shadow: 0 1px 2px #000;
    white-space: nowrap; pointer-events: none;
}
/* ───────── 행동 게이지 / 쿨 게이지 ─────────
   숫자로 "12s" 라고 적어두면 언제 터지는지 읽히지 않는다. 채워지는 칸으로 바꾸면
   행동 주기(battle_design §2)와 실시간 쿨(§6)이 눈으로 보인다. */

/* 행동 게이지 — 다 차면 그 유닛이 행동한다 */
.act-row {
    /* 5 → 8 (2026-09-03 사용자 지시) — 「차오르면 행동한다」의 인과가 5px 로는 안 읽혔다 */
    width: 100%; height: 8px; margin-top: 1px;
    background: var(--bg-input); border: 1px solid var(--border-dark);
}
.act-fill {
    display: block; height: 100%; width: 0;
    background: var(--color-warning);
    transition: width .1s linear;            /* 틱 간격과 맞춘다 */
}
.unit.enemy .act-fill { background: var(--enemy-fill); }
/* 막바지(85%~) 발광(.act-row.full)은 **삭제했다** (2026-09-04 사용자 지시) — 인과는 특수효과가 아니라
   게이지가 실제로 100% 까지 차는 것으로 읽는다. 행동 틱의 100% 표시와 스냅 리셋은 재생기(battle.js refreshUnit)가 든다 */

/* 스킬 쿨 3칸 — 슬롯 순서 = 동률 시 우선순위. **왼쪽부터** 1·2·3번 (2026-08-27 세로 3줄 → 가로 3칸).
   세로로 쌓으면 오른쪽 열의 가로 105px 중 아이콘이 13px 만 쓴다. 눕히면 같은 자리에서 아이콘이 13 → 32px 가 되고
   세로 예산은 43 → 35 로 오히려 준다. 아이콘이 안 읽히던 건 공간이 없어서가 아니라 배치가 세로였기 때문이다.
   이름도 % 도 찍지 않는다 — 이름·표기 쿨은 칸의 title 툴팁이 든다 (값을 지운 게 아니라 옮겼다).
   게이지·아이콘 전부 목업이다 — 스킬 미작성이라 타임라인에 스킬 이벤트가 없다 (DEV_PLAN 부채 #13) */
.cd-list { width: 100%; display: flex; flex-direction: row; gap: 5px; margin-top: 3px; }
.cd-slot {
    flex: 1 1 0; min-width: 0; height: 32px; position: relative; overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    font-size: 19px; line-height: 1; color: var(--text-primary);
    background: var(--bg-input); border: 1px solid var(--border-dark);
}
/* 칸이 드는 것은 그림이다 (2026-09-03 · SCREEN_DESIGN §2) — 이모지가 들던 자리를 그대로 채운다.
   `.cd-g` 는 발동 연출(`cd-fire`)이 튀게 하는 상자라 그림도 그 안에 든다 */
.cd-slot .cd-g { display: block; width: 100%; height: 100%; }
.cd-slot .cd-g img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
/* 쿨 마스크 — 남은 쿨만큼 위에서 덮는다. 다 걷히면 아이콘이 전부 드러난다 = 준비 완료 */
.cd-slot .cd-mask {
    position: absolute; left: 0; right: 0; top: 0; height: 100%;
    background: rgba(var(--veil-rgb),.78); transition: height .1s linear;
}
/* 빈 칸 — 액티브가 셋을 못 채운 영웅의 남은 자리. 칸 수는 언제나 active_slots 다 (SCREEN_DESIGN §4-2 개정 2026-08-31).
   칸이 사라지면 카드마다 줄 길이가 달라져 위아래 두 진영이 같은 격자로 안 읽힌다 */
/* ⚠ 테두리색을 `--border-dark`(#18182a) 에서 올렸다 (2026-09-03) — 카드 배경(#1a1a2a)과 값이 거의 같아
   **빈 칸이 아예 안 보였다.** 몬스터는 칸 셋이 전부 비어 있어(액티브 데이터 없음) 그 줄이 통째로 사라져 보이고,
   그러면 「스킬 줄이 없는 카드」로 읽힌다 — 빈 칸은 「없다」가 아니라 「아직 안 찼다」여야 한다 (SCREEN_DESIGN §4-2) */
.cd-slot.empty { background: transparent; border-style: dashed; border-color: var(--border-primary); }
/* 다 찬 스킬의 파란 강조(`ready` 테두리)는 **삭제했다** (2026-09-03 사용자 지시) — 찰 때마다 칸이 번쩍여
   소란스러웠다. 마스크가 다 걷힌 것 자체가 「준비」다 — 상태 표시가 이미 게이지 안에 있다 */
/* 발동 — 그 칸이 한 번 튄다. 튀는 건 글리프만 (칸을 키우면 .unit-body 의 고정 높이에 잘린다) */
.cd-slot.fire { border-color: var(--color-warning); background: var(--fire-bg); }
.cd-slot.fire .cd-g { animation: cd-fire .5s ease-out; }
@keyframes cd-fire {
    0% { transform: scale(1); }
    20% { transform: scale(1.45); }
    100% { transform: scale(1); }
}

/* 보스는 **지금 그대로 빨강** (2026-09-03 사용자 확인). 정예(노랑)보다 뒤에 와야 보스가 이긴다 — 순서가 규칙이다 */
.unit.boss { border-color: var(--boss-line); background: var(--boss-bg); }

/* 라운드 진행 트랙 — 구조가 고정이라 한눈에 읽힌다 */
/* 트랙이 헤드 첫 줄에 **가로로** 들어왔다 (2026-09-03) — 옛 세로 쌓기용 `margin-top: 6px` 는 걷었다 */
.round-track { display: flex; flex: 0 0 auto; gap: 2px; }
/* 칸 18 → 16 · 간격 3 → 2 [2026-09-04] — 헤드가 한 줄이 되며 가로를 26px 돌려받아야 했다 (한 자리 숫자라 안 넘친다) */
.round-track .rt {
    width: 16px; line-height: 16px; text-align: center; font-size: var(--fs-2xs);
    border: 1px solid var(--border-dark); background: var(--bg-input); color: var(--text-muted);
}
.round-track .rt.elite { border-color: var(--elite-line-soft); color: var(--elite-fg); }
.round-track .rt.boss { border-color: var(--boss-line); color: var(--text-accent); }
.round-track .rt.done { opacity: .35; }
.round-track .rt.now { background: var(--bg-tertiary); color: var(--text-primary); border-color: var(--border-highlight); }

/* 데미지 숫자 — 생성 후 0.9초 뒤 DOM에서 제거 */
/* 스킬 툴팁 문장 (2026-09-08 · SCREEN_DESIGN §4-2) — 수치표 대신 한 문장. 숫자만 강조색으로 뽑는다 */
.tip-line {
    margin-top: 6px; font-size: var(--fs-sm); line-height: 1.55; color: var(--text-primary);
    max-width: 30em;
}
.tip-hl { color: var(--color-warning); font-weight: 700; }
/* 계산식 [2026-09-10 · SCREEN_DESIGN §2 「스킬 설명창 규격」 · ADR-0089] — Alt 를 누르는 동안 숫자 뒤에 괄호로 선다.
   **숫자만 강조색, 식은 흐린 색** — 식은 풀이지 값이 아니라 문장을 밀어내지 않게 한 단 물러선다.
   값이 없는 자리(도감)는 식이 숫자 자리를 **대신**하므로 이 클래스를 안 쓴다(식 속 숫자가 `.tip-hl` 을 그대로 탄다) */
.tip-fx { color: var(--text-muted); }
/* 「Alt 계산식」 각주 — 기본 설명창 바닥 한 줄. 괄호가 붙을 숫자가 있을 때만 선다 */
.tip-foot {
    margin-top: 8px; padding-top: 5px; border-top: 1px solid var(--border-dark);
    font-size: var(--fs-xs); color: var(--text-muted);
}
/* 출처 · 태그 칩 — 이름 줄 아래 한 줄. 넘치면 접어 내린다(영어가 길다) */
.tip-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.tip-chip {
    font-style: normal; font-size: var(--fs-xs); line-height: 1.5;
    padding: 0 6px; border-radius: 3px;
    background: rgba(var(--tint-rgb),.06); border: 1px solid var(--border-primary); color: var(--text-secondary);
}
.tip-chip.src { color: var(--info-fg-soft); border-color: var(--info-line); background: rgba(var(--info-line-rgb),.18); }

.pop-layer { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.pop {
    position: absolute; top: 38%; left: 57px; font-size: var(--fs-sm);   /* 왼쪽 초상(101px 칸) 한가운데서 떠오른다 — 패딩 6 + 50.5 (2026-09-03) */
    animation: pop-up .9s ease-out forwards; white-space: nowrap;
    text-shadow: 0 1px 2px #000;
}
.pop.dmg { color: var(--dmg-out); }
.pop.dmg-in { color: var(--dmg-in); }
.pop.crit { color: var(--color-warning); font-size: var(--fs-lg); }
.pop.dead-tag { color: var(--text-muted); font-size: var(--fs-xs); }
.pop.heal { color: var(--heal-fg); }                                          /* 회복 — 피해와 같은 자리, 부호와 색만 반대 */
/* 피해 팝업의 스킬 아이콘 (2026-09-08) — 숫자 왼쪽. `inline-flex` 로 글자 기준선이 아니라 줄 가운데에 맞춘다.
   `em` 크기라 치명(fs-lg)에서 숫자와 같이 커진다. 아이콘이 없으면 이 요소 자체가 안 생겨 줄이 안 흔들린다 */
.pop-ico {
    display: inline-flex; align-items: center; vertical-align: middle;
    width: 1.15em; height: 1.15em; margin-right: 3px;
    filter: drop-shadow(0 1px 2px #000);
}
.pop-ico img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* 발동한 스킬 이름 — 피해 숫자(초상 위, top 38%)와 자리를 나눠 카드 가운데 위로 뜬다. 배경 위에서 읽히도록 제 칩을 갖는다 */
.pop.skill-tag {
    /* 카드 위에서 시작해 위칸 언저리까지 떠오른다 — 카드에서 완전히 떨어지면 어느 유닛이 쓴 건지 안 붙는다 */
    top: 12%; left: 50%; font-size: var(--fs-xs); color: var(--info-fg-soft);
    background: rgba(var(--veil-rgb),.72); border: 1px solid var(--info-line); padding: 1px 6px;
}
@keyframes pop-up {
    0% { transform: translate(-50%, 6px); opacity: 0; }
    18% { transform: translate(-50%, -2px); opacity: 1; }
    100% { transform: translate(-50%, -30px); opacity: 0; }
}

/* 로그 창 — 컨트롤의 버튼 둘이 여는 창 (2026-09-03, 옛 우측 열 폐기 · SCREEN_DESIGN §4-2).
   규격(어두운 판 · 가운데 · 정사각 X)은 셸의 창(.modal-layer/.modal-box)을 **그대로** 쓰고 여기서는 크기만 정한다.
   판 크기를 내용에 맡기면 로그가 쌓일 때마다 창이 커졌다 작아졌다 해서 읽는 자리가 흔들린다 — 그래서 고정이다.
   ⚠ .modal-box 의 `overflow:auto` 를 덮어 끈다 — 안 끄면 판이 아니라 창 자체가 스크롤한다 */
.bw-box { width: min(720px, 100%); height: min(560px, 100%); overflow: hidden; }
/* 판(로그 · 누적) — 창 안(넓게)이든 우측 열 안(나눔)이든 **같은 생김새**다. 집만 바뀐다 */
.bw-box .pane, .battle-side .pane {
    flex: 1 1 0; min-height: 0; overflow-y: auto;
    background: var(--bg-input); border: 1px solid var(--border-dark); padding: 8px 11px;
}
.bw-box .pane[hidden], .battle-side .pane[hidden] { display: none; }
/* 누적 데미지 — 유닛별 가한 피해 합계. 파티 / 적 두 묶음, 막대는 묶음 안 최대 기준, % 는 묶음 합 기준 */
.dmg-group { font-size: var(--fs-xs); letter-spacing: 1px; color: var(--text-muted); margin: 2px 0 6px; }
.dmg-row + .dmg-group { margin-top: 14px; }
.dmg-row { margin-bottom: 8px; }
.dmg-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: var(--fs-sm); }
.dmg-n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-secondary); }
.dmg-v { white-space: nowrap; color: var(--text-primary); }
.bar.dmg { margin-top: 3px; }
.dmg-row.party .bar.dmg > i { background: var(--color-info); }
.dmg-row.enemy .bar.dmg > i { background: var(--enemy-fill); }
.dmg-by { font-size: var(--fs-xs); color: var(--text-muted); margin-top: 2px; line-height: 1.5; }
.dmg-by b { font-weight: normal; color: var(--text-secondary); }
.battle-log { list-style: none; font-size: var(--fs-sm); }
.battle-log li { padding: 1px 0; color: var(--text-secondary); }
.battle-log li .t { color: var(--text-muted); margin-right: 8px; font-size: var(--fs-xs); }
.battle-log li b { font-weight: normal; color: var(--text-primary); }
.battle-log li b.crit-t { color: var(--color-warning); }
.battle-log li b.heal-t { color: var(--heal-fg); }

/* ───────── 서브 바 / 세그먼트 ───────── */

.sub-bar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; margin-bottom: 14px;
}
/* 패널 **안** 첫 줄 — 왼쪽 화면 전환(세그먼트) · 오른쪽 제목 [2026-09-03 사용자 지시].
   옛 `.sub-bar` 는 패널 **위**에 따로 서서 줄 하나를 먹었다. 제목 줄 자리를 같이 쓰므로 세로가 안 늘어난다 */
.panel-nav { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 8px; }
.panel-nav h2 { margin: 0; }
.segmented { display: flex; gap: 4px; flex-wrap: wrap; }

/* ───────── 스킬 ───────── */

/* 왼쪽 한 칸(포인트 · 액티브) + 판 셋이 **나란히** (2026-08-28 사용자 지시).
   옛 배치는 판 셋을 세로로 쌓아 한 화면(세로 예산 700)에 한 판 반밖에 안 들어왔다 — 스크롤 없이 셋을 다 보려면 옆으로 세운다.
   **폭에 상한을 준다** (2026-08-28 사용자 지시 — 칸 2/3 축소) — 1fr 로 두면 판이 화면 폭을 다 먹어 칸이 함께 커진다.
   고정 px 이 아니라 minmax 의 위쪽을 잡는 것이라 좁은 화면에서는 그대로 줄어든다 (ui/README 폭 정책).
   **판은 아래로 꽉 찬다** (2026-09-01 사용자 지시 — 옛 `align-items: start` 폐기): 판 셋의 아랫변이 왼쪽 칸과 나란히 맞는다.
   칸이 같이 부풀지는 않는다 — `.sk-cell` 높이가 62px 로 고정이고 `.sk-row` 가 안 늘어나므로, 남는 자리는 판 안 아래쪽 여백이 된다 */
.cols.c-skill {
    /* **열 넷을 비율이 나눈다** [개정 2026-09-09 사용자 지시] — 옛 판은 열 넷이 전부 고정 상한이라
       1920 짜리 화면에서도 창이 1190 에서 멈췄고, 좁은 하한(1280)에 맞춰 깎아 둔 판 셋(200px)이
       **넓은 화면에서도 계속 눌려 있었다.** 왼쪽 칸 1.9 : 판 셋 각 1. ⚠ 열 넷을 고정 px 로 되돌리면 이 성질이 사라진다 */
    /* 전체 폭은 **1600×800 한 장 기준 고정값**이다 (ADR-0087) — 1508 = 1600 − 창 레이어 패딩 40 − 창 안쪽 패딩 28 − 세로 스크롤바 몫 ≈24 */
    width: 1508px;
    grid-template-columns: minmax(340px, 1.9fr) repeat(3, minmax(0, 1fr));
    gap: 12px;
}

/* 판 하나 */
.sk-box {
    display: flex; flex-direction: column;
    background: var(--bg-card); border: 1px solid var(--border-primary);
    padding: 10px 11px 11px;
}
.sk-box.locked { opacity: .5; }

/* 좌상단 라벨 — 어떤 트리인지 */
/* 판 셋의 첫 줄이 같은 높이에서 시작하게 머리 높이를 맞춘다 — 안 맞추면 「나란히」가 깨진다 */
.sk-box-head {
    display: flex; align-items: baseline; align-content: flex-start; gap: 8px; flex-wrap: wrap;
    /* 42 → 88 → **62px** [정정 2026-09-09] — 88 은 판을 200px 로 깎아 뒀을 때 영어 「Advancement Tree」가
       두 줄로 접혀 §7 「판 머리 높이를 맞춰 첫 줄 정렬」이 깨진 것을 **덮으려던 값**이다. 같은 날 창이
       화면을 따라 넓어지면서(위 `.cols.c-skill`) 판이 228~303px 가 되어 **제목이 어디서도 안 접힌다** —
       실측 결과 머리는 ko/en · 1280/1920 전부 **59px 로 저절로 같다**. 88 은 26px 를 헛으로 먹으며
       세로 예산 700 에서 창을 스크롤시키고 있었다. 지금 값은 그 자연 높이에 얹은 **바닥**일 뿐이다.
       ⚠ 정렬을 지키는 것은 이 숫자가 아니라 **판이 제목을 한 줄에 담을 만큼 넓다**는 사실이다 —
          더 긴 판 이름이 생기면 여기서 다시 갈린다(실측 항목: `.sk-grid` 의 top 셋이 같은가) */
    min-height: 62px; padding-bottom: 7px; margin-bottom: 8px;
    border-bottom: 1px solid var(--border-dark);
}
.sk-tag {
    font-size: var(--fs-xs); color: var(--text-accent);
    border: 1px solid currentColor; padding: 0 6px; line-height: 16px;
}
.sk-title { font-size: var(--fs-md); }
.sk-sub { font-size: var(--fs-xs); }

/* 칸 폭은 판 폭이 정한다(고정 px 없음) · 높이는 고정이다 — 늘어나면 칸이 세로로 부툁다 (2026-08-28 사용자 지시) */
/* 마스터리 판 — **줄 하나가 한 단계**다. 위가 먼저 열리고 아래로 갈수록 늦게 열린다 (SCREEN_DESIGN §7) */
.sk-grid { display: flex; flex-direction: column; gap: 6px; }
/* 줄은 늘어나지 않는다 — `flex: 1 1 0` 이면 판 높이를 나눠 가져서 칸이 세로로 부푼다 */
.sk-row { display: flex; flex-direction: row; gap: 6px; }

/* 영어 노드명이 길다("All Resistances") — 긴 이름은 두 줄에서 접힌다.
   ⚠ **칸은 정사각형이다** [개정 2026-09-09 사용자 지시] — ~~높이 62px 고정~~(2026-08-28)을 물렸다.
   폭은 판 폭이 정하므로 높이도 그것을 따라간다(`aspect-ratio: 1`). 옛 고정값의 목적(칸이 판 높이를
   나눠 가져 세로로 부푸는 것을 막는다)은 `.sk-row` 가 안 늘어나는 규칙이 이미 지키고 있어 그대로 산다 */
.sk-cell {
    flex: 1 1 0; min-width: 0; aspect-ratio: 1 / 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
    padding: 3px 3px; text-align: center;
    background: var(--bg-tertiary); border: 1px solid var(--border-primary);
    cursor: pointer;
}
.sk-cell:hover { background: var(--surface-3); border-color: var(--border-highlight); }
.sk-cell.taken { background: var(--surface-1); }
.sk-cell.full { box-shadow: inset 0 0 0 1px rgba(var(--tint-rgb),.10); }
.sk-cell.locked { opacity: .6; cursor: not-allowed; }
/* 미작성 칸 — 가지 3 × 깊이 5 프레임이 보이도록 점선으로 남긴다 (비어 있음을 보여주는 것도 정보다) */
.sk-cell.empty {
    background: rgba(var(--tint-rgb), .015);
    border: 1px dashed var(--border-primary);
    cursor: default;
}
.sk-cell.empty:hover { background: rgba(var(--tint-rgb), .015); border-color: var(--border-primary); }
/* 잠긴 박스 안의 빈 칸은 한 번만 흐리게 — 이중으로 흐려지면 프레임이 사라진다 */
.sk-box.locked .sk-cell.empty { opacity: 1; }

.sk-n {
    font-size: var(--fs-2xs); line-height: 1.2; word-break: keep-all;
    overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
:root[lang="en"] .sk-n, html[lang="en"] .sk-n { letter-spacing: -.1px; }   /* 크기는 ko 와 같다 (2026-09-03 토큰 통일) */
.sk-r { font-size: var(--fs-2xs); color: var(--text-muted); }
.sk-cell.taken .sk-r { color: var(--text-secondary); }

/* 값 줄 — 현재 총합 + 랭크를 한 줄에. 잠긴 칸은 그 자리에 필요 레벨만 찍는다 (단계 번호는 화면에 쓰지 않는다) */
.sk-meta { display: flex; align-items: baseline; justify-content: center; gap: 5px; line-height: 1.2; }
/* 현재 총합 — 랭크 0 이어도 찍는다(빈 칸은 「안 재고 있다」로 읽힌다) */
.sk-v { font-size: var(--fs-2xs); color: var(--color-info); }
.sk-meta .lv { font-size: var(--fs-2xs); color: var(--color-warning); }
/* 못 찍는 칸은 손가락 커서를 주지 않는다 — 눌러도 되는 곳만 눌러 보인다 */
.sk-cell.dim { cursor: default; }
.sk-cell.dim:hover { background: var(--bg-tertiary); border-color: var(--border-primary); }
.sk-cell.taken.dim:hover { background: var(--surface-1); }
.sk-cell.can:hover { background: var(--surface-5); border-color: var(--border-highlight); }
.sk-tools { display: flex; justify-content: center; margin-top: 8px; }

/* 액티브 슬롯 3개 + 실효 쿨 병기 (battle_design §5·§6) */
.cycle-line {
    font-size: var(--fs-sm); padding-bottom: 6px; margin-bottom: 6px;
    border-bottom: 1px solid var(--border-dark);
}
.cycle-line b { font-weight: normal; color: var(--color-info); }
.cycle-line .muted { display: block; font-size: var(--fs-xs); }

/* 줄 셋은 **같은 높이**다 [2026-09-09 사용자 지시] — 전직 줄은 스킬이 없어 두 줄을 못 채우는데,
   그 줄만 낮으면 「덜 중요한 자리」로 읽힌다. 셋은 대등한 출처 칸이라 크기가 같아야 한다.
   `grid-auto-rows: 1fr` 이 **가장 큰 줄에 나머지를 맞춘다** — 높이를 px 로 못박지 않으므로
   문장이 한 줄이든 두 줄이든(en) 셋이 함께 따라간다 */
.slot-list { display: grid; grid-auto-rows: 1fr; row-gap: 4px; }
/* ⚠ 출처 열은 **고정 폭**이다 — README 「라벨 칸에 고정 px 금지」의 의도된 예외다 [2026-09-08 사용자 지시].
   줄마다 `.act-slot` 이 **자기 격자**라 `max-content` 는 줄마다 다르게 잡혔고, 그래서 en 에서
   「Hero」 줄과 「Weapon」 줄의 **아이콘 칸이 서로 다른 x 에 떨어졌다**(ko 는 둘 다 두 글자라 안 드러났다).
   폭은 en 최장 라벨 「Advance」(12px 에서 ≈47px)에 여유를 더한 값이고, 라벨은 칸 안에서 가운데 정렬된다.
   ⚠ 이 값을 줄이려면 `.no` 가 안 넘치는지 실측해야 한다(`white-space: nowrap` 이라 조용히 아이콘을 밀고 나간다) */
/* 줄이 여러 줄이므로 **위 정렬**이 기본이고(설명이 길어져도 이름 줄이 안 내려간다), 출처·아이콘 두 열만
   자기 축을 가운데로 되돌린다 — 그 둘은 줄 전체를 대표하는 표지라 글 흐름이 아니라 **줄의 중심**에 선다.
   아이콘 열은 `.ico` 실제 폭과 **같은 수**여야 한다 — 어긋나면 그림이 이름 쪽으로 밀린다 */
.act-slot {
    display: grid; grid-template-columns: 56px 44px 1fr; gap: 9px; align-items: start;
    padding: 6px 9px; background: var(--bg-tertiary); border: 1px solid var(--border-dark);
}
/* 빈 줄도 **같은 첫 열**을 쓴다 — 여기만 `max-content` 면 빈 줄의 사유가 다른 x 에서 시작한다 */
.act-slot.empty { grid-template-columns: 56px 1fr; border-style: dashed; opacity: .55; align-items: center; }
/* 출처는 **줄 가운데**에 선다 [2026-09-08 사용자 지시] — 여러 줄이 된 줄에서 위에 붙이면 아래가 비어 보인다.
   글씨는 9px(`--fs-2xs`) → **12px**(`--fs-xs`) [4차 지시] — 아이콘이 44px 로 커지면서 9px 라벨이 줄 왼쪽에서 사라졌다 */
.act-slot .no {
    font-size: var(--fs-xs); color: var(--text-secondary); text-align: center; white-space: nowrap;
    align-self: center;
}
/* 고유 칸 — 새 색 토큰을 만들지 않고 기존 강조색을 쓴다 (SCREEN_DESIGN §7 · skill_design §9-0).
   ⚠ 캐릭터 탭 카드(`.sk-card`)는 2026-09-08 로 **칸 이름 자체가 없다** — 이 규칙은 스킬 트리 창 목록 전용이다 */
.act-slot.innate .no { color: var(--text-accent); }
/* 그림이 들어오면서 칸을 정사각으로 잡는다 (2026-09-03 · SCREEN_DESIGN §2) — 이모지 때는 글씨 크기가 칸을 정했다.
   28 → **44px** [2026-09-08 4차 지시] — 줄이 세 줄이 되어 28px 그림이 줄 높이에 비해 점처럼 보였다.
   **정사각 칸으로 세운다** — 테두리·배경을 줘야 `ㅁ` 로 읽힌다(페이퍼돌 빈 칸·`.sk-card` 와 같은 문법) */
.act-slot .ico {
    display: flex; align-items: center; justify-content: center; align-self: center;
    width: 44px; height: 44px; padding: 3px;
    font-size: var(--fs-lg); text-align: center;
    background: var(--bg-input); border: 1px solid var(--border-dark);
}
.act-slot .ico img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
.act-slot .nm { font-size: var(--fs-sm); word-break: keep-all; line-height: 1.3; min-width: 0; }
/* 이름과 쿨은 **한 줄**에 선다 (2026-09-08 3차) — 설명이 아랫줄을 가져갔으므로 쿨이 더는 줄을 못 쓴다 */
.act-slot .nm .t { margin-right: 6px; }
/* 표기 쿨 — 값 하나뿐이다 (2026-09-08 2차 병기 폐기로 `.cd b` 규칙도 함께 사라졌다) */
.act-slot .cd { font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; }
/* 본문 한 줄 — **툴팁 문장과 같은 것**이다 [2026-09-08 · `tip.js:skillLineHtml`].
   툴팁의 `.tip-line` 을 그대로 쓰지 않고 별도 클래스를 두는 이유는 **크기만 다르기 때문**이다 —
   툴팁은 떠 있는 카드라 넉넉하고, 여기는 판 안이라 한 단 작다. 강조색(`.tip-hl`)은 전역이라 그대로 걸린다 */
/* 줄 높이는 툴팁(1.55)보다 **짜다** — 판 안이라 세로 예산 700 을 셋이 나눠 쓴다.
   ⚠ ~~`.ds`(회색 고정 설명 줄)~~ 은 2026-09-08 사용자 지시로 **삭제**됐다 — 문장이 같은 말을 더 정확히 한다 */
.act-slot .ln {
    display: block; margin-top: 2px;
    font-size: var(--fs-xs); line-height: 1.4; color: var(--text-primary); word-break: keep-all;
}

/* ───────── 선술집 ───────── */

.cand-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(256px, 1fr)); gap: 12px; }
.cand-card {
    background: var(--bg-tertiary); border: 1px solid var(--border-dark);
    border-top: 3px solid var(--border-secondary); padding: 12px;
}
.cand-head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.cand-head b { font-weight: normal; font-size: var(--fs-lg); }
.cand-trait {
    font-size: var(--fs-sm); color: var(--text-secondary);
    margin: 7px 0 9px; padding-bottom: 8px; border-bottom: 1px solid var(--border-dark);
}
.cand-cost {
    display: flex; align-items: baseline; gap: 7px; font-size: var(--fs-sm);
    margin: 10px 0 9px; padding-top: 9px; border-top: 1px solid var(--border-dark);
}
.cand-cost b { font-weight: normal; color: var(--color-warning); font-size: var(--fs-md); }

.reroll {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border-dark);
}

/* ───────── 도감 ───────── */

/* 스테이지 = 한 줄, 몬스터는 오른쪽으로 쭉 나열.
   한 챕터(4스테이지)가 한 화면(폭 정책의 세로 예산 700px)에 들어와야 한다 — 이 제약이 초상 크기의 상한이다 (2026-08-30) */
.codex-stage {
    padding: 6px 10px 7px; background: var(--bg-tertiary);
    border: 1px solid var(--border-dark); margin-bottom: 5px;
}
.cs-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
    flex-wrap: wrap; margin-bottom: 6px;
}
.cs-title { font-size: var(--fs-sm); }
.cs-title .muted { margin-right: 4px; }
.cs-gain { font-size: var(--fs-xs); }

/* 가로 나열 — 몬스터가 늘어나면 이 줄만 가로 스크롤된다 */
.mon-strip { display: flex; gap: 6px; overflow-x: auto; }

/* 가로형 카드 — 초상 왼쪽 / 정보 오른쪽. **카드 높이는 초상이 정한다** (2026-08-30, SCREEN_DESIGN §9).
   초상이 커진 만큼 본문도 넓어야 해서 min-width 를 올렸다 — 하한 폭 1280 에서 4장 + 여백이 들어간다 */
.mon-card {
    flex: 1 1 0; min-width: 190px; max-width: 360px;
    display: flex; align-items: stretch; gap: 9px; padding: 5px 8px;
    background: var(--bg-card); border: 1px solid var(--border-dark);
    border-left: 2px solid var(--border-secondary);
}
.mon-card.boss { border-left-color: var(--text-accent); }
.mon-card.maxed { border-color: var(--done-line); border-left-color: var(--color-success); background: var(--done-bg); }
/* 도감의 초상 — 이 화면에서 가장 큰 칸. 원형 마스크는 몬스터 공통 규칙이라 그대로 두고 지름만 키운다 */
.mon-card .face { width: 72px; height: 72px; font-size: var(--fs-lg); }
.mon-card .face img { width: 100%; height: 100%; object-fit: cover; }

.mon-body { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 4px; }
.mon-top { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
.mon-name {
    flex: 1 1 auto; min-width: 0;
    font-size: var(--fs-sm); line-height: 1.3; word-break: keep-all;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mon-name .b-tag { color: var(--text-accent); font-size: var(--fs-xs); margin-left: 4px; }
/* 장수는 줄바꿈하지 않는다 — 영어("0 cards")가 이름과 폭을 다투면 숫자가 두 줄로 접힌다. 줄어드는 쪽은 이름(말줄임)이다 */
.mon-kills { flex: 0 0 auto; white-space: nowrap; }
.mon-kills b { font-weight: normal; font-size: var(--fs-lg); color: var(--text-primary); }
/* 초상이 커지며 생긴 세로 여유로 핍과 「처치 · 다음」을 위아래로 나눈다 — 한 줄에 두면 좁은 칸에서 글자가 잘린다 */
.mon-mid { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.mon-next { font-size: var(--fs-xs); white-space: nowrap; }
.mon-card .bar { width: 100%; height: 5px; }

/* 레벨 핍 — 도감 레벨(카드 누적 문턱)을 한눈에 */
.pips { display: flex; gap: 3px; }
.pips .pip {
    width: 14px; height: 5px; background: var(--bg-input);
    /* 안 켜진 핍도 보여야 한다 — 「몇 번 더 올릴 수 있나」가 도감의 목표치다. --border-dark 는 카드 배경에 묻혔다 (2026-08-30) */
    border: 1px solid var(--border-secondary);
}
.pips .pip.on { background: var(--color-success); border-color: var(--color-success); }

/* ───────── 도감 — 자산 세그먼트 (SCREEN_DESIGN §9-1 · 2026-09-06 · 도감으로 흡수 2026-09-08) ─────────
   옛 「이미지 도감」 탭. 자산을 묶음별로 펼치는 조회 화면이고, 09-08 에 도감의 세그먼트 셋(캐릭터 · 아이템 · 스킬)이 됐다 —
   **클래스 이름은 `.ix-*` 그대로**다(화면의 속이 안 바뀌었다). 칸 폭은 고정 px 이 아니라 auto-fill + minmax 다 —
   이름과 파일명이 들어가는 칸이라 영어에서 길어진다 (폭 정책은 src/ui/README.md).
   마스크는 게임에서 쓰는 것 그대로 — 영웅·아이템·스킬은 네모(`box`), 몬스터는 원형(`round` — 09-08 이 화면에서는 안 쓰지만 §9 카드가 쓴다) */
.ix-style { display: flex; align-items: center; gap: 6px; font-size: var(--fs-xs); }
.ix-body { display: flex; flex-direction: column; gap: 10px; }
.ix-group {
    padding: 7px 10px 9px; background: var(--bg-tertiary);
    border: 1px solid var(--border-dark);
}
.ix-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 7px; }
.ix-title { font-size: var(--fs-sm); }
.ix-dir { font-size: var(--fs-xs); }
.ix-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); gap: 8px; }
.ix-tile {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 6px 4px; background: var(--bg-card); border: 1px solid var(--border-dark);
}
/* 그림 칸 — 게임에서 가장 큰 자리(도감 초상 72px)보다 크게 잡는다. 아트를 확인하러 오는 화면이라
   여기서까지 작으면 이 탭이 있을 이유가 없다. 그림이 없으면 이 빈 네모가 그대로 남는다 */
.ix-art {
    width: 92px; height: 92px; flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center; overflow: hidden;
    background: var(--bg-input); border: 1px solid var(--border-dark);
}
.ix-art.round { border-radius: 50%; }
.ix-art img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
/* 원형 마스크는 가장자리를 잘라낸다 — 몬스터 카드(.face img)와 같은 cover 라야 도감에서 보이는 그대로다 */
.ix-art.round img { object-fit: cover; }
.ix-name { font-size: var(--fs-xs); line-height: 1.25; text-align: center; word-break: keep-all; }
.ix-file { font-size: var(--fs-xs); line-height: 1.2; text-align: center; word-break: break-all; }

/* 조밀 격자 — 스킬 세그먼트 전용 (ADR-0075 · 2026-09-10).
   묶음이 다섯이라(직업) 92px 그림으로는 하한 1280x700 에서 둘 반만 보이고 나머지는 스크롤 아래였다.
   그림을 줄여 **다섯 묶음이 한 화면에 다 선다** — 캐릭터 · 아이템은 묶음이 셋 이하라 그대로 92px 이다.
   칸 폭(minmax)은 가장 큰 묶음(8칸)이 하한 폭에서 한 줄에 서도록 잡았다 — 접히면 세로 예산이 깨진다 */
/* 그림 칸은 **1600×800 한 장 기준 고정값**이다 (ADR-0087) */
.ix-body.dense { gap: 5px; --ix-art: 48px; }
.ix-body.dense .ix-group { padding: 3px 8px 4px; }
.ix-body.dense .ix-head { margin-bottom: 3px; gap: 8px; }
.ix-body.dense .ix-title { font-size: var(--fs-xs); }
.ix-body.dense .ix-grid { grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 5px; }
.ix-body.dense .ix-tile { padding: 3px; gap: 1px; }
.ix-body.dense .ix-art { width: var(--ix-art); height: var(--ix-art); }
.ix-body.dense .ix-name { line-height: 1.15; }
.ix-body.dense .ix-file { line-height: 1.1; }

/* ───────── 페이퍼돌 (부위 8종 · 위치 9개, 반지 ×2) ───────── */

.paperdoll {
    display: grid; grid-template-columns: repeat(3, 60px);
    gap: 8px; justify-content: center; margin-top: 4px;
}
.pd-gap { width: 60px; height: 60px; }

.pd-cell {
    width: 60px; height: 60px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    background: var(--bg-input); border: 2px solid var(--border-dark);
    position: relative; cursor: pointer;
}
.pd-cell:hover { background: var(--surface-2); }
.pd-cell.filled { background: var(--bg-tertiary); }

.pd-icon { font-size: 22px; line-height: 1; filter: grayscale(1) brightness(.55); }
.pd-cell.filled .pd-icon { filter: none; }
.pd-label { font-size: var(--fs-2xs); color: var(--text-muted); letter-spacing: 0; }
.pd-cell.filled .pd-label { color: var(--text-secondary); }

/* 미장착 칸 = 부위 실루엣 [2026-09-03] — 「여기에 무엇이 들어가는가」를 그림이 말한다.
   ⚠ CSS `background: url()` 이 아니라 **`<img>`** 다 (스킬 아이콘과 같은 문법 · 규칙은 `mock.js:slotArt`).
   커스텀 프로퍼티에 담은 상대 url 은 **이 파일 기준**(`/ui/assets/…`)으로 풀려 404 가 난다 —
   실제로 그렇게 짰다가 칸이 통째로 비었다. img 의 src 는 문서 기준이라 그 함정이 없다.
   **이모지를 밑에 깔지 않는다** — 투명 PNG 사이로 비친다(직업 글리프 폐지와 같은 이유).
   그림이 없는 부위(투구·목걸이)만 이모지로 남는다. `.pd-label` 의 `position` 은 그림 위로 글씨를 올린다 */
/* 라벨은 칸 **아래**로 내리고 그림은 그 위 영역에 가둔다 — 겹치면 옅은 실루엣 위에서 부위 이름이 안 읽힌다.
   그래서 `inset` 의 아래값(14px)과 `justify-content` 는 한 쌍이다: 한쪽만 바꾸면 다시 겹친다 */
.pd-cell.art { justify-content: flex-end; }
.pd-cell.art .pd-art { position: absolute; inset: 3px 3px 14px; pointer-events: none; }
.pd-cell.art .pd-art img {
    width: 100%; height: 100%; object-fit: contain;
    opacity: .3; image-rendering: var(--face-render);
}
.pd-cell.art .pd-label { position: relative; }

/* 아이템 그림 — 이모지가 들던 칸 넷 (2026-09-03 · SCREEN_DESIGN §2 · 규칙은 `mock.js:itemArt`).
   ⚠ 칸에 **크기를 준다**: 이모지는 글씨라 font-size 가 칸을 정했지만 img 는 부모가 정해야 한다.
   그림이 없는 부위(투구·목걸이)는 같은 칸에 이모지로 떨어지므로 font-size 도 그대로 남는다 */
.pd-icon, .inv-icon {
    display: flex; align-items: center; justify-content: center;
    width: 34px; height: 34px;
}
.pd-icon img, .inv-icon img, .fg-ic img {
    width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render);
}
.fg-row .fg-ic { display: block; width: 22px; height: 22px; }
.fg-head .fg-ic { display: block; width: 30px; height: 30px; flex: 0 0 auto; }

/* ───────── 인벤토리 격자 ───────── */

.inv-cells { display: grid; gap: 4px; }

.inv-cell {
    aspect-ratio: 1 / 1;
    display: flex; align-items: center; justify-content: center;
    background: var(--bg-input);
    border: 1px solid var(--border-dark);
    box-shadow: inset 1px 1px 0 0 rgba(var(--shadow-rgb), .5);
}
.inv-cell.filled {
    background: var(--bg-tertiary); border-width: 2px; cursor: pointer;
    box-shadow: none;
}
.inv-cell.filled:hover { background: var(--surface-5); }
.inv-icon { font-size: 20px; line-height: 1; }

/* 유니크는 은은하게 빛난다 */
.inv-cell.shine { animation: shine 2.4s ease-in-out infinite; }
@keyframes shine {
    0%, 100% { box-shadow: none; }
    50% { box-shadow: 0 0 9px rgba(var(--rarity-unique-rgb), .55); }
}

/* 도움말 본문의 글자 규격 (접이식 「구성 보기」는 2026-09-10 삭제 · ADR-0080) */
.note-body {
    font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.7;
    margin-top: 7px; padding-left: 2px;
}


/* ───────── 캐릭터 탭 (2026-08-23) ─────────
   세로 3단: 영웅 띠 / 4칸 / 아이템. 단 사이 간격은 .panel + .panel 이 아니라 스택이 준다 */

/* 세 단이 박스 높이를 통째로 나눠 갖는다 [2026-09-09 사용자 지시 · 박스 2026-09-11 ADR-0097] — **가방이 박스 끝에 서고**
   남는 세로는 가운데 네 칸(`.cols.c-char`)이 먹는다 (SCREEN_DESIGN §6).
   셋째 행이 `minmax(0, auto)` 인 이유 — 세로가 모자라면 네 칸은 하한(아래 `.cols.c-char > .panel`)을 지키고 **가방이 줄어**
   가방 칸이 가방 안에서 스크롤한다. 격자는 제 크기 행(띠 · 가방)을 먼저 채우고 1fr 에 나머지를 준다 */
.char-stack { display: grid; grid-template-rows: auto 1fr minmax(0, auto); gap: 14px; }
.char-stack > .bag, .char-stack > .bag-row > .bag { display: flex; flex-direction: column; min-height: 0; }
/* 칸 격자는 **줄기만 하고 자라지 않는다** (flex-grow 0 · 2026-09-14) — 늘어난 창고 패널의 남는 높이는 도구 줄이 받아야 두 칸의 칸 줄이 맞는다(`.bag-row`).
   가방 행이 `minmax(0, auto)` 라 이 격자가 자랄 자리는 원래 그 경우뿐이었다 */
.char-stack > .bag > .inv-cells, .char-stack > .bag-row > .bag > .inv-cells { flex: 0 1 auto; min-height: 0; overflow-y: auto; }

/* ① 영웅 띠 — 원정 편성·캐릭터·스킬·선술집 공통 상단 (2026-08-26 · 2026-08-27 개편 · 2026-08-27 원정 편성 추가). 초상이 카드 전체를 채우는 정사각이고,
   글자는 초상 위에 얹는 위칸 하나다: 왼쪽 = 지금 하는 일(색 태그) · 오른쪽 = 이름 (SCREEN_DESIGN §5).
   로스터 상한(7)까지 한 줄에 편다 — 개수를 CSS에 박지 않는다(roster_cap 은 데이터다). flex 로 나눠 갖되 상한폭을 둬서
   영웅이 적을 때 카드가 판넬을 다 먹지 않게 한다 */
.hs-panel { padding: 10px 12px; }
/* 편성 패널 안에 들어갈 때 — 패널 안 패널이 되지 않게 껍데기를 벗는다 */
.hs-panel.flat { padding: 0; background: none; border: 0; }
.hero-strip { display: flex; flex-wrap: wrap; gap: 8px; }
.hs-card {
    flex: 1 1 0; min-width: 96px; max-width: 120px;   /* 2026-08-27 축소 — 화면 대비 너무 컸다 (관전 유닛 카드 상한과는 별개다) */
    background: var(--bg-tertiary); border: 1px solid var(--border-dark);
    border-top: 3px solid var(--border-secondary);
    cursor: pointer; position: relative; overflow: hidden;
}
.hs-card:hover { border-color: var(--border-highlight); }
/* 편성 띠 — 파티에 넣을 수 있는 건 **대기**뿐이다. 출정 아웃은 거절(플래시)이므로 커서로도 미리 말한다.
   다른 탭에서는 아웃된 영웅도 눌러서 들여다볼 수 있으므로 이 띠에서만 건다 */
.hero-strip.party-mode .hs-card.downed { cursor: not-allowed; }
/* 클릭한 영웅 — **파란 겉 테두리**가 여기로 옮겨 왔다 (2026-09-08 사용자 지시 · SCREEN_DESIGN §5) */
.hs-card.on { border-color: var(--border-highlight); background: var(--surface-4); outline: 2px solid var(--color-info); outline-offset: 1px; }
/* 전투 파티 = **반투명** [개정 2026-09-09 사용자 지시 · SCREEN_DESIGN §5 · ADR-0056] —
   파란 겉 테두리(테두리 색 + 3px 아웃라인 + 번짐)를 통째로 걷고 **흐림 하나**가 그 뜻을 든다.
   띠가 탭 최상단으로 올라간 뒤(ADR-0055) 파티 영웅은 **아래 진형 보드에도 같이 서 있다** —
   그래서 위 카드의 흐림이 「이 영웅은 아래(전투)에 내려가 있다」로 읽힌다. 자리를 옮긴 표시지 못 쓰는 표시가 아니다.
   ⚠ 테두리를 안 쓰므로 `.on`(다른 띠의 「보고 있는 영웅」)과 표시가 겹칠 일이 없다 — 편성 띠는 `.on` 을 안 건다
   ⚠ **전진 패널이 열려 있을 때만 흐려진다** [2026-09-09 사용자 지시 · ADR-0058] — 「내려가 있다」는 **내려갈 곳이 있을 때만** 참이다.
     지역을 닫으면(`.deployed` 가 빠진다) 파티 영웅도 선명하게 돌아온다
   ⚠ **이 주석이 한 줄 일찍 닫혀 있었다** [2026-09-11 수정] — ADR-0058 문단이 주석 닫는 기호 뒤에 붙어 선택자로 읽히는 바람에
     바로 아래 `opacity: .5` 규칙이 통째로 버려졌다(09-09 cd72dcc 부터). hover 의 .72 만 살아 흐림이 올려놓을 때만 보였다.
     주석 안에 닫는 기호를 글자로 적지 않는다 — 적으면 같은 사고가 난다 */
.hero-strip.party-mode.deployed .hs-card.party { opacity: .5; }
.hero-strip.party-mode.deployed .hs-card.party:hover { opacity: .72; }
.hs-card.unique { border-bottom-color: var(--elite-line); }
.hs-card.downed { opacity: .62; }
.hs-card.empty {
    display: flex; align-items: center; justify-content: center; aspect-ratio: 1; cursor: default;
    border-style: dashed; border-top-width: 1px; background: transparent;
    color: var(--text-muted); font-size: var(--fs-lg);
}
.hs-card.empty:hover { border-color: var(--border-dark); }
/* 초상(카드 전체) · 위칸 · 이름의 규칙은 공통 조각에 있다 (.hs-card .hero-face / .hs-band / .hs-name) */
/* 리더 — 편성 화면에서 파티 첫 슬롯에만. 초상 아래쪽에 얹는다 (2026-08-27, 옛 파티 행의 리더 표시) */
/* 해고 — **고른 카드의 오른쪽 아래**에만 뜬다 [2026-09-09 사용자 지시 · SCREEN_DESIGN §5].
   리더 뱃지(`.hs-leader`)가 왼쪽 아래를 쓰므로 자리가 안 겹친다. 초상 위에 얹히니 제 배경을 갖는다 —
   그림이 밝으면 글자가 안 읽힌다(`.zone-pick` 이 배경 위에서 쓰는 것과 같은 이유) */
.hs-dismiss {
    position: absolute; right: 0; bottom: 0; z-index: 2;
    /* 한 단 키웠다 [2026-09-09 사용자 지시] — 9px 은 카드 구석에서 눌러야 할 것으로 안 읽혔다.
       상한은 카드 폭(.hs-card 하한 96px)이다: 영어 `Dismiss` 가 들어가야 하므로 여기서 더 키우지 않는다 */
    padding: 4px 9px; font-size: var(--fs-xs); line-height: 1.3;
    background: rgba(var(--danger-veil-rgb), .88); border: 1px solid var(--danger-line); color: var(--danger-fg);
}
.hs-dismiss:hover { background: var(--danger-bg-hover); border-color: var(--color-error); }

.hs-leader {
    position: absolute; left: 0; bottom: 0;
    font-size: var(--fs-xs); line-height: 1.2; padding: 2px 6px;
    background: color-mix(in srgb, var(--bg-primary) 78%, transparent);
    border-top: 1px solid var(--border-dark); border-right: 1px solid var(--border-dark);
    color: var(--text-accent);
}
/* 파티 없음 / 출발 불가 경고 — 띠 아래 (옛 파티 패널이 들던 자리) */
/* 경고 줄 — 글자가 없어도 **자리는 잡는다**. 안 그러면 편성 패널이 파티 상태에 따라 커졌다 작아진다 (2026-08-28) */
/* 세로 쌓기 시절의 윗 여백을 걷는다 (2026-09-09 · ADR-0059) — 이제 오른쪽 칸(.fp-side)의 첫 줄이라 gap 이 간격을 준다.
   ⚠ **줄은 여전히 항상 잡는다**(min-height) — 글자가 있고 없고에 따라 버튼이 위아래로 뛰면 안 된다 */
.exp-warn { font-size: var(--fs-xs); min-height: 1.35em; line-height: 1.35; }
/* 지금 하는 일 — 출정 아웃(빨강) / 전투 파티(파랑) / 대기(회색) */
.hs-doing {
    font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; line-height: 1.3;
    flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;   /* 줄어드는 쪽은 여기뿐 (2026-09-09) */
}
.hs-doing.exp { color: var(--color-warning); }      /* 원정 중 — 주황 (2026-09-08) */
.hs-doing.down { color: var(--color-error); }       /* 남겨 둔 색 — 지금 쓰는 자리는 없다 */

/* ② 네 칸 — 장비 / 기본 옵션(+현재 스킬) / 세부 옵션 1 / 세부 옵션 2. **같은 폭 · 같은 높이** (2026-08-27).
   폭은 1fr × 4 (최소 창 1280 에서 칸당 약 245px — 페이퍼돌 3×60 이 들어간다), 높이는 grid stretch 가 가장 큰 칸에 맞춘다 */
.cols.c-char { grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: stretch; }
/* 높이 하한 [2026-09-08 사용자 지시 「조금만 더 늘려」 · 430 → 412 2026-09-11 · ADR-0097] — 종전엔 가장 큰 칸(세부 옵션 1)이 정한 379px 이었다(실측).
   412 는 가방이 관전 크기(칸 52)로 커지며 **박스 안에 드는 값**이다 — 가장 긴 칸의 내용(약 401)보다 크다.
   ⚠ 이 값은 **세로 예산을 직접 깎는다** — 모자라면 가방 칸이 가방 안에서 스크롤한다 (위 `.char-stack`) */
.cols.c-char > .panel { display: flex; flex-direction: column; min-height: 412px; }

/* 패널 안의 작은 소제목 — h2 를 또 쓰면 칸이 나뉜 것처럼 보인다 */
.sub-h {
    font-size: var(--fs-sm); color: var(--text-secondary);
    margin: 9px 0 6px; padding-top: 7px; border-top: 1px solid var(--border-dark);
    display: flex; justify-content: space-between; align-items: baseline; gap: 6px;
}
.sub-h .muted { font-size: var(--fs-xs); }

/* ②-2 기본 능력치 막대 — 범위는 [balance.csv:hero_attr_min ~ hero_attr_max] */
/* **격자는 줄이 아니라 목록이 든다** (2026-09-01 사용자 지시) — 줄마다 자기 격자를 가지면 라벨 열이
   줄마다 따로 계산돼 **막대 시작점이 들쭉날쭉해진다**(「힘」과 「매력」의 글자 폭이 다르므로).
   목록이 열을 잡고 줄은 `display: contents` 로 사라져야 일곱 줄이 **같은 x 에서** 시작한다.
   열 폭은 여전히 내용이 정한다(고정 px 없음 — ko/en 어느 쪽에서도 안 깨진다) */
.attr-list {
    display: grid; grid-template-columns: minmax(0, auto) minmax(38px, 1fr) 24px;
    gap: 3px 7px; align-items: center;
}
.attr-row { display: contents; }
/* 격자 안에 든 줄 아닌 것(범위 표기)은 한 줄을 통째로 쓴다 */
.attr-range { grid-column: 1 / -1; }
/* 이름은 왼쪽 · **약어는 막대에 붙는다** (2026-09-01 사용자 지시) — 라벨 칸을 일곱 줄이 공유하므로,
   약어를 이름 뒤에 그냥 붙이면 이름 길이를 따라 x 가 흔들리고 막대와의 사이에 들쭉날쭉한 틈이 생긴다
   (영어에서 특히 — `Luck` 과 `Intelligence` 의 차이). 칸을 꽉 쓰고 양끝으로 밀면 약어 열이 **막대 왼쪽 변에 정렬**된다 */
.attr-n {
    font-size: var(--fs-sm); color: var(--text-secondary); white-space: nowrap;
    display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.attr-bar { height: 7px; background: var(--bg-input); border: 1px solid var(--border-dark); }
.attr-bar > i { display: block; height: 100%; }
.attr-v { font-size: var(--fs-sm); text-align: right; }
.attr-range { font-size: var(--fs-xs); text-align: right; margin-top: 2px; }

/* 능력치 약어 배지 — 언어 중립(STR/AGI…)이라 한/영 어느 쪽에서도 폭이 같다.
   **기본 옵션 막대 줄(`.attr-n`) 전용** — 세부 옵션 행에는 안 붙는다 (2026-09-08 사용자 지시, SCREEN_DESIGN §6) */
.cs-a {
    font-style: normal; font-size: var(--fs-2xs); color: var(--text-muted);
    border: 1px solid var(--border-dark); padding: 0 3px; margin-left: 4px;
    vertical-align: 1px; letter-spacing: 0; flex: 0 0 auto;
}

/* ②-3·4 세부 옵션 1·2 — 21행(impl=1)을 두 칸에 나눠 스크롤 없이 다 보이는 게 정상 (2026-08-27).
   flex-basis 는 auto — 목록의 본래 높이가 칸 높이 산정에 들어가야 가장 긴 칸이 네 칸의 높이를 정한다.
   (0 이면 목록이 높이 산정에서 빠져 다른 칸 높이에 맞춰 잘리고 스크롤이 생긴다)
   ⚠ 가장 긴 칸은 2026-09-01 로 **세부 옵션 1**(13행)이 됐다 — 칸 경계가 '피해 감소' 앞으로 옮겨갔다 (SCREEN_DESIGN §6) */
.cs-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: 4px; }
.cs-row { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; padding: 1px 0; }
.cs-n { font-size: var(--fs-sm); color: var(--text-secondary); }
.cs-v { font-size: var(--fs-sm); color: var(--text-primary); white-space: nowrap; }
/* 값이 없는 축 = 다음 장비가 들어올 자리. 지우지 않고 흐리게 남긴다 */
.cs-row.off .cs-n, .cs-row.off .cs-v { color: var(--text-muted); }
/* 머리 3줄 = 대표값(물리 공격력 · 마법 공격력 · 최대 HP) — **값 굵기 + 아래 선 하나** (2026-09-01 · 개정 2026-09-08).
   제목이 아니라 **선**이다: 카테고리 제목을 두지 않기로 한 08-26 결정을 지키면서 「여기까지가 대표값」만 말한다.
   ⚠ ~~font-size: var(--fs-md)~~ 는 2026-09-08 폐기 [사용자 지시] — 크기까지 키우면 선·굵기와 같은 말을 세 번 하고,
   세부 옵션 1·2 의 행 눈금이 어긋나며, 늘 꺼져 있는 쪽 공격력 줄이 시트에서 제일 큰 글씨가 된다 (SCREEN_DESIGN §6) */
.cs-row.lead .cs-v { font-weight: 700; }
.cs-row.lead + .cs-row:not(.lead) { border-top: 1px solid var(--border-primary); margin-top: 5px; padding-top: 6px; }

/* 버튼은 **칸 바닥에 못 박는다** (2026-09-08) — 스킬 블록이 위로 올라간 뒤 남는 세로를 이 auto 가 먹는다 */
.go-tree { width: 100%; margin-top: auto; }
/* 해고 창의 속 — 한 줄 + (막히지 않았으면) 위험 색 버튼. 규칙 설명이 아니라 상태와 확인이다 (SCREEN_DESIGN §6) */
.dismiss-box { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; font-size: var(--fs-sm); }
/* 답하는 버튼 줄 — 막힘이면 [확인] 하나, 확인이면 [확인] [취소] 둘 (2026-09-09 사용자 지시 · SCREEN_DESIGN §6).
   ⚠ **줄은 상태와 상관없이 늘 있다** — 막힘 상태에 버튼이 없던 옛 판은 창을 X 로만 닫을 수 있었다.
   **가로 가운데** (2026-09-09 사용자 지시) — 상자가 `align-items: flex-start` 라 줄이 왼쪽에 붙어 있었다.
   `align-self` 가 상자의 그 정렬을 이 줄에서만 덮고, `justify-content` 가 버튼 하나·둘 어느 쪽이든 가운데에 세운다 */
.dismiss-actions { display: flex; flex-direction: row; gap: 8px; align-self: center; justify-content: center; }

/* ②-2 액티브 스킬 — 기본 옵션 칸 아래쪽, 액티브 3 을 정사각 카드로 (2026-08-27 · 이름은 2026-09-08 개명).
   ⚠ 칸 폭을 그냥 3등분하면(`1fr`) 카드가 패널 폭을 따라 커진다 — 글자 줄이 있던 시절엔 그 줄들이 크기를
   붙들었지만, 그림 하나만 남은 뒤로는 붙드는 것이 없어 67px 짜리 판때기가 됐다 (2026-09-08 사용자 지적).
   그래서 **상한을 캡으로 묶는다** — 고정 px 이 아니라 폭 비례라 좁은 화면에서는 퍼센트가, 넓으면 캡이 든다.
   ⚠ **퍼센트 항은 캡보다 커야 캡이 산다** — 처음 넣은 `clamp(34px, 18%, 44px)` 은 1280 에서 18% = 39px 이라
   44px 캡이 **한 번도 안 걸렸고** 카드가 39px 로 떨어졌다. 지금의 `30%`(1280 에서 ≈65px)는 캡 60 위에 있다 */
/* 블록은 **막대 바로 밑**에 붙고(선 하나로 가른다), 남는 세로는 아래 버튼의 `margin-top: auto` 가 먹는다
   [2026-09-08 사용자 지시 「위치 좀 옮겨봐」] — 종전엔 이 줄이 `margin-top: auto` 라 블록 전체가 칸 바닥으로
   밀려 막대와의 사이에 빈 띠가 크게 남아 있었다(칸 높이 하한 430px 이 그 띠를 더 벌렸다) */
.sk-cards-wrap {
    display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
    margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border-primary);
}
.sk-cards { display: grid; grid-template-columns: repeat(3, clamp(44px, 30%, 60px)); gap: 8px; }
.sk-card {
    aspect-ratio: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    padding: 3px; text-align: center;
    background: var(--bg-input); border: 1px solid var(--border-dark);
}
/* 찬 칸은 **그림 하나뿐**이라 (2026-09-08 · SCREEN_DESIGN §6) 그림이 칸을 꽉 쓴다.
   칸이 `aspect-ratio: 1` 이므로 `min-height: 0` 으로 카드가 먼저 줄게 둔다 */
.sk-card .ico { line-height: 1; width: 100%; height: 100%; min-height: 0; }
.sk-card .ico img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
/* 빈 칸 — **글자가 없다.** 칸이 아이콘 크기(≤44px)라 `Not advanced` 가 안 들어간다(9px + 여백 0 에서도 잘렸다).
   사유는 `title` 이 들고, **찍는** 자리는 스킬 트리 창 목록(`.act-slot.empty`)이다 (SCREEN_DESIGN §6 · §7).
   빈 것을 말하는 것은 파선 테두리다 — 페이퍼돌 빈 칸 · `.act-slot.empty` 와 같은 문법 */
.sk-card.vacant { border-style: dashed; opacity: .55; }
/* 후보 카드의 고유 스킬 — 살 수 있는 영웅이라 주기를 모른다. 그 자리에 **기본값**이 온다 (SCREEN_DESIGN §3) */
.ng-skill .cd { display: block; font-style: normal; font-size: var(--fs-2xs); color: var(--text-muted); }

/* ③ 아이템 — 열 수는 창 폭이 정한다. 데이터는 용량(INV_GRID.cap)만 지킨다 */
.inv-cells.wide { grid-template-columns: repeat(auto-fill, minmax(42px, 1fr)); }
.inv-filter { margin-bottom: 10px; }

/* ───────── 새 게임 (2026-08-24) ─────────
   게임 밖 화면이라 네비·자원을 접고 본문이 전폭을 쓴다. 로고와 언어 토글만 남는다 */

#app.pregame { grid-template-areas: "brand topbar" "main main"; }
#app.pregame .nav { display: none; }

.ng-wrap {
    max-width: 1060px; margin: 0 auto;
    padding: 24px 0 24px;
}
.ng-title { text-align: center; margin-bottom: 19px; }
.ng-title h1 {
    font-size: var(--fs-xl); font-weight: normal; letter-spacing: 2px;
    color: var(--text-primary); margin-bottom: 6px;
}
.ng-title p { font-size: var(--fs-sm); }

/* 세 장은 같은 무게로 놓인다 — 하나를 크게 하면 그쪽이 정답처럼 읽힌다 */
.ng-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }

.ng-card {
    background: rgba(var(--surface-0-rgb), var(--panel-alpha));
    border: 1px solid var(--border-primary);
    border-top: 3px solid var(--border-secondary);
    padding: 14px 16px 13px;
    /* 초상이 **카드 폭**을 보게 하는 자리 (2026-09-10 · ADR-0076). 아래 .ng-head .hero-face 의 `cqw` 가 이걸 쓴다.
       `contain: layout` 이 함께 걸리지만 카드 안에 카드 밖을 기준으로 눕는 것이 없어 안전하다 —
       초상 위 겹침(.hero-face img)은 초상 안쪽이고, 툴팁(#tooltip)은 `#stage` 바로 아래라 카드의 자손이 아니다 */
    container-type: inline-size;
}
/* 이름 블록은 초상 **윗변에 맞추고**, 고유 스킬 칸은 **아랫변에 붙인다** (SCREEN_DESIGN §3 2026-09-03).
   가운데 정렬이면 이름이 내려앉아 스킬 칸이 설 자리가 없고, 스킬 칸을 글 흐름에 그냥 두면
   역할 줄이 두 줄이 되는 카드(영어 「Bow / Crossbow」)에서만 칸이 내려가 세 장의 높이가 어긋난다 */
.ng-head { display: flex; align-items: stretch; gap: 11px; margin-bottom: 10px; }
/* 후보 카드의 초상은 **카드에서 가장 큰 조각**이다 (2026-08-31 사용자 지시 · SCREEN_DESIGN §3) —
   시작 화면은 그림을 처음 보는 자리이고 고르는 근거의 절반이 인상이라, 아이콘 크기로는 얼굴이 안 읽힌다.
   고정 px 이 아니라 따라 자란다(폭 정책 — src/ui/README.md).
   ⚠ 기준은 **창이 아니라 카드**다 [개정 2026-09-10 · ADR-0076] — ~~`9.5vw`~~ 는 창을 봐서, 같은 `.ng-card` 인데도
   시작 화면(`.ng-wrap` 이 1060px 에서 자른다 → 카드 343px)과 선술집(패널 전폭 → 카드 378px)에서 **초상만 같은 137px** 이었다.
   카드는 10% 넓은데 얼굴은 그대로라 「카드에서 가장 큰 조각」이 선술집에서만 풀렸다. `cqw` 는 카드 안쪽 폭의 %라
   두 화면 모두 **44%** 로 같다(시작 136px · 선술 151px). 상한 152px 은 그대로 — 넓은 창에서 무한정 크지 않는다 */
.ng-head .hero-face { width: clamp(96px, 44cqw, 152px); height: clamp(96px, 44cqw, 152px); }
.ng-id { min-width: 0; display: flex; flex-direction: column; }
/* 정체성은 **두 줄**이다 — 칩 줄(등급 + 죄종) 위, 이름 아래 [개정 2026-09-08 사용자 지시].
   ~~이름 + 칩 둘을 한 줄에~~ (2026-09-01) 는 영어에서 이름을 상시로 잘랐다: 3열 카드의 좁은 폭에
   `Gluttony` 같은 긴 칩이 함께 서면 **줄어들 수 있는 것이 이름뿐**이었다(칩은 flex-shrink:0 이라 안 줄어든다).
   이름이 제 줄을 통째로 쓰면 말줄임이 거의 안 걸리고, §5 관전 카드가 09-07 에 간 길(신원 윗줄 · 이름 아랫줄)과
   문법이 같아진다. 칩 둘이 나란히 서는 것은 그대로다 (SCREEN_DESIGN §3) */
.ng-chips { display: flex; align-items: center; gap: 6px; line-height: 1.3; }
.ng-chips .tier-chip, .ng-chips .sin-chip { flex: 0 0 auto; }
/* 칩 줄과 이름 사이는 **살짝 띄운다** (2026-09-08 사용자 지시) — 붙어 있으면 두 줄이 한 덩어리로 읽혀
   「무엇인가(칩) / 누구인가(이름)」가 안 갈린다. 층을 가르는 최소값이라 4px 이고 그 이상은 카드가 길어진다 */
.ng-name { line-height: 1.3; min-width: 0; margin-top: 4px; }
.ng-name > b {
    display: block;
    font-weight: normal; font-size: var(--fs-lg);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ng-cls { font-size: var(--fs-sm); color: var(--text-secondary); white-space: nowrap; }
/* 역할/무기군 줄 — **언제나 두 줄 자리를 잡는다** (2026-09-03). 한국어는 한 줄, 영어는 직업에 따라 두 줄이라
   (「Ranged Physical · Bow / Crossbow」) 접히는 카드만 키가 커져 세 장이 어긋났다. 자리를 늘 비워 두면
   카드 높이가 언어·직업과 무관해지고, 그래야 아래 스킬 칸을 마음껏 키울 수 있다 */
.ng-role { font-size: var(--fs-xs); line-height: 1.35; min-height: calc(2 * 1.35em); margin-top: 1.35em; }
/* ↑ **한 줄 내린다** (2026-09-08 사용자 지시) — 직업 줄(`Warrior · Lv.1`)과 붙어 있으면 정체성 두 줄과
   역할 줄이 넉 줄 한 덩어리로 읽힌다. 한 줄 비워 「이 영웅이 누구인가」와 「무엇을 하는가」를 가른다 */
/* 고유 스킬 칸 — 네모 아이콘 + 이름. 능력치 막대 위·정체성 줄 아래다 (§3).
   **칸은 나중에 들어올 스킬 이미지의 자리다** (2026-09-03 사용자 지시) — 지금 든 이모지는 임시이고,
   크기는 그림이 들어와도 읽히도록 44px 로 잡았다. 오른쪽 열 합(**칩 줄 20** + 이름 23 + 직업 18 + 역할 2줄 33 + 여백 6 + 44 ≒ 144)이
   초상 clamp 하한(121)보다 커졌다 [2026-09-08 — 칩 줄이 생겼다]. 좁은 창에서는 **오른쪽 열이 카드 높이를 정한다** */
.ng-skill { display: flex; align-items: center; gap: 8px; margin-top: auto; padding-top: 6px; min-width: 0; }
.ng-skill .ico {
    flex: 0 0 auto; width: 44px; height: 44px; display: grid; place-items: center;
    background: var(--bg-secondary); border: 1px solid var(--border-dark); border-radius: 3px;
    font-size: var(--fs-xl); line-height: 1;
    overflow: hidden;   /* 그림이 들어오면 칸을 넘지 않는다 */
}
/* 그림이 칸을 통째로 채운다 — 2026-09-03 부터 실제로 그림이 들어온다 (SCREEN_DESIGN §2 · app.js:skillImg) */
.ng-skill .ico img { width: 100%; height: 100%; object-fit: contain; image-rendering: var(--face-render); }
.ng-skill .txt { min-width: 0; line-height: 1.25; }
.ng-skill .tag { display: block; font-style: normal; font-size: var(--fs-xs); color: var(--text-accent); }
.ng-skill b { font-weight: normal; font-size: var(--fs-sm); word-break: keep-all; }

.ng-line {
    display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
    font-size: var(--fs-sm); color: var(--text-secondary); padding: 3px 0;
}
.ng-line b { font-weight: normal; color: var(--text-primary); }
.ng-line.sep { border-top: 1px solid var(--border-dark); margin-top: 9px; padding-top: 8px; }
.ng-card .attr-list { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--border-dark); }

.ng-actions {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    margin-top: 19px;
}
.ng-count { font-size: var(--fs-xs); margin-right: 4px; }
.btn.lg { padding: 10px 26px; font-size: var(--fs-md); }

/* ───────── 프롤로그 (2026-09-03 · SCREEN_DESIGN §3-1) ─────────
   시작 화면과 같은 pregame 셸을 쓴다. 읽는 화면이라 폭을 좁히고 줄 사이를 넓힌다.
   본문의 줄바꿈은 i18n 문자열이 들고 있고 pre-line 이 편다 — 화면이 <br> 을 심지 않는다 */

.pro-wrap {
    max-width: 660px; height: 100%; margin: 0 auto;
    padding: 16px 16px 10px;
    display: flex; flex-direction: column;
}
.pro-step { font-size: var(--fs-xs); letter-spacing: 2px; text-align: center; }
.pro-h {
    font-size: var(--fs-xl); font-weight: normal; letter-spacing: 4px;
    color: var(--text-accent); text-align: center;
    margin: 8px 0 16px;
}
/* 씬마다 길이가 5줄~23줄로 크게 달라 **본문 칸이 남는 높이를 먹고 스스로 넘친다** —
   그래야 버튼이 어느 씬에서도 화면 안에 선다. `safe center` 라 넘칠 때는 위에서부터 읽힌다 */
.pro-body {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
    display: grid; align-content: safe center;
    white-space: pre-line;
    font-size: var(--fs-md); line-height: 1.85;
    color: var(--text-secondary); text-align: center;
}
/* 바알이 처음 입을 여는 줄 — 본문과 층이 다르다 */
.pro-q {
    margin-top: 16px; text-align: center;
    font-size: var(--fs-lg); font-style: italic; color: var(--text-primary);
}
.pro-end {
    margin-top: 10px; padding-top: 10px; text-align: center;
    border-top: 1px solid var(--border-dark);
    font-size: var(--fs-sm); letter-spacing: 3px; color: var(--text-muted);
}
.pro-actions {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    margin-top: 20px;
}

/* ───────── 초반 루프 실동작 (2026-08-25) ───────── */

/* 한 줄 피드백 — 장착 실패·고용 결과 등. 다음 render() 에서 사라진다 */
.flash {
    font-size: var(--fs-sm); color: var(--color-warning);
    padding: 6px 10px; margin-bottom: 10px;
    border: 1px solid var(--warn-line); background: var(--warn-bg);
}

/* 시작 화면 — 이어하기 */
.ng-continue {
    max-width: 760px; margin: 0 auto 16px;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    border: 1px solid var(--border-secondary); background: rgba(var(--surface-0-rgb), var(--panel-alpha)); padding: 10px 14px;
}
.ng-continue .l { font-size: var(--fs-sm); color: var(--text-secondary); }
.ng-continue .l small { display: block; color: var(--text-muted); font-size: var(--fs-xs); }
.btn.danger { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger-fg); }
.btn.danger:hover { background: var(--danger-bg-hover); border-color: var(--color-error); }

/* 편성 — 누르는 줄 */
.party-slot.click { cursor: pointer; }
.party-slot.click:hover { border-color: var(--border-highlight); }
.party-slot .b-toggle { margin-left: auto; }

/* 반복 토글 */
.repeat-row {
    display: flex; align-items: center; gap: 10px; margin-top: 10px;
    padding-top: 10px; border-top: 1px solid var(--border-dark);
}
.repeat-row .sub { font-size: var(--fs-xs); color: var(--text-muted); }
.btn.toggle.on { background: var(--toggle-bg); border-color: var(--toggle-line); color: var(--toggle-fg); }

/* 부재중 정산 배너 */
/* 재접속 알림 — 반복 원정은 게임이 켜져 있는 동안만 (08-25). 꺼진 사이의 런은 마무리됐다는 배너 */
.notice-box {
    border: 1px solid var(--note-line); background: var(--note-bg); padding: 10px 12px; margin-bottom: 14px;
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.notice-box .t { font-size: var(--fs-xs); color: var(--color-info); letter-spacing: 1px; }
.notice-box .b { font-size: var(--fs-sm); flex: 1; }

/* 리포트 — 패배·철수 */
.report-head .verdict.lose { color: var(--color-error); }
.report-head .verdict.retreat { color: var(--color-warning); }
.report-head .verdict.running { color: var(--color-info); }
.report-actions { display: flex; gap: 8px; align-items: center; margin-top: 12px; }

/* 전투 결과 띠 — 아레나 위에 뜬다 */
.arena { position: relative; }
.battle-result {
    display: none; position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%);
    z-index: 3; align-items: center; gap: 12px;
    background: rgba(var(--surface-0-rgb), var(--panel-alpha-soft)); border: 1px solid var(--border-secondary); padding: 8px 14px;
}
.battle-result.show { display: flex; }
.battle-result .verdict { font-size: var(--fs-lg); letter-spacing: 1px; }
.pop.miss { color: var(--text-muted); }

/* 분해 모드 — 클릭이 파괴 행동이 되므로 칸 모양을 바꾼다 */
.inv-cells.salvage .inv-cell.filled { border-style: dashed; cursor: crosshair; }
.inv-cells.salvage .inv-cell.filled:hover { background: var(--danger-cell-hover); }
/* 강화 모드 — 클릭이 골드를 쓰므로 칸에 비용을 적는다 (SCREEN_DESIGN §6) */
.inv-cell { position: relative; }
.inv-up { position: absolute; top: 1px; right: 2px; font-size: var(--fs-xs); color: var(--color-warning); }
/* 재료 칸의 오른쪽 위 숫자는 **개수**다 — 강화 단계(+N)와 색을 갈라 둔다 (ADR-0055) */
.mat-cell { cursor: default; }
.mat-cell .inv-up { color: var(--text-primary); font-weight: 700; }
/* ───────── 창 레이어 (SCREEN_DESIGN §2 · §7) ─────────
   탭 위에 겹쳐 뜨는 판 하나. 툴팁(z-index 50)보다 아래에 둔다 — 창 안의 스킬 칸에도 툴팁이 떠야 한다.
   판은 자기 내용 폭을 쓰되 화면을 넘지 않는다(고정 px 금지 · ui/README 폭 정책). 세로가 모자라면 판 안에서만 스크롤한다 */
.modal-layer {
    position: fixed; inset: 0; z-index: 40;
    display: flex; align-items: center; justify-content: center; padding: 20px;
    background: rgba(var(--veil-rgb), .72);
}
/* ⚠ `display:flex` 는 브라우저 기본 `[hidden]{display:none}` 을 **이긴다** — 이 한 줄이 없으면 창이 닫혀 있어도
   어두운 판이 화면을 계속 덮는다. 재생기가 `hidden` 으로 여닫는 자리(.battle-log-wrap 등)와 같은 함정이다 */
.modal-layer[hidden] { display: none; }
.modal-box {
    display: flex; flex-direction: column; gap: 10px;
    max-width: 100%; max-height: 100%; overflow: auto;
    /* 14/16 → 12/14 [2026-09-09] — 스킬 창이 세로 예산 700 에서 몇 px 넘쳐 스크롤이 생겼다. 창 공통 규격이라
       로그 창도 함께 좁아지지만 그쪽은 `.bw-box` 가 크기를 못박아 두어 영향이 없다 */
    padding: 12px 14px 14px;
    background: var(--bg-secondary); border: 1px solid var(--border-highlight);
    box-shadow: 0 12px 40px -8px #000;
}
/* 창 머리 — 왼쪽 제목 / 오른쪽 닫기. 닫는 길 셋 중 **눈에 보이는** 하나다 */
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.modal-head h2 { margin: 0; }
/* 닫기 = **정사각 X** (2026-09-01 사용자 지시). 창이 여럿이 돼도 **모양도 자리도 같다** — 창마다 다르면
   닫는 법을 창마다 다시 배워야 한다. 글자가 아니라 글리프라 ko/en 에서 폭이 흔들리지 않는다(이름은 title 이 든다) */
.modal-x {
    flex: 0 0 auto; width: 28px; height: 28px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: var(--fs-lg); line-height: 1;
}

/* ───────── 파견 목록 (SCREEN_DESIGN §8) ─────────
   [개정 2026-09-04 사용자 지시] **세로 카드 3장** — 채광 · 채집 · 벌목. 미착수 카드도 그린다(어디까지 열리는지가 보여야 한다).
   **3열 격자는 새로 만들지 않았다** — 시작 화면·선술집이 쓰는 `.ng-row`(같은 무게 3열)를 렌더러가 그대로 쓴다.
   `.dp-cell` 은 칸에서 **카드**가 됐지만 규칙은 그대로다(세로 flex · 열린 카드 왼쪽 강조선) — 클래스 이름도 안 바꾼다.
   ⚠ `.dp-list` 는 이 개정으로 **참조가 0** 이 됐다 — 지우지 않고 남긴다(다른 곳에서 쓰는지 확인 전).
   라벨이 드는 칸이라 고정 px 을 주지 않는다 (ui/README 폭 정책) */
.dp-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
.dp-cell {
    display: flex; flex-direction: column; gap: 5px;
    padding: 9px 11px; cursor: pointer;
    background: var(--bg-card); border: 1px solid var(--border-primary); border-left: 3px solid var(--border-dark);
}
/* **이 탭에서 클릭을 받는 것은 단 하나뿐이다** [개정 2026-09-09 사용자 지시] — 그래서 단만 손가락 커서를
   들고, 단만 hover 에 반응한다(테두리까지 밝아진다). 안쪽 단계 상자는 아무 반응도 안 한다 */
.dp-cell:hover { background: var(--bg-tertiary); border-color: var(--border-secondary); }
/* 열려 있는 칸 — 아래에 그 파견처의 속이 붙어 있다는 표시 */
.dp-cell.on { border-left-color: var(--border-highlight); background: var(--bg-tertiary); }
.dp-cell.todo { opacity: .72; }
.dp-n { font-size: var(--fs-md); }
.dp-meta { display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); font-style: normal; }
/* 담당 능력치 — 미정이면 `—` 가 그대로 선다. 빈 칸은 "안 재고 있다"로 읽힌다 (§4-1) */
.dp-attr { color: var(--text-secondary); font-style: normal; }
/* 인원 — 파견처는 1인 배치, 탐험만 파티다. 기획의 「탐험은 파견처가 아니다」를 화면에서 드는 표시 (§8) */
.dp-size { color: var(--text-muted); font-style: normal; border: 1px solid var(--border-dark); padding: 0 4px; }
/* 배지는 이름 줄 안에 든다 [개정 2026-09-09] — 카드 바닥에 따로 서면 상자 7개와 세로를 다툰다 */
.dp-n .todo-badge { vertical-align: baseline; }

/* 자원 탭의 세로 단 — 단 3개가 박스 높이를 다 쓴다 [신설 2026-09-09 사용자 지시 · 박스 ADR-0097 · SCREEN_DESIGN §8].
   단계 7이 얇은 줄이던 시절엔 카드가 위쪽 1/3만 쓰고 남은 세로를 안내 패널이 먹었다.
   `1fr auto` — 단이 남는 세로를 갖고 안내는 제 높이만 쓴다. `.char-stack` 의 `auto 1fr auto` 와 반대 배분이라
   클래스를 따로 둔다(같은 이름에 두 배분을 넣으면 다른 탭이 같이 흔들린다) */
.res-stack { display: grid; grid-template-rows: minmax(0, 1fr) auto; gap: 14px; }
/* 모자라면 단이 줄고 단계 목록이 단 안에서 스크롤한다 (박스 · ADR-0097) */
.res-stack > .ng-row { grid-template-rows: minmax(0, 1fr); }

/* 단계 트랙 — 카드마다 같은 줄 수로 선다 [신설 2026-09-04]. 줄 수는 CSS 가 아니라 CSV 표가 정한다(mine_node.csv).
   **세 카드 모두 그린다** — 트랙을 지우면 「이 파견처는 단계가 없다」로 읽힌다 (§8).
   [개정 2026-09-09 사용자 지시] 줄이 **상자**가 됐다 — 트랙이 단의 남은 세로를 받고(`flex:1`)
   상자 7개가 그걸 **균등 분할**한다(`grid-auto-rows: 1fr`). 개수는 여전히 CSV 가 정한다 */
.dp-tiers { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; border-top: 1px solid var(--border-dark); padding-top: 6px; }
.dp-tier-h { font-size: var(--fs-xs); color: var(--text-muted); margin-bottom: 5px; }
.dp-tier-list { list-style: none; margin: 0; padding: 0; display: grid; grid-auto-rows: 1fr; gap: 5px; flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* 단계 상자 — **누를 것이 아니다** [개정 2026-09-09 사용자 지시]. 그래서 `.dp-cell` 의 선택 문법을 안 빌린다:
   왼쪽 강조선(= 열렸다)도, `--bg-tertiary`(= 골라졌다)도 안 쓴다. 대신 **파인 칸**(`--bg-input`)이라
   단 안의 내용으로 읽힌다 — 클릭을 받는 것은 단 하나뿐이다.
   ⚠ 곁들여 고친 것: 열린 단은 배경이 `--bg-tertiary` 라 상자가 같은 색이면 **테두리만 남고 사라졌다** */
.dp-tier {
    display: flex; align-items: center; gap: 9px; min-height: 0;
    padding: 5px 9px;
    background: var(--bg-input); border: 1px solid var(--border-dark);
}
/* 단계 번호 — 상자가 커진 만큼 배지도 읽히는 크기로 [개정 2026-09-09 사용자 지시] */
.dp-t-n {
    flex: 0 0 auto; min-width: 20px; text-align: center;
    font-size: var(--fs-xs); font-style: normal; color: var(--text-muted);
    border: 1px solid var(--border-dark); background: var(--bg-primary);
}
/* 상자 속 두 줄 — 이름과 산출물. 라벨이 드는 칸이라 고정 px 을 주지 않는다 (ui/README 폭 정책) */
.dp-t-body { display: flex; flex-direction: column; gap: 1px; flex: 1 1 auto; min-width: 0; }
/* 이름 — 상자의 알맹이라 본문 크기다(`--fs-md`). 영어가 길다(`Twisted Root Gallery`) — 넘치면 말줄임 */
.dp-t-name { font-size: var(--fs-md); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 산출물 — 이 단계가 무엇을 주는가. 값이 없으면 `—` 가 선다 (§4-1) */
.dp-t-ore { font-size: var(--fs-xs); color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 표가 아직 없는 파견처(채집 · 벌목) — 두 줄 다 `—` 만 선다. 상자는 지우지 않는다 (§4-1) */
.dp-tier.empty .dp-t-name { color: var(--text-muted); }

/* 미착수 탭 — 제목 옆 배지 하나로 「여긴 아직 없다」를 말한다 (SCREEN_DESIGN §1) */
.todo-badge { font-size: var(--fs-xs); color: var(--color-warning); border: 1px solid var(--color-warning); padding: 0 6px; margin-left: 6px; vertical-align: middle; }
.panel.todo .note-body { max-width: 70ch; }

/* 탐험 지도 — 탭 머리에 전폭으로 서는 **아트 한 장** [신설 2026-09-04 사용자 지시 · SCREEN_DESIGN §8-4]
   ⚠ **클릭을 안 받는다** — 노드·경로가 기획 백지라 손잡이가 없다. `cursor` 도 안 바꾼다(누를 수 있는 것처럼 보이면 안 된다)
   ⚠ **`image-rendering: pixelated` 를 안 건다** — 계승 배경 4장(`body::before` · `.arena.has-bg` · `.panel.town-bg`)과 달리
      이건 신규 카툰 아트라 픽셀아트가 아니다. 보간을 꺼 두면 축소할 때 선이 끊긴다 (§5 얼굴 스타일에서 겪은 것과 같은 함정)
   화면비는 자산 그대로다 — `cover` 가 잘라 내는 곳이 없다. **2752×1211 (2.27:1)** [개정 2026-09-04]:
   생성 원본은 1536 높이였고 **아래 띠(생성기 워터마크 자리)를 잘라 낸** 것이 이 값이다. 세로가 짧아지면서
   같은 날 등재했던 **세로 예산 예외가 해소됐다** — 하한 1280×700 에서 지도와 미착수 안내가 함께 선다 (src/ui/README.md) */
.ex-map {
    aspect-ratio: 2752 / 1211;
    background-size: cover;
    background-position: center;
    border: 1px solid var(--border-secondary);
    /* `.panel + .panel` 규칙이 안 걸리는 자리다(지도는 패널이 아니다) — 아래 미착수 패널과의 간격을 여기서 든다 */
    margin-bottom: 14px;
}
.items-tools { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
/* 옛 제목 줄이 들던 수치(칸 수 · 장착 대상)가 도구 줄 **오른쪽 끝**으로 옮겨 왔다 (2026-09-01) */
.items-meta { margin-left: auto; font-size: var(--fs-xs); }
.pd-cell.filled { cursor: pointer; }
.pd-cell.filled:hover { background: var(--surface-7); }

/* 선술집 후보 — 시작 화면(.ng-row)과 **완전히 같은 카드**다 [개정 2026-09-08 사용자 지시 · SCREEN_DESIGN §3 · §8-1].
   ~~크기만 줄인다~~(2026-09-03)를 걷고 09-01 의 「완전히 같은 카드」로 돌아왔다 — 영웅을 고르는 일은 두 화면이 같고,
   초상이 그 판단의 절반이라 명단에서도 크게 읽혀야 한다. 그래서 이 블록에는 **크기를 줄이는 값이 하나도 없다**.
   ⚠ 대가는 세로다 — 카드가 ~120px 자라 **하한 1280×700 에서는 의뢰 줄이 접히고 패널이 스크롤된다**(src/ui/README 세로 예산).
   1440×900 에서는 명단 · 도구 줄 · 의뢰 줄이 한 화면에 다 선다 */
/* `align-items: start` — 카드가 **제 높이만 쓴다** [2026-09-10 사용자 지시 · ADR-0077]. 늘어나면 수색 결과가
   왔을 때(결과 카드는 이야기 줄 + 만남 + 영웅 + 버튼 둘이라 후보보다 한참 길다) 후보 카드 안쪽이 **222px 빈다** —
   테두리는 아래까지 내려오는데 속이 없어 「덜 그려졌다」로 읽힌다. 늘어나야 하는 둘만 아래에서 되돌린다 */
.tv-cands { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin-bottom: 10px; align-items: start; }
/* 크기를 정하던 값들(초상 clamp · 카드 패딩 · 이름 글씨 · 고유 스킬 칸 · 능력치 줄간격 · 아래 두 줄)은
   **2026-09-08 에 전부 삭제됐다** — 카드가 `.ng-card` 규격을 그대로 탄다. 남는 것은 명단 격자와
   선술집에만 있는 조각들(고용 버튼 · 빈 칸 · 수색 칸)뿐이다 */
/* 고용한 칸 — 빈 채로 남는다. 카드 자리를 지켜야 명단이 「줄었다」가 아니라 「비었다」로 읽힌다.
   그래서 격자의 `align-items: start` 를 **여기서만 되돌린다** — 빈 칸이 글자 높이로 쪼그라들면 자리가 사라진다 */
.tv-cands .tv-empty {
    align-self: stretch;
    display: flex; align-items: center; justify-content: center; text-align: center;
    color: var(--text-muted); font-size: var(--fs-sm); border-style: dashed; background: none;
}
.tv-cands .b-hire { width: 100%; margin-top: 7px; }
/* 수색 칸 — 후보 카드와 **같은 크기**다 (2026-09-01 사용자 지시 · SCREEN_DESIGN §8-1 · 실동작 ADR-0062).
   격자가 늘 3열이라(후보 2 + 수색 1) 폭은 저절로 같고, 높이는 같은 행의 카드가 정한다.
   내용이 적어 버튼이 위로 붙지 않게 `margin-top:auto` 로 **아래에 앉힌다** — 카드의 고용 버튼과 같은 자리다.
   상태 셋이 이 한 칸에 선다: 대기(칩 격자) · 수색 중(이야기) · 완료(`.ng-card` 결과 카드에 이 클래스가 덧붙는다) */
.tv-search { align-self: stretch; display: flex; flex-direction: column; gap: 8px; }
.tv-search-h { font-size: var(--fs-lg); }
.tv-search-h .todo-badge { vertical-align: middle; }
.tv-search-spec { font-size: var(--fs-sm); }
.tv-search-who { font-size: var(--fs-md); font-weight: 600; }
.tv-search-odds { font-size: var(--fs-xs); }
.tv-search .b-search { width: 100%; margin-top: auto; }
/* 결과 카드는 명단 카드와 **같은 규격**이라 칸 본체의 flex+gap 을 안 받는다 —
   받으면 조각 사이마다 간격이 붙어 카드가 ~140px 자라고 같은 행의 후보 카드까지 밀려
   1440×900 에서도 의뢰 줄이 화면 밖으로 나간다 (2026-09-09 측정) */
.tv-search-res .b-take, .tv-search-res .b-drop { width: 100%; margin-top: 7px; }
/* 이야기 줄 — 막마다 하나씩 열린다 (ADR-0062). 목록 기호를 안 쓴다: 항목이 아니라 문장이라
   점을 찍으면 「설정값 목록」으로 읽힌다. 새 줄이 아래에 쌓이므로 **왼쪽 선**이 하나로 묶는다 */
.tv-story {
    display: flex; flex-direction: column; gap: 5px;
    border-left: 2px solid var(--border-secondary); padding-left: 8px;
    font-size: var(--fs-sm); color: var(--text-secondary);
}
.tv-story p { margin: 0; }
/* 완료 줄만 결과 카드 **위**에 선다 — 「무엇이 돌아왔나」보다 「어떻게 찾았나」가 먼저 읽혀야 이야기가 이어진다 */
.tv-story.done { border-left-color: var(--color-success); margin-bottom: 10px; }
.tv-story.done i { display: block; color: var(--color-success); font-style: normal; font-size: var(--fs-xs); }
/* 소문 — 만날 사람의 죄종을 **보내기 전에** 말한다 (ADR-0068). 죄종 칩을 그대로 쓴다:
   화제를 숨기지 않는 것이 이 기능의 전제라 별도 표기를 발명하지 않는다 */
.tv-rumor {
    display: flex; align-items: baseline; gap: 6px;
    padding: 6px 8px; background: var(--bg-input);
    border-left: 2px solid var(--border-highlight);
    font-size: var(--fs-sm); color: var(--text-secondary);
}
.tv-rumor .sin-chip { flex: 0 0 auto; }
/* 만남 — 질문 하나 + 답 몇 개. 이야기 줄(.tv-story)과 **다른 테두리**를 준다:
   이야기는 읽는 것이고 만남은 **누르는 것**이라 같은 문법으로 서면 클릭할 수 있다는 게 안 읽힌다 */
.tv-meet { display: flex; flex-direction: column; gap: 5px; padding: 8px; background: var(--bg-input); border: 1px solid var(--border-highlight); }
.tv-meet.done { border-color: var(--border-primary); }
.tv-meet-h { font-size: var(--fs-xs); color: var(--text-muted); }
.tv-meet-h .sin-chip { margin-left: 4px; }
.tv-meet-q { font-size: var(--fs-sm); color: var(--text-primary); }
.tv-ans {
    display: block; width: 100%; text-align: left; padding: 5px 7px;
    background: var(--bg-card); border: 1px solid var(--border-primary);
    color: var(--text-secondary); font-size: var(--fs-xs); cursor: pointer;
}
.tv-ans:hover { border-color: var(--border-highlight); color: var(--text-primary); }
/* 보낸 영웅이 연 답 — **왜 열렸는지를 그 줄이 든다.** 열렸다는 사실만으로는 인과가 안 읽힌다 */
.tv-ans.key { border-color: var(--color-warning); }
.tv-ans .why { display: block; font-style: normal; font-size: var(--fs-xs); color: var(--color-warning); margin-bottom: 2px; }
.tv-ans.picked { cursor: default; border-color: var(--border-secondary); color: var(--text-primary); }
.tv-meet-cut { font-size: var(--fs-xs); }
.tv-meet-cut.up { color: var(--color-success); }

/* 보낼 영웅 칩 — **고르는 자리에 결정 입력(매력 · 죄종)이 함께 선다** (SCREEN_DESIGN §8-1).
   2열이라 로스터 상한(7)에서 파티를 뺀 인원이 네 줄 안에 들어온다. 고정 px 을 안 쓴다(폭 정책) */
.tv-pick { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
.tv-chip {
    display: flex; align-items: center; gap: 6px; min-width: 0; text-align: left;
    padding: 4px 5px; background: var(--bg-card);
    border: 1px solid var(--border-primary); border-top: 2px solid var(--border-secondary);
    color: var(--text-primary); cursor: pointer;
}
.tv-chip:hover { border-color: var(--border-highlight); }
.tv-chip.on { border-color: var(--border-highlight); background: var(--bg-tertiary); }
.tv-chip .hero-face { width: 26px; height: 26px; flex: 0 0 auto; }
.tv-chip-b { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.tv-chip .n { font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tv-chip .m { display: flex; align-items: center; gap: 4px; font-size: var(--fs-xs); }
.tv-chip .cha { font-style: normal; color: var(--text-accent); }
.tv-tools { display: flex; align-items: center; gap: 10px; }
/* 의뢰 게시판 섹션 (2026-09-03 사용자 지시 · SCREEN_DESIGN §8-1) — 선술집 맨 아래, 도구 줄 다음.
   같은 날 아침 삭제된 도박장 줄의 자리다. 명단 격자 밖이라 후보 카드와 안 섞인다
   (같은 격자에 세우면 「후보」로 읽힌다). 카드 규격 자체는 .cm-board / .cm-card 가 그대로 든다 */
.tv-cm { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border-primary); }
.tv-cm-h { font-size: var(--fs-md); margin-bottom: 7px; }

/* 네비 맨 아래 — 시작 화면으로 (새 게임 / 이어하기) */
.nav .b-newgame { margin-top: auto; color: var(--text-muted); font-size: var(--fs-sm); border-top: 1px solid var(--border-dark); }

/* 편성 줄 — 이름 줄 / 죄종·출정 아웃 줄 */
.party-slot .ps-main { flex: 1; min-width: 0; }
.party-slot .ps-name { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.party-slot .ps-leader { font-size: var(--fs-xs); margin-left: auto; }
.party-slot .ps-sub { display: flex; align-items: center; gap: 6px; margin-top: 4px; flex-wrap: wrap; }
.party-slot .ps-sub .injury-chip { margin-top: 0; white-space: nowrap; }
.party-slot .b-toggle { flex: 0 0 auto; }

/* ───────── 도움말 탭 (2026-08-26) ─────────
   인게임 패널에서 걷어낸 설명 문장이 전부 모이는 한 페이지. 읽기 폭과 제목 간격만 잡는다 — 장식 없음.
   본문 글자는 기존 `.note-body` 규격을 그대로 쓴다 */
.help { max-width: 860px; }
.help > h1 { font-size: var(--fs-xl); color: var(--text-primary); font-weight: normal; }
.help > .segmented { margin: 12px 0 4px; }
/* 본문(`.help-body`)은 박스 안에서 스크롤한다 — 제목 · 점프 세그먼트는 서 있다 (ADR-0097).
   여기 h2 는 패널 제목이 아니라 문서 섹션 제목이다 — 모양만 준다 */
.help-body > h2 {
    display: block; letter-spacing: 0;
    font-size: var(--fs-lg); color: var(--text-primary); font-weight: normal;
    margin: 26px 0 0; padding-bottom: 6px; border-bottom: 1px solid var(--border-dark);
    scroll-margin-top: 10px;
}
.help-body > h3 {
    font-size: var(--fs-sm); color: var(--text-secondary); font-weight: normal;
    margin: 15px 0 0;
}
.help-body > h3 small { color: var(--text-muted); font-size: var(--fs-xs); margin-left: 7px; }
.help-body > .note-body { margin-top: 5px; }
.help-body > .note-body + .note-body { margin-top: 7px; }

/* ───────── 연구 탭 — 파티 전술 (2026-08-30 · SCREEN_DESIGN §13) ─────────
   칸 수는 `tactic_slot.csv` 행 수다 — 격자는 행 수에 맞춰 접히고 잠긴 칸도 자리를 지킨다.
   칸 폭은 고정 px 이 아니라 `minmax()` — 영어 조건 문장이 한국어보다 길다 (src/ui/README 폭 정책) */
.rs-head {
    display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap;
    font-size: var(--fs-sm); color: var(--text-secondary);
    padding-bottom: 9px; margin-bottom: 11px; border-bottom: 1px solid var(--border-dark);
}
.rs-head b { color: var(--text-primary); font-size: var(--fs-md); }

.rs-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; }

.rs-cell {
    display: flex; flex-direction: column; gap: 5px; min-width: 0;
    padding: 9px 10px 10px;
    background: var(--bg-tertiary); border: 1px solid var(--border-primary);
}
/* 켜짐/꺼짐이 칸의 첫인상 — 켜진 칸만 테두리가 산다 (죄종 색은 쓰지 않는다, 전술은 파티 것이다) */
.rs-cell.on { background: var(--surface-1); border-color: var(--border-highlight); }
.rs-cell.off { opacity: .82; }
.rs-cell.locked {
    opacity: .6; background: rgba(var(--tint-rgb), .015);
    border-style: dashed; justify-content: flex-start;
}

.rs-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.rs-no { font-size: var(--fs-xs); color: var(--text-muted); }
.rs-state { font-size: var(--fs-xs); color: var(--text-muted); margin-left: auto; }
/* 전술 옵션 등급 — 색은 아이템 희귀도에서 빌리되 축은 별개다 (SCREEN_DESIGN §13-2 · tactic_card_design §5-5) */
.rs-grade {
    font-size: var(--fs-xs); padding: 0 5px; border-radius: 3px;
    border: 1px solid currentColor; color: var(--text-muted);
}
.rs-grade.magic { color: var(--rarity-magic); }
.rs-grade.rare { color: var(--rarity-rare); }
.rs-cell.on .rs-state { color: var(--color-success); }

.rs-cond {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    font-size: var(--fs-sm); color: var(--text-secondary); word-break: keep-all;
}
/* 조건 카운터 「지금 / 필요」 — 안 보이면 조건이 함정이 된다 (tactic_card_design §4) */
.rs-cnt { flex: none; font-size: var(--fs-xs); color: var(--text-muted); }
.rs-cell.on .rs-cnt { color: var(--color-info); }
.rs-eff { font-size: var(--fs-sm); color: var(--color-info); }
.rs-lock { font-size: var(--fs-sm); color: var(--color-warning); margin-top: 4px; }
.rs-roll { align-self: flex-start; margin-top: 3px; }

/* ───────── 제련소 (SCREEN_DESIGN §8-2) ─────────
   배치 줄 + 세그먼트 2 + 「목록 | 작업 패널」 2단. 2단 격자는 §4-1 편성 패널과 같은 문법이고
   좁아지면 세로로 접힌다 — 라벨 칸에 고정 px 을 주지 않는다 (src/ui/README.md 폭 정책) */
.fg-assign { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 8px 10px; background: var(--bg-tertiary); border: 1px solid var(--border-primary); border-radius: 3px; }
.fg-assign .fg-who { display: flex; flex-direction: column; gap: 1px; }
.fg-assign .fg-who b { font-weight: 500; }
.fg-assign .fg-who small { color: var(--text-muted); font-size: var(--fs-2xs); letter-spacing: .06em; }
.fg-stat { font-size: var(--fs-xs); color: var(--text-secondary);
    border: 1px solid var(--border-primary); padding: 2px 8px; border-radius: 2px; }
.fg-stat b { color: var(--color-success); }
.fg-assign .fg-sp { flex: 1; }

.fg-work { display: grid; grid-template-columns: minmax(200px, 1fr) minmax(240px, 1.15fr); gap: 8px; }
.fg-col { border: 1px solid var(--border-dark); background: var(--bg-input); border-radius: 3px; padding: 8px; min-width: 0; }
.fg-list { display: flex; flex-direction: column; gap: 3px; max-height: 320px; overflow-y: auto; }
.fg-row { display: grid; grid-template-columns: 22px 1fr auto; gap: 8px; align-items: center;
    border: 1px solid var(--border-dark); background: var(--bg-card); padding: 5px 7px; border-radius: 2px; cursor: pointer; }
.fg-row:hover { border-color: var(--border-secondary); }
.fg-row.on { border-color: var(--border-highlight); background: var(--bg-tertiary); }
.fg-row .fg-ic { text-align: center; }
.fg-row .fg-n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs); }
.fg-row .fg-sub { display: block; color: var(--text-muted); font-size: var(--fs-2xs);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fg-row .fg-up { font-size: var(--fs-2xs); color: var(--text-secondary); }

.fg-head { display: flex; gap: 8px; align-items: flex-start;
    padding-bottom: 7px; margin-bottom: 8px; border-bottom: 1px solid var(--border-dark); }
.fg-head .fg-title { font-size: var(--fs-md); }
.fg-head .fg-meta { color: var(--text-muted); font-size: var(--fs-2xs); }
.fg-block { border: 1px solid var(--border-dark); background: var(--bg-card); border-radius: 2px; padding: 8px 9px; }
.fg-block + .fg-block { margin-top: 7px; }
.fg-block > h3 { font-size: var(--fs-2xs); letter-spacing: .1em; color: var(--text-muted); margin-bottom: 6px; }
.fg-pips { display: flex; gap: 2px; margin-bottom: 7px; }
.fg-pip { flex: 1; height: 4px; background: var(--bg-input); border: 1px solid var(--border-dark); }
.fg-pip.on { background: var(--color-success); border-color: var(--color-success); }
.fg-val { display: flex; gap: 6px; align-items: baseline; font-size: var(--fs-sm); margin-bottom: 7px; }
.fg-val span { color: var(--text-secondary); font-size: var(--fs-xs); }
.fg-opts { display: flex; flex-direction: column; gap: 2px; margin-bottom: 7px; font-size: var(--fs-xs); }
.fg-act { display: flex; align-items: center; gap: 8px; }
.fg-act .fg-cost { margin-left: auto; font-size: var(--fs-xs); color: var(--text-secondary); }
.fg-act .fg-cost.no { color: var(--color-error); }
.fg-pick { color: var(--text-muted); padding: 24px 8px; text-align: center; font-size: var(--fs-xs); }

/* ───────── 상단 (SCREEN_DESIGN §8-3) — 세로 2단, 둘 다 짧아 한 화면에 든다 ───────── */
.td-sec + .td-sec { margin-top: 12px; }
.td-h { font-size: var(--fs-2xs); letter-spacing: .12em; color: var(--text-muted); margin-bottom: 6px; }
.td-list { display: flex; flex-direction: column; gap: 3px; }
.td-row { display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: center;
    border: 1px solid var(--border-dark); background: var(--bg-input); padding: 6px 9px; border-radius: 2px; }
.td-row .td-n { font-size: var(--fs-xs); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.td-row .td-n small { color: var(--text-muted); font-size: var(--fs-2xs); margin-left: 7px; }
.td-row .td-gold { font-size: var(--fs-xs); color: var(--color-warning); white-space: nowrap; }
.td-row .td-gold.no { color: var(--color-error); }
/* 의뢰 게시판 (SCREEN_DESIGN §14) — **가로 한 줄.** 좁아져도 격자로 접지 않고 가로 스크롤로 받는다:
   「7장이 쭉」이 이 화면의 형태라 접는 순간 형태가 사라진다. 그래서 `flex-wrap: nowrap` + `flex: 0 0`.
   카드 폭은 라벨이 드는 칸이므로 고정 px 이 아니라 clamp — 영어가 길어져도 안 깨진다 (ui/README 폭 정책) */
.cm-board {
    display: flex; flex-wrap: nowrap; gap: 6px;
}
.cm-card {
    /* 일곱이 **줄을 나눠 갖는다** — 폭을 고정하면 하한 폭(1280)에서 마지막 장이 스크롤 뒤로 밀려
       「7개가 쭉」이 깨진다. `1 1 0` + `min-width: 0` 이라 일곱이 언제나 한 줄에 선다 */
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; gap: 5px;
    padding: 9px 9px;
    background: var(--bg-card); border: 1px solid var(--border-dark);
    /* 종류는 카드의 첫인상이다 — 왼쪽 굵은 변이 둘을 가른다 (§14) */
    border-left: 3px solid var(--border-dark);
}
/* 유형 둘 — 무엇이 목표를 채우는가 (2026-09-07 목표형 개정 · ~~약탈·보호(k-raid·k-escort)~~ 는 탐험으로 이관돼 규칙째 삭제) */
.cm-card.k-kill { border-left-color: var(--color-success); }
.cm-card.k-collect { border-left-color: var(--border-highlight); }
.cm-kind { font-size: var(--fs-sm); }
/* 배지만으로는 넷의 시간축 차이가 안 읽힌다 — 「어떻게 도는가」가 한 줄로 든다 (§14) */
.cm-how { font-size: var(--fs-2xs); color: var(--text-muted); word-break: keep-all; }
.cm-goal { font-size: var(--fs-xs); line-height: 1.35; word-break: keep-all; margin-top: 2px; }
.cm-rew {
    display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
    margin-top: auto; padding-top: 6px; border-top: 1px solid var(--border-dark);
    font-size: var(--fs-2xs);
}
.cm-gold { color: var(--color-warning); }
.cm-fame { color: var(--text-muted); }
.cm-go { align-self: stretch; }

/* 방문 상태 줄 — 아무도 없어도 자리를 지킨다. 재촉 연출(깜빡임·빨강)을 붙이지 않는다 */
.td-state { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
    border: 1px solid var(--border-dark); background: var(--bg-secondary);
    padding: 7px 9px; border-radius: 2px; margin-bottom: 6px; font-size: var(--fs-xs); }
.td-state.on { border-color: var(--border-secondary); }
.td-state b { font-weight: 500; }
.td-state span { color: var(--text-muted); font-size: var(--fs-2xs); }
.td-note { margin-top: 10px; font-size: var(--fs-2xs); }

/* ⚠ 제련소 시안 2026-09-03 — 세그먼트 대신 좌우 두 박스 (SCREEN_DESIGN §8-2 개정 검토 중) */
.fg-split { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; align-items: start; }
/* 박스 안에서는 두 칸이 박스 끝까지 선다 (ADR-0097) — 넘치면 두 칸 영역이 스크롤한다 */
.fg-split.box-body { align-items: stretch; }
.fg-box { border: 1px solid var(--border-primary); background: var(--bg-secondary);
    border-radius: 3px; padding: 10px; min-width: 0; }
.fg-boxh { font-size: var(--fs-sm); font-weight: 500; margin-bottom: 8px;
    padding-bottom: 6px; border-bottom: 1px solid var(--border-dark); }
/* 박스 안에서는 「목록 | 작업 패널」이 세로로 접힌다 — 폭이 절반이라 2단을 못 든다 */
.fg-box .fg-work { grid-template-columns: 1fr; background: transparent; gap: 8px; min-height: 0; }
.fg-box .fg-col { background: var(--bg-card); border: 1px solid var(--border-dark); border-radius: 2px; }
.fg-box .fg-list { max-height: 168px; }
