@import url('./item-filter.28cbeb050b777007.css');

@import url('./notifications.28cbeb050b777007.css');

/* ── 중단점 다섯. **여섯째를 더하지 않는다** (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; }

.skip-link {
  position: fixed; z-index: 1000; top: 8px; left: 8px;
  transform: translateY(calc(-100% - 16px));
  padding: 12px 16px; background: var(--ink); color: var(--text);
  border: 2px solid var(--gold); border-radius: 4px;
}
.skip-link:focus { transform: translateY(0); }
#main-content { scroll-margin-top: 16px; }

/* 화면에는 숨기되 제목·설명과 검색 label은 보조 기술에 남긴다. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

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

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

/* ── 본문 글꼴 — Pretendard (2026-08-24) ──────────────────────────────────
   ⚠ **이름만 적혀 있고 안 실리던 것을 실제로 싣는다.** `--font-body` 스택에
   'Pretendard' 가 있었는데 `@font-face` 도 파일도 없었다. 그래서 실제로는:

       맥      Apple SD Gothic Neo  (스택 첫 항목이라 걸린다)
       윈도우  ✗ → ✗ → ✗ → system-ui 가 한글을 못 그려 → **맑은 고딕**

   디자인 조사 보고서가 「돋움/굴림/맑은 고딕 혼용 = 2005년 사이트 인상의 최대
   원인」으로 지목한 그 상태였다(요약 2번 · 하면 좋은 것 2번).

   ⚠⚠ **보고서 권고(다이나믹 서브셋)를 안 따랐다 — 우리 데이터에서는 손해다.**
   실측(2026-08-24): 화면에 뜨는 고유 글자 1,450자(한글 1,275). 다이나믹 서브셋
   92조각 중 **70조각**이 걸려 ≈2.05MB — **통짜 가변 폰트(2.01MB)와 같다.**
   아이템 1,183개 + 주문 이름이 한글 음절을 넓게 훑어서 조각이 거의 다 걸린다.
   그 권고는 짧고 반복적인 한국어 사이트 기준이다.

   그래서 **KS X 1001 서브셋(261KB)** 을 쓴다. 폰트 cmap 으로 잰 실측:

       KS X 1001 서브셋   우리 글자 1,450자 중 빠진 것 35자 — **그중 한글 2자**
       통짜 가변 폰트     빠진 것 26자 — 한글 0자

   한글 2자는 `꼅`(아이템 설명 「느꼅니다」)·`엺`(「엺게」)로 **둘 다 게임 텍스트의
   오타**다. 아이템 1,183개 중 2개의 설명문에서 그 한 글자만 대체 글꼴로 뜬다.
   그거 하나 때문에 8배(261KB → 2MB)를 물리지 않는다.
   ⚠ 나머지 26자는 통짜에도 없다 — 딩뱃·원문자(㉠㉢)·괘선이라 Pretendard 에 애초에
   없는 글자다. 어느 쪽을 골라도 대체 글꼴로 뜬다.

   ⚠ **게시판 글(UGC)은 못 잰다.** 사용자가 무슨 글자를 쓸지 모른다 — 2,350자 밖은
   대체 글꼴로 떨어진다. 글자별로 떨어지는 것이라 글이 깨지지는 않는다.

   ⚠ **`font-display: swap` 이라 글자가 한 번 튄다(FOUT).** 지금은 시스템 글꼴이라
   안 튀던 것이 **새로 생기는 현상**이다. 대안인 `block` 은 그동안 글자가 아예 안
   보이고, `optional` 은 첫 방문에 폰트를 아예 안 쓸 수 있다 — 둘 다 더 나쁘다.
   ⚠ 파일은 `web/fonts/` 에 둔다. `web/skin/` 은 **게임 자산 전용**이라 섞지 않는다
   (그쪽은 gitignore 대상이고 이건 커밋한다). */
@font-face {
  font-family: 'Pretendard';
  src: url('fonts/Pretendard-subset.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
}

/* 제목 글꼴 조각 시작 */
/* tools/subset-title-font.py 생성. 흔한 한글과 나머지 글자를 분리한다. */
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.44d5167da8d9c376.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+20-7E,U+A0-103,U+110-113,U+11A-11B,U+128-12B,U+143-144,U+147-148,U+14C-14F,U+152-153,U+168-16D,U+192,U+1A0-1A1,U+1AF-1B0,U+1CD-1DC,U+1F8-1F9,U+1100-11FF,U+2002-2003,U+2010-2016,U+2018-201A,U+201C-201E,U+2020-2022,U+2025-2027,U+2030,U+2032-2033,U+2035,U+2039-203C,U+2042,U+2047-2049,U+2051,U+3000-303F,U+3131-318E,U+A960-A97C,U+D7B0-D7C6,U+D7CB-D7FB,U+FF01-FFBE,U+FFC2-FFC7,U+FFCA-FFCF,U+FFD2-FFD7,U+FFDA-FFDC,U+FFE0-FFE6,U+FFE8-FFEE;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.9b36e371cd9c9f10.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+AC00-AC01,U+AC04,U+AC07-AC0A,U+AC10-AC17,U+AC19-AC1D,U+AC20,U+AC24,U+AC2C-AC2D,U+AC2F-AC31,U+AC38-AC39,U+AC3C,U+AC40,U+AC4B,U+AC4D,U+AC54,U+AC58,U+AC5C,U+AC70-AC71,U+AC74,U+AC77-AC78,U+AC7A,U+AC80-AC81,U+AC83-AC86,U+AC89-AC8C,U+AC90,U+AC94,U+AC9C-AC9D,U+AC9F-ACA1,U+ACA8-ACAA,U+ACAC,U+ACAF-ACB0,U+ACB8-ACB9,U+ACBB-ACBD,U+ACC1,U+ACC4,U+ACC8,U+ACCC,U+ACD5,U+ACD7,U+ACE0-ACE1,U+ACE4,U+ACE7-ACE8,U+ACEA,U+ACEC,U+ACEF-ACF1,U+ACF3,U+ACF5-ACF6,U+ACFC-ACFD,U+AD00,U+AD04,U+AD06,U+AD0C-AD0D,U+AD0F,U+AD11,U+AD18,U+AD1C,U+AD20,U+AD29,U+AD2C-AD2D,U+AD34-AD35,U+AD38,U+AD3C,U+AD44-AD45,U+AD47,U+AD49,U+AD50,U+AD54,U+AD58,U+AD61,U+AD63,U+AD6C-AD6D,U+AD70,U+AD73-AD76,U+AD7B-AD7D,U+AD7F,U+AD81-AD82,U+AD88-AD89,U+AD8C,U+AD90,U+AD9C-AD9D,U+ADA4,U+ADB7,U+ADC0-ADC1,U+ADC4,U+ADC8,U+ADD0-ADD1,U+ADD3,U+ADDC,U+ADE0,U+ADE4,U+ADF8-ADF9,U+ADFC,U+ADFF-AE01,U+AE08-AE09,U+AE0B,U+AE0D,U+AE14,U+AE30-AE31,U+AE34,U+AE37-AE38,U+AE3A,U+AE40-AE41,U+AE43,U+AE45-AE46,U+AE4A,U+AE4C-AE4E,U+AE50,U+AE54,U+AE56,U+AE5C-AE5D,U+AE5F-AE61,U+AE65,U+AE68-AE69,U+AE6C,U+AE70,U+AE78-AE79,U+AE7B-AE7D,U+AE84-AE85,U+AE8C,U+AEBC-AEBE,U+AEC0,U+AEC4,U+AECC-AECD,U+AECF-AED1,U+AED8-AED9,U+AEDC,U+AEE8,U+AEEB,U+AEED,U+AEF4,U+AEF8,U+AEFC,U+AF07-AF08,U+AF0D,U+AF10,U+AF2C-AF2D,U+AF30,U+AF32,U+AF34,U+AF3C-AF3D,U+AF3F,U+AF41-AF43,U+AF48-AF49,U+AF50,U+AF5C-AF5D,U+AF64-AF65,U+AF79,U+AF80,U+AF84,U+AF88,U+AF90-AF91,U+AF95,U+AF9C,U+AFB8-AFB9,U+AFBC,U+AFC0,U+AFC7-AFC9,U+AFCB,U+AFCD-AFCE,U+AFD4,U+AFDC,U+AFE8-AFE9,U+AFF0-AFF1,U+AFF4,U+AFF8,U+B000-B001,U+B004,U+B00C,U+B010,U+B014,U+B01C-B01D,U+B028,U+B044-B045,U+B048,U+B04A,U+B04C,U+B04E,U+B053-B055,U+B057,U+B059,U+B05D,U+B07C-B07D,U+B080,U+B084,U+B08C-B08D,U+B08F,U+B091,U+B098-B09A,U+B09C,U+B09F-B0A2,U+B0A8-B0A9,U+B0AB-B0AF,U+B0B1,U+B0B3-B0B5,U+B0B8,U+B0BC,U+B0C4-B0C5,U+B0C7-B0C9,U+B0D0-B0D1,U+B0D4,U+B0D8,U+B0E0,U+B0E5,U+B108-B109,U+B10B-B10C,U+B110,U+B112-B113,U+B118-B119,U+B11B-B11D,U+B123-B125,U+B128,U+B12C,U+B134-B135,U+B137-B139,U+B140-B141,U+B144,U+B148,U+B150-B151,U+B154-B155,U+B158,U+B15C,U+B160,U+B178-B179,U+B17C,U+B180,U+B182,U+B188-B189,U+B18B,U+B18D,U+B192-B194,U+B198,U+B19C,U+B1A8,U+B1CC,U+B1D0,U+B1D4,U+B1DC-B1DD,U+B1DF,U+B1E8-B1E9,U+B1EC,U+B1F0,U+B1F9,U+B1FB,U+B1FD,U+B204-B205,U+B208,U+B20B-B20C,U+B214-B215,U+B217,U+B219,U+B220,U+B234,U+B23C,U+B258,U+B25C,U+B260,U+B268-B269,U+B274-B275,U+B27C,U+B284-B285,U+B289,U+B290-B291,U+B294,U+B298-B29A,U+B2A0-B2A1,U+B2A3,U+B2A5-B2A6,U+B2AA,U+B2AC,U+B2B0,U+B2B4,U+B2C8-B2C9,U+B2CC,U+B2D0,U+B2D2,U+B2D8-B2D9,U+B2DB,U+B2DD,U+B2E2,U+B2E4-B2E6,U+B2E8,U+B2EB-B2EF,U+B2F3-B2F5,U+B2F7-B2FB,U+B2FF-B301,U+B304,U+B308,U+B310-B311,U+B313-B315,U+B31C,U+B354-B356,U+B358,U+B35B-B35C,U+B35E-B35F,U+B364-B365,U+B367,U+B369,U+B36B,U+B36E,U+B370-B371,U+B374,U+B378,U+B380-B381,U+B383-B385,U+B38C,U+B390,U+B394,U+B3A0-B3A1,U+B3A8,U+B3AC,U+B3C4-B3C5,U+B3C8,U+B3CB-B3CC,U+B3CE,U+B3D0,U+B3D4-B3D5,U+B3D7,U+B3D9,U+B3DB,U+B3DD,U+B3E0,U+B3E4,U+B3E8,U+B3FC,U+B410,U+B418,U+B41C,U+B420,U+B428-B429,U+B42B,U+B434,U+B450-B451,U+B454,U+B458,U+B460-B461,U+B463,U+B465,U+B46C,U+B480,U+B488,U+B49D,U+B4A4,U+B4A8,U+B4AC,U+B4B5,U+B4B7,U+B4B9,U+B4C0,U+B4C4,U+B4C8,U+B4D0,U+B4D5,U+B4DC-B4DD,U+B4E0,U+B4E3-B4E4,U+B4E6,U+B4EC-B4ED,U+B4EF,U+B4F1,U+B4F8,U+B514-B515,U+B518,U+B51B-B51C,U+B524-B525,U+B527-B52A,U+B530-B531,U+B534,U+B538,U+B540-B541,U+B543-B545,U+B54B-B54D,U+B550,U+B554,U+B55C-B55D,U+B55F-B561,U+B5A0-B5A1,U+B5A4,U+B5A8,U+B5AA-B5AB,U+B5B0-B5B1,U+B5B3-B5B5,U+B5BB-B5BD,U+B5C0,U+B5C4,U+B5CC-B5CD,U+B5CF-B5D1,U+B5D8,U+B5EC,U+B610-B611,U+B614,U+B618,U+B625,U+B62C,U+B634,U+B648,U+B664,U+B668,U+B69C-B69D,U+B6A0,U+B6A4,U+B6AB-B6AC,U+B6B1,U+B6D4,U+B6F0,U+B6F4,U+B6F8,U+B700-B701,U+B705,U+B728-B729,U+B72C,U+B72F-B730,U+B738-B739,U+B73B,U+B744,U+B748,U+B74C,U+B754-B755,U+B760,U+B764,U+B768,U+B770-B771,U+B773,U+B775,U+B77C-B77D,U+B780,U+B784,U+B78C-B78D,U+B78F-B792,U+B796-B799,U+B79C,U+B7A0,U+B7A8-B7A9,U+B7AB-B7AD,U+B7B4-B7B5,U+B7B8,U+B7C7,U+B7C9,U+B7EC-B7ED,U+B7F0,U+B7F4,U+B7FC-B7FD,U+B7FF-B801,U+B807-B809,U+B80C,U+B810,U+B818-B819,U+B81B,U+B81D,U+B824-B825,U+B828,U+B82C,U+B834-B835,U+B837-B839,U+B840,U+B844,U+B851,U+B853,U+B85C-B85D,U+B860,U+B864,U+B86C-B86D,U+B86F,U+B871,U+B878,U+B87C,U+B88D,U+B8A8,U+B8B0,U+B8B4,U+B8B8,U+B8C0-B8C1,U+B8C3,U+B8C5,U+B8CC,U+B8D0,U+B8D4,U+B8DD,U+B8DF,U+B8E1,U+B8E8-B8E9,U+B8EC,U+B8F0,U+B8F8-B8F9,U+B8FB,U+B8FD,U+B904,U+B918,U+B920,U+B93C-B93D,U+B940,U+B944,U+B94C,U+B94F,U+B951,U+B958-B959,U+B95C,U+B960,U+B968-B969,U+B96B,U+B96D,U+B974-B975,U+B978,U+B97C,U+B984-B985,U+B987,U+B989-B98A,U+B98D-B98E,U+B9AC-B9AD,U+B9B0,U+B9B4,U+B9BC-B9BD,U+B9BF,U+B9C1,U+B9C8-B9C9,U+B9CC,U+B9CE-B9D2,U+B9D8-B9D9,U+B9DB,U+B9DD-B9DE,U+B9E1,U+B9E3-B9E5,U+B9E8,U+B9EC,U+B9F4-B9F5,U+B9F7-B9FA,U+BA00-BA01,U+BA08,U+BA15,U+BA38-BA39,U+BA3C,U+BA40,U+BA42,U+BA48-BA49,U+BA4B,U+BA4D-BA4E,U+BA53-BA55,U+BA58,U+BA5C,U+BA64-BA65,U+BA67-BA69,U+BA70-BA71,U+BA74,U+BA78,U+BA83-BA85,U+BA87,U+BA8C,U+BAA8-BAA9,U+BAAB-BAAC,U+BAB0,U+BAB2,U+BAB8-BAB9,U+BABB,U+BABD,U+BAC4,U+BAC8,U+BAD8-BAD9,U+BAFC,U+BB00,U+BB04,U+BB0D,U+BB0F,U+BB11,U+BB18,U+BB1C,U+BB20,U+BB29,U+BB2B,U+BB34-BB36,U+BB38,U+BB3B-BB3E,U+BB44-BB45,U+BB47,U+BB49,U+BB4D,U+BB4F-BB50,U+BB54,U+BB58,U+BB61,U+BB63,U+BB6C,U+BB88,U+BB8C,U+BB90,U+BBA4,U+BBA8,U+BBAC,U+BBB4,U+BBB7,U+BBC0,U+BBC4,U+BBC8,U+BBD0,U+BBD3,U+BBF8-BBF9,U+BBFC,U+BBFF-BC00,U+BC02,U+BC08-BC09,U+BC0B-BC0D,U+BC0F,U+BC11,U+BC14-BC18,U+BC1B-BC1F,U+BC24-BC25,U+BC27,U+BC29,U+BC2D,U+BC30-BC31,U+BC34,U+BC38,U+BC40-BC41,U+BC43-BC45,U+BC49,U+BC4C-BC4D,U+BC50,U+BC5D,U+BC84-BC85,U+BC88,U+BC8B-BC8C,U+BC8E,U+BC94-BC95,U+BC97,U+BC99-BC9A,U+BCA0-BCA1,U+BCA4,U+BCA7-BCA8,U+BCB0-BCB1,U+BCB3-BCB5,U+BCBC-BCBD,U+BCC0,U+BCC4,U+BCCD,U+BCCF-BCD1,U+BCD5,U+BCD8,U+BCDC,U+BCF4-BCF6,U+BCF8,U+BCFC,U+BD04-BD05,U+BD07,U+BD09,U+BD10,U+BD14,U+BD24,U+BD2C,U+BD40,U+BD48-BD49,U+BD4C,U+BD50,U+BD58-BD59,U+BD64,U+BD68,U+BD80-BD81,U+BD84,U+BD87-BD8A,U+BD90-BD91,U+BD93,U+BD95,U+BD99-BD9A,U+BD9C,U+BDA4,U+BDB0,U+BDB8,U+BDD4-BDD5,U+BDD8,U+BDDC,U+BDE9,U+BDF0,U+BDF4,U+BDF8,U+BE00,U+BE03,U+BE05,U+BE0C-BE0D,U+BE10,U+BE14,U+BE1C-BE1D,U+BE1F,U+BE44-BE45,U+BE48,U+BE4C,U+BE4E,U+BE54-BE55,U+BE57,U+BE59-BE5B,U+BE60-BE61,U+BE64,U+BE68,U+BE6A,U+BE70-BE71,U+BE73-BE75,U+BE7B-BE7D,U+BE80,U+BE84,U+BE8C-BE8D,U+BE8F-BE91,U+BE98-BE99,U+BEA8,U+BED0-BED1,U+BED4,U+BED7-BED8,U+BEE0,U+BEE3-BEE5,U+BEEC,U+BF01,U+BF08-BF09,U+BF18-BF19,U+BF1B-BF1D,U+BF40-BF41,U+BF44,U+BF48,U+BF50-BF51,U+BF55,U+BF94,U+BFB0,U+BFC5,U+BFCC-BFCD,U+BFD0,U+BFD4,U+BFDC,U+BFDF,U+BFE1,U+C03C,U+C051,U+C058,U+C05C,U+C060,U+C068-C069,U+C090-C091,U+C094,U+C098,U+C0A0-C0A1,U+C0A3,U+C0A5,U+C0AC-C0AD,U+C0AF-C0B0,U+C0B3-C0B6,U+C0BC-C0BD,U+C0BF-C0C1,U+C0C5,U+C0C8-C0C9,U+C0CC,U+C0D0,U+C0D8-C0D9,U+C0DB-C0DD,U+C0E4-C0E5,U+C0E8,U+C0EC,U+C0F4-C0F5,U+C0F7,U+C0F9,U+C100,U+C104,U+C108,U+C110,U+C115,U+C11C-C120,U+C123-C124,U+C126-C127,U+C12C-C12D,U+C12F-C131,U+C136,U+C138-C139,U+C13C,U+C140,U+C148-C149,U+C14B-C14D,U+C154-C155,U+C158,U+C15C,U+C164-C165,U+C167-C169,U+C170,U+C174,U+C178,U+C185,U+C18C-C18E,U+C190,U+C194,U+C196,U+C19C-C19D,U+C19F,U+C1A1,U+C1A5,U+C1A8-C1A9,U+C1AC,U+C1B0,U+C1BD,U+C1C4,U+C1C8,U+C1CC,U+C1D4,U+C1D7-C1D8,U+C1E0,U+C1E4,U+C1E8,U+C1F0-C1F1,U+C1F3,U+C1FC-C1FD,U+C200,U+C204,U+C20C-C20D,U+C20F,U+C211,U+C218-C219,U+C21C,U+C21F-C220,U+C228-C229,U+C22B,U+C22D,U+C22F,U+C231-C232,U+C234,U+C248,U+C250-C251,U+C254,U+C258,U+C260,U+C265,U+C26C-C26D,U+C270,U+C274,U+C27C-C27D,U+C27F,U+C281,U+C288-C289,U+C290,U+C298,U+C29B,U+C29D,U+C2A4-C2A5,U+C2A8,U+C2AC-C2AD,U+C2B4-C2B5,U+C2B7,U+C2B9,U+C2DC-C2DD,U+C2E0,U+C2E3-C2E4,U+C2EB-C2ED,U+C2EF,U+C2F1,U+C2F6,U+C2F8-C2F9,U+C2FB-C2FC,U+C300,U+C308-C309,U+C30C-C30D,U+C313-C315,U+C318,U+C31C,U+C324-C325,U+C328-C329,U+C345,U+C368-C369,U+C36C,U+C370,U+C372,U+C378-C379,U+C37C-C37D,U+C384,U+C388,U+C38C,U+C3C0,U+C3D8-C3D9,U+C3DC,U+C3DF-C3E0,U+C3E2,U+C3E8-C3E9,U+C3ED,U+C3F4-C3F5,U+C3F8,U+C408,U+C410,U+C424,U+C42C,U+C430,U+C434,U+C43C-C43D,U+C448,U+C464-C465,U+C468,U+C46C,U+C474-C475,U+C479,U+C480,U+C494,U+C49C,U+C4B8,U+C4BC,U+C4E9,U+C4F0-C4F1,U+C4F4,U+C4F8,U+C4FA,U+C4FF-C501,U+C50C,U+C510,U+C514,U+C51C,U+C528-C529,U+C52C,U+C530,U+C538-C539,U+C53B,U+C53D,U+C544-C545,U+C548-C54A,U+C54C-C54E,U+C553-C555,U+C557-C559,U+C55D-C55E,U+C560-C561,U+C564,U+C568,U+C570-C571,U+C573-C575,U+C57C-C57D,U+C580,U+C584,U+C587,U+C58C-C58D,U+C58F,U+C591,U+C595,U+C597-C598,U+C59C,U+C5A0,U+C5A9,U+C5B4-C5B5,U+C5B8-C5B9,U+C5BB-C5BE,U+C5C4-C5CA,U+C5CC,U+C5CE,U+C5D0-C5D1,U+C5D4,U+C5D8,U+C5E0-C5E1,U+C5E3,U+C5E5,U+C5EC-C5EE,U+C5F0,U+C5F4,U+C5F6-C5F7,U+C5FC-C601,U+C605-C608,U+C60C,U+C610,U+C618-C619,U+C61B-C61C,U+C624-C625,U+C628,U+C62C-C62E,U+C630,U+C633-C635,U+C637,U+C639,U+C63B,U+C640-C641,U+C644,U+C648,U+C650-C651,U+C653-C655,U+C65C-C65D,U+C660,U+C66C,U+C66F,U+C671,U+C678-C679,U+C67C,U+C680,U+C688-C689,U+C68B,U+C68D,U+C694-C695,U+C698,U+C69C,U+C6A4-C6A5,U+C6A7,U+C6A9,U+C6B0-C6B1,U+C6B4,U+C6B8-C6BA,U+C6C0-C6C1,U+C6C3,U+C6C5,U+C6CC-C6CD,U+C6D0,U+C6D4,U+C6DC-C6DD,U+C6E0-C6E1,U+C6E8-C6E9,U+C6EC,U+C6F0,U+C6F8-C6F9,U+C6FD,U+C704-C705,U+C708,U+C70C,U+C714-C715,U+C717,U+C719,U+C720-C721,U+C724,U+C728,U+C730-C731,U+C733,U+C735,U+C737,U+C73C-C73D,U+C740,U+C744,U+C74A,U+C74C-C74D,U+C74F,U+C751-C758,U+C75C,U+C760,U+C768,U+C76B,U+C774-C775,U+C778,U+C77C-C77E,U+C783-C785,U+C787-C78A,U+C78E,U+C790-C791,U+C794,U+C796-C798,U+C79A,U+C7A0-C7A1,U+C7A3-C7A6,U+C7AC-C7AD,U+C7B0,U+C7B4,U+C7BC-C7BD,U+C7BF-C7C1,U+C7C8-C7C9,U+C7CC,U+C7CE,U+C7D0,U+C7D8,U+C7DD,U+C7E4,U+C7E8,U+C7EC,U+C800-C801,U+C804,U+C808,U+C80A,U+C810-C811,U+C813,U+C815-C816,U+C81C-C81D,U+C820,U+C824,U+C82C-C82D,U+C82F,U+C831,U+C838,U+C83C,U+C840,U+C848-C849,U+C84C-C84D,U+C854,U+C870-C871,U+C874,U+C878,U+C87A,U+C880-C881,U+C883,U+C885-C887,U+C88B-C88D,U+C894,U+C89D,U+C89F,U+C8A1,U+C8A8,U+C8BC-C8BD,U+C8C4,U+C8C8,U+C8CC,U+C8D4-C8D5,U+C8D7,U+C8D9,U+C8E0-C8E1,U+C8E4,U+C8F5,U+C8FC-C8FD,U+C900,U+C904-C906,U+C90C-C90D,U+C90F,U+C911,U+C918,U+C92C,U+C934,U+C950-C951,U+C954,U+C958,U+C960-C961,U+C963,U+C96C,U+C970,U+C974,U+C97C,U+C988-C989,U+C98C,U+C990,U+C998-C999,U+C99B,U+C99D,U+C9C0-C9C1,U+C9C4,U+C9C7-C9C8,U+C9CA,U+C9D0-C9D1,U+C9D3,U+C9D5-C9D6,U+C9D9-C9DA,U+C9DC-C9DD,U+C9E0,U+C9E2,U+C9E4,U+C9E7,U+C9EC-C9ED,U+C9EF-C9F1,U+C9F8-C9F9,U+C9FC,U+CA00,U+CA08-CA09,U+CA0B-CA0D,U+CA14,U+CA18,U+CA29,U+CA4C-CA4D,U+CA50,U+CA54,U+CA5C-CA5D,U+CA5F-CA61,U+CA68,U+CA7D,U+CA84,U+CA98,U+CABC-CABD,U+CAC0,U+CAC4,U+CACC-CACD,U+CACF,U+CAD1,U+CAD3,U+CAD8-CAD9,U+CAE0,U+CAEC,U+CAF4,U+CB08,U+CB10,U+CB14,U+CB18,U+CB20-CB21,U+CB41,U+CB48-CB49,U+CB4C,U+CB50,U+CB58-CB59,U+CB5D,U+CB64,U+CB78-CB79,U+CB9C,U+CBB8,U+CBD4,U+CBE4,U+CBE7,U+CBE9,U+CC0C-CC0D,U+CC10,U+CC14,U+CC1C-CC1D,U+CC21-CC22,U+CC27-CC29,U+CC2C,U+CC2E,U+CC30,U+CC38-CC39,U+CC3B-CC3E,U+CC44-CC45,U+CC48,U+CC4C,U+CC54-CC55,U+CC57-CC59,U+CC60,U+CC64,U+CC66,U+CC68,U+CC70,U+CC75,U+CC98-CC99,U+CC9C,U+CCA0,U+CCA8-CCA9,U+CCAB-CCAD,U+CCB4-CCB5,U+CCB8,U+CCBC,U+CCC4-CCC5,U+CCC7,U+CCC9,U+CCD0,U+CCD4,U+CCE4,U+CCEC,U+CCF0,U+CD01,U+CD08-CD09,U+CD0C,U+CD10,U+CD18-CD19,U+CD1B,U+CD1D,U+CD24,U+CD28,U+CD2C,U+CD39,U+CD5C,U+CD60,U+CD64,U+CD6C-CD6D,U+CD6F,U+CD71,U+CD78,U+CD88,U+CD94-CD95,U+CD98,U+CD9C,U+CDA4-CDA5,U+CDA7,U+CDA9,U+CDB0,U+CDC4,U+CDCC,U+CDD0,U+CDE8,U+CDEC,U+CDF0,U+CDF8-CDF9,U+CDFB,U+CDFD,U+CE04,U+CE08,U+CE0C,U+CE14,U+CE19,U+CE20-CE21,U+CE24,U+CE28,U+CE30-CE31,U+CE33,U+CE35,U+CE58-CE59,U+CE5C,U+CE5F-CE61,U+CE68-CE69,U+CE6B,U+CE6D,U+CE74-CE75,U+CE78,U+CE7C,U+CE84-CE85,U+CE87,U+CE89,U+CE90-CE91,U+CE94,U+CE98,U+CEA0-CEA1,U+CEA3-CEA5,U+CEAC-CEAD,U+CEC1,U+CEE4-CEE5,U+CEE8,U+CEEB-CEEC,U+CEF4-CEF5,U+CEF7-CEF9,U+CF00-CF01,U+CF04,U+CF08,U+CF10-CF11,U+CF13,U+CF15,U+CF1C,U+CF20,U+CF24,U+CF2C-CF2D,U+CF2F-CF31,U+CF38,U+CF54-CF55,U+CF58,U+CF5C,U+CF64-CF65,U+CF67,U+CF69,U+CF70-CF71,U+CF74,U+CF78,U+CF80,U+CF85,U+CF8C,U+CFA1,U+CFA8,U+CFB0,U+CFC4,U+CFE0-CFE1,U+CFE4,U+CFE8,U+CFF0-CFF1,U+CFF3,U+CFF5,U+CFFC,U+D000,U+D004,U+D011,U+D018,U+D02D,U+D034-D035,U+D038,U+D03C,U+D044-D045,U+D047,U+D049,U+D050,U+D054,U+D058,U+D060,U+D06C-D06D,U+D070,U+D074,U+D07C-D07D,U+D081,U+D0A4-D0A5,U+D0A8,U+D0AC,U+D0B4-D0B5,U+D0B7,U+D0B9,U+D0C0-D0C1,U+D0C4,U+D0C8-D0C9,U+D0D0-D0D1,U+D0D3-D0D5,U+D0DC-D0DD,U+D0E0,U+D0E4,U+D0EC-D0ED,U+D0EF-D0F1,U+D0F8,U+D10D,U+D130-D131,U+D134,U+D138,U+D13A,U+D140-D141,U+D143-D145,U+D14C-D14D,U+D150,U+D154,U+D15C-D15D,U+D15F,U+D161,U+D168,U+D16C,U+D17C,U+D184,U+D188,U+D1A0-D1A1,U+D1A4,U+D1A8,U+D1B0-D1B1,U+D1B3,U+D1B5,U+D1BA,U+D1BC,U+D1C0,U+D1D8,U+D1F4,U+D1F8,U+D207,U+D209,U+D210,U+D22C-D22D,U+D230,U+D234,U+D23C-D23D,U+D23F,U+D241,U+D248,U+D25C,U+D264,U+D280-D281,U+D284,U+D288,U+D290-D291,U+D295,U+D29C,U+D2A0,U+D2A4,U+D2AC,U+D2B1,U+D2B8-D2B9,U+D2BC,U+D2BF-D2C0,U+D2C2,U+D2C8-D2C9,U+D2CB,U+D2D4,U+D2D8,U+D2DC,U+D2E4-D2E5,U+D2F0-D2F1,U+D2F4,U+D2F8,U+D300-D301,U+D303,U+D305,U+D30C-D30E,U+D310,U+D314,U+D316,U+D31C-D31D,U+D31F-D321,U+D325,U+D328-D329,U+D32C,U+D330,U+D338-D339,U+D33B-D33D,U+D344-D345,U+D37C-D37D,U+D380,U+D384,U+D38C-D38D,U+D38F-D391,U+D398-D399,U+D39C,U+D3A0,U+D3A8-D3A9,U+D3AB,U+D3AD,U+D3B4,U+D3B8,U+D3BC,U+D3C4-D3C5,U+D3C8-D3C9,U+D3D0,U+D3D8,U+D3E1,U+D3E3,U+D3EC-D3ED,U+D3F0,U+D3F4,U+D3FC-D3FD,U+D3FF,U+D401,U+D408,U+D41D,U+D440,U+D444,U+D45C,U+D460,U+D464,U+D46D,U+D46F,U+D478-D479,U+D47C,U+D47F-D480,U+D482,U+D488-D489,U+D48B,U+D48D,U+D494,U+D4A9,U+D4CC,U+D4D0,U+D4D4,U+D4DC,U+D4DF,U+D4E8,U+D4EC,U+D4F0,U+D4F8,U+D4FB,U+D4FD,U+D504,U+D508,U+D50C,U+D514-D515,U+D517,U+D53C-D53D,U+D540,U+D544,U+D54C-D54D,U+D54F,U+D551,U+D558-D559,U+D55C,U+D560,U+D565,U+D568-D569,U+D56B,U+D56D,U+D574-D575,U+D578,U+D57C,U+D584-D585,U+D587-D589,U+D590,U+D5A5,U+D5C8-D5C9,U+D5CC,U+D5D0,U+D5D2,U+D5D8-D5D9,U+D5DB,U+D5DD,U+D5E4-D5E5,U+D5E8,U+D5EC,U+D5F4-D5F5,U+D5F7,U+D5F9,U+D600-D601,U+D604,U+D608,U+D610-D611,U+D613-D615,U+D61C,U+D620,U+D624,U+D62D,U+D638-D639,U+D63C,U+D640,U+D645,U+D648-D649,U+D64B,U+D64D,U+D651,U+D654-D655,U+D658,U+D65C,U+D667,U+D669,U+D670-D671,U+D674,U+D683,U+D685,U+D68C-D68D,U+D690,U+D694,U+D69D,U+D69F,U+D6A1,U+D6A8,U+D6AC,U+D6B0,U+D6B9,U+D6BB,U+D6C4-D6C5,U+D6C8,U+D6CC,U+D6D1,U+D6D4,U+D6D7,U+D6D9,U+D6E0,U+D6E4,U+D6E8,U+D6F0,U+D6F5,U+D6FC-D6FD,U+D700,U+D704,U+D711,U+D718-D719,U+D71C,U+D720,U+D728-D729,U+D72B,U+D72D,U+D734-D735,U+D738,U+D73C,U+D744,U+D747,U+D749,U+D750-D751,U+D754,U+D756-D759,U+D760-D761,U+D763,U+D765,U+D769,U+D76C,U+D770,U+D774,U+D77C-D77D,U+D781,U+D788-D789,U+D78C,U+D790,U+D798-D799,U+D79B,U+D79D;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.24703a0bd53c311a.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+AC02-AC03,U+AC05-AC06,U+AC0B-AC0F,U+AC18,U+AC1E-AC1F,U+AC21-AC23,U+AC25-AC2B,U+AC2E,U+AC32-AC37,U+AC3A-AC3B,U+AC3D-AC3F,U+AC41-AC4A,U+AC4C,U+AC4E-AC53,U+AC55-AC57,U+AC59-AC5B,U+AC5D-AC6F,U+AC72-AC73,U+AC75-AC76,U+AC79,U+AC7B-AC7F,U+AC82,U+AC87-AC88,U+AC8D-AC8F,U+AC91-AC93,U+AC95-AC9B,U+AC9E,U+ACA2-ACA7,U+ACAB,U+ACAD-ACAE,U+ACB1-ACB7,U+ACBA,U+ACBE-ACC0,U+ACC2-ACC3,U+ACC5-ACC7,U+ACC9-ACCB,U+ACCD-ACD4,U+ACD6,U+ACD8-ACDF,U+ACE2-ACE3,U+ACE5-ACE6,U+ACE9,U+ACEB,U+ACED-ACEE,U+ACF2,U+ACF4,U+ACF7-ACFB,U+ACFE-ACFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.d98632032c68518a.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+AD01-AD03,U+AD05,U+AD07-AD0B,U+AD0E,U+AD10,U+AD12-AD17,U+AD19-AD1B,U+AD1D-AD1F,U+AD21-AD28,U+AD2A-AD2B,U+AD2E-AD33,U+AD36-AD37,U+AD39-AD3B,U+AD3D-AD43,U+AD46,U+AD48,U+AD4A-AD4F,U+AD51-AD53,U+AD55-AD57,U+AD59-AD60,U+AD62,U+AD64-AD6B,U+AD6E-AD6F,U+AD71-AD72,U+AD77-AD7A,U+AD7E,U+AD80,U+AD83-AD87,U+AD8A-AD8B,U+AD8D-AD8F,U+AD91-AD9B,U+AD9E-ADA3,U+ADA5-ADB6,U+ADB8-ADBF,U+ADC2-ADC3,U+ADC5-ADC7,U+ADC9-ADCF,U+ADD2,U+ADD4-ADDB,U+ADDD-ADDF,U+ADE1-ADE3,U+ADE5-ADF7,U+ADFA-ADFB,U+ADFD-ADFE;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.b041308a3c538c89.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+AE02-AE07,U+AE0A,U+AE0C,U+AE0E-AE13,U+AE15-AE2F,U+AE32-AE33,U+AE35-AE36,U+AE39,U+AE3B-AE3F,U+AE42,U+AE44,U+AE47-AE49,U+AE4B,U+AE4F,U+AE51-AE53,U+AE55,U+AE57-AE5B,U+AE5E,U+AE62-AE64,U+AE66-AE67,U+AE6A-AE6B,U+AE6D-AE6F,U+AE71-AE77,U+AE7A,U+AE7E-AE83,U+AE86-AE8B,U+AE8D-AEBB,U+AEBF,U+AEC1-AEC3,U+AEC5-AECB,U+AECE,U+AED2-AED7,U+AEDA-AEDB,U+AEDD-AEE7,U+AEE9-AEEA,U+AEEC,U+AEEE-AEF3,U+AEF5-AEF7,U+AEF9-AEFB,U+AEFD-AEFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.5befc4a9ea55d4d5.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+AF00-AF06,U+AF09-AF0C,U+AF0E-AF0F,U+AF11-AF2B,U+AF2E-AF2F,U+AF31,U+AF33,U+AF35-AF3B,U+AF3E,U+AF40,U+AF44-AF47,U+AF4A-AF4F,U+AF51-AF5B,U+AF5E-AF63,U+AF66-AF78,U+AF7A-AF7F,U+AF81-AF83,U+AF85-AF87,U+AF89-AF8F,U+AF92-AF94,U+AF96-AF9B,U+AF9D-AFB7,U+AFBA-AFBB,U+AFBD-AFBF,U+AFC1-AFC6,U+AFCA,U+AFCC,U+AFCF-AFD3,U+AFD5-AFDB,U+AFDD-AFE7,U+AFEA-AFEF,U+AFF2-AFF3,U+AFF5-AFF7,U+AFF9-AFFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.d3526971c87f9fa3.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B002-B003,U+B005-B00B,U+B00D-B00F,U+B011-B013,U+B015-B01B,U+B01E-B027,U+B029-B043,U+B046-B047,U+B049,U+B04B,U+B04D,U+B04F-B052,U+B056,U+B058,U+B05A-B05C,U+B05E-B07B,U+B07E-B07F,U+B081-B083,U+B085-B08B,U+B08E,U+B090,U+B092-B097,U+B09B,U+B09D-B09E,U+B0A3-B0A7,U+B0AA,U+B0B0,U+B0B2,U+B0B6-B0B7,U+B0B9-B0BB,U+B0BD-B0C3,U+B0C6,U+B0CA-B0CF,U+B0D2-B0D3,U+B0D5-B0D7,U+B0D9-B0DF,U+B0E1-B0E4,U+B0E6-B0FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.46345114bbc3ad10.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B100-B107,U+B10A,U+B10D-B10F,U+B111,U+B114-B117,U+B11A,U+B11E-B122,U+B126-B127,U+B129-B12B,U+B12D-B133,U+B136,U+B13A-B13F,U+B142-B143,U+B145-B147,U+B149-B14F,U+B152-B153,U+B156-B157,U+B159-B15B,U+B15D-B15F,U+B161-B177,U+B17A-B17B,U+B17D-B17F,U+B181,U+B183-B187,U+B18A,U+B18C,U+B18E-B191,U+B195-B197,U+B199-B19B,U+B19D-B1A7,U+B1A9-B1CB,U+B1CD-B1CF,U+B1D1-B1D3,U+B1D5-B1DB,U+B1DE,U+B1E0-B1E7,U+B1EA-B1EB,U+B1ED-B1EF,U+B1F1-B1F8,U+B1FA,U+B1FC,U+B1FE-B1FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.3fba4d2ea649705c.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B200-B203,U+B206-B207,U+B209-B20A,U+B20D-B213,U+B216,U+B218,U+B21A-B21F,U+B221-B233,U+B235-B23B,U+B23D-B257,U+B259-B25B,U+B25D-B25F,U+B261-B267,U+B26A-B273,U+B276-B27B,U+B27D-B283,U+B286-B288,U+B28A-B28F,U+B292-B293,U+B295-B297,U+B29B-B29F,U+B2A2,U+B2A4,U+B2A7-B2A9,U+B2AB,U+B2AD-B2AF,U+B2B1-B2B3,U+B2B5-B2C7,U+B2CA-B2CB,U+B2CD-B2CF,U+B2D1,U+B2D3-B2D7,U+B2DA,U+B2DC,U+B2DE-B2E1,U+B2E3,U+B2E7,U+B2E9-B2EA,U+B2F0-B2F2,U+B2F6,U+B2FC-B2FE;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.8eec5693d2b04fab.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B302-B303,U+B305-B307,U+B309-B30F,U+B312,U+B316-B31B,U+B31D-B353,U+B357,U+B359-B35A,U+B35D,U+B360-B363,U+B366,U+B368,U+B36A,U+B36C-B36D,U+B36F,U+B372-B373,U+B375-B377,U+B379-B37F,U+B382,U+B386-B38B,U+B38D-B38F,U+B391-B393,U+B395-B39F,U+B3A2-B3A7,U+B3A9-B3AB,U+B3AD-B3C3,U+B3C6-B3C7,U+B3C9-B3CA,U+B3CD,U+B3CF,U+B3D1-B3D3,U+B3D6,U+B3D8,U+B3DA,U+B3DC,U+B3DE-B3DF,U+B3E1-B3E3,U+B3E5-B3E7,U+B3E9-B3FB,U+B3FD-B3FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.684bb28bce10b821.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B400-B40F,U+B411-B417,U+B419-B41B,U+B41D-B41F,U+B421-B427,U+B42A,U+B42C-B433,U+B435-B44F,U+B452-B453,U+B455-B457,U+B459-B45F,U+B462,U+B464,U+B466-B46B,U+B46D-B47F,U+B481-B487,U+B489-B49C,U+B49E-B4A3,U+B4A5-B4A7,U+B4A9-B4AB,U+B4AD-B4B4,U+B4B6,U+B4B8,U+B4BA-B4BF,U+B4C1-B4C3,U+B4C5-B4C7,U+B4C9-B4CF,U+B4D1-B4D4,U+B4D6-B4DB,U+B4DE-B4DF,U+B4E1-B4E2,U+B4E5,U+B4E7-B4EB,U+B4EE,U+B4F0,U+B4F2-B4F7,U+B4F9-B4FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.7851595f34aeb988.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B500-B513,U+B516-B517,U+B519-B51A,U+B51D-B523,U+B526,U+B52B-B52F,U+B532-B533,U+B535-B537,U+B539-B53F,U+B542,U+B546-B54A,U+B54E-B54F,U+B551-B553,U+B555-B55B,U+B55E,U+B562-B59F,U+B5A2-B5A3,U+B5A5-B5A7,U+B5A9,U+B5AC-B5AF,U+B5B2,U+B5B6-B5BA,U+B5BE-B5BF,U+B5C1-B5C3,U+B5C5-B5CB,U+B5CE,U+B5D2-B5D7,U+B5D9-B5EB,U+B5ED-B5FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.5b8fc60e143e1737.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B600-B60F,U+B612-B613,U+B615-B617,U+B619-B624,U+B626-B62B,U+B62D-B633,U+B635-B647,U+B649-B663,U+B665-B667,U+B669-B69B,U+B69E-B69F,U+B6A1-B6A3,U+B6A5-B6AA,U+B6AD-B6B0,U+B6B2-B6D3,U+B6D5-B6EF,U+B6F1-B6F3,U+B6F5-B6F7,U+B6F9-B6FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.7ff8f2d956f4a485.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B702-B704,U+B706-B727,U+B72A-B72B,U+B72D-B72E,U+B731-B737,U+B73A,U+B73C-B743,U+B745-B747,U+B749-B74B,U+B74D-B753,U+B756-B75F,U+B761-B763,U+B765-B767,U+B769-B76F,U+B772,U+B774,U+B776-B77B,U+B77E-B77F,U+B781-B783,U+B785-B78B,U+B78E,U+B793-B795,U+B79A-B79B,U+B79D-B79F,U+B7A1-B7A7,U+B7AA,U+B7AE-B7B3,U+B7B6-B7B7,U+B7B9-B7C6,U+B7C8,U+B7CA-B7EB,U+B7EE-B7EF,U+B7F1-B7F3,U+B7F5-B7FB,U+B7FE;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.b153b5b2c44aa131.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B802-B806,U+B80A-B80B,U+B80D-B80F,U+B811-B817,U+B81A,U+B81C,U+B81E-B823,U+B826-B827,U+B829-B82B,U+B82D-B833,U+B836,U+B83A-B83F,U+B841-B843,U+B845-B850,U+B852,U+B854-B85B,U+B85E-B85F,U+B861-B863,U+B865-B86B,U+B86E,U+B870,U+B872-B877,U+B879-B87B,U+B87D-B88C,U+B88E-B8A7,U+B8A9-B8AF,U+B8B1-B8B3,U+B8B5-B8B7,U+B8B9-B8BF,U+B8C2,U+B8C4,U+B8C6-B8CB,U+B8CD-B8CF,U+B8D1-B8D3,U+B8D5-B8DC,U+B8DE,U+B8E0,U+B8E2-B8E7,U+B8EA-B8EB,U+B8ED-B8EF,U+B8F1-B8F7,U+B8FA,U+B8FC,U+B8FE-B8FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.3c6f200ed754e32e.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+B900-B903,U+B905-B917,U+B919-B91F,U+B921-B93B,U+B93E-B93F,U+B941-B943,U+B945-B94B,U+B94D-B94E,U+B950,U+B952-B957,U+B95A-B95B,U+B95D-B95F,U+B961-B967,U+B96A,U+B96C,U+B96E-B973,U+B976-B977,U+B979-B97B,U+B97D-B983,U+B986,U+B988,U+B98B-B98C,U+B98F-B9AB,U+B9AE-B9AF,U+B9B1-B9B3,U+B9B5-B9BB,U+B9BE,U+B9C0,U+B9C2-B9C7,U+B9CA-B9CB,U+B9CD,U+B9D3-B9D7,U+B9DA,U+B9DC,U+B9DF-B9E0,U+B9E2,U+B9E6-B9E7,U+B9E9-B9EB,U+B9ED-B9F3,U+B9F6,U+B9FB-B9FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.87eeb3c9f2a8b6a6.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+BA02-BA07,U+BA09-BA14,U+BA16-BA37,U+BA3A-BA3B,U+BA3D-BA3F,U+BA41,U+BA43-BA47,U+BA4A,U+BA4C,U+BA4F-BA52,U+BA56-BA57,U+BA59-BA5B,U+BA5D-BA63,U+BA66,U+BA6A-BA6F,U+BA72-BA73,U+BA75-BA77,U+BA79-BA82,U+BA86,U+BA88-BA8B,U+BA8D-BAA7,U+BAAA,U+BAAD-BAAF,U+BAB1,U+BAB3-BAB7,U+BABA,U+BABC,U+BABE-BAC3,U+BAC5-BAC7,U+BAC9-BAD7,U+BADA-BAFB,U+BAFD-BAFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.f4fd86af17b0bd67.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+BB01-BB03,U+BB05-BB0C,U+BB0E,U+BB10,U+BB12-BB17,U+BB19-BB1B,U+BB1D-BB1F,U+BB21-BB28,U+BB2A,U+BB2C-BB33,U+BB37,U+BB39-BB3A,U+BB3F-BB43,U+BB46,U+BB48,U+BB4A-BB4C,U+BB4E,U+BB51-BB53,U+BB55-BB57,U+BB59-BB60,U+BB62,U+BB64-BB6B,U+BB6D-BB87,U+BB89-BB8B,U+BB8D-BB8F,U+BB91-BBA3,U+BBA5-BBA7,U+BBA9-BBAB,U+BBAD-BBB3,U+BBB5-BBB6,U+BBB8-BBBF,U+BBC1-BBC3,U+BBC5-BBC7,U+BBC9-BBCF,U+BBD1-BBD2,U+BBD4-BBF7,U+BBFA-BBFB,U+BBFD-BBFE;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.5a69c7c827fd7f9a.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+BC01,U+BC03-BC07,U+BC0A,U+BC0E,U+BC10,U+BC12-BC13,U+BC19-BC1A,U+BC20-BC23,U+BC26,U+BC28,U+BC2A-BC2C,U+BC2E-BC2F,U+BC32-BC33,U+BC35-BC37,U+BC39-BC3F,U+BC42,U+BC46-BC48,U+BC4A-BC4B,U+BC4E-BC4F,U+BC51-BC5C,U+BC5E-BC83,U+BC86-BC87,U+BC89-BC8A,U+BC8D,U+BC8F-BC93,U+BC96,U+BC98,U+BC9B-BC9F,U+BCA2-BCA3,U+BCA5-BCA6,U+BCA9-BCAF,U+BCB2,U+BCB6-BCBB,U+BCBE-BCBF,U+BCC1-BCC3,U+BCC5-BCCC,U+BCCE,U+BCD2-BCD4,U+BCD6-BCD7,U+BCD9-BCDB,U+BCDD-BCF3,U+BCF7,U+BCF9-BCFB,U+BCFD-BCFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.dc99f3aee029a583.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+BD00-BD03,U+BD06,U+BD08,U+BD0A-BD0F,U+BD11-BD13,U+BD15-BD23,U+BD25-BD2B,U+BD2D-BD3F,U+BD41-BD47,U+BD4A-BD4B,U+BD4D-BD4F,U+BD51-BD57,U+BD5A-BD63,U+BD65-BD67,U+BD69-BD7F,U+BD82-BD83,U+BD85-BD86,U+BD8B-BD8F,U+BD92,U+BD94,U+BD96-BD98,U+BD9B,U+BD9D-BDA3,U+BDA5-BDAF,U+BDB1-BDB7,U+BDB9-BDD3,U+BDD6-BDD7,U+BDD9-BDDB,U+BDDD-BDE8,U+BDEA-BDEF,U+BDF1-BDF3,U+BDF5-BDF7,U+BDF9-BDFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.358c8c32008a3e85.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+BE01-BE02,U+BE04,U+BE06-BE0B,U+BE0E-BE0F,U+BE11-BE13,U+BE15-BE1B,U+BE1E,U+BE20-BE43,U+BE46-BE47,U+BE49-BE4B,U+BE4D,U+BE4F-BE53,U+BE56,U+BE58,U+BE5C-BE5F,U+BE62-BE63,U+BE65-BE67,U+BE69,U+BE6B-BE6F,U+BE72,U+BE76-BE7A,U+BE7E-BE7F,U+BE81-BE83,U+BE85-BE8B,U+BE8E,U+BE92-BE97,U+BE9A-BEA7,U+BEA9-BECF,U+BED2-BED3,U+BED5-BED6,U+BED9-BEDF,U+BEE1-BEE2,U+BEE6-BEEB,U+BEED-BEFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.6c70598f4cb78e20.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+BF00,U+BF02-BF07,U+BF0A-BF17,U+BF1A,U+BF1E-BF3F,U+BF42-BF43,U+BF45-BF47,U+BF49-BF4F,U+BF52-BF54,U+BF56-BF93,U+BF95-BFAF,U+BFB1-BFC4,U+BFC6-BFCB,U+BFCE-BFCF,U+BFD1-BFD3,U+BFD5-BFDB,U+BFDD-BFDE,U+BFE0,U+BFE2-BFFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.17f72ee99c24f95a.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C000-C03B,U+C03D-C050,U+C052-C057,U+C059-C05B,U+C05D-C05F,U+C061-C067,U+C06A-C08F,U+C092-C093,U+C095-C097,U+C099-C09F,U+C0A2,U+C0A4,U+C0A6-C0AB,U+C0AE,U+C0B1-C0B2,U+C0B7-C0BB,U+C0BE,U+C0C2-C0C4,U+C0C6-C0C7,U+C0CA-C0CB,U+C0CD-C0CF,U+C0D1-C0D7,U+C0DA,U+C0DE-C0E3,U+C0E6-C0E7,U+C0E9-C0EB,U+C0ED-C0F3,U+C0F6,U+C0F8,U+C0FA-C0FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.ff8e92313b9e4c00.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C101-C103,U+C105-C107,U+C109-C10F,U+C111-C114,U+C116-C11B,U+C121-C122,U+C125,U+C128-C12B,U+C12E,U+C132-C135,U+C137,U+C13A-C13B,U+C13D-C13F,U+C141-C147,U+C14A,U+C14E-C153,U+C156-C157,U+C159-C15B,U+C15D-C163,U+C166,U+C16A-C16F,U+C171-C173,U+C175-C177,U+C179-C184,U+C186-C18B,U+C18F,U+C191-C193,U+C195,U+C197-C19B,U+C19E,U+C1A0,U+C1A2-C1A4,U+C1A6-C1A7,U+C1AA-C1AB,U+C1AD-C1AF,U+C1B1-C1BC,U+C1BE-C1C3,U+C1C5-C1C7,U+C1C9-C1CB,U+C1CD-C1D3,U+C1D5-C1D6,U+C1D9-C1DF,U+C1E1-C1E3,U+C1E5-C1E7,U+C1E9-C1EF,U+C1F2,U+C1F4-C1FB,U+C1FE-C1FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.0830d1e516a65606.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C201-C203,U+C205-C20B,U+C20E,U+C210,U+C212-C217,U+C21A-C21B,U+C21D-C21E,U+C221-C227,U+C22A,U+C22C,U+C22E,U+C230,U+C233,U+C235-C247,U+C249-C24F,U+C252-C253,U+C255-C257,U+C259-C25F,U+C261-C264,U+C266-C26B,U+C26E-C26F,U+C271-C273,U+C275-C27B,U+C27E,U+C280,U+C282-C287,U+C28A-C28F,U+C291-C297,U+C299-C29A,U+C29C,U+C29E-C2A3,U+C2A6-C2A7,U+C2A9-C2AB,U+C2AE-C2B3,U+C2B6,U+C2B8,U+C2BA-C2DB,U+C2DE-C2DF,U+C2E1-C2E2,U+C2E5-C2EA,U+C2EE,U+C2F0,U+C2F2-C2F5,U+C2F7,U+C2FA,U+C2FD-C2FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.5d331c9149fd12b0.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C301-C307,U+C30A-C30B,U+C30E-C312,U+C316-C317,U+C319-C31B,U+C31D-C323,U+C326-C327,U+C32A-C344,U+C346-C367,U+C36A-C36B,U+C36D-C36F,U+C371,U+C373-C377,U+C37A-C37B,U+C37E-C383,U+C385-C387,U+C389-C38B,U+C38D-C3BF,U+C3C1-C3D7,U+C3DA-C3DB,U+C3DD-C3DE,U+C3E1,U+C3E3-C3E7,U+C3EA-C3EC,U+C3EE-C3F3,U+C3F6-C3F7,U+C3F9-C3FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.6d2e64724adf56c4.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C400-C407,U+C409-C40F,U+C411-C423,U+C425-C42B,U+C42D-C42F,U+C431-C433,U+C435-C43B,U+C43E-C447,U+C449-C463,U+C466-C467,U+C469-C46B,U+C46D-C473,U+C476-C478,U+C47A-C47F,U+C481-C493,U+C495-C49B,U+C49D-C4B7,U+C4B9-C4BB,U+C4BD-C4E8,U+C4EA-C4EF,U+C4F2-C4F3,U+C4F5-C4F7,U+C4F9,U+C4FB-C4FE;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.242f9922bdf72bdd.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C502-C50B,U+C50D-C50F,U+C511-C513,U+C515-C51B,U+C51D-C527,U+C52A-C52B,U+C52D-C52F,U+C531-C537,U+C53A,U+C53C,U+C53E-C543,U+C546-C547,U+C54B,U+C54F-C552,U+C556,U+C55A-C55C,U+C55F,U+C562-C563,U+C565-C567,U+C569-C56F,U+C572,U+C576-C57B,U+C57E-C57F,U+C581-C583,U+C585-C586,U+C588-C58B,U+C58E,U+C590,U+C592-C594,U+C596,U+C599-C59B,U+C59D-C59F,U+C5A1-C5A8,U+C5AA-C5B3,U+C5B6-C5B7,U+C5BA,U+C5BF-C5C3,U+C5CB,U+C5CD,U+C5CF,U+C5D2-C5D3,U+C5D5-C5D7,U+C5D9-C5DF,U+C5E2,U+C5E4,U+C5E6-C5EB,U+C5EF,U+C5F1-C5F3,U+C5F5,U+C5F8-C5FB;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.29f44960ea6e8122.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C602-C604,U+C609-C60B,U+C60D-C60F,U+C611-C617,U+C61A,U+C61D-C623,U+C626-C627,U+C629-C62B,U+C62F,U+C631-C632,U+C636,U+C638,U+C63A,U+C63C-C63F,U+C642-C643,U+C645-C647,U+C649-C64F,U+C652,U+C656-C65B,U+C65E-C65F,U+C661-C66B,U+C66D-C66E,U+C670,U+C672-C677,U+C67A-C67B,U+C67D-C67F,U+C681-C687,U+C68A,U+C68C,U+C68E-C693,U+C696-C697,U+C699-C69B,U+C69D-C6A3,U+C6A6,U+C6A8,U+C6AA-C6AF,U+C6B2-C6B3,U+C6B5-C6B7,U+C6BB-C6BF,U+C6C2,U+C6C4,U+C6C6-C6CB,U+C6CE-C6CF,U+C6D1-C6D3,U+C6D5-C6DB,U+C6DE-C6DF,U+C6E2-C6E7,U+C6EA-C6EB,U+C6ED-C6EF,U+C6F1-C6F7,U+C6FA-C6FC,U+C6FE-C6FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.5694e46e7cc89d41.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C700-C703,U+C706-C707,U+C709-C70B,U+C70D-C713,U+C716,U+C718,U+C71A-C71F,U+C722-C723,U+C725-C727,U+C729-C72F,U+C732,U+C734,U+C736,U+C738-C73B,U+C73E-C73F,U+C741-C743,U+C745-C749,U+C74B,U+C74E,U+C750,U+C759-C75B,U+C75D-C75F,U+C761-C767,U+C769-C76A,U+C76C-C773,U+C776-C777,U+C779-C77B,U+C77F-C782,U+C786,U+C78B-C78D,U+C78F,U+C792-C793,U+C795,U+C799,U+C79B-C79F,U+C7A2,U+C7A7-C7AB,U+C7AE-C7AF,U+C7B1-C7B3,U+C7B5-C7BB,U+C7BE,U+C7C2-C7C7,U+C7CA-C7CB,U+C7CD,U+C7CF,U+C7D1-C7D7,U+C7D9-C7DC,U+C7DE-C7E3,U+C7E5-C7E7,U+C7E9-C7EB,U+C7ED-C7FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.2fed7447c56ef267.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C802-C803,U+C805-C807,U+C809,U+C80B-C80F,U+C812,U+C814,U+C817-C81B,U+C81E-C81F,U+C821-C823,U+C825-C82B,U+C82E,U+C830,U+C832-C837,U+C839-C83B,U+C83D-C83F,U+C841-C847,U+C84A-C84B,U+C84E-C853,U+C855-C86F,U+C872-C873,U+C875-C877,U+C879,U+C87B-C87F,U+C882,U+C884,U+C888-C88A,U+C88E-C893,U+C895-C89C,U+C89E,U+C8A0,U+C8A2-C8A7,U+C8A9-C8BB,U+C8BE-C8C3,U+C8C5-C8C7,U+C8C9-C8CB,U+C8CD-C8D3,U+C8D6,U+C8D8,U+C8DA-C8DF,U+C8E2-C8E3,U+C8E5-C8F4,U+C8F6-C8FB,U+C8FE-C8FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.bf860038928a958b.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+C901-C903,U+C907-C90B,U+C90E,U+C910,U+C912-C917,U+C919-C92B,U+C92D-C933,U+C935-C94F,U+C952-C953,U+C955-C957,U+C959-C95F,U+C962,U+C964-C96B,U+C96D-C96F,U+C971-C973,U+C975-C97B,U+C97D-C987,U+C98A-C98B,U+C98D-C98F,U+C991-C997,U+C99A,U+C99C,U+C99E-C9BF,U+C9C2-C9C3,U+C9C5-C9C6,U+C9C9,U+C9CB-C9CF,U+C9D2,U+C9D4,U+C9D7-C9D8,U+C9DB,U+C9DE-C9DF,U+C9E1,U+C9E3,U+C9E5-C9E6,U+C9E8-C9EB,U+C9EE,U+C9F2-C9F7,U+C9FA-C9FB,U+C9FD-C9FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.79e8e06ed7416b3d.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+CA01-CA07,U+CA0A,U+CA0E-CA13,U+CA15-CA17,U+CA19-CA28,U+CA2A-CA4B,U+CA4E-CA4F,U+CA51-CA53,U+CA55-CA5B,U+CA5E,U+CA62-CA67,U+CA69-CA7C,U+CA7E-CA83,U+CA85-CA97,U+CA99-CABB,U+CABE-CABF,U+CAC1-CAC3,U+CAC5-CACB,U+CACE,U+CAD0,U+CAD2,U+CAD4-CAD7,U+CADA-CADF,U+CAE1-CAEB,U+CAED-CAF3,U+CAF5-CAFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.6002df957111822c.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+CB00-CB07,U+CB09-CB0F,U+CB11-CB13,U+CB15-CB17,U+CB19-CB1F,U+CB22-CB40,U+CB42-CB47,U+CB4A-CB4B,U+CB4D-CB4F,U+CB51-CB57,U+CB5A-CB5C,U+CB5E-CB63,U+CB65-CB77,U+CB7A-CB9B,U+CB9D-CBB7,U+CBB9-CBD3,U+CBD5-CBE3,U+CBE5-CBE6,U+CBE8,U+CBEA-CBFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.e973b9cf86448b81.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+CC00-CC0B,U+CC0E-CC0F,U+CC11-CC13,U+CC15-CC1B,U+CC1E-CC20,U+CC23-CC26,U+CC2A-CC2B,U+CC2D,U+CC2F,U+CC31-CC37,U+CC3A,U+CC3F-CC43,U+CC46-CC47,U+CC49-CC4B,U+CC4D-CC53,U+CC56,U+CC5A-CC5F,U+CC61-CC63,U+CC65,U+CC67,U+CC69-CC6F,U+CC71-CC74,U+CC76-CC97,U+CC9A-CC9B,U+CC9D-CC9F,U+CCA1-CCA7,U+CCAA,U+CCAE-CCB3,U+CCB6-CCB7,U+CCB9-CCBB,U+CCBD-CCC3,U+CCC6,U+CCC8,U+CCCA-CCCF,U+CCD1-CCD3,U+CCD5-CCE3,U+CCE5-CCEB,U+CCED-CCEF,U+CCF1-CCFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.d4dfd1527743a9b7.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+CD00,U+CD02-CD07,U+CD0A-CD0B,U+CD0D-CD0F,U+CD11-CD17,U+CD1A,U+CD1C,U+CD1E-CD23,U+CD25-CD27,U+CD29-CD2B,U+CD2D-CD38,U+CD3A-CD5B,U+CD5D-CD5F,U+CD61-CD63,U+CD65-CD6B,U+CD6E,U+CD70,U+CD72-CD77,U+CD79-CD87,U+CD89-CD93,U+CD96-CD97,U+CD99-CD9B,U+CD9D-CDA3,U+CDA6,U+CDA8,U+CDAA-CDAF,U+CDB1-CDC3,U+CDC5-CDCB,U+CDCD-CDCF,U+CDD1-CDE7,U+CDE9-CDEB,U+CDED-CDEF,U+CDF1-CDF7,U+CDFA,U+CDFC,U+CDFE-CDFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.312c48b3914ea8d0.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+CE00-CE03,U+CE05-CE07,U+CE09-CE0B,U+CE0D-CE13,U+CE15-CE18,U+CE1A-CE1F,U+CE22-CE23,U+CE25-CE27,U+CE29-CE2F,U+CE32,U+CE34,U+CE36-CE57,U+CE5A-CE5B,U+CE5D-CE5E,U+CE62-CE67,U+CE6A,U+CE6C,U+CE6E-CE73,U+CE76-CE77,U+CE79-CE7B,U+CE7D-CE83,U+CE86,U+CE88,U+CE8A-CE8F,U+CE92-CE93,U+CE95-CE97,U+CE99-CE9F,U+CEA2,U+CEA6-CEAB,U+CEAE-CEC0,U+CEC2-CEE3,U+CEE6-CEE7,U+CEE9-CEEA,U+CEED-CEF3,U+CEF6,U+CEFA-CEFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.d78f28c96c76cccc.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+CF02-CF03,U+CF05-CF07,U+CF09-CF0F,U+CF12,U+CF14,U+CF16-CF1B,U+CF1D-CF1F,U+CF21-CF23,U+CF25-CF2B,U+CF2E,U+CF32-CF37,U+CF39-CF53,U+CF56-CF57,U+CF59-CF5B,U+CF5D-CF63,U+CF66,U+CF68,U+CF6A-CF6F,U+CF72-CF73,U+CF75-CF77,U+CF79-CF7F,U+CF81-CF84,U+CF86-CF8B,U+CF8D-CFA0,U+CFA2-CFA7,U+CFA9-CFAF,U+CFB1-CFC3,U+CFC5-CFDF,U+CFE2-CFE3,U+CFE5-CFE7,U+CFE9-CFEF,U+CFF2,U+CFF4,U+CFF6-CFFB,U+CFFD-CFFF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.75629e46616c143e.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D001-D003,U+D005-D010,U+D012-D017,U+D019-D02C,U+D02E-D033,U+D036-D037,U+D039-D03B,U+D03D-D043,U+D046,U+D048,U+D04A-D04F,U+D051-D053,U+D055-D057,U+D059-D05F,U+D061-D06B,U+D06E-D06F,U+D071-D073,U+D075-D07B,U+D07E-D080,U+D082-D0A3,U+D0A6-D0A7,U+D0A9-D0AB,U+D0AD-D0B3,U+D0B6,U+D0B8,U+D0BA-D0BF,U+D0C2-D0C3,U+D0C5-D0C7,U+D0CA-D0CF,U+D0D2,U+D0D6-D0DB,U+D0DE-D0DF,U+D0E1-D0E3,U+D0E5-D0EB,U+D0EE,U+D0F2-D0F7,U+D0F9-D0FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.1db1016931109a0c.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D100-D10C,U+D10E-D12F,U+D132-D133,U+D135-D137,U+D139,U+D13B-D13F,U+D142,U+D146-D14B,U+D14E-D14F,U+D151-D153,U+D155-D15B,U+D15E,U+D160,U+D162-D167,U+D169-D16B,U+D16D-D17B,U+D17D-D183,U+D185-D187,U+D189-D19F,U+D1A2-D1A3,U+D1A5-D1A7,U+D1A9-D1AF,U+D1B2,U+D1B4,U+D1B6-D1B9,U+D1BB,U+D1BD-D1BF,U+D1C1-D1D7,U+D1D9-D1F3,U+D1F5-D1F7,U+D1F9-D1FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.766924328408deaa.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D200-D206,U+D208,U+D20A-D20F,U+D211-D22B,U+D22E-D22F,U+D231-D233,U+D235-D23B,U+D23E,U+D240,U+D242-D247,U+D249-D25B,U+D25D-D263,U+D265-D27F,U+D282-D283,U+D285-D287,U+D289-D28F,U+D292-D294,U+D296-D29B,U+D29D-D29F,U+D2A1-D2A3,U+D2A5-D2AB,U+D2AD-D2B0,U+D2B2-D2B7,U+D2BA-D2BB,U+D2BD-D2BE,U+D2C1,U+D2C3-D2C7,U+D2CA,U+D2CC-D2D3,U+D2D5-D2D7,U+D2D9-D2DB,U+D2DD-D2E3,U+D2E6-D2EF,U+D2F2-D2F3,U+D2F5-D2F7,U+D2F9-D2FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.d4e72238e3cdf225.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D302,U+D304,U+D306-D30B,U+D30F,U+D311-D313,U+D315,U+D317-D31B,U+D31E,U+D322-D324,U+D326-D327,U+D32A-D32B,U+D32D-D32F,U+D331-D337,U+D33A,U+D33E-D343,U+D346-D37B,U+D37E-D37F,U+D381-D383,U+D385-D38B,U+D38E,U+D392-D397,U+D39A-D39B,U+D39D-D39F,U+D3A1-D3A7,U+D3AA,U+D3AC,U+D3AE-D3B3,U+D3B5-D3B7,U+D3B9-D3BB,U+D3BD-D3C3,U+D3C6-D3C7,U+D3CA-D3CF,U+D3D1-D3D7,U+D3D9-D3E0,U+D3E2,U+D3E4-D3EB,U+D3EE-D3EF,U+D3F1-D3F3,U+D3F5-D3FB,U+D3FE;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.f03a92483da4a4b0.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D400,U+D402-D407,U+D409-D41C,U+D41E-D43F,U+D441-D443,U+D445-D45B,U+D45D-D45F,U+D461-D463,U+D465-D46C,U+D46E,U+D470-D477,U+D47A-D47B,U+D47D-D47E,U+D481,U+D483-D487,U+D48A,U+D48C,U+D48E-D493,U+D495-D4A8,U+D4AA-D4CB,U+D4CD-D4CF,U+D4D1-D4D3,U+D4D5-D4DB,U+D4DD-D4DE,U+D4E0-D4E7,U+D4E9-D4EB,U+D4ED-D4EF,U+D4F1-D4F7,U+D4F9-D4FA,U+D4FC,U+D4FE-D4FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.afcc5b26a32f2c08.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D500-D503,U+D505-D507,U+D509-D50B,U+D50D-D513,U+D516,U+D518-D53B,U+D53E-D53F,U+D541-D543,U+D545-D54B,U+D54E,U+D550,U+D552-D557,U+D55A-D55B,U+D55D-D55F,U+D561-D564,U+D566-D567,U+D56A,U+D56C,U+D56E-D573,U+D576-D577,U+D579-D57B,U+D57D-D583,U+D586,U+D58A-D58F,U+D591-D5A4,U+D5A6-D5C7,U+D5CA-D5CB,U+D5CD-D5CF,U+D5D1,U+D5D3-D5D7,U+D5DA,U+D5DC,U+D5DE-D5E3,U+D5E6-D5E7,U+D5E9-D5EB,U+D5ED-D5F3,U+D5F6,U+D5F8,U+D5FA-D5FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.c322ff4eec51459b.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D602-D603,U+D605-D607,U+D609-D60F,U+D612,U+D616-D61B,U+D61D-D61F,U+D621-D623,U+D625-D62C,U+D62E-D637,U+D63A-D63B,U+D63D-D63F,U+D641-D644,U+D646-D647,U+D64A,U+D64C,U+D64E-D650,U+D652-D653,U+D656-D657,U+D659-D65B,U+D65D-D666,U+D668,U+D66A-D66F,U+D672-D673,U+D675-D682,U+D684,U+D686-D68B,U+D68E-D68F,U+D691-D693,U+D695-D69C,U+D69E,U+D6A0,U+D6A2-D6A7,U+D6A9-D6AB,U+D6AD-D6AF,U+D6B1-D6B8,U+D6BA,U+D6BC-D6C3,U+D6C6-D6C7,U+D6C9-D6CB,U+D6CD-D6D0,U+D6D2-D6D3,U+D6D5-D6D6,U+D6D8,U+D6DA-D6DF,U+D6E1-D6E3,U+D6E5-D6E7,U+D6E9-D6EF,U+D6F1-D6F4,U+D6F6-D6FB,U+D6FE-D6FF;
}
@font-face {
  font-family: 'BG3 KR';
  src: url('fonts/serif/BuildersSerifKR.d3829e0faea5d3bf.woff2') format('woff2');
  font-display: optional;
  unicode-range: U+D701-D703,U+D705-D710,U+D712-D717,U+D71A-D71B,U+D71D-D71F,U+D721-D727,U+D72A,U+D72C,U+D72E-D733,U+D736-D737,U+D739-D73B,U+D73D-D743,U+D745-D746,U+D748,U+D74A-D74F,U+D752-D753,U+D755,U+D75A-D75F,U+D762,U+D764,U+D766-D768,U+D76A-D76B,U+D76D-D76F,U+D771-D773,U+D775-D77B,U+D77E-D780,U+D782-D787,U+D78A-D78B,U+D78D-D78F,U+D791-D797,U+D79A,U+D79C,U+D79E-D7A3;
}
/* 제목 글꼴 조각 끝 */
@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;
}

/* ══════════════════════════════════════════════════════════════════════════
   개편 토큰 — **색 이름이 아니라 역할 이름**으로 부른다 (2026-08-23)

   ⚠ **왜 이름을 바꾸나.** 밝은 판에서 「cream 글자」는 뜻이 안 선다. 두 판이 같은
   규칙을 쓰려면 「면·글자·선·강조」로 불러야 한다. 옛 이름(`--gold`·`--cream` …)은
   **안 지운다** — 1,960줄이 그걸 쓰고 있어서 한 번에 갈면 어디가 깨졌는지 못 본다.
   새 규칙은 역할 토큰만 쓰고, 옛 토큰은 그 아래로 **매핑해서** 남긴다.

   결정 기록: docs/superpowers/specs/2026-08-23-ui-overhaul-design.md
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  /* ── 면(surface) ── 뒤로 갈수록 위에 얹히는 판이다 */
  --bg:        #0b0907;   /* 바탕 */
  --surface:   #221c15;   /* 판 */
  --surface-2: #1a150f;   /* 판 위의 칸(접기 머리·탭 등) */
  --surface-3: #2a2319;   /* 그 위(hover·선택) */

  /* ── 글자 ── 셋뿐이다. 넷째가 필요하면 위계가 잘못된 것이다
     ⚠ **옛 `--faint-decorative`(#6d6353)는 글자로 쓰지 않는다** — 판 대비 2.86 으로
     기준(4.5) 미달이다(실측 2026-08-23). 그 색은 아래 `--line-2` 로만 남는다. */
  --text:      #e6dcc4;   /* 12.37 : 본문 */
  --text-2:    #9a8e76;   /*  5.22 : 보조 */
  --text-3:    #b3974d;   /*  3.77 : **큰 글자·비장식 전용** */

  /* ── 선 ── */
  --line:      #3b3122;
  --line-2:    #241c11;   /* 더 조용한 구분선 */

  /* ── 강조 ── 하나로 아낀다. 지금은 제목·링크·태그·밑줄·배지에 다 쓰여서
     「어디를 보라는 건지」가 안 선다. */
  --accent:       #c8a24c;
  --accent-quiet: #b3974d;   /* ⚠ #8d7439 였다 — 위 --gold-dim 주석의 실측 참고 */
  --danger:       #e0a03c;

  /* ── 글자 크기 ── 여섯을 넷으로 줄인다(옛: 8·10·11·12·13·15px 혼재)
     ⚠ 본문이 11–12px 이던 것이 「가시성이 낮다」의 **한** 원인이다.
     ⚠⚠ **처음에 「대비는 통과였다」고 적었다. 틀렸다**(2026-08-23 브라우저 실측).
     그렇게 읽은 까닭은 `tests/contrast.test.js` 가 **토큰 하나**(`--faint-readable`)
     만 재기 때문이다 — 절 제목이 쓰는 `--gold-dim` 은 아무도 안 재고 있었고
     세 배경 모두에서 기준 미달이었다. **초록불을 「전부 쟀다」로 읽은 자리다.** */
  --fs-sm:   12px;   /* 보조·라벨 */
  /* 칸에 딸린 아주 작은 라벨. 지금 쓰는 곳은 단축 바의 상위 시전 선택기 하나다 —
     46px 칸 아래에 들어가야 해서 --fs-sm(12px)로는 「1레벨」이 안 맞는다.
     ⚠ 리터럴로 박지 않는다: `tests/typography.test.js` 의 래칫이 **리터럴이 느는
     것**을 막는다. 새 크기가 필요하면 토큰을 만드는 것이 옳은 길이다. */
  --fs-xs:   10px;
  /* 단축 바 상위 슬롯 선택기의 높이. 모바일이 글자를 키우면 여기도 커진다. */
  --hbcast-h: 15px;
  /* 퀵슬롯 칸 아래 값 줄의 높이. 한 자리에서 정하고 나머지가 읽는다(`--hbcast-h` 와 같은 규약). */
  --hbval-h: 13px;
  /* ── 퀵슬롯 칸의 두 폭 ────────────────────────────────────────────────
     `--hb-cell` 이 **격자 한 열**이고 `--hb-icon` 이 그 안의 **아이콘 상자**다.
     시안 3a 가 64px 열에 46px 아이콘을 그린다 — 값 줄과 시전 레벨 고르기가
     46px 에 안 들어가서다.
     ⚠ **한 자리에서 정하고 나머지가 읽는다.** 여덟 군데가 46px 을 따로 적고
     있었고, 그러면 폭을 바꿀 때 한 곳이 반드시 빠진다.
     ⚠ `tests/hotbar-grid.test.js` 가 **열 폭과 칸 폭이 같은 수인지** 잰다 —
     둘 다 `--hb-cell` 을 읽으므로 어긋날 수 없다. */
  --hb-cell: 64px;
  --hb-icon: 46px;
  --fs-base: 13px;   /* 쓰는 화면 본문(계산·장비) */
  --fs-lg:   15px;   /* 훑는 화면 본문(게시판·프로필) */
  --fs-h:    20px;   /* 큰 수치 — 시트 능력치·계산 탭 스탯 값.
                        ⚠ 예전 주석은 「절 제목」이었는데 **틀렸다**(2026-08-24).
                        절 제목은 --fs-lg(15px)를 쓴다 — `body.bg3 .sub` 참고.
                        이름과 쓰임이 갈린 채로 두면 다음 사람이 제목에 이걸 쓴다. */
  --fs-hh:   26px;   /* 화면 제목 */
  /* ── 전투 시뮬레이션(계산 탭)이 쓰는 세 자리 ───────────────────────────
     시안이 요구한 11·24·34px 다. **리터럴로 안 박는다** — 위 `--fs-xs` 주석과
     같은 이유고, `tests/typography.test.js` 의 래칫이 지금 상한에 붙어 있어서
     리터럴로 넣으면 그 자리에서 빨개진다.
     이름은 크기가 아니라 **쓰임**으로 짓는다(`--fs-h` 가 이름과 쓰임이 갈려
     겪은 일이 바로 위에 적혀 있다). */
  --fs-micro:  11px;  /* 구역 번호 원·자원 핍 — --fs-xs(10px)로는 원 안에서 안 읽힌다 */
  --fs-num-md: 17px;  /* 행동 줄의 명중·맞으면 — 본문(13)보다 읽히되 기대 피해(20)보다 작다 */
  --fs-num-lg: 24px;  /* ③ 결과의 총 기대 피해 */
  --fs-num-xl: 34px;  /* ① 상대의 AC — 이 화면에서 제일 먼저 읽혀야 하는 수 */

  /* ── 여백 ── 4의 배수 하나로 (옛: 1·2·3·4·5·6·8·10px 이 섞여 있었다) */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px;

  /* ── 글꼴 ── ⚠ **제목만 세리프, 본문은 산세리프**(사용자 결정 2026-08-23).
     게임 세리프를 11–12px 본문에 `font-weight:500` 으로 쓰던 것이 「두껍고 안
     깔끔하다」의 원인이다. 분위기는 제목·수치가 지고, 읽는 몫은 산세리프가 진다. */
  --font-title: 'BG3 KR', 'BG3 EN', 'Apple SD Gothic Neo', Georgia, serif;
  /* ⚠ **Pretendard 가 맨 앞이다** — 이제 실제로 싣기 때문이다(위 @font-face).
     앞서는 'Apple SD Gothic Neo' 뒤에 있어서 맥에서는 영영 안 걸렸고, 윈도우에서는
     셋 다 없어 맑은 고딕으로 떨어졌다. 맨 앞에 두면 **두 판이 같은 글꼴로 뜬다.**
     뒤 항목들은 폰트를 못 받았을 때의 사다리로 남긴다. */
  --font-body: 'Pretendard', 'Apple SD Gothic Neo', 'Noto Sans KR', system-ui, sans-serif;
  --font-num: 'BG3 EN', 'SF Mono', ui-monospace, monospace;
}

/* 밝은 판. ⚠ **아직 뼈대다** — 강조색은 정하는 중이다(금색 #c8a24c 는 흰 배경에서
   대비 2.0 대라 글자로 못 쓴다). 켜는 자리·기억하는 법도 아직 안 정했다. */
:root[data-ui="light"] {
  --bg:        #f4f1ea;
  --surface:   #fffdf8;
  --surface-2: #efeade;
  --surface-3: #e5dece;
  --text:      #241d14;
  --text-2:    #5b5142;
  --text-3:    #7a5c1a;
  --line:      #d8cfba;
  --line-2:    #e8e1d0;
  --accent:       #7a5c1a;
  --accent-quiet: #9c8442;
  --danger:       #9a5b12;

  /* 등급 색 — 밝은 판. **같은 색을 못 쓴다**: 흰 바탕에서 「평범」 `#f0f0e7` 은
     1.05:1 로 사실상 안 보이고 「고급」 `#55fe88` 도 1.4:1 이다. 색상(hue)은 지키고
     명도만 내린다 — 등급을 색으로 알아보는 습관이 안 깨진다.
     실측(밝은 배경 `#faf7ef`·`#f2ece0`·`#ffffff` 셋): 최저 5.34:1. */
  --rar-common:    #4a463c;
  --rar-uncommon:  #146b32;
  --rar-rare:      #0d5f8a;
  --rar-veryrare:  #9c1263;
  --rar-legendary: #7d5a10;
  --rar-story:     #9c3c0a;
}

:root {
  --gold:      #c8a24c;
  /* ⚠ **읽기용이다 — 장식이 아니다.** `--gold-dim` 참조가 skin.css 78 ·
     style.css 8 · mobile.css 5 · mockup.html 7 곳이고, 그중 skin.css 만 봐도 **67곳이
     `color:`** 다(실측 2026-08-24, ui-overhaul-2 병합 뒤).
     대부분 11~13px 보조 글이라 WCAG large-text 예외(3:1)를 못 받는다.
     **절 제목이 전부 여기 물려 있다** — 이 한 값이 화면의 위계를 통째로 진다.

     옛 `#8d7439` 는 **셋 다 미달**이었다 — --ink 위 4.44 · 카드(#16110c) 4.19 ·
     --panel 위 3.77 (AA 4.5). 사용자 제보도 같은 말이었다:
     「블랙 배경에 폰트도 어두운 걸 써서 잘 보이지도 않는다」.

     `#b3974d` 는 같은 셋에서 7.05 · 6.65 · 5.98 로 여유를 두고 넘는다.
     ⚠ **금색 위계는 좁아진다 — 「그대로」가 아니다.** --gold(#c8a24c)와의 **직접**
     대비가 1.86 → **1.17** 이다. 그래도 강조색까지 올리지는 않는다(그러면 제목이
     강조와 같아져 위계가 아예 사라진다). 1.1 이 바닥이고 그 자리를
     tests/contrast.test.js 가 잰다.

     ⚠ **정본은 여기 하나다.** 같은 값을 따로 적어 둔 자리가 둘 더 있다 —
     mobile.css 의 `--m-dim`(skin.css 를 못 싣는 화면용 되돌림)과 mockup.html 의
     `--gold-dim`(링크는 안 걸려 있지만 배포에 실린다). 셋이 갈리면 터지도록
     tests/contrast.test.js 가 셋을 대조한다. */
  --gold-dim:  #b3974d;
  /* 제목 그라디언트 글자의 양끝(2026-09-05). 공식 사이트(baldursgate3.game)가 제목마다
     쓰는 `--text-gradient` 를 옮긴 것 — 밝은 끝은 그쪽 하이라이트(#fbcea0) 계열을 우리
     금색에 맞춰 눌렀고, 어두운 끝은 --gold-dim 한 단 아래.
     ⚠ 글자색 토큰이 아니다 — `color:` 에 쓰지 말 것. 대비 그물(tests/contrast.test.js)은
     `color: var(…)` 만 재므로 여기 두 값은 그물 밖이고, 그래서 배경으로만 쓴다. */
  --gold-hi:   #f3e2b4;
  --gold-lo:   #8c6d2c;
  --cream:     #e6dcc4;
  --muted:     #9a8e76;
  --faint-readable:   #9a8e76;
  --faint-decorative: #6d6353;
  --ink:       #0b0907;
  --panel:     #221c15;
  --line:      #3b3122;
  --warn:      #e0a03c;
  --bg3-serif: 'BG3 KR', 'BG3 EN', 'Apple SD Gothic Neo', 'Noto Serif KR', Georgia, serif;

  /* ── 아이템 등급 색 ────────────────────────────────────────────────────
     ⚠ **한때 이 여섯이 `web/lib/rarity.js` 안에 리터럴로 있었고, JS 가 인라인
     `style=` 로 여섯 화면에 주입했다.** 그래서 등급 색만 **CSS 를 통째로 우회**했고
     어두운 배경을 전제로 골라져 있었다 — 「평범」의 `#f0f0e7` 은 흰 바탕에서 안 보인다.
     밝은 판을 켜는 길을 막고 있던 것이 이것 하나였다.

     지금은 `등급색()` 이 **이 토큰을 가리키는 문자열**을 돌려준다. 값은 여기 한 곳에
     있고 판마다 갈아끼운다. **이름 대응표는 `rarity.js` 가 쥔다**(슬러그 ↔ 등급) —
     둘로 적으면 그게 또 둘째 생산자다.

     ⚠ **CSS 이름은 ASCII 다.** 등급 이름은 한글이지만 토큰은 슬러그를 쓴다 —
     `tests/contrast.test.js` 를 비롯한 그물들이 `[a-z0-9-]` 로 이름을 문다. */
  /* ⚠ **두 벌이다.** `-dark-` 붙은 것은 **판을 안 따라간다** — 어두운 카드 위에
     얹히는 자리(인게임 툴팁 `web/tooltip.css` 의 `.tt`)가 쓴다. 그 카드는 배경을
     `#1c1813` 으로 스스로 쥐는 **게임 그림 재현**이라, 밝은 판에서도 어두운 채다.
     판을 따라가는 이름을 거기 쓰면 **밝은 판에서 어두운 글자가 어두운 카드에**
     얹혀 안 보인다(「평범」 `#4a463c` 대 `#1c1813` → 1.5:1).
     ⚠ **값은 여기 한 번만 적는다.** 아래는 별칭이지 사본이 아니다 —
     `tests/rarity.test.js` 가 별칭을 풀어서 대조한다. */
  --rar-dark-common:    #f0f0e7;
  --rar-dark-uncommon:  #55fe88;
  --rar-dark-rare:      #55d4ff;
  --rar-dark-veryrare:  #fe55b8;
  --rar-dark-legendary: #e8c06c;
  --rar-dark-story:     #ff9055;

  /* 판을 따라가는 이름. 어두운 판에서는 위와 같다. */
  --rar-common:    var(--rar-dark-common);
  --rar-uncommon:  var(--rar-dark-uncommon);
  --rar-rare:      var(--rar-dark-rare);
  --rar-veryrare:  var(--rar-dark-veryrare);
  --rar-legendary: var(--rar-dark-legendary);
  --rar-story:     var(--rar-dark-story);
}

body.bg3 {
  margin: 0;
  min-height: 100vh;
  background: var(--ink) radial-gradient(ellipse at 50% -10%, #1c1610 0%, #0b0907 65%) fixed;
  color: var(--cream);
  /* ── 본문은 산세리프, 제목·수치만 세리프 (개편 1차, 2026-08-23) ────────────
     제보 「폰트가 두껍고 안 깔끔하다」의 원인은 **세리프 500 을 11–12px 본문에
     쓴 것**이었다. 분위기는 제목과 수치가 지고, 읽는 몫은 산세리프가 진다.
     ⚠ 옛 값은 `var(--bg3-serif)` · 14px · 1.65 였다. `--bg3-serif` 는 아직
     살아 있다 — 제목 쪽 자산 목록이 그 이름을 쓴다(`--font-title`). */
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: 1.7;               /* 1.65 → 1.7 : 줄 사이가 「몰려 있다」의 절반이다 */
  -webkit-font-smoothing: antialiased;
}
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; }

/* ── 활자 체계 ─────────────────────────────────────────────────────────
   화면 전체가 쓰는 활자 위계다. **한 화면의 규칙이 아니라 바탕 규칙**이라
   여기 산다 — 계산·장비·만들기·게시판이 전부 이것을 물려받는다.

   ⚠ `body.bg3` 를 붙여 구체성을 한 칸 올려 둔 것은 **일부러다.** 아래 각 화면
   절에 `.hint { font-size: 12px }` 처럼 낱개로 박아 둔 옛 값이 아직 남아 있고,
   그것들을 한꺼번에 걷으면 무엇이 달라졌는지 사람이 못 본다. 위계가 여기서
   이기게 해 두고, 화면 절을 손볼 때 하나씩 지운다.

   ⚠ **크기 값을 여기에 새로 만들지 않는다.** 정본은 `:root` 의 `--fs-*` 다. */

/* 제목은 게임 세리프. 분위기를 지는 자리가 여기다(사용자 결정 2026-08-23). */
body.bg3 h1, body.bg3 h2, body.bg3 h3, body.bg3 .sub,
body.bg3 .lv, body.bg3 .bg3-title, body.bg3 #pickertitle {
  font-family: var(--font-title);
  font-weight: 500;
}
/* 수치는 세리프를 쓰되 **자릿수를 고정**한다 — 표에서 숫자가 흔들리면 밀도가
   더 답답해 보인다. 어느 칸이 숫자 칸인지는 tests/typography.test.js 가 쥔다.
   ⚠ **공격 카드의 값도 여기 있어야 한다**(2026-09-06). 전엔 `.turndmg`(계산 탭)와
   `.gatkdmg`·`.gtotal b`(「내 빌드」)가 이 규칙 밖이라 **한 화면에서 같은 성격의 수가
   두 글꼴로 갈렸다** — 머리 타일의 「17.3」은 게임 글꼴(`.gtile .v` 가 `.v` 라 여기
   걸린다)인데 바로 아래 카드의 「8.6」과 합계의 「17.3」은 본문 산세리프였다(확대
   스크린샷으로 잡았다). 클래스 이름이 다를 뿐 같은 자리라, 규칙을 나누지 말고 얹는다. */
body.bg3 .v, body.bg3 .calcstat .v, body.bg3 .econv, body.bg3 .glv .n,
body.bg3 .turndmg, body.bg3 .gatkdmg, body.bg3 .gtotal b, body.bg3 .simac {
  font-family: var(--font-num); font-variant-numeric: tabular-nums;
}

/* 글자 크기 바닥. 실측(2026-08-23): 11px 42곳 · 10px 9곳 · 8px 5곳.
   ⚠ 계산·장비는 「쓰는 화면」이라 훑는 화면(15px)까지 안 벌린다 — 한 화면에
   안 들어간다(설계 정본의 결정 1: 밀도는 화면마다). */
body.bg3 .hint, body.bg3 .calcstat .k, body.bg3 .glv .cls,
body.bg3 .reactioncost, body.bg3 .turnrange, body.bg3 .econk { font-size: var(--fs-sm); }
body.bg3 .hint { color: var(--text-2); line-height: 1.65; }

/* ⚠ **글자에 쓰던 흐린 색을 걷는다** — `--faint-decorative`(#6d6353)는 판 대비
   2.86 으로 기준(4.5) 미달이다. 선으로만 남긴다. */
body.bg3 .reactioncost, body.bg3 .hint { color: var(--text-2); }

/* ⚠⚠ **상태가 붙은 힌트는 제 색을 되찾는다** (2026-08-24).
   위 `body.bg3 .hint` 는 구체성 (0,2,1) 이고 `.hint.warn` 은 (0,2,0) 이라,
   개편 1차가 이 규칙을 들이면서 **경고색이 통째로 졌다.** 화면 25자리(게시판
   저장 실패·파티 불러오기 실패·프로필 오류)와 능력치 초과 안내 1자리가 조용히
   회색으로 떴다 — `.hint.over` 옆에는 「초과 상태를 색 하나로만 알리지 않는다」는
   주석까지 붙어 있는데 그 색조차 없어진 상태였다.
   **끄지 않고 옮긴다** — 상태 쪽 구체성을 한 칸 올려 순서와 무관하게 이기게 한다.
   tests/contrast.test.js 가 「상태 힌트가 실제로 이기나」를 잰다. */
body.bg3 .hint.warn { color: var(--warn); }
body.bg3 .hint.over { color: var(--warn); }

/* 절 제목 — 지금은 본문과 크기가 거의 같아 **어디서 절이 갈리는지** 안 보인다.
   ⚠⚠ **`.sub` 의 주인은 이 규칙 하나다** (2026-08-24 정리). 그 전에는 셋이 다퉜다:
       h3.sub          (옛 규칙)  12px · 금색 · **위 선**
       body.bg3 .sub   (개편 1차) 20px · 본문색 · **아래 선**
       body.bg3 h3.sub (절 제목)  15px
   그래서 같은 역할인데 **태그마다 다르게** 떴다 — `<h3>` 은 15px 에 **선이 위아래
   둘**, `<summary>`(계산 탭 접는 절)는 20px 에 아래 선 하나.
   ⚠ **15px 으로 통일했다.** `<h3 class="sub">` 이 57자리, `<summary class="sub">` 가
   3자리라 20px 로 올리면 57자리가 움직이는데 **그것을 눈으로 확인할 수단이 없다.**
   적게 움직이는 쪽을 골랐다 — 크기를 올릴 생각이면 사람이 보고 정할 일이다.
   ⚠ **선은 아래 하나다.** 제목 밑의 선이 「여기부터 이 절」을 뜻한다. 위아래 둘은
   앞 절과 이 절을 두 번 가르는 꼴이라 덩어리가 안 읽힌다. */
body.bg3 .sub {
  font-size: var(--fs-lg);
  color: var(--text);
  letter-spacing: .06em;
  line-height: 1.4;
  border-bottom: 1px solid var(--line-2);
  padding-bottom: var(--sp-2);
  margin: var(--sp-5) 0 var(--sp-3);
}

/* ── 절 제목이 본문보다 안 보이던 것 (2026-08-23) ──────────────────────────
   사용자 제보(「내 빌드」·「장비」 화면 스크린샷 셋):
   「블랙 배경에 폰트도 어두운 걸 써서 잘 보이지도 않고 텍스트만 와바박 모여 있다」.

   재 보니 **감이 아니라 수치로** 그랬다:

       절 제목  #8d7439 · 11px · 자간 .22em   대비 4.44 : 1   ← 기준 4.5 미달
       본문     #e6dcc4 · 13px               대비 14.58 : 1

   **제목이 본문보다 어둡고 작았다 — 위계가 거꾸로다.** 크기 차이가 11 대 13px 뿐이라
   「어디가 제목인가」를 오직 색으로만 구분하는데, 그 색이 화면에서 제일 어두웠다.

   ⚠ **자간도 원인이다.** `.22em` 은 라틴 소문자 라벨을 겨눈 값인데 우리 제목은
   한글이다. 11px 한글에 그 자간을 주면 글자가 **낱개 블록으로 흩어져** 한 낱말로
   안 읽힌다. 크기를 올리면서 자간은 내린다.

   색은 토큰(`--gold-dim`)에서 이미 올렸다 — 여기서는 **크기·자간·간격**만 잡는다. */
/* ⚠ `h3.sub` 은 여기서 뺐다 — 위 `body.bg3 .sub` 가 태그를 안 가리고 덮는다.
   여기 남겨 두면 `<h3>` 만 값이 갈려 또 태그마다 다르게 뜬다. */
body.bg3 .gsec,
body.bg3 .gact .h,
body.bg3 #detail h3,
body.bg3 .taggroup h4,
body.bg3 .tagpicker summary,
body.bg3 #pfform legend {
  font-size: var(--fs-lg);
  letter-spacing: .06em;
  line-height: 1.4;
}
/* ⚠ **`.flabel` 은 이 무리에서 뺐다 — 절 제목이 아니라 줄 이름표다** (2026-08-24).
   `슬롯`·`등급`·`막`(items.html)과 `명중`·`피해`(panels/calc.js 의 수식 펼치기)가
   같은 클래스를 쓴다. 제목 무리에 넣으면 11 → 15px 이 되어 **칩·수치보다 커져**
   위계가 뒤집히고, `align-items: baseline` 인 줄에서 baseline 이 흔들린다.

   ⚠⚠ **되돌리는 규칙이 `style.css` 에만 있었다.** 그 파일은 `items.html` 만 싣고
   `build.html` 은 안 싣는다 — 그래서 필터 라벨은 멀쩡한데 **계산 탭의 「명중」·
   「피해」만 커진 채**였다. CLAUDE.md 층 표의 「두 페이지가 싣는 파일이 다르다」가
   정확히 이 자리다. **두 페이지에 다 닿는 여기(skin.css)에서 정한다.**

   ⚠ **크기만 여기서 정한다 — 자간은 화면마다 다르다.** 아이템 필터는 시안의
   금색 소문자 라벨이라 `.22em`(style.css), 계산 탭 수식 라벨은 `.08em`(아래
   `.flabel` 기본)이다. 하나로 묶으면 둘 중 하나가 반드시 틀린다. 옛 되돌림
   규칙이 `.12em` 이라는 **셋째 값**을 만들고 있었는데 그것도 같이 걷는다. */
body.bg3 .flabel { font-size: var(--fs-sm); }
/* 제목 위의 숨 쉴 자리. 「텍스트만 와바박 모여 있다」는 **줄 사이**가 아니라
   **덩어리 사이**가 없다는 말이다 — 절이 어디서 갈리는지가 안 보인다. */
body.bg3 .sub, body.bg3 .gsec, body.bg3 #detail h3 { margin-top: var(--sp-5); }
/* ⚠ 첫 제목은 예외다 — 판 맨 위에 빈 칸이 생기면 그게 또 「비었다」로 보인다. */
body.bg3 .gcol > .gsec:first-child,
body.bg3 #detail > h3:first-of-type { margin-top: var(--sp-2); }

/* 「기술」·「내성 굴림」 같은 **속 라벨**은 절 제목이 아니다 — 한 칸 아래 위계다.
   같이 키우면 절 제목과 안 갈린다. 크기는 두고 **색만** 본문 쪽으로 당긴다. */
body.bg3 .gsub { color: var(--text-2); font-size: var(--fs-sm); letter-spacing: .04em; }

/* ── 창틀 ───────────────────────────────────────────────────────────────
   게임의 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 {
    border: 46px solid transparent;
    padding: 0 4px 8px;
  }
  .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) {
    .pane { border-width: 18px; padding: 0 2px 6px; }
    .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 안쪽에서 시작해 빈 띠가 생긴다. */
  #editor.pane { border-width: 14px; }
  .pane.buildlist, .credits .pane { border-width: 20px; }
  .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) {
    #editor.pane { border-width: 10px; }
    .pane.buildlist, .credits .pane { border-width: 12px; }
    .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 로고 글꼴, 투명 배경, 금색 현재 밑줄을 모든 페이지에 적용한다.
   내 정보는 오른쪽 끝에, 데이터 개수와 스포일러 옵션은 다음 줄에 둔다. */
.bg3-header {
  position: relative; isolation: isolate; z-index: 50;
  min-height: 88px;
  box-sizing: border-box;
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 32px;
  row-gap: 0;
  max-width: 1440px; margin: auto; padding: 16px 64px;
  border: 0;
  text-align: left;
  background: transparent;
}
.bg3-header::before { content: none; }

.bg3-header h1 {
  order: 0; flex: none;
  margin: 0; line-height: 1;
  font-size: clamp(20px, 1.8vw, 24px);
  letter-spacing: -.025em;
  text-indent: 0;
}
body.bg3 .bg3-header h1 {
  font-family: var(--font-body);
  font-weight: 700;
}
.bg3-header .sitebrand {
  flex: none;
  display: inline-flex; align-items: center;
  min-height: 44px;
  color: var(--text);
  font-family: 'BG3 EN', serif;
  font-size: 24px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .06em;
  text-decoration: none;
  white-space: nowrap;
  text-shadow: none;
}
.bg3-header .sitebrand:hover { color: #fff; }
.bg3-header .sitebrand:focus-visible,
.bg3-header .sitetab:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 4px;
}

/* 큰 카테고리. 단추처럼 보이게 하던 테두리·상자·그라디언트는 없다. */
.bg3-header nav.sitetabs {
  order: 1; flex: 1 0 calc(100% - 240px);
  align-self: stretch;
  min-width: max-content;
  margin: 0;
  display: flex; align-items: stretch; justify-content: center; flex-wrap: nowrap;
  gap: 32px;
  position: static;
}
.bg3-header .sitetab {
  position: relative;
  min-height: 44px;
  display: inline-flex; align-items: center;
  padding: 0;
  border: 0; border-radius: 0;
  background: none;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  font-weight: 400;
  letter-spacing: -.01em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: color .14s ease;
}
.sitetab::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 4px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .14s ease;
}
.sitetab:hover,
.sitetab[aria-current] { color: var(--accent); }
.sitetab:hover::after,
.sitetab:focus-visible::after,
.sitetab[aria-current]::after { transform: scaleX(1); }

.bg3-header .siteprofile { order: 1; margin-left: auto; }

/* 언어 전환은 보조 링크다. 버튼 상자 없이 헤더 오른쪽의 금색 텍스트로 둔다. */
.bg3-header > .locale-switch,
.bg3-header > [data-locale-switch] {
  order: 2;
  flex: none;
  margin-left: auto;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--muted, #bdbdbd);
  font: inherit;
  font-size: var(--fs-sm);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: color .14s ease, opacity .14s ease;
}
.bg3-header > .locale-switch:hover,
.bg3-header > .locale-switch:focus-visible,
.bg3-header > [data-locale-switch]:hover,
.bg3-header > [data-locale-switch]:focus-visible {
  color: var(--accent);
  opacity: 1;
}
.bg3-header > .locale-switch:focus-visible,
.bg3-header > [data-locale-switch]:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 5px;
}

/* 긴 영어 메뉴도 모든 화면에서 같은 규칙으로 줄을 나눈다. */
html[lang="en"] .bg3-header nav.sitetabs { flex-wrap: wrap; }

/* 보조 정보가 언어 전환과 같은 줄의 너비를 나눠 갖지 않게 한다. */
.bg3-header > .hdrfresh,
.bg3-header > .hdrstats,
.bg3-header > .cx-fresh,
.bg3-header > .spoilerfree {
  order: 3; flex: 0 0 100%;
  margin: 0;
  color: #bdbdbd;
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  white-space: normal;
}

/* 홈과 같은 메뉴 배치를 위해 머리말의 보조 검색은 숨긴다.
   검색은 홈과 모바일 전체 메뉴에서 제공한다. */
.bg3-header > .siteq { display: none; }
.bg3-header > .siteq input {
  width: clamp(160px, 16vw, 240px); box-sizing: border-box; min-height: 32px;
  font: inherit; font-size: var(--fs-sm); color: var(--text);
  background: var(--ink); border: 1px solid var(--line); border-radius: 2px;
  padding: 5px 10px;
}
.bg3-header > .siteq input:focus-visible { outline: none; border-color: var(--gold); }

@media (max-width: 1100px) {
  .bg3-header { padding: 16px 32px; gap: 24px; }
  .bg3-header nav.sitetabs { gap: 20px; }
}
@media (max-width: 900px) {
  .sitetab { font-size: var(--fs-lg); }
  /* 긴 데이터 판·개수는 메뉴와 겹치는 것보다 이 폭에서 접는 편이 낫다.
     모바일에서는 위 메뉴 자체가 사라지므로 mobile.css가 다시 보여 준다. */
  .bg3-header > .hdrfresh,
  .bg3-header > .hdrstats,
  .bg3-header > .cx-fresh { display: none; }
  /* 스포일러 방지는 동작이라 숨기지 않고 둘째 줄을 준다. */
  .bg3-header > .spoilerfree {
    order: 3;
    flex-basis: 100%;
    padding-bottom: 9px;
  }
  /* 검색도 이 폭에선 한 줄에 안 들어간다 — 스포일러 방지처럼 제 줄을 준다(그 앞). */
  .bg3-header > .siteq { order: 3; flex-basis: 100%; padding-bottom: 9px; }
  .bg3-header > .siteq input { width: 100%; }
}

/* ── 프로필 화면 ────────────────────────────────────────────────────── */
.profilepane { margin: 0 0 14px; }
.profilepane .account { justify-content: flex-start; }
.clouddocs { list-style: none; margin: 10px 0 0; padding: 0; }
/* ⚠ **행 구분선의 정본은 여기 하나다**(2026-08-25, 홈 디자인 피드백 ⑦로 실측 후 정리).
   `.narrow .clouddocs li`(아래 「게시판 — 훑는 화면의 밀도」절)가 전에 이 색을
   `var(--line-2)` 로 다시 적었는데, `--line-2`(#241c11)는 `.pane` 배경(#221c15cc,
   합성하면 거의 같은 값)과 거의 안 갈려 **board.html 에서는 줄이 사실상 안 보였다**
   (사용자가 운영 화면에서 확인 — 홈의 같은 `.clouddocs` 는 이 기본 규칙만 받아
   보였다). 좁은 화면 절이 `border-bottom` 을 다시 안 적어야 이 규칙이 그대로
   먹는다 — **복붙해서 재정의하지 말 것.** 정말 다른 색이 필요하면 그 예외를
   여기 이 주석에 적고 실제 배경에 대고 대비를 잰 값을 쓸 것. */
.clouddocs li {
  display: flex; justify-content: space-between; gap: 12px; align-items: baseline;
  /* ⚠ 긴 게시물 제목·표시 이름이 카드를 밀지 않게 한다(계정 3-2 Task 7,
     설계 §6 — 「긴 표시 이름이 카드/화면 폭을 밀어내지 않는다」). 기본값
     `flex-wrap: nowrap` 에 자식들의 `min-width: auto` 가 겹치면 글자가 줄어들지
     못하고 옆으로 밀린다 — 아래 `.cdname`·`.cdmeta` 의 `min-width: 0` 과 한 쌍이다. */
  flex-wrap: wrap;
  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; }
/* 그 쌓임을 **무엇이** 쌓나. 장비마다 한 줄이라 조건이 서로 다른 것이 드러난다
   (「번개·천둥·광휘 피해일 때만」 대 「조건 없이 맞힐 때마다」). */
.stacksrc { margin: 0 0 4px 0; padding-left: 14px; list-style: disc;
  font-size: 11px; color: var(--gold-dim); line-height: 1.6; opacity: .85; }
/* `min-width: 0` 없이는 flex 자식이 내용 폭 아래로 못 줄어든다 — 긴 표시
   이름·제목이 그대로 카드를 밀어낸다(위 `.clouddocs li` 주석과 한 쌍). */
.cdname { color: var(--gold); min-width: 0; overflow-wrap: break-word; }
/* 빌드 줄·카드의 클래스 아이콘(web/lib/class-icon.js, 2026-09-05). 제목 앞에 최대 셋.
   `flex: none` — 카드(`.homecard`)가 flex 라 아이콘이 줄어들지 않게. 세로 정렬은
   글자 밑선에 맞춘다(-5px: 20px 그림을 13px 글자 옆에 세울 때 눈으로 맞춘 값). */
.clsicons { display: inline-flex; gap: 2px; vertical-align: -5px; margin-right: 6px; flex: none; }
.clsico { width: 20px; height: 20px; object-fit: contain; }
.cdmeta { color: var(--gold-dim); font-size: 12px; min-width: 0; white-space: normal; overflow-wrap: break-word; }
/* 클라우드 문서 픽커 행(`클라우드문서줄HTML`, board.js) — 「게시판에 새로
   쓰기」·「빌드 새 판 올리기」 창(`#clouddocpick`)의 「내 저장 목록」.
   ⚠ **`.clouddocs li` 의 직계 자식이 span 셋이 아니라 버튼 하나다** — 위
   `justify-content: space-between` 은 직계 자식만 벌리므로, 두 줄(제목 ·
   요약+시간)은 버튼 안에서 따로 짠다. 버튼은 `.buildlist`·`.pickerlist`
   바깥이라(그 두 곳의 `.build-row`·`.picker-row` 리셋이 안 닿는다) 기본 UA
   단추 모양을 여기서 직접 지운다. */
.cdpickrow {
  display: flex; flex-direction: column; gap: 4px;
  width: 100%; padding: 0; text-align: left;
  font: inherit; color: inherit; background: none; border: 0; cursor: pointer;
}
.cdpickrow:hover { background: #ffffff08; }
/* 요약(왼쪽) · 상대 시간(오른쪽) — 게시판 행이 `.clouddocs li` 전체를 좌우로
   벌리는 것과 같은 결을, 여기서는 이 한 줄 안에서 흉내 낸다. `margin-left:
   auto` 라 요약이 없어 시간 혼자 남아도(빈 목록이 아니라 요약이 빈 문서일
   때) 여전히 오른쪽에 붙는다. */
.cdpickmeta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
.cdpickmeta .cdsum { min-width: 0; }
.cdpickmeta .cdmeta { margin-left: auto; white-space: nowrap; }
/* 게시판 작성자 링크(계정 3-2 Task 7) — 목록·상세가 같이 쓴다(`board.js`). */
.authorlink { color: var(--gold-dim); text-decoration: underline; text-underline-offset: 2px; }
.authorlink:hover { color: var(--gold); }
/* 레벨마다 붙이는 설명. `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; }

/* ── 공개 프로필 (계정 3-2 Task 7) ────────────────────────────────────────
   `profile.html` 의 카드·`author.html` 의 공개 화면·편집 폼이 같이 쓴다
   (web/lib/profile-editor.js · web/author.js).

   ⚠ **테마는 accent 색 하나만 바꾼다** — `profile-vocabulary.js` 머리말의
   「본문 색을 바꾸지 않는다」를 그대로 지킨다. 다섯 값 전부 `--pf-*` 로
   :root 에 한 번만 적어 두고 `.pfcard`·`.pfswatch` 가 `data-theme` 로 고른다 —
   색을 두 자리에 따로 적으면 갈린다(CLAUDE.md 「공유 어휘」와 같은 결). */
:root {
  --pf-gold: var(--gold);
  --pf-ember: #c9612f;
  --pf-arcane: #8f7fe0;
  --pf-grove: #6f9c4a;
  --pf-frost: #5ea8c9;
}
.pfcard {
  --pf-accent: var(--pf-gold);
  display: flex; gap: 14px; align-items: flex-start;
  padding: 12px; border: 1px solid var(--line);
}
.pfcard[data-theme="ember"]  { --pf-accent: var(--pf-ember); }
.pfcard[data-theme="arcane"] { --pf-accent: var(--pf-arcane); }
.pfcard[data-theme="grove"]  { --pf-accent: var(--pf-grove); }
.pfcard[data-theme="frost"]  { --pf-accent: var(--pf-frost); }

.pfavatar {
  flex: none; width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; border: 2px solid var(--pf-accent);
  background: #17130d; overflow: hidden;
}
/* 폼 안의 아바타 후보는 더 작다 — 라디오 한 줄에 이름표까지 나란히 놓인다. */
.pfavatar.pfavatar-sm { width: 28px; height: 28px; }
.pfavatar-img { width: 100%; height: 100%; object-fit: contain; padding: 8px; box-sizing: border-box; }
.pfavatar-initial { font-size: 20px; color: var(--pf-accent); }
.pfavatar-sm .pfavatar-initial { font-size: 13px; }

.pfmeta { min-width: 0; flex: 1 1 auto; }
.pfname { color: var(--cream); font-size: 15px; margin: 0; overflow-wrap: break-word; }
.pfhandle { color: var(--pf-accent); font-size: 12px; margin: 2px 0 0; overflow-wrap: break-word; }
.pfbio { color: var(--muted); font-size: 13px; margin: 6px 0 0; white-space: pre-line; overflow-wrap: break-word; }

.pfroles { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; padding: 0; list-style: none; }
.pfroles li { border: 1px solid var(--line); color: var(--gold-dim); font-size: 11px; padding: 2px 8px; }

/* 편집 폼(`#pfform`, web/lib/profile-editor.js). */
#pfform .row { display: flex; flex-direction: column; gap: 4px; margin: 0 0 10px; }
#pfform fieldset { border: 1px solid var(--line); margin: 0 0 10px; padding: 8px; }
#pfform legend { color: var(--gold-dim); font-size: 12px; padding: 0 4px; }
.pfchoice { display: flex; align-items: center; gap: 6px; padding: 4px 0; }
.pfchoice input { margin: 0; }
.pfswatch {
  display: inline-block; width: 14px; height: 14px; border-radius: 50%;
  background: var(--pf-swatch, var(--pf-gold));
}
.pfswatch[data-theme="gold"]   { --pf-swatch: var(--pf-gold); }
.pfswatch[data-theme="ember"]  { --pf-swatch: var(--pf-ember); }
.pfswatch[data-theme="arcane"] { --pf-swatch: var(--pf-arcane); }
.pfswatch[data-theme="grove"]  { --pf-swatch: var(--pf-grove); }
.pfswatch[data-theme="frost"]  { --pf-swatch: var(--pf-frost); }

.pfconfirm h3 { margin: 0 0 10px; color: var(--gold); font-weight: normal; }
/* 철회 확인 화면의 「무엇이 지워지고 무엇이 남는지」 목록(계정 3-2 검수 대응 C1). */
.pfconfirm ul { margin: 10px 0; padding-left: 18px; color: var(--muted); font-size: 13px; line-height: 1.6; }
.pfconflict {
  border-left: 2px solid var(--warn); padding: 6px 10px; margin: 0 0 10px;
  color: var(--muted); font-size: 12px;
}

/* ── 게시판 — 훑는 화면의 밀도 (2026-08-23) ────────────────────────────────
   ⚠ 계산 탭과 **다른 밀도**다(설계 정본의 결정 1). 여기는 훑는 화면이라
   크게·성기게 간다. 참고 사이트의 개방감은 ① 큰 글자 ② 넓은 행 ③ 거르개를
   목록 위 한 줄로 세운 것에서 온다 — 셋 다 여기서 가져온다.
   없는 축(공지·뉴스)은 **지어내지 않는다.**
   ⚠ **`border-bottom` 을 여기서 다시 안 적는다** — 위 `.clouddocs li` 의 정본
   규칙을 그대로 물려받는다(2026-08-25 정리, 위 주석 참고). 전에는 `--line-2`
   로 다시 적어서 board.html 에서 줄이 사실상 안 보였다. */
.narrow .clouddocs { font-size: var(--fs-lg); }
/* ⚠ **좋아요·조회(`.cdstats`)가 제 줄을 다 차지해 목록이 세로로 길었다**
   (홈 디자인 웨이브 4, 2026-08-25 — 사용자가 운영 게시판 스크린샷에서 지적).
   `display: grid` 에 열을 안 정해 두면 자식 넷(cdname·cdsum?·cdmeta·cdstats?)이
   전부 제 줄을 갖는다 — 그게 하트·눈이 통째로 한 줄을 먹던 원인이다.
   2열(`1fr auto`)로 바꾸고 `cdname`·`cdsum` 만 두 칸을 다 잇게(`1/-1`) 해서
   전체 폭을 쓰고, `cdmeta`(왼쪽 칸)·`cdstats`(오른쪽 칸)는 **한 줄을 나눠
   갖는다.** 마크업 순서(`목록줄HTML`: cdname → cdsum? → cdmeta → cdstats?)를
   그대로 두고 칸만 지정하면, 그리드 자동 배치가 「그 칸이 빈 줄」을 찾아
   채운다 — `cdsum` 이 없으면 `cdmeta` 가 곧장 둘째 줄로 올라오고, `cdstats`
   가 없으면 `cdmeta` 혼자 그 줄을 쓴다(실측: 넷 다 있을 때·`cdsum` 없을
   때·`cdstats` 없을 때 셋 다 확인). */
.narrow .clouddocs li {
  padding: var(--sp-3) var(--sp-2);
  display: grid; grid-template-columns: 1fr auto; gap: 2px 8px;
}
.narrow .cdname { grid-column: 1 / -1; }
.narrow .cdname a { font-size: var(--fs-lg); line-height: 1.5; text-decoration: none; }
.narrow .cdname a:hover { text-decoration: underline; text-underline-offset: 3px; }
.narrow .cdsum { grid-column: 1 / -1; color: var(--text-2); font-size: var(--fs-base); }
.narrow .cdmeta { grid-column: 1; color: var(--text-2); font-size: var(--fs-sm); }
/* `.cdstats` 는 이제 `.cdmeta` 와 **같은 줄의 둘째 칸**(오른쪽 끝)이다 —
   `auto` 트랙이 제 내용 폭만 차지해 `1fr` 칸을 밀어내며 저절로 오른쪽에
   붙는다(넓은 화면의 `justify-content: space-between` 과 같은 「우측 정렬」
   결과). 전에는 `justify-self: end` 로 **제 줄 안에서** 오른쪽에 붙였는데,
   지금은 칸 자체가 오른쪽이라 그 선언이 필요 없다 — 세로 가운데만 맞춘다. */
.narrow .cdstats { grid-column: 2; align-self: center; }

/* 거르개 칩 줄. 시안의 「전체 · 자유 · 플레이 · 직업」 자리인데, 우리 데이터에 있는
   축은 **직업 하나**라 그것만 세운다. 고른 것 하나에만 색을 준다 — 강조는 아낀다. */
.chiprow {
  display: flex; flex-wrap: wrap; gap: 0;
  margin: var(--sp-4) 0 var(--sp-3);
  padding: 4px 0 8px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.chiprow .chip {
  position: relative; display: inline-flex; align-items: center;
  gap: 6px;
  font: inherit; font-size: var(--fs-sm);
  padding: 6px 14px;
  background: transparent; color: var(--text-2);
  border: 0; border-radius: 0;
  cursor: pointer;
}
.chiprow .boardchip-icon {
  width: 22px; height: 22px; flex: none; object-fit: contain;
  filter: saturate(.8) brightness(.9);
}
.chiprow .chip:hover .boardchip-icon,
.chiprow .chip.on .boardchip-icon { filter: none; }
.chiprow .chip + .chip::before {
  content: ''; position: absolute; left: 0; top: 50%; width: 1px; height: 14px;
  background: var(--line); transform: translateY(-50%);
}
.chiprow .chip:hover { color: var(--text); }
.chiprow .chip.on {
  color: var(--accent); background: transparent;
}
.chiprow .chip.on::after {
  content: ''; position: absolute; right: 14px; bottom: 1px; left: 14px; height: 1px;
  background: var(--accent);
}
@media (max-width: 720px) {
  .chiprow .chip { padding-right: 10px; padding-left: 10px; }
  .chiprow .boardchip-icon { width: 20px; height: 20px; }
}
/* 좋아요·조회 — 행 오른쪽에 따로 앉는다(홈 디자인 피드백, 2026-08-25). 전에는
   `.cdlike` 로 `.cdmeta` 문장 끝에 ` · ♥ N` 으로 붙어 있었다 — 「글쓴이 · N일 전」
   문장에 섞여 위치가 이상하다는 지적을 받아 홈 카드(`home.css` 의 `.hclikes`)와
   같은 결로 뺐다. `.clouddocs li` 가 `justify-content: space-between` 이라
   마지막 자식이 저절로 행 오른쪽에 붙는다 — 정본은 `web/lib/board-row.js`
   의 `목록줄HTML`. */
.cdstats { flex: none; font-size: 12px; color: var(--gold-dim); white-space: nowrap; }
/* 좋아요·조회 아이콘 배지(하트·눈, 인라인 SVG) — `community-stats.js` 의
   `참여배지` 가 낸다. 홈 카드(`.hclikes`, home.css)와 게시판 목록 줄(`.cdstats`,
   위)이 같이 쓰는데 **두 화면이 싣는 CSS 파일이 다르다**(index.html 은
   home.css 도 신지만 board.html 은 skin.css·mobile.css 뿐이다) — 그래서 둘 다
   신는 이 파일에 정본을 둔다. 크기는 부모의 font-size 에 `em` 으로 따라가
   `.hclikes`(11px)·`.cdstats`(12px) 양쪽에서 따로 안 맞춰도 된다(홈 디자인
   웨이브 3, 2026-08-25).
   ⚠ **`vertical-align: middle`(홈 다듬기 웨이브, 2026-08-25)** — `.hcstat` 은
   `inline-flex` 라 안에서는(아이콘·수) `align-items: center` 로 이미 서로
   가운데 맞는다. 그런데 `.hcstat` **자기 자신**이 부모 줄(`.hclikes`)
   안에서는 기본값(`vertical-align: baseline`)을 받아 글줄의 베이스라인에
   붙어 **줄의 시각적 중앙보다 살짝 위**로 떠 보였다(실측: iframe 프로브로
   잰 중심이 줄 상자 중심보다 1.4px 위 — 사용자가 스크린샷에서 지적한
   자리). `middle` 로 바꾸면 부모 글자의 x-height 중간에 맞아 그 차이가
   준다. 아이콘도 `1em → 1.15em` 으로 살짝 키웠다(11px 문맥에서 +1.65px ·
   12px 문맥에서 +1.8px — 「1~2px 급」 지시 안). */
.hcstat { display: inline-flex; align-items: center; gap: 3px; vertical-align: middle; }
.hcstat + .hcstat { margin-left: 8px; }
.hcicon { width: 1.15em; height: 1.15em; flex: none; }

/* 게시판 거르개 한 줄. 좁은 화면에서는 접혀 내려간다 — 가로로 밀리면 못 쓴다.
   찾기 줄은 칩 아래에서 조용히 — 옛 값(gap 6 · 아래 8)일 때는 목록과 무게가 같아
   어디가 목록 시작인지 안 보였다. */
.boardfilter {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--sp-2); margin: 0 0 var(--sp-4);
}
.boardfilter input[type="search"] { flex: 1 1 18rem; min-width: 0; }
.boardfilter #boardclass { flex: 0 1 11rem; min-width: 9rem; }
.boardfilter #boardsearch { flex: 0 0 auto; }
/* 게시판 미리보기 한 줄 — 「노움 · 몽크 9 / 도적 3 · 총 12레벨」.
   ⚠ `nowrap` 을 안 준다. 이름이 길면 줄이 넘치는 게 잘리는 것보다 낫다. */
.cdsum { color: var(--gold-dim); font-size: 12px; line-height: 1.5; }
/* 저장할 때 생기는 갈래. 본문 맨 위에 온다(머리말이 아니다). */
/* ⚠ 알림 상자는 세로줄 셋(210px · 1fr · 320px)의 **한 칸을 먹으면 안 된다**(2026-09-03 실측,
   운영). 비어 있으면 안 보이지만, 충돌 창이 채워지는 순간 첫 칸에 앉아 빌드 목록이 가운데로,
   편집기가 오른쪽 320px 칸으로 밀렸다 — 「UI 도 이상해」. 한 줄을 통째로 쓰게 한다. */
.bg3-main > .notice { grid-column: 1 / -1; max-width: 560px; margin: 0 auto 12px; }
.bg3-main > .notice:empty { display: none; }
.bg3-main > .notice p { margin: 0 0 var(--sp-2); font-size: var(--fs-base); color: var(--text-3); }
.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;
}
/* ── 제목 그라디언트 글자 (2026-09-05, docs/reports/2026-09-05 §2.2) ─────────────
   공식 사이트는 제목마다 금색 그라디언트로 로고의 금속감을 글자에 옮긴다. 우리 판
   제목(「통합 검색」·「인기 빌드」·「캐릭터」…)에 같은 것을 얹는다.
   ⚠ `color` 는 위 규칙의 `var(--gold)` 그대로다. 그라디언트는 `-webkit-text-fill-color`
   로만 얹고 `@supports` 안에만 둔다 — `color: transparent` 로 적으면 지원 안 하는
   브라우저에서 글자가 **사라지는데 대비 그물은 초록**이다(그물은 `color: var(…)` 만
   읽는다). tests/title-gradient.test.js 가 그 꼴을 문다.
   ⚠ 도감 쪽 제목(`.cx-tree-head h1`·`.cx-main > h1`)은 codex.css 가 같은 꼴로 얹는다 —
   그 파일은 색 리터럴을 못 쓰므로 토큰은 여기(:root)에 있다. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  h2.title {
    background-image: linear-gradient(180deg, var(--gold-hi) 0%, var(--gold) 52%, var(--gold-lo) 100%);
    /* ⚠ **한 줄상자만큼** 펼친다 — `h2.title::after`(장식 18px)가 같은 상자 안이라 100% 로
       펼치면 글자는 위쪽 절반(밝은 끝)만 받고 어두운 끝은 장식 자리에 떨어진다
       (눈가림 검수 2026-09-05 경미 2: 도감 제목과 판 제목이 다르게 보였다).

       ⚠⚠ **옛 값 `1.3em` 은 글줄 높이가 아니었다**(2026-09-07 실측, 사용자 제보 「글자
       밑에가 약간씩 짤려」). 칠은 상자 위에서부터 재는데 —

         줄상자 28.9px(=1.7em) · 반여백 1.95 · 베이스라인 21.95 · **획 바닥 23.96**
         칠 높이 22.1(=1.3em)  →  **1.86px 이 칠 밖**

       칠 밖의 획은 `-webkit-text-fill-color: transparent` 그대로라 **사라진다.** 그래서
       제목마다 밑이 잘렸다(전수 38자리 다, 1.23~1.86px). `1lh` 는 그 요소의 줄상자라
       — 도감 제목(`.cx-tree-head h1`, 칠이 상자=줄상자)과도 비율이 같아진다.

       ⚠ **`repeat-y` 다.** `no-repeat` 이면 **둘째 줄이 통째로 안 보인다** — 실측:
       `/404.html` 데스크톱에서 「주소를 다시 봐 주세요」가 좁은 칸에 두 줄로 접혀
       「주소를 다시 봐 주」까지만 뜨고 **「세요」가 없었다.** 타일이 1lh 라 줄상자와
       칸이 맞으므로 줄마다 같은 그라디언트를 하나씩 받는다.

       ⚠ 아래 `1.7em` 은 `lh` 를 모르는 브라우저(사파리 16.3 이하)용 대체이고, 값은
       `body.bg3` 의 `line-height` **사본**이다. 갈리지 않게 tests/title-gradient.test.js
       가 두 값을 대조한다 — 줄 높이를 바꾸면 여기도 같이 바뀌어야 빨간불이 풀린다. */
    background-size: 100% 1.7em;
    background-size: 100% 1lh;
    background-repeat: repeat-y;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
/* 인쇄·강제 고대비에서는 배경이 안 찍히거나 걷히는데 글자색만 비워 두면 제목이 사라진다 —
   글자색을 되돌린다. 도감 제목 둘도 skin.css 를 싣는 쪽이라 여기서 같이 되돌린다. */
@media print, (forced-colors: active) {
  h2.title, .cx-tree-head h1, .cx-main > h1 {
    background-image: none;
    -webkit-text-fill-color: currentColor;
  }
}
/* ⚠ 옛 `h3.sub` 규칙을 걷었다 (2026-08-24). 살아 있던 선언은 `border-top` 과
   `padding-top` **둘뿐**이었고 — 나머지(12px · normal · 금색 · .18em)는 이미
   `body.bg3 .sub`·제목 무리에 져서 어디에도 안 닿는 죽은 선언이었다.
   그 둘이 남긴 것이 「위아래 선 둘」이라 같이 뗀다. 값은 위 `body.bg3 .sub` 가 쥔다. */

/* ── 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;
}
/* ⚠ **`1fr` 이 아니라 `minmax(0, 1fr)` 이다.** `1fr` 은 `minmax(**auto**, 1fr)` 이라
   그 최소가 **안쪽 내용의 min-content 보다 작아지지 못한다** — 한 칸에 안 줄어드는
   것이 하나만 있어도 칸이 벌어지고, 같은 칸을 쓰는 형제(머리띠·빌드 목록)까지
   통째로 밀린다. 실제로 났다(2026-08-27, 사용자 휴대폰 스크린샷): 카드 오른쪽이
   화면 밖으로 잘렸고 **머리띠도 같이** 잘렸다 — 한 칸이 아니라 바깥 격자가
   벌어졌다는 실마리였다.
   ⚠ **`.bg3-main.wide` 는 처음부터 `minmax(0, 1fr)` 이었다** — 한쪽만 고쳐져
   있던 자리다. `tests/page-stylesheets.test.js` 가 다시 갈리지 않게 잡는다. */
@media (max-width: 1100px) { .bg3-main { grid-template-columns: minmax(0, 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; }

  /* ⚠ 탭줄 붙이기는 **위 `.tabs` 로 옮겼다**(2026-08-24) — 데스크톱에서도 붙어야
     하는데 여기 갇혀 있었다. 값을 두 곳에 두면 한쪽만 고쳐진다. */
}

/* ── ④ 「빌드 한눈에」 ─────────────────────────────────────────────────
   전폭 탭. 세 칸 격자를 한 칸으로 바꾸고 좌우 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; }
.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-readable); }
.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; }
/* 대표가 「작성자가 짠 1라운드」인지 「자동 선택」인지 밝히는 작은 표. 아래 카드
   줄의 머리라서 그것과 붙여 놓고, 값이 아니라 **꼬리표**라 조용하게 둔다. */
.gfeat {
  margin: 10px 6px 0;
  font-size: 11px; letter-spacing: .02em;
  color: var(--faint-readable);
}
/* 못 놓음·피해 없음 같은 **고지** 줄. 카드가 아니라 글이다. */
.grange { margin: 8px 6px 0; font-size: 13px; color: var(--cream); }
.grange.none { color: var(--faint-readable); font-size: 12px; }
/* ④ 짜 둔 1라운드의 공격 카드 — **계산 탭의 턴 칸(.turnitem)과 같은 꼴**이다(사용자
   요청 2026-09-06: 줄글 나열 말고 계산 탭에서 본 그 카드와 기대값을). 격자·여백·글자
   크기를 .turnitem 과 같게 두되, 여기는 누르는 자리가 아니라 커서·hover 를 안 준다.
   「턴당 기대」는 확률을 감안한 값이라 「맞으면 얼마」와 「얼마나 자주」가 안 보인다 —
   그 둘을 카드 아래 .gatkrange 한 줄에 **늘 나란히** 둔다(범위만 떼면 명중률 30%
   공격이 세 보인다). */
.gturn { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 6px 6px 0; }
.gatk {
  box-sizing: border-box; max-width: 100%;
  display: grid; grid-template-columns: 40px minmax(0, 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);
}
.gatk .frame { grid-row: 1 / 3; width: 40px; height: 40px; }
.gatk .frame img { width: 100%; height: 100%; object-fit: contain; }
/* 글자 크기는 **토큰**으로(`tests/typography.test.js` 의 래칫). 이름은 .turnname 의 13px 과
   같은 --fs-base, 범위 줄은 body.bg3 .turnrange 가 쓰는 --fs-sm — 계산 탭과 같은 크기다.
   금색 수치는 아래 .turndmg 규칙에 선택자로 얹어 **한 정의**를 나눠 쓴다. */
.gatkname { font-size: var(--fs-base); }
.gatkcost { display: flex; gap: 6px; flex-wrap: wrap; min-height: 12px; }
.gatkdmg { grid-row: 1 / 3; grid-column: 3; }
/* 범위 문장은 셋째 줄, 그림 칸을 비우고 이름 아래 붙는다. 자릿수는 고정(.turnrange 와 같다). */
.gatkrange {
  grid-column: 2 / 4; font-size: var(--fs-sm); color: var(--muted);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
/* 카드 줄 아래 합계 — 예상(머리 타일과 같은 값·라벨)과 최대를 나란히. 라벨은 죽은 색,
   수는 금색·고정 자릿수.
   ⚠ **합계는 제 부분보다 커야 한다.** 처음엔 --fs-lg(15px)로 뒀는데 카드 한 장의 값이
     17px 이라 **합이 부분보다 작았다** — 눈이 먼저 카드로 가고 합계는 각주처럼 읽힌다.
     위계는 머리 타일(27px) > 합계(--fs-h 20px) > 카드 한 장(17px) 이다. */
.gtotal {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 16px;
  margin: 6px 6px 0; font-size: var(--fs-sm); color: var(--muted);
}
/* ⚠ **라벨과 수는 한 묶음이다.** 전엔 넷이 같은 flex 자식이라 좁은 화면에서 줄이 바뀌면
   「최대 피해」만 남고 수가 다음 줄로 떨어질 수 있었다 — 그러면 그 수가 어느 라벨의
   것인지 화면이 말해 주지 않는다. 묶어 두면 묶음째 넘어간다. */
.gtotal .t { display: inline-flex; align-items: baseline; gap: 6px; }
.gtotal b { color: var(--gold); font-size: var(--fs-h); line-height: 1.1; font-variant-numeric: tabular-nums; }
/* 합계 뒤에 오는 고지(못 놓음 · 계산 미구현)는 카드 덩어리에서 떼어 놓는다 — 붙여 두면
   합계가 고지에 딸린 글처럼 읽힌다. */
.gtotal + .grange { margin-top: 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`). 반대로 적으면 안 된다.
   2026-08-09 실측 당시에는 아이템 화면(`style.css` 의 `.vgrid`)도 같은
   `min-width: 1240px` 을 썼고, 부등호 방향이 갈리면 정확히 1240px 인 그 한
   픽셀에서만 두 화면이 다르게 접히는 문제가 있었다(1239 → 둘 다 1열 ·
   1240 → vgrid 3열인데 gcols 1열 · 1241 → 둘 다 3열).

   ⚠ **2026-08-25부터 `.vgrid` 는 이 값을 안 쓴다** — 아이템 탭이 넓은 화면
   전용 3열 배치를 걷어내고 모든 폭에서 필터-상단 흐름을 쓰도록 바뀌면서
   `style.css` 의 1240px 분기가 사라졌다(`.vgrid` 는 이제 이 화면(items.html)의
   DOM 에도 안 나온다 — `.gcols` 는 `web/panels/glance.js`, 즉 **빌드 탭**
   전용이다). 그러니 지금 1240px 을 쓰는 규칙은 이 `.gcols` 하나뿐이고, 위
   실측의 「두 규칙이 만난다」는 걱정은 더 안 해도 된다. 값을 그대로 남긴 것은
   이 화면 **혼자서도** 기본 1열 · 넓을 때 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-readable); 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-readable); line-height: 1.7; }
.gsub { font-size: 12px; color: var(--faint-readable); 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-readable); }
/* ⚠ `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: var(--sp-2) 0; border-bottom: 1px solid #241c11; }
/* ⚠ **가운데가 아니라 오른쪽이다** — 레벨이 세로로 12줄 쌓이는 **숫자 열**이라서다.
   가운데 정렬이면 `1` 과 `12` 의 자릿수가 어긋나 눈이 열을 못 따라간다
   (tabular-nums 로 폭은 고정했는데 정렬 축이 없으면 그 이득이 반만 난다 —
   디자인 조사 보고서 §4.3: 숫자 열은 우측 정렬, 가운데 정렬 금지). */
.glv .n { width: 2rem; flex: none; text-align: right; 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-readable); }
.gslot .it { line-height: 1.3; color: var(--cream); }
.gslot.empty .it, .gslot.locked .it { color: var(--faint-readable); }

/* ── 장비 부가 효과 한 줄 (2026-09-10 사용자 지적: 「텍스트만 나열하는 게 아니라
   부가 효과를 실제 느낄 수 있게」) ────────────────────────────────────────
   실측(조회 246 짜리 빌드 글): 이 목록이 15줄인데 줄 높이가 24px, 글자가 12px,
   출처가 11px 회색이었다 — `padding: 2px` 는 줄 사이에 **틈이 없다**는 뜻이라
   열다섯 줄이 한 덩어리로 읽혔다.
   ⚠ 출처(`.src`)는 **회색으로 남긴다.** 여기는 한 줄 안에 「무엇이」와 「무엇이
   줬나」가 나란히 있어서, 설명글처럼 선으로 가를 자리가 없다 — 둘을 같은 색으로
   올리면 뭉친다. 크기만 11 → 12px 로 올려 읽히게 한다. */
.geff { display: flex; gap: var(--sp-3); padding: 5px 0; font-size: var(--fs-base); }
.geff > span:first-child { flex: 1; }
.geff .src { color: var(--text-2); font-size: var(--fs-sm); white-space: nowrap; }
.geff > span:first-child { display: flex; align-items: center; gap: 6px; }
/* ⚠ **크기를 안 주면 게임 아이콘 원본 크기로 나온다**(64px 이상) — 한 줄짜리 목록에
   그게 들어가면 줄 높이가 통째로 무너진다(사용자 제보 2026-08-08 「이미지 너무 커」).
   같은 화면의 칩(`.gchip .ci`, 위)과 **같은 값**을 쓴다 — 나란히 놓이는 것들이라
   크기가 다르면 그것대로 눈에 걸린다.
   ⚠ 15 → 17px(2026-09-10): 줄 글자가 12 → 13px 이 되면서 그림이 글자보다 작아졌다.
   `.gchip .ci` 도 같이 옮기지 **않는다** — 칩은 글자가 그대로 12px 이다. */
.geff .ci { width: 17px; height: 17px; 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-readable); }
.gpend .p { padding: 3px 0; border-top: 1px solid #241c11; font-size: 12px; }
.gpend.on .p b { color: var(--gold); }
/* 피해 범위·명중률이 들어간다 — 공격 줄끼리 세로로 견주는 자리라 자릿수를 고정한다.
   (계산 탭의 다른 숫자 넷(.calcstat .v · .econv · .turndmg · .abils .v)은 이미 그렇다) */
.turnrange {
  display: block; padding: 1px 0 3px 46px; font-size: 11px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.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 가 겪은 자리다). */
/* ⚠ **창이 아니라 「이 칸」의 폭으로 잰다** (2026-08-27, 사용자 스크린샷).
   옛 규칙은 `@media (min-width: 1240px)` 로 **창**을 봤다. 그런데 이 절이 실제로
   놓이는 칸은 창보다 훨씬 좁다 — 실측: 창 1920px 에서 `#panel` 842px,
   게시판 공개 미리보기는 **540px**.
   540px 에 `300px 1fr 350px` 를 깔면 고정 650 + 간격 40 = 690 > 540 이라
   **가운데 1fr 이 0 으로 찌부러지고 칩이 왼쪽 내용 위로 올라탄다**(실측: 넘치는
   요소 42개). 사용자 화면에서 레벨별 진행이 뭉개져 보인 것이 이것이다.
   ⚠ **게시판만의 문제가 아니었다.** 창 1240px 이면 패널은 약 545px 이라
   **빌드 화면도 그 폭에서 같은 겹침**이 났다 — 창을 재는 한 이 자리는 못 고친다.
   문턱 760px 은 지어낸 값이 아니라 이 배치가 요구하는 최소다:
   300 + 350 + 간격 40 = 690, 가운데가 최소한 70px 은 있어야 한다.
   실측으로도 갈린다 — 빌드 ~800(3열 유지) · 게시판 540(1열로 접힘).

   ⚠ **게시판 540px 은 2026-09-10부터 낡은 값이다.** 그 글이 좌우 두 칸이던
   시절의 수치인데, 전폭 세로로 펴면서(아래 `.bdsplit`) 미리보기 칸이 **1,116px**
   이 됐다 — 이제 문턱 760 을 넘어 **3열로 흐른다**. 그 덕에 데이터 높이가
   4,165 → 2,071px 로 절반이 됐다(실측). 여기 규칙은 안 바꿨다 — **창이 아니라
   칸을 재기 때문에** 칸이 넓어진 것만으로 저절로 따라왔다. 그게 이 컨테이너
   쿼리가 옳았다는 증거이기도 하다. */
.glance { container-type: inline-size; }
@container (min-width: 760px) {
  .gcols { grid-template-columns: 300px minmax(0, 1fr) 350px; }
}
@media (min-width: 1240px) {
  /* ⚠ 창을 재는 것이 **맞는** 자리 — 고르기 창은 뷰포트에 맞춰 커진다. */
  #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: minmax(0, 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; }
}

/* ── 탭 ── */
/* ── 탭줄을 화면 위에 붙인다 (2026-08-24) ────────────────────────────────
   디자인 조사 보고서 §7 「sticky header 가 동작하는가」. 여태 이 규칙은
   `@media (max-width: 720px)` **안에만** 있었다 — 좁은 화면에서는 붙는데
   데스크톱에서는 계산 탭을 훑는 동안 탭줄이 화면 밖으로 나갔다.
   계산 탭은 원래 제보가 「길어서 보기 힘들다」였던 화면이라 여기가 제일 값한다.

   ⚠ **배경이 불투명해야 한다.** 반투명이면 밑으로 지나가는 내용이 비쳐서
   탭 글자와 겹친다. 판 색(`--surface`)을 알파 없이 쓴다.
   ⚠ **z-index 는 판 안쪽 것들보다 위, 창(dialog)보다 아래.** 20 은 좁은 화면
   규칙이 이미 쓰던 값이라 그대로 맞춘다 — 두 자리가 다르면 화면 폭에 따라
   겹침 순서가 달라진다.
   ⚠ **위 여백을 음수로 당기지 않는다.** `.pane` 이 안여백을 갖고 있어서 탭줄이
   붙었을 때 그 안여백만큼 위가 비는데, 그걸 음수 마진으로 메우면 자산 판
   (`border-image`)에서 테두리를 파고든다.
   ⚠ 조상에 `overflow`·`transform` 이 없어야 붙는다 — 실측으로 확인했다
   (`.bg3-main`·`.pane`·`#editor`·`body.bg3` 넷 다 없다). 생기면 조용히 안 붙는다. */
.tabs {
  display: flex; gap: 2px; flex-wrap: wrap; margin-bottom: 10px;
  position: sticky; top: 0; z-index: 20;
  background: var(--surface);
}
.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; }
  /* 게시판 글의 탭은 **셋**이다(내 빌드·계산·설명, 2026-09-13). 2×2 면 셋째가 둘째 줄에
     혼자 남으니 한 줄 3등분 — 글자가 「내 빌드」 넉 자라 375px 에서도 든다. */
  #boardpreviewtabs { grid-template-columns: repeat(3, 1fr); }
}

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

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

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

/* 새 native 행과 탭도 키보드 포커스를 놓치지 않는다. 선택·경고 색은 기존 규칙에 맡긴다. */
.buildlist .build-row:focus-visible,
.buildlist .party-row:focus-visible,
.pickerlist .picker-row:focus-visible,
.cdpickrow:focus-visible,
.partyslot-main:focus-visible,
.tab:focus-visible,
.mktab:focus-visible,
.acttab:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* ── 아이콘 격자. 게임의 선택 화면이 이 모양이다 ── */
.pickgrid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: var(--sp-3) var(--sp-2); margin-bottom: var(--sp-1);
}
/* ⚠ 이름은 62px 틀 **아래**에 놓인다. 11 → 12px 이라 두 줄이 세 줄이 될 수 있고
   칸이 세로로 는다 — 격자라 줄이 밀릴 뿐 겹치지는 않는다.
   (방사형인 일리시드 나무는 사정이 달라 그대로 뒀다. 그 화면은 이 개편의 범위
   밖이고, 칸이 붙어 있어 크기를 올리면 이름끼리 겹친다 — `.tadnode` 주석 참고.) */
.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(--text-2); font: inherit; font-size: var(--fs-sm);
  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(--text); }
.pickitem:hover img { filter: none; }
.pickitem .noicon { color: var(--text-2); font-size: var(--fs-h); }
/* ── 재주가 올린 능력치 고르기 ─────────────────────────────────────────
   여섯 능력치를 한 줄에 놓고 ± 로 점수를 나눈다. 남은 점수는 머리말에 뜬다. */
.abrow { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--sp-2); }
.abpick {
  display: flex; align-items: center; gap: var(--sp-1); padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--line); background: #100c08;
  font-size: var(--fs-sm); color: var(--text-2);
}
.abpick.on { color: var(--accent); border-color: var(--accent); }
.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-readable); 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(--accent); }
.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(--danger); }

/* ── 다른 레벨에서 이미 고른 재주 ──
   게임은 재주를 **한 번만** 준다(41개 중 「능력 향상」·「원소 숙련」 둘만 예외).
   `dup`(주문)과 다르다 — 그쪽은 게임이 허용해서 **알려만 주고**, 이쪽은 아예 막는다.
   ⚠ **지우지 않고 흐린다.** 없애 버리면 「내 재주가 어디 갔지」가 되고, 왜 못 고르는지
   말할 자리도 사라진다. `title` 이 다른 레벨에서 골랐다고 알려 준다. */
.pickitem.blocked {
  opacity: .38; cursor: not-allowed; filter: grayscale(1);
}
.pickitem.blocked .frame { border-color: var(--line); box-shadow: none; }
.pickitem.blocked:hover { background: none; }

/* ── 고른 것의 설명 ── */
.gamedesc {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  margin: var(--sp-2) 0 var(--sp-1); padding: var(--sp-3);
  background: #16110c; border: 1px solid var(--line);
}
.gamedesc > img { width: 54px; height: 54px; flex: none; object-fit: contain; }
.gamedesc-name { color: var(--accent); font-size: var(--fs-lg); margin-bottom: 2px; }
.gamedesc-body { line-height: 1.6; max-height: 11em; overflow-y: auto; }
/* 게임 용어. 게임 툴팁의 그 밑줄이었다 — **지금은 안 긋는다.**
   제보 「노란 밑줄은 왜 있는지 모르겠다」(2026-08-23). 그 표시는 **게임 용어에
   설명이 붙어 있다**는 뜻인데, 11px 글자 밑의 점선이라 노이즈로만 읽혔다.
   뜻은 **색과 커서**로 남기고 선을 걷는다 — 커서를 올리면 그때 밑줄이 뜬다
   (있다는 것은 알리되 늘 소리치지 않는다).
   ⚠ 같은 결정이 툴팁 쪽 `.st-body .lstag` 에도 걸려 있다 — **둘은 같이 움직인다.** */
.gamedesc .lstag {
  border-bottom: 0;
  color: var(--accent);
  cursor: help;
  text-underline-offset: 3px;
}
.gamedesc .lstag:hover,
.gamedesc .lstag:focus-visible {
  text-decoration: underline dotted var(--accent-quiet);
}
/* 용어 칩의 그림(2026-09-05, 디자인 조사 C — bg3.wiki 의 「링크마다 아이콘」). 글줄 높이 안에
   앉힌다: 1.15em 이면 줄 간격을 안 밀고, 밑선 아래로 .22em 내려야 글자 가운데와 맞는다.
   어느 칩이 그림을 받나는 등록부(web/lib/term-icons.js)가 정한다 — 여기는 크기·자리뿐. */
.lstag-ico { width: 1.15em; height: 1.15em; vertical-align: -.22em; margin-right: .18em; object-fit: contain; }
/* 칩은 한 덩어리다 — `<img>` 뒤가 줄바꿈 자리라 그림만 앞 줄 끝에 남고 낱말이 다음 줄로 가는 일이
   있었다(눈가림 검수 2026-09-05 심각 4: 1,941개 중 12~20). 칩 글자는 최장 14자라 안 접어도 넘치지
   않는다. */
.lstag { white-space: nowrap; }
/* 게임이 실행 중 계산해 넣는 값. 우리가 채울 수 없어 원문 그대로 둔다. */
.gamedesc .ph { color: var(--text-3); background: #241c11; padding: 0 var(--sp-1); border-radius: 2px; }

/* ── 버튼 ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1);
  min-height: 40px; box-sizing: border-box; appearance: none;
  font: inherit; font-size: var(--fs-base); color: var(--text); cursor: pointer;
  background: transparent; border: 0; border-bottom: 1px solid var(--accent-quiet);
  padding: 7px 4px 8px; letter-spacing: .06em;
  transition: color .2s ease, background-color .2s ease, border-color .2s ease;
}
.btn:hover { color: var(--accent); border-bottom-color: var(--accent); background: rgba(198, 151, 58, .09); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
/* ── 주 단추의 장식 프레임 (2026-09-05, docs/reports/2026-09-05 §2.4) ───────────
   공식 사이트의 「GET IT NOW」·「BUY NOW」는 양끝이 뾰족한 금테 단추다. 자산 없이
   CSS 로 그린다 — 양쪽 테두리 가운데에 마름모 하나씩. 「주 단추」는 그 화면의
   **다음 행동 하나**다(새 빌드 · 저장 · 빌드에 끼우기 · 프로필 확정). 한 화면에 둘
   이상 두면 프레임이 아무것도 안 가리킨다.
   ⚠ 마름모는 테두리 밖으로 **약 7px** 나간다(8px + 테두리 1px 을 45° 돌린 대각의
   반 — 전역 box-sizing 이 없어 content-box 다). 그래서 단추 자신이 좌우 7px 여백을
   쥔다 — 이웃이 공백 하나로만 떨어져 있어도(프로필 확인 화면의 「공개한다 · 돌아가서
   고치기」, 눈가림 검수 2026-09-05 심각 1) 안 덮는다. 여백 값과 마름모 크기는
   tests/title-gradient.test.js 가 **계산으로** 맞댄다.
   「주 단추」는 한 판(영역)에 하나 — 왼쪽 판의 「새 빌드」와 편집기 도구줄의 「저장」은
   서로 다른 판이라 같이 보여도 된다. 한 판에 둘이면 프레임이 아무것도 안 가리킨다. */
.btn.primary {
  position: relative; color: var(--accent); border-color: var(--gold-dim);
  background: transparent;
  margin-inline: 7px;
}
.btn.primary:hover { border-color: var(--accent); }   /* .btn:hover 와 같은 강조 — 뒤 규칙이라 다시 적는다 */
.btn.primary::before, .btn.primary::after {
  content: ''; position: absolute; top: 50%; width: 8px; height: 8px;
  border: 1px solid var(--gold-dim); background: #1a130b;   /* 단추 아랫색 — 판·바탕 어느 쪽에서도 점으로 안 뜬다 */
  transform: translate(-50%, -50%) rotate(45deg);
}
.btn.primary::before { left: 0; }
.btn.primary::after { left: 100%; }
.btn.primary:hover::before, .btn.primary:hover::after { border-color: var(--accent); }
.btn.ghost { border-bottom-color: var(--line); padding: var(--sp-1) var(--sp-2); font-size: var(--fs-sm); }
/* ⚠ **되돌리기 어려운 단추.** 「글 삭제」가 그 옆의 「빌드 최신화」와 **생김새가
   같으면** 실수로 첫 누름을 한다(2단계 확인이 있어도 첫 누름은 막을 게 없다).
   막지는 않고 **다르게 보이게만** 한다 — 이 저장소의 결(「모르는 것을 참으로
   치지 않는다」)대로 사람이 판단할 재료를 준다. */
.btn.danger { color: var(--danger); border-bottom-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.btn.danger:hover { color: var(--danger); border-bottom-color: var(--danger); background: color-mix(in srgb, var(--danger) 9%, transparent); }

/* ── 게시판 상세의 단추 묶음 셋(2026-08-26) ─────────────────────────────
   읽는 사람 / 작성자 관리 / 부수. 전에는 여덟이 한 줄에 섞여 있었다. */
.bdauthor { margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--line); }
.bdauthorlabel { margin-right: var(--sp-1); }
/* 부수는 층을 낮춘다 — 위 둘과 같은 무게로 보이면 안 된다. */
.bdminor { margin-top: var(--sp-3); opacity: .75; }
.bdminor:hover { opacity: 1; }

/* ── 댓글 (3단계 · 익명 허용, 2026-09-09) ───────────────────────────────
   설계: docs/superpowers/specs/2026-09-09-anonymous-comments-design.md
   ⚠ 색만으로 상태를 가르지 않는다(설계 §8) — tombstone 은 기울임 + 문구,
     익명은 글자 배지로 구별한다. */
.bdcomments {
  margin-top: var(--sp-4); padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}
/* ⚠ **`display: flex` 를 여기서 명시한다.** `.row` 는 이 저장소에서 flex 가
   아니라(껍데기 전수 확인 2026-09-09) 이 줄이 없으면 제목과 잠금 단추가 세로로
   쌓인다 — 미리보기에서 실제로 그렇게 보였다. */
.bdcomhead {
  display: flex; align-items: baseline;
  justify-content: space-between; gap: var(--sp-2);
}
.bdcomtitle { margin: 0; font-size: var(--fs-lg); }

/* ── 대화 영역을 **상자**로 (2026-09-09, 사용자 지적) ────────────────────
   전에는 판과 같은 배경에 구분선만 있어서 「여기가 댓글」이 안 읽혔다.
   ⚠ **`--ink` 를 쓰지 않는다.** 그 토큰은 밝은 판에 재정의가 없어(`#0b0907`
     하나뿐) 밝은 판에서 검은 상자가 된다 — 대비 19.56 으로 통째로 깨진다.
     실제로 계산해 보고 갈렸다.
   ⚠ **배경만으로는 안 된다.** `--surface-2` 대 판 대비가 어두운 판 1.08 ·
     밝은 판 1.18 이다 — 상자로 읽히게 하는 것은 **테두리와 여백**이고 배경은
     보조다. 칩 배경에서 겪은 것과 같은 함정이라 여기 적어 둔다. */
#boardcommentlist {
  margin-top: var(--sp-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 2px var(--sp-3);
}
/* 상자가 여백을 쥐므로 목록 자신은 안 밀어낸다. */
.bdclist { list-style: none; margin: 0; padding: 0; }
.bdcitem {
  padding: var(--sp-2) 0; border-bottom: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 4px;
}
.bdcitem:last-child { border-bottom: 0; }
/* 답글은 한 단계뿐이라 들여쓰기도 한 단계다. */
.bdcreplies { list-style: none; margin: 0; padding: 0 0 0 var(--sp-3); border-left: 1px solid var(--line); }
.bdcreply { padding-left: 0; }

.bdchead { display: flex; align-items: baseline; gap: var(--sp-1); flex-wrap: wrap; }
.bdcwho { font-weight: 600; color: var(--cream); text-decoration: none; }
a.bdcwho:hover { border-bottom: 1px solid var(--gold-dim); }
/* ⚠ 익명 닉네임은 신원이 아니라 라벨이다(설계 §3) — 계정 작성자와 다르게 보인다. */
.bdcanonwho { font-weight: 500; color: var(--muted); }
.bdcbadge {
  margin-left: 4px; padding: 0 5px; font-size: var(--fs-xs);
  color: var(--gold-dim); border: 1px solid var(--line); border-radius: 2px;
}
.bdcwhen, .bdcedited { font-size: var(--fs-xs); color: var(--muted); }

.bdcbody { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
/* tombstone — 색이 아니라 기울임과 문구로 말한다(설계 §8: 색만으로 안 가른다).
   줄 자체도 무게를 낮춘다 — 답글만 남은 자리라 본문 줄과 같아 보이면 안 된다. */
.bdcdead { padding: var(--sp-2) 0; }
.bdcdeadbody { font-style: italic; color: var(--muted); }

.bdcacts { display: flex; gap: var(--sp-1); }
.bdcacts .btn { font-size: var(--fs-sm); padding: 2px 6px; }
.bdcempty { margin: var(--sp-2) 0; }

.bdcform { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-1); }
.bdcform textarea { width: 100%; resize: vertical; min-height: 4.5em; }
.bdcanon { gap: var(--sp-1); flex-wrap: wrap; }
.bdcanon input { flex: 1 1 8em; min-width: 0; }
/* 위젯이 뜨기 전에는 자리를 안 차지한다 — 빈 상자를 남기지 않는다. */
.bdccaptcha:empty { display: none; }
.bdccaptcha { margin: 2px 0; }

/* ── 댓글 속 도감 아이콘 (2026-09-09) ───────────────────────────────────
   설명글의 아이콘무리(`.bb-icon`)와 **판정은 같고 마크업은 다르다** — 그쪽은
   블록(figure>ul>li)이고 이쪽은 글 흐름에 끼는 인라인이다.
   ⚠ 글리프가 늘 있고 그림이 그 위에 얹힌다 — 그림 파일이 없는 종류(기술 18종)
     에서도 표지가 남는다(`data-fallback="제거"` 가 img 를 지우면 글리프가 드러난다). */
.bdcchip {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 0 5px 0 3px; border: 1px solid var(--line); border-radius: 3px;
  color: var(--cream); text-decoration: none;
  /* ⚠ **배경을 준다**(2026-09-09, 미리보기를 보고 사용자 지적). 테두리만으로는
     글 흐름에서 도드라지지 않아 「이게 누를 수 있는 것인가」가 안 읽혔다.
     ⚠ **색을 박지 않고 토큰을 쓴다** — `--surface-3` 는 어두운 판에서 살짝
     떠오르고 밝은 판에서 살짝 가라앉아, 두 판 **모두**에서 글과 갈린다.
     리터럴로 적으면 밝은 판에서 배경과 같은 색이 되는 날이 온다. */
  /* ⚠ **금색을 22% 섞는다.** `--surface-3` 만으로는 어두운 판에서 판과 대비가
     **1.09** 였다 — 사실상 구분이 안 됐다(2026-09-09 계산). 22% 면 어두운 판
     1.65 · 밝은 판 1.68 로 두 판이 균형을 이룬다. 30% 는 더 세지만 한 댓글에
     칩이 여럿일 때 글이 얼룩덜룩해진다.
     ⚠ 칩이 도감으로 가는 것이라 금색이 그 뜻과도 맞는다. */
  background: color-mix(in srgb, var(--gold-dim) 22%, var(--surface-3));
  /* 글 줄 사이에 끼므로 줄 높이를 밀지 않게 눌러 둔다. */
  line-height: 1.35; vertical-align: baseline;
}
/* hover 는 배경 **위에** 섞는다 — `transparent` 에 섞으면 위 배경이 사라져
   눌렀을 때 오히려 납작해진다. */
a.bdcchip:hover {
  border-color: var(--gold-dim);
  background: color-mix(in srgb, var(--gold-dim) 34%, var(--surface-3));
}
/* ⚠⚠ **`.bdcchip-i` 는 이 요소 *안에* 있어야 한다.** 아래 `position: absolute` 의
   기준이 여기(`relative`)라서다 — 형제로 두면 기준을 못 찾아 **페이지 왼쪽 위에
   그림이 튀어나온다**(2026-09-09 실측). 그 중첩을
   `tests/comment-icons.test.js` 가 구조로 지킨다. */
.bdcchip-g {
  position: relative; width: 16px; height: 16px;
  /* ⚠ 리터럴을 안 박는다 — 정본은 `:root` 의 `--fs-*` 다(`tests/typography.test.js`
     가 리터럴 수를 상한으로 문다). `--fs-sm` 이 정확히 12px 다. */
  font-size: var(--fs-sm); line-height: 16px; text-align: center; color: var(--gold-dim);
}
.bdcchip-i { position: absolute; inset: 0; width: 16px; height: 16px; object-fit: contain; }
.bdcchip-n { font-size: var(--fs-sm); }

/* 고르기 칸 — 접혀 있다가 「아이콘 넣기」로 열린다. */
.bdcicons { margin-top: 2px; }
.bdciconbox { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: 2px; }
.bdciconbox input { width: 100%; }
.bdciconhits { display: flex; flex-wrap: wrap; gap: 4px; max-height: 168px; overflow-y: auto; }
.bdciconhits:empty { display: none; }
.bdciconhit {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 7px; border: 1px solid var(--line); border-radius: 3px;
  /* 고르기 목록은 **가라앉는다**(`--surface-2`) — 본문 칩(`--surface-3`)이
     떠올라 보여야 「글에 든 것」과 「고를 것」이 눈으로 갈린다. */
  /* 목록은 **약하게**(gold 10%) — 스무 개가 나열되므로 다 세면 시끄럽다.
     누를 때(hover) 강해진다. */
  background: color-mix(in srgb, var(--gold-dim) 10%, var(--surface-2));
  color: var(--cream); cursor: pointer; font: inherit;
}
.bdciconhit:hover {
  border-color: var(--gold-dim);
  background: color-mix(in srgb, var(--gold-dim) 30%, var(--surface-2));
}

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-readable` 는 이 파일이 쓰는 「읽히되 앞에 안 나서는」 색이다. */
input::placeholder, textarea::placeholder { color: var(--faint-readable); 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 {
  /* 전폭이지만 `.btn.primary` 의 좌우 여백(7px)만큼 좁힌다 — 안 그러면 판을 14px 넘친다. */
  display: block; width: calc(100% - 14px); text-align: center;
  box-sizing: border-box;
  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%; box-sizing: border-box; text-align: center; }

.buildlist ul { list-style: none; margin: 10px 0 0; padding: 0; }
.buildlist li {
  display: flex; align-items: center; gap: 6px; padding: 0; cursor: default;
  border-left: 2px solid transparent;
}
.buildlist .build-row,
.buildlist .party-row {
  display: flex; flex: 1; min-width: 0; align-items: center; gap: 6px;
  padding: 5px 8px; text-align: left; font: inherit; color: inherit;
  background: none; border: 0; cursor: pointer;
}
.buildlist .build-row:hover,
.buildlist .party-row: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-readable); cursor: pointer; font: inherit; }
.buildlist .del:hover { color: var(--warn); }

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

/* 단계 목록 — 「만들기」 탭의 목차이기도 하다(아래 `.steps li.goto`). */
.steps { list-style: none; margin: var(--sp-4) 0 0; padding: 0; font-size: var(--fs-sm); }
.steps li { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) 0; color: var(--text-2); }
.steps .dot { width: 13px; height: 13px; border-radius: 50%; border: 1px solid var(--accent-quiet); flex: none; }
.steps li.done { color: var(--text); }
.steps li.done .dot { background: var(--gold); box-shadow: 0 0 6px #c8a24c88; }
.steps li small { margin-left: auto; color: var(--text-3); }
/* ④ 만들기 탭이 세로로 길어져서 왼쪽 목록을 목차로 쓴다. 절이 있는 줄만 누를 수 있다. */
.steps li.goto { cursor: pointer; }
.steps li.goto:hover { color: var(--accent); }

/* ── 오른쪽: 캐릭터 요약 ── */
.who { display: flex; gap: var(--sp-3); align-items: center; }
.who img { width: 56px; height: 56px; object-fit: contain; }
.who .n { color: var(--accent); font-size: var(--fs-lg); }
.who .l { color: var(--text-2); font-size: var(--fs-sm); }

/* ⚠ 능력치 여섯 칸은 320px 레일 안에서 6열이라 칸이 ~46px 다. 라벨은 한글 두 자
   (근력·민첩…)라 12px 에서 24px, 값은 두 자리라 20px 에서 ~22px — 둘 다 들어간다.
   10px 라벨을 그대로 두면 이 화면에서 제일 작은 글자가 된다. */
.abils { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px; margin: var(--sp-3) 0 2px; }
.abils > div { text-align: center; }
.abils .k { font-size: var(--fs-sm); color: var(--text-2); }
.abils .v { font-size: var(--fs-h); color: var(--text); font-variant-numeric: tabular-nums; }
.abils .m { font-size: var(--fs-sm); color: var(--text-3); }
.abils img { width: 22px; height: 22px; opacity: .8; }

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

/* ── 능력치 입력 ── */
.abilityrows { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--sp-2) var(--sp-4); }
.abilityrow { display: flex; align-items: center; gap: var(--sp-2); 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(--text-3); font-size: var(--fs-sm); width: 2.2em; }
#points { color: var(--text-2); font-size: var(--fs-base); letter-spacing: 0; }
#points.over { color: var(--danger); }
/* 배분 점수 칸의 이름. 예전에는 숫자만 있어서 무엇의 29/27 인지 화면 어디에도
   적혀 있지 않았다(ability.js 의 POINTS_LABEL). */
.pointslabel { color: var(--text-2); font-size: var(--fs-base); }
/* 초과 상태를 색 하나로만 알리지 않는다 — 색각 이상·모바일에서 안 보인다. */
.hint.over { color: var(--warn); }

/* ── 레벨 트랙 ── */
.levelrow {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-2) 0; border-bottom: 1px solid var(--line-2);
}
/* 레벨 트랙도 같은 숫자 열이다 — 위 `.glv .n` 과 같은 까닭으로 오른쪽. */
.levelrow .lv {
  width: 2rem; flex: none; text-align: right; color: var(--text-3);
  font-variant-numeric: tabular-nums; padding-top: var(--sp-1);
}
.levelrow .lvicon { width: 34px; height: 34px; flex: none; object-fit: contain; }
.levelrow .lvpicks { display: flex; flex-direction: column; gap: var(--sp-1); flex: 1; min-width: 0; }
.levelrow .lvhead { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.lvinfo { display: flex; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--fs-sm); }
.lvinfo .gain { color: var(--text-2); }
.choicebox { display: inline-flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.choicebox .picklabel { color: var(--text-3); font-size: var(--fs-sm); }
/* ⚠ **이름이 겹친다 — 지금은 문제없지만 알고 있을 것.** `.chip` 은 여기 레벨 트랙의
   고른 것 칩이고, 게시판 거르개도 `.chip` 을 쓴다(위 `.chiprow .chip`). 두 화면이
   안 겹쳐서 지금은 조용한데, 한 화면에 둘이 서면 이 규칙이 게시판 칩에도 닿는다.
   그때는 이름을 가르는 것이 맞다 — `.chiprow .chip` 처럼 부모로 좁히는 것은
   임시방편이다(구체성 싸움이 시작되면 그쪽이 먼저 무너진다). */
.chip {
  font: inherit; font-size: var(--fs-sm); padding: 1px 9px; cursor: pointer;
  background: #2a2419; border: 1px solid var(--line); color: var(--text);
}
.chip:hover { border-color: var(--accent-quiet); }

/* ── 장비 칸 ── */
/* 왼쪽에 칸 덩어리, 오른쪽에 정보. 게임 인벤토리의 구성이다. */
.equip { display: grid; grid-template-columns: minmax(0, 1fr) 220px; gap: var(--sp-4); }
@media (max-width: 900px) { .equip { grid-template-columns: minmax(0, 1fr); } }
.slots { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-2); }
.weaponset {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line);
}
.weaponset .setlabel {
  min-width: 3.5em; color: var(--text-3); font-size: var(--fs-sm); letter-spacing: .08em;
}
.equipinfo { border: 1px solid var(--line); background: #16110c80; padding: var(--sp-3); }
/* 낀 장비가 주는 효과. 갈래 이름 아래 문장이 오고, 줄 끝에 어느 장비에서 왔는지 적는다.
   ⚠ **여기가 220px 칸 안이다.** 글자 바닥을 올리면 줄이 더 접히지만, 이 목록은
   원래 여러 줄로 흐르는 자리라 접히는 것이 잘리는 것보다 낫다. */
.effgroup { margin-bottom: var(--sp-2); }
.effkind {
  display: block; font-size: var(--fs-sm); color: var(--text-3);
  letter-spacing: .08em; margin-bottom: 2px;
}
.efflist { list-style: none; margin: 0; padding: 0; font-size: var(--fs-sm); }
/* ⚠ `padding: 1px` 은 줄 사이에 **틈이 없다**는 뜻이라 열다섯 줄이 한 덩어리로
   읽힌다(2026-09-10, `.geff` 와 같은 자리·같은 처방). 3px 로 편다. */
.efflist li { padding: 3px 0; line-height: 1.5; }
/* ⚠ **여기는 인라인 그림이다** — 「내 빌드 보기」(`.geff .ci`)는 flex 칸이라
   `display: block` 인데, 이 목록은 span 둘이 그냥 흐르는 배치다. 같은 `block` 을
   주면 그림이 제 줄을 차지하고 글이 아래로 내려간다(그 실수를 시안에서 한 번
   했다 — `.ef` 가 이미 쓰이는 클래스라 `flex-direction: column` 을 물려받았다).
   크기는 `.geff .ci` 와 맞춘다 — 같은 데이터를 그리는 두 화면이라 다르면 눈에 띈다. */
.efflist .ci { width: 17px; height: 17px; vertical-align: -3px; margin-right: 5px; }
.efftext { color: var(--text); }
.effsrc { color: var(--text-2); font-size: var(--fs-sm); }
.effunread { margin-top: var(--sp-2); font-size: var(--fs-sm); }

/* 「아직 계산에 안 들어간 것」 목록. 위 `.effunread`(못 옮긴 원문)와 **다른 것**이다 —
   저쪽은 우리가 글로 못 옮긴 것이고, 이쪽은 **옮길 것도 없이 숫자에 안 들어간 것**이다.
   조용한 것보다 낫게 하려고 두는 자리라 눈에 띄되 경고처럼 붉지는 않게 둔다. */
.effoutside { margin: var(--sp-1) 0 0; padding-left: 18px; font-size: var(--fs-sm); color: var(--cream-dim); }
.effoutside li { margin: 2px 0; }
.effunread summary { color: var(--text-2); 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(--text-2); font-size: var(--fs-sm); }
.proflist { list-style: none; margin: 0 0 var(--sp-2); padding: 0; font-size: var(--fs-sm); }
.proflist li { color: var(--text); padding: 1px 0; }
/* 숙련 없는 것을 낀 칸. 막지는 않는다 — 우리가 못 읽는 숙련이 있다. */
.slotbtn.warn .frame { border-color: var(--danger); }
.slotbtn .frame { position: relative; }
.warnmark { position: absolute; right: 1px; bottom: 0; font-size: var(--fs-sm); color: var(--danger); }
.notice {
  margin: 0 0 var(--sp-2); padding: var(--sp-2) var(--sp-3); font-size: var(--fs-sm);
  border: 1px solid var(--accent-quiet); background: #2b251980; color: var(--text);
}
/* 「분류 안 됨」(고르는 칸)과 「이름 없음」(목표 성질 칸·피해 속성 칸,
   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-readable); }
/* 막별 계획 고르기 창에서 「막을 모르는 것」 표시. 고른 막의 아이템과 섞여 뜨므로
   구별이 없으면 전부 그 막에 나온다고 읽힌다(build.js 의 막모름안내). */
/* 장비 종류(「장검 · 군용 무기」·「평갑」). **사실**을 적는 칸이라 경고 색을 안 쓴다 —
   바로 위 .unsorted(우리가 못 갈랐다)·.actunknown(우리가 못 정했다)과 성격이 다르다.
   ⚠ 크기는 **토큰**으로 준다. 이웃 배지 둘은 11px 리터럴이지만 그건 걷어내는 중인
   빚이고(tests/typography.test.js 의 래칫), 여기에 하나 더 박으면 그 수가 는다. */
.pickerlist .itemkind { font-size: var(--fs-sm); color: var(--dim); white-space: nowrap; }
.pickerlist .actunknown { font-size: 11px; color: var(--gold-dim); }
/* 결함②(2026-08-17, 전체 브랜치 검수) — 「못 얻는다」 축(web/tooltip.js 의
   못얻음문구). .actunknown(잡음 축, 「우리가 못 정했다」)과 다른 색을 준다 —
   이쪽은 게임이 못박은 사실이다. `--warn` 은 .tt-missing·`.tt-unobtainable`
   과도 같은 계열이라 화면마다 색이 흔들리지 않는다. */
.pickerlist .unobtainable-tag { font-size: 11px; color: var(--warn); }
/* .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; }
/* ⚠ `.slotitem` 이 `max-width: 100px` + ellipsis 다 — 11 → 12px 이면 같은 폭에
   들어가는 글자가 줄어 **더 일찍 잘린다.** 잘린 이름은 툴팁과 아래 목록에서
   그대로 읽히니 정보가 사라지지는 않는다. 대신 칸 이름이 읽힌다. */
.slotbtn {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: var(--sp-2) var(--sp-1); cursor: pointer; font: inherit; font-size: var(--fs-sm);
  background: none; border: 1px solid transparent; color: var(--text);
}
/* 장비 칸의 틀. **고르기 격자(`.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(--accent-quiet); }
.slotbtn .slotlabel { color: var(--text-2); }
.slotbtn .slotitem { color: var(--text); max-width: 100px; overflow: hidden; text-overflow: ellipsis; }
.slotbtn.empty .slotitem { color: var(--text-2); }
/* 양손 무기가 잠근 보조 칸 — 고를 수 없지만 왜 잠겼는지 title 로 알 수 있다. */
.slotbtn.locked { cursor: default; opacity: .5; }
.slotbtn.locked .frame { border-style: dashed; }

/* 장비 아래에 붙는 인벤토리 격자. 위는 지금 낀 것, 아래는 노릴 것.
   ⚠ 이 줄이 화면을 둘로 가르는 **구획**이다(설계 정본: 쓰는 화면은 밀도를
   유지하되 구획으로 숨 쉬게 한다). 그래서 절 사이 여백을 한 칸 크게 준다. */
.equipsep {
  margin: var(--sp-5) 0 var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line);
  color: var(--text-2); font-size: var(--fs-sm); letter-spacing: .05em;
}
.acttabs { display: flex; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.acttab {
  padding: var(--sp-1) var(--sp-3); font: inherit; font-size: var(--fs-sm); cursor: pointer;
  background: #1e1a14; border: 1px solid var(--line); border-bottom: none;
  border-radius: 3px 3px 0 0; color: var(--text-2);
}
.acttab.on { color: var(--text); border-color: var(--accent); background: #2b2519; }
.acttab .n { color: var(--text-2); }
.baggrid { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.bagcell {
  width: 52px; height: 52px; padding: 3px; cursor: pointer; font: inherit;
  background: #100c08; border: 1px solid var(--line); color: var(--text-2);
  display: grid; place-items: center;
}
.bagcell img { width: 100%; height: 100%; object-fit: contain; }
.bagcell:hover { border-color: var(--accent-quiet); }
.bagcell.on { border-color: var(--accent); box-shadow: 0 0 8px #c8a24c55; }
.bagcell.stale { border-style: dashed; }
.bagdetail {
  margin-top: var(--sp-2); padding: var(--sp-2) var(--sp-3); min-height: 52px;
  border: 1px solid var(--line); background: #16110c80;
}
.bagdetail .nm { display: block; }
.bagdetail .where { display: block; font-size: var(--fs-sm); color: var(--text-2); line-height: 1.45; }
/* 이 막에 입수 행이 없어 딴 막까지 넓혀 온 줄의 앞머리(「2막 — 」). 뒤따르는
   장소보다 밝게 둔다 — 이 줄에서 제일 먼저 읽어야 하는 것이 「이 막이 아니다」다. */
.bagdetail .whereact { color: var(--text-3); font-weight: 600; }
.bagdetail .note { display: block; font-size: var(--fs-sm); color: var(--text-3); }
/* 결함②(2026-08-17, 전체 브랜치 검수) — 「못 얻는다」 축. `.note`(막 메모, 위 규칙)
   보다 먼저 읽혀야 하므로 `--warn` 으로 구분한다(다른 두 자리 — #list ·
   .pickerlist 의 .unobtainable-tag — 와 같은 색이라 화면마다 안 흔들린다). */
/* 장비 종류(「장검 · 군용 무기」). `.note` 의 크기를 그대로 쓰되 이름 바로 아래
   붙는 사실이라 한 칸 밝게 둔다 — 아래 .unobtainable-tag(경고)와 색으로 갈린다. */
.bagdetail .note.kind { color: var(--text-2); }
.bagdetail .unobtainable-tag { color: var(--danger); }
.bagdetail .btn { margin-top: var(--sp-2); }

/* ── 고르기 창 ── */
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; }
/* ⚠ **고르기 창 제목은 id 다** — `#pickertitle`(build.html·party.html).
   개편 1차의 제목 목록이 `.pickertitle`(클래스)로 적혀 있어 **아무것도 안 물었다**
   — 「아무것도 안 잡는 그물」의 CSS 판이다. 위 활자 체계 절에서 `#pickertitle` 로
   고쳤고, id 라 구체성이 (1,1,1) 이라 이 규칙과 순서를 다투지 않는다.
   여기 `font-weight: normal` 은 그래서 **더 이상 제목에 안 닿는다** — 남겨 두면
   다음 사람이 「왜 안 먹지」를 겪는다. 뗀다. */
dialog.picker h3 { margin: 0 0 10px; color: var(--gold); }
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: block; padding: 0; cursor: default;
}
.pickerlist .picker-row {
  display: flex; width: 100%; gap: 8px; align-items: center; padding: 4px 7px;
  text-align: left; font: inherit; color: inherit; background: none; border: 0; cursor: pointer;
}
.pickerlist .picker-row:hover { background: #ffffff0d; }
.pickerlist .build-choice {
  display: block; width: 100%; padding: 4px 7px; text-align: left;
  font: inherit; color: inherit; background: none; border: 0; cursor: pointer;
}
.pickerlist .build-choice:hover { background: #ffffff0d; }
.pickerlist .rarity { margin-left: auto; font-size: 11px; color: var(--muted); }
.pickerlist .where { font-size: 11px; color: var(--faint-readable); }

.hint { color: var(--faint-readable); font-size: 12px; }
.hint.warn { color: var(--warn); }
.saved { color: var(--gold-dim); font-size: 12px; }
/* ── 꼬리말(사이트 푸터) ──────────────────────────────────────────────────
   마크업 정본은 web/lib/site-nav.js 의 꼬리말HTML() 이고 화면 13쪽이 그 사본을
   싣는다(tests/site-nav.test.js 가 전수 대조). 2026-09-03 까지는 「출처와 라이선스 ·
   … — 작은 힘이 됩니다」 한 줄(11px 가운데 정렬)이었다 — 사용자 지적(「촌티난다」)
   으로 머리띠와 같은 어법(본문 글꼴·조용한 선·금색 강조)의 띠로 바꿨다.
   격자 네 칸: 왼쪽 위 브랜드 · 오른쪽 위 디스코드/후원 단추 · 왼쪽 아래 안내 링크 ·
   오른쪽 아래 면책. **DOM 차례(안내 링크 → 단추)는 정본 그대로고 자리만 격자가
   바꾼다** — 순서를 마크업에서 바꾸면 그물이 깨진다.
   ⚠ `.footnote` 이름은 남긴다 — print.css 숨김·home.css 격자 자리·아래 모바일
   순서(`.bg3-main > .footnote`)가 전부 이 이름에 걸려 있다.
   ⚠ `cursor: pointer` 를 안 적는다 — 링크라 원래 손가락이고, 적는 순간
   tests/mobile.test.js 의 44px 그물에 걸린다(모바일 높이는 아래에서 따로 준다). */
.footnote {
  grid-column: 1 / -1;
  box-sizing: border-box;
  margin-top: 8px;
  padding: 22px 4px 10px;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "brand community" "legal meta";
  gap: 14px 24px;
  align-items: center;
  color: var(--text-2);
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  line-height: 1.5;
  text-align: left;
}
.sf-brand { grid-area: brand; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.sf-name {
  color: var(--text); font-size: var(--fs-lg); font-weight: 700;
  letter-spacing: -.02em; line-height: 1.2;
}
.sf-tag { color: var(--text-2); }
.sf-legal { grid-area: legal; display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 0; }
/* ⚠ `body.bg3 a { color: var(--gold) }`(0,1,2) 가 `.sf-legal a`(0,1,1) 를 이긴다 — 실측
   (헤드리스 크롬, 2026-09-03) 링크가 금색으로 나왔다. 조상 하나를 더 적어 (0,2,1) 로 이긴다.
   기본은 조용한 보조색, 올리면 금색 — 출처 목록(.srclist a)과 같은 어법이다. */
.footnote .sf-legal a { color: var(--text-2); text-decoration: none; transition: color .14s ease; }
.footnote .sf-legal a:hover, .footnote .sf-legal a:focus-visible { color: var(--accent); }
.sf-community { grid-area: community; justify-self: end; display: flex; flex-wrap: wrap; gap: 8px; }
.sf-btn {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 36px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface-2);
  color: var(--text); font-size: var(--fs-base); font-weight: 600; letter-spacing: -.01em;
  text-decoration: none; white-space: nowrap;
  transition: border-color .14s ease, background-color .14s ease, color .14s ease;
}
.sf-btn:hover, .sf-btn:focus-visible { border-color: var(--accent); background: var(--surface-3); }
.sf-btn:focus-visible, .sf-legal a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sf-ico { width: 16px; height: 16px; flex: none; fill: currentColor; }
/* 브랜드색은 **아이콘에만** 준다 — 글자색 토큰이 아니라 대비 그물 밖이고, 글자는 그대로다. */
.sf-discord:hover .sf-ico, .sf-discord:focus-visible .sf-ico { color: #5865f2; }
.sf-heart:hover .sf-ico, .sf-heart:focus-visible .sf-ico { color: var(--accent); }
.sf-meta { grid-area: meta; justify-self: end; margin: 0; text-align: right; color: var(--text-2); font-size: var(--fs-sm); }
@media (max-width: 720px) {
  .footnote {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "brand" "community" "legal" "meta";
    gap: 14px;
    padding: 20px 2px 8px;
  }
  .sf-community { justify-self: stretch; }
  /* 손가락 크기(mobile.css 의 --m-touch). 이 파일은 그 변수를 못 가질 수 있어 되돌림을 둔다. */
  .sf-community .sf-btn { flex: 1 1 0; justify-content: center; min-height: var(--m-touch, 44px); }
  .sf-legal a { min-height: var(--m-touch, 44px); display: inline-flex; align-items: center; }
  .sf-meta { justify-self: start; text-align: left; }
}

/* ── 출처와 라이선스 화면 ── */
/* 읽는 화면이라 한 칸이다. 폭을 재는 것은 글줄 길이(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; }

/* ── 업데이트 및 공지사항 ────────────────────────────────────────────────── */
.bg3-main.updates { gap: var(--sp-5); }
.updates-intro {
  padding: var(--sp-6) var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--line-2);
  text-align: center;
}
.updates-intro h2 {
  margin: var(--sp-2) 0;
  color: var(--text);
  font-family: var(--font-title);
  font-size: var(--fs-hh);
  font-weight: 500;
  letter-spacing: .06em;
}
.updates-intro > p:last-child {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-lg);
  line-height: 1.7;
}
.updates-kicker {
  margin: 0;
  color: var(--text-3);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.updates-section { display: grid; gap: var(--sp-3); }
.updates-section-title {
  margin: var(--sp-3) 0 0;
  color: var(--text-3);
  font-size: var(--fs-sm);
  letter-spacing: .14em;
}
.updates-list { display: grid; gap: var(--sp-3); }
.update-entry { padding: var(--sp-5); }
.update-entry h3 {
  margin: var(--sp-2) 0;
  color: var(--text);
  font-family: var(--font-title);
  font-size: var(--fs-h);
  font-weight: 500;
}
.update-entry p {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-lg);
  line-height: 1.75;
}
.update-entry-notice {
  border-color: var(--accent-quiet);
  box-shadow: inset 3px 0 var(--accent), 0 8px 22px #0003;
}
.update-meta {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--text-2);
  font-family: var(--font-num);
  font-size: var(--fs-sm);
}
.update-badge {
  padding: 2px 7px;
  border: 1px solid var(--accent-quiet);
  color: var(--accent);
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: .08em;
}
@media (max-width: 620px) {
  .updates-intro { padding: var(--sp-5) var(--sp-2) var(--sp-3); }
  .updates-intro h2 { font-size: var(--fs-h); }
  .update-entry { padding: var(--sp-4); }
}

/* ── 게시판은 **더 넓다** (2026-08-29 사용자 지적) ───────────────────────
   > 「게시판은 칸을 너무 좁게 쓰는 거 같아 양쪽도 남는데」

   ⚠ **`.narrow`(40rem) 자체를 안 넓힌다.** 그 클래스는 `profile.html`·
   `author.html` 도 쓴다 — 넓히면 세 화면이 같이 움직인다. 게시판만 modifier 를
   하나 더 진다(`board.html` 의 `<main class="bg3-main narrow board">`).
   ⚠ `.narrow` 를 **떼지도 않는다** — 목록 줄의 3행 격자(`.narrow .clouddocs li`
   부터 `.narrow .cdstats` 까지 여섯 규칙)가 그 클래스에 걸려 있다. 떼면 목록이
   통째로 옛 한 줄 꼴로 돌아간다.

   두 폭인 까닭: 목록은 훑는 화면이라 글줄이 너무 길면 눈이 되돌아오기 힘들고,
   글 하나는 **훑는 데이터가 3열로 흘러야** 해서 더 필요하다.
   ⚠ 옛 주석은 「빌드와 설명을 **좌우로** 놓아야 해서」였는데, #173 이 그 두 칸을
     전폭 세로로 펴면서 그 까닭이 사라졌다 — 낡은 주석을 지운다. */
.bg3-main.narrow.board { grid-template-columns: minmax(0, 64rem); }
/* 첫 HTML의 빈 SSR 자리와 늦게 도착하는 필터가 목록을 밀지 않게 한다.
   직업 칩은 한 줄로 스크롤하며, 목록/오류가 짧아도 하단 정보는 화면 아래에 둔다. */
#boardssr:empty { display: none; }
#boardlistpane { box-sizing: border-box; }
#boardlanguages, #boardchips { min-height: 48px; box-sizing: border-box; }
#boardchips { flex-wrap: nowrap; overflow-x: auto; }
#boardchips .chip { flex-shrink: 0; }
/* 상세 HTML은 처음부터 상세 폭을 쓴다. 서버 글을 읽는 동안 빈 목록/상세 셸을
   중복 표시하지 않고, 미리보기 준비가 끝나 SSR을 걷으면 같은 자리에 나타낸다. */
.bg3-main.narrow.board:has(#boardssr:not(:empty)) { grid-template-columns: minmax(0, 88rem); }
#boardssr:not(:empty) ~ #boardlistpane,
#boardssr:not(:empty) ~ #boardone { display: none; }
/* 글 하나를 연 상태(`board.js` 가 `<main>` 에 켠다).

   ⚠ **바깥이 쓰는 폭을 다 쓴다**(2026-09-11, 사용자 지적 「양 옆을 넓게」).
   실측(창 1,665px): `.bg3-main` 이 **1,472px** 을 쓰는데 글은 76rem(1,216px)에
   갇혀 **좌우로 128px 씩 버리고** 있었다. 88rem = 1,408px 은 `.bg3-main` 의
   `max-width: 1440px` 안쪽(1,440 − padding 32)에 **딱** 든다 — 사이트 기준선을
   안 건드리고 최대로 쓰는 값이다.

   값을 하는 자리는 `.gcols` 가운데 칸이다(`300px | 1fr | 350px`):
       76rem → 426px      88rem → **618px** (+45%)
   레벨업 요약의 칩이 그만큼 덜 접힌다 — 넓힌 까닭이 「여백이 아까워서」가 아니라
   **읽을 것이 실제로 더 들어가서**다.

   (`.bdbody`(설명글)를 720px 에 두던 단서는 2026-09-13 에 풀렸다 — 설명이 탭이
   되면서 셋 다 이 폭을 쓴다. 아래 `.bdsplit` 절.) */
.bg3-main.narrow.board.one { grid-template-columns: minmax(0, 88rem); }

/* ── 쪽 이동 (번호 페이지) ───────────────────────────────────────────────
   ⚠ **단추가 아니라 링크다.** `board.js` 가 `<a href="/board?p=2">` 로 그린다 —
   가운데 클릭·새 탭·주소 복사가 다 되고, 자바스크립트가 죽어도 주소는 살아 있다.
   지금 쪽은 `aria-current="page"` 를 진다(그 자리를 CSS 가 표시로 쓴다). */
.pagenav {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: var(--sp-2); margin: var(--sp-4) 0 0;
}
.pagenav a, .pagenav span {
  min-width: 2rem; padding: 6px 10px; border-radius: 4px;
  font-size: var(--fs-base); text-align: center; text-decoration: none;
  color: var(--text-2); border: 1px solid var(--line-2);
}
.pagenav a:hover { color: var(--text-1); border-color: var(--line-1); }
/* 지금 쪽. **색만 바꾸지 않는다** — 색만으로 나르면 못 보는 사람이 있다.
   테두리까지 같이 굵어져 형태로도 드러난다. */
.pagenav a[aria-current="page"] {
  color: var(--gold-1); border-color: var(--gold-2); font-weight: 600;
}
/* 갈 수 없는 쪽(첫 쪽에서의 「이전」). `<span>` 이라 애초에 못 누른다 —
   `disabled` 를 흉내 낸 링크를 두지 않는다(탭 이동이 헛돈다). */
.pagenav span { opacity: .35; }
/* 「…」 자리. 쪽이 많을 때 가운데를 접는다. */
.pagenav .gap { border-color: transparent; min-width: 1rem; padding: 6px 2px; }

/* ── 글 하나 — **탭 셋이 전폭을 쓴다** (2026-09-13) ───────────────────────
   내 빌드 · 계산 · **설명**. 셋째가 새로 탭이 됐다(사용자 결정: 「이걸 그냥 내 빌드/계산
   처럼 또 다른 탭으로 하자. 그리고 화면은 다 쓰게 하고. 지금은 오른쪽 부분이 비어
   있잖아」). 같은 자리를 **세 번째로** 고치는 것이라 앞 두 판의 실측을 남긴다:

   · 2026-08-29 좌우 두 칸 — .bdbuild 627×4,165 · .bdbody 465×3,265(조회 246 글).
     900px 어긋나 「같이 보기」가 안 됐고, sticky 도 4,165px 이 화면에 안 들어 안 붙었다.
   · 2026-09-10 전폭 세로 — 데이터가 3열로 흘러 4,165 → 2,071px. 대신 문서가 +17%
     길어졌고, 설명은 읽기 줄 길이 때문에 720px 에 뒀다 — 그래서 **오른쪽 ~700px 이
     빈 채로** 남았다(사용자 스크린샷 2026-09-13).
   탭이면 둘 다 없다 — 한 번에 하나만 보고, 그 하나가 폭을 다 쓴다.

   ⚠ 설명의 줄 길이는 이제 바깥 폭(88rem, 15px 기준 한 줄 ~90자)이다. 한글 권장
     (25~40자)을 넘는 것을 **알고** 정한 값이다 — 이 글들의 문단이 2~3줄이라 읽힌다.

   ── 상태는 `#boardpreview[data-preview-active]` 하나가 나른다 ─────────────
   설명 본문(`.bdbody`)은 `#boardpreview` **밖·바로 뒤 형제**다(board.html 의 주석 —
   그 칸은 글을 열 때마다 통째로 갈린다). 그래서 탭 모듈(`public-build-preview.js`)은
   mount 에 상태만 적고, 무엇을 보이고 숨길지는 여기서 정한다:

       속성 없음        본문 보임  (첫 HTML · JS 가 안 뜬 판 · 미리보기를 뗀 뒤)
       glance · calc    본문 숨김 · 패널 보임
       body             패널 숨김 · 본문 보임

   ⚠ **`hidden` 을 안 쓴다.** 종이(`print.css`)가 탭 상태와 상관없이 본문을 되살려야
     하는데, `[hidden]` 을 되살리는 규칙은 이 저장소가 금한다(`tests/hidden-attr.test.js`
     — 네 번 데인 자리). 속성 값으로 가르면 인쇄 쪽이 id 둘(2,1,0)로 그냥 이긴다.
   ⚠ 패널 탭을 **낱낱이 적는다**(`glance`·`calc`). `:not([data-preview-active="body"])`
     로 접으면 특정도가 (1,3,0)이 되어 인쇄 규칙과 싸운다. 패널 탭이 늘면 여기도 한 줄
     는다 — 빠뜨리면 그 탭에서 본문이 **같이 보인다**(조용히 사라지는 쪽이 아니라 눈에
     띄는 쪽으로 틀리게 해 뒀다).
   ⚠ 차례는 여전히 **빌드 먼저, 설명 나중**이다 — DOM 그대로(`tests/board-buttons.test.js`). */
.bdsplit { margin-top: var(--sp-3); }
/* 본문은 패널과 **같은 자리**(탭줄 아래)에 앉는다. 폭 제한은 없다 — 위 결정. */
.bdbody { min-width: 0; }
#boardpreview[data-preview-active="glance"] ~ .bdbody,
#boardpreview[data-preview-active="calc"] ~ .bdbody { display: none; }
#boardpreview[data-preview-active="body"] #boardpreviewpanel { display: none; }
.credits .pane + .pane { margin-top: 14px; }

/* ── 산문 화면의 본문은 **훑는 화면 크기**다 ─────────────────────────────
   ⚠ **개편이 여기서 거꾸로 갔다**(2026-08-24 눈가림 검수). `body.bg3` 기본을
   14 → 13px 로 내리면서 「훑는 화면은 벌린다」(설계 결정 1)를 같이 넣었는데,
   `--fs-lg`(15px)가 실제로 닿은 곳은 **절 제목과 게시판 목록뿐**이었다.
   그래서 출처·약관·개인정보·작성자·프로필의 **산문이 14 → 13px 로 줄었다** —
   「글자가 작다」는 제보에서 출발한 개편이 그 화면들만 더 작게 만든 꼴이다.

   여기가 그 연결이다. 읽기만 하는 산문(문단·목록·정의)에만 건다 —
   폼·표·칩은 조작하는 자리라 쓰는 화면 밀도(13px)를 그대로 둔다.
   ⚠ 새 값을 만들지 않는다. `--fs-lg` 는 게시판 목록이 이미 쓰는 그 토큰이다. */
.credits .pane p, .credits .pane li, .credits .pane dd,
.narrow .pane > p, .narrow .pane > ul > li {
  font-size: var(--fs-lg);
}
/* 출처 목록은 34개짜리 2단 조판이라 예외다 — 키우면 단이 무너진다(아래 .srclist). */
.credits .pane .srclist li { font-size: 12px; }

.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: stretch; gap: 4px;
  padding: 0; 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-main {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  width: 100%; padding: 12px 6px; cursor: pointer; font: inherit; font-size: 12px;
  text-align: center; background: transparent; border: 0; color: var(--cream);
}
.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-readable); 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-readable); font-size: 10px; letter-spacing: .1em; }
.partyslot-main.empty .pname { color: var(--faint-readable); }
/* 없는 역할은 눈에 띄게 — 강제하지는 않고 알려만 준다. */
.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-readable);
}
.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-damage { margin-top: 8px; color: var(--cream); font-size: 12px; line-height: 1.5; }
.st-damage-basis, .st-damage-condition { color: var(--muted); font-size: 11px; }
.st-damage dl { margin: 4px 0 0; }
.st-damage-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2px 12px; padding: 3px 0; }
.st-damage-row dt { flex: 1 1 100px; overflow-wrap: anywhere; }
.st-damage-row dd { margin: 0; overflow-wrap: anywhere; }
.st-damage-condition { display: block; }
.st-damage-row strong { color: var(--accent); }
.st-body { margin-top: 6px; color: var(--cream); font-size: 12px; line-height: 1.5; }
/* ⚠ `.gamedesc .lstag` 와 **한 몸이다**(점선 걷기, 2026-08-23). 한쪽만 고치면
   같은 표시가 화면마다 달라진다 — 그 절의 주석에 까닭이 적혀 있다. */
.st-body .lstag {
  border-bottom: 0;
  color: var(--accent);
  cursor: help;
  text-underline-offset: 3px;
}
.st-body .lstag:hover,
.st-body .lstag:focus-visible {
  text-decoration: underline dotted var(--accent-quiet);
}
.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-classes {
  margin-top: 7px; padding-top: 6px;
  border-top: 1px solid #2d2417; font-size: var(--fs-sm);
}
.st-classes-title { margin-bottom: 5px; color: var(--muted); }
.st-class-list { display: flex; flex-wrap: wrap; gap: 5px; }
.st-class {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px;
  border: 1px solid var(--accent-quiet);
  border-radius: 3px; color: var(--accent); text-decoration: none;
}
.st-class-icon { width: 14px; height: 14px; flex: none; object-fit: contain; }
.st-class:hover, .st-class:focus-visible {
  color: var(--cream); border-color: var(--accent);
}
.st-parents {
  margin-top: 7px; padding-top: 6px;
  border-top: 1px solid #2d2417; font-size: var(--fs-sm);
}
.st-parents-title { margin-bottom: 5px; color: var(--muted); }
.st-parent-list { display: flex; flex-wrap: wrap; gap: 5px; }
.st-parent {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px;
  border: 1px solid var(--accent-quiet);
  border-radius: 3px; color: var(--accent); text-decoration: none;
}
.st-parent-icon { width: 14px; height: 14px; flex: none; object-fit: contain; }
.st-parent:hover, .st-parent:focus-visible {
  color: var(--cream); border-color: var(--accent);
}
/* 점은 게임 아이콘을 쓰고, 없으면 색 동그라미로 되돌아간다. */
.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(--accent); font-size: var(--fs-sm); }
.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: var(--sp-2); font-size: var(--fs-lg); padding: var(--sp-2) 22px; }
.btn.levelup .uparrow { width: 22px; height: 22px; object-fit: contain; }
.btn.levelup.blocked { opacity: .45; cursor: default; }
.btn.levelup.blocked:hover { color: var(--text); border-color: var(--accent-quiet); }

/* 확정하면 잠깐 뜨는 표시. 게임의 레벨업 화살표를 쓴다. */
.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 .picker-row { 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-readable); }
.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; }

/* title 에만 있던 정보를 덧붙인 자리(build.js 의 갈래 + 힌트 덧붙이기 참고).
   ⚠ **이건 본문 상자 안이 아니라 형제다.** build.js 가 `${본문}<div class="tt-hint">…`
   로 내보내므로 .tt-hint 는 .st / .tt 의 **바깥**에 선다.
   시트(.bsheet-body)는 제 배경과 안여백이 있어 구분선만으로 충분하다 — 아래 기본값이
   그 경로용이다. */
.tt-hint {
  margin-top: 6px; padding-top: 6px; border-top: 1px solid #2d2417;
  color: var(--muted); font-size: 11px; line-height: 1.5;
}
/* ⚠ **떠 있을 때는 제 상자를 쥔다.** `.st-float`(:1286)에는 배경도 안여백도 없고
   상자는 `.st`(:1289)와 `.tt`(tooltip.css:4)가 **각자** 갖는다. 그래서 형제로 붙은
   힌트는 데스크톱 hover 에서 **테두리선 한 줄과 11px 글씨가 페이지 위에 그냥 떴다**
   (2026-08-16 리뷰 I-1). 「새 상자는 안 만든다」던 옛 주석은 이 전제를 틀리게 읽은
   것이다 — 시트 경로만 멀쩡해서 하네스(마크업만 잰다)도 못 봤다. */
.st-float .tt-hint {
  margin-top: 8px; padding: 7px 11px;
  background: #17130d; border: 1px solid var(--gold-dim); border-radius: 6px;
  box-shadow: 0 8px 24px #000a;
}
/* ⚠ **받는 중·못 받음 한 줄도 제 상자를 쥔다** — 위 `.tt-hint` 와 같은 뿌리다. 아이템
   툴팁이 상세를 기다리는 동안과 못 받았을 때 내는 것은 맨 `<p class="hint">` 하나라
   (panels/cell-tooltip.js 의 itemTooltipFor) 떠 있는 상자에서 **페이지 글 위에 맨 글자로
   겹쳤다**(2026-09-23 실측: 고르기 창 줄에 키보드 포커스 — 오른쪽 패널의 「레벨」 위에 얹혔다).
   고르기 후보가 목록 행으로 가짜 카드를 그리던 동안에는 안 보이던 자리다.
   시트(.bsheet-body)는 제 배경이 있어 안 건드린다 — `>` 로 떠 있는 상자의 맨 자식만 겨눈다. */
.st-float > .hint {
  margin: 0; padding: 9px 11px;
  background: #17130d; border: 1px solid var(--gold-dim); border-radius: 6px;
  box-shadow: 0 8px 24px #000a;
}
/* 카드 **뒤에** 붙는 한 줄은 카드와 띄운다 — 몬스터 인벤토리 설명창이 못 받았을 때 칸 요약 아래에
   실패 줄을 붙인다(item-detail-tooltip.js). 위 `.tt-hint` 와 같은 간격이다. */
.st-float > * + .hint { margin-top: 8px; }

/* 종족이 주는 수치(이동 속도·숙련·저항). 특성 칩과 구분해 테두리만 다르게 준다. */
.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; }

/* ── 전투 시뮬레이션 — 세 구역 골격 (계산 탭 개편 3a) ──────────────────────
   열여섯 절이 세로로 흩어져 「뭘 해야 할지」가 안 보이던 것을 **① 상대 · ②
   계획 · ③ 결과** 세 구역으로 접는다.

   ⚠ **배치만 바꾼다 — 계산은 한 줄도 안 건드린다.** 값의 정본은 그대로
   `round-sim.js`·`attack-source.js`·`damage.js` 다. 이 개편이 값을 안 움직였다는
   것은 `tools/calc-oracle.mjs`(무기 421)와 렌더 스냅샷 전후 대조로 잰다.

   ⚠ **정보를 줄이지 않는다.** 내성·성질·저항은 지우는 게 아니라 ① 상대의
   「세부 조정」 접기 뒤로 **옮긴다** — 접기 안은 옛 `목표 설정` 절 그대로다.

   ⚠ **오른쪽 열이 `sticky` 라 조상에 `overflow`·`transform` 을 걸면 조용히 안
   붙는다.** 실패가 아니라 침묵이다 — `tests/typography.test.js` 의 「붙는 줄의
   조상」 그물에 `.simgrid` 를 같이 넣어 그 자리를 물게 해 뒀다. */
/* ⚠⚠ **창이 아니라 칸을 잰다.** 처음엔 `@media (max-width: 1100px)` 로 접었는데
   **효과가 거꾸로였다**(실측 2026-09-15). 1100px 은 「빌드 플래너 3단 → 1단」
   문턱이라, 그 **아래**에서 `#editor` 가 오히려 **전폭**이 된다. 그래서 그 규칙은
   넓은 칸에서 1열로 접고, 정작 좁은 3단(1280 뷰포트에서 `#editor` **671px**)에서
   2열로 쪼개고 있었다 — 왼쪽 계획 열이 **275px** 이었다.

   칸을 재면 그 자리가 사라진다. 「한눈에」(`.glance`)가 같은 이유로 이미 컨테이너
   쿼리를 쓰고, 그 주석이 근거를 적어 뒀다 — 「칸이 넓어진 것만으로 저절로 따라왔다」.
   중단점 다섯을 안 늘리는 길이기도 하다(여섯째 금지, `tests/mobile.test.js`). */
.simwrap { container-type: inline-size; }
.simgrid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-5);
  /* ⚠ `start` 가 **sticky 의 전제**다. 기본값(`stretch`)이면 오른쪽 열이 격자
     높이만큼 늘어나 붙을 여백 자체가 없다 — 규칙은 그대로인데 안 붙는다. */
  align-items: start;
  margin-top: var(--sp-4);
}
/* ⚠⚠ **한 열일 때 `.simside` 는 칸이 아니라 통로다.** `display: grid` 로 두면 그 격자의
   트랙이 `auto` 라 자식의 **최소콘텐츠 폭**으로 부푼다 — 실측(2026-09-16, 390px): 문서가
   **566px** 까지 옆으로 새서 ①상대·③결과가 화면 밖으로 나갔다. `.simgrid`(`minmax(0,1fr)`)와
   `.simplan`(`min-width:0`)에는 이미 걸어 놨는데 **이 한 층만 빠져 있었다**
   (CLAUDE.md 「값의 뜻을 바꾸면 층을 전부 훑는다」).

   ⚠ 그리고 한 열일 때는 **차례가 ②→①→③ 이 된다** — 오른쪽 열에 있던 ①과 ③이 계획 뒤로
   통째로 밀려서다. 구역에 번호를 매겨 놓고 번호 아닌 차례로 읽히면 그게 곧 「이상하다」는
   신호다. `display: contents` 로 `.simside` 를 걷어 ①②③을 `.simgrid` 의 자식으로 만들고
   `order` 로 세운다. 부푸는 트랙도 같이 사라진다. */
.simside { display: contents; }
.simfoe { order: 1; }
.simplan { order: 2; }
.simresult { order: 3; }
/* 칸이 이만큼 넓을 때만 두 열이다. 336px 오른쪽 열을 빼고도 계획 쪽에 560px 이
   남는 폭 — 그 아래로는 행동 줄(아이콘·이름·명중·맞으면·기대)이 뭉갠다. */
@container (min-width: 900px) {
  .simgrid { grid-template-columns: minmax(0, 1fr) 336px; }
  /* 두 열이면 다시 오른쪽 열 하나로 묶는다. 트랙을 `minmax(0, 1fr)` 로 못박아 위에서 본
     부풀기가 넓은 쪽에서도 안 나게 한다. */
  .simside {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3);
    /* 한 열일 때는 붙일 곳이 없다 — 붙은 채로 두면 스크롤 중에 겹친다. */
    position: sticky; top: var(--sp-4);
  }
  /* 열이 갈리면 차례는 자리로 정해진다 — `order` 를 되돌려 DOM 순서대로. */
  .simfoe, .simplan, .simresult { order: 0; }
}
/* 왼쪽 열은 `minmax(0,1fr)` 이라 안의 넓은 것(표·핫바)이 열을 밀지 못한다. */
.simplan { min-width: 0; }

/* ① 의 두 겹(`.simfoepin` 고정될 것 · `.simfoemore` 흐를 것)과 퀵슬롯 시트(`.hbsheet`)는
   **데스크톱에서 모양이 없는 블록이다** — 좁은 화면에서만 붙고 뜬다(`mobile.css` 의 3b 절).
   손잡이는 데스크톱에서 누를 것이 없어 안 보인다. */
.simfoepin, .simfoemore, .hbsheet { display: block; }
.hbhandle { display: none; }
/* 접힘(`folded`)은 **좁은 화면의 시트에서만 뜻이 있다.** 좁은 화면에서 접고 창을 넓히면 상태가
   남는데, 데스크톱 퀵슬롯은 늘 펼쳐져 있어야 한다 — 그래서 여기서는 아무것도 안 숨긴다. */
.hbsheet.folded { display: block; }

/* ── 지금 할 일 ── 한 줄. 행동이 남은 라운드 · 계획이 꽉 찼음 ── */
.simtodo {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); margin: var(--sp-3) 0;
  border: 1px solid var(--line); border-left: 3px solid var(--gold);
  background: #16110c80;
}
.simtodo .k {
  font-size: var(--fs-xs); color: var(--gold);
  letter-spacing: .08em; white-space: nowrap;
}
.simtodo .v { font-size: var(--fs-sm); color: var(--text); min-width: 0; }
.simtodo .simshare { margin-left: auto; flex: none; font-size: var(--fs-sm); }
/* 시나리오 중의 「되돌리기」 — 링크 복사 왼쪽. 셋 다 오른쪽에 붙되 auto 여백은 맨 앞 것 하나만. */
.simtodo .simrestore { margin-left: auto; flex: none; font-size: var(--fs-sm); color: var(--danger); }
.simtodo .simscenario { margin-left: auto; flex: none; font-size: var(--fs-sm); }
.simtodo .simrestore + .simscenario,
.simtodo .simscenario + .simshare { margin-left: 0; }

/* 이름을 받아 목표+계획 스냅샷을 저장한다(§4 ①). */
.scenarioform { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.scenarioform input { flex: 1; min-width: 0; }
/* 저장된 시나리오 — 누르면 불러오고, ✕ 로 지운다. */
.scenariolist { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: 0 0 var(--sp-3); }
.scenariopill {
  display: inline-flex; align-items: center; gap: 2px;
  border: 1px solid var(--line); border-radius: 999px; padding: 2px 2px 2px var(--sp-2);
  background: #16110c80;
}
.scenariopill .scenarioload { background: none; border: none; color: var(--text-2); font-size: var(--fs-xs); cursor: pointer; }
.scenariopill .scenariodel {
  background: none; border: none; color: var(--muted); font-size: var(--fs-xs);
  width: 18px; height: 18px; display: grid; place-items: center; cursor: pointer;
}
body.bg3 .scenariopill .scenarioload:hover { color: var(--gold); }
body.bg3 .scenariopill .scenariodel:hover { color: var(--danger); }

/* 오른쪽 #summary 가 전폭이라 감춰져 이름·능력치를 한 줄로 대신 낸다(§4 ②). */
.simsummary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3);
  margin: 0 0 var(--sp-2); font-size: var(--fs-sm);
}
.simsummary .who { color: var(--text); }
.simsummary .abils { display: flex; flex-wrap: wrap; gap: 0 var(--sp-2); }
.simsummary .abils .a { color: var(--muted); font-variant-numeric: tabular-nums; }
.simsummary .abils .a b { color: var(--text-2); font-weight: 600; }

/* 「+ 조건 더하기」(§4 ③) — 세부 조정의 「목표의 성질」로 데려가는 문. */
.addcondbtn { font-size: var(--fs-xs); margin-top: var(--sp-1); }

/* ── 구역 제목 — 번호 원 + 이름 ── */
.simhead { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
/* 구역 제목 오른쪽의 ⓘ — 값이 어디서 오는지 말한다(시안 3a). */
.simhead .note {
  margin-left: auto; font-size: var(--fs-xs); color: var(--muted);
  border-bottom: 1px dotted var(--gold-dim); cursor: help; white-space: nowrap;
}
/* ② 머리의 부제(시안 3a 「라운드를 고르고 퀵슬롯에서 넣기」) — 옛 안내 문단 셋이 이 글의 툴팁이다.
   좁으면 줄임표로 접는다(`min-width: 0` 이 없으면 flex 가 안 줄인다). */
.simhead .simsub {
  min-width: 0; font-size: var(--fs-sm); color: var(--text-2); cursor: help;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 고른 라운드의 줄 머리(「n라운드」) 곁 ⓘ — 구역 제목의 것과 같은 옷. 제목은 세리프·자간이 있어
   ⓘ 만 본문 글꼴로 되돌린다. */
.turntitle { display: flex; align-items: center; gap: var(--sp-2); }
.turntitle .note {
  margin-left: auto; font-family: var(--font-body); font-size: var(--fs-xs); font-weight: 400;
  letter-spacing: 0; color: var(--muted); border-bottom: 1px dotted var(--gold-dim);
  cursor: help; white-space: nowrap;
}
.simnum {
  flex: none; width: 18px; height: 18px; display: grid; place-items: center;
  border: 1px solid var(--gold-dim); border-radius: 50%;
  font-size: var(--fs-micro); color: var(--gold);
}

/* ── ① 상대 · ③ 결과 카드 ── */
.simfoe { border: 1px solid var(--gold-dim); background: #16110c; padding: var(--sp-3) 14px; }
.simresult { border: 1px solid var(--line); background: #16110c80; padding: var(--sp-3) 14px; }
/* AC 를 이 화면에서 제일 먼저 읽히게 둔다. 값은 `목표.ac` 하나이고, 슬라이더를
   끄는 동안에는 `writeTurnNumbers()` 가 여기도 같이 갈아 끼운다(패널을 다시
   그리면 슬라이더 포커스가 죽는다 — 그 규칙은 `#acvalue` 와 같다). */
.simac { font-size: var(--fs-num-xl); color: var(--text); line-height: 1.1;
  font-variant-numeric: tabular-nums; }
.simfoe .simack { font-size: var(--fs-xs); color: var(--muted); letter-spacing: .08em; }
/* AC 아래 프리셋 이름(시안 3a 「보통 적」) — 프리셋에서 벗어나면 빈 글이라 자리를 안 먹는다. */
.simfoe .simfoename { font-size: var(--fs-sm); color: var(--text-2); }
.simfoe .simfoename:empty { display: none; }
/* 좁은 열(336px)이라 접기 안의 슬라이더 줄이 넘치지 않게 한 열로 접는다. */
.simfoe .acslider { flex-wrap: wrap; }

/* ── 「다른 상대라면?」 매트릭스(시안 3a) ────────────────────────────────
   진하기는 그 표 안의 최대 대비다 — 값은 `--v`(0~1)로 인라인으로 들어온다. */
.simmx { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.simmx th {
  font-size: var(--fs-xs); color: var(--muted); font-weight: 400; padding: 2px 4px; text-align: center;
}
.simmx thead th .sub { display: block; font-size: var(--fs-xs); color: var(--gold-dim); }
.simmx tbody th { text-align: left; white-space: nowrap; }
.simmx td {
  padding: 0; text-align: right; font-variant-numeric: tabular-nums; color: var(--text);
  border: 1px solid var(--line);
  background: rgba(200, 162, 76, calc(0.06 + 0.34 * var(--v, 0)));
}
/* 칸을 누르면 그 조건·상대로 바뀐다(시안 3a) — 칸 전체가 누르는 자리라 안여백은 단추가 진다. */
.mxcell {
  display: block; width: 100%; padding: 4px; font: inherit; color: inherit;
  background: none; border: 0; cursor: pointer; text-align: right;
  font-variant-numeric: tabular-nums;
}
.mxcell:hover { color: var(--gold); }
.mxcell.on { box-shadow: inset 0 0 0 1px var(--gold); color: var(--gold); }

/* ── ③ 결과의 명중 굴림 세 줄 비교(시안 3a) ─────────────────────────────
   주황 세로선(`em`)이 상대 체력이다 — 막대가 그 선을 넘으면 쓰러뜨린다는 뜻. */
.rollcmp { margin: var(--sp-3) 0; }
.rollcmp .k { margin: 0 0 var(--sp-1); font-size: var(--fs-xs); color: var(--muted); letter-spacing: .06em; }
.rcrow { display: grid; grid-template-columns: 44px minmax(0, 1fr) 48px 62px; gap: var(--sp-1); align-items: center; }
.rcrow.on .rcname { color: var(--gold); }
.rcname {
  font: inherit; font-size: var(--fs-sm); text-align: left; cursor: pointer;
  border: 0; background: transparent; color: var(--text-2); padding: 2px 0;
}
body.bg3 .rcname:hover { color: var(--gold); }
.rcbar { position: relative; height: 10px; background: var(--line-2); border: 1px solid var(--line); }
.rcbar i { display: block; height: 100%; background: linear-gradient(90deg, var(--gold-lo), var(--gold)); }
/* 상대 체력 기준선. `left` 를 인라인으로 받는다 — 값은 `목표.hp` 하나에서 온다. */
.rcbar em { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--danger); }
.rcval, .rckill { font-size: var(--fs-sm); text-align: right; font-variant-numeric: tabular-nums; color: var(--text-2); }

/* ── ① 상대의 조건 칩(시안 3a) — 「켜면 이 목표엔 얼마인가」 ────────────── */
.condchips { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: var(--sp-2) 0; }
.condchip {
  display: flex; flex-direction: column; gap: 1px; align-items: flex-start;
  padding: 4px 8px; font: inherit; text-align: left; cursor: pointer;
  border: 1px solid var(--line); background: transparent; color: var(--text-2);
}
.condchip.on { border-color: var(--gold-dim); background: #2a2116; color: var(--text); }
.condchip .n { font-size: var(--fs-sm); }
.condchip .d { font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
/* 켜서 좋으면 금색, 나쁘면 위험색. 영향이 없으면 색을 안 준다 — 지우지도 않는다. */
.condchip.good .d { color: var(--gold); }
.condchip.bad .d { color: var(--danger); }
/* 목표의 **성질** 칩(시안 3a·4a의 「+ 언데드」류) — 조건 칩과 같은 옷이되, 켜기 전에는
   점선이다. 「이 빌드가 이미 쥔 조건」이 아니라 「상대를 그렇게 정한다」라서 뜻이 다르다. */
.condchip.tgchip { border-style: dashed; }
.condchip.tgchip.on { border-style: solid; }
body.bg3 .condchip:hover { border-color: var(--gold); }

/* ── ① 상대의 적 이름 검색(시안 3a) ─────────────────────────────────────
   작은 검색 색인만 받고 거르는 일은 브라우저가 한다 — 정적 호스팅이라 `?q=` 를 못 쓴다. */
/* ① 의 검색·세부 조정 겹(`.foefold`) — 넓은 화면에선 늘 열려 있고 여닫는 줄이 없다(시안 3a 는 검색칸이
   보인다). 좁은 화면의 줄은 mobile.css 가 되살린다. 접기 선·여백도 여기선 없앤다. */
/* ⚠ `.calcfold` 의 규칙이 이 파일 **뒤쪽**에 있어 같은 특이성이면 진다 — 클래스 둘로 올린다(실측: 데스크톱에
   여닫는 줄이 그대로 보였다). */
.calcfold.foefold { margin: 0; border-top: 0; padding-top: 0; }
.calcfold.foefold > summary { display: none; }
.foesearch { margin: var(--sp-3) 0; }
.foesearch input {
  width: 100%; box-sizing: border-box; padding: 6px 8px;
  border: 1px solid var(--line); background: #100c08; color: var(--text); font: inherit;
}
.foelist { list-style: none; margin: var(--sp-1) 0 0; padding: 0; display: grid; gap: 2px; }
.foelist button {
  display: grid; grid-template-columns: 32px minmax(0, 1fr) auto; align-items: center; gap: var(--sp-2);
  width: 100%; padding: 4px 6px; font: inherit; font-size: var(--fs-sm); text-align: left;
  cursor: pointer; border: 1px solid var(--line); background: transparent; color: var(--text);
}
body.bg3 .foelist button:hover { border-color: var(--gold); }
.foelist .sub { font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.foelist .foe-result-name { min-width: 0; overflow-wrap: anywhere; }
.foelist .monster-portrait { --portrait-size: 32px; }

/* 초상화는 정사각형 칸을 미리 잡아 로딩 중에도 이름과 수치가 움직이지 않는다. */
.monster-portrait {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--portrait-size, 56px); height: var(--portrait-size, 56px); flex: none;
  overflow: hidden; box-sizing: border-box;
  background: var(--surface); border: 1px solid var(--line); border-radius: 3px;
}
.monster-portrait img { display: block; width: 100%; height: 100%; object-fit: contain; }
.monster-portrait.is-empty { color: var(--text-2); font-size: var(--fs-lg); }
@media (max-width: 620px) {
  .foelist button { grid-template-columns: 32px minmax(0, 1fr); column-gap: var(--sp-2); row-gap: 2px; }
  .foelist .monster-portrait { grid-row: span 2; }
  .foelist .sub { grid-column: 2; }
}

/* ── 명중 굴림 세그먼트(시안 3a) ─────────────────────────────────────────
   환경이지 덮어쓰기가 아니다 — `환경굴림적용` 주석 참고. */
.rollseg { display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-3) 0; }
.rollseg .k { font-size: var(--fs-xs); color: var(--muted); letter-spacing: .06em; white-space: nowrap; }
.segbtn {
  /* ⚠ 데스크톱은 32px 로 충분하고, 좁은 화면에서는 `mobile.css` 가 44px 로 되받는다
     (`.btn`·`.rcard` 와 같은 줄). 여기서 44 를 박으면 데스크톱 밀도가 깨진다. */
  flex: 1 1 0; min-height: 32px; padding: 4px 6px;
  font: inherit; font-size: var(--fs-sm); cursor: pointer;
  border: 1px solid var(--line); background: transparent; color: var(--text-2);
}
.segbtn.on { border-color: var(--gold); background: #2a2116; color: var(--text); }
body.bg3 .segbtn:hover { border-color: var(--gold); color: var(--text); }

/* ── ① 상대 카드의 머리와 프리셋 ──────────────────────────────────────── */
.simfoetop { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.simhp { flex: 1 1 auto; min-width: 0; text-align: right; }
.simhp .k { font-size: var(--fs-xs); color: var(--muted); letter-spacing: .06em; }
.simhp .v { margin-left: var(--sp-1); font-size: var(--fs-base); color: var(--text); font-variant-numeric: tabular-nums; }
.simhp .hpbar { display: block; height: 8px; margin-top: 4px; background: var(--line-2); border: 1px solid var(--line); }
.simhp .hpbar i { display: block; height: 100%; background: linear-gradient(90deg, var(--gold-lo), var(--gold)); }
/* 프리셋 넷 — 이름 아래에 그 난이도가 뜻하는 AC·생명력. 값은 `난이도값` 이 낸다. */
.targetpresets .preset { display: flex; flex-direction: column; align-items: center; gap: 1px; flex: 1 1 0; }
.targetpresets .preset .pname { font-size: var(--fs-sm); }
.targetpresets .preset .psub { font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
/* 지금 상대와 같은 프리셋은 굴림 세그먼트(`.segbtn.on`)와 같은 옷으로 고른 것임을 보인다(시안 3a). */
.targetpresets .preset.on { border-color: var(--gold); background: #2a2116; color: var(--text); }
/* 「직접 입력」 — 프리셋 넷과 나란히 서지만 값이 아니라 **문**이다(세부 조정을 연다).
   부제가 없어 한 줄이라, 넷과 같은 높이로 서도록 가운데에 세운다. */
.targetpresets .preset.manual { justify-content: center; color: var(--text-2); }

/* ── ② 계획의 라운드 카드 줄과 리본 ──────────────────────────────────────
   값은 엔진 보고의 것이다(`라운드카드줄`·`리본들` 주석 참고). */
.rcards { display: flex; flex-wrap: wrap; gap: 5px; margin: var(--sp-2) 0; }
.rcard {
  /* ⚠ **늘어나지 않는다.** `1 1` 이면 카드가 하나일 때 줄을 통째로 먹는다
     (실측 2026-09-15: 1라운드짜리 계획에서 카드가 전폭이 됐다). 시안은 96px 카드가
     나열되는 모양이라 **자라지 않고 줄지도 않게** 고정한다. */
  flex: 0 0 96px; min-width: 96px; min-height: 84px;
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-1);
  padding: var(--sp-2) 10px; border: 1px solid var(--line); background: #16110c80;
  color: var(--text-2); font: inherit; cursor: pointer; text-align: left;
}
.rcard.on { border-color: var(--gold); background: #2a2116; color: var(--text); }
body.bg3 .rcard:hover { border-color: var(--gold); }
.rcard.before { flex: 0 0 96px; }
.rcard.add, .rcard.del { flex: 0 0 36px; min-width: 36px; border-style: dashed; align-items: center; justify-content: center; font-size: var(--fs-lg); }
.rcard .rtop { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-1); }
.rcard .rn { font-size: var(--fs-sm); color: var(--muted); }
.rcard .rdmg { font-size: var(--fs-lg); color: var(--gold); font-variant-numeric: tabular-nums; }
.rcard .ricons { display: flex; gap: 3px; flex-wrap: wrap; min-height: 20px; }
.rcard .ricon { width: 20px; height: 20px; object-fit: contain; }
.rcard .ricon.blank { border: 1px solid var(--line-2); }
.rcard .rbot { display: flex; gap: 4px; align-items: center; }
/* 「행동 남음」 — 시안 3a 의 위험색 꼬리표. 핍 옆에 선다. */
.rcard .rleft { margin-left: auto; font-size: var(--fs-xs); color: var(--danger); white-space: nowrap; }
/* 자원 핍 — 행동 ● · 보조 ▲ · 대응 ★ (게임 자원 색을 따른다) */
.rpip { width: 8px; height: 8px; display: inline-block; }
.rpip.action { border-radius: 50%; background: #3f8f4a; }
.rpip.bonus { background: #d9822b; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.rpip.reaction { background: #c94f8a; clip-path: polygon(50% 0,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%); }
.rpip.used { background: var(--line); }

.ribbons { display: grid; gap: 3px; margin-bottom: var(--sp-3); }
/* ⚠ **격자다** — 띠(`.rbcell.band`)가 여러 라운드를 걸치려면 칸을 셀 수 있어야 한다.
   라운드 수는 `--rn` 으로 들어온다(화면이 트랙을 세지 않는다). */
.ribbon { display: grid; grid-template-columns: 96px repeat(var(--rn, 1), minmax(0, 1fr)); gap: 5px; align-items: stretch; }
.rblabel {
  padding: 4px 6px; font-size: var(--fs-sm); color: var(--text);
  background: #2a2116; border: 1px solid var(--gold-dim); border-right: 3px solid var(--gold);
}
.rbcell {
  grid-column: span var(--span, 1); min-width: 0; padding: 4px 6px; font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums; color: var(--text);
  border: 1px solid var(--gold-dim);
  /* 진하기가 곧 유지 확률이다 — 값은 `--p` 로 들어온다(화면이 안 곱한다). */
  background: rgba(200, 162, 76, calc(0.12 + 0.55 * var(--p, 0)));
}
.rbcell.weak { border-color: var(--danger); color: var(--danger); }
.rbcell.off { background: transparent; border-style: dashed; border-color: var(--line-2); }
/* 집중이 아닌 효과 — 걸려 있는 동안이 한 띠다(시안 3a 의 둘째 리본 꼴). */
.rbcell.band {
  background: linear-gradient(90deg, #3a2f14, #2a2116 60%, #1e1811);
  border-color: var(--gold-dim); color: var(--text);
}
/* 「n라운드에 깨진다면」(시안 3a) — 칸 오른쪽의 작은 단추, 깨진 뒤의 칸은 dashed 갈색.
   「없던 것」(.off, 흐린 선)과 「깨진 것」(.broken, 진한 갈색)을 옷으로 가른다. */
.rbcell { display: flex; align-items: center; justify-content: space-between; gap: 4px; }
.rbcell.broken { background: transparent; border-style: dashed; border-color: #5a3a2a; justify-content: flex-end; }
.rbcell .rbbtn {
  flex: none; padding: 0 4px; font-size: var(--fs-xs); letter-spacing: .04em; line-height: 1.5;
  /* 유지 확률이 높은 칸은 바탕이 금색이라 금색 글자가 묻힌다 — 본문색으로 두고 흐림만 준다. */
  color: var(--text); opacity: .7; border-color: transparent; background: none;
}
.rbcell .rbbtn:hover { opacity: 1; border-color: var(--gold-dim); }

/* ── 행동 줄 — 시안 3a 의 `명중 × 맞으면 = 기대 피해 · 전부 치명타면` ────────
   ⚠ **열 자리를 머리글과 줄이 나눠 쓴다.** 두 곳에 따로 적으면 조용히 어긋나므로
   변수 하나로 두고 둘 다 그것을 쓴다. */
.turnhead, .simplan .turnitem {
  --turncols: 40px minmax(0, 1fr) 64px 18px 72px 18px 84px 76px 28px;
}
/* 시안 4a — 켠 칩이 있으면 「칩으로 달라진 값」 열이 하나 는다. **칩이 없으면 열도 없다** —
   빈 열을 늘 붙이면 좁은 칸에서 자리만 먹는다. 머리글과 줄이 같은 변수를 쓰므로 한 곳만 고친다. */
.turnhead:has(.c-delta), .simplan .turnitem:has(.turndelta) {
  --turncols: 40px minmax(0, 1fr) 64px 18px 72px 18px 84px 76px 52px 28px;
}
.turnhead .c-delta { grid-column: 9; }
.simplan .turnitem .turndelta {
  grid-column: 9; grid-row: 1 / 3; text-align: right;
  font-size: var(--fs-sm); color: var(--gold); font-variant-numeric: tabular-nums;
}
.simplan .turnitem:has(.turndelta) .turnx { grid-column: 10; }
.turnhead {
  display: grid; grid-template-columns: var(--turncols); gap: 0 var(--sp-2);
  padding: 0 10px var(--sp-1); align-items: end;
}
.turnhead span { font-size: var(--fs-xs); color: var(--muted); letter-spacing: .06em; text-align: right; }
/* ⚠ **머리글 칸마다 규칙을 준다.** `span` 으로만 입히면 클래스 자체에는 규칙이
   없어 `tests/skin-coverage.test.js` 가 「껍데기 없는 클래스」로 문다 — 실제로
   물렸다(2026-09-15). 각 칸이 자기 열에 앉는 것도 여기서 못박아, 마크업 순서가
   바뀌어도 머리글과 줄이 같은 열을 쓴다. */
.turnhead .c-name { grid-column: 1 / 3; text-align: left; }
.turnhead .c-hit  { grid-column: 3; }
.turnhead .c-op   { grid-column: auto; }
.turnhead .c-onhit { grid-column: 5; }
.turnhead .c-dmg  { grid-column: 7; }
.turnhead .c-crit { grid-column: 8; }
.turnhead .c-x    { grid-column: 9; }
/* 적 여럿의 줄(시안 4b) — 「전부 치명타면」 칸 자리에 「공격 대상」 고르기가 선다. 머리글과 줄이 같은
   변수를 쓴다(위 `--turncols` 와 같은 이유). */
.turnhead.mthead, .simplan .turnitem.mtitem {
  --turncols: 40px minmax(0, 1fr) 64px 18px 72px 18px 84px minmax(0, 150px) 28px;
}
.turnhead .c-target { grid-column: 8; text-align: left; }
.simplan .turnitem .mttarget {
  grid-column: 8; grid-row: 1 / 3; display: flex; flex-direction: column; gap: 2px;
  font-size: var(--fs-xs); color: var(--muted);
}
.simplan .turnitem .mttarget select { width: 100%; min-width: 0; }
/* 실행 확률 — 처치 보상에 걸린 후속 행동은 100% 가 아니다. 100% 면 안 적는다. */
.simplan .turnitem .mtexec { margin-left: var(--sp-1); font-size: var(--fs-xs); color: var(--danger); }
.mtarea { border: 1px dashed var(--line); padding: var(--sp-2) var(--sp-3); }
/* ⚠ **옛 `.turnitem` 은 2행 격자다**(`grid-template-rows: auto auto`) — 이름 아래에
   비용 핍이 서고 `.frame` 이 두 행을 걸친다. 열만 바꾸면 **숫자 칸들이 둘째 행으로
   흘러내린다**(실측 2026-09-15: 기대 피해가 왼쪽에, 치명이 아래로 밀렸다).
   그래서 **자리를 하나씩 박는다** — 이름·비용은 둘째 열에 2행으로 쌓고, 수치 칸은
   두 행을 걸쳐 세로 가운데에 선다. 시안 3a 의 줄 모양이 그것이다. */
.simplan .turnitem {
  display: grid; grid-template-columns: var(--turncols);
  grid-template-rows: auto auto; gap: 0 var(--sp-2);
  align-items: center; text-align: left; width: 100%;
}
.simplan .turnitem .frame     { grid-column: 1; grid-row: 1 / 3; }
.simplan .turnitem .turnname  { grid-column: 2; grid-row: 1; align-self: end; }
.simplan .turnitem .turncost  { grid-column: 2; grid-row: 2; align-self: start; }
.simplan .turnitem .turnhit   { grid-column: 3; grid-row: 1 / 3; }
.simplan .turnitem .op1       { grid-column: 4; grid-row: 1 / 3; }
.simplan .turnitem .turnonhit { grid-column: 5; grid-row: 1 / 3; }
.simplan .turnitem .op2       { grid-column: 6; grid-row: 1 / 3; }
.simplan .turnitem .turndmg   { grid-column: 7; grid-row: 1 / 3; }
.simplan .turnitem .turncrit  { grid-column: 8; grid-row: 1 / 3; }
.simplan .turnitem .turnx     { grid-column: 9; grid-row: 1 / 3; }
/* 범위 문장은 둘째 줄(비용 핍 옆)로 들어온다 — 옛 자리(줄 밖 블록)의 들여쓰기는 안 쓴다. */
.simplan .turnitem .turnrange { display: inline; padding: 0; }
/* 명중·맞으면은 단추다(시안 3a) — 점선 밑줄, 누르면 그 줄 아래 식이 펼쳐진다. 열린 줄은 실선. */
button.turnhit, button.turnonhit {
  font: inherit; background: none; border: 0; padding: 0; cursor: pointer;
  justify-self: end; border-bottom: 1px dotted var(--gold-dim); border-radius: 0;
}
button.turnhit:hover, button.turnonhit:hover { border-bottom-color: var(--gold); color: var(--gold); }
button.turnhit[aria-expanded="true"], button.turnonhit[aria-expanded="true"] { border-bottom: 1px solid var(--gold); }
/* ✕ — 시안의 28px 마지막 열. 줄 전체가 단추이던 옛 꼴을 대신한다. */
.turnx {
  font: inherit; font-size: var(--fs-lg); line-height: 1; background: none; border: 0;
  padding: 0 4px; cursor: pointer; color: var(--text-2); justify-self: end;
}
.turnx:hover { color: var(--danger); }
/* 둘째 줄의 굴림 배지 — 「유리 (복수의 맹세 → 유리)」 */
.turnroll { font-size: var(--fs-xs); color: var(--text-2); letter-spacing: .02em; }
.turnroll.advantage { color: var(--gold); }
.turnroll.disadvantage { color: var(--danger); }
.term.fexpect { font-variant-numeric: tabular-nums; }
.turnhit, .turnonhit, .turncrit { text-align: right; font-variant-numeric: tabular-nums; }
/* 시안 3a 의 줄에서 제일 먼저 읽히는 두 수다 — 본문보다 확실히 크게 둔다. */
.turnhit, .turnonhit { font-size: var(--fs-num-md); color: var(--text); }
.turnop { text-align: center; font-size: var(--fs-xs); color: var(--muted); }
.turncrit { font-size: var(--fs-lg); color: var(--text-2); }
.simplan .turnitem .turndmg { text-align: right; font-size: var(--fs-h); color: var(--gold); }

/* ── ③ 결과 카드의 머리와 표 ────────────────────────────────────────────
   값은 전부 엔진 보고에서 온다(`결과머리`·`결과라운드표` 주석 참고). */
.simkill { margin: 0 0 var(--sp-2); font-size: var(--fs-base); color: var(--text); }
.simtotal { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.simtotal .k { font-size: var(--fs-xs); color: var(--muted); letter-spacing: .06em; }
.simtotal .v { font-size: var(--fs-num-lg); color: var(--gold); }
.simtotal .crit { font-size: var(--fs-xs); color: var(--muted); }
.simtotal .crit b { font-weight: 400; color: var(--text-2); }
/* 시안 4a — 「켠 조건 없이 x · 차이 +N」. 총합 바로 밑에 붙어 그 수가 어디서 왔는지 말한다. */
.simwithout { margin: calc(var(--sp-3) * -1) 0 var(--sp-3); font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; }

.simrtable { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
/* ③ 대상별 요약(시안 4b) — 한 칸에 누적 · 남음 · 잡을 확률 막대. 적이 셋 이상이면 칸이 좁아
   `.combat-target-table` 이 옆으로 민다(좁은 화면 규칙은 mobile.css). */
/* ① 적 카드(시안 4b) — 카드 전체가 「불러오기」 단추다. */
.mtfoes { display: grid; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.mtcards { display: grid; gap: 6px; }
.mtcard {
  display: grid; gap: 6px; width: 100%; padding: 10px 14px; text-align: left; font: inherit; cursor: pointer;
  color: var(--text); background: #16110c; border: 1px solid var(--gold-dim);
}
body.bg3 .mtcard:hover { border-color: var(--gold); }
.mtcard .mtname { font-size: var(--fs-base); letter-spacing: .06em; }
.mtcard .mtbody { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; align-items: end; }
.mtcard .mtac .k { display: block; font-size: var(--fs-xs); color: var(--muted); letter-spacing: .08em; }
.mtcard .mtac .v { font-size: var(--fs-hh); line-height: 1; font-variant-numeric: tabular-nums; }
.mtcard .mthp { display: block; min-width: 0; }
.mtcard .mthpline { display: flex; justify-content: space-between; gap: var(--sp-1); font-size: var(--fs-xs); color: var(--muted); }
.mtcard .mtafter { color: var(--text); font-variant-numeric: tabular-nums; }
.mtcard .mtbar { position: relative; display: block; height: 8px; margin-top: 4px; background: var(--line-2); border: 1px solid var(--line); }
.mtcard .mtbar i { position: absolute; left: 0; top: 0; bottom: 0; display: block; }
/* 어두운 = 지금 체력(깎일 몫 포함) · 밝은 = 기대로 남는 체력. 밝은 것이 위에 겹친다. */
.mtcard .mtbar i.now { background: #5a3a2a; }
.mtcard .mtbar i.left { background: linear-gradient(90deg, var(--gold-lo), var(--gold)); }
.mtcard .mtkill { font-size: var(--fs-sm); color: var(--text); }
.mtadd { border-style: dashed; }
.mtresult { margin: 0 0 var(--sp-3); }
/* ⚠ `.simrtable` 을 **물려받지 않는다.** 그 표는 「마지막 칸만 flex」(막대 한 줄)라, 적 칸이 여럿인
   이 표에 섞으면 마지막 적 칸만 가로로 흘러 막대가 옆 칸으로 넘어가 보였다(실측 2026-09-16,
   306px 열). 칸마다 누적 · 남음 · 「막대 + 확률」 세 줄을 똑같이 쌓는다. */
.mttable { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); table-layout: fixed; }
.mttable th {
  padding: 2px 4px; text-align: left; font-weight: 400; font-size: var(--fs-xs); color: var(--muted);
  border-bottom: 1px solid var(--line); overflow-wrap: anywhere;
}
.mttable th:first-child, .mttable td:first-child { width: 28px; }
.mttable td { padding: 4px; vertical-align: top; color: var(--text-2); border-bottom: 1px solid var(--line-2); }
.mttable .mtcum { display: block; color: var(--text); font-variant-numeric: tabular-nums; }
.mttable .mtleft { display: block; font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.mttable .mtkill { display: flex; align-items: center; gap: var(--sp-1); margin-top: 2px; }
.mttable .pct { min-width: 34px; text-align: right; font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.simrtable th {
  font-size: var(--fs-xs); color: var(--muted); font-weight: 400;
  text-align: right; padding: 2px 4px; border-bottom: 1px solid var(--line);
}
.simrtable th:first-child, .simrtable td:first-child { text-align: left; }
.simrtable td { padding: 3px 4px; text-align: right; color: var(--text-2); }
.simrtable tr.on td { color: var(--text); background: #2a211680; }
/* 「여기까지 잡을 확률」 — 막대와 값이 한 칸에 같이 선다. */
.simrtable td:last-child { display: flex; align-items: center; gap: var(--sp-1); justify-content: flex-end; }
.simbar { flex: 1 1 auto; min-width: 28px; height: 6px; background: var(--line-2); border: 1px solid var(--line); }
.simbar i { display: block; height: 100%; background: linear-gradient(90deg, var(--gold-lo), var(--gold)); }
.simrtable .pct { min-width: 34px; text-align: right; }

/* ── 계산 탭 ── */
/* ⚠ 여백은 **4의 배수 하나**로 간다(`--sp-*`). 제보 「너무 몰려 있다」의 실측은
   padding 3·4·5·6px 이 지배한다는 것이었다 — 줄 높이와 절 사이를 벌리되
   **칸 수는 안 줄인다**(밀도는 이 화면의 값이다). */
.calcgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--sp-3); margin: var(--sp-4) 0; }
.calcstat {
  display: flex; flex-direction: column; gap: 2px; align-items: center;
  padding: var(--sp-3) var(--sp-2); border: 1px solid var(--line); background: #16110c80;
}
.calcstat .k {
  font-size: 11px; color: var(--muted); letter-spacing: .06em;
  margin-bottom: 2px; display: block;
}
.calcstat .v {
  font-size: var(--fs-h); color: var(--cream); font-variant-numeric: tabular-nums;
  line-height: 1.25;
}
/* 방어 칸(2026-09-03) — 숫자가 아니라 글이라 한 줄을 다 쓰고 글자도 본문 크기다. */
.calcstat.wide { grid-column: 1 / -1; }
.calcstat .v.txt { font-size: var(--fs-base); font-family: inherit; line-height: 1.5; text-align: center; }

/* ── 행동 경제 ──
   아이콘은 게임 자산 그대로다(web/skin/res_*.png) — 행동은 녹색 원, 보조 행동은
   주황 삼각형, 대응은 분홍 별. 색으로 구분되는 그림이라 우리가 색을 덧입히지 않는다. */
.combat-rules { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
.combat-rules > .hint { flex-basis: 100%; margin: 0; }
.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; }
.formtoggle select { min-width: 0; max-width: 100%; flex: 0 1 auto; }

/* ── 이 턴 ── */
.turnslots { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
.turnitem {
  font: inherit; 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);
}
/* 줄 자체가 단추인 것은 대상별 계획(`combat-targets.js`)의 옛 꼴뿐이다 — 계산 탭의 줄은
   `<div>` 고 지우기는 ✕(`.turnx`), 식 펼치기는 명중·맞으면 단추가 맡는다(시안 3a). */
button.turnitem { cursor: pointer; }
.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; }
/* 대상별 계획의 이름만 있는 버튼은 아이콘용 40px 열에 글을 가두지 않는다. */
.turnitem:has(> .turnname:only-child) { display: block; max-width: 100%; min-height: var(--m-touch, 44px); }
.turncost { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
/* .gatkdmg(「내 빌드」 공격 카드의 수)도 같은 옷이다 — 두 화면이 같은 카드를 그린다. */
.turndmg, .gatkdmg {
  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 {
  /* ⚠ **`box-sizing` 과 `min-width` 는 한 짝이다.** 둘 중 하나만 고치면 안 낫는다.
     `build.html` 에는 `* { box-sizing: border-box }` 가 없다(그 규칙은 style.css
     에만 있고 items.html 만 싣는다 — 아래 input[type=checkbox] 주석 참고). 그래서
     이 상자는 content-box 였고, `min-width: 280px` 이 실제로 요구한 것은
     **280 + 안여백 20 + 테두리 2 = 302px** 이었다.

     실측 2026-08-29 — 320px 뷰포트, 진짜 `/build` 의 `#panel`(안쪽 280px) 안:

         고정 280px             오른끝 322 > 320   넘침 2개 (.turnrow · .formula)
         min(280px,100%) 만     오른끝 322 > 320   넘침 1개 (.formula)   ← **여전히 샌다**
         min(…) + border-box    오른끝 320 = 320   넘침 0

     재는 법(사람 손 없이 돈다):

         node tools/mobile-measure.mjs --폭 320,360,390,430 --마크업 '<div class="turnslots">…' /build

     ⚠ **가운뎃줄이 이 자리의 함정이다.** 원장(2026-08-29 「남은 것」①)에 적혀
     있던 고침이 `min(280px, 100%)` 하나였는데, content-box 에서는 `100%` 가
     **안여백 밖**이라 상자는 그대로 302px 을 요구한다. 넘친 **요소 수**는 2에서
     1로 줄지만 **오른끝은 322 그대로** — 「나아졌다」로 읽으면 안 되는 자리다.
     개수만 세는 그물이 여기서 눈이 먼다.

     ⚠ 360px 이상에서는 셋 다 넘침 0 이라 **넓은 화면만 보면 고쳤는지 아닌지를
     구별할 수 없다.** 반드시 320 을 같이 잰다.

     ⚠ 마크업을 줄여서 재면 안 된다 — 「수식 접기」 단추를 뺀 마크업으로 쟀더니
     ②가 넘침 0 으로 나왔다(실측). 셋은 **같은 마크업**으로 견준다. */
  box-sizing: border-box;
  flex-basis: 100%; min-width: min(280px, 100%); 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; }
/* ⚠ 크기는 여기서 안 정한다 — 위 `body.bg3 .flabel`(구체성 한 칸 위)이 쥔다.
   여기 `font-size: 11px` 이 남아 있었는데 어차피 지던 **죽은 선언**이라 걷었다. */
.flabel { min-width: 3em; color: var(--gold-dim); letter-spacing: .08em; }
/* 상태 셋. 적용은 보통 글자색(--cream), 미정은 조건 토글의 체크박스 accent-color
   와 같은 --gold-dim(같은 개념이니 같은 옷 — 위 .conds input 참고), 미구현은
   다른 흐린 글자들과 같은 읽기용 토큰(흐리게). */
/* 수식 항(`+7`·`1d8+4`·`19~26`). 줄마다 세로로 견주는 자리라 자릿수를 고정한다. */
.term { color: var(--cream); font-variant-numeric: tabular-nums; }
.term.pending { color: var(--gold-dim); }
.term.unread { color: var(--faint-readable); }

/* 미정 항을 눌러 목표 성질 절(.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%;
  /* ⚠ 틀 그림은 상자에 맞춰 **늘어난다**(100% 100%) — 그림 속 테두리 선도 같이 두꺼워져서, 폭 1,308px 이면
     왼쪽 선이 안쪽으로 16px 들어온다. 안여백이 12px 고정이면 첫 열 아이콘이 그 선 위에 앉아 「칸이 틀 밖으로
     빠져나간」 것처럼 보인다(2026-09-14 사용자 제보 · 운영 게시판 글 1,920px 실측). 좌우 안여백을 폭에 비례
     (1.6% ≈ 선 1.2% + 여유)시키고 12px 를 바닥으로 둔다 — 좁은 화면은 그대로다. 위는 12px(높이 333px 까지
     선 3.6% 를 덮는다). 정확히 하려면 border-image 슬라이스가 맞지만 그건 틀의 모양을 바꾸는 일이라 따로. */
  padding: 12px max(12px, 1.6%) 0;
  border: 1px solid var(--line);
}
.hbslots {
  display: grid; grid-template-columns: repeat(auto-fill, var(--hb-cell)); gap: 4px;
  min-height: 46px;
}
.hbslot {
  position: relative; width: var(--hb-icon); height: var(--hb-icon); 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); }
/* 턴 줄에서 「주는 것」. 먹는 것과 **부호가 반대**라 색으로 가른다 — 같은 옷을
   입히면 「행동」 옆에 「행동 +1」이 나란히 서서 한 덩어리로 읽힌다(눈가림 검수).
   ⚠ 새 색을 만들지 않는다 — `--accent` 는 두 판(어두운·밝은)에 다 정의돼 있고
   대비가 이미 재진 값이다. 초록을 새로 들이면 이 껍데기의 금빛 규약이 깨진다. */
.respip.respipgain { color: var(--accent); }
/* 못 쓰는 칸은 게임처럼 죽인다. 이유는 title(hover)과 data-hint(길게 누르기) 양쪽에
   있다 — title 한 곳에만 두면 터치에서 통째로 사라진다(2026-08-16). */
.hbslot.off { cursor: not-allowed; }
.hbslot.off .hbart img { filter: grayscale(1) brightness(.5); }

/* 핫바 칸에 담기 단추를 얹으려면 격자 칸(hbslots 의 grid item)이 하나로 남아야
   한다 — hbslot 단추 옆에 형제로 그냥 붙이면 격자 칸이 늘어나 정렬이 밀린다.
   이 얇은 래퍼가 격자 칸을 그대로 하나로 유지한다. */
.hbslotwrap { position: relative; width: var(--hb-cell); height: var(--hb-icon); }
/* 아이콘 상자는 칸 안에서 가운데 선다 — 칸이 아이콘보다 넓어졌다(64 vs 46). */
.hbslot { margin: 0 auto; }
/* ── 칸 아래의 값 줄(시안 3a) ─────────────────────────────────────────────
   「누르면 이 턴에 얼마가 붙나」를 칸마다 보인다. 값은 `핫바값`(정본
   `expectedFor`)에서 오고, 피해가 없거나 못 읽은 칸에는 **아무것도 안 적는다**.

   ⚠ **칸 폭은 46px 그대로다.** 시안은 64px 열이지만 그 수는 `.hbcast`·`.hbsustain`
   의 폭과 `calc(46px + …)` 높이 여러 곳에 퍼져 있어 한 번에 옮기면 파급이 크다.
   값 줄이 주는 이득(칸마다 수가 보인다)은 46px 안에서도 그대로라 먼저 넣는다 —
   폭 확장은 `tests/hotbar-grid.test.js` 의 리터럴을 같이 옮겨야 하는 별개 작업이다.

   ⚠ **세로 안여백으로 자리를 만든다**(`.hbsustain` 과 같은 처방). 격자 그물이 막는
   것은 **가로** 안여백이다 — 그것이 칸 폭을 넓혀 열을 깨뜨리기 때문이다. */
.hbslotwrap:has(> .hbval) { box-sizing: content-box; padding-bottom: calc(var(--hbval-h) + 2px); }
.hbval {
  position: absolute; left: 0; bottom: 0; width: var(--hb-cell); height: var(--hbval-h);
  font-size: var(--fs-micro); line-height: var(--hbval-h); text-align: center;
  color: var(--gold); font-variant-numeric: tabular-nums;
  overflow: hidden; white-space: nowrap;
}
/* 피해가 아닌 효과 글자(「유리」 등, §4 ⑤) — 금색은 「이 칸의 기대 피해」라는 뜻이라
   숫자가 아닌 글자에 쓰면 값처럼 읽힌다. 옅은 색으로 가른다. */
.hbval.hbeffect { color: var(--muted); font-variant-numeric: normal; }
/* 유지 추가는 주문 실행·슬롯 선택 아래에 독립된 공간을 갖는다. */
.hbslotwrap:has(> .hbsustain) {
  /* 「＋ 유지」 높이 = 시전 레벨 고르기 높이(`--hbcast-h` 15px). 28px 이던 것을 사용자가 「너무 크다」고
     해서 낮췄다(2026-09-14). 모바일은 mobile.css 가 `--m-touch`(44px)로 다시 올린다 — 터치 대상이라서. */
  --hbsustain-h: 15px;
  box-sizing: content-box;
  padding-bottom: calc(var(--hbsustain-h) + 4px);
}
/* 상위 슬롯을 고르는 칸은 버튼 아래에 둔다. select 를 버튼 안에 넣으면 HTML도
   깨지고, 버튼을 누른 것과 슬롯을 고른 것이 한 이벤트로 섞인다. */
/* ⚠ **높이는 변수 하나가 정한다.** 칸 높이(`.hascast`)·자리(`.hbcast`)·컨트롤
   (`select`) 셋이 같이 움직여야 하는데, 셋을 따로 적으면 모바일에서 글자만 커져
   상자를 넘는다 — 실제로 그럴 뻔했다(모바일은 iOS 확대를 막으려고 글자를 16px 로
   되받는다, `mobile.css`). **한 자리에서 정하고 나머지는 그것을 읽는다.**
   ⚠ 변수를 `.hbcast`(자식)에 걸면 안 된다 — CSS 변수는 아래로만 상속하므로 높이를
     읽는 부모 `.hbslotwrap.hascast` 가 못 본다. 처음에 그렇게 짰다가 걸렸다. */
.hbslotwrap.hascast { height: calc(var(--hb-icon) + 2px + var(--hbcast-h)); }
/* 변형 고르기가 있으면 한 줄 더 쓴다. 둘 다 있으면 두 줄이다. */
.hbslotwrap.hasmeta { height: calc(var(--hb-icon) + 4px + var(--hbcast-h) * 2); }
.hbcast {
  position: absolute; left: 0; top: calc(var(--hb-icon) + 2px); width: var(--hb-cell); height: var(--hbcast-h);
  margin: 0; padding: 0;
}
/* 변형 마법 고르기. **`.hbcast` 의 옷을 그대로 입는다**(마크업이 두 클래스를 같이
   단다) — 치수·글자 크기·좁은 화면 되받기를 새로 적지 않는다. 두 벌이 되면 한쪽만
   고쳐졌을 때 조용히 갈리고, 실제로 처음에 `font-size: 9px` 를 손으로 적었다가
   그물 둘에 걸렸다(16px 미만 입력칸 · `--fs-*` 정본). 여기서는 **자리만** 내린다. */
.hbmeta { top: calc(48px + var(--hbcast-h) + 2px); }
/* ⚠ **공통 `select` 옷(난이도 고르개)을 그대로 쓰면 이 자리에선 뚱뚱하다.**
   그쪽은 한 줄에 홀로 서는 컨트롤이라 굵은 금테가 맞지만, 여기는 46px 칸 **아래
   딸린 값**이라 칸보다 먼저 눈에 들어오면 안 된다. 선을 1px·낮은 투명도로 낮추고
   화살표도 4px 로 줄인다(공통은 5px + padding-right 26px 이라 46px 안에서 절반을
   먹는다). 누를 수 있다는 신호는 남긴다 — 테두리를 아예 없애 보니 그게 약했다. */
.hbcast select {
  /* 테두리까지 `--hbcast-h` 안에 넣고(border-box) 줄상자 기준선 여백을 없앤다(block) — 안 그러면
     15px 칸에 17px 상자가 앉아 칸 바닥을 3px 삐져나온다(헤드리스 실측 2026-09-14). */
  box-sizing: border-box; display: block;
  width: var(--hb-cell); height: var(--hbcast-h); padding: 0 13px 0 3px;
  font-size: var(--fs-xs); line-height: var(--hbcast-h);
  border: 1px solid rgba(200, 162, 76, 0.26); border-radius: 2px;
  background-color: rgba(13, 10, 7, 0.85); color: var(--gold-dim);
  background-position: right 5px center, right 1px center;
  background-size: 4px 4px;
}
.hbcast select:hover { border-color: rgba(200, 162, 76, 0.55); color: var(--gold); }
/* 세부 효과 고르기가 달린 칸. 효과·레벨·변형 고르기와 「＋ 유지」를 **칸 폭 46px 안에**
   차례로 쌓는다(절대배치 대신 flex 열 — 셋이 어느 조합으로 와도 자리를 손으로 안 센다).
   ⚠⚠ **칸 폭을 넘기지 않는다.** #143(2026-09-09) 이 여기에 `grid-column: span 3` 과
   `width: 100%` 를 걸어 「이름을 읽을 공간」을 냈는데, 그 칸이 세 열을 먹고 아이콘은
   가운데 앉아 「빈칸·아이콘·빈칸」으로 보였고, 줄 끝에 세 열이 안 남으면 통째로 다음
   줄로 내려가 그 줄 끝이 비었다 — 스크린샷 한 장에 그림 없는 칸 14개(실측 2026-09-13).
   mobile.css 가 같은 자리에서 두 번 틀린 기록을 적어 뒀는데 주석이라 아무것도 안 막았다.
   지금은 `tests/hotbar-grid.test.js` 가 문다. 긴 이름은 아래 줄임표와 title 로 읽는다. */
.hbslotwrap.haseffect {
  height: auto;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.hbslotwrap.haseffect:has(> .hbsustain) { padding-bottom: 0; }
.haseffect > .hbcast { position: static; width: 100%; height: auto; }
/* 「＋ 유지」는 높이를 지킨다(`--hbsustain-h`: 28px · 모바일 44px). #143 은 여기에 height: auto 를
   걸어 모바일 터치 대상이 12px 로 줄었다 — 소스만 보는 44px 그물이 못 본 자리(눈가림 검수 M-3). */
.haseffect > .hbsustain { position: static; width: 100%; }
.haseffect > .hbcast select { width: 100%; }
/* 세부 효과 이름은 46px 에 안 들어간다(「치유의 손길: 하급 치유」). 잘리는 것을 숨기지
   않고 줄임표로 드러내고, 온 이름은 select 의 title(hover)·data-hint(길게 누르기)와 펼친 목록에서 읽는다 —
   크롬은 select 에도 text-overflow 를 찍는다(헤드리스 실측 2026-09-13: 「치유…」). */
.hbeffect select { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
/* 주문 실행과 다른 기능이므로 아이콘 위에 겹치지 않는 별도 단추로 둔다. */
.hbsustain {
  position: absolute; right: 0; bottom: 0; width: var(--hb-cell); height: var(--hbsustain-h); padding: 0;
  box-sizing: border-box; /* 테두리까지 변수 안에 — 15px 에 17px 상자가 앉지 않게(select 와 같은 처방) */
  font: inherit; font-size: var(--fs-xs); line-height: 1; text-align: center; cursor: pointer;
  border: 1px solid var(--gold-dim); border-radius: 3px; 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: '▾'; }
/* ⚠ **구체성으로 못박는다 — 순서에 기대면 또 죽는다** (2026-08-24).
   `body.bg3 .sub` 가 (0,2,1) 이고 이 규칙은 (0,2,1) 이라 **순서가 승자를 가른다.**
   개편 1차가 같은 선언을 파일 끝에 얹어 두던 동안 이 hover 는 122자리에서
   **아무 일도 안 했다** — 눌러도 색이 안 변했다. 접기로 되살아났지만 그때는
   「지금 순서가 이래서」였다. 한 칸 올려 자리와 무관하게 이기게 한다. */
body.bg3 .calcfold > summary:hover { color: var(--gold); }
.calcfold > summary:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.foldsum { color: var(--faint-readable); font-size: 11px; letter-spacing: 0; }

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

/* 난이도 프리셋 단추 줄 — 목표 설정 맨 위. 값은 `web/lib/target.js` 가 실제 적
   분포에서 낸다(여기서 숫자를 적지 않는다).
   ⚠ **줄바꿈을 허용한다** — 320px 에서 네 단추가 한 줄에 안 들어간다. 안 감싸면
   가로 넘침이 난다(이 저장소가 `.formula`·`.cx-index` 에서 이미 데인 자리). */
.targetpresets {
  display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-2);
}
.targetpresets .btn { flex: 0 1 auto; }

/* 적의 공격 프로필(2026-09-03) — 목록 한 줄 + 적기 폼. 폼 칸은 세로 라벨이라 좁은
   화면에서도 줄바꿈으로 흘러내린다. 단추는 .btn 이라 44px 목록에 이미 든다. */
/* 라운드 표 — 쓰러진 뒤 라운드는 회색(2026-09-03). */
.plantable tr.fallen td { color: var(--muted); }
.enemyattacks { list-style: none; margin: 0 0 var(--sp-2); padding: 0; display: flex; flex-direction: column; gap: 4px; }
.enemyattack { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); }
.enemyattack.unread { color: var(--muted); }
.enemyform { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: flex-end; margin: var(--sp-2) 0; }
.ef { display: inline-flex; flex-direction: column; gap: 2px; font-size: var(--fs-xs); color: var(--muted); }
/* 행동 줄 아래의 「목표까지 거리(m)」 — 줄 하나로 오른쪽에 붙인다(시안 3a 의 줄은 한 덩어리다). 값·이름은
   그대로고 모양만 눕혔다(2026-09-17). */
.turnrow > .ef { display: flex; flex-direction: row; align-items: center; justify-content: flex-end; gap: 6px; margin: 2px 0 6px; }
.turnrow > .ef input { width: 5em; padding: 1px 4px; font-size: var(--fs-xs); }
.ef input, .ef select { width: 7.5em; }
.ef select[data-ef="roll"] { width: 11em; }

/* ── 미끄럼 막대 ── 금장 프레임 한복판에 회색 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; }
/* 켜도 위 숫자가 안 움직이는 줄. **흐리게 두되 감추지 않는다** — 감추면 「없는 것」이
   되고, 사용자는 켜 보고 나서야 헛돈다는 걸 안다(위 .effunread 와 같은 규칙). */
.conds .notreached { color: var(--faint-readable); font-size: 11px; font-style: italic; }
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;
    /* ⚠ 44 를 손으로 적지 않는다 — 정본은 mobile.css:21 의 `--m-touch` 다.
       리터럴로 적혀 있어서 「누른다고 선언한 자리에 44px 이 걸렸나」 그물이 이 자리를
       **못 보고 지나갔다**(2026-08-16). 값은 맞았는데 정본을 안 써서 안 세어진 것이라,
       그물을 느슨하게 하는 대신 이쪽을 정본에 맞춘다. 되돌리면 그물이 문다(실측). */
    cursor: pointer; min-height: var(--m-touch);
    pointer-events: auto;      /* 모바일에서만 누를 수 있다 */
  }
  /* 모바일에서는 **펴진 절에도** 표식을 둔다 — 접을 수 있다는 것을 알려야 누른다. */
  .gfold[open] > summary::after { content: '▾'; margin-left: auto; color: var(--gold-dim); }
}

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

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

   자리마다 안 고치고 전역으로 두는 이유: 체크박스가 items.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 에만 있고 items.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; }
/* ⚠ **자릿수 고정이 빠져 있었다**(2026-08-24). 이 표가 앱의 유일한 <table> 이고
   조합마다 「턴당 12.3」·「AC 15」 가 세로로 쌓여 견주는 자리인데, 우측 정렬만 있고
   tabular-nums 가 없어 숫자 폭이 글자마다 달랐다 — 소수점이 어긋난다.
   보고서 §4.3 이 둘을 **한 쌍**으로 권고하는 까닭이 이것이다. */
.setcmp .v { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* 「못 읽은 항」·「없는 수단」은 값이 낮은 이유라 값 옆에 둔다 — 안 보이면
   사용자가 장비 탓으로 읽는다(equipment-sets.js 머리말). */
.setcmp .note { color: var(--warn); font-size: 11px; }

/* ── 장비 조합(세트) 줄 ── */
/* 계산 탭의 「조합 비교」가 이 조합들을 견준다. 만드는 자리가 없으면 그 절은
   영영 안 뜬다(equipment.js 의 조합줄 머리말). */
.setbar { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; margin: var(--sp-2) 0 var(--sp-3); }
.setbar .setlabel { color: var(--text-2); font-size: var(--fs-sm); }
/* ⚠ 여기 있던 `font-size: 11px` 은 전역 `body.bg3 .hint`(구체성 (0,2,1))에 지던
   **죽은 선언**이라 뗐다. 화면은 11 → 12px 로 **바뀐다** — 이 절의 글자 바닥
   올리기가 하는 일이 그것이다.
   ⚠ 첫 판 주석에 「같은 12px 이라 화면은 안 바뀐다」고 적었는데 **틀렸다**(뗀 값은
   11px 이었다). 「안 바뀐다」는 말은 검증을 건너뛰게 만드니 정정해 둔다. */
.setbar .hint { color: var(--text-2); }
.setchip {
  font: inherit; font-size: var(--fs-sm); padding: 3px var(--sp-3); cursor: pointer;
  color: var(--text-2); background: #16110c80; border: 1px solid var(--line);
}
.setchip:hover { color: var(--text); }
/* 지금 낀 조합. 「어느 것을 보고 있나」가 이 줄에서 제일 먼저 읽혀야 한다. */
.setchip.on { color: var(--accent); border-color: var(--accent-quiet); }
.setchip.add { color: var(--text-3); }
.setchip.del { color: var(--text-2); }

/* 라운드 계획(2026-09-02) — 라운드 줄과 라운드 표. 턴 칸(.turnslots) 위·아래에 앉는다.
   라운드가 하나면 줄만 늘고 표는 안 그린다. */
.roundtabs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: var(--sp-3) 0 var(--sp-2); }
.roundtabs .k { font-size: var(--fs-sm); color: var(--muted); }
.roundtab { min-width: 2.2em; padding: 2px 8px; border: 1px solid var(--line); border-radius: 4px;
  background: transparent; color: inherit; cursor: pointer; font: inherit; }
.roundtab.on { border-color: var(--gold); font-weight: 600; }
.roundtab.add, .roundtab.del { color: var(--muted); }
.plantable { width: 100%; border-collapse: collapse; margin: var(--sp-3) 0; font-size: var(--fs-sm); }
.plantable th, .plantable td { text-align: left; padding: 4px 6px; border-bottom: 1px solid var(--line-2); vertical-align: top; }
.plantable th { color: var(--muted); font-weight: 500; }
.plantable tr.on td { border-bottom-color: var(--gold); }
.plantable tr.notice td { color: var(--muted); }
.plantable .dim { color: var(--muted); }
.turnitem.off { opacity: .55; }
.turnblocked { font-size: var(--fs-sm); color: var(--muted); }
.sustainlist li.off { opacity: .55; }
.roundtab.before { font-size: var(--fs-sm); color: var(--muted); }
/* 고정 탭 막대 뒤로 숨지 않게 — 「전투 전」 칩이 유지 칸으로 데려갈 때와 같은 여백 */
.roundtabs, .sustain { scroll-margin-top: 200px; }
