/* ── 중단점 다섯. **여섯째를 더하지 않는다** (tests/mobile.test.js 가 강제) ───────
   620   툴팁 글씨·아이콘 · 「한눈에」 타일·장비 격자 · 파티 칸 1열 · 출처 단
   720   **모바일** — 하단 탭 바 · 세로 순서 · 터치 44px · 바텀 시트 · 접는 절
   900   장비 격자 · 파티 칸 2열
   1100  빌드 플래너 3단 → 1단
   1240  「한눈에」 열

   JS 쪽 정본은 web/lib/viewport.js 의 모바일중단점(720)이다. 폭이 늘어나면 어느
   화면이 어디서 접히는지 아무도 못 외우고, 그러면 「모바일에서만」이라던 규칙이
   슬금슬금 데스크톱으로 샌다. 모바일 껍데기(탭 바·바텀 시트·터치 대상)는
   web/mobile.css 에 있다 — 아이템 화면이 이 파일을 안 싣기 때문이다.
   ────────────────────────────────────────────────────────────────────────── */

/* ── `hidden` 을 **한 번에** 못박는다 ─────────────────────────────────────
   ⚠ **작성자가 쓴 `display` 는 UA 기본값 `[hidden] { display: none }` 을 이긴다.**
   그래서 `hidden` 을 달아도 요소가 그대로 보인다.

   이 저장소는 **이 자리에서 네 번 데였다:**
     2026-08-07  nav#itemfilter — 주문 탭인데 h=127 로 살아 있어 두 필터가 겹쳤다
     2026-08-07  .taggroup label — 「1개짜리도 보기」가 한 번도 안 먹어 목록이 416줄
     2026-08-07  #tagbar — 위 둘을 겪은 뒤 예방으로 짝지음
     2026-08-11  .calcstat — 「이 턴에 쓰러뜨릴」 칸이 빈 상자로 남았다

   **네 번 다 그 선택자만 막았다.** 두 번째 자리의 주석에 「이 파일이 nav 에 대해
   이미 같은 경고를 적어 두고도 여기서 또 났다」고 적혀 있다 — 경고를 읽고도 났다는
   뜻이라, **자리마다 막는 것이 틀린 크기다.** display 를 지정한 규칙이 이 파일에만
   127개이고(flex 68 · grid 27 · block 18 …) 그 전부가 같은 구멍을 갖는다.

   !important 를 쓰는 이유: `hidden` 은 「감춘다」는 뜻이고 **켜고도 보여야 하는
   자리는 없다**(실측 — web/*.css 에 그런 규칙 0건). 예외가 필요해지면 그때는
   `hidden` 이 아니라 다른 속성을 써야 한다는 신호다.

   ⚠ **이 파일은 공개판에서 통째로 갈아끼운다.** 그러면 이 규칙도 같이 사라진다 —
   그래서 `tests/hidden-attr.test.js` 가 「모든 화면이 이 규칙에 닿나」를 강제한다.
   ⚠ 뒤에 `display: … !important` 를 하나라도 더하면 특정도가 같아 **나중 것이
   이긴다.** 같은 그물이 그것도 막는다. */
[hidden] { display: none !important; }

/* ─────────────────────────────────────────────────────────────────────────
   인게임 껍데기. 게임 자산(web/skin/, web/icons/)을 쓰는 규칙은 전부 이 파일에만 있다.
   공개 배포본을 만들 때 이 파일만 갈아끼우면 Larian 자산 없이도 같은 배치가 나온다.

   자산이 없어도 화면은 그대로 동작해야 한다 (게임 미설치 환경). 그래서 규칙이 하나 있다:
   **색과 테두리를 먼저 주고, 그림은 그 위에 얹는다.** 그림이 없으면 색만 남는다.
   ───────────────────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'BG3 KR';
  src: url('skin/NotoSerifKR-Regular.otf') format('opentype');
  font-display: swap;
}
@font-face {
  font-family: 'BG3 EN';
  src: url('skin/Alegreya-Regular.ttf') format('truetype');
  font-display: swap;
}
/* ⚠ **게임이 같이 주는 중간 굵기.** 여태 파일만 있고 아무도 안 썼다(실측:
   `Alegreya-Medium.ttf` 참조 0건). 제목의 금박 레터링이 이 굵기라야 로고 느낌이
   난다 — 얇은 획에는 양각이 안 얹힌다. `font-weight: 500` 을 요구한 자리만 이걸
   받고 나머지는 그대로 Regular 다. */
@font-face {
  font-family: 'BG3 EN';
  src: url('skin/Alegreya-Medium.ttf') format('truetype');
  font-weight: 500;
  font-display: swap;
}

:root {
  --gold:      #c8a24c;
  --gold-dim:  #8d7439;
  --cream:     #e6dcc4;
  --muted:     #9a8e76;
  --faint:     #6d6353;
  --ink:       #0b0907;
  --panel:     #221c15;
  --line:      #3b3122;
  --warn:      #e0a03c;
  --bg3-serif: 'BG3 KR', 'BG3 EN', 'Apple SD Gothic Neo', 'Noto Serif KR', Georgia, serif;
}

body.bg3 {
  margin: 0;
  min-height: 100vh;
  background: var(--ink) radial-gradient(ellipse at 50% -10%, #1c1610 0%, #0b0907 65%) fixed;
  color: var(--cream);
  font-family: var(--bg3-serif);
  font-size: 14px;
  line-height: 1.65;
}
body.bg3 a { color: var(--gold); }
/* 스크롤바. **밝은 기본 스크롤바가 어두운 판을 가른다** — 목록 옆에 흰 세로줄이
   생겨서 경계선처럼 보였다(2026-08-07 브라우저 실측). 시안도 이것을 명시한다.
   `color-scheme` 만으로는 트랙 색이 판과 안 맞는다. */
body.bg3 { scrollbar-color: var(--line) #120e09; scrollbar-width: thin; }
body.bg3 ::-webkit-scrollbar { width: 8px; height: 8px; }
body.bg3 ::-webkit-scrollbar-thumb { background: var(--line); }
body.bg3 ::-webkit-scrollbar-track { background: #120e09; }

/* ── 창틀 ───────────────────────────────────────────────────────────────
   게임의 summaryPane 은 9-slice 텍스처다. CSS border-image 가 같은 방식이라
   한 장으로 어떤 크기의 창이든 게임과 같은 테두리가 나온다.
   slice 를 150 으로 잡는 이유: 모서리 덩굴 장식이 그 안에 들어 있다. 더 작게 자르면
   장식이 잘리고, 더 크게 자르면 작은 창에서 위아래가 겹친다.

   ⚠⚠ **`@supports` 만으로는 못 가른다. `.skin-assets` 가 함께 있어야 한다.**
   `@supports (border-image: url(...))` 는 브라우저가 그 **문법을 아는지**만 묻고
   URL 이 200인지는 **안 본다.** 그래서 자산이 없어도 이 블록이 적용되는데, 안에서
   `background: none` 과 투명한 46px 테두리가 **기본 색·테두리를 덮어** 판이 통째로
   사라진다. 외부 검수 실측(2026-08-09): 자산을 치우면 판 셋이 전부
   `background: transparent none` + 투명 테두리였다.
   **이건 판을 역할별로 가르기 전부터 있던 결함이다** — 새로 생긴 게 아니라 드러났다.
   (이 파일 머리말의 「그림이 없으면 색만 남는다」가 판에서는 거짓이었다.)

   `.skin-assets` 는 `web/lib/img-fallback.js` 의 `자산확인()` 이 그림 한 장을
   실제로 불러 보고 `<html>` 에 붙인다. **덮어쓰는 규칙만** 이 신호를 쓴다 —
   슬롯·구분선처럼 `background-image` 만 얹는 규칙은 색이 그대로 남으므로 필요 없다. */
.pane {
  background: #221c15cc;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 18px 20px;
}
@supports (border-image: url('skin/summaryPane.png') 150 fill / 46px stretch) {
  .skin-assets .pane {
    background: none;
    border: 46px solid transparent;
    border-radius: 0;
    border-image: url('skin/summaryPane.png') 150 fill / 46px stretch;
    padding: 0 4px 8px;
  }
  /* 좁은 화면에서는 **장식 테두리가 화면을 먹는다.** 46px × 2 = 92px 에 바깥
     여백 16px × 2 를 더하면 375px 기기에서 **132px(35%)** 가 내용에 안 쓰인다
     — 실측(2026-08-08): 본문에 남는 폭이 243px 뿐이라 두 낱말짜리 칩도 줄을
     바꿨다(사용자 제보 「UI 사이즈들이 좀 애매한 거 같다」). 18px 로 줄이면
     본문이 319px 이 된다(버려지는 폭 132 → 56).
     ⚠ **`@supports` 안에 둔다.** 밖에 두면 border-image 를 못 쓰는 환경에서
     되돌림인 `border: 1px solid` 를 18px 짜리 민무늬 테두리로 바꿔 버린다. */
  @media (max-width: 620px) {
    .skin-assets .pane {
      border-width: 18px;
      border-image: url('skin/summaryPane.png') 150 fill / 18px stretch;
      padding: 0 2px 6px;
    }
  }

  /* ── 판마다 다른 틀 ────────────────────────────────────────────────────
     **여태 판 전부가 `summaryPane` 하나를 썼다.** 그래서 빌드 목록·편집기·캐릭터가
     모서리 덩굴까지 똑같았고, 화면이 「같은 액자를 세 번 건 것」처럼 보였다
     (외부 검수 지적, 2026-08-09). 좁은 폭에서 판이 세로로 쌓이면 더 두드러진다.

     **게임은 역할마다 다른 9-slice 를 쓴다.** 우리는 그 자산을 이미 뽑아 두고
     안 쓰고 있었다 — `web/skin` 의 판·프레임 갈래 68개 중 쓰던 것이 18개였다.

     | 판 | 자산 | 왜 |
     |---|---|---|
     | `#summary` | `summaryPane` · 46px | **이름 그대로 캐릭터 요약 판이다.** 제일 장식적인 것을 시트에 준다 |
     | `#editor` | `genericFaded_bg` · **14px** | 얇은 틀로 본문 폭을 벌린다. 제일 넓은 판이라 장식이 얕아야 내용이 산다 |
     | `.buildlist` | `genericFaded_bg` · 20px | 같은 틀을 **두껍게** 써서 무게로 가른다 |
     | `.credits .pane` | `genericFaded_bg` · 20px | 그 화면은 판이 여섯이다 — 장식 액자 여섯이 이어지면 제일 심하게 반복으로 보인다 |

     ⚠⚠ **`#editor` 에 `contentPane` 을 썼다가 되돌렸다(2026-08-09, 사용자 제보).**
     그건 **테두리가 아니라 바탕 그림**이라 옆·아래 가장자리가 없다. 그래서 위는
     화려한 아치인데 옆은 가는 선이고 아래 장식과 안 이어져, 양옆의 완결된 액자
     사이에서 **「닫히지 않은 상자」**로 읽혔다.
     **이 파일에 「바탕 그림은 넓은 판에만 쓴다」고 적어 두고 내가 그걸 어겼다** —
     경고를 쓴 사람이 그 경고에 걸린다.

     ⚠ **후보를 브라우저에서 하나씩 대 보고 골랐다.** `contentPane`(가장자리 없음) ·
     `sorting_bg`(이 크기에서 테두리가 안 보임) · `generic_bg`(마찬가지) 셋 다 탈락.
     **이 판 크기에서 닫힌 틀을 주는 것은 `genericFaded_bg` 하나였다.** 그래서 자산이
     아니라 **두께**로 위계를 준다 — 자산 목록이 많다고 아무거나 골라 쓸 수 있는 게
     아니다(68개 중 실제로 이 자리에 맞는 것은 하나였다).

     ⚠ **`border-width` 를 같이 준다.** `border-image` 의 `/ <폭>` 은 그림을 그리는
     자리만 정하고 **자리 차지는 `border-width` 가 한다** — 안 맞추면 그림은 14px 인데
     내용이 46px 안쪽에서 시작해 빈 띠가 생긴다. */
  .skin-assets #editor.pane {
    border-width: 14px;
    border-image: url('skin/genericFaded_bg.png') 50 fill / 14px stretch;
  }
  .skin-assets .pane.buildlist, .skin-assets .credits .pane {
    border-width: 20px;
    border-image: url('skin/genericFaded_bg.png') 50 fill / 20px stretch;
  }
  @media (max-width: 620px) {
    .skin-assets #editor.pane { border-width: 10px; border-image-width: 10px; }
    .skin-assets .pane.buildlist, .skin-assets .credits .pane { border-width: 12px; border-image-width: 12px; }
  }
}

/* ── 머리글 ── */
/* ── 머리띠 (2026-08-11, 사용자: 「시작 부분인데 텅 빈 느낌」) ─────────────
   게임 자산과 게임 폰트만 쓴다. **없는 그림을 지어내지 않는다.**

   ⚠ **게임 배경 화면(스크린샷)은 못 넣는다.** 우리가 가진 것은 UI 자산뿐이고,
   게임의 지형 텍스처는 라리안의 가상 텍스처 형식이라 우리 디코더가 못 읽는다
   (2026-08-11 실측: `Textures.pak` 의 `.DDS` 항목이 「DDS 아님」으로 떨어진다).
   대신 게임이 실제로 쓰는 **패널 가죽 질감**을 얕게 깔았다 — 그건 진짜 게임 그림이다.

   ⚠ **자산이 없어도 무너지면 안 된다.** `background-image` 는 겹쳐 깔되 색은
   그라디언트가 진다 — `web/skin/` 이 비어 있는 환경(새 워크트리·CI)에서도 금색
   글씨와 어두운 바탕이 그대로 선다. 이 저장소가 이미 한 번 데인 자리다
   (자산 없는 환경에서 체크박스·탭이 흐려졌다). */
.bg3-header {
  position: relative; isolation: isolate;
  /* ⚠ 위아래를 넉넉히 둔다(2026-08-11, 사용자 요청). 제목이 금박이 되면서
     글자 자체가 무거워졌는데 여백이 그대로라 눌린 것처럼 보였다 — 표장은
     둘레의 빈자리가 있어야 표장으로 읽힌다. */
  padding: 46px 26px 26px;
  border-bottom: 1px solid var(--line);
  text-align: center;
  background:
    radial-gradient(120% 150% at 50% 0%, rgba(200, 162, 76, .10), transparent 62%),
    linear-gradient(180deg, rgba(0, 0, 0, .28), transparent);
}
/* 가죽 질감 — 얕게. `::before` 라 자산이 없으면 그냥 아무것도 안 그려진다. */
.bg3-header::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: url('skin/pane_body_bg_9s.png') center/cover no-repeat;
  opacity: .18;
  /* 아래로 갈수록 사라지게 — 머리띠와 본문 사이에 선이 생기지 않는다. */
  -webkit-mask-image: linear-gradient(180deg, #000 35%, transparent);
  mask-image: linear-gradient(180deg, #000 35%, transparent);
}
.bg3-header h1 {
  /* 줄 높이로 글자 **위아래에 같이** 여백을 준다 — 위만 padding 으로 밀면
     아래 장식과의 간격이 안 따라온다. */
  margin: 0; line-height: 1.28;
  /* 게임의 영문 서체(Alegreya)를 그대로 쓴다 — 한글 서체보다 앞에 둔다.
     ⚠ 500 은 게임이 같이 주는 Medium 이다(위 @font-face). 로고의 획 굵기가 그것이고,
     얇은 Regular 에는 아래 양각이 얹힐 자리가 없다. */
  font-family: 'BG3 EN', 'BG3 KR', Georgia, serif;
  font-weight: 500;
  font-size: clamp(30px, 5.2vw, 52px);
  /* 로고는 글자가 거의 붙어 있다. 자간을 좁히면 덩어리로 읽혀 표장처럼 보인다. */
  letter-spacing: .04em; text-indent: .04em;   /* 자간 때문에 오른쪽으로 밀리는 것을 되돌린다 */
  color: var(--gold);
  text-shadow: 0 0 22px rgba(200, 162, 76, .28), 0 2px 3px rgba(0, 0, 0, .6);
}

/* ── 제목을 **금속 금박**으로 ──────────────────────────────────────────────
   게임 로고의 느낌(2026-08-11, 사용자가 레퍼런스를 줬다). **글자 모양은 이미
   맞다** — 위 규칙이 게임 서체를 그대로 쓴다. 빠져 있던 것은 **재질**이다:

     ① 위가 밝고 아래가 깊어지는 금 그라디언트   background-clip: text
     ② 어두운 테두리                          -webkit-text-stroke + paint-order
     ③ 위 모서리에 빛, 아래에 그림자(양각)      drop-shadow 두 겹
     ④ 은은한 금빛 번짐                        drop-shadow 셋째 겹

   ⚠ **로고 문양(악마 두개골)은 안 쓴다.** 그건 라리안의 표장이다. 여기서 흉내
   내는 것은 **레터링의 재질**뿐이고, 글자는 이 사이트의 이름이다.

   ⚠ **`@supports` 로 감싼다.** `background-clip: text` 를 못 쓰는 곳에서
   `color: transparent` 만 먹으면 **제목이 통째로 사라진다** — 이 파일이 이미
   적어 둔 「자산이 없어도 무너지면 안 된다」와 같은 종류의 사고다. 감싸 두면
   그런 환경은 위 규칙의 금색 글씨 그대로다.

   ⚠ **`text-shadow` 를 안 쓰고 `filter: drop-shadow` 를 쓴다.** 글자가 투명해지면
   text-shadow 는 **투명한 글자 모양의 그림자**를 그려서 위 규칙의 그림자가 글자
   위로 비쳐 지저분해진다. drop-shadow 는 그려진 결과(테두리 포함)의 알파를 따라간다. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .bg3-header h1 {
    background: linear-gradient(180deg,
      #f6e3b0 0%,      /* 위쪽 하이라이트 — 금이 빛을 받는 자리 */
      #d9b25e 34%,
      #b6863a 62%,     /* 중간 — 기준 금색(--gold)에 가깝다 */
      #8a5f26 88%,
      #6d4a1d 100%);   /* 아래 — 깊은 그림자 쪽 */
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-stroke: .5px #2a1c0c;
    paint-order: stroke fill;   /* 테두리를 글자 **뒤**로 — 안 하면 획이 먹힌다 */
    text-shadow: none;          /* 위 규칙의 그림자를 끈다(위 ⚠ 참고) */
    filter:
      drop-shadow(0 1px 0 rgba(255, 240, 205, .30))   /* 양각 — 윗면 빛 */
      drop-shadow(0 -1px 0 rgba(0, 0, 0, .55))        /* 양각 — 아랫면 그늘 */
      drop-shadow(0 3px 6px rgba(0, 0, 0, .55))       /* 바닥 그림자 */
      drop-shadow(0 0 18px rgba(200, 162, 76, .22));  /* 금빛 번짐 */
  }
}
/* 게임의 금박 장식. 없으면 안 그려질 뿐이다.
   ⚠ **`header_charactersheet_faded` 를 쓰면 안 된다.** 그건 캐릭터 시트에서
   초상화를 끼우는 자리라 가운데에 **검은 원 셋**이 뚫려 있다 — 제목 밑줄로 쓰면
   그 구멍만 뭉쳐 보인다(2026-08-11 배포본에서 눈으로 확인). 같은 계열이지만
   구멍이 없는 `Selected_Decor_Top` 이 맞고, 그건 `h2.title` 이 이미 쓰고 있다.
   ⚠ 자산 비율이 10:1 이라 `contain` 은 **높이가 폭을 정한다** — 폭을 넓히려면
   높이를 키워야 한다. 처음에 폭만 520px 로 적어 260px 로 줄어들었다. */
.bg3-header h1::after {
  content: ''; display: block; height: 22px; margin: 16px auto 0; max-width: 340px;
  background: url('skin/Selected_Decor_Top.png') center/contain no-repeat;
  opacity: .9;
}
.bg3-header .sitesub {
  margin: 10px 0 0; font-size: 13px; letter-spacing: .22em;
  color: var(--gold-dim);
}
/* ── 카테고리 탭 ────────────────────────────────────────────────────────
   ⚠ **예전엔 링크가 그냥 글자로 떠 있었다**(사용자 지적 2026-08-12). 화면마다
   이름도 갈렸고(「빌드 플래너」/「빌드」, 「데이터 검증」/「아이템」) 어디에도
   「지금 여기」 표시가 없었다. 이름의 정본은 `web/lib/site-nav.js` 다.

   ⚠ **머리띠 아래 선에 붙여 그린다.** 탭이 선 위에 얹히고 켜진 것만 그 선을
   지우면 「지금 이 서랍이 열려 있다」가 모양으로 읽힌다 — 색만 바꾸면 그냥 다른
   색 글자다. 그래서 `.bg3-header` 의 `border-bottom` 자리로 1px 내려 앉힌다. */
.bg3-header nav.sitetabs {
  margin: 18px auto -19px;      /* -19px = 머리띠 아래 여백(18) + 선(1) */
  display: flex; gap: 4px;
  align-items: flex-end; justify-content: center; flex-wrap: wrap;
  position: relative; z-index: 1;
}
.sitetab {
  padding: 8px 20px 7px;
  font-size: 13px; letter-spacing: .1em; text-decoration: none;
  color: var(--gold-dim);
  border: 1px solid var(--line);
  border-bottom-color: var(--line);
  border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, .18), rgba(0, 0, 0, .42));
  transition: color .12s, background .12s;
}
.sitetab:hover { color: var(--gold); background: rgba(0, 0, 0, .3); }
/* ⚠ **켜진 탭의 정본은 `aria-current` 다.** 클래스로 표시하면 화면 읽어 주는
   프로그램에는 아무 말도 안 한 것이 되고, 그러면 「보이는 것」과 「읽히는 것」이
   갈린다. 하나를 두 곳에 적지 않는다. */
.sitetab[aria-current="page"] {
  color: var(--gold);
  background:
    radial-gradient(120% 180% at 50% 0%, rgba(200, 162, 76, .16), transparent 70%),
    linear-gradient(180deg, rgba(0, 0, 0, .1), rgba(0, 0, 0, .5));
  border-color: var(--edge);
  border-bottom-color: transparent;   /* 아래 선을 지워 본문과 이어 붙인다 */
  cursor: default;
}

/* 스포일러 스위치는 카테고리가 아니라 **설정**이다 — 탭 줄 밖에 둔다. */
.bg3-header > .spoilerfree { margin-top: 14px; }

/* ── 프로필 화면 ────────────────────────────────────────────────────── */
.profilepane { margin: 0 0 14px; }
.profilepane .account { justify-content: flex-start; }
.clouddocs { list-style: none; margin: 10px 0 0; padding: 0; }
.clouddocs li {
  display: flex; justify-content: space-between; gap: 12px; align-items: baseline;
  padding: 8px 4px; border-bottom: 1px solid var(--line);
}
.clouddocs li:last-child { border-bottom: 0; }
/* 아직 계산에 안 들어간 특성. **흐리게 두되 안 감춘다** — 감추면 「없는 것」이 된다. */
.feat.dim { opacity: .62; border-style: dashed; }
/* 쌓이는 상태의 조건 한 줄. 이름 밑에 붙어 「왜 안 터지나」를 말한다. */
.stackhint { margin: 2px 0 6px 0; font-size: 12px; color: var(--gold-dim); line-height: 1.5; }
.cdname { color: var(--gold); }
.cdmeta { color: var(--gold-dim); font-size: 12px; white-space: nowrap; }
/* 레벨마다 붙이는 설명. `textarea` 는 요소 단위 규칙을 이미 받는다 —
   여기서는 폭과 세로 늘이기만 정한다. */
.lvnote { width: 100%; box-sizing: border-box; resize: vertical; min-height: 3.2em;
  font-family: inherit; font-size: 13px; line-height: 1.6; }
/* 남은 글자 수. 머리줄 오른쪽 끝에 붙여 **잘리기 전에** 보이게 한다. */
.lvnoteleft { margin-left: auto; }

/* 클라우드 목록에서 「게시판에 올라감」 표시와 내리는 단추. */
.cdpub { color: var(--gold-dim); font-size: 11px; border: 1px solid #3a3020;
  border-radius: 3px; padding: 0 4px; }
.cdtake { font-size: 11px; padding: 1px 6px; }

/* 게시판 거르개 한 줄. 좁은 화면에서는 접혀 내려간다 — 가로로 밀리면 못 쓴다. */
.boardfilter { flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.boardfilter input[type="search"] { flex: 1 1 160px; min-width: 0; }
/* 게시판 미리보기 한 줄 — 「노움 · 몽크 9 / 도적 3 · 총 12레벨」.
   ⚠ `nowrap` 을 안 준다. 이름이 길면 줄이 넘치는 게 잘리는 것보다 낫다. */
.cdsum { color: var(--gold-dim); font-size: 12px; line-height: 1.5; }
/* 저장할 때 생기는 갈래. 본문 맨 위에 온다(머리말이 아니다). */
.bg3-main > .notice { max-width: 560px; margin: 0 auto 12px; }
.bg3-main > .notice:empty { display: none; }
.bg3-main > .notice p { margin: 0 0 8px; font-size: 13px; color: var(--gold-dim); }
.bg3-header .spoilerfree {
  display: inline-flex; align-items: center; gap: 4px; font-size: 13px;
  color: var(--gold-dim); cursor: pointer; user-select: none;
}
/* 계정 자리. ⚠ **비어 있을 때 자리를 안 차지한다** — 클라우드가 없는 판에서는
   끝까지 비므로, `margin` 을 늘 주면 머리말 밑에 이유 없는 틈이 생긴다.
   `:empty` 가 그것을 막는다(`hidden` 을 쓰면 `display:flex` 가 이긴다 — 아래
   `[hidden]` 규칙의 주석 참고). */
/* ⚠ **머리말에 매지 않는다.** 계정 자리는 프로필 화면으로 옮겼다 — `.bg3-header`
   밑으로 한정해 두면 그 화면에서 규칙이 통째로 안 먹고, 그건 **마크업은 있는데
   모양이 없는** 조용한 실패다(이 저장소가 `[hidden]` 으로 네 번 데인 것과 같은 꼴). */
.account {
  margin: 12px auto 0; display: flex; gap: 10px;
  align-items: center; justify-content: center; flex-wrap: wrap;
}
.account:empty, .adopt:empty { display: none; }
.acctname { color: var(--gold); font-size: 13px; letter-spacing: .08em; }
.acctbtn {
  font: inherit; font-size: 12px; letter-spacing: .06em;
  padding: 5px 12px; cursor: pointer;
  color: var(--gold-dim); background: rgba(0, 0, 0, .35);
  border: 1px solid var(--edge); border-radius: 2px;
}
.acctbtn:hover { color: var(--gold); border-color: var(--gold-dim); }
/* 가져오기 물음. 좁게 둔다 — 여기가 첫 로그인의 첫 화면이다. */
.adopt {
  margin: 12px auto 0; max-width: 460px; padding: 12px 16px;
  background: rgba(0, 0, 0, .4); border: 1px solid var(--edge); border-radius: 3px;
  display: flex; flex-direction: column; gap: 8px; align-items: center;
}
.adopt p { margin: 0; font-size: 13px; color: var(--gold-dim); }
.adopt .hint { font-size: 12px; opacity: .8; }

@media (max-width: 620px) {
  /* ⚠ 중단점은 다섯뿐이다 — 새 값을 더하면 tests/mobile.test.js 가 문다.
     560 을 적었다가 걸렸고, 그물이 옳다(화면마다 다른 폭에서 접히면 못 맞춘다). */
  .bg3-header { padding: 20px 14px 14px; }
  .bg3-header h1::after { height: 16px; }
}

h2.title {
  margin: 0 0 12px; font-size: 17px; font-weight: normal;
  color: var(--gold); text-align: center; letter-spacing: .12em;
}
h2.title::after {
  content: ''; display: block; height: 18px; margin: 4px auto 0; max-width: 260px;
  background: url('skin/Selected_Decor_Top.png') center/contain no-repeat;
}
h3.sub {
  margin: 18px 0 8px; font-size: 12px; font-weight: normal;
  color: var(--gold-dim); letter-spacing: .18em;
  border-top: 1px solid var(--line); padding-top: 10px;
}

/* ── 3단 배치. 게임 캐릭터 생성 화면과 같다 (왼쪽 단계 · 가운데 선택 · 오른쪽 요약) ── */
.bg3-main {
  display: grid; grid-template-columns: 210px minmax(0, 1fr) 320px;
  gap: 16px; padding: 16px; max-width: 1440px; margin: 0 auto; align-items: start;
}
@media (max-width: 1100px) { .bg3-main { grid-template-columns: 1fr; } }

/* ── 모바일: 세로 순서 (A2) ──────────────────────────────────────────────
   2026-08-07 실측(375px): 빌드 목록이 맨 위 719px 를 먹어서 탭줄이 1,002px 지점 ·
   캐릭터 요약(AC·명중·기대)이 2,167px 지점에 있었다. 폰에서 「지금 이 빌드가
   어떻다」를 보려면 세 번 쓸어 내려야 했다.

   **마크업을 안 고친다** — CSS order 로만 바꾼다. 그래야 렌더 스냅샷이
   「데스크톱 산출물은 바이트까지 같다」를 증명할 수 있다.

   ⚠ order 의 기본값은 0 이라 **안 적은 형제가 맨 앞으로 간다.** .bg3-main 의
   자식에는 각주 <p class="footnote"> 둘도 있어서 그것까지 적어야 한다.
   ⚠ 빌드를 안 골랐을 때 #editor·#summary 는 hidden 이라 격자 자리를 안 먹는다 —
   그때는 목록만 뜬다(실측 확인). */
@media (max-width: 720px) {
  /* #coverage 는 파티 화면의 요약이다(파티 상태). 안 적으면 order 기본값 0 으로
     **우연히** 맨 앞에 온다 — 우연을 의도로 바꿔 적는다. */
  #summary, #coverage { order: 1; }
  #editor { order: 2; }
  .bg3-main > .buildlist { order: 3; }
  .bg3-main > .footnote { order: 4; }

  /* 요약을 통째로 위에 두면 733px 이라 탭줄이 또 한 화면 아래로 밀린다.
     정보를 **감추지 않고** 높이만 묶는다 — 스크롤하면 다 있다. */
  #summary { max-height: 40vh; overflow-y: auto; }

  /* 탭줄을 위에 붙인다 — 패널을 훑는 동안 탭이 화면 밖으로 안 나간다.
     ⚠ `--bg` 라는 변수는 없다(실측). 탭줄은 #editor.pane 안에 있고 그 판의 배경이
     #221c15cc 다 — **알파를 뗀** 같은 색을 쓴다. 반투명이면 아래 내용이 비친다. */
  #tabs { position: sticky; top: 0; z-index: 20; background: #221c15; }
}

/* ── ④ 「빌드 한눈에」 ─────────────────────────────────────────────────
   전폭 탭. 세 칸 격자를 한 칸으로 바꾸고 좌우 aside 를 닫는다.
   hidden 이 아니라 display:none 인 이유는 renderSummary 가 hidden 을 다시 켜서다. */
.bg3-main.wide { grid-template-columns: minmax(0, 1fr); }
.bg3-main.wide #summary { display: none; }
/* ⚠ **왼쪽 칸을 통째로 닫으면 안 된다.** 그 aside 안에는 빌드 목록만이 아니라
   새 빌드·내보내기·불러오기·진행 단계가 다 들어 있다 — 통째로 닫으면 이 사이클이
   만든 「내보내기를 누르면 이 화면이 뜬다」를 **정작 이 화면에서 못 누른다**(리뷰 m-1).
   목록과 진행 단계만 접고 단추는 남긴다. */
.bg3-main.wide .buildlist { max-width: 210px; }
.bg3-main.wide .buildlist > h2, .bg3-main.wide #builds, .bg3-main.wide #steps { display: none; }

.glance { --gline: #3b3122; --gsub: #8d7439; }
.ghead { display: flex; align-items: flex-start; gap: 18px; padding: 2px 6px 0; flex-wrap: wrap; }
.gportrait img { width: 74px; height: 74px; border: 1px solid var(--line); }
.gwho { flex: 1; min-width: 12rem; }
.gwho .n { font-size: 25px; color: var(--gold); letter-spacing: .08em; line-height: 1.2; }
.gwho .l { margin-top: 4px; font-size: 13px; color: var(--muted); }
.gwho .l.dim { font-size: 12px; color: var(--faint); }
.gtiles { display: flex; gap: 8px; flex: none; }
.gtile { min-width: 92px; text-align: center; padding: 9px 12px; border: 1px solid var(--line); background: #16110c; }
.gtile .k { font-size: 10px; color: var(--muted); letter-spacing: .12em; }
.gtile .v { font-size: 27px; color: var(--gold); line-height: 1.2; font-variant-numeric: tabular-nums; }
/* ④ 「턴당 기대」는 확률을 감안한 값이라 「맞으면 얼마」와 「얼마나 자주」가 안 보인다.
   그 둘을 **늘 나란히** 둔다 — 범위만 떼면 명중률 30% 공격이 세 보인다. */
.grange { margin: 8px 6px 0; font-size: 13px; color: var(--cream); }
.grange .who { color: var(--gold-dim); margin-right: 8px; }
.grange.none { color: var(--faint); font-size: 12px; }
/* 구분선. 색 그라디언트를 **먼저** 깔고 게임의 덩굴 장식을 그 위에 얹는다 —
   자산이 없으면 예전과 똑같은 한 줄이 남는다(이 파일 머리말의 규칙).
   ⚠ 높이를 1px 로 두면 그림이 보일 자리가 없다. 장식이 들어갈 만큼만 키운다. */
.gdivider {
  height: 12px; margin: 14px 0;
  background:
    url('skin/divider.png') center / contain no-repeat,
    linear-gradient(90deg, transparent, var(--gold-dim), transparent) center / 100% 1px no-repeat;
}

/* ⚠ **기본이 1열이고 넓을 때 3열이다**(`min-width`). 반대로 적으면 안 된다 —
   아이템 화면(`style.css` 의 `.vgrid`)이 `min-width: 1240px` 을 쓰는데 여기가
   `max-width: 1240px` 이면 **정확히 1240px 에서 둘 다 참**이라, 그 한 픽셀에서만
   아이템 화면은 3열인데 이 화면은 1열이 된다. 실측(2026-08-09, iframe 으로 폭을
   고정해서 잼): 1239 → 둘 다 1열 · **1240 → vgrid 3열인데 gcols 1열** · 1241 →
   둘 다 3열. 같은 값을 쓰는 두 규칙은 **부등호 방향도 같아야** 한다. */
.gcols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; align-items: start; }
.gsec { font-size: 11px; color: var(--gold-dim); letter-spacing: .22em;
  border-bottom: 1px solid var(--line); padding-bottom: 6px; margin: 18px 0 10px; }
.gcol > .gsec:first-child { margin-top: 0; }
.gabils { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px; text-align: center; }
.gabils .k { font-size: 10px; color: var(--muted); }
.gabils .v { font-size: 20px; font-variant-numeric: tabular-nums; }
.gabils .m { font-size: 11px; color: var(--gold-dim); }
.grows2 { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 16px; font-size: 12px; }
.grow { display: flex; white-space: nowrap; }
.grow .k { color: var(--muted); }
.grow .v { margin-left: auto; color: var(--gold); }
.unknown { color: var(--faint); font-style: italic; }
.gchips { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 6px; }
.gchip { display: inline-flex; align-items: center; gap: 7px; flex: none; white-space: nowrap;
  padding: 2px 9px; font-size: 12px; border: 1px solid var(--line); background: #1d1710; color: var(--muted); }
.gchip.picked { border-color: var(--gold-dim); background: #241c11; color: var(--gold); }
.gchip.res { padding: 4px 11px; }
.gchip .ci { width: 15px; height: 15px; display: block; flex: none; }
.gabils .ai { width: 18px; height: 18px; display: block; margin: 0 auto 1px; }
.grow .k { display: flex; align-items: center; gap: 5px; }
.grow .ri { width: 13px; height: 13px; display: block; flex: none; }
.gtile .ti { width: 18px; height: 18px; display: block; margin: 0 auto 2px; }
.gslot .frame img { width: 100%; height: 100%; display: block; }
.gchip .k { color: var(--muted); }
.gchip b { color: var(--gold); font-weight: normal; }
.gfoot { margin-top: 18px; font-size: 11px; color: var(--faint); line-height: 1.7; }
.gsub { font-size: 12px; color: var(--faint); margin: 8px 0 4px; }
.gsechead { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.gsechead .gsec { flex: none; }
.glegend { font-size: 11px; color: var(--faint); }
/* ⚠ `minmax(0, 1fr)` 이 **없으면 좁은 화면에서 페이지 전체가 벌어진다.**
   암묵 트랙의 기본은 `auto`(최대가 max-content)라, 줄 하나(.glv)의 max-content
   폭이 그대로 트랙 폭이 된다 — 칩이 안 줄바꿈된 채 옆으로 늘어선 길이다.
   실측(2026-08-08, 375px 기기): .glv 가 444px 이 되고 그게 .gcol → .pane →
   main 으로 번져 문서가 510px, 브라우저가 그만큼 **축소해서** 좌우가 안 고정된
   것처럼 보였다(사용자 제보 「좌우가 고정이 안 돼」). 트랙 최대를 1fr 로 묶으면
   컨테이너를 못 넘고, .glv .chips 의 `flex-wrap: wrap`(아래)이 그때부터 실제로
   먹는다 — 375px 에서 444 → 243.
   넓은 화면에서는 어차피 한 줄짜리 단일 열이라 보이는 것이 안 바뀐다. */
.glevels { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px; }
.glv { display: flex; align-items: center; gap: 10px; padding: 5px 0; border-bottom: 1px solid #241c11; }
.glv .n { width: 2rem; flex: none; text-align: center; color: var(--gold-dim); font-variant-numeric: tabular-nums; }
.glv .ic { width: 30px; height: 30px; flex: none; border: 1px solid var(--line); display: block; }
.glv .ic.new { border-color: var(--gold); box-shadow: 0 0 10px #c8a24c44; }
.glv .ic img { width: 100%; height: 100%; display: block; }
.glv .cls { width: 5.5rem; flex: none; font-size: 12px; color: var(--muted); }
.glv .chips { display: flex; flex: 1; min-width: 0; flex-wrap: wrap; gap: 5px; }
.gchip.star { border-color: var(--gold-dim); color: var(--gold); font-weight: 600; }

/* 장비 격자 — 등급 색이 테두리와 이름에 그대로 온다(web/lib/rarity.js). */
.gslots { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px 6px; }
.gslot { display: flex; flex-direction: column; align-items: center; gap: 3px; font-size: 10px; text-align: center; }
/* 「빌드 한눈에」의 장비 칸. 위 `.slotbtn .frame` 과 **같은 자산**이다 — 같은 것을
   두 화면이 다르게 그리면 안 된다(자원 아이콘에서 이미 겪었다). */
.gslot .frame {
  position: relative; width: 62px; height: 62px; border: 1px solid var(--line);
  background: #100c08 url('skin/features_slot_d.png') center / 100% 100% no-repeat;
}
.gslot .frame img { width: 100%; height: 100%; display: block; }
.gslot.empty .frame, .gslot.locked .frame { border-style: dashed; opacity: .5; }
.gslot.warn .frame { border-color: var(--warn); box-shadow: 0 0 10px #e0a03c44; }
.gslot .wm { position: absolute; right: 1px; bottom: 0; font-size: 12px; color: var(--warn); }
.gslot .lb { color: var(--faint); }
.gslot .it { line-height: 1.3; color: var(--cream); }
.gslot.empty .it, .gslot.locked .it { color: var(--faint); }

.geff { display: flex; gap: 8px; padding: 2px 0; font-size: 12px; }
.geff > span:first-child { flex: 1; }
.geff .src { color: var(--faint); font-size: 11px; white-space: nowrap; }
.geff > span:first-child { display: flex; align-items: center; gap: 6px; }
/* ⚠ **크기를 안 주면 게임 아이콘 원본 크기로 나온다**(64px 이상) — 한 줄짜리 목록에
   그게 들어가면 줄 높이가 통째로 무너진다(사용자 제보 2026-08-08 「이미지 너무 커」).
   같은 화면의 칩(`.gchip .ci`, 위)과 **같은 값**을 쓴다 — 나란히 놓이는 것들이라
   크기가 다르면 그것대로 눈에 걸린다. */
.geff .ci { width: 15px; height: 15px; display: block; flex: none; }
.gacts { display: flex; gap: 10px; font-size: 12px; }
.gact { flex: 1; min-width: 0; }
.gact .h { color: var(--gold-dim); font-size: 11px; margin-bottom: 4px; }
.gact .it { line-height: 1.5; }
.gact .it.none { color: var(--faint); }
.gpend .p { padding: 3px 0; border-top: 1px solid #241c11; font-size: 12px; }
.gpend.on .p b { color: var(--gold); }
.turnrange { display: block; padding: 1px 0 3px 46px; font-size: 11px; color: var(--muted); }
.gpend .src { display: block; color: var(--muted); font-size: 11px; }

/* ④ 내보내기 창은 「빌드 한눈에」를 품으므로 넓다. 격자는 그 폭에서 세 열이 안 되니
   한 열로 접는다 — 창 안에서까지 1560px 을 기대하지 않는다. */
#iodlg.wide { max-width: min(96vw, 1100px); width: min(96vw, 1100px); }
#iodlgglance { max-height: 52vh; overflow-y: auto; margin-bottom: 10px; }
#iodlgglance:empty { display: none; }
/* 넓은 화면에서만 여러 열로 편다. 기본이 1열이라 좁은 쪽은 규칙이 필요 없다.
   ⚠ 미디어 쿼리는 **우선순위를 안 올린다** — `#iodlg.wide .gcols`(id+class)가
   그냥 `.gcols`(class)를 이긴다. 그래서 창 쪽을 **같은 블록 안에서 다시** 적는다
   (안 적으면 창이 3열이 되어 1100px 안에서 가로로 샌다. 리뷰 m-2 가 겪은 자리다). */
@media (min-width: 1240px) {
  .gcols { grid-template-columns: 300px minmax(0, 1fr) 350px; }
  #iodlg.wide .gcols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
/* 좁은 폭: 머리의 타일 셋이 이름 옆에 못 붙는다 — 줄을 바꿔 3등분한다.
   ⚠ .gtiles 가 flex:none 이라 그냥 두면 **가로 스크롤이 생긴다**(실측 375px 에서
   442px 로 넘쳤다). 장비 격자도 4열이면 62px×4 라 이름이 뭉개져 2열로 줄인다. */
@media (max-width: 620px) {
  .ghead { gap: 12px; }
  .gtiles { flex: 1 0 100%; }
  .gtile { flex: 1; min-width: 0; padding: 8px 4px; }
  .gtile .v { font-size: 22px; }
  .gslots { grid-template-columns: repeat(2, 1fr); }
  .gacts { flex-wrap: wrap; }
  .grows2 { grid-template-columns: 1fr; }
  /* 바깥 여백도 줄인다 — 위 .pane 테두리 축소와 한 쌍이다(둘이 합쳐 132 → 56). */
  .bg3-main { padding-left: 8px; padding-right: 8px; }
}

/* ── 좁은 화면: 가로로 늘어선 줄을 **세로로 접는다** ─────────────────────
   ⚠ 이게 없으면 「빌드 한눈에」 탭에서 **페이지 전체가 벌어진다.** 375px 기기
   실측(2026-08-08): 레벨 진행 줄과 기술 줄이 안 접혀 문서가 510px 이 되고,
   브라우저가 그만큼 축소해 다른 탭으로 옮겨도 좌우가 375 로 안 돌아왔다
   (사용자 제보 「모바일에서 좌우가 고정이 안 돼」). 이건 「스크롤이 좀 생긴다」가
   아니라 **뷰포트 배율이 바뀌는** 문제라 눈에 크게 띈다.

   원인이 넷이고 넷을 다 접어야 375 로 떨어진다(하나씩 껐다 켜며 실측):
     .glevels 트랙(위 그 줄)   510 → 444 로만 줄고 남음
     .glv 줄바꿈               444 → 416
     .geff·조건부 긴 토큰      416 → 375  ← 여기서 문서가 뷰포트에 맞는다
     .gchip 긴 글              칩 하나가 칸보다 길 때 (「★ 추가 공격 …」)

   ⚠ **720px 는 mobile.css 의 경계와 같은 값이다.** 하단 탭 바가 거기서 켜지므로
   갈리면 「탭 바는 떴는데 본문은 데스크톱 배치」인 구간이 생긴다. */
@media (max-width: 720px) {
  /* 레벨 진행 줄: 번호·아이콘·클래스는 한 줄에, 칩은 그 아래 줄 전체를 쓴다. */
  .glv { flex-wrap: wrap; row-gap: 4px; }
  .glv .chips { flex: 1 1 100%; }
  .glv .cls { width: auto; }
  /* 칩 하나가 칸보다 길 수 있다 — 게임 글을 그대로 싣는 칩(★)이 그렇다. */
  .gchip { white-space: normal; overflow-wrap: anywhere; max-width: 100%; }
  /* 「기술 — 준 아이템」 줄: 출처를 아랫줄로 내린다. */
  .geff { flex-wrap: wrap; }
  .geff .src { flex-basis: 100%; text-align: left; }
  /* 조건부 원문은 `SizeEqualOrGreater(Size.Large)` 처럼 띄어쓰기가 없다 —
     안 끊으면 한 낱말이 칸을 통째로 넘긴다. */
  .glance .p, .gpend .p { overflow-wrap: anywhere; }
}

/* ── 탭 ── */
.tabs { display: flex; gap: 2px; flex-wrap: wrap; margin-bottom: 10px; }
.tab {
  font: inherit; font-size: 13px; cursor: pointer; color: var(--muted);
  background: #1a150f; border: 1px solid var(--line); border-bottom-color: transparent;
  padding: 6px 14px; letter-spacing: .06em;
}
.tab:hover { color: var(--cream); }
.tab[aria-selected="true"] { color: var(--gold); background: #2a2116; border-color: var(--gold-dim); }

/* 게임의 주 화면 탭 그림을 위에 얹는다(Buttons/tabNav_*).
   위 규칙이 색과 테두리를 이미 줬으므로 **자산이 없으면 그대로 색만 남는다** —
   이 파일 머리말의 규칙 그대로다.

   ⚠ **늘이지 않고 `border-image` 로 자른다.** 원본은 544×220 인데 아래 좌우에
   덩굴 장식이 있어서, `background-size: 100% 100%` 로 늘이면 그 덩굴이 납작해진다.
   모서리는 원본 비율로 두고 가운데만 늘여야 게임처럼 보인다.
   ⚠ **덩굴 장식까지 자르면 안 된다.** 원본은 544×220(2.5:1)인데 우리 탭은 70×44
   안팎이라, 장식 폭(좌우 110px = 원본의 20%)을 그대로 쓰면 좌우 띠만으로 탭 폭을
   거의 다 먹어 글자를 침범한다(실측). 그래서 **바깥 테두리만** 자르고 덩굴은
   가운데 늘임 구역에 남겨 흐릿하게 깔리게 둔다 — 게임 느낌은 남고 글자는 산다. */
@supports (border-image: url('skin/tabNav_default_d.png') 34 40 64 40 fill / 6px 10px 12px 10px stretch) {
  /* ⚠ **`border: none` 을 쓰면 안 된다.** `@supports (border-image: url(…))` 는
     **문법 지원 여부만** 보지 자산이 있는지는 안 본다 — 그림이 없어도 이 블록이
     적용된다. 테두리를 지우면 자산 없는 환경에서 탭 넷이 경계 없는 한 덩어리가
     되고(배경 대비 1.15:1), 이 파일 머리말의 「그림이 없으면 색만 남는다」가
     거짓이 된다. 기본 규칙의 테두리를 **그대로 두면** 그림이 그 위를 덮고,
     그림이 없을 때만 테두리가 드러난다. */
  .tab {
    background: #1a150f;
    border-image: url('skin/tabNav_default_d.png') 34 40 64 40 fill / 6px 10px 12px 10px stretch;
    padding: 9px 20px 11px;
  }
  .tab:hover { border-image-source: url('skin/tabNav_default_h.png'); }
  .tab[aria-selected="true"] {
    background: #2a2116;
    border-image-source: url('skin/tabNav_selected_d.png');
  }
  .tab[aria-selected="true"]:hover { border-image-source: url('skin/tabNav_selected_h.png'); }
  .tab:disabled, .tab[aria-disabled="true"] {
    border-image-source: url('skin/tabNav_default_disabled.png');
  }
  /* 그림에 이미 테두리가 있어서 칸 사이를 좁혀도 선이 겹쳐 보이지 않는다.
     ⚠ 0 으로 붙이지 않는다 — 위와 같은 이유로 그림이 없을 때 탭이 한 덩어리가 된다. */
  .tabs { gap: 1px; }
}
/* 좁은 화면: 탭 넷이 `만들기·장비·계산` + `빌드 한눈에` 로 **3+1 로 갈라져**
   둘째 줄이 거의 비어 있었다(실측 375px: 70·57·57 / 102). 2×2 로 두면 같은 두
   줄인데 칸이 고르고 손가락에도 넉넉하다.
   ⚠ **이 블록은 `.tabs` 기본 정의보다 뒤에 있어야 한다.** 미디어 쿼리는 특정성을
   안 올리므로, 앞에 두면 뒤따르는 `.tabs { display: flex }` 가 그냥 이긴다 —
   처음에 위쪽 620px 블록에 넣었다가 그렇게 조용히 안 먹었다(이 파일이 리뷰 m-2
   에서 이미 겪은 자리다, 아래 #iodlg.wide 주석 참고). */
@media (max-width: 620px) {
  .tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
  .tabs .tab { padding-inline: 6px; text-align: center; }
}

/* ── 만들기 탭의 절 탭 (.mktabs/.mktab) ────────────────────────────────────
   **여태 규칙이 하나도 없었다** — 어두운 껍데기 한복판에 브라우저 기본 버튼
   여섯이 떠 있었다(체크박스가 흰 상자로 남아 있던 것과 같은 종류의 사고다).
   전수로 재서 찾았다: 앱이 쓰는 클래스 284종 중 데스크톱 규칙이 없는 것이
   `.mktabs`·`.mktab` 이었다(`.mktab` 은 mobile.css 의 터치 대상 규칙만 있었다).

   ⚠ **주 탭(.tab)의 그림을 쓰지 않는다.** 이것은 그 **안쪽** 단계다 —
   같은 tabNav_* 을 입히면 층이 사라져 어느 쪽이 상위인지 안 보인다. 그래서
   이 파일이 이미 쓰는 **둘째 단계 어휘**(.acttab — 막별 계획의 1·2·3막)를
   그대로 따른다. 새 시각 언어를 만들지 않는다.

   ⚠ 그림 자산을 안 쓰므로 이 규칙은 게임 미설치 환경에서도 그대로 뜬다. */
.mktabs {
  display: flex; flex-wrap: wrap; gap: 3px;
  margin-bottom: 12px; border-bottom: 1px solid var(--line);
}
.mktab {
  font: inherit; font-size: 12px; cursor: pointer; color: var(--muted);
  background: #1e1a14; border: 1px solid var(--line); border-bottom: none;
  border-radius: 3px 3px 0 0;
  padding: 5px 13px; margin-bottom: -1px; letter-spacing: .05em;
}
.mktab:hover { color: var(--cream); }
.mktab[aria-selected="true"] {
  color: var(--gold); background: #2b2519; border-color: var(--gold-dim);
}
/* 네이티브 테두리를 지웠으므로 키보드 자리를 직접 준다(체크박스와 같은 이유). */
.mktab:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

/* ── 아이콘 격자. 게임의 선택 화면이 이 모양이다 ── */
.pickgrid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 10px 8px; margin-bottom: 4px;
}
.pickitem {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px 2px 4px; cursor: pointer; border: 1px solid transparent;
  background: none; color: var(--muted); font: inherit; font-size: 11px; text-align: center;
}
.pickitem .frame {
  width: 62px; height: 62px; display: grid; place-items: center;
  background: #100c08 url('skin/features_slot_d.png') center/100% 100% no-repeat;
  border: 1px solid var(--line);
}
.pickitem img { width: 48px; height: 48px; object-fit: contain; filter: brightness(.78) saturate(.7); }
.pickitem:hover { color: var(--cream); }
.pickitem:hover img { filter: none; }
.pickitem .noicon { color: var(--faint); font-size: 20px; }
/* ── 재주가 올린 능력치 고르기 ─────────────────────────────────────────
   여섯 능력치를 한 줄에 놓고 ± 로 점수를 나눈다. 남은 점수는 머리말에 뜬다. */
.abrow { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 6px; }
.abpick {
  display: flex; align-items: center; gap: 4px; padding: 4px 6px;
  border: 1px solid var(--line); background: #100c08; font-size: 11px; color: var(--muted);
}
.abpick.on { color: var(--gold); border-color: var(--gold); }
.abpick .ablabel { flex: 1; display: flex; align-items: center; gap: 4px; }
.abpick .abico { width: 16px; height: 16px; object-fit: contain; }
.abpick .abval { min-width: 22px; text-align: center; }
/* ⚠ 두 단추는  이 꾸미지만 **클래스마다 규칙이 있어야** 한다(그물이
   그렇게 요구한다) — 눌리는 자리를 넓혀 손가락으로도 되게 한다. */
.abplus, .abminus { padding: 0 6px; line-height: 1.4; min-width: 22px; }
.abpick .btn:disabled { opacity: .35; cursor: not-allowed; }

/* ── 일리시드 능력 나무 — 게임의 뇌 화면처럼 방사형 ────────────────────
   ⚠ 자리는 **서버가 준 고리·각도**에서 나온다. 여기서 배치를 다시 계산하지
   않는다 — 생산자가 둘이 되면 게임 데이터가 바뀔 때 조용히 갈린다. */
/* 바탕은 **게임 자산 그대로**다(`Public/Game/GUI/Assets/TadpoleTree/`):
     IllithidAbstract_BG  붉은 안개
     Default_Brain        뇌

   ⚠ **자산이 없어도 화면이 선다.** `web/skin/` 은 빌드 산출물이라 게임이 안 깔린
   환경에는 없다 — 그래서 `radial-gradient` 를 **밑에 깔고** 그림을 그 위에 얹는다.
   그림이 없으면 예전 모습 그대로다(이 파일의 기존 원칙). */
.tadtree {
  position: relative; width: min(100%, 620px); aspect-ratio: 1; margin: 8px auto 12px;
  border-radius: 50%;
  background:
    url('./skin/Default_Brain.png') no-repeat 50% 48% / 78% auto,
    url('./skin/IllithidAbstract_BG.png') no-repeat 50% 50% / cover,
    radial-gradient(circle at 50% 50%, #1a1108 0%, #120c06 55%, transparent 72%);
}
/* ⚠ overflow:hidden 을 **안 건다.** 바깥 고리(r=47)의 칸이 원 밖으로 조금 나가는데
   자르면 그 칸이 반쪽이 된다. 배경은 border-radius 가 이미 잘라 준다. */
/* 뇌 위에 칸·선을 얹으니 그림이 너무 세면 글이 안 읽힌다. 어둡게 깔아 둔다 —
   게임도 그 화면에서 뇌를 배경으로 눌러 놓는다. */
.tadtree::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(8,5,3,.35) 0%, rgba(8,5,3,.72) 70%);
  pointer-events: none;
}
/* 선이 칸 **아래**에 깔려야 한다. viewBox 가 0 0 100 100 이라 칸의 %(left/top)와
   같은 좌표계다 — 안 맞추면 선이 칸에서 떨어진다. */
.tadlines { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.tadlines line { stroke: var(--line); stroke-width: .35; }
.tadlines line.on { stroke: var(--gold); stroke-width: .6; }
.tadnode {
  position: absolute; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  /* ⚠ 좁게 둔다 — 방사형이라 칸이 붙어 있어서 넓으면 **이름끼리 겹친다.** */
  width: 74px; padding: 0; cursor: pointer;
  background: none; border: none; color: var(--muted); font: inherit; font-size: 9px;
  text-align: center;
}
.tadnode .frame {
  width: 52px; height: 52px; display: grid; place-items: center;
  background: #100c08 url('skin/features_slot_d.png') center/100% 100% no-repeat;
  border: 1px solid var(--line); border-radius: 50%;
}
.tadnode img { width: 38px; height: 38px; object-fit: contain; filter: brightness(.78) saturate(.7); }
.tadnode .noicon { color: var(--faint); font-size: 18px; }
.tadname { line-height: 1.15; }
.tadnode:hover:not(:disabled) { color: var(--cream); }
.tadnode:hover:not(:disabled) img { filter: none; }
.tadnode.on { color: var(--gold); }
.tadnode.on img { filter: none; }
.tadnode.on .frame { border-color: var(--gold); box-shadow: 0 0 8px rgba(200, 160, 80, .35); }
/* 선행을 아직 안 채운 칸. 흐리게 두되 **숨기지 않는다** — 무엇을 먼저 골라야
   하는지가 이 화면의 요점이라 안 보이면 길을 못 찾는다. */
.tadnode.locked { opacity: .4; cursor: not-allowed; }

/* 게임의 selector 자산은 흰색이라 웹에서 튄다. 금색 테두리로 대신한다. */
.pickitem.on { color: var(--gold); }
.pickitem.on img { filter: none; }
.pickitem.on .frame {
  border-color: var(--gold);
  box-shadow: 0 0 12px #c8a24c66, inset 0 0 14px #c8a24c22;
}
/* 다른 레벨에서 이미 고른 주문 — 두 번 배울 수 없어 한 칸이 버려진다.
   막지는 않는다, 테두리로만 알린다. .on 과 겹쳐도(이미 고른 것 자체가 중복일 때)
   구분되도록 .on 보다 뒤에 두어 우선한다. */
.pickitem.dup .frame {
  border-color: var(--warn);
  box-shadow: 0 0 12px #e0a03c66, inset 0 0 14px #e0a03c22;
}
.pickitem.dup:not(.on) { color: var(--warn); }

/* ── 고른 것의 설명 ── */
.gamedesc {
  display: flex; gap: 12px; align-items: flex-start;
  margin: 8px 0 4px; padding: 11px 13px;
  background: #16110c; border: 1px solid var(--line);
}
.gamedesc > img { width: 54px; height: 54px; flex: none; object-fit: contain; }
.gamedesc-name { color: var(--gold); font-size: 15px; margin-bottom: 2px; }
.gamedesc-body { line-height: 1.6; max-height: 11em; overflow-y: auto; }
/* 게임 용어. 게임 툴팁의 그 밑줄이다. */
.gamedesc .lstag { color: var(--gold); border-bottom: 1px dotted var(--gold-dim); cursor: help; }
/* 게임이 실행 중 계산해 넣는 값. 우리가 채울 수 없어 원문 그대로 둔다. */
.gamedesc .ph { color: var(--gold-dim); background: #241c11; padding: 0 4px; border-radius: 2px; }

/* ── 버튼 ── */
.btn {
  font: inherit; font-size: 13px; color: var(--cream); cursor: pointer;
  background: linear-gradient(#2c2318, #17110a); border: 1px solid var(--gold-dim);
  padding: 7px 20px; letter-spacing: .06em;
}
.btn:hover { color: var(--gold); border-color: var(--gold); }
.btn.primary { color: var(--gold); }
.btn.ghost { border-color: var(--line); padding: 4px 10px; font-size: 12px; }

input, select, textarea {
  font: inherit; color: var(--cream); background: #120e09;
  border: 1px solid var(--line); padding: 5px 8px;
}
input:focus, select:focus, textarea:focus { outline: 1px solid var(--gold-dim); }

/* 안내 글자(placeholder). **규칙이 없어서 브라우저 기본값이 나왔다** — 팔레트
   밖의 중성 회색이라 「빌드 이름」·「이름으로 검색」이 어두운 판 위에서 차갑게 떴다.
   `--faint` 는 이 파일이 쓰는 「읽히되 앞에 안 나서는」 색이다. */
input::placeholder, textarea::placeholder { color: var(--faint); opacity: 1; }
/* 누를 수 있다는 것을 색으로 말한다 — 옆에 선 .btn 이 그렇게 한다. */
input:hover, textarea:hover { border-color: var(--gold-dim); }

/* ── 고르기 칸(select) ── 난이도 고르기가 이것이다 ─────────────────────────
   **게임에는 이 컨트롤이 없다** — 그래서 자산이 아니라 **버튼 어휘**(.btn)를
   빌린다. 같은 줄에 나란히 서는 것이 저장 버튼이라서다(build.html:39-41).

   ⚠ `appearance: none` 이 네이티브 화살표까지 지운다. 쓸 그림 자산이 없으므로
   화살표를 **CSS 로 그린다**(사선 gradient 둘) — 이 파일 머리말의 「그림이
   없으면 색만 남는다」가 여기서는 「그림이 아예 안 걸린다」이므로, 자산 유무와
   무관하게 늘 뜨는 것이 옳다.
   ⚠ 열린 목록(option 팝업)은 OS 가 그린다 — CSS 로 못 닿는다. `color-scheme`
   으로 어둡게는 되지만 이 파일 58줄이 적어 둔 대로 판 색과는 안 맞는다.
   **모르는 것을 참으로 치지 않는다** — 닿는 데까지만 맞추고 여기 적어 둔다. */
select {
  appearance: none; -webkit-appearance: none;
  cursor: pointer; padding-right: 26px; border-color: var(--gold-dim);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--gold-dim) 50%),
    linear-gradient(135deg, var(--gold-dim) 50%, transparent 50%);
  background-position: right 13px center, right 8px center;
  background-size: 5px 5px;
  background-repeat: no-repeat;
}
select:hover {
  color: var(--gold); border-color: var(--gold);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--gold) 50%),
    linear-gradient(135deg, var(--gold) 50%, transparent 50%);
}

/* ── 왼쪽: 빌드 목록 ── */

/* 단추 세 개의 자리 (2026-08-11, 사용자: 「UI 위치가 뭔가 부자연스럽다」).
   ⚠ **규칙이 하나도 없었다** — `+ 새 빌드` 는 제 글자 폭만큼만 차지하고 아래
   두 개는 `.row` 로 왼쪽에 붙어서, 무게가 같은 단추 셋이 들쭉날쭉 흩어져 보였다.
   **주 동작 하나 + 보조 둘**로 무게를 갈라 세로로 쌓는다. 칸 폭이 210px 로
   고정이라 폭을 채우면 줄이 가지런해진다. */
.buildlist #newbuild {
  display: block; width: 100%; text-align: center;
  padding: 7px 10px; font-size: 13px; color: var(--gold);
}
.buildlist .buildio {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 6px;
}
.buildlist .buildio .btn { width: 100%; text-align: center; }

.buildlist ul { list-style: none; margin: 10px 0 0; padding: 0; }
.buildlist li {
  display: flex; align-items: center; gap: 6px; padding: 5px 8px; cursor: pointer;
  border-left: 2px solid transparent;
}
.buildlist li:hover { background: #ffffff08; }
.buildlist li.selected { border-left-color: var(--gold); color: var(--gold); background: #ffffff0a; }
.buildlist li span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.buildlist .del { border: none; background: none; color: var(--faint); cursor: pointer; font: inherit; }
.buildlist .del:hover { color: var(--warn); }

/* 반응 칸 (2026-08-11). **유지 칸과 다른 것이다** — 유지는 사람이 걸어 두는
   것이고 반응은 조건이 맞으면 터진다. 그래서 담기·빼기 단추가 없고, 대신 무엇을
   먹는지를 오른쪽에 적는다. 틀은 유지 칸과 같은 계열로 두어 「같은 종류의 칸」으로
   읽히게 한다. */
.reactions { margin-top: 14px; }
.reactionlist { list-style: none; margin: 8px 0 0; padding: 0; }
.reactionlist li {
  display: flex; align-items: center; gap: 6px; padding: 3px 0;
  border-bottom: 1px solid var(--line);
}
.reactionlist li:last-child { border-bottom: none; }
.reactioncost { margin-left: auto; font-size: 11px; color: var(--faint); white-space: nowrap; }

/* 단계 목록 */
.steps { list-style: none; margin: 14px 0 0; padding: 0; font-size: 12px; }
.steps li { display: flex; align-items: center; gap: 8px; padding: 4px 0; color: var(--muted); }
.steps .dot { width: 13px; height: 13px; border-radius: 50%; border: 1px solid var(--gold-dim); flex: none; }
.steps li.done { color: var(--cream); }
.steps li.done .dot { background: var(--gold); box-shadow: 0 0 6px #c8a24c88; }
.steps li small { margin-left: auto; color: var(--gold-dim); }
/* ④ 만들기 탭이 세로로 길어져서 왼쪽 목록을 목차로 쓴다. 절이 있는 줄만 누를 수 있다. */
.steps li.goto { cursor: pointer; }
.steps li.goto:hover { color: var(--gold); }

/* ── 오른쪽: 캐릭터 요약 ── */
.who { display: flex; gap: 12px; align-items: center; }
.who img { width: 56px; height: 56px; object-fit: contain; }
.who .n { color: var(--gold); font-size: 16px; }
.who .l { color: var(--muted); font-size: 12px; }

.abils { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px; margin: 12px 0 2px; }
.abils > div { text-align: center; }
.abils .k { font-size: 10px; color: var(--muted); }
.abils .v { font-size: 17px; color: var(--cream); font-variant-numeric: tabular-nums; }
.abils .m { font-size: 10px; color: var(--gold-dim); }
.abils img { width: 22px; height: 22px; opacity: .8; }

.summary-line { display: flex; gap: 8px; align-items: center; padding: 3px 0; font-size: 12px; }
.summary-line img { width: 26px; height: 26px; object-fit: contain; flex: none; }
.summary-line .lv { color: var(--gold-dim); width: 2em; text-align: right; }

/* ── 능력치 입력 ── */
.abilityrows { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 6px 14px; }
.abilityrow { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.abilityrow img { width: 26px; height: 26px; opacity: .85; }
.abilityrow input { width: 4rem; text-align: center; font-variant-numeric: tabular-nums; }
.abilityrow .mod { color: var(--gold-dim); font-size: 12px; width: 2.2em; }
#points { color: var(--muted); font-size: 13px; letter-spacing: 0; }
#points.over { color: var(--warn); }
/* 배분 점수 칸의 이름. 예전에는 숫자만 있어서 무엇의 29/27 인지 화면 어디에도
   적혀 있지 않았다(ability.js 의 POINTS_LABEL). */
.pointslabel { color: var(--muted); font-size: 13px; }
/* 초과 상태를 색 하나로만 알리지 않는다 — 색각 이상·모바일에서 안 보인다. */
.hint.over { color: var(--warn); }

/* ── 레벨 트랙 ── */
.levelrow {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid #241c11;
}
.levelrow .lv {
  width: 2rem; flex: none; text-align: center; color: var(--gold-dim);
  font-variant-numeric: tabular-nums; padding-top: 4px;
}
.levelrow .lvicon { width: 34px; height: 34px; flex: none; object-fit: contain; }
.levelrow .lvpicks { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.levelrow .lvhead { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.lvinfo { display: flex; flex-wrap: wrap; gap: 8px; font-size: 12px; }
.lvinfo .gain { color: var(--muted); }
.choicebox { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.choicebox .picklabel { color: var(--gold-dim); font-size: 12px; }
.chip {
  font: inherit; font-size: 12px; padding: 1px 9px; cursor: pointer;
  background: #2a2419; border: 1px solid var(--line); color: var(--cream);
}
.chip:hover { border-color: var(--gold-dim); }

/* ── 장비 칸 ── */
/* 왼쪽에 칸 덩어리, 오른쪽에 정보. 게임 인벤토리의 구성이다. */
.equip { display: grid; grid-template-columns: minmax(0, 1fr) 220px; gap: 14px; }
@media (max-width: 900px) { .equip { grid-template-columns: 1fr; } }
.slots { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.weaponset {
  display: flex; align-items: center; gap: 8px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line);
}
.weaponset .setlabel {
  min-width: 3.5em; color: var(--gold-dim); font-size: 12px; letter-spacing: .08em;
}
.equipinfo { border: 1px solid var(--line); background: #16110c80; padding: 10px 11px; }
/* 낀 장비가 주는 효과. 갈래 이름 아래 문장이 오고, 줄 끝에 어느 장비에서 왔는지 적는다. */
.effgroup { margin-bottom: 8px; }
.effkind {
  display: block; font-size: 11px; color: var(--gold-dim);
  letter-spacing: .08em; margin-bottom: 2px;
}
.efflist { list-style: none; margin: 0; padding: 0; font-size: 12px; }
.efflist li { padding: 1px 0; line-height: 1.45; }
.efftext { color: var(--cream); }
.effsrc { color: var(--faint); font-size: 11px; }
.effunread { margin-top: 6px; font-size: 12px; }

/* 「아직 계산에 안 들어간 것」 목록. 위 `.effunread`(못 옮긴 원문)와 **다른 것**이다 —
   저쪽은 우리가 글로 못 옮긴 것이고, 이쪽은 **옮길 것도 없이 숫자에 안 들어간 것**이다.
   조용한 것보다 낫게 하려고 두는 자리라 눈에 띄되 경고처럼 붉지는 않게 둔다. */
.effoutside { margin: 4px 0 0; padding-left: 18px; font-size: 12px; color: var(--cream-dim); }
.effoutside li { margin: 2px 0; }
.effunread summary { color: var(--muted); cursor: pointer; }
.effunread ul { list-style: none; margin: 4px 0 0; padding: 0; }

/* 출처 페이지의 「맞춰 본 문서 전부 보기」. 화면에는 메인 페이지 셋만 보이고
   34개 문서 목록은 여기 접혀 있다 — 귀속은 남기고 화면은 깔끔하게. */
.srcall { margin-top: 10px; font-size: 12px; }
.srcall summary { color: var(--muted); cursor: pointer; }

/* 출신 탭의 오리진 고르기 줄. 배경 격자 위에 한 줄로 앉는다. */
.originrow { display: flex; gap: 10px; align-items: center; margin-bottom: 10px; }
.originrow select { flex: 1; min-width: 12rem; }
.effunread code { color: var(--faint); font-size: 11px; }
.proflist { list-style: none; margin: 0 0 8px; padding: 0; font-size: 12px; }
.proflist li { color: var(--cream); padding: 1px 0; }
/* 숙련 없는 것을 낀 칸. 막지는 않는다 — 우리가 못 읽는 숙련이 있다. */
.slotbtn.warn .frame { border-color: var(--warn); }
.slotbtn .frame { position: relative; }
.warnmark { position: absolute; right: 1px; bottom: 0; font-size: 12px; color: var(--warn); }
.notice {
  margin: 0 0 8px; padding: 6px 9px; font-size: 12px;
  border: 1px solid var(--gold-dim); background: #2b251980; color: var(--cream);
}
/* 「분류 안 됨」(고르는 칸)과 「이름 없음」(목표 성질 칸·피해 속성 칸,
   web/lib/target-labels.js) 이 같은 옷을 입는다 — 둘 다 "이 값을 못 찾았다" 는
   같은 성질이다. .dummytag·.dmgstate 는 .pickerlist 밖에 있어 원래 셀렉터가
   안 닿으므로 셀렉터만 넓힌다(선언은 그대로 — .pickerlist .unsorted 쪽 렌더링은
   안 바뀐다). .dmgstate 는 지금 데이터로는 13/13 전부 이름이 있어 이 배지가 실제로
   그려질 일이 없지만(target-labels.test.js 의 yaml 전수 그물), yaml 이 줄면
   스타일 없는 배지 대신 이 규칙을 그대로 받는다. */
.pickerlist .unsorted, .dummytag .unsorted, .dmgstate .unsorted { font-size: 11px; color: var(--faint); }
/* 막별 계획 고르기 창에서 「막을 모르는 것」 표시. 고른 막의 아이템과 섞여 뜨므로
   구별이 없으면 전부 그 막에 나온다고 읽힌다(build.js 의 막모름안내). */
.pickerlist .actunknown { font-size: 11px; color: var(--gold-dim); }
/* .pickerlist 쪽은 li 가 display:flex; gap 을 이미 갖고 있어(아래 .pickerlist li)
   위 .unsorted 배지가 이름과 절로 떨어진다. .dummytag·.dmgstate(둘 다 <label>) 는
   그 껍데기가 없어 <span>이름</span><span class="unsorted">…</span> 이 공백 없이
   그대로 붙어 "CONSTRUCT이름 없음"으로 읽혔다 — 이 규칙이 그 틈을 준다(.st-stat·
   .st-cost 와 같은 인라인 칩 옷). */
.dummytag { display: inline-flex; align-items: center; gap: 4px; }
/* 피해 속성 칸. .dummytag 와 같은 인라인 칩 옷을 쓰되 <select> 가 들어가야 해서
   따로 둔다 — .dummytags 를 넓히면 목표 성질 체크박스 쪽 렌더링까지 흔들린다. */
.dummydmg { display: flex; flex-wrap: wrap; gap: 6px 10px; }
.dmgstate { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; }
.slotbtn {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px 4px; cursor: pointer; font: inherit; font-size: 11px;
  background: none; border: 1px solid transparent; color: var(--cream);
}
/* 장비 칸의 틀. **고르기 격자(`.pickitem .frame`)와 같은 자산을 쓴다** — 둘 다
   「게임의 칸」이라 어휘가 갈리면 안 된다. 색·테두리를 먼저 주므로 자산이 없으면
   예전의 1px 상자가 그대로 남는다. */
.slotbtn .frame {
  width: 66px; height: 66px; display: grid; place-items: center;
  border: 1px solid var(--line);
  background: #100c08 url('skin/features_slot_d.png') center / 100% 100% no-repeat;
}
.slotbtn:hover .frame { background-image: url('skin/features_slot_h.png'); }
.slotbtn .frame img { width: 100%; height: 100%; object-fit: contain; }
.slotbtn:hover .frame { border-color: var(--gold-dim); }
.slotbtn .slotlabel { color: var(--faint); }
.slotbtn .slotitem { color: var(--cream); max-width: 100px; overflow: hidden; text-overflow: ellipsis; }
.slotbtn.empty .slotitem { color: var(--faint); }
/* 양손 무기가 잠근 보조 칸 — 고를 수 없지만 왜 잠겼는지 title 로 알 수 있다. */
.slotbtn.locked { cursor: default; opacity: .5; }
.slotbtn.locked .frame { border-style: dashed; }

/* 장비 아래에 붙는 인벤토리 격자. 위는 지금 낀 것, 아래는 노릴 것. */
.equipsep {
  margin: 16px 0 10px; padding-top: 10px; border-top: 1px solid var(--line);
  color: var(--faint); font-size: 12px; letter-spacing: .05em;
}
.acttabs { display: flex; gap: 4px; margin-bottom: 8px; }
.acttab {
  padding: 4px 12px; font: inherit; font-size: 12px; cursor: pointer;
  background: #1e1a14; border: 1px solid var(--line); border-bottom: none;
  border-radius: 3px 3px 0 0; color: var(--muted);
}
.acttab.on { color: var(--cream); border-color: var(--gold); background: #2b2519; }
.acttab .n { color: var(--faint); }
.baggrid { display: flex; flex-wrap: wrap; gap: 6px; }
.bagcell {
  width: 52px; height: 52px; padding: 3px; cursor: pointer; font: inherit;
  background: #100c08; border: 1px solid var(--line); color: var(--faint);
  display: grid; place-items: center;
}
.bagcell img { width: 100%; height: 100%; object-fit: contain; }
.bagcell:hover { border-color: var(--gold-dim); }
.bagcell.on { border-color: var(--gold); box-shadow: 0 0 8px #c8a24c55; }
.bagcell.stale { border-style: dashed; }
.bagdetail {
  margin-top: 8px; padding: 8px 10px; min-height: 52px;
  border: 1px solid var(--line); background: #16110c80;
}
.bagdetail .nm { display: block; }
.bagdetail .where { display: block; font-size: 11px; color: var(--muted); line-height: 1.45; }
/* 이 막에 입수 행이 없어 딴 막까지 넓혀 온 줄의 앞머리(「2막 — 」). 뒤따르는
   장소보다 밝게 둔다 — 이 줄에서 제일 먼저 읽어야 하는 것이 「이 막이 아니다」다. */
.bagdetail .whereact { color: var(--gold-dim); font-weight: 600; }
.bagdetail .note { display: block; font-size: 11px; color: var(--gold-dim); }
.bagdetail .btn { margin-top: 6px; }

/* ── 고르기 창 ── */
dialog.picker {
  width: min(52rem, 94vw); max-height: 84vh; color: var(--cream);
  background: #16110c; border: 1px solid var(--gold-dim); padding: 18px 20px;
}
dialog.picker::backdrop { background: #000000b0; }
dialog.picker h3 { margin: 0 0 10px; color: var(--gold); font-weight: normal; }
dialog.picker .row { display: flex; gap: 8px; align-items: center; margin: 8px 0; flex-wrap: wrap; }
.pickerlist { list-style: none; margin: 8px 0; padding: 0; max-height: 42vh; overflow: auto; }
.pickerlist li {
  display: flex; gap: 8px; align-items: center; padding: 4px 7px; cursor: pointer;
}
.pickerlist li:hover { background: #ffffff0d; }
.pickerlist .rarity { margin-left: auto; font-size: 11px; color: var(--muted); }
.pickerlist .where { font-size: 11px; color: var(--faint); }

.hint { color: var(--faint); font-size: 12px; }
.hint.warn { color: var(--warn); }
.saved { color: var(--gold-dim); font-size: 12px; }
.footnote {
  grid-column: 1 / -1; text-align: center; color: var(--faint); font-size: 11px;
  line-height: 1.7; padding: 6px 16px 20px;
}

/* ── 출처와 라이선스 화면 ── */
/* 읽는 화면이라 한 칸이다. 폭을 재는 것은 글줄 길이(65~75자)이지 격자가 아니다. */
.bg3-main.credits { grid-template-columns: minmax(0, 62rem); justify-content: center; }
/* ⚠ **`.bg3-main` 은 빌드 화면의 격자다**(210px · 본문 · 320px). 그 위에 한 칸짜리
   화면을 얹으면 판이 **왼쪽 210px 칸에 갇힌다** — 실제로 그랬다(프로필 첫 배포).
   출처 화면이 이미 같은 이유로 자기 modifier 를 갖고 있다. */
.bg3-main.narrow { grid-template-columns: minmax(0, 40rem); justify-content: center; }
.credits .pane + .pane { margin-top: 14px; }
.credits p { line-height: 1.75; margin: 0 0 8px; }
.credits .srclist {
  columns: 2; column-gap: 24px; margin: 10px 0 0; padding-left: 18px;
  font-size: 12px; line-height: 1.9;
}
.credits .srclist a { color: var(--dim); }
.credits .srclist a:hover { color: var(--gold); }
@media (max-width: 620px) { .credits .srclist { columns: 1; } }

/* ── 4인 파티 ── */
.partyslots { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
@media (max-width: 900px) { .partyslots { grid-template-columns: repeat(2, 1fr); } }
/* 폰에서 2열은 칸이 117px 로 눌려 글이 279px 높이로 흐른다(2026-08-07 실측).
   시안도 파티원을 전폭 줄로 그린다. **기존 중단점 620 을 쓴다** — 새 중단점을
   만들지 않는다(tests/mobile.test.js 가 다섯으로 못박는다). */
@media (max-width: 620px) { .partyslots { grid-template-columns: minmax(0, 1fr); } }
.partyslot {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 12px 6px; cursor: pointer; font: inherit; font-size: 12px; text-align: center;
  background: #16110c80; border: 1px solid var(--line); color: var(--cream);
}
.partyslot:hover { border-color: var(--gold-dim); }
.partyslot .frame {
  width: 74px; height: 74px; display: grid; place-items: center;
  border: 1px solid var(--line); background: #100c08;
}
.partyslot .frame img { width: 64px; height: 64px; object-fit: contain; }
.partyslot .noicon { color: var(--faint); font-size: 22px; }
.partyslot .pname { color: var(--gold); font-size: 14px; }
.partyslot .pmeta { color: var(--muted); }
.partyslot .pclass { display: flex; align-items: center; gap: 5px; color: var(--cream); }
.partyslot .pclass img { width: 20px; height: 20px; object-fit: contain; }
.partyslot .pkind { color: var(--faint); font-size: 10px; letter-spacing: .1em; }
.partyslot.empty .pname { color: var(--faint); }
/* 없는 역할은 눈에 띄게 — 강제하지는 않고 알려만 준다. */
.summary-line.lack span:last-child { color: var(--warn); }
#companionchoices .pmeta { color: var(--muted); font-size: 10px; }

/* 게임 진행표에서 온 특성. 나무위키 안내문(.gain)과 눈에 띄게 구분한다. */
.lvfeats { display: flex; flex-wrap: wrap; gap: 6px; }
.lvfeats .feat, .lvchips .feat {
  display: inline-flex; align-items: center; gap: 5px; cursor: help;
  padding: 2px 9px 2px 4px; font-size: 12px; color: var(--cream);
  background: #1d1710; border: 1px solid var(--line);
}
.lvfeats .featicon, .lvchips .featicon { width: 18px; height: 18px; object-fit: contain; }

/* ── 레벨업 화면 ────────────────────────────────────────────────────────
   게임처럼 한 레벨씩 연다. 위는 가로 레벨 트랙, 아래는 그 레벨의 레벨업 패널. */
.lvtrack { display: flex; gap: 4px; flex-wrap: wrap; margin: 6px 0 14px; }
.lvstep {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 4px 3px; cursor: pointer; font: inherit; font-size: 11px;
  background: none; border: 1px solid transparent; color: var(--faint);
}
.lvstep .frame {
  width: 40px; height: 40px; display: grid; place-items: center;
  border: 1px solid var(--line); background: #100c08;
}
.lvstep .frame img { width: 32px; height: 32px; object-fit: contain; filter: brightness(.8); }
.lvstep.filled { color: var(--cream); }
.lvstep.filled .frame img { filter: none; }
.lvstep:hover .frame { border-color: var(--gold-dim); }
.lvstep.on { color: var(--gold); }
.lvstep.on .frame { border-color: var(--gold); box-shadow: 0 0 10px #c8a24c55; }

.lvpanel { border: 1px solid var(--line); background: #16110c66; padding: 12px 14px; }
.lvpanelhead { display: flex; gap: 12px; align-items: center; margin-bottom: 10px; }
.lvpanelhead .bigicon { width: 52px; height: 52px; object-fit: contain; }
.lvpanelhead .lvtitle { color: var(--gold); font-size: 16px; }
.lvpanelhead .btn { margin-left: auto; }

.lvblock { margin: 12px 0; }
.lvblockhead {
  display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px;
  border-bottom: 1px solid #241c11; padding-bottom: 3px;
}
.lvblockhead .what { color: var(--gold-dim); font-size: 12px; letter-spacing: .14em; }
/* 몇 개 골랐는지. 알려만 주고 막지는 않는다. */
.lvblockhead .cnt { margin-left: auto; font-size: 12px; color: var(--muted); }
.lvblockhead .cnt.done { color: var(--gold); }
.lvblockhead .cnt.over { color: var(--warn); font-weight: 700; }
.lvchips { display: flex; flex-wrap: wrap; gap: 6px; }
.pickgrid.small { grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px 6px; }
.pickgrid.small .frame { width: 50px; height: 50px; }
.pickgrid.small img { width: 40px; height: 40px; }

/* 꽉 찬 선택 칸. 고른 것 말고는 흐려서 '더 못 고른다' 가 눈에 보인다. */
.pickgrid.full .pickitem:not(.on) { opacity: .38; cursor: default; }
.pickgrid.full .pickitem:not(.on):hover img { filter: brightness(.78) saturate(.7); }
/* 꽉 찼는데 더 누르면 계수기가 한 번 튄다 — 조용히 씹으면 왜 안 되는지 알 수 없다. */
.lvblockhead .cnt.bump { color: var(--warn); transform: scale(1.25); transition: none; }
.lvblockhead .cnt { display: inline-block; transition: transform .25s, color .25s; }

/* ── 인게임 주문 툴팁 ────────────────────────────────────────────────────
   틀은 게임의 TT_full_bg 를 9-slice 로 늘려 쓴다 — 게임 툴팁이 쓰는 바로 그 그림이다.
   자산이 없으면 색과 테두리만 남는다. */
/* 폭을 뷰포트에 묶는다. 375px 화면에서 440px 상자는 오른쪽으로 넘친다(2026-08-07 실측).
   min() 이라 **데스크톱 값은 안 바뀐다** — 좁을 때만 걸린다. 16px 은 좌우 여백 8+8 이고,
   place() 가 left 를 최소 8 로 밀어 두는 것과 같은 값이다(spell-tooltip.js). */
.st-float { position: fixed; z-index: 50; width: max-content; max-width: min(290px, 100vw - 16px); pointer-events: none; }
/* 아이템 툴팁은 담는 것이 많아 더 넓다. */
.st-float:has(.tt) { max-width: min(440px, 100vw - 16px); }
.st {
  background: #17130d; border: 1px solid var(--gold-dim); border-radius: 6px;
  padding: 9px 11px; box-shadow: 0 8px 24px #000a;
}
/* 자르는 폭 16 = 모서리 둥근 정도(약 14px) + 금색 선. 그리는 폭도 16px 이라 모서리가
   1:1 로 나온다 — 늘리거나 줄이면 금색 선 굵기가 어긋난다.
   추출할 때 투명 그림자 여백(사방 60px)을 잘라냈기 때문에 이 숫자가 맞는다.
   그림자는 여기서 CSS 로 되살린다. */
@supports (border-image: url('skin/TT_full_bg.png') 16 fill / 16px stretch) {
  .st {
    background: none; border: 16px solid transparent; border-radius: 0; box-shadow: none;
    border-image: url('skin/TT_full_bg.png') 16 fill / 16px stretch;
    padding: 0;
    filter: drop-shadow(0 6px 16px #000c);
  }
}
.st-head { display: flex; align-items: flex-start; gap: 8px; }
.st-title { flex: 1; min-width: 0; }
.st-name { color: var(--cream); font-size: 14px; line-height: 1.3; }
.st-kind { color: var(--muted); font-size: 11px; margin-top: 1px; }
/* 게임은 아이콘을 오른쪽 위에 살짝 비쳐 보이게 둔다. */
.st-icon { width: 34px; height: 34px; flex: none; object-fit: contain; opacity: .9; }
.st-body { margin-top: 6px; color: var(--cream); font-size: 12px; line-height: 1.5; }
.st-body .lstag { color: var(--gold); border-bottom: 1px dotted var(--gold-dim); }
.st-body .ph { color: var(--gold-dim); background: #241c11; padding: 0 4px; border-radius: 2px; }

.st-stats, .st-foot {
  display: flex; flex-wrap: wrap; gap: 10px; margin-top: 7px; padding-top: 6px;
  border-top: 1px solid #2d2417; font-size: 11px; color: var(--cream);
}
.st-stat, .st-cost { display: inline-flex; align-items: center; gap: 4px; }
/* 점은 게임 아이콘을 쓰고, 없으면 색 동그라미로 되돌아간다. */
.st-dot {
  width: 12px; height: 12px; border-radius: 50%; flex: none;
  background-size: contain; background-repeat: no-repeat; background-position: center;
}
.st-dot.range { background-color: #6f6350; background-image: url('skin/ico_range.png'); }
.st-dot.save { background-color: #6f6350; background-image: url('skin/ico_roll_save.png'); }
.st-dot.action { background-color: #4f9d5a; }
.st-dot.slot { background-color: #3f8fd0; background-image: url('skin/ico_spellSlotTT.png'); }
.st-dot.conc { background-color: #6f6350; background-image: url('skin/ico_concentration.png'); }
.st-dot.ritual { background-color: #8d7439; }

/* 능력치: 굴린 값 + 보너스 = 최종. 게임도 이 셋을 나란히 보여준다. */
.abilityrow .bonus { width: 2em; text-align: right; color: var(--gold); font-size: 12px; }
.abilityrow .total { width: 2em; text-align: right; color: var(--cream); font-variant-numeric: tabular-nums; }
#points { display: inline-block; transition: color .2s, transform .2s; }
#points.over { color: var(--warn); transform: scale(1.12); }

.bonusrows { display: flex; gap: 12px; flex-wrap: wrap; }
.bonusrow { display: inline-flex; align-items: center; gap: 8px; }
.bonusrow .amt { color: var(--gold); font-size: 15px; width: 1.8em; text-align: right; }

/* ㉩ 퀘스트·이야기 영구 보상. 켜기 + (고르는 것이면) 능력치 고르기 + 값 문장.
   값 문장은 부스트 원문에서 파생된다 — web/lib/quest-bonus.js 의 값문장. */
.questrows { display: grid; gap: 4px; margin: 6px 0 2px; }
.questrow { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.questrow .qn { flex: 1; min-width: 10rem; }
.questrow .qv { color: var(--gold); font-size: 12px; font-variant-numeric: tabular-nums; }
.questrow .qwarn { color: var(--warn); cursor: help; }
.questsum { margin: 6px 0 0; color: var(--cream); font-size: 13px; }

/* ── 레벨업 확정 ── */
.lvconfirm {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 16px; padding-top: 12px; border-top: 1px solid #241c11;
}
.btn.levelup { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; padding: 8px 22px; }
.btn.levelup .uparrow { width: 22px; height: 22px; object-fit: contain; }
.btn.levelup.blocked { opacity: .45; cursor: default; }
.btn.levelup.blocked:hover { color: var(--cream); border-color: var(--gold-dim); }

/* 확정하면 잠깐 뜨는 표시. 게임의 레벨업 화살표를 쓴다. */
.levelup-flash {
  position: fixed; inset: 0; display: grid; place-content: center; justify-items: center;
  gap: 4px; z-index: 90; pointer-events: none; text-align: center;
  animation: levelup-pop 1.1s ease-out forwards;
}
.levelup-flash img { width: 120px; height: 120px; object-fit: contain; }
.levelup-flash .lv { font-size: 46px; color: var(--gold); line-height: 1; }
.levelup-flash .txt { font-size: 15px; color: var(--cream); letter-spacing: .3em; }
@keyframes levelup-pop {
  0%   { opacity: 0; transform: translateY(18px) scale(.9); }
  18%  { opacity: 1; transform: translateY(0) scale(1); }
  70%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-14px) scale(1.04); }
}

/* 고르기 창의 아이템 줄. 그림 → 이름 → 등급. */
.pickerlist li { gap: 10px; }
.pickerlist .itemicon {
  width: 40px; height: 40px; flex: none; display: grid; place-items: center;
  border: 1px solid var(--line); background: #100c08;
}
.pickerlist .itemicon img { width: 100%; height: 100%; object-fit: contain; }
.pickerlist .itemicon .noicon { color: var(--faint); }
.pickerlist .itemname { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 아이템 툴팁은 자체 껍데기(tooltip.css)를 갖고 있어 틀을 덧씌우지 않는다. */
.st-float .tt { max-width: min(420px, 100vw - 16px); }

/* 고르는 창의 아이템 툴팁은 짧게.
   아이템 화면의 툴팁은 입수처 서술을 다 보여주지만, 고를 때는 그게 화면을 넘긴다.
   막·방식·장소 태그만 남기고 서술과 플레이버는 감춘다 — 원문은 아이템 화면에 그대로 있다. */
.st-float .tt-acq-raw,
.st-float .tt-flavor { display: none; }
.st-float .tt-acq-line { margin: 3px 0; }
.st-float .tt { max-height: 78vh; overflow: hidden; }
.st-float .tt-body { max-height: 30vh; overflow: hidden; }

/* 종족이 주는 수치(이동 속도·숙련·저항). 특성 칩과 구분해 테두리만 다르게 준다. */
.lvchips .feat.boost { border-color: var(--gold-dim); color: var(--gold); }
.st-grants { gap: 8px; }
.st-grants .st-cost { color: var(--muted); }

/* 동료 빌드에서 잠긴 칸. 게임이 정해 둔 것이라 못 바꾼다 — 고른 것만 남긴다. */
.pickgrid.locked .pickitem { cursor: default; }
.hint.lock { border-left: 2px solid var(--gold-dim); padding-left: 8px; margin: 6px 0 10px; }
.buildlist .listicon { width: 20px; height: 20px; object-fit: contain; flex: none; }

.partyslot .gobuild { margin-top: 4px; text-decoration: none; }

/* 동료 초상은 사각형 그림이라 칸을 꽉 채운다 — 문양 아이콘처럼 여백을 두지 않는다. */
.partyslot .frame.portrait img,
.pickitem .frame.portrait img { width: 100%; height: 100%; object-fit: cover; filter: none; }
.who img.portrait { width: 56px; height: 56px; object-fit: cover; border: 1px solid var(--line); }
.buildlist .listicon.portrait { object-fit: cover; border-radius: 2px; }

/* 파티 칸 고르기 창. 빌드가 늘면 창이 화면을 넘쳐서 목록만 따로 스크롤한다. */
#picker #buildchoices { max-height: 22vh; overflow-y: auto; }
#picker #companionchoices { max-height: 46vh; overflow-y: auto; }

/* ── 계산 탭 ── */
.calcgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; margin: 10px 0; }
.calcstat {
  display: flex; flex-direction: column; gap: 2px; align-items: center;
  padding: 8px 6px; border: 1px solid var(--line); background: #16110c80;
}
.calcstat .k { font-size: 11px; color: var(--muted); letter-spacing: .08em; }
.calcstat .v { font-size: 18px; color: var(--cream); font-variant-numeric: tabular-nums; }

/* ── 행동 경제 ──
   아이콘은 게임 자산 그대로다(web/skin/res_*.png) — 행동은 녹색 원, 보조 행동은
   주황 삼각형, 대응은 분홍 별. 색으로 구분되는 그림이라 우리가 색을 덧입히지 않는다. */
.econbar, .slotbar { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.econ, .slotres {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border: 1px solid var(--line); background: #16110c80;
  font-size: 12px; color: var(--cream);
}
.econ.full, .slotres.full { border-color: #5a3a2a; color: var(--muted); }
.econicon { width: 16px; height: 16px; object-fit: contain; }
.econk { color: var(--muted); letter-spacing: .04em; }
.econv { color: var(--gold); font-variant-numeric: tabular-nums; }

.econnotes { list-style: none; margin: 6px 0; padding: 0; font-size: 12px; }
.econnotes li { padding: 3px 0; color: var(--muted); border-top: 1px solid #241c11; }
.econnotes li:first-child { border-top: none; }
.econnotes b { color: var(--gold-dim); font-weight: 600; }

/* 형상(다크 어지 슬레이어) 스위치. 켜면 공격 목록 자체가 갈리므로 핫바 바로 위에
   두고 눈에 띄게 한다 — 껐다 켰다가 무엇을 바꾸는지 붙어 있어야 보인다. */
.formtoggle {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 10px 0; padding: 8px 10px;
  border: 1px solid #5a3a2a; border-radius: 4px; background: #1a1109;
  cursor: pointer;
}
.formtoggle:has(input:checked) { border-color: var(--gold-dim); background: #251708; }
.formtoggle .formname { color: var(--gold-dim); font-weight: 600; }
.formtoggle .hint { margin: 0; font-size: 12px; }

/* ── 이 턴 ── */
.turnslots { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
.turnitem {
  font: inherit; cursor: pointer; text-align: left;
  display: grid; grid-template-columns: 40px 1fr auto; grid-template-rows: auto auto;
  gap: 2px 8px; align-items: center; padding: 6px 10px;
  background: #16110c80; border: 1px solid var(--gold-dim); color: var(--cream);
}
.turnitem:hover { border-color: var(--gold); }
.turnitem .frame { grid-row: 1 / 3; width: 40px; height: 40px; }
.turnitem .frame img { width: 100%; height: 100%; object-fit: contain; }
.turnname { font-size: 13px; }
.turncost { display: flex; gap: 6px; flex-wrap: wrap; }
.turndmg {
  grid-row: 1 / 3; grid-column: 3; font-size: 17px; color: var(--gold);
  font-variant-numeric: tabular-nums; padding-left: 6px;
}

/* ── 수식 펼치기 ──
   .turnrow 가 .turnitem(빼기 버튼)과 펼침 버튼을 한 줄에 둔다. .turnitem 자체가
   <button> 이라 그 안에 또 버튼을 넣을 수 없어서(HTML 이 버튼 중첩을 허용하지
   않는다) 형제로 뺐다 — .formula 는 flex-basis:100% 로 같은 줄에서 줄바꿈해
   버튼들 아래로 떨어진다. */
.turnrow { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.formula {
  flex-basis: 100%; min-width: 280px; max-width: 480px;
  padding: 8px 10px; border: 1px solid var(--line); background: #16110c80; font-size: 12px;
}
.frow { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px; padding: 2px 0; }
.flabel { min-width: 3em; color: var(--gold-dim); font-size: 11px; letter-spacing: .08em; }
/* 상태 셋. 적용은 보통 글자색(--cream), 미정은 조건 토글의 체크박스 accent-color
   와 같은 --gold-dim(같은 개념이니 같은 옷 — 위 .conds input 참고), 미구현은
   다른 흐린 글자들과 같은 --faint(흐리게). */
.term { color: var(--cream); }
.term.pending { color: var(--gold-dim); }
.term.unread { color: var(--faint); }

/* 미정 항을 눌러 목표 성질 절(.dummytags)로 스크롤한 뒤 한 번 깜빡여 강조한다
   (Task 10, calcClick 의 data-termgo 처리). 새 색을 만들지 않고 기존 강조색을
   쓴다 — .lvstep.on .frame·.bagcell.on 과 같은 글로우 값(#c8a24c 계열)이다. */
.flash { animation: term-flash 1.2s ease-out; }
@keyframes term-flash {
  0%, 100% { box-shadow: 0 0 0 0 #c8a24c00; }
  20% { box-shadow: 0 0 16px 4px #c8a24c88; }
}

.calcstat.big .v { font-size: 26px; color: var(--gold); }

/* ── 핫바 ──
   게임 화면 아래 그 막대다. 칸에 아이콘만 두고 이름은 툴팁으로 본다. 칸 틀·탭 그림은
   게임 자산 그대로(hotbarSlot, btn_hb_selected/unselected_d). 자산이 없으면
   background-image 가 비고 아래의 테두리·바탕색만 남는다 — 화면은 그대로 돈다. */
.hb {
  margin: 8px 0;
  background-image: url('./skin/bar_body.png');
  background-size: 100% 100%;
  padding: 10px 12px 0;
  border: 1px solid var(--line);
}
.hbslots {
  display: grid; grid-template-columns: repeat(auto-fill, 46px); gap: 4px;
  min-height: 46px;
}
.hbslot {
  position: relative; width: 46px; height: 46px; padding: 0; cursor: pointer;
  background: url('./skin/hotbarSlot.png') center/100% 100% no-repeat, #0d0a07;
  border: none;
}
.hbslot:hover { filter: brightness(1.25); }
.hbart { position: absolute; inset: 5px; }
.hbart img { width: 100%; height: 100%; object-fit: contain; }
/* 주문 레벨은 게임처럼 칸 귀퉁이 로마 숫자 그림으로 얹는다. */
.hblevel { position: absolute; top: 1px; right: 1px; width: 14px; height: 14px; }
/* 피해를 못 읽은 수단. 회색(못 씀)과 **다른 사실**이라 다른 자리·다른 모양이다. */
.hbunknown { position: absolute; top: 2px; left: 2px; font-size: 11px; line-height: 1;
  padding: 1px 3px; border-radius: 3px; background: #4a4230; color: #e8d9a0; }
/* 여는 조건을 못 정한 기술. ⚠ **`.hbunknown` 바로 밑에 쌓는다** — 네 귀퉁이가
   이미 다 찼다(오른쪽 위 주문 레벨 · 왼쪽 위 피해모름 · 왼쪽 아래 비용 ·
   오른쪽 아래 유지단추). 겹치면 둘 다 못 읽는다. */
.hbcond { position: absolute; top: 16px; left: 2px; font-size: 8px; line-height: 1;
  padding: 1px 2px; border-radius: 3px; background: #3a3550; color: #cfc4ea; }
/* 비용은 칸 아래 귀퉁이에 작은 자원 아이콘으로. 게임도 여기에 찍는다. */
.hbcost { position: absolute; left: 2px; bottom: 1px; display: flex; gap: 1px; }
.hbcosticon { width: 11px; height: 11px; object-fit: contain; }
.hbcosttxt { font-size: 8px; color: var(--muted); }
/* 못 쓰는 칸은 게임처럼 죽인다. 이유는 title 툴팁에 있다. */
.hbslot.off { cursor: not-allowed; }
.hbslot.off .hbart img { filter: grayscale(1) brightness(.5); }

/* 핫바 칸에 담기 단추를 얹으려면 격자 칸(hbslots 의 grid item)이 하나로 남아야
   한다 — hbslot 단추 옆에 형제로 그냥 붙이면 격자 칸이 늘어나 정렬이 밀린다.
   이 얇은 래퍼가 격자 칸을 그대로 하나로 유지한다. */
.hbslotwrap { position: relative; width: 46px; height: 46px; }
/* 유지 칸에 담는 단추. 오른쪽 아래 귀퉁이에 얹는다 — 나머지 세 귀퉁이는 이미
   찼다(오른쪽 위: 주문 레벨 배지 .hblevel, 왼쪽 위: 피해모름 배지 .hbunknown,
   왼쪽 아래: 비용 아이콘 .hbcost). */
.hbsustain {
  position: absolute; right: 0; bottom: 0; width: 14px; height: 14px; padding: 0;
  font: inherit; font-size: 11px; line-height: 13px; text-align: center; cursor: pointer;
  border: none; border-radius: 3px 0 0 0; background: #4a4230; color: #e8d9a0;
}
.hbsustain:hover { background: var(--gold-dim); color: #100c08; }

/* 유지 중인 효과 칸. 핫바 바로 위에 산다 — 담긴 것만 그린다. */
.sustain { margin: 0 0 .6rem; }
.sustainlist { display: flex; flex-wrap: wrap; gap: .35rem; list-style: none; margin: 0; padding: 0; }
.sustainlist li { display: flex; align-items: center; gap: .3rem; padding: .2rem .4rem;
  border: 1px solid var(--line); border-radius: .3rem; }
.sustainicon { width: 16px; height: 16px; object-fit: contain; }
.sustainconc { font-size: .75em; opacity: .75; }
.sustaindrop {
  font: inherit; font-size: .85em; line-height: 1; padding: 0 2px; cursor: pointer;
  background: none; border: none; color: var(--muted);
}
.sustaindrop:hover { color: var(--warn); }

/* 아래 탭. 게임의 Common · <클래스> · Items · Passives · Custom 그 줄이다. */
.hbtabs { display: flex; gap: 2px; margin-top: 8px; transform: translateY(1px); }
.hbtab {
  font: inherit; font-size: 11px; letter-spacing: .06em; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px; padding: 5px 14px;
  color: var(--muted); border: none;
  background: url('./skin/btn_hb_unselected_d.png') center/100% 100% no-repeat, #14100b;
}
.hbtab:hover { color: var(--cream); }
.hbtab.on {
  color: var(--gold);
  background: url('./skin/btn_hb_selected.png') center/100% 100% no-repeat, #241c11;
}
.hbtabico { width: 16px; height: 16px; object-fit: contain; }

.respip { display: inline-flex; align-items: center; gap: 3px; font-size: 10px; color: var(--muted); }
.respipimg { width: 12px; height: 12px; object-fit: contain; }

/* ── 계산 탭의 접는 설정 절 ─────────────────────────────────────────────
   계산 탭이 「설정 앱」처럼 읽히던 이유는 **설정이 결과보다 위에** 있어서였다
   (외부 검수, 2026-08-09). 본체는 자원 띠 → 핫바 → 이번 턴 + 결과로 두고, 목표
   설정과 판정 못 한 조건을 이 접기 둘로 내렸다.

   ⚠ **`.gfold`(빌드 한눈에)와 달리 데스크톱에서도 눌러 접힌다.** 저기는 「다 보는
   화면」이라 접히면 안 되지만, 여기는 **설정을 치워 두는 것이 목적**이라 그 반대다.

   ⚠ **요약 줄은 접혔을 때도 보인다.** 접어서 감추는 것은 **자세한 목록**이지
   「모르는 게 있다」는 사실이 아니다 — 판정 못 한 수가 접기 밖에 안 남으면
   「모르는 것을 참으로 치지 않는다」가 화면에서 사라진다. */
.calcfold { margin: 14px 0; border-top: 1px solid var(--line); padding-top: 8px; }
.calcfold > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: baseline; gap: 10px;
  min-height: 32px;
}
.calcfold > summary::-webkit-details-marker { display: none; }
.calcfold > summary::after { content: '▸'; color: var(--gold-dim); margin-left: auto; }
.calcfold[open] > summary::after { content: '▾'; }
.calcfold > summary:hover { color: var(--gold); }
.calcfold > summary:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.foldsum { color: var(--faint); font-size: 11px; letter-spacing: 0; }

.acslider { display: flex; align-items: center; gap: 10px; }

/* ── 미끄럼 막대 ── 금장 프레임 한복판에 회색 OS 위젯이 떠 있던 자리 ─────────
   `accent-color` 만으로는 트랙·손잡이가 OS 것 그대로다. 게다가 위쪽
   `input, select, textarea` 의 테두리·패딩까지 받아 **네이티브 슬라이더가 상자 안에
   든** 꼴이었다.

   ⚠ **쓸 자산이 없다.** `xpbar_*` 는 끝이 마감된 경험치 띠라 늘리면 그 마감이
   찌그러진다. 그래서 **색으로만** 그린다 — 이 파일 머리말의 「그림이 없으면 색만
   남는다」가 여기서는 처음부터 색뿐이라는 뜻이고, 게임 미설치 환경과 결과가 같다.

   ⚠ **트랙·손잡이는 벤더별로 선택자가 다르고 `,` 로 묶으면 통째로 버려진다** —
   한 브라우저가 모르는 선택자 하나가 규칙 전체를 무효로 만든다. 그래서 갈래마다
   따로 적는다(중복이 아니라 필수다). */
.acslider input[type="range"] {
  flex: 1; appearance: none; -webkit-appearance: none;
  height: 18px; padding: 0; border: none; background: none; cursor: pointer;
}
.acslider input[type="range"]:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.acslider input[type="range"]::-webkit-slider-runnable-track {
  height: 4px; background: #241c11; border: 1px solid var(--line);
}
.acslider input[type="range"]::-moz-range-track {
  height: 4px; background: #241c11; border: 1px solid var(--line);
}
/* 손잡이는 게임의 보석 모양을 색으로 흉내 낸다 — 마름모 + 금색 테두리. */
.acslider input[type="range"]::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 14px; height: 14px; margin-top: -6px;
  background: linear-gradient(#d8b463, #8d7439);
  border: 1px solid var(--gold); transform: rotate(45deg);
}
.acslider input[type="range"]::-moz-range-thumb {
  width: 12px; height: 12px; border-radius: 0;
  background: linear-gradient(#d8b463, #8d7439);
  border: 1px solid var(--gold); transform: rotate(45deg);
}
.acslider input[type="range"]:hover::-webkit-slider-thumb { box-shadow: 0 0 8px #c8a24c99; }
.acslider input[type="range"]:hover::-moz-range-thumb { box-shadow: 0 0 8px #c8a24c99; }
.acslider #acvalue, .acslider [data-savevalue] {
  min-width: 6em; text-align: center; color: var(--gold);
  font-size: 15px; font-variant-numeric: tabular-nums;
}

/* 판정 못 한 조건부. 켜면 참인 셈 치고 다시 계산한다 — 재주·전투 유파 목록과
   같은 칩 모양 대신 체크박스 목록으로 둔다, 조건식 원문이 함께 있어야 하니까. */
.conds { list-style: none; margin: 4px 0; padding: 0; }
.conds li { padding: 3px 0; border-top: 1px solid #241c11; }
.conds li:first-child { border-top: none; }
.conds label {
  display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 10px; row-gap: 2px;
  cursor: pointer; font-size: 12px;
}
.conds input[type="checkbox"] { accent-color: var(--gold-dim); }
/* 체크박스는 아래 전역 규칙이 게임 그림으로 갈아끼운다 — 위 accent-color 는
   `appearance` 를 못 끄는 환경에서의 되돌아갈 자리로 남겨 둔다. */
/* 조건과 효과를 시각적으로 가른다 — 조건은 굵게, 효과는 화살표를 붙여 "이런 조건 → 이런 효과" 로 읽힌다. */
.conds .cond { color: var(--cream); font-weight: 600; }
.conds .cond.raw { color: var(--muted); font-weight: 400; font-style: italic; } /* 못 옮긴 원문 — 흐리게 표시 */
.conds .eff { color: var(--muted); font-size: 11px; }
.conds .eff::before { content: '→ '; opacity: 0.6; }
dialog.picker { max-height: 88vh; overflow-y: auto; }

/* ── 접는 절 (panels/glance.js 의 절()) ────────────────────────────────────
   데스크톱에서는 늘 펴져 있고 모양이 안 바뀌어야 한다 — <details open> 의 삼각형만
   지우면 옛 <div class="gsec"> 와 같아 보인다. */
.gfold > summary {
  list-style: none;
  cursor: default;
  /* ⚠ **데스크톱에서는 눌러도 안 접혀야 한다.** list-style 만 지우면 삼각형은
     사라져도 <details> 의 토글은 살아 있어서, 제목을 클릭하면 절이 통째로 접힌다 —
     그런데 ▸/▾ 표식도 요약 줄도 모바일에서만 보이므로 「내용이 사라진」 모양이 된다.
     옛 <div class="gsec"> 는 눌러도 아무 일이 없었다(리뷰 I-5, 2026-08-07). */
  pointer-events: none;
}
.gfold > summary::-webkit-details-marker { display: none; }
/* 요약 줄은 **접혔을 때만** 보인다 — 펴져 있으면 내용이 그 말을 이미 하고 있다.
   ⚠ 폭에 안 걸린다. pointer-events 는 마우스만 막고 **키보드 활성화는 못 막는다**
   (<summary> 는 tabIndex 0 이라 Tab 으로 포커스가 가고 Enter 가 토글한다 — 리뷰
   확인). 데스크톱에서 그렇게 접히면 표식도 요약도 없어 「내용이 통째로 사라진」
   화면이 되고 되돌릴 길이 안 보인다. 그래서 **접힘의 표시는 폭과 무관하게** 둔다. */
.gfold:not([open]) > summary .gsum { display: inline; }
.gsum { display: none; color: var(--muted); letter-spacing: 0; font-size: 12px; }
/* 접혔다는 것과 되돌리는 법. 펴져 있을 때는 데스크톱에서 안 보인다(모양 불변). */
.gfold:not([open]) > summary::after { content: '▸'; margin-left: auto; color: var(--gold-dim); }
.gfold:not([open]) > summary { display: flex; align-items: baseline; gap: 10px; pointer-events: auto; cursor: pointer; }

@media (max-width: 720px) {
  /* 모바일에서만 접힌다. 375px 에서 이 화면은 세로 3,839px 이었다(2026-08-07 실측). */
  .gfold > summary {
    display: flex; align-items: baseline; gap: 10px;
    cursor: pointer; min-height: 44px;
    pointer-events: auto;      /* 모바일에서만 누를 수 있다 */
  }
  /* 모바일에서는 **펴진 절에도** 표식을 둔다 — 접을 수 있다는 것을 알려야 누른다. */
  .gfold[open] > summary::after { content: '▾'; margin-left: auto; color: var(--gold-dim); }
}

/* ── 체크박스 ── 게임 옵션 화면의 그것 ─────────────────────────────────────
   여태 네이티브였다 — 어두운 껍데기 한복판에 흰 상자가 떠 있었다.
   게임은 빈 상자(checkBox_*)와 체크 표시(ico_check_*)를 **따로** 두므로
   배경으로 상자를 깔고 `::after` 로 표시를 얹는다.

   ⚠ **색을 먼저 준다**(이 파일 머리말의 규칙). `appearance: none` 은 네이티브
   그림을 지우므로, 자산이 없으면 표시할 것이 아무것도 안 남는 사고가 난다.
   그래서 테두리·바탕색을 먼저 주고 켜졌을 때 **바탕을 금색으로** 바꾼다 —
   그림이 없어도 켜짐/꺼짐이 눈에 보인다. 그림이 있으면 그 위를 덮는다.

   자리마다 안 고치고 전역으로 두는 이유: 체크박스가 index.html·build.html·
   ability.js·calc.js·item-filter.js 다섯 곳에 흩어져 있다. 한 곳만 빠뜨리면
   그 화면만 흰 상자로 남는다. */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  position: relative; flex: none;
  width: 15px; height: 15px; margin: 0 4px 0 0; vertical-align: -2px;
  /* ⚠ **`padding: 0` 이 없으면 15px 네모가 안 나온다.** 위쪽 `input, select, textarea
     { padding: 5px 8px }` 가 여기까지 닿는다 — style.css:205 가 `.taggroup input` 에서
     이미 겪고 적어 둔 자리다. 게임의 네모난 상자 그림(`checkBox_d.png`)이 그
     직사각형으로 늘어난다.

     **브라우저 실측(2026-08-09, Chromium, build.html):** 같은 요소에서
     `padding: 0` → **15×15**, 되돌리면 **18×15**.

     ⚠ 한때 여기 「content-box 라 33×27 이 된다」고 적혀 있었는데 **틀렸다.**
     `build.html`·`party.html` 에 `* { box-sizing: border-box }` 가 없는 것은 맞지만
     (그 규칙은 style.css 에만 있고 index.html 만 싣는다), 체크박스는 **UA 스타일이
     border-box 를 준다.** 33×27 은 content-box 였다면 나왔을 값이고 실제로는 안 난다.
     고침 자체는 필요하지만 **근거의 수치는 재서 적어야 한다** — 추론으로 쓴 값이
     주석에 굳으면 다음 사람이 그걸 사실로 읽는다(외부 검수 지적).

     작은 것을 그릴 때는 물려받은 패딩을 먼저 지운다. */
  padding: 0;
  cursor: pointer;
  border: 1px solid var(--gold-dim); background-color: #14100b;
  background-image: url('skin/checkBox_d.png');
  background-size: 100% 100%; background-repeat: no-repeat;
}
input[type="checkbox"]:hover  { background-image: url('skin/checkBox_h.png'); }
input[type="checkbox"]:active { background-image: url('skin/checkBox_p.png'); }
input[type="checkbox"]:disabled {
  cursor: default; opacity: .55;
  background-image: url('skin/checkBox_disabled.png');
}
/* 켜짐 — 바탕색이 자산 없을 때의 신호고, 그림은 그 위에 얹힌다.
   ⚠ **밝기를 두 조건 사이에서 맞춰야 한다.** 원본 상자는 가운데가 투명이라 이 색이
   그대로 비친다 — 너무 밝으면 그 위에 얹는 금색 체크 표시를 삼키고(실측: `--gold-dim`
   에서 그랬다), 너무 어두우면 **자산이 없을 때** 켜짐/꺼짐이 거의 구분되지 않는다
   (실측: `#3a2f14` 은 꺼짐 `#14100b` 대비 1.44:1 로 비텍스트 최소 기준 3:1 의 절반).
   `#6b5518` 은 약 3.4:1 이면서 체크 표시도 산다 — 네 갈래(자산 유무 × 켜짐/꺼짐)를
   브라우저에서 나란히 놓고 골랐다. */
input[type="checkbox"]:checked { background-color: #6b5518; }
input[type="checkbox"]:checked::after {
  content: ''; position: absolute; inset: -20%;
  background: url('skin/ico_check_d.png') center / contain no-repeat;
}
input[type="checkbox"]:checked:hover::after { background-image: url('skin/ico_check_h.png'); }
/* 키보드로 옮겨 다닐 때가 안 보이면 안 된다 — 네이티브 테두리를 지웠으므로 직접 준다. */
input[type="checkbox"]:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

/* ── 장비 조합 비교 ── */
.setcmp { width: 100%; border-collapse: collapse; font-size: 12px; }
.setcmp td { padding: 4px 6px; border-top: 1px solid var(--line); }
.setcmp tr.now td { color: var(--cream); }
.setcmp .nm { color: var(--muted); }
.setcmp tr.now .nm { color: var(--gold); }
.setcmp .tag { color: var(--gold-dim); font-size: 11px; }
.setcmp .v { text-align: right; white-space: nowrap; }
/* 「못 읽은 항」·「없는 수단」은 값이 낮은 이유라 값 옆에 둔다 — 안 보이면
   사용자가 장비 탓으로 읽는다(equipment-sets.js 머리말). */
.setcmp .note { color: var(--warn); font-size: 11px; }

/* ── 장비 조합(세트) 줄 ── */
/* 계산 탭의 「조합 비교」가 이 조합들을 견준다. 만드는 자리가 없으면 그 절은
   영영 안 뜬다(equipment.js 의 조합줄 머리말). */
.setbar { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin: 6px 0 10px; }
.setbar .setlabel { color: var(--muted); font-size: 12px; }
.setbar .hint { font-size: 11px; color: var(--faint); }
.setchip {
  font: inherit; font-size: 12px; padding: 3px 10px; cursor: pointer;
  color: var(--muted); background: #16110c80; border: 1px solid var(--line);
}
.setchip:hover { color: var(--cream); }
/* 지금 낀 조합. 「어느 것을 보고 있나」가 이 줄에서 제일 먼저 읽혀야 한다. */
.setchip.on { color: var(--gold); border-color: var(--gold-dim); }
.setchip.add { color: var(--gold-dim); }
.setchip.del { color: var(--faint); }

