:root {
  --bg: #f2f4f8;
  --fg: #2b3342;
  --muted: #78849a;
  --line: #ccd4e0;
  --card-bg: #ffffff;
  --sheet-bg: #ffffff;
  --btn-bg: #4f5d76;
  --btn-fg: #f2f5f9;
  --ally: #3f6ea8;
  --hero: #b4802c;
  --enemy: #9c4a44;
  --hp: #5f9c56;
  --hp-low: #c1503f;
  --mp: #4d74b8;
  --heal: #4f9a63;
  --harm: #c1503f;
  --zone-heal: #4f9a63;
  --zone-harm: #c1503f;
  --sel: #d9e4f2;
  /* 아이템 등급 색. 밝은 테마에서는 흰색이 배경에 묻히므로 일반만 글자색을
     그대로 쓴다 — 여섯을 다 물들이면 "색이 없는 것"이라는 등급이 사라진다. */
  --tier-common: #5b6577;
  --tier-uncommon: #2f8a4c;
  --tier-rare: #2f6fd0;
  --tier-epic: #8a4fd0;
  --tier-legend: #b8860b;
  --tier-myth: #c23b30;
  /* 스킬이 무엇을 하는가. 아이콘이 "어떤 스킬인가"를 알리고 이 색이 "무엇을
     하는가"를 알린다 — 둘 중 하나만으로는 서른 몇 개를 훑을 수 없다. */
  --kind-harm: #b4453c;
  --kind-bane: #8a4fd0;
  --kind-mend: #2f8a4c;
  --kind-pull: #b8860b;
  --kind-mana: #2f6fd0;
  --kind-stun: #8a6a2f;
  --kind-boon: #1f8f8f;
  --kind-wilt: #9c4f7a;
  /* 혼란. 약화(자홍)와 갈라야 해서 주황 쪽으로 뺐다 — 둘 다 적에게 거는 것이라
     색이 가까우면 무엇이 걸린 것인지 화면에서 구별되지 않는다. */
  --kind-daze: #c2611f;
  /* 계열. 역할 색만으로는 궁수와 마법사가 같은 줄로 보인다. */
  --spec-tank: #4a72b8;
  --spec-warrior: #b4453c;
  --spec-rogue: #5b6577;
  --spec-archer: #2f8a4c;
  --spec-mage: #8a4fd0;
  --spec-priest: #2f8a8a;
  --spec-shaman: #9a5fb8;
  --spec-bard: #c07a2f;
  --spec-paladin: #b8912f;
  --spec-grunt: #7a8a4a;
  --spec-chieftain: #a83b2c;
  /* 상위 계열. 아래 계열과 **같은 계통이되 한 단 진하다** — 다른 색을 주면 같은
     동료가 레벨 하나에 전혀 다른 사람으로 보인다. */
  --spec-bulwark: #2f4f8c;
  --spec-berserker: #8c2f26;
  --spec-assassin: #3b4353;
  --spec-marksman: #1e6635;
  --spec-archmage: #6a2fae;
  /* 전투 화면이 가로로 길어 다른 게임(440px)보다 넓게 잡았다. 좁히면 아군과 적
     사이가 붙어 버려 거리와 장판 반경이 눈에 들어오지 않는다. */
  --app-max: 860px;
  --pad-x: clamp(10px, 3vmin, 24px);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #161a21;
    --fg: #dee4ee;
    --muted: #8792a5;
    --line: #313a48;
    --card-bg: #1f252f;
    --sheet-bg: #1f252f;
    --btn-bg: #47536a;
    --ally: #6f9ad4;
    --hero: #d8a84a;
    --enemy: #cf7168;
    --hp: #6aa860;
    --hp-low: #d8654f;
    --mp: #6b93d8;
    --heal: #6fb883;
    --harm: #dd7a68;
    --sel: #35435a;
    /* 어두운 바탕에서는 같은 색이 가라앉는다. 등급 색만 한 단계씩 올린다. */
    --tier-common: #b9c2d2;
    --tier-uncommon: #5fc47f;
    --tier-rare: #6b9ee8;
    --tier-epic: #b587ea;
    --tier-legend: #e8c352;
    --tier-myth: #ec7367;
    --kind-harm: #e08a80;
    --kind-bane: #b587ea;
    --kind-mend: #5fc47f;
    --kind-pull: #e8c352;
    --kind-mana: #6b9ee8;
    --kind-stun: #d8b45f;
    --kind-boon: #5fd0d0;
    --kind-wilt: #e08ab4;
    --kind-daze: #f0925a;
    --spec-tank: #7fa6e8;
    --spec-warrior: #e08a80;
    --spec-rogue: #a9b3c4;
    --spec-archer: #5fc47f;
    --spec-mage: #b587ea;
    --spec-priest: #5fc4c4;
    --spec-shaman: #c79ae0;
    --spec-bard: #e8a95f;
    --spec-paladin: #e0c46a;
    --spec-grunt: #b3c47a;
    --spec-chieftain: #e2705c;
    --spec-bulwark: #9dbdf2;
    --spec-berserker: #e8867c;
    --spec-assassin: #a3adbf;
    --spec-marksman: #7fd39a;
    --spec-archmage: #c49af0;
  }
}

* { box-sizing: border-box; }
html, body { margin: 0; min-height: 100%; }

/* hidden 속성의 기본값은 display:none인데, 아래에서 화면과 패널에 display:flex를
   주는 순간 그 기본값이 덮인다. 숨긴 화면이 그대로 보이므로 다시 못 박아 둔다. */
[hidden] { display: none !important; }

body {
  background: var(--bg);
  color: var(--fg);
  font-family: "Pretendard", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  display: flex;
  justify-content: center;
  padding: clamp(10px, 3vmin, 24px) var(--pad-x);
  -webkit-user-select: none;
  user-select: none;
}

.app {
  width: min(100%, var(--app-max));
  display: flex;
  flex-direction: column;
  gap: clamp(8px, 2vmin, 14px);
  /* 하단 탭 바가 마지막 카드를 가리지 않게 그만큼 비워 둔다. */
  padding-bottom: calc(64px + env(safe-area-inset-bottom));
}

/* 다섯 게임이 같은 헤더 배치를 쓴다. 목록으로 돌아가는 길을 게임마다 다시
   찾지 않게 하려는 것이라, 이 게임도 왼쪽 위·가운데·오른쪽 위를 그대로 맞춘다. */
.title-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
}

.title-row h1 { text-align: center; }
.title-row .head-nav { justify-self: start; }
.head-nav { display: flex; align-items: center; gap: 14px; }
.title-row .head-actions { justify-self: end; }

h1 {
  margin: 0;
  font-size: clamp(24px, 6vmin, 34px);
  font-weight: 800;
  letter-spacing: -0.02em;
}

h2 { margin: 0; font-size: 16px; font-weight: 700; }

.head-actions { display: flex; align-items: baseline; gap: 14px; }

.toggle {
  border: 0; background: none; padding: 0;
  color: inherit; font-family: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer; opacity: 0.6;
}
.toggle:hover { opacity: 1; }
.toggle[aria-pressed="false"] { opacity: 0.28; text-decoration: line-through; }

.back {
  color: inherit; opacity: 0.6; text-decoration: none;
  font-size: 14px; font-weight: 600;
}
.back:hover { opacity: 1; }

.sub-row {
  display: flex; align-items: baseline; gap: 10px;
  font-size: 14px;
}
.step-back {
  border: 0; background: none; padding: 0;
  color: inherit; font-family: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer; opacity: 0.6;
}
.step-back:hover { opacity: 1; }
.step { font-weight: 700; }
.step-note { color: var(--muted); }

.screen { display: flex; flex-direction: column; gap: clamp(8px, 2vmin, 14px); }

/* --- 퀘스트 목록 --- */
.quests { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }

.quest {
  width: 100%; text-align: left;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--card-bg); color: inherit;
  font-family: inherit; cursor: pointer;
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 8px;
}
.quest:hover { border-color: var(--btn-bg); }
.quest-title { display: flex; align-items: baseline; gap: 8px; }
.quest-title b { font-size: 17px; }
.quest-title .tier { color: var(--muted); font-size: 13px; }
.quest-desc { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.5; }
.quest-meta { display: flex; flex-wrap: wrap; gap: 6px; font-size: 12px; }

.tag {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 2px 9px; color: var(--muted);
}
.tag.gold { color: var(--hero); border-color: currentColor; }
.tag.place { color: var(--fg); border-color: var(--btn-bg); font-weight: 600; }

/* --- 편성 --- */
.panel {
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--card-bg);
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 8px;
}
.panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
#char-job { margin-right: auto; }
.count { color: var(--muted); font-size: 13px; font-weight: 600; }
.panel-note { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.5; }
/* 방금 무슨 일이 있었는지 알리는 줄. 설명문과 같은 자리에 서므로 색으로 가른다 —
   전투 화면의 로그는 다른 화면에서 보이지 않는다. */
.panel-note.said { color: var(--hero); font-weight: 600; }

.skill-picks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }

/* **동료 목록은 격자다.** 한 줄에 스킬과 장비까지 늘어놓던 때에는 한 명이 네 줄
   높이라 여섯이 화면을 다 먹었다. 이름과 직업만 남기면 한 명이 한 칸이고, 그만큼
   더 많은 동료를 한 화면에서 훑는다. */
.roster {
  list-style: none; margin: 0; padding: 0;
  /* **한 줄에 둘씩 고정이다.** auto-fill로 두었더니 폭이 좁은 기기에서 한 칸으로
     접혀, 격자로 바꾼 뜻이 그 화면에서만 사라졌다. */
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;
}
/* 화면이 넓으면 더 담는다. 둘로 고정해 두면 넓은 창에서 카드가 지나치게 길어진다. */
@media (min-width: 620px) {
  .roster { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* 주인공 줄은 고를 수 있는 것이 아니므로 한 줄을 통째로 쓴다. */
.roster > li.wide { grid-column: 1 / -1; }
/* 묶음 이름표. 카드가 아니라 줄 사이의 안내라 배경 없이 글자만 둔다 — 카드처럼
   그리면 누를 수 있는 것으로 보인다. */
.roster > li.group {
  display: flex; align-items: baseline; gap: 8px;
  padding: 4px 2px 0; font-size: 13px; font-weight: 700;
}
.roster > li.group .group-note { font-size: 12px; font-weight: 400; color: var(--muted); }

.pick.card { padding: 0; gap: 0; overflow: hidden; }
.pick-open {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 8px;
  padding: 8px; border: 0; background: none; color: inherit; font: inherit;
  text-align: left; cursor: pointer;
}
.pick-open[aria-pressed="true"] { background: var(--sel); }
/* 좁은 칸이라 이름이 두 줄로 감기면 카드 높이가 들쭉날쭉해진다.
   **어절 안에서 자르지 않는다**(`keep-all`) — 기본값으로 두었더니 "별을 읽는
   오릭"이 "별을 읽는 오 / 릭"으로 갈렸다. 띄어쓰기가 없는 긴 이름만 마지막
   수단으로 아무 데서나 자르고, 두 줄을 넘지 않게 잘라 낸다 — 세 줄이 되면 그
   카드만 키가 자라 격자가 어긋난다. */
.pick.card .pick-name {
  font-size: 14px; line-height: 1.25;
  word-break: keep-all; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.pick.card .pick-sub { font-size: 11px; }
.pick.card .avatar { width: 24px; height: 31px; }
/* 그림과 레벨을 한 칸에 세로로 쌓는다. 레벨이 글자 줄에서 빠져야 직업·계열이
   한 줄에 들어간다. */
.pick-face { display: flex; flex-direction: column; align-items: center; gap: 1px; flex: none; }
.pick-face .lv { font-size: 10px; font-weight: 700; color: var(--muted); }
.pick-face .power { font-size: 10px; font-weight: 800; color: var(--hero); }
/* 장비 줄의 전투력 증감. 오르내림을 색으로 갈라 두어야 옵션 줄을 읽기 전에
   결론이 먼저 보인다. */
.pick-sub.power-diff { font-weight: 800; }
.pick-sub.power-diff.up { color: var(--heal); }
.pick-sub.power-diff.down { color: var(--harm); }
/* 직업·계열은 한 줄로 둔다. 감기면 카드 높이가 서로 달라진다. */
.pick.card .job { display: block; font-size: 10.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 좁은 기기에서는 그림과 표 단추를 줄여 글자 줄에 자리를 준다 — "딜러·음유시인"이
   들어가지 못하면 그 동료만 계열이 잘려 나간다.
   **문턱이 389px일 때에는 아이폰(390~430px)이 여기에 걸리지 않았다.** 그 폭에서
   카드 본문이 110px뿐이라 "대마법사"가 "대마…"로 잘리고 이름이 두 줄로 감겼다 —
   재 보니 계열이 12px, 보수 줄이 1px 넘쳤다. 문턱을 올려 그 기기들도 여기를
   타게 한다. */
@media (max-width: 430px) {
  .pick.card .job { font-size: 9.5px; }
  .pick.card .avatar { width: 20px; height: 26px; }
  .pick-face .lv { font-size: 9px; }
  .pick-face .power { font-size: 9px; }
  .pick-take { width: 28px; }
  .pick-open { padding: 7px 6px; }
  /* **데려가기 단추를 아래로 내린다.** 오른쪽에 세워 두면 그 폭(28px)이 그대로
     글자 자리에서 빠져, 이름이 두 줄로 감기고 계열이 잘린다 — 재 보니 본문이
     84px에서 118px로 넓어져 웬만한 이름은 한 줄에 들어간다. 손가락으로 누르기도
     아래쪽 넓은 띠가 낫다. */
  .pick.card { flex-direction: column; align-items: stretch; }
  /* 아래 기본 규칙보다 뒤에 오지 않으므로 마디를 하나 더 얹어 이긴다 —
     같은 무게면 파일에서 나중에 적힌 쪽이 이기는데, 여기가 앞이다. */
  .pick.card .pick-take {
    width: auto; align-self: stretch; min-height: 26px;
    border-left: 0; border-top: 1px solid var(--line);
  }
  /* 아랫줄도 함께 줄인다. 신뢰도 값표가 네 자리(+100)고 보수도 네 자리라, 줄이지
     않으면 카드가 잘라 낸다 — 잘린 숫자는 틀린 숫자로 읽힌다. */
  .pick.card .trust-tag { font-size: 10px; padding: 0 3px; }
  .pick-deal { gap: 4px; }
  .pick-deal .wage { font-size: 11px; }
  .pick-deal .ico-box svg { width: 11px; height: 11px; }
  .pick.card .feel-tag { font-size: 9.5px; padding: 0 3px; }
  .pick-tags { gap: 3px; }
}
/* 아주 좁은 기기(320px 언저리)에서는 이름을 세 줄까지 연다. 두 줄로 자르면
   "별을 읽는…"처럼 이름이 통째로 사라지는데, **이름은 곧 그 동료의 신원이라
   계열보다 먼저 지킨다.** 글자도 한 단 줄인다 — 여기서는 일곱 자짜리 이름이
   7px 모자라 두 줄로 감기고, 그 줄만 카드가 17px 높아진다.
   **칸 수는 줄이지 않는다**: 한 줄에 하나로 접으면 격자로 바꾼 뜻이 그 화면에서만
   사라진다. */
@media (max-width: 340px) {
  .pick.card .pick-name { font-size: 12.5px; -webkit-line-clamp: 3; }
}

/* **모자라면 자르지 말고 접는다.** 두 줄은 보기에 성기지만 잘린 숫자·이름보다
   낫다 — 320px 언저리 기기에서는 아무리 줄여도 한 줄에 들어가지 않는다. */
.pick-deal, .pick-tags { flex-wrap: wrap; }
/* 데려가기. 표만 있는 단추라 눌린 상태가 색으로 보여야 한다. */
.pick-take {
  flex: none; width: 34px; align-self: stretch;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-left: 1px solid var(--line);
  background: none; color: var(--muted); cursor: pointer;
}
.pick-take[aria-pressed="false"] { opacity: 0.35; }
.pick-take[aria-pressed="true"] { background: var(--btn-bg); color: var(--btn-fg); opacity: 1; }
.pick-take:disabled { opacity: 0.35; cursor: default; }
.pick-take svg { width: 18px; height: 18px; }

/* 상세의 머리줄은 고를 수 있는 것이 아니라 읽는 것이다. 목록의 잠긴 줄(.locked)을
   그대로 쓰면 흐려져서 정작 상세가 안 읽힌다. */
.sheet-head { cursor: default; }
#member-head { margin-bottom: 10px; }
#member-chips { display: flex; flex-wrap: wrap; gap: 6px; }
/* 칩은 눌러서 설명을 여는 단추다. 손가락으로는 title이 보이지 않는다. */
#member-chips .chip { cursor: pointer; font: inherit; }
#member-chips .chip[aria-pressed="true"] { background: var(--sel); }

.chip-detail {
  margin-top: 10px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--card-bg);
}
.detail-title { margin: 0 0 4px; font-size: 14px; font-weight: 700; }
.detail-line { margin: 0; font-size: 13px; line-height: 1.5; }
.detail-note { margin: 6px 0 0; font-size: 12px; color: var(--muted); }

.pick {
  width: 100%; text-align: left;
  border: 1px solid var(--line); border-radius: 11px;
  background: none; color: inherit; font-family: inherit;
  padding: 9px 12px; cursor: pointer;
  display: flex; align-items: center; gap: 10px;
}
.pick:hover { border-color: var(--btn-bg); }
.pick[aria-pressed="true"] { background: var(--sel); border-color: var(--btn-bg); }
.pick.locked { opacity: 0.45; cursor: default; }
.pick .avatar { width: 26px; height: 34px; flex: none; }
/* 아이콘은 글자가 아니라 SVG다. 글자 크기 대신 상자 크기로 재고, `currentColor`로
   그리므로 색은 놓인 자리가 정한다. 줄 안에서는 글자와 밑선을 맞춘다. */
.ico-box { display: inline-flex; flex: none; line-height: 0; vertical-align: -0.18em; }
.ico-box svg { width: 1.15em; height: 1.15em; }
.pick .icon, .item .icon, .slot-row .icon, .skill-row .icon {
  width: 26px; justify-content: center; flex: none;
}
.pick .icon svg, .item .icon svg, .slot-row .icon svg, .skill-row .icon svg {
  width: 22px; height: 22px;
}
.with-ico { display: inline-flex; align-items: center; gap: 6px; }
.pick-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pick-name { font-weight: 700; font-size: 15px; display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.pick-name .job { font-size: 12px; font-weight: 600; color: var(--muted); }
.pick-name .job.tank { color: var(--ally); }
.pick-name .job.dealer { color: var(--enemy); }
.pick-name .job.healer { color: var(--heal); }
/* 장비가 얹어 준 능력치. 내가 넣은 점수와 색으로 갈라 둔다. */
.pick-name .job.gear { color: var(--hero); }

/* 계열 색. 같은 딜러라도 궁수와 마법사가 다른 색으로 읽혀야 편성이 고민이 된다. */
.job.spec-tank { color: var(--spec-tank); }
.job.spec-warrior { color: var(--spec-warrior); }
.job.spec-rogue { color: var(--spec-rogue); }
.job.spec-archer { color: var(--spec-archer); }
.job.spec-mage { color: var(--spec-mage); }
.job.spec-priest { color: var(--spec-priest); }
.job.spec-shaman { color: var(--spec-shaman); }
.job.spec-bard { color: var(--spec-bard); }
.job.spec-grunt { color: var(--spec-grunt); }
.job.spec-chieftain { color: var(--spec-chieftain); }
.job.spec-bulwark { color: var(--spec-bulwark); }
.job.spec-berserker { color: var(--spec-berserker); }
.job.spec-assassin { color: var(--spec-assassin); }
.job.spec-marksman { color: var(--spec-marksman); }
.job.spec-archmage { color: var(--spec-archmage); }

/* 스킬 이름표. 색이 무엇을 하는 스킬인지를 알린다. */
.chip { display: inline-flex; align-items: center; gap: 4px; }
.chip .ico-box svg { width: 13px; height: 13px; }
.chip.skill { border-color: currentColor; }
.chip.skill.harm { color: var(--kind-harm); }
.chip.skill.bane { color: var(--kind-bane); }
.chip.skill.mend { color: var(--kind-mend); }
.chip.skill.pull { color: var(--kind-pull); }
.chip.skill.mana { color: var(--kind-mana); }
.chip.skill.stun { color: var(--kind-stun); }
.chip.skill.boon { color: var(--kind-boon); }
.chip.skill.wilt { color: var(--kind-wilt); }
.chip.skill.daze { color: var(--kind-daze); }
.pick-sub { font-size: 12px; color: var(--muted); line-height: 1.45; }
.pick-cost { font-size: 12px; color: var(--muted); flex: none; text-align: right; }

.btn {
  border: 1px solid var(--line); border-radius: 11px;
  background: var(--card-bg); color: inherit;
  font-family: inherit; font-size: 15px; font-weight: 700;
  padding: 12px 18px; cursor: pointer;
}
.btn:hover { border-color: var(--btn-bg); }
.btn.primary { background: var(--btn-bg); color: var(--btn-fg); border-color: var(--btn-bg); }
.btn:disabled { opacity: 0.4; cursor: default; }

/* --- 전투 --- */
.battle-top { display: flex; align-items: baseline; gap: 10px; min-height: 20px; }
.wave { font-size: 13px; font-weight: 700; color: var(--muted); flex: none; }
.log {
  margin: 0; font-size: 13px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.field-wrap { display: flex; flex-direction: column; gap: 6px; }

/* 좌표계(data.js의 FIELD)와 화면 비율을 맞춰 둔다. 어긋나면 장판이 가로세로로
   다르게 늘어나 원이 타원으로 보인다. */
.field {
  position: relative;
  aspect-ratio: 100 / 56;
  border: 1px solid var(--line); border-radius: 14px;
  background: #1d1a24;
  overflow: hidden;
  touch-action: none;
}

/* 배경은 퀘스트 장소에 따라 scenes.js가 만들어 넣는다. 밝은 테마에서도 배경은
   그대로 어둡다 — 던전 안이 페이지 설정에 따라 밝아질 이유가 없다. */
/* 배경을 두 장 이어 붙여 놓고 통째로 왼쪽으로 민다. 두 장이 똑같으므로 한 장
   폭만큼 밀렸을 때 되감으면 이음매가 보이지 않는다 — 무리와 무리 사이에 걸어서
   이동하는 것으로 보이게 하는 방법이고, 유닛 좌표는 건드리지 않는다. */
.scene-layer {
  position: absolute; inset: 0;
  display: flex; width: 200%;
  will-change: transform;
}
.scene { display: block; width: 50%; height: 100%; flex: none; }
.field.aiming { cursor: crosshair; }
.field.aiming::after {
  content: ""; position: absolute; inset: 0; z-index: 90;
  border: 2px dashed #f0e2a8; border-radius: 13px; opacity: 0.75;
  pointer-events: none;
}

/* 앞뒤는 발이 놓인 높이가 정한다(z-index를 main.js가 준다). 전장이 비스듬히
   내려다본 자리라 아래에 선 쪽이 앞이고, 그것이 없으면 노드가 만들어진 차례가
   앞뒤가 되어 뒤에 선 적이 앞의 아군을 덮었다. 장판은 바닥에 놓인 것이라 그
   아래, 뜨는 숫자와 조준 테두리는 그 위에 둔다 — 층을 여기 한 곳에 모아 둔다. */
.unit {
  position: absolute;
  /* 폭은 그림마다 다르므로 main.js가 정한다. */
  transform: translate(-50%, -72%);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  pointer-events: none;
}
.unit.pickable { pointer-events: auto; cursor: pointer; }
/* 쓰러진 유닛은 눕힌다. 흐리게만 두었더니 도트 그림이 회색 덩어리로 뭉개져
   무엇이 쓰러진 것인지 알 수 없었다. 눕히면 형태는 남고 상태는 분명해진다. */
.unit.dead { opacity: 0.32; }
.unit.dead .mark { opacity: 0.25; }
.unit.dead .hpbar { display: none; }
/* 발끝을 축으로 넘어뜨린다. 가운데를 축으로 돌리면 쓰러진 유닛이 바닥에서
   떠올라 공중에 눕는다. */
.unit.dead .sprite { transform-origin: 50% 100%; }
.unit.ally.dead .sprite { transform: rotate(-80deg); }
.unit.enemy.dead .sprite { transform: scaleX(-1) rotate(-80deg); }

.sprite { width: 100%; height: auto; display: block; }

/* 그림 파일로 그리는 유닛(주인공). 시트를 통째로 넣고 상자로 잘라 보여 준다 —
   이미지가 상자의 cols×rows 배라, 제 크기의 1/cols씩 밀면 칸이 딱 떨어진다.
   `background-position`을 %로 잡으면 요소 크기에 따라 계산이 달라져 이 방법이
   더 안전하다. 가로세로비는 칸에서 나오므로 main.js가 넣는다. */
.filmstrip { position: relative; overflow: hidden; display: block; }
.filmstrip img {
  position: absolute; left: 0; top: 0;
  transform-origin: 0 0;
  image-rendering: auto;
  pointer-events: none;
}
/* 아바타는 높이가 정해져 있다. 폭을 칸의 비율대로 따라오게 두어야 인물이
   납작해지지 않는다. */
.avatar.filmstrip { width: auto; }

/* 도트 그림은 제 색을 갖는다. color는 이제 그림이 아니라 발판과 강조 테두리에만
   쓰인다 — 편을 가르는 일을 그것들이 대신한다. */
.unit.ally { color: var(--ally); }
.unit.ally.is-hero { color: var(--hero); }
.unit.enemy { color: var(--enemy); }
/* 적은 왼쪽을 보고 서야 아군과 마주 본다. */
.unit.enemy .sprite { transform: scaleX(-1); }

.unit .mark {
  position: absolute; bottom: 4%; left: 50%;
  width: 70%; height: 12%;
  transform: translateX(-50%);
  border-radius: 50%;
  background: color-mix(in srgb, currentColor 55%, transparent);
  box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.45);
}

.unit .hpbar {
  width: 118%; height: 4px; border-radius: 2px;
  background: rgba(0, 0, 0, 0.55); overflow: hidden;
}
.unit .hpbar span { display: block; height: 100%; background: var(--hp); }

/* 시전 막대. 체력 막대와 색을 나눠 두지 않으면 외우는 중인지 회복 중인지
   구분이 안 된다. 시전은 잠깐이라 늘 떠 있지 않다. */
.unit .castbar {
  width: 118%; height: 3px; border-radius: 2px;
  background: rgba(0, 0, 0, 0.55); overflow: hidden;
}
.unit .castbar span { display: block; height: 100%; width: 0; background: #f0e2a8; }

/* 무리 사이의 걸음을 흔들기(`trudge`)로 흉내 내던 규칙은 걷어냈다. 걷는 프레임이
   따로 있는 유닛은 거기서 뺐는데(`is-sheet`), 이제 모든 유닛이 그림 파일이라
   해당하는 유닛이 하나도 없다 — `main.js`가 이동 중인 아군을 오른쪽 걷기로
   고정하는 것이 그 일을 대신한다. */
.unit.dead .castbar { display: none; }
.unit.low .hpbar span { background: var(--hp-low); }

/* 기절. 굳어 있는 동안 그림이 살짝 기울고 노란 테가 돈다 — 화면에서 "지금 저것은
   아무것도 못 한다"가 보여야 기절이 있다는 것을 알 수 있다. */
.unit.stunned .sprite { filter: drop-shadow(0 0 3px var(--kind-stun)); }
.unit.stunned .mark { box-shadow: 0 0 0 2px var(--kind-stun); }
/* 혼란. 굳은 것과 갈라야 해서 색이 다르고, 발판까지 물들여 "편이 뒤집혔다"를
   알린다 — 발판 색이 곧 편이라(`.mark`), 거기가 흔들리는 것이 이 상태의 뜻이다. */
.unit.confused .sprite { filter: drop-shadow(0 0 3px var(--kind-daze)); }
.unit.confused .mark { box-shadow: 0 0 0 2px var(--kind-daze); background: var(--kind-daze); }
/* 유닛 이름표는 없다. 아홉 그림이 실루엣만으로 갈리도록 그렸고, 아군의 이름은
   아래 초상화 줄에 있다. 뭉쳐 싸울 때 이름표가 서로 겹쳐 읽히지도 않으면서
   화면만 덮었다 — 그림을 구분되게 그린 것이 이름표를 없애기 위해서였다. */
.unit.targeted .sprite { filter: drop-shadow(0 0 3px currentColor); }

/* 조준 중에 고를 수 있는 대상. 테두리가 아니라 그림자를 쓰는 것은 유닛이
   1초에 30번 움직여서, 레이아웃에 영향을 주는 속성을 건드리면 흔들리기 때문이다. */
.field.aiming .unit.valid .sprite { filter: drop-shadow(0 0 5px currentColor); }
.field.aiming .unit:not(.valid) { opacity: 0.4; }

.zone {
  position: absolute; border-radius: 50%; z-index: 1;
  transform: translate(-50%, -50%);
  pointer-events: none;
  border: 2px solid var(--zone-heal);
  background: color-mix(in srgb, var(--zone-heal) 16%, transparent);
}
.zone.damage { border-color: var(--zone-harm); background: color-mix(in srgb, var(--zone-harm) 16%, transparent); }

/* 주인공의 사거리. 눌러 보고 나서 "사거리 밖"을 듣는 것보다 먼저 보이는 것이
   낫다 — 그동안 다른 스킬의 쿨타임이 돈다. */
.reach {
  position: absolute; border-radius: 50%; z-index: 1;
  transform: translate(-50%, -50%);
  border: 1px dashed rgba(240, 226, 168, 0.5);
  pointer-events: none;
}

.aim {
  position: absolute; border-radius: 50%; z-index: 1;
  transform: translate(-50%, -50%);
  border: 2px dashed #f0e2a8;
  background: rgba(240, 226, 168, 0.12);
  pointer-events: none;
}

.float {
  position: absolute; transform: translate(-50%, -50%); z-index: 80;
  font-size: clamp(11px, 2.2vw, 15px); font-weight: 800;
  pointer-events: none;
  animation: rise 0.9s ease-out forwards;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.float.heal { color: var(--heal); }
.float.harm { color: var(--harm); }

@keyframes rise {
  from { opacity: 1; transform: translate(-50%, -50%); }
  to { opacity: 0; transform: translate(-50%, -220%); }
}

.pulse {
  position: absolute; border-radius: 50%; z-index: 80;
  transform: translate(-50%, -50%);
  border: 2px solid var(--heal);
  pointer-events: none;
  animation: pulse 0.5s ease-out forwards;
}
.pulse.harm { border-color: var(--harm); }

@keyframes pulse {
  from { opacity: 0.9; scale: 0.3; }
  to { opacity: 0; scale: 1; }
}

.aim-hint { margin: 0; font-size: 13px; color: var(--btn-bg); font-weight: 600; text-align: center; }

/* 초상화. 범위 스킬의 기준점을 동료로 잡는 통로이자 공격 스킬의 대상 자리라
   (기획서 8.1) 전투 중 가장 자주 눌리는 곳이다 — 손가락이 닿는 크기를 지킨다.
   두 줄이 같은 칸을 쓴다. 줄마다 flex로 늘려 두었더니 셋이 남은 적 줄과
   다섯이 선 아군 줄의 초상화 크기가 달랐고, 적 줄을 따로 작게까지 두어
   공격 스킬의 대상 자리인데도 손가락이 빗나갔다. 양쪽 다 최대 다섯이라
   다섯 칸으로 나눈다 — 빈 칸은 오른쪽에 남는다. */
.portraits {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px;
}
.portrait.enemy { border-color: color-mix(in srgb, var(--enemy) 45%, var(--line)); }
.portrait.enemy .bar span { background: var(--enemy); }

.portrait {
  position: relative;
  width: 100%; min-width: 0;
  border: 1px solid var(--line); border-radius: 11px;
  background: var(--card-bg); color: inherit; font-family: inherit;
  padding: 6px 4px 5px; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
}
.portrait .avatar { width: 22px; height: 30px; color: var(--ally); }
.portrait.enemy .avatar { color: var(--enemy); }
.portrait.is-hero .avatar { color: var(--hero); }
.portrait .pname {
  font-size: 10px; font-weight: 700; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.portrait .bar { width: 100%; }
.portrait.dead { opacity: 0.35; }
.portrait.valid { border-color: var(--btn-bg); box-shadow: 0 0 0 2px color-mix(in srgb, var(--btn-bg) 40%, transparent); }
.aiming-mode .portrait:not(.valid) { opacity: 0.4; }

.bar {
  position: relative; height: 6px; border-radius: 3px;
  background: rgba(128, 128, 128, 0.25); overflow: hidden;
}
.bar span { display: block; height: 100%; width: 100%; background: var(--hp); transition: width 0.1s linear; }
.bar.low span { background: var(--hp-low); }
.bar.mp span { background: var(--mp); }

.bars { display: flex; gap: 8px; }
.bars .bar { flex: 1; height: 18px; border-radius: 9px; }
.bars .bar b {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; color: var(--btn-fg);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

/* 주인공이 위험할 때. 막대와 전장 테두리가 함께 맥박치는 것은, 눈이 둘 중
   어디에 있든 걸리게 하려는 것이다. 소리는 main.js가 한 번만 낸다 — 매 프레임
   울리면 경고가 아니라 소음이 된다. */
/* 맥박은 채워진 부분에만 준다. 막대째 흐려지면 그 위의 숫자까지 함께 사라져
   정작 얼마나 남았는지를 못 읽는다. */
.bars.danger .bar.hp { box-shadow: 0 0 0 2px var(--hp-low); }
.bars.danger .bar.hp span { animation: danger-pulse 0.9s ease-in-out infinite; }
.field.danger::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 0 0 3px var(--hp-low);
  animation: danger-pulse 0.9s ease-in-out infinite;
}

@keyframes danger-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* 움직임을 줄여 달라고 한 기기에서는 맥박 대신 계속 켜 둔다. */
@media (prefers-reduced-motion: reduce) {
  .bars.danger .bar.hp span, .field.danger::after { animation: none; }
}

.skillbar { display: flex; gap: 6px; }

.slot {
  flex: 1; min-width: 0; position: relative;
  border: 1px solid var(--line); border-radius: 11px;
  background: var(--card-bg); color: inherit; font-family: inherit;
  padding: 8px 4px 6px; cursor: pointer; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.slot .glyph svg { width: 22px; height: 22px; }
.slot .sname {
  font-size: 10px; font-weight: 700; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.slot .cost { font-size: 10px; color: var(--muted); }
.slot[aria-pressed="true"] { background: var(--sel); border-color: var(--btn-bg); }
.slot.short { opacity: 0.5; }
/* 쿨타임은 위에서 덮어 내려온다. 숫자로 적으면 여러 개를 동시에 읽을 수 없다. */
.slot .cool {
  position: absolute; inset: 0;
  background: rgba(20, 24, 32, 0.55);
  transform-origin: top;
  pointer-events: none;
}

/* --- 결과 --- */
.verdict { margin: 0; font-size: 22px; font-weight: 800; }
.verdict.won { color: var(--heal); }
.verdict.lost { color: var(--harm); }
.verdict-note { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.6; }

.loot, .awards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
/* 한 줄에 아이콘·이름·이유·받는 사람·굴린 값을 다 밀어 넣었더니 이름이 글자
   단위로 쪼개졌다. 넘치면 줄을 바꾸고, 이름 쪽에만 남는 폭을 준다. */
.loot li, .awards li {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px;
  font-size: 14px; padding: 6px 0;
  border-bottom: 1px solid var(--line);
}
.loot li:last-child, .awards li:last-child { border-bottom: 0; }
.awards .iname { flex: 1 1 auto; min-width: 0; }
.awards .to { margin-left: auto; font-weight: 700; white-space: nowrap; }
.awards .why { color: var(--muted); font-size: 12px; white-space: nowrap; }
.awards .rolls {
  flex: 1 0 100%; color: var(--muted); font-size: 11px; padding-left: 26px;
  line-height: 1.5;
}

.methods { display: flex; gap: 6px; flex-wrap: wrap; }
.method {
  flex: 1; min-width: 92px;
  border: 1px solid var(--line); border-radius: 11px;
  background: none; color: inherit; font-family: inherit;
  padding: 8px 6px; cursor: pointer;
  display: flex; flex-direction: column; gap: 2px; align-items: center;
}
.method b { font-size: 13px; }
.method small { font-size: 10px; color: var(--muted); text-align: center; line-height: 1.35; }
.method[aria-pressed="true"] { background: var(--sel); border-color: var(--btn-bg); }

.result-actions { display: flex; gap: 8px; }
.result-actions .btn { flex: 1; }

/* --- 도움말 --- */
.sheet {
  position: fixed; left: 50%; bottom: 0; transform: translateX(-50%);
  width: min(100%, var(--app-max));
  background: var(--sheet-bg);
  border: 1px solid var(--line); border-bottom: 0;
  border-radius: 16px 16px 0 0;
  padding: 18px var(--pad-x) calc(18px + env(safe-area-inset-bottom));
  box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.16);
  z-index: 10;
  max-height: 82vh; overflow-y: auto;
}
.sheet-title { margin: 0 0 10px; font-size: 18px; font-weight: 800; }
.help-list { margin: 0; padding-left: 18px; font-size: 14px; line-height: 1.65; }
.help-list li { margin-bottom: 7px; }
.sheet-actions { margin-top: 14px; display: flex; gap: 8px; }
.sheet-actions .btn { flex: 1; }

@media (max-width: 400px) {
  .slot .sname, .portrait .pname { font-size: 9px; }
  .quest-desc { font-size: 13px; }
}

@media (prefers-reduced-motion: reduce) {
  .float, .pulse { animation-duration: 0.01ms; }
}


/* --- 하단 메뉴 --- */
/* 메인 화면에만 나온다. 편성·전투·결과에서는 되돌아갈 곳이 헤더의 뒤로이지
   탭이 아니다 — 전투 중에 탭이 보이면 누를 수 있는 것처럼 보인다. */
.tabbar {
  position: fixed; left: 50%; bottom: 0; transform: translateX(-50%);
  width: min(100%, var(--app-max));
  display: flex; gap: 0;
  background: var(--card-bg);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 5;
}

.tab {
  flex: 1;
  border: 0; background: none; color: var(--muted);
  font-family: inherit; font-size: 12px; font-weight: 700;
  padding: 9px 4px 10px; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  border-top: 2px solid transparent; margin-top: -1px;
}
.tab-icon { display: inline-flex; line-height: 0; }
.tab-icon svg { width: 21px; height: 21px; }
.tab[aria-pressed="true"] { color: var(--fg); border-top-color: var(--btn-bg); }

.tab-page { display: flex; flex-direction: column; gap: clamp(8px, 2vmin, 14px); }

/* 캐릭터 화면 안의 갈래. 아래 탭바와 달리 화면에 붙여 두지 않고 페이지 맨 위에
   둔다 — 같은 화면 안에서 무엇을 보고 있는지를 가르는 것이라, 화면을 옮기는
   탭바와 같은 무게로 보이면 안 된다. */
.subtabs {
  display: flex; gap: 4px;
  background: var(--card-bg);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 4px;
}
.subtab {
  flex: 1;
  border: 0; border-radius: 999px; background: none; color: var(--muted);
  font-family: inherit; font-size: 13px; font-weight: 700;
  padding: 8px 4px; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 5px;
}
.subtab[aria-pressed="true"] { background: var(--btn-bg); color: var(--btn-fg); }
/* 안 쓴 점수가 있는 갈래에 점을 찍는다. 갈래로 나눈 값이 "다른 화면에 있는 것을
   못 본다"라, 이것이 없으면 레벨이 올랐는데 점수를 그냥 지나간다. */
.subtab.has-point::after {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--kind-mend);
}
.subtab[aria-pressed="true"].has-point::after { background: var(--btn-fg); }

.char-page { display: flex; flex-direction: column; gap: clamp(8px, 2vmin, 14px); }

.mini {
  border: 1px solid var(--line); border-radius: 999px;
  background: none; color: inherit; font-family: inherit;
  font-size: 12px; font-weight: 700; padding: 3px 11px; cursor: pointer;
}
.mini:hover { border-color: var(--btn-bg); }

/* --- 퀘스트 난이도 --- */
/* 적정 레벨만 적어 두면 그것이 쉬운지 어려운지를 매번 머리로 빼야 한다. */
.quest-title .level { font-size: 12px; font-weight: 700; }
.level.easy { color: var(--muted); }
.level.fair { color: var(--hp); }
.level.hard { color: var(--hero); }
.level.deadly { color: var(--harm); }

/* --- 전투 리포트 --- */
/* 숫자 칸을 고정폭으로 잡아 줄마다 자리가 맞는다. 이름만 남는 폭을 갖는 것은
   이름 길이가 제각각이라 이름 쪽을 고정하면 잘리는 줄이 생기기 때문이다. */
.report { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.report li {
  display: grid; grid-template-columns: 1fr repeat(3, 58px);
  gap: 6px; align-items: baseline;
  font-size: 13px; padding: 5px 0; border-bottom: 1px solid var(--line);
}
.report li:last-child { border-bottom: 0; }
.report .rname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.report b { text-align: right; font-weight: 600; }
.report .head-row { color: var(--muted); font-size: 11px; }
.report .head-row span:not(.rname) { text-align: right; }
.report .why { color: var(--muted); font-size: 11px; font-weight: 400; }

/* --- 레벨과 경험치 --- */
.levels, .stats, .slots, .inventory, .skill-list, .attrs {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}

.level-row { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.level-row b { flex: none; min-width: 76px; }
.level-row .lv { flex: none; font-weight: 700; color: var(--muted); }
.level-row small { flex: none; color: var(--muted); font-size: 11px; min-width: 64px; text-align: right; }
.bar.exp { flex: 1; height: 8px; }
.bar.exp span { background: var(--hero); }

.stats li {
  display: flex; align-items: baseline; justify-content: space-between;
  font-size: 14px; padding: 4px 0; border-bottom: 1px solid var(--line);
}
.stats li:last-child { border-bottom: 0; }
/* 동료가 제 몫으로 산 것. 위 줄에 딸린 이야기라 선 없이 한 단 작게 둔다 —
   같은 무게로 두면 명부 줄이 두 배로 길어 보인다. */
.stats li.sub-row { border-bottom: 0; padding-top: 0; font-size: 12.5px; }
.stat-value { font-variant-numeric: tabular-nums; }

.slot-row, .item {
  width: 100%; text-align: left;
  border: 1px solid var(--line); border-radius: 11px;
  background: none; color: inherit; font-family: inherit;
  padding: 8px 12px; cursor: pointer;
  display: flex; align-items: center; gap: 10px;
}
.slot-row:hover, .item:hover { border-color: var(--btn-bg); }
.slot-row:disabled { cursor: default; opacity: 0.6; }
.slot-name { flex: none; min-width: 52px; font-size: 12px; font-weight: 700; color: var(--muted); }
.item-name { flex: 1; min-width: 0; font-weight: 600; font-size: 14px; }
.item-name.empty { color: var(--muted); font-weight: 400; }

/* **등급은 색으로 먼저 읽힌다.** 이름을 하나하나 읽어 등급을 가리게 하면
   목록에서 훑어지지 않는다. 색만으로 가르지 않도록 이름에도 등급이 적혀 있다. */
.tier-common { color: var(--tier-common); }
.tier-uncommon { color: var(--tier-uncommon); }
.tier-rare { color: var(--tier-rare); }
.tier-epic { color: var(--tier-epic); }
.tier-legend { color: var(--tier-legend); }
.tier-myth { color: var(--tier-myth); }
/* 이름표로 쓰일 때에는 테두리도 같이 물든다. */
.chip.gear.tier-common { border-color: var(--tier-common); color: var(--tier-common); }
.chip.gear.tier-uncommon { border-color: var(--tier-uncommon); color: var(--tier-uncommon); }
.chip.gear.tier-rare { border-color: var(--tier-rare); color: var(--tier-rare); }
.chip.gear.tier-epic { border-color: var(--tier-epic); color: var(--tier-epic); }
.chip.gear.tier-legend { border-color: var(--tier-legend); color: var(--tier-legend); }
.chip.gear.tier-myth { border-color: var(--tier-myth); color: var(--tier-myth); }

/* 게시판의 적 등급. 우두머리가 나오는 의뢰인지가 한눈에 보여야 전리품을 노리고
   고르는 일이 생긴다. */
.tag.rank-elite { color: var(--tier-rare); border-color: currentColor; }
.tag.rank-boss { color: var(--tier-myth); border-color: currentColor; font-weight: 700; }
/* 이름과 수치가 서로 밀면 이름이 한 글자씩 접힌다. 수치 쪽을 좁게 묶어 둔다. */
.slot-row .why { flex: none; max-width: 46%; text-align: right; line-height: 1.4; }

/* 지금 낀 것보다 나은 물건. 눌러 볼 이유가 있는 줄만 눈에 띄면 된다. */
.item.better { border-color: var(--hp); }
.item .pick-cost { color: var(--btn-bg); font-weight: 700; }

.empty-note { color: var(--muted); font-size: 13px; padding: 6px 0; }

/* 주인공이 쓰러진 뒤. 전투는 이어지지만 스킬은 나가지 않는다 — 눌러도 아무 일이
   없으면 화면이 고장 난 것으로 보인다. */
.skillbar.down { opacity: 0.45; }
.skillbar.down .slot { cursor: default; }

.skill-row {
  display: flex; align-items: center; gap: 10px;
  border: 1px solid var(--line); border-radius: 11px; padding: 8px 12px;
}
.skill-row.locked { opacity: 0.45; }

/* 동료가 무엇을 들고 오는지. 레벨에 따라 다르므로 이름만으로는 고를 수 없다. */
.skill-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.chip {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 1px 8px; font-size: 11px; font-weight: 600; color: var(--fg);
}
.chip.dim { color: var(--muted); }


/* --- 초상화의 마나 --- */
/* 동료도 마나를 쓴다. 사제가 왜 가만히 있는지가 화면에 없으면 고장 난 것처럼
   보이므로 체력 아래에 얇게 한 줄 더 둔다. */
.bar.thin { height: 4px; margin-top: 2px; }
.portrait .bar.mp span { background: var(--mp); }

/* --- 편성 화면의 칩 --- */
.chip.gear { border-color: var(--hero); color: var(--hero); }

/* --- 아이템 줄 --- */
/* 옵션 줄과 차이 줄이 같은 색이면 무엇이 지금 붙어 있고 무엇이 달라지는지
   구분되지 않는다. */
.pick-sub.diff { color: var(--btn-bg); font-weight: 600; }
/* 시전 시간·사거리 줄. 설명보다 한 단계 물러나 있어야 설명이 먼저 읽힌다. */
.pick-sub.dim { font-size: 11px; opacity: 0.75; }

/* 초상화 위로 떠오르는 피해·회복 숫자. 전장에서도 같은 숫자가 뜨지만, 뭉쳐
   싸울 때에는 그쪽이 서로 겹쳐 읽히지 않는다. */
.pops {
  position: absolute; left: 0; right: 0; top: -2px;
  pointer-events: none;
}
.pop {
  position: absolute; left: 50%; transform: translateX(-50%);
  font-size: 12px; font-weight: 800; white-space: nowrap;
  animation: pop-rise 0.85s ease-out forwards;
}
.pop.harm { color: var(--harm); }
.pop.heal { color: var(--heal); }
.pop.crit { font-size: 14px; }

/* 전투 중 머리 위로 뜨는 스킬 아이콘. 숫자보다 크게 띄워야 피해량과 섞이지
   않고, 같은 색 규칙을 써야 이름표에서 본 것과 같은 것으로 읽힌다. */
.float.skill {
  font-size: clamp(13px, 2.8vw, 19px);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
}
.float.ico-float { line-height: 0; }
.float.ico-float svg { width: clamp(16px, 3.4vw, 24px); height: clamp(16px, 3.4vw, 24px); }
.float.skill.harm { color: var(--kind-harm); }
.float.skill.bane { color: var(--kind-bane); }
.float.skill.mend { color: var(--kind-mend); }
.float.skill.pull { color: var(--kind-pull); }
.float.skill.mana { color: var(--kind-mana); }
.float.skill.stun { color: var(--kind-stun); }
.float.skill.boon { color: var(--kind-boon); }
.float.skill.wilt { color: var(--kind-wilt); }

/* 걸려 있는 것 — 지속 피해·지속 회복·기절·도발·혼란·강화·약화. 초상화 오른쪽
   위에 작게 붙는다. 예전에는 색 점이었는데, 점은 좋은 쪽인지 나쁜 쪽인지만 알리고
   무엇이 걸렸는지는 알리지 않았다. 색은 스킬 종류 색을 그대로 쓴다 — 스킬 카드에서
   본 색이 그 스킬이 남긴 상태에도 걸려야 둘이 같은 것으로 읽힌다.
   접어 내리게 두는 것은, 일곱 가지가 한꺼번에 걸리면 가로로는 초상화를 넘기 때문이다.
   글자 위가 아니라 그림 위로 접히도록 폭을 절반으로 묶는다. */
.status {
  position: absolute; top: 2px; right: 2px;
  display: flex; flex-wrap: wrap; justify-content: flex-end;
  max-width: 60%; gap: 1px; pointer-events: none;
  /* 두 줄까지만 보인다. 일곱 가지가 한꺼번에 걸리면 세로로 흘러넘쳐 초상화 밖까지
     내려가는데, 목록은 급한 것부터 순서가 잡혀 있으므로(`logic.STATUS_KINDS`)
     잘리는 것은 늘 강화·약화 쪽이다. */
  max-height: 23px; overflow: hidden;
}
.status .ico-box svg { width: 11px; height: 11px; }
.status .bane { color: var(--kind-bane); }
.status .mend { color: var(--kind-mend); }
.status .pull { color: var(--kind-pull); }
.status .stun { color: var(--kind-stun); }
.status .daze { color: var(--kind-daze); }
.status .boon { color: var(--kind-boon); }
.status .wilt { color: var(--kind-wilt); }

@keyframes pop-rise {
  from { opacity: 1; transform: translate(-50%, 0); }
  to { opacity: 0; transform: translate(-50%, -16px); }
}

/* 시전 중인 유닛은 초상화 테두리가 밝아진다. 누가 무엇을 외우고 있는지가
   전장에서만 보이면 뭉쳐 있을 때 놓친다. */
.portrait.casting { border-color: #f0e2a8; }
.item .pick-cost { white-space: nowrap; }
.item:disabled { opacity: 0.45; cursor: default; }

/* --- 레벨이 오른 줄 --- */
.stat-value.up { color: var(--hp); }


/* --- 능력치 --- */
/* 값과 올리는 단추가 오른쪽에 붙는다. 남은 점수가 없으면 단추가 흐려질 뿐
   자리는 그대로 둔다 — 자리가 사라지면 줄 폭이 바뀌어 값이 움직인다. */
.attr-row {
  display: flex; align-items: center; gap: 10px;
  border: 1px solid var(--line); border-radius: 11px; padding: 8px 12px;
}
.attr-value {
  flex: none; min-width: 44px; text-align: right;
  font-size: 17px; font-variant-numeric: tabular-nums;
}
.attr-add {
  flex: none; width: 34px; height: 34px;
  border: 1px solid var(--btn-bg); border-radius: 9px;
  background: none; color: var(--btn-bg);
  font-family: inherit; font-size: 17px; font-weight: 700; cursor: pointer;
}
.attr-add:hover:not(:disabled) { background: var(--sel); }
.attr-add:disabled { opacity: 0.25; cursor: default; }
/* 배우기 단추는 글자라 폭이 넓다. ＋와 같은 칸에 두면 글자가 잘린다. */
.attr-add.learn { width: auto; padding: 0 10px; font-size: 13px; font-weight: 600; }

/* 동료의 계열 바꾸기. 칩 줄이라 시트 안에서 스킬 칩과 같은 결로 읽힌다. */
.spec-swap { display: grid; gap: 6px; padding: 10px 0 0; border-top: 1px solid var(--line); }
.spec-row { display: flex; flex-wrap: wrap; gap: 6px; }
.spec-pick { cursor: pointer; }
.spec-pick[aria-pressed="true"] { border-color: currentColor; background: var(--sel); }
.spec-pick:disabled { cursor: default; opacity: 0.5; }
.spec-pick[aria-pressed="true"]:disabled { opacity: 1; }
.spec-tank { color: var(--spec-tank); } .spec-warrior { color: var(--spec-warrior); }
.spec-rogue { color: var(--spec-rogue); } .spec-archer { color: var(--spec-archer); }
.spec-mage { color: var(--spec-mage); } .spec-priest { color: var(--spec-priest); }
.spec-bard { color: var(--spec-bard); }

/* 계열 고르기. 한 줄에 둘로 고정하는 것은 편성 카드와 같은 이유다 — auto-fill로
   두면 좁은 기기에서 한 칸으로 접혀 견주는 화면이 아니게 된다. */
.job-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.job-card {
  display: block; text-align: left; width: 100%;
  border: 1px solid var(--line); border-radius: 12px; padding: 10px;
  background: var(--card); color: inherit; font-family: inherit; cursor: pointer;
}
.job-card[aria-pressed="true"] { border-color: var(--btn-bg); background: var(--sel); }
/* 조건을 못 채운 계열도 읽혀야 한다 — 무엇이 모자란지가 그 카드에 적혀 있다. */
.job-card:disabled { cursor: default; }
.job-card:disabled:not([aria-pressed="true"]) { opacity: 0.55; }
.job-card:hover:not(:disabled) { border-color: var(--btn-bg); }

/* 빗나간 공격. 숫자가 아니라 글자라 피해·회복과 헷갈리지 않는다. */
.float.miss { color: var(--muted); font-size: clamp(10px, 2vw, 13px); }
/* 혼란은 빗나감·기절과 같은 작은 글자지만 색이 다르다 — 걸린 순간이 셋 다
   비슷하게 지나가면 무엇이 걸렸는지 못 읽는다. */
.float.daze { color: var(--kind-daze); font-size: clamp(10px, 2vw, 13px); font-weight: 700; }

/* 치명타. 색만 다르게 하면 피해·회복과 헷갈리고 숫자만 키우면 그냥 많이 맞은
   것으로 보인다 — 크기와 테두리를 함께 준다. */
.float.crit {
  font-size: clamp(15px, 3.2vw, 22px);
  -webkit-text-stroke: 0.6px rgba(0, 0, 0, 0.55);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
.float.harm.crit { color: #ff9a3c; }
.float.heal.crit { color: #8fe07a; }

/* --- 평판과 신뢰도 --- */

/* 평판 한 줄. 게시판 위와 결과 화면 두 곳이 같은 모양을 쓴다 — 두 벌로 두면
   한쪽만 고치게 된다. */
.rep { display: flex; flex-direction: column; gap: 5px; margin-top: 8px; }
.rep-head { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.rep-head .ico-box svg { width: 15px; height: 15px; }
.rep-head .why { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.rep-bar {
  position: relative; height: 6px; border-radius: 3px;
  background: rgba(128, 128, 128, 0.25); overflow: hidden;
}
.rep-bar span { display: block; height: 100%; background: var(--hero); }
.rep-note { margin: 0; font-size: 11.5px; color: var(--muted); }

/* 신뢰도 값표. **단계마다 색이 갈린다** — 숫자만으로는 -20과 -60이 다르다는
   것이 훑을 때 보이지 않고, 그 둘 사이에 모집 거부가 있다. 색만으로 가르지
   않도록 상세에는 단계 이름이 글자로도 적힌다. */
.trust-tag {
  flex: none; font-size: 11px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  border: 1px solid currentColor; border-radius: 999px; padding: 0 5px;
}
.t-broken { color: var(--tier-myth); }
.t-hate { color: var(--harm); }
.t-cold { color: var(--spec-bard); }
.t-neutral { color: var(--muted); }
.t-warm { color: var(--spec-archer); }
.t-high { color: var(--heal); }
.t-bond { color: var(--kind-boon); }

/* 편성 카드의 아랫줄. 신뢰도와 보수, 그리고 난이도가 맞는 동료의 표뿐이라 한
   줄에 들어간다 — 이유까지 적으면 카드가 다시 네 줄이 되어 격자로 바꾼 뜻이
   사라진다. */
.pick-deal { display: flex; align-items: center; gap: 5px; margin-top: 3px; }
/* **동전과 금액은 한 덩어리다.** 따로 두었더니 줄이 접히는 좁은 화면에서 동전만
   윗줄에 남아, 값이 아니라 장식으로 보였다. */
.pick-deal .wage-box { display: inline-flex; align-items: center; gap: 4px; flex: none; }

/* 계열 이름표와 난이도 표가 함께 서는 줄. */
.pick-tags { display: flex; align-items: center; gap: 4px; min-width: 0; }

/* 이 의뢰를 제 레벨에 맞다고 보는 동료의 표. **게시판의 "알맞음"과 같은 색을
   쓴다**(`.level.fair`) — 같은 판단을 두 화면이 다른 색으로 알리면 색이 뜻을
   잃는다. 색만으로 가르지 않도록 글자로도 적는다(등급 색과 같은 잣대다). */
.feel-tag {
  flex: none; font-size: 10.5px; font-weight: 700; color: var(--hp);
  border: 1px solid currentColor; border-radius: 999px; padding: 0 5px;
}
.pick-deal .ico-box svg { width: 12px; height: 12px; }
.pick-deal .wage {
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.pick-deal .wage.no { color: var(--harm); font-weight: 600; }

/* 동료 상세의 신뢰도 자리. 값을 이룬 배수와 대사가 여기에만 있다. */
.trust { display: flex; flex-direction: column; gap: 4px; margin: 8px 0 2px; }
.trust-head { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.trust-head .ico-box svg { width: 15px; height: 15px; }
.trust-line { margin: 0; font-size: 12.5px; }
.trust-line.no { color: var(--harm); font-weight: 600; }
.trust-wage { display: flex; align-items: baseline; gap: 6px; font-size: 14px; }
.trust-wage .ico-box svg { width: 14px; height: 14px; }
.trust-wage .why { color: var(--muted); font-size: 11.5px; }
.trust .pick-sub.dim { opacity: 0.85; }

/* 얹어 주기와 선물. 칩이 줄바꿈으로 흘러야 인벤토리가 길어져도 시트가 가로로
   밀리지 않는다. */
.favor { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.favor-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.favor-row .chip { cursor: pointer; font: inherit; }
/* 그 동료가 쓸 수 있는 물건. 색만으로 가르지 않도록 칩에 오른 신뢰도가 적혀 있다. */
.favor-row .chip.liked { border-color: currentColor; font-weight: 700; }

/* 모자라거나 깎인 값. 오르는 쪽(.up)과 짝이다. */
.count.short, .stat-value.short { color: var(--harm); }
.count.up { color: var(--hp); }
