/*
 * 이 사이트가 스킨에 더하는 규칙 전부. `site.stylesheet` 로 실린다 —
 * 코어 테마 → 스킨 시트들 → 이 파일 순서다(`packages/core/src/routes/render.ts:39`).
 *
 * site `AGENTS.md` 규칙 6: 스킨 시트를 복사해 오지 않는다. 여기 있는 것은 스킨이 모르는 플러그인
 * 마크업과, 운영 화면에 맞추려고 스킨 기본값을 덮는 자리뿐이다.
 *
 * 규칙은 스킨 토큰을 그대로 쓴다(`--board-*`). 보드 스킨은 `replacesTheme` 라 `--gb-*` 는 안 실린다.
 *
 * 스킨 규칙은 복사하지 않지만 **토큰 값**은 아래 블록에서 다시 선언한다(엔진 `docs/skin-api.md` §3n).
 * 노리터의 색·면을 보드 스킨에 입히는 자리는 이 블록 하나다. 값은 레거시에서 왔다.
 * 밝은 쪽은 `apps/frontend/app/assets/styles/_tokens.scss`, 어두운 쪽은 `_themes.scss` 다.
 * 레거시에 없는 단계(`mid`, `rule`, `tint-2`)만 그 사이 값으로 채웠다.
 */

/*
 * Pretendard Variable 을 우리 도메인에서 든다. 엔진은 `site.stylesheet` 를 **한 파일**로만 받고
 * (엔진 `docs/skin-api.md` §3n), head 기여의 `rel="stylesheet"` 는 거절되므로(같은 문서 §3p)
 * 스타일시트를 하나 더 링크할 길이 없다. 그래서 스킨 시트 다음에 실리는 이 파일의 **첫 규칙**으로
 * `@import` 한다 — `@import` 는 다른 규칙보다 앞에 있어야 하고, 여기 주석 다음이 그 자리다.
 * 경로에 버전(1.3.9)이 박혀 있어 내용이 바뀌면 경로가 바뀐다. `public/_headers` 가 그 경로를
 * 1년 immutable 로 둔다. 동적 서브셋이라 페이지가 실제로 쓰는 `unicode-range` 청크만 내려온다.
 */
@import url('/fonts/pretendard-1.3.9/pretendardvariable-dynamic-subset.css');

:root {
  --board-bg: #eef3f2;
  --board-surface: #ffffff;
  --board-tint: #f5f8f7;
  --board-tint-2: #e7eeec;
  --board-line: #dce4e2;
  --board-rule: #c9d4d1;
  --board-text: #17201f;
  --board-mid: #46524f;
  --board-dim: #65726f;
  --board-ink: #17201f;
  --board-on-ink: #ffffff;
  --board-accent: #146c5a;
  --board-on-accent: #ffffff;
  /* 주 단추 hover 채움 — 운영 `AppButton.vue:16` 의 `--color-brand-700`. 다크는 아래 블록에서 따로 둔다. */
  --board-accent-hover: #105649;
  --board-accent-text: #146c5a;
  --board-count: #146c5a;
  --board-danger: #c63838;
  /*
   * 통신사 색 — 레거시 `_tokens.scss:8-10` 의 `--color-carrier-*`. KT 는 레거시와 같이
   * 잉크(`--color-ink`)라 여기서도 `var(--board-ink)` 로 둔다.
   */
  --board-carrier-skt: #d8412f;
  --board-carrier-kt: var(--board-ink);
  --board-carrier-lgu: #c8247c;
  /*
   * 입력 포커스의 두 색은 레거시 `AppInput.vue:4` 의 `--color-brand-500`(선)과
   * `--color-brand-100`(3px 고리)다 — 이 팔레트에 없는 단계라 토큰으로 단다.
   */
  --board-brand-500: #18806a;
  /*
   * 브랜드 눈금 50(옅은 면)·100(옅은 선)·700(진한 글자)은 레거시 `--color-brand-50/100/700`
   * (`_tokens.scss:2,3,7`)이다 — 이 팔레트에 없는 눈금이라 `--board-brand-500` 과 같은 식으로 단다.
   * 어두운 값은 아래 어두운 블록이 뜻대로 둔다.
   */
  --board-brand-50: #edf8f5;
  --board-brand-100: #d5eee7;
  --board-brand-700: #105649;
  /* 눌린 단추·탭의 테두리 — 밝을 땐 강조색 그대로. */
  --site-pressed-line: #146c5a;
  /* 떠 있는 판의 그림자 — 레거시 `--shadow-md`(`_tokens.scss`). */
  --site-shadow-md: 0 10px 30px rgb(15 37 32 / 10%);
  /* 본문 글자색 — 레거시 PostContent 의 먹색. */
  --site-prose-text: #101716;
  /* 코드 칸 가장자리 — 밝을 땐 없음. */
  --site-code-line: transparent;
  --board-ring: #d5eee7;
  /* 포커스 선·고리. 스킨이 `--board-accent` 로 읽는 자리를 이 사이트 값으로 고정한다. */
  --board-focus-line: var(--board-brand-500);
  --board-focus-ring: var(--board-ring);
  --board-radius-l: 0;
  --board-shadow: 0 1px 2px rgb(15 37 32 / 7%);
  /* 빈 상태 안쪽 여백 — 레거시 `.empty-state`(global.scss:31). */
  --board-empty-pad: 2.5rem 1rem;
  /*
   * 셸 최대폭과 좌우 여백은 레거시 `.container` 한 줄이다 — `width: min(calc(100% - 2rem),
   * var(--content-width))`(`global.scss:17`, `--content-width: 1180px` 은 `_tokens.scss:42`).
   * 스킨은 셸의 최대폭 안쪽으로 `--board-gap` 만큼 패딩을 두므로(`styles.ts:207`) 내용 1180 은
   * 겉폭 1212(75.75rem)에 좌우 1rem 을 뺀 값이다. 스킨 기본 gap 은 20px 로 1rem 보다 넓다.
   */
  --board-max: 75.75rem;
  --board-gap: 1rem;
  /*
   * 스킨 기본값은 `Pretendard`(로컬 설치)를 먼저 찾고 그다음 `Pretendard Variable` 이다. 우리가
   * 든 것은 후자뿐이라 순서를 뒤집는다 — 안 그러면 Pretendard 가 없는 Windows 방문자가
   * `Malgun Gothic` 으로 떨어진다. 시스템 폴백은 스킨 기본값에서 그대로 가져왔다.
   */
  --board-font: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", system-ui, sans-serif;
  /*
   * 제목 크기는 레거시 `--text-page`(`_tokens.scss:55`)다. 스킨 토큰은 1.35rem + 1.1vw 라
   * (`styles.ts:38`) 1280 에서 35.68 로 운영 36 보다 작다. 이 토큰은 게시판 머리
   * `.board-title`(`styles.ts:549`)과 글 상세 `.post-title`(`:863`), 태그 머리가 같이 쓰므로
   * 토큰 하나를 덮어 세 화면의 제목을 한꺼번에 맞춘다 — 1280 에서 36, 390 에서 28.
   */
  --board-size-title: clamp(1.75rem, 3vw, 2.25rem);
}

/*
 * 물려 내려가는 줄높이만 운영 값으로 돌린다 — 레거시 `_typography.scss` 의
 * `body { line-height: 1.6 }` 다. 스킨 기본은 1.5(`--board-leading-ui`)인데, 그 토큰은
 * 공지 표·꼬리표·요약처럼 줄높이를 **직접** 쓰는 자리들도 같이 쓰므로 토큰을 갈면
 * 맞춰 둔 뱃지 높이가 다시 어긋난다. 그래서 토큰이 아니라 `body` 만 덮는다.
 * 이걸로 `small`(13px) 이 19.5px → 20.8px 로 운영과 같아지고, 디아블로 화면에 남아 있던
 * 꼬리표·제목 1~2px 차이가 없어진다.
 */
body {
  line-height: 1.6;
}

/*
 * 제목 줄높이의 전역 바탕은 레거시 `_typography.scss:3-5` 다 — h1 1.25, h2 1.35, h3 1.4
 * (h4 는 레거시에 규칙이 없어 두지 않는다). 굵기는 스킨 `--board-weight-title`(600)이 주므로
 * 여기선 줄높이만 잡는다 — 스킨 기본(`styles.ts`)의 `--board-leading-tight`(1.3)를 같은
 * 요소 선택자로 순서로 이긴다. 클래스로 크기·굵기·줄높이를 따로 잡은 제목
 * (`.board-title`·`.post-title`·`.d2r .name-row h2` 등)은 그쪽 규칙이 이긴다.
 */
h1 {
  line-height: 1.25;
}

h2 {
  line-height: 1.35;
}

h3 {
  line-height: 1.4;
}

/*
 * 카드 안쪽 여백. 운영의 카드는 전부 `AppSurface` 한 부품이고 안쪽 여백이 모든 폭에서
 * 1.1rem 이다(`apps/frontend/app/components/ui/AppSurface.vue:4` `.app-surface { padding: 1.1rem }`).
 * 스킨 기본은 20px(`--board-space-5`)이고 48rem 이하에서 `:root:root`(0,2,0)로 16px 로
 * 갈린다 — 이기려면 같은 점수가 필요하다. 이 파일이 스킨 시트 뒤에 실리므로 같은 선택자를
 * 여기 다시 선언하면 넓은 화면과 좁은 화면 둘 다 순서로 이긴다.
 * 카드 위·아래 여백이 따로 잡힌 곳(`.board-list` 등)은 토큰이 아니라 그 규칙이 정한다.
 */
:root:root {
  --board-card-pad: 1.1rem;
}

/*
 * 어두운 값. 엔진의 밝기 선택 계약대로 두 선택자에 같은 값을 둔다. 하나는 OS 가 어둡고 방문자가 밝게를
 * 고르지 않았을 때, 다른 하나는 방문자가 어둡게를 골랐을 때다. `:root:root` 겹침은 스킨의 어두운
 * 블록과 특이성을 맞추려는 것이고, 이 파일이 나중에 실려 순서로 이긴다.
 *
 * 레거시 다크는 브랜드색을 바꾸지 않았다. 버튼 채움은 그대로 두고, 글자로 쓰는 녹색만 어두운 면에서
 * 읽히도록 밝혔다(`#146c5a` 는 `#18201f` 위에서 대비가 3:1 이 안 된다).
 */
@media (prefers-color-scheme: dark) {
  :root:root:not([data-theme='light']) {
    --board-bg: #101716;
    --board-surface: #18201f;
    --board-tint: #202a28;
    --board-tint-2: #2a3532;
    --board-line: #34413e;
    --board-rule: #45524f;
    --board-text: #e8efed;
    --board-mid: #c2ccc9;
    --board-dim: #9eaaa7;
    --board-ink: #e8efed;
    --board-on-ink: #101716;
    --board-accent-text: #56b89f;
    /* on-accent 가 밝은 글자(#ffffff)라 hover 는 어둡게 — 엔진 기본(흰색 28% 섞기)은 대비가 4.5 에 못 미친다. */
    --board-accent-hover: color-mix(in srgb, var(--board-accent) 72%, #000);
    --board-count: #56b89f;
    /* 통신사 색 — 레거시 다크 `_themes.scss:8,9`. KT 는 레거시가 다크 값을 따로 두지 않아 잉크를 따라간다. */
    --board-carrier-skt: #ff8272;
    --board-carrier-kt: var(--board-ink);
    --board-carrier-lgu: #f07cb2;
    /*
     * 브랜드 눈금의 어두운 값. 레거시 다크는 눈금을 안 바꿨지만 밝은 면이 어두운 면 위에서 튀어서
     * 뜻대로 옮긴다 — 700(진한 글자)은 글자용 강조색, 50(옅은 면)은 강조색을 면에 30%,
     * 100(옅은 선)은 글자용 강조색을 면에 35% 섞는다.
     */
    --board-brand-50: color-mix(in srgb, var(--board-accent) 30%, var(--board-surface));
    --board-brand-100: color-mix(in srgb, var(--board-accent-text) 35%, var(--board-surface));
    --board-brand-700: #56b89f;
    --site-pressed-line: color-mix(in srgb, var(--board-accent-text) 45%, var(--board-surface));
    /* 레거시 다크 `--shadow-md`(`_themes.scss`). */
    --site-shadow-md: 0 12px 36px rgb(0 0 0 / 35%);
    --site-prose-text: #e8efed;
    /* 코드 칸(#17211f)이 글 면(#18201f)과 한 끗 차라 가장자리를 긋는다. */
    --site-code-line: var(--board-line);
    /* 어두운 면에서 밝은 연초록 고리는 튄다 — 어두운 면의 글자용 브랜드색을 옅게 섞는다. */
    --board-ring: color-mix(in srgb, var(--board-accent-text) 30%, transparent);
    --board-shadow: 0 1px 2px rgb(0 0 0 / 30%);
  }
}

:root:root[data-theme='dark'] {
  --board-bg: #101716;
  --board-surface: #18201f;
  --board-tint: #202a28;
  --board-tint-2: #2a3532;
  --board-line: #34413e;
  --board-rule: #45524f;
  --board-text: #e8efed;
  --board-mid: #c2ccc9;
  --board-dim: #9eaaa7;
  --board-ink: #e8efed;
  --board-on-ink: #101716;
  --board-accent-text: #56b89f;
  /* on-accent 가 밝은 글자(#ffffff)라 hover 는 어둡게 — 엔진 기본(흰색 28% 섞기)은 대비가 4.5 에 못 미친다. */
  --board-accent-hover: color-mix(in srgb, var(--board-accent) 72%, #000);
  --board-count: #56b89f;
  /* 통신사 색 — 레거시 다크 `_themes.scss:8,9`. KT 는 레거시가 다크 값을 따로 두지 않아 잉크를 따라간다. */
  --board-carrier-skt: #ff8272;
  --board-carrier-kt: var(--board-ink);
  --board-carrier-lgu: #f07cb2;
  /*
   * 브랜드 눈금의 어두운 값. 레거시 다크는 눈금을 안 바꿨지만 밝은 면이 어두운 면 위에서 튀어서
   * 뜻대로 옮긴다 — 700(진한 글자)은 글자용 강조색, 50(옅은 면)은 강조색을 면에 30%,
   * 100(옅은 선)은 글자용 강조색을 면에 35% 섞는다.
   */
  --board-brand-50: color-mix(in srgb, var(--board-accent) 30%, var(--board-surface));
  --board-brand-100: color-mix(in srgb, var(--board-accent-text) 35%, var(--board-surface));
  --board-brand-700: #56b89f;
  --site-pressed-line: color-mix(in srgb, var(--board-accent-text) 45%, var(--board-surface));
  /* 레거시 다크 `--shadow-md`(`_themes.scss`). */
  --site-shadow-md: 0 12px 36px rgb(0 0 0 / 35%);
  --site-prose-text: #e8efed;
  /* 코드 칸(#17211f)이 글 면(#18201f)과 한 끗 차라 가장자리를 긋는다. */
  --site-code-line: var(--board-line);
  --board-ring: color-mix(in srgb, var(--board-accent-text) 30%, transparent);
  --board-shadow: 0 1px 2px rgb(0 0 0 / 30%);
}

/*
 * 사이트 공통 부품 — 펼침 선택(레거시 `AppSelect.vue`). 알뜰폰·성지시세·디아블로 정렬이 같은 마크업을 쓴다:
 * details.select > summary.select-trigger + form.select-content > button.select-item.
 *
 * 트리거는 12rem 을 못 박고 좁은 화면에서 `min-width: 0` 으로 푼다 — 글자 길이가 바뀌어도 옆 단추가
 * 밀리지 않게 하는 자리다. 글자가 400 에 줄 높이 1.6 인 것은 이 자리가 「단추」가 아니라 「고른 값」이라서다.
 * 펼친 판은 단추 아래로 열고 너비는 단추를 따라가며(원본 `min-width: var(--reka-select-trigger-width)`)
 * 오른쪽 끝을 맞춘다. 간격 0·안쪽 .3rem·z 100·그림자는 원본 `.select-content`(`AppSelect.vue:18`
 * — `--z-popover`·`--shadow-md`, `_tokens.scss:24,41`), 위 5px 는 원본의 `side-offset` 이다.
 * 항목은 원본 `.select-item`(`AppSelect.vue:19-20`): 패딩 .5/.6, r.3rem, 1rem/1.6 이라 줄 높이 41.6.
 * 고른 항목은 배경이 아니라 오른쪽 체크(`SelectItemIndicator` 의 svg)로 보여주고, 가리킨 항목은
 * `[data-highlighted]` 의 brand-50/700 이다. 스킨이 `button[type='submit']` 에 채우는 강조색은
 * 같은 특이도로 맞세워 벗긴다.
 */
.select {
  position: relative;
}

.select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-width: 12rem;
  min-height: var(--board-control-h);
  padding: var(--board-control-pad-y) var(--board-input-pad-x);
  border: 1px solid var(--board-line);
  border-radius: var(--board-control-radius);
  background: var(--board-surface);
  color: var(--board-text);
  font-size: var(--board-size-ui);
  font-weight: 400;
  line-height: 1.6;
  list-style: none;
  cursor: pointer;
}

.select-trigger::-webkit-details-marker {
  display: none;
}

.select[open] > .select-content {
  position: absolute;
  top: calc(100% + 5px);
  right: 0;
  z-index: 100;
  display: grid;
  min-width: 100%;
  padding: 0.3rem;
  border: 1px solid var(--board-line);
  border-radius: 0.4rem;
  background: var(--board-surface);
  box-shadow: var(--site-shadow-md);
}

/* 스킨의 submit 채움 규칙(0,4,1)·hover(0,5,1)와 같은 무게로 맞선다 — 이 파일이 뒤에 실려 차례로 이긴다. */
.select .select-content button.select-item[type='submit'] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: 0;
  border-radius: 0.3rem;
  background: transparent;
  color: var(--board-text);
  font-family: inherit;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  text-align: left;
  cursor: pointer;
}

.select .select-content button.select-item[type='submit']:hover,
.select .select-content button.select-item[type='submit']:focus-visible {
  background: var(--board-brand-50);
  color: var(--board-brand-700);
  opacity: 1;
}

/*
 * 사이트 공통 부품 — 필터 칩(레거시 `_filters.scss:29-76`). 알뜰폰·성지시세 목록은
 * submit 단추 + `aria-pressed`, 성지시세 상세는 라디오 + label 이 같은 칩을 쓴다.
 * 디아블로 칩은 자기 판이라 여기 안 건드린다.
 *
 * 스킨의 submit 채움 규칙(0,4,1)·hover(0,5,1)와 같은 무게로 맞선다 — 이 파일이 뒤에
 * 실려 차례로 이긴다. hover 는 글자 brand-700·선 brand-500 만 바뀌고(`_filters.scss:45`)
 * 눌린 칩은 accent 채움이다. 통신사 칩은 꺼졌을 때 `--chip-tone` 이 글자·hover 선을
 * 같이 잡는다(`_filters.scss:57` 의 `--carrier-color`). 50rem 이하는 같은 폭 격자
 * (`_filters.scss:70` 의 auto-fit)에 칸 2.1rem.
 */
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0;
}

/* 추천은 칩 하나가 폼 하나다. 폼 상자가 흐름을 끊지 않도록 상자를 지운다. */
.filter-chips > form {
  display: contents;
}

.filter-chips button.filter-chip[type='submit'][aria-pressed],
.filter-chips label.filter-chip {
  min-height: 2.35rem;
  padding: 0 0.9rem;
  border: 1px solid var(--board-line);
  border-radius: 6.4px;
  background: var(--board-surface);
  color: var(--chip-tone, var(--board-dim));
  font-family: inherit;
  font-size: var(--board-size-caption);
  font-weight: 600;
  line-height: 1.6;
  cursor: pointer;
}

.filter-chips button.filter-chip[type='submit'][aria-pressed='true'],
.filter-chips input:checked + label.filter-chip {
  border-color: var(--board-accent);
  background: var(--board-accent);
  color: var(--board-on-accent);
}

.filter-chips button.filter-chip[type='submit'][aria-pressed]:not([aria-pressed='true']):hover,
.filter-chips input:not(:checked) + label.filter-chip:hover {
  border-color: var(--chip-tone, var(--board-brand-500));
  background: var(--board-surface);
  color: var(--chip-tone, var(--board-brand-700));
  opacity: 1;
}

/* 눌린 칩은 운영에도 별도 hover 가 없다 — `.active` 가 `:hover` 뒤에 서서 눌린 모양을 지킨다. */
.filter-chips button.filter-chip[type='submit'][aria-pressed='true']:hover {
  border-color: var(--board-accent);
  background: var(--board-accent);
  color: var(--board-on-accent);
  opacity: 1;
}

.filter-chips input:focus-visible + label.filter-chip {
  outline: 2px solid var(--board-accent);
  outline-offset: 2px;
}


/*
 * 통신사 색은 글자색이 아니라 변수로 든다. 글자색을 정하는 것은 위 칩 규칙이고(선택됐으면 강조색),
 * 여기서는 그 규칙이 읽는 값만 바꾼다 — 특이도 싸움을 한 번으로 줄이는 자리다.
 */
.carrier-tone--skt {
  --chip-tone: var(--board-carrier-skt);
}

.carrier-tone--kt {
  --chip-tone: var(--board-carrier-kt);
}

.carrier-tone--lgu {
  --chip-tone: var(--board-carrier-lgu);
}

@media (max-width: 50rem) {
  /* 칸 수를 폭이 정한다 — 레거시 `_filters.scss:70` 의 auto-fit. 560 에서 6개, 800 에서 9개가
     한 줄에 서고, 칸이 좁으면 칩 글자가 두 줄로 접힌다(`white-space: normal`). */
  .filter-chips {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(4.25rem, 1fr));
    gap: 0.3rem;
  }

  .filter-chips button.filter-chip[type='submit'][aria-pressed] {
    min-width: 0;
    min-height: 2.1rem;
    padding: 0.25rem 0.4rem;
    line-height: 1.3;
    white-space: normal;
  }
}

/*
 * 헤더 — 레거시 `AppHeader.vue` 의 세 자리를 스킨 값에 맞춘다.
 *
 * 로고: 레거시 `.brand`(`AppHeader.vue:25`)는 줄높이를 따로 두지 않아 body 의 1.6 을 물려받는다 —
 * 24px 글자가 38.4px 상자로 헤더 가운데 선다. 스킨은 `line-height: 1` 이라 상자가 24px 라 같은
 * 크기의 글자가 7px 위로 붙어 보인다. 자간도 레거시의 -.06em.
 */
.gb-brand {
  line-height: 1.6;
  letter-spacing: -0.06em;
}

/*
 * 로그인: 레거시 `.login-button`(`AppHeader.vue:25`)은 채움·테두리 없는 단추로 안쪽만 .3rem 이다 —
 * 16px/25.6 에 위아래 4.8 을 더한 35px 상자. 스킨은 링크에 색만 줘 날글자로 보인다.
 * `.gb-sign-in` 은 익명 방문자에게만 그려진다(스킨 `chrome.tsx` AccountMenu) — 로그인한 헤더의
 * 계정 메뉴에는 닿지 않는다.
 */
.gb-account .gb-sign-in {
  padding: 0.3rem;
}

/*
 * 데스크톱 헤더 메뉴 항목 간격 — 레거시 `AppHeader.vue:25` 의 `.desktop-nav` gap 1.2rem.
 * 스킨은 `--board-space-5`(1.25rem)를 쓰므로 여기서 운영 값으로 덮는다. 60rem 이하는
 * 햄버거 판의 한 줄짜리 세로 격자라 건드리지 않는다.
 */
@media (min-width: 60.01rem) {
  .board-menu ul { column-gap: 1.2rem; }
}

/*
 * 태블릿(768~960)의 헤더. 운영은 `below(desktop)` = 960px 에서 데스크톱 메뉴를 숨기고
 * 햄버거로 바꾼다(레거시 `AppHeader.vue:25-28`) — 스킨은 같은 전환을 47.99rem 에서만
 * 하므로(`styles.ts:500-529`) 그 사이에서 메뉴가 펼쳐진 채로 남는다. 스킨의 폰 헤더 규칙 중
 * 헤더 줄 배치와 메뉴 판에 해당하는 것만 여기서 다시 켠다. 폰 전용 축소(로고 20px·아이콘
 * 38px·가입 단추 패딩, `styles.ts:507-508·527`)는 운영이 이 폭에서 데스크톱 크기를
 * 유지하므로(768 실측 햄버거 40×40·헤더 65) 옮기지 않는다. 검색 패널·목록·격자 등 헤더 밖
 * 규칙도 둔다.
 */
@media (min-width: 48rem) and (max-width: 60rem) {
  /* 햄버거가 앞에 서고 메뉴는 행 아래의 한 줄 — 스킨과 같은 이유로 줄 감쌈과 자동 높이.
     간격은 운영 `below(desktop)` 의 .65rem(`AppHeader.vue`, 아래 블록과 같은 값). */
  .board-header-row { position: relative; flex-wrap: wrap; height: auto; min-height: 4rem; row-gap: 0; column-gap: 0.65rem; }
  .board-spacer { min-height: 4rem; }
  /* 햄버거가 로고를 앞서므로 메뉴 앞 간격으로 둔 로고의 오른쪽 마진을 뺀다(글자 크기는 데스크톱 값 유지). */
  .gb-brand { margin-right: 0; }
  .board-menu-pop { display: block; order: -1; position: static; flex: none; align-self: center; }
  .board-menu-pop > summary { display: flex; }
  .board-menu-pop[open] > summary { background: none; color: var(--board-ink); }
  /* 판은 운영처럼 좌우 8px 까지 펼친다 — 줄 안쪽 여백은 이 폭에서 16 이라(43.75rem 아래에서만
     8 로 줄어듦) 판만 반칸 바깥으로 내민다. */
  .board-menu { order: 1; flex: 0 0 auto; width: calc(100% + 1rem); display: none; margin-inline: -0.5rem; }
  .board-header-row:has(> .board-menu-pop[open]) > .board-menu { display: block; border-top: 1px solid var(--board-line); padding: 0.35rem 0 var(--board-space-3); }
  .board-menu ul { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
  .board-menu a { min-height: 2.75rem; padding: 0.55rem 0.6rem; border-radius: 0.4rem; line-height: 1.6; font-size: var(--board-size-ui); }
  .board-menu a[aria-current] { color: var(--board-ink); }
}

/*
 * xs(400px) 와 스킨의 폰 경계(47.99rem) 사이 — 스킨은 폰 블록에서 로고 20px·아이콘 38px·
 * 가입 단추 안쪽 .6rem 으로 줄이지만(`styles.ts:507-508·527`), 운영은 그 축소를
 * `below(xs)` = 400px 이하에서만 한다(레거시 `AppHeader.vue` 마지막 @include). 이 폭에서는
 * 운영이 데스크톱 값을 유지하므로 — 로고 --text-title 1.5rem, 아이콘 40×40(.icon-button
 * 2.5rem), 가입 단추 .55rem .8rem — 스킨의 축소를 되돌린다. 햄버거가 앞에 선 이 폭의
 * 간격은 운영 `below(desktop)` 의 .65rem 이다. 400 이하는 스킨 폰 값이 운영 xs 값과
 * 같으므로(로고 --text-section·아이콘 2.35rem) 그대로 둔다.
 */
@media (min-width: 400.02px) and (max-width: 47.99rem) {
  .board-header-row { column-gap: 0.65rem; }
  .gb-brand { font-size: 1.5rem; }
  .board-menu-pop > summary, .board-search-pop > summary, .gb-theme-toggle { width: 2.5rem; height: 2.5rem; }
  .gb-account .sign-up { padding: 0.55rem 0.8rem; }
}

/*
 * 본문 첫 칸이 시작하는 높이는 레거시 `.page { padding-block: 1.4rem 3rem }`(`layouts/default.vue:61`)
 * 의 윗값 22.4 다 — 스킨은 `.board-body` 에 위 24(60rem 아래에선 20)를 둔다. 모든 화면이
 * 이 안쪽 여백 하나로 시작하므로 여기서 맞추면 게시판 머리·글 상세·태그가 같이 선다.
 */
.board-body {
  padding-top: 1.4rem;
}
@media (max-width: 60rem) {
  .board-body {
    padding-top: 1.4rem;
  }
}

/*
 * 시세 띠(`plugins/market-strip`). 운영 noriter.com 과 같이 **상자 없는 한 줄**이다 — 레거시
 * `PromoMarketStrip.vue` 가 상자를 벗긴 판단이 맞았고, 한동안 카드였던 것을 되돌린다. 띠라는 것은
 * 아랫선 하나가 말한다(레거시 `.strip` 도 `border-bottom` 만 두고 배경은 두지 않았다).
 *
 * 띠는 헤더 **밖**, `.board-shell` 의 `.board-body` 바로 앞에 선다(스킨 `index.tsx`). 헤더는 셸 밖의
 * 전폭 띠라서 그 아랫선과의 사이는 띠가 스스로 벌린다 — 헤더 아랫선 아래로 윗여백 하나.
 *
 * 닫으면 `public/market-strip.js` 가 `<html data-market-strip="off">` 를 단다. 숨기는 것은 코어가
 * 씌운 `.gb-plugin-market-strip` 이다 — 안쪽만 숨기면 슬롯 div 가 빈 채로 남는다.
 */
html[data-market-strip='off'] .gb-plugin-market-strip {
  display: none;
}

.market-strip {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  /* 운영과 같은 값. 글자 사이를 띄우는 값이라 토큰 눈금에 없다. */
  gap: 0.15rem 1.1rem;
  min-width: 0;
  /*
   * 아래는 `.board-body` 의 윗여백이 이미 벌린다. 위는 헤더 선에서 17.6px — 레거시
   * `.promo-slot { margin-block: 1.1rem 0 }`(`global.scss:60`). 토큰 눈금에 없는 리터럴이다.
   */
  margin: 1.1rem 0 0;
  /* 오른쪽은 닫기 단추가 설 자리, 아래는 아랫선과 글자 사이. 운영 `.strip--closable` 과 같다. */
  padding: 0 1.75rem 0.65rem 0;
  border-bottom: 1px solid var(--board-line);
  font-size: var(--board-size-meta);
}

.market-strip__ask {
  flex: none;
}

/* 단추가 아니라 글 속의 링크로 보이게 한다. 밑줄 하나면 눌리는 것인 줄 안다. */
.market-strip__links {
  flex: none;
}

/* 링크 색은 운영의 `--color-brand-700` — `--board-brand-700` 이 그 값이다. */
.market-strip__links a {
  color: var(--board-brand-700);
  font-weight: var(--board-weight-bold);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--board-rule);
}

.market-strip__links a:hover {
  text-decoration-color: currentcolor;
}


.market-strip__how {
  flex: none;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

/*
 * 수집 사실 줄(「09-05 확인 · 판매처 N곳 · 요금제 N개」). 오른쪽 끝으로 밀어 닫기 단추 앞에 붙인다.
 * 레거시 `PromoMarketStrip.vue` `.strip__fact` 그대로이고, 거기서도 `below(desktop)` — 960px
 * **이하**에서는 접는다(`_breakpoints.scss` 의 below 는 경계를 포함한다) — 좁으면 문장과 표
 * 이름이 먼저 자리를 가져야 한다.
 */
.market-strip__fact {
  flex: none;
  margin-left: auto;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

@media (max-width: 960px) {
  .market-strip__fact {
    display: none;
  }
}

/*
 * 닫기 단추. 자리를 차지하지 않는다 — 절대 자리에 두고 글자는 오른쪽 여백으로 비켜 준다.
 *
 * 이 규칙의 값어치는 세로 자리다. 단추는 **첫 줄** 가운데에 온다. 넓은 화면에서는 띠가 한 줄이라
 * 블록 가운데와 첫 줄 가운데가 같지만 좁은 화면에서는 둘로 갈리므로(아래 `@media`) 첫 줄에 붙인다.
 *
 * 넓은 화면의 `top: 50%` 는 여백 상자의 가운데다. 아래 여백(0.65rem)의 절반만큼 도로 끌어올리면
 * 첫 줄 가운데와 겹친다 — 그래서 `- 0.325rem` 이다. 운영도 같은 식을 쓴다.
 */
.market-strip__close {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translateY(calc(-50% - 0.325rem));
  display: grid;
  place-items: center;
  /* 스킨의 `button` 이 `min-height: 2.25rem` 을 깐다. 이 단추는 그보다 작다. */
  width: 1.75rem;
  height: 1.75rem;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--board-dim);
  cursor: pointer;
}

.market-strip__close:hover {
  background: var(--board-tint);
  color: var(--board-ink);
}

/*
 * 좁은 화면에서는 문장이 한 줄을 통째로 쓰고 표 이름이 그 아래 선다. 운영과 같다.
 * 띠의 오른쪽 여백이 사라지므로(단추 자리를 글자 쪽에서 비운다) 문장에만 그만큼 준다.
 */
@media (max-width: 47.5rem) {
  .market-strip {
    gap: 0.15rem 0.9rem;
    padding: 0 0 0.55rem;
  }

  .market-strip__ask {
    width: 100%;
    padding-right: 1.75rem;
  }

  /* 두 줄이 되면 여백 상자의 가운데는 아랫줄 언저리다. 첫 줄에 붙인다. */
  .market-strip__close {
    top: -3px;
    transform: none;
  }
}

/* 레거시 `sm`(560px). */
@media (max-width: 35rem) {
  .market-strip {
    gap: 0.15rem 0.7rem;
  }
}

/*
 * 알뜰폰 요금제 비교(`plugins/mvno`). 플러그인 페이지의 HTML 은 코어가 준 대로 나가고
 * 스킨은 그 안을 모르므로, 이 화면들의 규칙은 여기 있어야 한다.
 *
 * **레거시 스타일을 옮겨 오지 않았다.** 레거시 `.vue` 의 scoped 스타일은 자기 디자인
 * 토큰(`--color-brand-600` 등)을 깔고 앉아 있는데 그건 이 사이트에 없다. 재현해야 하는
 * 것은 픽셀이 아니라 주소·마크업·메타이므로(gbun-board `AGENTS.md` 규칙 18) 여기서는
 * 스킨 토큰만으로 읽을 수 있게만 짠다.
 */
/*
 * 좌우 여백은 목록 카드와 같은 값을 쓴다(운영 `--compare-inset`). 머리만 이 값을 안고 있고
 * 카드·기준·툴바는 제 안쪽 패딩으로 같은 자리를 만든다 — 그래서 값이 두 군데 적혀 있다.
 */
.mvno-head {
  padding: 0 17.6px;
}

.mvno-head h1 {
  /* 아래 문단과의 사이는 레거시 `.compare-head` 의 격자 간격 .2rem 이다(`_compare.scss:21`). */
  margin: 0 0 0.2rem;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.3;
}

.mvno-head p {
  margin: 0;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  line-height: 1.6;
}

/*
 * 수집 기준. 접히는 한 줄이라 카드가 아니라 `details` 이고, 본문 셋은 그 뒤에 온다.
 * 여닫는 것은 브라우저가 하고, 열림 여부는 `[open]` 으로만 본다 — 스크립트는 없다.
 * `summary` 의 기본 삼각형은 `list-style: none` 과 `::-webkit-details-marker` 로 지운다.
 */
.mvno-note {
  margin: 0 0 1rem;
  padding: 12px 17.6px;
  border: 1px solid var(--board-line);
  border-radius: 12px;
  background: var(--board-surface);
}

.mvno-note > summary {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  line-height: 1.5;
  list-style: none;
  cursor: pointer;
}

.mvno-note > summary::-webkit-details-marker {
  display: none;
}

.mvno-note > summary > svg {
  flex: 0 0 auto;
  color: var(--board-accent);
}

.mvno-note-title {
  flex: 0 0 auto;
  margin: 0;
  color: var(--board-text);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: inherit;
}

.mvno-note-meta {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: 400;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 색은 옅지 않다 — 접힌 줄에서 「자세히」가 먼저 눈에 들어와야 한다. 운영 값 그대로. */
.mvno-note-toggle {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--board-brand-700);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.mvno-note-toggle span:last-child {
  display: none;
}

.mvno-note[open] .mvno-note-toggle span:first-child {
  display: none;
}

.mvno-note[open] .mvno-note-toggle span:last-child {
  display: inline;
}

.mvno-note-body {
  margin: 0.7rem 0 0;
  padding-top: 0.7rem;
  border-top: 1px solid var(--board-line);
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  line-height: 1.7;
}

.mvno-note-facts,
.mvno-extra dl {
  margin: 0.6rem 0 0;
}

.mvno-note-facts {
  display: grid;
  gap: 0.35rem;
}

.mvno-note-facts > div,
.mvno-extra dl > div {
  display: grid;
  grid-template-columns: 6rem minmax(0, 1fr);
  gap: 0.7rem;
  padding: 0.35rem 0;
  font-size: var(--board-size-caption);
}

.mvno-note-facts > div {
  border-bottom: 1px solid var(--board-line);
}

.mvno-note-facts > div:last-child {
  border-bottom: 0;
}

.mvno-note-facts dt {
  color: var(--board-brand-700);
  /* 레거시 `dt` 는 caption(13px)이다 — 위 `> div` 의 글자 크기만 물려 받으면 엔진의 dt 기본값에 져서 14px 로 남는다. */
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.mvno-extra dt {
  color: var(--board-dim);
}

.mvno-note-facts dd {
  margin: 0;
  line-height: 1.6;
}

.mvno-extra dd {
  margin: 0;
}


/*
 * 조건 카드. 폼인 이유는 `plugins/mvno/src/screen.tsx` 머리에 적혀 있다 — 크롤 함정을 안 여는 것.
 * 칩 하나가 곧 조건 하나를 바꾸는 제출 단추이고, 나머지 값은 숨은 칸이 들고 간다.
 */
.mvno-picker {
  margin: 0 0 1.5rem;
  padding: 21.6px 17.6px;
  border: 1px solid var(--board-line);
  border-radius: 16px;
  background: var(--board-surface);
}

.mvno-rows {
  display: grid;
  gap: 0.8rem;
  margin-bottom: 1rem;
}

.mvno-row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
}

.mvno-row > strong {
  color: var(--board-text);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.6;
}

/* 추천 줄만 아래를 가른다 — 나머지 셋은 「전체 필터」로 이어지는 같은 무리다. */
.mvno-row-preset {
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--board-line);
}

/*
 * 「전체 필터」 줄. 여기는 `summary` 가 줄 전체다 — 「필터 초기화」가 왼쪽, 여닫는 단추가
 * 오른쪽에 같은 줄로 서야 하는데 `summary` 는 하나뿐이라 안에 둘 다 넣었다. 링크를 눌러도
 * 접기가 함께 일어나지만 그건 상관없다 — 어차피 `/mvno` 로 간다.
 */
.mvno-adv-bar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 1rem;
  padding-top: 13.6px;
  border-top: 1px solid var(--board-line);
  list-style: none;
  cursor: pointer;
}

.mvno-adv-bar::-webkit-details-marker {
  display: none;
}

.mvno-reset {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 2.35rem;
  margin-right: auto;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: 600;
  text-decoration: none;
}

/* 안쪽 여백 1px 6px 는 운영에서 이 자리가 `button` 이라 붙던 기본값이다 — 상자 크기를 맞춘다. */
.mvno-adv-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 2.35rem;
  padding: 1px 6px;
  color: var(--board-dim);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.6;
}

.mvno-adv-toggle svg:last-child {
  transition: transform 0.15s;
}

.mvno-advanced[open] .mvno-adv-toggle svg:last-child {
  transform: rotate(180deg);
}

/*
 * 상세 조건 일곱 줄 — 운영 `.advanced-filter-section`(`MvnoCompareView.vue:125`). 줄마다
 * `<form>` 하나라 이 상자는 폼이 아니라 테두리만이다.
 */
.mvno-options {
  margin-top: 0.5rem;
  border: 1px solid var(--board-line);
  border-radius: 0.4rem;
  overflow: hidden;
}

.mvno-opt-row {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  min-height: 3rem;
  border-top: 1px solid var(--board-line);
}

.mvno-opt-row:first-of-type {
  border-top: 0;
}

.mvno-opt-row > * {
  min-width: 0;
}

.mvno-opt-row > strong {
  display: flex;
  align-items: center;
  padding: 0.65rem 0.85rem;
  background: var(--board-tint);
  color: var(--board-text);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

/* 운영 `.filter-button-list` — 단추가 곧 그 값으로 가는 제출 단추다(위 tsx 의 `ButtonRow`). */
.mvno-btn-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.65rem;
}

/*
 * 칩과 같은 이유로 스킨 제출 단추 규칙(0,4,1)과 무게를 맞춘다. 운영은 켜진 단추가
 * brand-50 면 + brand-700 글자 + 앞에 「✓」다 — 이 팔레트에서는 tint-2·`--board-brand-700`·ring
 * 이 그 자리다. 어두운 면 대응은 아래 두 선택자가 한다.
 */
.mvno-btn-list button.mvno-opt[type='submit'][aria-pressed] {
  min-height: 1.95rem;
  padding: 0 0.65rem;
  border: 1px solid transparent;
  border-radius: 0.3rem;
  background: transparent;
  color: var(--board-dim);
  font-family: inherit;
  font-size: var(--board-size-caption);
  font-weight: 600;
  cursor: pointer;
}

.mvno-btn-list button.mvno-opt[type='submit'][aria-pressed='true'] {
  border-color: var(--board-ring);
  background: var(--board-tint-2);
  color: var(--board-brand-700);
}

.mvno-btn-list button.mvno-opt[type='submit'][aria-pressed='true']::before {
  content: '✓';
  margin-right: 0.25rem;
}


/*
 * 운영 옵션 단추엔 hover 가 없다 — 엔진의 submit:hover(0,5,1)가 채움을 입히지 못하게
 * 같은 무게 + 뒤 차례로 rest 모양을 그대로 다시 선다. 눌린 것도 눌린 모양을 지킨다.
 */
.mvno-btn-list button.mvno-opt[type='submit'][aria-pressed]:not([aria-pressed='true']):hover {
  border-color: transparent;
  background: transparent;
  color: var(--board-dim);
  opacity: 1;
}

.mvno-btn-list button.mvno-opt[type='submit'][aria-pressed='true']:hover {
  border-color: var(--board-ring);
  background: var(--board-tint-2);
  color: var(--board-brand-700);
  opacity: 1;
}


/*
 * 통신사 줄만 격자다 — 운영 `.provider-button-list`. 운영은 스크립트로 가장 넓은 단추를 재서
 * `--provider-button-width` 를 박는데, 여기는 재지 않고 그 초기값 7.5rem 을 그대로 둔다.
 */
.mvno-providers {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 7.5rem), 1fr));
  align-items: stretch;
  padding: 0.6rem 0.15rem;
}

.mvno-providers button.mvno-opt {
  width: 100%;
  overflow-wrap: break-word;
}

/* 구간 줄은 라벨 면이 끝까지 내려와야 한다(운영 `.range-filter-row`). */
.mvno-range-row {
  align-items: stretch;
}

/*
 * 두 손잡이 슬라이더 — 운영 `MvnoRangeSlider.vue` 의 `.range-slider` 를 토큰으로 옮겼다.
 * 손잡이가 싣는 값은 눈금 번호고 GB·원은 숨은 칸이 든다(화면 tsx 의 `RangeRow`).
 */
.mvno-range {
  box-sizing: border-box;
  min-width: 0;
  width: auto;
  max-width: 36rem;
  margin: 0.25rem 0.75rem;
  padding: 0.55rem 0.4rem 0.4rem;
}

/* 운영 `.range-slider__value`. 「적용」은 `<noscript>` 안이라 스크립트가 켜진 화면에서는 이 줄이 24px 다. */
.mvno-range-value {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-height: 1.5rem;
  margin-bottom: 0.45rem;
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.mvno-range-apply {
  min-height: 1.95rem;
  padding: 0 0.65rem;
  border: 1px solid var(--board-line);
  border-radius: 0.3rem;
  background: var(--board-surface);
  color: var(--board-dim);
  font-family: inherit;
  font-size: var(--board-size-caption);
  font-weight: 600;
  cursor: pointer;
}

.mvno-range-rail {
  position: relative;
  height: 1.25rem;
}

.mvno-range-track {
  position: absolute;
  top: 0.5rem;
  right: 0.45rem;
  left: 0.45rem;
  height: 0.25rem;
  border-radius: 999px;
  background: var(--board-line);
}

.mvno-range-track span {
  position: absolute;
  inset-block: 0;
  border-radius: inherit;
  background: var(--board-accent);
}

.mvno-range-rail input[type='range'] {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  width: 100%;
  height: 1.25rem;
  margin: 0;
  background: transparent;
  pointer-events: none;
  appearance: none;
}

.mvno-range-rail input[type='range']::-webkit-slider-runnable-track {
  height: 0.25rem;
  background: transparent;
}

.mvno-range-rail input[type='range']::-webkit-slider-thumb {
  width: 1.1rem;
  height: 1.1rem;
  margin-top: -0.425rem;
  border: 2px solid var(--board-accent);
  border-radius: 50%;
  background: var(--board-surface);
  box-shadow: 0 1px 4px rgb(0 0 0 / 16%);
  cursor: grab;
  pointer-events: auto;
  appearance: none;
}

.mvno-range-rail input[type='range']::-moz-range-track {
  height: 0.25rem;
  background: transparent;
}

.mvno-range-rail input[type='range']::-moz-range-thumb {
  width: 1rem;
  height: 1rem;
  border: 2px solid var(--board-accent);
  border-radius: 50%;
  background: var(--board-surface);
  box-shadow: 0 1px 4px rgb(0 0 0 / 16%);
  cursor: grab;
  pointer-events: auto;
}

.mvno-range-rail input[type='range']:focus-visible::-webkit-slider-thumb {
  outline: 3px solid color-mix(in srgb, var(--board-accent) 25%, transparent);
  outline-offset: 2px;
}

.mvno-range-ticks {
  position: relative;
  height: 1.8rem;
  margin: 0 0.45rem;
}

.mvno-range-ticks span {
  position: absolute;
  top: 0;
  display: flex;
  align-items: center;
  flex-direction: column;
  transform: translateX(-50%);
  white-space: nowrap;
}

.mvno-range-ticks i {
  width: 1px;
  height: 0.35rem;
  background: var(--board-line);
}

.mvno-range-ticks small {
  margin-top: 0.15rem;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-style: normal;
}

.mvno-range-ticks span:first-child {
  align-items: flex-start;
  transform: none;
}

.mvno-range-ticks span:last-child {
  align-items: flex-end;
  transform: translateX(-100%);
}

/*
 * 개수와 정렬. 왼쪽은 칸을 다 쓰고 오른쪽 정렬만 제 폭을 갖는다.
 * 아래 테두리는 이 줄과 목록을 가르는 선이다(운영 `.compare-toolbar`).
 */
.mvno-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 1rem;
  margin: 0 0 1rem;
  padding: 0.8rem 1.1rem 0.6rem;
  border-bottom: 1px solid var(--board-line);
}

.mvno-count {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  min-width: 0;
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.35;
}

.mvno-count span {
  flex: 0 0 auto;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  font-weight: 400;
}

.mvno-list {
  display: grid;
  /* 운영 실측 1rem. 카드가 그림자를 들면서 --board-space-3(12px)로는 그림자끼리 맞붙는다. */
  gap: 1rem;
}

/*
 * 상세(`.mvno-hero`)와 값이 갈리는 자리(폭·그림자)가 있어 더는 선택자를 공유하지 않는다.
 * 값이 같은 테두리·모서리·면만 아래 `.mvno-hero` 에 그대로 다시 적었다. hover·덮는 링크처럼
 * 목록 카드만의 것은 여전히 이 아래 두 번째 `.mvno-card` 블록에만 둔다.
 */
.mvno-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 17.5rem;
  border: 1px solid var(--board-line);
  border-radius: 1rem;
  background: var(--board-surface);
}

/*
 * 상세 히어로는 목록 카드와 폭이 다르다(운영 실측 300px, 목록은 280px) — 같은 선택자를 쓰면 안 된다.
 * 테두리·모서리·면은 목록과 값이 같아 그대로 옮기고, 그림자는 목록에 없던 걸 새로 준다
 * (운영 `.plan-hero` 는 그림자를 든다).
 */
.mvno-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 18.75rem;
  overflow: hidden;
  border: 1px solid var(--board-line);
  border-radius: 1rem;
  background: var(--board-surface);
  box-shadow: 0 2px 10px rgb(0 0 0 / 2%);
}

.mvno-card {
  position: relative;
  overflow: hidden;
  box-shadow: 0 2px 8px rgb(0 0 0 / 2%);
  transition: box-shadow 0.24s, transform 0.24s, border-color 0.24s;
}

/* hover 테두리는 운영 `--color-brand-100`(`MvnoCompareView.vue:125`) — `--board-brand-100` 이 그 값이다. */
.mvno-card:hover {
  border-color: var(--board-brand-100);
  box-shadow: 0 12px 28px rgb(0 0 0 / 6%);
  transform: translateY(-4px);
}


@media (prefers-reduced-motion: reduce) {
  .mvno-card {
    transition: none;
  }

  .mvno-card:hover {
    transform: none;
  }
}

/*
 * 카드 전체를 눌리게 하는 덮는 링크(운영과 같은 값). 제목에 이미 같은 곳으로 가는 링크가 있어
 * 여기 것은 `tabindex="-1"`/`aria-hidden="true"` 로 접근성 트리에서 뺀다(마크업은 `screen.tsx`) —
 * 안 그러면 같은 주소가 스크린리더에 두 번 잡힌다.
 */
.mvno-card .card-link {
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
}

.mvno-card-main {
  min-width: 0;
  padding: 1.4rem 1.1rem;
}

/* 운영 실측 1.5rem/1.1rem — 목록 카드의 1.4rem 과 갈려 이름도 따로 쓴다. */
.mvno-hero-main {
  min-width: 0;
  padding: 1.5rem 1.1rem;
}

.mvno-card h2 {
  /* .mvno-count(602행 근처)와 같은 크기 — 운영 제목이 딱 그 눈금이다. */
  margin: 0.7rem 0;
  font-size: 1.25rem;
  font-weight: 600;
}

.mvno-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--board-space-2);
  margin: 0;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

/*
 * 세 칩 모두 줄높이를 따로 두지 않는다 — 레거시도 `.rank`/`.network-chip`/`.pricing-badge`
 * (`MvnoCompareView.vue:96-98`)에 line-height 가 없어 body 의 1.6 을 물려받는다. 스킨
 * `--board-leading-ui`(1.5)를 주면 칩 높이가 운영보다 1.3px 낮아진다.
 */
.mvno-rank,
.mvno-chip,
.mvno-badge {
  padding: 0.2rem 0.5rem;
  font-weight: 600;
}

/* 레거시 `MvnoCompareView.vue:96` 의 `.rank` — brand-700 글자·brand-50 면·brand-100 선 그대로. */
.mvno-rank {
  border: 1px solid var(--board-brand-100);
  border-radius: 0.4rem;
  color: var(--board-brand-700);
  background: var(--board-brand-50);
}

/* 레거시 `MvnoCompareView.vue:96` 의 `.provider-name` — muted 600. */
.mvno-provider {
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  font-weight: 600;
}

/* 레거시 `MvnoCompareView.vue:97` 의 `.network-chip` — muted 글자·surface-subtle 면. */
.mvno-chip {
  border-radius: 0.4rem;
  color: var(--board-dim);
  background: var(--board-tint);
}

/*
 * 목록 카드의 통신망 칩 테두리 — 레거시 같은 규칙(`MvnoCompareView.vue:97`)의
 * `color-mix(--carrier-color 25%, --color-line)`. `--carrier-color` 는 아래 `mvno-chip-*` 가 단다.
 */
.mvno-card .mvno-chip {
  border: 1px solid color-mix(in srgb, var(--carrier-color, var(--board-line)) 25%, var(--board-line));
}

/*
 * 상세 머리의 통신망 칩 — 레거시 `[id].vue:90` 은 톤 클래스 없이 `--detail-line`(= `--color-line`)
 * 선에 `.23rem .5rem`·`.35rem` 이다. 목록 카드와 값이 달라 따로 둔다.
 */
.mvno-hero .mvno-chip {
  padding: 0.23rem 0.5rem;
  border: 1px solid var(--board-line);
  border-radius: 0.35rem;
}

/*
 * 카드 칩이 테두리에 섞는 통신사 색 — 레거시 `_compare.scss:120-122` 의 `.carrier-tone--*`
 * (`--color-carrier-*` 는 `_tokens.scss:8-10`). 필터 칩은 공통 `.carrier-tone--*` 가
 * `--chip-tone` 으로 따로 주니 카드 칩엔 같은 색을 `--carrier-color` 로 단다.
 */
.mvno-chip-skt {
  --carrier-color: var(--board-carrier-skt);
}

.mvno-chip-kt {
  --carrier-color: var(--board-carrier-kt);
}

.mvno-chip-lgu {
  --carrier-color: var(--board-carrier-lgu);
}

/*
 * 요금 배지 — 레거시 `MvnoCompareView.vue:98` 의 `.pricing-badge`. 테두리는 레거시에 없다
 * (두르면 운영보다 높이가 0.7px 커진다). 톤마다 `--tone`(글자)·`--tone-soft`(면)만 두고
 * 한 규칙이 칠한다. `standard` 는 톤이 없어 토큰 폴백(dim/tint)으로 다크를 따라간다.
 */
.mvno-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 1.5rem;
  border-radius: 0.35rem;
  background: var(--board-tint);
}

.mvno-badge[data-tone='promo'] { --tone: #b94616; --tone-soft: #fff0e8; }
.mvno-badge[data-tone='stable'] { --tone: #167454; --tone-soft: #e9f7f1; }
.mvno-badge[data-tone='unknown'] { --tone: #91610c; --tone-soft: #fff6dc; }
.mvno-badge[data-tone='conditional'] { --tone: #6750a4; --tone-soft: #f1edff; }

.mvno-badge[data-tone],
.mvno-schedule[data-warning] {
  color: var(--tone, var(--board-dim));
  background: var(--tone-soft, var(--board-tint));
}

/*
 * 다크의 배지 면은 톤 글자색을 어두운 면에 18% 섞고, 글자는 톤을 흰색에 40% 섞어 밝힌다 —
 * 면 휘도는 0.03 아래, 글자 대비는 7.7 이상으로 톤 구분도 남는다.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .mvno-badge[data-tone]:not([data-tone='standard']),
  :root:not([data-theme='light']) .mvno-schedule[data-warning] {
    color: color-mix(in srgb, var(--tone) 40%, #ffffff);
    background: color-mix(in srgb, var(--tone) 18%, var(--board-surface));
  }
}
:root[data-theme='dark'] .mvno-badge[data-tone]:not([data-tone='standard']),
:root[data-theme='dark'] .mvno-schedule[data-warning] {
  color: color-mix(in srgb, var(--tone) 40%, #ffffff);
  background: color-mix(in srgb, var(--tone) 18%, var(--board-surface));
}

.mvno-bonus {
  display: flex;
  flex-wrap: wrap;
  gap: var(--board-space-1);
  margin: 0 0 var(--board-space-2);
  font-size: var(--board-size-caption);
}

.mvno-bonus span {
  padding: 0 var(--board-space-2);
  border-radius: var(--board-radius-s);
  background: var(--board-tint-2);
}

/*
 * 칸마다 원형 아이콘이 서는 구조(운영과 같다). `dl > div` 안에는 `dt`/`dd` 만 올 수 있어
 * 아이콘을 끼울 자리가 없었다 — 그래서 `dl` 을 버렸다. 이름(`small`)이 값 앞에 그대로 남아
 * 읽는 순서는 바뀌지 않는다(마크업은 `screen.tsx`).
 */
.mvno-specs {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 1rem;
  margin: 0;
  padding-top: 0.85rem;
  border-top: 1px solid var(--board-line);
}

.mvno-spec {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-width: 0;
}

.mvno-spec-icon {
  display: grid;
  flex: 0 0 2.25rem;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--board-tint);
  color: var(--board-accent-text);
}

.mvno-spec > span:last-child {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.mvno-spec small {
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

.mvno-spec strong {
  /* 스킨 눈금엔 15px 단계가 없다 — 1173행 근처와 같은 값을 그대로 적는다. */
  font-size: 0.9375rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/*
 * 상세 머리의 스펙 값은 카드와 다르다 — 레거시 `[id].vue:90` 의 `.key-spec strong` 은
 * 14px(`--text-meta`)에 말줄임 대신 `overflow-wrap: break-word` 로 줄바꿈한다. 목록 카드는
 * 목록 레거시 `MvnoCompareView.vue:129` 의 `.allowance strong`(15px `--text-label`, 말줄임)이라
 * 위 공통 규칙 그대로 둔다.
 */
.mvno-hero .mvno-spec strong {
  font-size: var(--board-size-meta);
  overflow: visible;
  white-space: normal;
  overflow-wrap: break-word;
}

.mvno-spec em {
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-style: normal;
  font-weight: var(--board-weight-normal);
}

.mvno-card-price {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-end;
  padding: 1.4rem 1.1rem;
  border-left: 1px solid var(--board-line);
  background: color-mix(in srgb, var(--board-tint) 60%, transparent);
  text-align: right;
  /* 덮는 링크가 이 칸 위에서도 눌리게 흘려보낸다 — 얹힌 순서만 z-index, 클릭은 아래로. */
  z-index: 2;
  pointer-events: none;
}

.mvno-card-price strong {
  margin: 0.25rem 0 0.4rem;
  font-size: 1.5rem;
  font-weight: var(--board-weight-bold);
  line-height: 1.2;
}

.mvno-card-price strong span {
  margin-left: 0.15rem;
  font-size: var(--board-size-ui);
  font-weight: 600;
  /* 운영은 "원" 도 body 줄높이 1.6(25.6px)을 쓴다 — 낮추면 strong 줄 상자가 28.8 아래로 내려간다. */
  line-height: 1.6;
}

.mvno-period {
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.mvno-schedule {
  padding: 0.25rem 0.5rem;
  border-radius: 0.3rem;
  background: var(--board-tint);
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

/*
 * 「요금 오름」 경고 — 레거시 `.after.warning`(`MvnoCompareView.vue:101`, 조건은 `:49` 의
 * `priceIncrease >= 10000`, 속성은 `screen.tsx` 가 단다). 배지와 같은 톤 규칙이 칠한다.
 */
.mvno-schedule[data-warning] { --tone: #c94736; --tone-soft: #fdf2f2; }

/*
 * 운영 `.load-more-wrap` + `.load-more-button`(`MvnoCompareView.vue:50,131`)을 옮겼다.
 * 운영은 단추 하나로 이어 붙이고 우리는 쪽 링크라(CSR 을 안 쓴다) 「이전」·「요금제 더보기」
 * 둘이 같이 나올 수 있어 둘 다 같은 단추 꼴로 낸다. 개수는 운영처럼 「더보기」 단추 안 `small`
 * 에 두고, 마지막 쪽이라 「더보기」 가 없으면 단추 없이 홀로 회색으로 선다.
 * 최소 15rem·3rem 과 0.4rem 모서리는 운영 값이고 스킨 단계에 없어 그대로 적었다.
 */
.mvno-more {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--board-space-3);
  margin: 1.9rem auto 0.6rem;
  font-size: var(--board-size-meta);
}

.mvno-more a {
  display: flex;
  min-width: 15rem;
  min-height: 3rem;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0 var(--board-space-4);
  border: 1px solid var(--board-line);
  border-radius: 0.4rem;
  background: var(--board-surface);
  color: var(--board-ink);
  font-weight: 600;
}

.mvno-more a:hover {
  border-color: var(--board-accent);
  color: var(--board-accent-text);
}

/* 단추 안 개수는 운영 `small` 처럼 글자색만 흐리게 — 크기·굵기는 단추 글자와 같다. */
.mvno-more a small {
  color: var(--board-dim);
  font-size: inherit;
  font-weight: 600;
}

/* 마지막 쪽에서 「더보기」 없이 홀로 서는 개수. */
.mvno-more > span {
  color: var(--board-dim);
  font-weight: 600;
}

.mvno-empty {
  padding: var(--board-space-7) 0;
  color: var(--board-dim);
  text-align: center;
}

/*
 * 아래 두 덩이는 운영 `.category-links` 와 `.seo-guide` 다. 둘 다 면이 없고 위에 줄 하나만
 * 있는데, 좌우 여백은 위 카드들과 같은 1.1rem 을 물려 글자가 카드 글자와 한 줄로 선다.
 * 15px(0.9375rem)·20px(1.25rem)은 운영 `--text-label`·`--text-section` 이고 스킨 단계에
 * 없는 크기여서 그대로 적었다.
 */
.mvno-cats {
  display: grid;
  gap: 0.9rem;
  margin-top: var(--board-space-7);
  padding: var(--board-space-6) 1.1rem;
  border-top: 1px solid var(--board-line);
}

.mvno-cats h2,
.mvno-guide h2 {
  margin: 0;
  font-size: 1.25rem;
}

.mvno-cat-group {
  display: grid;
  grid-template-columns: 5.25rem minmax(0, 1fr);
  align-items: start;
  gap: 0.6rem;
}

.mvno-cat-group > strong {
  padding-top: 0.35rem;
  color: var(--board-dim);
  font-size: 0.9375rem;
}

.mvno-cat-group ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.mvno-cat-group a {
  display: inline-block;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--board-line);
  border-radius: 999px;
  font-size: 0.9375rem;
}

.mvno-cat-group a:hover {
  border-color: var(--board-accent);
}

.mvno-cat-group a[aria-current='page'] {
  border-color: var(--board-ink);
}

.mvno-cat-all {
  font-size: 0.9375rem;
}

.mvno-guide {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--board-space-6);
  margin-top: var(--board-space-7);
  padding: 1.75rem 1.1rem;
  border-top: 1px solid var(--board-line);
}

.mvno-guide h2 {
  grid-column: 1 / -1;
}

.mvno-guide h3 {
  margin: 0 0 0.4rem;
  font-size: 0.9375rem;
}

.mvno-guide p {
  margin: 0;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  line-height: var(--board-leading-read);
}

/* 상세. 목록의 카드 규칙을 거의 그대로 물려받고 다른 것만 여기 있다. */
.mvno-detail {
  padding: 0 0 2rem;
}

.mvno-back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.25rem 0 0.9rem 1.1rem;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  font-weight: 600;
}

.mvno-back:hover {
  color: var(--board-accent-text);
}

/*
 * 운영 실측 0.75rem/1.4rem — 위아래 합이 토큰 조합(space-2+space-4)보다 커서 히어로 높이가 맞다.
 * 크기·줄높이는 레거시 `.compare-title`(`_compare.scss:27` — `--text-title` 1.5rem, 줄높이 1.3)이다.
 * 굵기 600 은 위 전역 h1 규칙이 준다.
 */
.mvno-hero h1 {
  margin: 0.75rem 0 1.4rem;
  font-size: 1.5rem;
  line-height: 1.3;
}

/* 상세 스펙 칸은 목록보다 아이콘이 작다(운영 실측 32×32, 목록은 36×36) — 격자 비율·위 여백도 다르다. */
.mvno-hero .mvno-specs {
  grid-template-columns: 1.45fr 1fr 1fr;
  padding-top: 1rem;
}

.mvno-hero .mvno-spec-icon {
  flex: 0 0 2rem;
  width: 2rem;
  height: 2rem;
}

.mvno-hero-price {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 1.5rem 1.1rem;
  border-left: 1px solid var(--board-line);
  /*
   * 팔레트에 이 옅은 초록 단계가 없다 — 레거시 `[id].vue:90` 의
   * `.hero-price { background: color-mix(in srgb, var(--color-brand-50) 55%, var(--color-surface)) }`
   * 를 `--board-brand-50`(= `--color-brand-50`)으로 옮겼다. 토큰이 어두운 값을 들고 있어 다크에서도 같이 간다.
   */
  background: color-mix(in srgb, var(--board-brand-50) 55%, var(--board-surface));
}

.mvno-price-label {
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.mvno-main-price {
  margin: 0.3rem 0 1.15rem;
}

.mvno-main-price strong {
  /* 24px — 목록 `.mvno-card-price strong`(910행 근처)과 같은 리터럴. */
  font-size: 1.5rem;
  font-weight: var(--board-weight-bold);
  line-height: 1.2;
}

.mvno-main-price span {
  margin-left: 0.2rem;
  font-weight: 600;
}

.mvno-official {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.75rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--board-accent);
  border-radius: 0.4rem;
  background: var(--board-surface);
  /* 운영 `--color-brand-700` — `--board-brand-700` 이 그 값이다. */
  color: var(--board-brand-700);
  font-size: var(--board-size-caption);
  font-weight: 600;
  text-align: center;
}


.mvno-official:hover {
  background: var(--board-accent);
  color: var(--board-surface);
}

.mvno-flow,
.mvno-extra,
.mvno-source {
  margin-top: var(--board-space-4);
  padding: 1.4rem 1.1rem;
  border: 1px solid var(--board-line);
  /* `--board-radius` 는 없는 토큰이라 모서리가 0 이 되던 자리 — 목록 카드와 같은 1rem 으로 적는다. */
  border-radius: 1rem;
  background: var(--board-surface);
  box-shadow: 0 2px 10px rgb(0 0 0 / 2%);
}

.mvno-source {
  padding: 1rem 1.1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
}

.mvno-sec-head {
  margin-bottom: 1.1rem;
}

.mvno-sec-kicker {
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.mvno-sec-head h2 {
  margin: 0.3rem 0 0;
  /* 20px — 스킨 눈금에 없어 .mvno-cats h2(1006행 근처)처럼 리터럴로 적는다. */
  font-size: 1.25rem;
  /* 운영은 h2 가 600·줄높이 27px(레거시 `.section-heading h2`). 스킨 기본 700·26px 과 다르다. */
  font-weight: 600;
  line-height: 1.35;
}

.mvno-extra h2 {
  /* 「추가 제공」은 눈썹이 없어 절 제목이 스스로 위아래 여백을 진다(마크업은 screen.tsx). */
  margin: 0 0 var(--board-space-3);
  font-size: 1.25rem;
}

.mvno-flow-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 2.1rem minmax(0, 1fr);
  align-items: center;
  gap: 0.65rem;
}

.mvno-phase {
  min-width: 0;
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--board-line);
  border-radius: 0.75rem;
  background: var(--board-tint);
}

/*
 * 팔레트에 이 옅은 초록 단계가 없다 — 레거시 `[id].vue:90` 의
 * `.phase-promo { background: color-mix(in srgb, var(--color-brand-50) 62%, var(--color-surface));
 * border-color: color-mix(in srgb, var(--color-brand-600) 25%, var(--detail-line)) }` 를
 * `--board-brand-50`(`--color-brand-50`)과 `--board-accent`(= `--color-brand-600` #146c5a)로 옮겼다.
 * 두 토큰은 어두운 값도 들고 있어 다크에서도 같이 간다.
 */
.mvno-phase-promo {
  background: color-mix(in srgb, var(--board-brand-50) 62%, var(--board-surface));
  border-color: color-mix(in srgb, var(--board-accent) 25%, var(--board-line));
}

/*
 * 두 줄 다 `p` 라 시트 앞쪽의 문단 여백을 그대로 든다. 아래 여백을 지우지 않으면 두 줄 사이가
 * 12px 벌어지고 단계 판이 운영보다 14px 높아진다 — 옛 `.mvno-phase p { margin: 0 }` 자리다.
 */
.mvno-phase-top {
  display: flex;
  justify-content: space-between;
  gap: var(--board-space-2);
  margin: 0;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

.mvno-phase-top strong {
  color: var(--board-accent-text);
}

.mvno-phase-price {
  margin: 0.45rem 0 0;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
}

.mvno-phase-price strong {
  color: var(--board-ink);
  /* 20px 리터럴 — 위 h2 와 같은 이유. */
  font-size: 1.25rem;
}

.mvno-flow-arrow {
  color: var(--board-dim);
  justify-self: center;
}

/*
 * 안의 svg 가 인라인이라 몸줄높이(1.6)의 줄상자를 만들어 화살표 행이 25.6px 로 높아진다 —
 * 운영은 svg 자체가 격자 항목이라(레거시 `[id].vue:33`) 행이 그림 높이(19)다. 블록화해 같은 값을 낸다.
 */
.mvno-flow-arrow svg {
  display: block;
}

.mvno-source p {
  margin: 0;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

.mvno-source p:last-child {
  text-align: right;
}

.mvno-source-left {
  display: flex;
  align-items: center;
  gap: var(--board-space-2);
  white-space: nowrap;
}

.mvno-source-left svg {
  color: var(--board-accent-text);
}

/* 운영은 strong 이 본문 잉크를 물려받는다(`[id].vue:43`) — dim 이 물려 내려오지 않게 잉크로 고정. */
.mvno-source-left strong {
  color: var(--board-ink);
  font-size: var(--board-size-meta);
}

/*
 * 800px 이하 — 레거시 `below(tablet-wide)`(`_breakpoints.scss`). 목록 카드·상세 히어로가 한 열로
 * 접히고 가격 칸이 아랫줄로 내려간다(`MvnoCompareView.vue:134`, `pages/mvno/plans/[id].vue:91`).
 * 좌우 여백은 이 폭의 `--compare-inset` 값 .9rem(`_compare.scss:182`)을 따른다 — 560px 이하에서
 * .8rem 으로 한 번 더 주는 것은 아래 35rem 블록이다.
 * 운영은 이 폭에서도 `.promo strong` 이 1.5rem/1.2(실측 28.8px)로 넓은 폭과 같다 — 레거시 소스의
 * 축소 규칙은 운영 실측과 어긋나 옮기지 않았다.
 */
@media (max-width: 50rem) {
  .mvno-card,
  .mvno-hero,
  .mvno-flow-grid,
  .mvno-guide {
    grid-template-columns: 1fr;
  }

  .mvno-detail {
    padding-inline: 0.1rem;
  }

  .mvno-flow-arrow {
    transform: rotate(90deg);
  }

  .mvno-hero-price {
    border-top: 1px solid var(--board-line);
    border-left: 0;
  }

  .mvno-main-price {
    margin-bottom: 0.9rem;
  }

  .mvno-source {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
  }

  .mvno-source p:last-child {
    text-align: left;
  }

  .mvno-source-left {
    white-space: normal;
    flex-wrap: wrap;
  }

  /* 좁아진 폭에서 카드·가격 칸 여백을 함께 줄인다 — 운영은 `--compare-inset` 하나로 들어간다. */
  .mvno-card-main {
    padding: 1.2rem 0.9rem;
  }

  /*
   * 상세의 판들도 같이 줄인다. 우리는 규칙마다 값을 적으니 여기서 같이 적어 줘야 한다 —
   * 이게 빠지면 이 폭에서 상세만 좌우 17.6px 로 남아 같은 화면의 목록 카드와 안쪽선이 어긋난다.
   */
  .mvno-back {
    margin-left: 0.9rem;
  }

  .mvno-hero-main,
  .mvno-hero-price {
    padding-inline: 0.9rem;
  }

  .mvno-flow,
  .mvno-extra,
  .mvno-source {
    padding-inline: 0.9rem;
  }

  .mvno-card-price {
    align-items: flex-start;
    padding: 1.1rem 0.9rem;
    border-top: 1px solid var(--board-line);
    border-left: 0;
    text-align: left;
  }

  /* 800 이하에서 운영은 가격 숫자를 24 → 20 으로 줄인다(레거시 `below(tablet-wide)` 소스 값). */
  .mvno-card-price strong {
    font-size: 1.25rem;
    line-height: 1.2;
  }

  /*
   * 상세 스펙 칸은 여기서 두 열이 된다(레거시 `.key-specs`, `[id].vue:91`). 목록 `.mvno-specs` 는
   * 560px 까지 세 열을 유지하므로 여기선 `.mvno-hero` 것만 건드린다.
   */
  .mvno-hero .mvno-specs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.9rem;
  }

  .mvno-hero .mvno-specs > div:first-child {
    grid-column: 1 / -1;
  }

  /*
   * 위쪽 블록(머리·수집 기준·필터 판·정렬 줄)도 같은 `below(tablet-wide)` 에서 접힌다
   * (`_compare.scss:181-191`, `_filters.scss:60-73`, `MvnoCompareView.vue:134`).
   * 좌우 여백은 이 폭의 `--compare-inset` .9rem — 560 이하에서 .8rem 으로 주는 것은
   * 아래 35rem 블록이다.
   */
  .mvno-head {
    padding: 0 0.9rem;
  }

  /* 접힌 줄에서 기준일은 제 줄로 내려간다 — 제목 옆에 두면 잘려서 못 읽는다. */
  .mvno-note {
    padding: 12px 0.9rem;
  }

  .mvno-note > summary {
    flex-wrap: wrap;
    gap: 0.35rem;
  }

  .mvno-note > summary > svg {
    order: 1;
  }

  .mvno-note-title {
    order: 2;
  }

  .mvno-note-toggle {
    order: 3;
  }

  .mvno-note-meta {
    order: 4;
    flex: 1 1 100%;
    margin-top: 0.15rem;
    white-space: normal;
  }

  .mvno-note-facts > div {
    grid-template-columns: 5.5rem minmax(0, 1fr);
  }

  .mvno-picker {
    padding: 17.6px 0.9rem;
  }

  /* 줄 사이를 좁힌다 — 칩이 격자로 접혀 카드가 길어진다. */
  .mvno-rows {
    gap: 0.6rem;
  }

  .mvno-row {
    grid-template-columns: 4.6rem minmax(0, 1fr);
    gap: 0.45rem;
    align-items: start;
  }

  .mvno-row > strong {
    margin-top: 0.38rem;
    font-size: 0.875rem;
  }

  .mvno-row-preset {
    padding-bottom: 0.9rem;
  }

  .mvno-opt-row {
    grid-template-columns: 5.25rem minmax(0, 1fr);
  }

  /* 운영 `below(tablet-wide)` 의 `.provider-button-list`·`.range-slider` 분기. */
  .mvno-providers {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    padding-inline: 0.25rem;
  }

  .mvno-providers button.mvno-opt {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .mvno-range {
    margin-inline: 0.4rem;
  }

  /* 정렬은 개수 아래 제 줄로 내려가되 폭은 절반만 쓴다(운영의 두 칸 격자). */
  .mvno-toolbar {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0.5rem 0.45rem;
    padding: 0.8rem 0.9rem 0.6rem;
  }

  .mvno-count {
    grid-column: 1 / -1;
  }

  .mvno-sort {
    grid-column: 1;
  }
}

/*
 * 44rem 이하는 위쪽 블록 분기가 아니다 — 목록 아래의 분류·안내·더 보기만 폰 폭에 맞춘다.
 * 위쪽 블록의 분기는 위 50rem·35rem 블록이 레거시 `below(tablet-wide)`·`below(sm)` 그대로 든다.
 */
@media (max-width: 44rem) {
  /*
   * `.mvno-cat-group` 은 폰에서도 `5.25rem minmax(0,1fr)` 그대로 둔다 — 운영도 여기엔 폰
   * 분기가 없다. 한 줄로 세우면 덩이마다 줄이 하나 늘어 62px 이 길어진다(실측).
   */

  /* 운영 폰 실측 12.8px. 위 카드들과 같이 좁힌다. */
  .mvno-cats {
    padding: var(--board-space-6) 0.8rem;
  }

  .mvno-guide {
    padding: 1.75rem 0.8rem;
  }

  /* 운영은 여기에 폰 분기가 없어 단추 하나는 15rem·가운데 그대로다. 「이전」·「더보기」 가
   * 같이 나올 때만 15rem 둘이 폰 폭에 안 들어가니 줄을 나눠 한 줄씩 쓰게 한다. */
  .mvno-more:has(a + a) a {
    min-width: 0;
    flex: 1 1 100%;
  }
}

/*
 * 600px 이하 — 레거시 `below(mobile)`(`MvnoRangeSlider.vue:111`). 슬라이더 안쪽 여백을 줄이고
 * 눈금은 짝수번째(끝 하나는 살림)와 다섯 번째를 지운다 — 좁은 폭에서 글자끼리 겹치지 않게.
 */
@media (max-width: 37.5rem) {
  .mvno-range {
    padding-inline: 0.15rem;
  }

  .mvno-range-ticks small {
    font-size: 0.65rem;
  }

  .mvno-range-ticks span:nth-child(even):not(:last-child),
  .mvno-range-ticks span:nth-child(5) {
    display: none;
  }
}

/*
 * 560px 이하 — 레거시 `below(sm)`(`MvnoCompareView.vue:135`). 목록 스펙 칸이 두 열로 접히고
 * 첫 칸(데이터)이 줄 전체를 쓴다. `--compare-inset` 도 .8rem 으로 줄어(`_compare.scss:196`)
 * 위 50rem 블록에서 .9rem 으로 적은 안쪽 여백을 여기서 한 단계 더 좁힌다.
 * 상세 히어로의 스펙 칸은 이미 800px 에서 두 열이 됐고 이 폭의 추가 분기가 없다 — 여기서
 * 아이콘·글자를 줄이는 것은 목록 카드(`.mvno-card`)뿐이다.
 */
@media (max-width: 35rem) {
  .mvno-specs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .mvno-specs > div:first-child {
    grid-column: 1 / -1;
  }

  .mvno-card .mvno-spec strong {
    font-size: var(--board-size-meta);
  }

  .mvno-card .mvno-spec-icon {
    flex: 0 0 1.9rem;
    width: 1.9rem;
    height: 1.9rem;
  }

  .mvno-card-main {
    padding: 1.2rem 0.8rem;
  }

  .mvno-back {
    margin-left: 0.8rem;
  }

  .mvno-hero-main,
  .mvno-hero-price {
    padding-inline: 0.8rem;
  }

  .mvno-flow,
  .mvno-extra,
  .mvno-source {
    padding-inline: 0.8rem;
  }

  .mvno-card-price {
    padding: 1.1rem 0.8rem;
  }

  /* 위쪽 블록의 좌우 여백도 `--compare-inset` 이 .8rem 으로 주는 만큼 같이 좁힌다(`_compare.scss:195`). */
  .mvno-head {
    padding: 0 0.8rem;
  }

  .mvno-note {
    padding: 12px 0.8rem;
  }

  .mvno-note-facts > div {
    grid-template-columns: 1fr;
    gap: 0.2rem;
  }

  .mvno-picker {
    padding: 17.6px 0.8rem;
  }

  .mvno-opt-row {
    grid-template-columns: 4.7rem minmax(0, 1fr);
  }

  .mvno-toolbar {
    padding: 0.8rem 0.8rem 0.6rem;
  }
}

/* 운영은 400px 에서 한 번 더 좁힌다 — 상세 스펙 칸만 걸린다(목록은 이 분기가 없다). */
@media (max-width: 25rem) {
  .mvno-hero .mvno-spec {
    gap: 0.45rem;
  }

  .mvno-hero .mvno-spec-icon {
    flex: 0 0 1.8rem;
    width: 1.8rem;
    height: 1.8rem;
  }
}

/*
 * 휴대폰 성지 가격 비교(`plugins/phonedeal`). 알뜰폰과 같은 원칙이다 — 레거시 `.vue` 의
 * scoped 스타일을 옮겨 오지 않고 스킨 토큰만으로 읽을 수 있게 짠다.
 *
 * 다른 점 하나: 여기 규칙은 **플러그인 페이지와 섹션 둘 다**에 걸린다. 가격표는 공간
 * (`/posts/phone`)에 섹션으로 얹히고 조건을 건 목록은 제 페이지라, 같은 마크업이 두 자리에
 * 나온다. 그래서 선택자를 `.deal-page` 아래로 묶지 않는다.
 *
 * **통신사 색을 안 가져왔다.** 레거시는 3사에 브랜드 색을 줬는데(`_tokens.scss:8`) 칸마다
 * 이름이 글자로 이미 적혀 있어 색이 정보를 더하지 않고, 스킨에 그 토큰이 없다.
 */
.gb-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.deal-page h1,
.deal-detail h1 {
  margin: 0 0 var(--board-space-3);
}

/* 머리 — 시세표 제목 한 줄. `head` 섹션이 들고, 표 섹션과 따로 선다. */
.compare-head {
  display: grid;
  gap: 0.2rem;
  margin: 0;
  padding: 0 1.1rem;
}

.compare-title {
  margin: 0;
  color: var(--board-text);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.3;
}

/* 조건 패널. 폼인 이유는 `plugins/phonedeal/src/screen.tsx` 머리에 적혀 있다 — 크롤 함정을 안 여는 것. */
.deal-filters {
  margin: 0 0 10px;
  padding: 0.75rem 1.1rem 1.1rem;
  border: 1px solid var(--board-line);
  border-radius: 16px;
  background: var(--board-surface);
}

.deal-filters > summary {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0 0 0.8rem;
  padding: 0 0 0.7rem;
  border-bottom: 1px solid var(--board-line);
  cursor: pointer;
  /* 레거시 `PhoneDealPage.vue` 의 `summary { line-height: 1.4 }` — 물린 1.6 이면 머리 줄이 3px 높다. */
  line-height: 1.4;
  list-style: none;
}

.deal-filters > summary strong {
  font-size: 0.9375rem;
  font-weight: 600;
}

.filter-summary {
  overflow: hidden;
  color: var(--board-dim);
  font-size: 0.8125rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * 조건 초기화. 머리(`summary`)가 아니라 조건 줄들 **아래**에 선다 — 접힌 화면에서도 조건을 한눈에
 * 보이게 하는 `filter-summary` 와 자리를 다투지 않으려고 운영이 그렇게 두었다(좁은 화면에서는
 * 그 요약이 아예 안 보인다, 아래 `@media`). 조건이 하나라도 걸렸을 때만 그려진다.
 *
 * 윗줄은 조건 줄들과의 경계다. 그래서 위 여백(`0.7rem`)은 `border-top` 바깥이 아니라 안쪽 패딩으로
 * 준다 — 운영 실측 49.8px = 테두리 1 + 패딩 11.2 + 단추 37.6.
 */
.filter-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 1rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--board-line);
}

/*
 * 「조건 초기화」. 레거시는 글자만 있는 링크였고 지금은 회전 화살표가 앞에 선다(운영과 같은
 * lucide `rotate-ccw`, `screen.tsx`). 색은 운영의 `--color-brand-700` — `--board-brand-700` 이
 * 그 값이다(시세 띠 링크와 같은 자리).
 */
.deal-reset {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 2.35rem;
  padding: 1px 6px;
  color: var(--board-brand-700);
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
}

/* 열기/닫기 안내 — 스크립트 없이 `details[open]` 으로만 바꾼다. 색은 위 「조건 초기화」와 같은 운영 `--color-brand-700`(`PhoneDealPage.vue:373`). */
.filter-toggle {
  margin-left: auto;
  color: var(--board-brand-700);
  font-size: 0.8125rem;
  font-weight: 600;
}

.filter-toggle span:last-child {
  display: none;
}

.deal-filters[open] .filter-toggle span:first-child {
  display: none;
}

.deal-filters[open] .filter-toggle span:last-child {
  display: inline;
}


.filter-rows {
  display: grid;
  gap: 0.8rem;
}

.filter-row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
}

/*
 * 고른 지역 아래가 있을 때만 서는 줄(`screen.tsx` 의 `Filters`). 뿌리만 그리는 지역 줄에서는
 * 자식(서울 북부)을 눌릴 수 없어, 부모 아래에 그 자식들이 한 줄 더 선다. 운영도 이 줄만 바탕을
 * 깔아 「지역 줄에 딸린 줄」임을 보인다 — 색은 `--board-tint`(운영 rgb(245,248,247)).
 */
.sub-region-row {
  padding: 0.5rem 0;
  border-radius: 6.4px;
  background: var(--board-tint);
  /* 운영처럼 바탕을 칩 밖으로 한 뼘 넓힌다 — 여백을 늘리면 줄의 칸이 옆 줄과 어긋난다. */
  box-shadow: 0 0 0 0.5rem var(--board-tint);
}

.filter-row-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem 1.4rem;
}

.filter-row strong {
  color: var(--board-text);
  font-size: 0.9375rem;
  font-weight: 600;
}

/*
 * 공지 띠(`pinned` 섹션의 `notice` 변형 — 이 화면에서만 쓴다). 스킨은 줄마다
 * `min-height: 2.625rem` 을 깔아 항목이 42px 이다. 레거시 `PhoneDealNotices.vue` 는
 * 최소 높이 없이 여백(.5rem)과 글줄(16px/1.6 = 25.6)로 41.6px 를 만든다 — 그대로 둔다.
 */
.notice-strip a {
  min-height: 0;
}

/* 결과 블록 — 표가 자기 테두리를 들고 오므로 여기선 자리만 잡는다. */
.deal-results {
  margin: 0;
}

.compare-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 1rem;
  padding: 0.8rem 1.1rem 0.6rem;
}

.compare-toolbar__count {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
}

.compare-toolbar__count span {
  color: var(--board-dim);
  font-size: 0.875rem;
  font-weight: 400;
}

.compare-toolbar__controls {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}

/* 「기기 검색」 — 글자를 가운데로 모으고 700 으로 눕힌다(운영). 줄 높이 1.2 라 높이는 여백이 아니라 `min-height` 가 정한다. */
.device-search-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: var(--board-control-h);
  padding: var(--board-control-pad-y) var(--board-control-pad-x);
  border: 1px solid var(--board-line);
  border-radius: var(--board-control-radius);
  background: var(--board-surface);
  color: var(--board-text);
  font-size: var(--board-size-ui);
  font-weight: 700;
  line-height: 1.2;
  list-style: none;
  cursor: pointer;
}

/*
 * 「기기 검색」 대화상자 — 레거시 `AppModal`(`apps/frontend/app/components/ui/AppModal.vue:3-5,17-21`)
 * 을 스크립트 없는 `popover` 로 옮긴다. 열린 popover 는 최상위 레이어에 서므로 z-index 를 둘
 * 자리가 없고, `::backdrop` 이 운영의 반투명 검정(`.modal-overlay`)을, `html:has()` 규칙이
 * 본문 스크롤 잠금을 맡는다. 너비 `min(calc(100% - 2rem), 28rem)` 는 레거시 호출의
 * `width="28rem"`(`PhoneDealPage.vue:77`) 그대로다. UA 가 주는 `inset:0; margin:auto` 위에
 * 폭·높이만 얹어 가운데로 모은다.
 */
.device-search-modal {
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(calc(100% - 2rem), 28rem);
  height: fit-content;
  max-height: calc(100vh - 2rem);
  overflow: auto;
  padding: 1.2rem;
  border: 0;
  border-radius: 0.75rem;
  background: var(--board-surface);
  color: var(--board-text);
  box-shadow: var(--site-shadow-md);
}

.device-search-modal::backdrop {
  background: rgb(0 0 0 / 50%);
}

html:has(#device-search-dialog:popover-open) {
  overflow: hidden;
}

/* 머리 — 운영 `.modal-head`(1.25rem/800)와 `.modal-close`(투명, .35rem, muted). */
.device-search-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 1.25rem;
  font-weight: 800;
}

.device-search-modal__close {
  min-height: 0;
  padding: 0.35rem;
  border: 0;
  border-radius: 0.4rem;
  background: transparent;
  color: var(--board-dim);
}

.device-search-modal__description {
  margin: 0.4rem 0 1rem;
  color: var(--board-dim);
}

/* 폼 — 운영 `.device-search`(grid, .8rem)와 `.device-search-actions`(오른쪽, .45rem). */
.device-search-form {
  display: grid;
  gap: 0.8rem;
}

/* 입력은 스킨 기본(입력칸 토큰)이 운영 `AppInput` 값이다 — 넓이만 채운다. */
.device-search-form input[type='search'] {
  width: 100%;
}

.device-search-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.45rem;
}

/*
 * 행동 단추 둘의 치수는 스킨 단추가 준다 — 「검색」의 강조색 채움은 `button[type='submit']`
 * 그대로, 「검색 초기화」는 마크업의 `.gb-btn` 이 조용한 단추를 그린다.
 */
.device-search-reset {
  display: inline-flex;
  align-items: center;
}

/*
 * 좁은 화면에서 표를 가로로 흘린다. 레거시는 같은 가격을 `<table>` 과 `<ol>` 로 두 번 그리고
 * CSS 로 하나를 감췄는데, 200줄이면 본문이 두 배가 된다. 그래서 표 하나만 두고 좁은 화면에서는
 * `.deal-price-table` 규칙이 줄 하나를 카드 하나로 접는다(gbun 은 `@media (max-width: 50rem)` 아래).
 */
.deal-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--board-line);
  border-radius: var(--board-radius);
  background: var(--board-surface);
}

.deal-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--board-size-meta);
}

.deal-table th,
.deal-table td {
  padding: var(--board-space-2) var(--board-space-3);
  text-align: left;
  vertical-align: top;
  white-space: nowrap;
}

.deal-table thead th {
  border-bottom: 1px solid var(--board-line);
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-normal);
}

.deal-table tbody tr + tr th,
.deal-table tbody tr + tr td {
  border-top: 1px solid var(--board-line);
}

.deal-table tbody th[scope='row'] {
  font-weight: var(--board-weight-bold);
}

.deal-checked {
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

/*
 * 시세표 카드. 레거시 `.price-table` 자리다 — 상세의 `.deal-offer-table` 과 클래스가 갈려
 * 목록의 좁은 칸·가운데 정렬·카드 모서리가 상세 표로 새지 않는다.
 */
.deal-results .deal-table-wrap {
  overflow: hidden;
  border-radius: 1rem;
}

.deal-price-table {
  table-layout: fixed;
  font-size: 1rem;
}

/*
 * 선택자를 `.deal-table.deal-price-table` 로 겹쳐 무게를 올린다 — 스킨의 낙차 규칙
 * `table:not(.board-table) th` (0,1,2) 가 `.deal-price-table th` (0,1,1) 를 이겨 칸 여백이
 * 12.8px 이 아니라 8px 로 나왔다. 이 표는 두 클래스를 같이 달고 나온다(`screen.tsx` 의 Results).
 */
.deal-table.deal-price-table th,
.deal-table.deal-price-table td {
  padding: 0.8rem 0.75rem;
  border-bottom: 1px solid var(--board-line);
  text-align: left;
  vertical-align: middle;
  white-space: normal;
}

.deal-price-table th:first-child,
.deal-price-table td:first-child {
  padding-left: 1.1rem;
}

/* 마지막 열은 좌우 여백을 같게 둬 가운데 정렬한 값이 열 가운데에 놓인다. */
.deal-price-table th:last-child,
.deal-price-table td:last-child {
  padding-inline: 1.1rem;
}

.deal-price-table thead th {
  border-bottom: 1px solid var(--board-line);
  color: var(--board-dim);
  background: var(--board-tint);
  font-size: 0.8125rem;
  font-weight: 600;
  text-align: center;
}

/* 머리글과 값 모두 열 가운데에 둔다. 금액 블록은 내용 너비만 차지하고 그 안에서 오른쪽 기준선을 지킨다. */
.deal-price-table tbody td {
  text-align: center;
}

.deal-price-table th:first-child {
  width: 32%;
}

.deal-price-table th:not(:first-child):not(:last-child) {
  width: 19%;
}

.deal-price-table th:last-child {
  width: 11%;
}

.deal-price-table tbody tr:last-child > * {
  border-bottom: 0;
}

.deal-price-table tbody th[scope='row'] {
  font-size: 0.9375rem;
  font-weight: 600;
}

.deal-price-table .deal-checked {
  font-size: 0.8125rem;
  color: var(--board-dim);
}

/* 날짜 앞 이름(매장·확인)은 좁은 화면에서만 선다. */
.deal-checked__label {
  display: none;
}

/* 목록 표는 칸마다 아래 선만 쓴다 — `.deal-table` 의 `tr + tr` 윗선을 끈다. */
.deal-price-table tbody tr + tr th,
.deal-price-table tbody tr + tr td {
  border-top: 0;
}

.deal-price-table .device-link {
  display: block;
  color: inherit;
  text-decoration: none;
}

.deal-price-table .price-row:hover > * {
  background: var(--board-tint);
}

/* 행 hover 글자는 운영 `--color-brand-700`(`PhoneDealPage.vue:442`) — `--board-brand-700` 이 그 값이다. */
.deal-price-table .price-row:hover .device-link {
  color: var(--board-brand-700);
}


/* 표 칸의 값: 금액과 통신사 줄을 칸의 오른쪽 기준선에 맞춘다. */
.price-cell {
  display: grid;
  width: 100%;
  gap: 0.18rem;
  justify-items: end;
  text-align: right;
}

/* 값이 없는 칸은 대시만 남기고 칸 가운데에 둔다. */
.price-cell--empty {
  place-items: center;
  text-align: center;
}

/* 구매 조건 이름. 표에서는 머리 줄이 있어 감추고, 좁은 화면 카드에서만 선다. */
.price-cell__label {
  display: none;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

.price-cell__amount {
  font-size: 0.9375rem;
  font-weight: var(--board-weight-bold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 지원금이 기깃값을 넘으면 음수로 나온다 — 운영은 이 값을 브랜드 색으로 강조한다. */
.price-cell__amount[data-subsidy] {
  color: var(--board-accent-text);
}

.price-cell__carriers {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  min-width: 0;
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-normal);
  white-space: nowrap;
}

/*
 * 통신사 색은 여기서만 참조한다. `.deal-filters` 의 칩 색과 같은 값이다 — 레거시
 * `_compare.scss:120-123` 의 `.carrier-tone--*` + `.carrier-text`(값은 `_tokens.scss:8-10`).
 * 상세 가격 줄의 라벨(`.carrier-price-line small`, 레거시 `PhoneDealDetailPage.vue:70,93` 의
 * `small.carrier-text`)도 같은 색을 쓴다.
 */
.price-cell__carrier {
  opacity: 0.62;
}

.price-cell__carrier[data-carrier='SKT'],
.carrier-price-line small[data-carrier='SKT'] {
  color: var(--board-carrier-skt);
}

.price-cell__carrier[data-carrier='KT'],
.carrier-price-line small[data-carrier='KT'] {
  color: var(--board-carrier-kt);
}

.price-cell__carrier[data-carrier='LGU'],
.carrier-price-line small[data-carrier='LGU'] {
  color: var(--board-carrier-lgu);
}

.price-cell__carrier[data-lowest] {
  opacity: 1;
  font-weight: 600;
}

/* 「최저」 딱지는 통신사와 무관한 같은 색을 쓴다. 통신사 구분은 라벨 색이 맡는다. */
.price-cell__carrier em {
  margin-left: 0.18rem;
  padding: 0.04rem 0.22rem;
  color: var(--board-accent-text);
  background: var(--board-notice);
  border-radius: 0.22rem;
  font-size: 0.66rem;
  font-style: normal;
  font-weight: var(--board-weight-bold);
}

.price-cell__empty,
.deal-empty-price,
.carrier-empty {
  color: var(--board-dim);
  font-weight: var(--board-weight-normal);
}

/*
 * 가격 수집 기준. 레거시 `CompareNote` 그대로 접히는 `<details>` 다. 표 카드 안에 넣으면
 * 윗줄 구분선만 남기고 자기 카드는 버린다 — 둥근 모서리 두 개가 맞물려 이음매가 생기지 않게.
 */
.compare-note {
  padding: 0.75rem 1.1rem;
  background: var(--board-surface);
  border: 1px solid var(--board-line);
  border-radius: 0.75rem;
}

.deal-results .deal-table-wrap > .compare-note {
  border: 0;
  border-top: 1px solid var(--board-line);
  border-radius: 0;
}

.compare-note > summary {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  line-height: 1.5;
  cursor: pointer;
  list-style: none;
}

.compare-note > summary::-webkit-details-marker {
  display: none;
}

.compare-note > summary > svg {
  flex: 0 0 auto;
  color: var(--board-accent);
}

.compare-note__title {
  flex: 0 0 auto;
  margin: 0;
  color: var(--board-ink);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: inherit;
}

.compare-note__meta {
  overflow: hidden;
  flex: 1 1 auto;
  min-width: 0;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-normal);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.compare-note__toggle {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.compare-note__toggle span:last-child {
  display: none;
}

.compare-note[open] .compare-note__toggle span:first-child {
  display: none;
}

.compare-note[open] .compare-note__toggle span:last-child {
  display: inline;
}

.compare-note__body {
  margin: 0.7rem 0 0;
  padding-top: 0.7rem;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  line-height: 1.7;
  border-top: 1px solid var(--board-line);
}

.compare-note__facts {
  display: grid;
  gap: 0.35rem;
  margin: 0.6rem 0 0;
}

.compare-note__facts > div {
  display: grid;
  grid-template-columns: 6rem minmax(0, 1fr);
  gap: 0.7rem;
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--board-line);
}

.compare-note__facts > div:last-child {
  border-bottom: 0;
}

.compare-note__facts dt {
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 600;
}

.compare-note__facts dd {
  margin: 0;
  font-size: var(--board-size-caption);
  line-height: 1.6;
}

/*
 * 빈 결과 카드 — 레거시 `AppSurface`(`ui/AppSurface.vue:4`) 위의 `.empty-result`
 * (`PhoneDealPage.vue:444`). 면·선·그림자·모서리 0(`--radius-card` 도 0 — `_tokens.scss:28`)은
 * 카드 토큰 그대로고, 글자는 `--color-muted` → `--board-dim`. 글자 크기는 레거시처럼 본문
 * 크기(1rem)를 물려받는다 — 메타 크기로 내리던 로컬 규칙은 뺐다.
 */
.deal-empty {
  display: grid;
  place-items: center;
  gap: 0.35rem;
  min-height: 12rem;
  padding: var(--board-card-pad);
  border: 1px solid var(--board-line);
  border-radius: var(--board-radius-l);
  background: var(--board-surface);
  box-shadow: var(--board-shadow);
  color: var(--board-dim);
  text-align: center;
}

/* 회차가 아예 없을 때 — 레거시 `.deal-state`(`PhoneDealPage.vue:348-349`): 낮은 카드·잉크 제목. */
.deal-section > .deal-empty {
  min-height: 5.5rem;
  gap: 0.25rem;
}

.deal-section > .deal-empty strong {
  color: var(--board-ink);
}

/* 접기/펼치기는 표 카드 아래 한가운데 선다. 레거시 `.expand-wrap`·`.expand-button` 그대로다. */
.expand-wrap {
  display: flex;
  justify-content: center;
  margin: 0.9rem 0 0;
}

.expand-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-width: 16rem;
  min-height: 2.8rem;
  color: var(--board-ink);
  background: var(--board-surface);
  border: 1px solid var(--board-line);
  border-radius: 0.4rem;
  font-size: var(--board-size-meta);
  font-weight: 600;
  text-decoration: none;
}

.expand-button:hover {
  color: var(--board-accent-text);
  border-color: var(--board-accent);
}

/* 상세. 목록의 표 규칙을 그대로 물려받고 다른 것만 여기 있다. 값은 `PhoneDealDetailPage.vue` 의 scoped 스타일. */

/*
 * 머리 카드. 운영은 흰 판·1px 선·모서리 12·`--shadow-sm`(`PhoneDealDetailPage.vue:278`).
 * 왼쪽에 꺾쇠 링크와 제목, 오른쪽 끝에 최종 수집 시각.
 */
.deal-detail-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.65rem;
  padding: 1.1rem;
  border: 1px solid var(--board-line);
  border-radius: 0.75rem;
  background: var(--board-surface);
  box-shadow: var(--board-shadow);
}

.deal-detail-heading {
  display: flex;
  align-items: flex-start;
  min-width: 0;
  gap: 0.35rem;
}

/* 제목이 두 줄로 감겨도 꺾쇠는 첫 줄 옆에 붙어 있어야 해서 flex-start 로 세우고 살짝 당긴다(`PhoneDealDetailPage.vue:279`). */
.deal-detail-back {
  display: grid;
  flex: none;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  margin-left: -0.4rem;
  /* 레거시 `.detail-eyebrow` radius-sm(.4rem, `PhoneDealDetailPage.vue:280`). */
  border-radius: 0.4rem;
  color: var(--board-dim);
}

.deal-detail-back:hover {
  color: var(--board-accent-text);
  background: var(--board-tint);
}

/* `.compare-title` 수치다(`PhoneDealDetailPage.vue:19`) — 머리 카드 높이 68.4 는 이 한 줄로 정해진다. */
.deal-detail-head h1 {
  min-width: 0;
  margin: 0;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.3;
}

.deal-detail-updated {
  flex: none;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  font-weight: var(--board-weight-normal);
}

/*
 * 상세의 공지 띠 — 머리 카드와 필터 판 사이, 마크업·클래스는 목록의 것과 같다.
 * 칸 간격은 레거시 쌓기 간격 .65rem(`PhoneDealDetailPage.vue` — 머리의 margin-bottom 도 같은 값).
 * 스킨의 `.notice-strip`(0,1,0)이 margin:0 을 깔아 여기선 아래 여백만 얹는다.
 */
.deal-detail .notice-strip {
  margin: 0 0 0.65rem;
}

/*
 * 통신사·가입 방식 필터 판 — 운영 `.offer-filters`(`PhoneDealDetailPage.vue:281`).
 * 칩은 단추가 아니라 `<input type="radio">` + `<label>` 이다 — 상세의 필터는 주소를 안
 * 만드는 화면 안 상태라(머리 주석 7번) `:checked` 만으로 걸러내고 스크립트를 안 쓴다.
 */
.offer-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  margin-bottom: 0.7rem;
  padding: 0.7rem 1.1rem;
  border: 1px solid var(--board-line);
  border-radius: 0.75rem;
  background: var(--board-surface);
}

.offer-filters .filter-group {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.offer-filters .filter-group > strong {
  font-size: var(--board-size-caption);
  font-weight: 600;
  white-space: nowrap;
}

/*
 * 입력은 시각적으로만 숨긴다 — `display: none` 이면 Tab 초점과 화살표 이동이 죽는다.
 * 초점 링은 라벨이 단다(아래 `:focus-visible + label`).
 */
.offer-filters .offer-filter-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/*
 * 칩 값은 공통 필터 칩(위쪽)과 같고 높이만 다르다 — 운영 상세 칩은
 * 32px(`PhoneDealDetailPage.vue:281` 의 `min-height: 2rem`)이라 목록의 2.35rem 을 안 쓴다.
 */
.offer-filters label.filter-chip {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  padding: 0 0.7rem;
}

/*
 * 표 바로 위 주의 문단 — 레거시 `.compare-footnote`(`_compare.scss:172-178`): 위아래 .85rem·좌우
 * `--compare-inset`(1.1rem), 줄높이 1.7, 글자색은 muted 보다 한 단계 진한 ink·muted 반반.
 */
.deal-footnote {
  margin: 0.85rem 1.1rem;
  color: color-mix(in srgb, var(--board-ink) 50%, var(--board-dim));
  font-size: var(--board-size-caption);
  line-height: 1.7;
}

/* 표 바깥 틀 — 운영 `.offer-table-wrap` 모서리 16(`PhoneDealDetailPage.vue:282`). */
.deal-offers .deal-table-wrap {
  overflow: hidden;
  border-radius: 1rem;
}

/*
 * 칸 수치는 전부 운영 `.offer-table` 규칙이다(`PhoneDealDetailPage.vue:282`). `table.` 을 붙이는
 * 이유: 스킨의 `table:not(.board-table) td`(0,1,2)가 클래스 하나짜리 선택자를 특이도로 이겨
 * 칸 여백·정렬이 스킨 기본값으로 돌아간다 — 같은 점수(0,1,2)로 맞세우면 차례로 이긴다.
 */
table.deal-offer-table {
  table-layout: fixed;
}

table.deal-offer-table th,
table.deal-offer-table td {
  padding: 0.8rem 0.7rem;
  border-bottom: 1px solid var(--board-line);
  text-align: center;
  vertical-align: middle;
  white-space: normal;
}

.deal-offer-table thead th {
  background: var(--board-tint);
  font-weight: 600;
  text-align: center;
}

.deal-offer-table tbody tr:last-child td {
  border-bottom: 0;
}

table.deal-offer-table td {
  font-size: var(--board-size-meta);
  font-weight: var(--board-weight-normal);
}

/* 칸 폭 — 매장 16 / 조건 셋 각 21 / 날짜 10 / 원문 11(`PhoneDealDetailPage.vue:282`). */
.deal-offer-table th:first-child {
  width: 16%;
  min-width: 7.5rem;
}

.deal-offer-table th:nth-child(2),
.deal-offer-table th:nth-child(3),
.deal-offer-table th:nth-child(4) {
  width: 21%;
  min-width: 8.5rem;
}

.deal-offer-table th:nth-last-child(2) {
  width: 10%;
  min-width: 6rem;
}

.deal-offer-table th:last-child {
  width: 11%;
  min-width: 7.5rem;
}

/* 통신사별 가격 줄 — 운영 `.carrier-price-stack`·`.carrier-price-line`(`PhoneDealDetailPage.vue:282`). */
.carrier-price-stack {
  display: inline-grid;
  gap: 0.3rem;
}

.carrier-price-line {
  display: grid;
  grid-template-columns: 2.9rem 7rem;
  align-items: baseline;
  gap: 0.45rem;
  min-height: 1.55rem;
}

.carrier-price-line small {
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: 600;
  white-space: nowrap;
}

/* 폰 카드 전용 한 글자 라벨(레거시 `mobileCarrierLabel`). 넓은 화면에서는 숨기고, 43.75rem 아래 블록이 둘을 바꿔 그린다. */
.carrier-price-line .carrier-initial {
  display: none;
}

.carrier-price-line strong {
  font-size: var(--board-size-ui);
  font-weight: var(--board-weight-bold);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum';
  text-align: right;
  white-space: nowrap;
}

.carrier-empty {
  text-align: right;
}

.carrier-empty,
.deal-empty-price {
  color: var(--board-dim);
}

/*
 * 여기서부터 라디오가 실제로 걸러내는 규칙 — 전부 `.deal-detail:has(input:checked)` 다.
 *
 * 통신사를 고르면(레거시 `visibleCarriers`) 그 통신사의 가격 줄만 남기고 다른 통신사 줄을
 * 지운다. 그 통신사 가격이 하나도 없는 매장은 행째 뺀다(레거시 `filteredStores`) — 행의
 * `data-carriers` 는 `storeCarriers` 가 담은, 가격이 하나라도 있는 통신사 집합이다.
 * 가입 방식을 고르면 다른 조건의 열(th·td)을 접는다 — 레거시는 열을 두고 고른 열만 칠했는데,
 * 칸 폭이 고정(`table-layout: fixed`)이라 숨긴 열의 자리는 남은 열로 다시 나뉜다.
 * 둘 다 걸리면 그 조건에서 그 통신사 가격이 있는 매장만 남는다 — 행의
 * `data-carriers-{조건}` 집합으로 보는, 레거시의 AND 다.
 */
.deal-detail:has(input[name='detail-carrier'][value='SKT']:checked) .carrier-price-line:not(:has(> small[data-carrier='SKT'])),
.deal-detail:has(input[name='detail-carrier'][value='KT']:checked) .carrier-price-line:not(:has(> small[data-carrier='KT'])),
.deal-detail:has(input[name='detail-carrier'][value='LGU']:checked) .carrier-price-line:not(:has(> small[data-carrier='LGU'])) {
  display: none;
}

/* 통신사만 골랐을 때 — 어느 조건이든 그 통신사 가격이 없는 매장 행을 뺀다. */
.deal-detail:has(input[name='detail-carrier'][value='SKT']:checked):has(input[name='detail-type'][value='ALL']:checked) .deal-offer-table tbody tr:not([data-carriers~='SKT']),
.deal-detail:has(input[name='detail-carrier'][value='KT']:checked):has(input[name='detail-type'][value='ALL']:checked) .deal-offer-table tbody tr:not([data-carriers~='KT']),
.deal-detail:has(input[name='detail-carrier'][value='LGU']:checked):has(input[name='detail-type'][value='ALL']:checked) .deal-offer-table tbody tr:not([data-carriers~='LGU']) {
  display: none;
}

/* 가입 방식만 골랐을 때 — 그 조건 가격이 없는 매장 행을 뺀다. */
.deal-detail:has(input[name='detail-type'][value='NEW']:checked):has(input[name='detail-carrier'][value='ALL']:checked) .deal-offer-table tbody tr:not([data-types~='NEW']),
.deal-detail:has(input[name='detail-type'][value='PORT_IN']:checked):has(input[name='detail-carrier'][value='ALL']:checked) .deal-offer-table tbody tr:not([data-types~='PORT_IN']),
.deal-detail:has(input[name='detail-type'][value='DEVICE_CHANGE']:checked):has(input[name='detail-carrier'][value='ALL']:checked) .deal-offer-table tbody tr:not([data-types~='DEVICE_CHANGE']) {
  display: none;
}

/* 둘 다 골랐을 때 — 고른 조건에서 고른 통신사 가격이 있어야 행이 남는다. */
.deal-detail:has(input[name='detail-carrier'][value='SKT']:checked):has(input[name='detail-type'][value='NEW']:checked) .deal-offer-table tbody tr:not([data-carriers-new~='SKT']),
.deal-detail:has(input[name='detail-carrier'][value='KT']:checked):has(input[name='detail-type'][value='NEW']:checked) .deal-offer-table tbody tr:not([data-carriers-new~='KT']),
.deal-detail:has(input[name='detail-carrier'][value='LGU']:checked):has(input[name='detail-type'][value='NEW']:checked) .deal-offer-table tbody tr:not([data-carriers-new~='LGU']),
.deal-detail:has(input[name='detail-carrier'][value='SKT']:checked):has(input[name='detail-type'][value='PORT_IN']:checked) .deal-offer-table tbody tr:not([data-carriers-port_in~='SKT']),
.deal-detail:has(input[name='detail-carrier'][value='KT']:checked):has(input[name='detail-type'][value='PORT_IN']:checked) .deal-offer-table tbody tr:not([data-carriers-port_in~='KT']),
.deal-detail:has(input[name='detail-carrier'][value='LGU']:checked):has(input[name='detail-type'][value='PORT_IN']:checked) .deal-offer-table tbody tr:not([data-carriers-port_in~='LGU']),
.deal-detail:has(input[name='detail-carrier'][value='SKT']:checked):has(input[name='detail-type'][value='DEVICE_CHANGE']:checked) .deal-offer-table tbody tr:not([data-carriers-device_change~='SKT']),
.deal-detail:has(input[name='detail-carrier'][value='KT']:checked):has(input[name='detail-type'][value='DEVICE_CHANGE']:checked) .deal-offer-table tbody tr:not([data-carriers-device_change~='KT']),
.deal-detail:has(input[name='detail-carrier'][value='LGU']:checked):has(input[name='detail-type'][value='DEVICE_CHANGE']:checked) .deal-offer-table tbody tr:not([data-carriers-device_change~='LGU']) {
  display: none;
}

/* 가입 방식을 고르면 다른 조건의 열을 접는다 — 머리 칸과 값 칸 둘 다. */
.deal-detail:has(input[name='detail-type'][value='NEW']:checked) .deal-offer-table [data-type]:not([data-type='NEW']),
.deal-detail:has(input[name='detail-type'][value='PORT_IN']:checked) .deal-offer-table [data-type]:not([data-type='PORT_IN']),
.deal-detail:has(input[name='detail-type'][value='DEVICE_CHANGE']:checked) .deal-offer-table [data-type]:not([data-type='DEVICE_CHANGE']) {
  display: none;
}

/*
 * 「원문 확인」 단추 — 운영 `.outbound-link`(`PhoneDealDetailPage.vue:282`). brand-50 은
 * `--board-notice`(#edf8f5, 다크는 #16302a)가 맡고, 팔레트에 없는 brand-200 선은 강조 25% 를
 * 면에 섞는다 — 리터럴이면 다크에서 연초록 선이 그대로 남는다. brand-700 글자는
 * `--board-brand-700` 이 그 값이다.
 */
.deal-outbound {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 2.35rem;
  padding: 0 0.65rem;
  border: 1px solid color-mix(in srgb, var(--board-accent) 25%, var(--board-surface));
  /* 레거시 `.outbound-link` radius-sm(.4rem, `PhoneDealDetailPage.vue:282`). */
  border-radius: 0.4rem;
  background: var(--board-notice);
  color: var(--board-brand-700);
  font-size: var(--board-size-caption);
  font-weight: 600;
  white-space: nowrap;
}


/*
 * 태블릿 대(701~959px) — 아직 표이지만 마지막 칸(11%)이 「원문 확인」 단추(88.8px)보다
 * 좁아 단추가 칸 밖으로 잘린다. 이 대에서는 단추를 아이콘만으로 줄인다 — 글자는 `.gb-sr-only`
 * 와 같은 숨김으로 남겨 접근 이름을 잃지 않는다(`<a>` 의 `aria-label` 도 그대로다).
 * 아래쪽은 700.02 부터다 — 700 은 레거시 `below(tablet-narrow)` 에 포함돼 카드형이다.
 */
@media (min-width: 700.02px) and (max-width: 59.99rem) {
  .deal-outbound .deal-outbound-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .deal-outbound {
    gap: 0;
    width: 2.35rem;
    justify-content: center;
    padding: 0;
  }

  /*
   * 같은 대에서 조건 칸(21%, ≈125px)은 `2.9rem 7rem`(≈158px) 가격 줄보다 좁아 금액이
   * 옆 칸 위로 넘쳤다. 폰 카드와 같이 한 글자 라벨로 바꾸고 줄을 `1rem minmax(0,1fr)`
   * 로 접어, 금액을 작게 죄어 칸 안에 머물게 한다.
   */
  .deal-offer-table .carrier-price-line {
    grid-template-columns: 1rem minmax(0, 1fr);
    gap: 0.2rem;
  }

  .deal-offer-table .carrier-price-line small {
    text-align: center;
  }

  .deal-offer-table .carrier-price-line .carrier-name {
    display: none;
  }

  .deal-offer-table .carrier-price-line .carrier-initial {
    display: inline;
  }

  .deal-offer-table .carrier-price-line strong {
    font-size: clamp(0.78rem, 1.6vw, var(--board-size-ui));
  }
}

/*
 * 폰 상세 — 레거시 `below(tablet-narrow)`(700px 포함) 분기(`PhoneDealDetailPage.vue:283`).
 * 레거시는 같은 가격을 `<ol class="mobile-offers">` 로 한 번 더 그렸는데, 여기서는 표 줄
 * 하나를 카드 한 장으로 접는다 — 목록 표(`.deal-price-table`, 아래 50rem 블록)와 같은
 * 방식이다. 칸마다 붙는 조건 이름은 `td` 의 `data-label` 이 `::before` 로 그린다.
 */
@media (max-width: 43.75rem) {
  .deal-detail-head {
    flex-direction: column;
    align-items: flex-start;
    padding: 1.2rem 1rem;
  }

  /* 운영 `below(tablet-narrow)` 의 `.offer-filters` — 그룹이 세로로 서고 칩은 4칸 같은 폭 격자다.
     안쪽 여백은 운영 `--compare-inset` — 800 이하는 .9rem, 560 이하는 .8rem(`_compare.scss:181·196`). */
  .offer-filters {
    display: grid;
    gap: 0.6rem;
    padding: 0.7rem 0.9rem;
  }

  .offer-filters .filter-group {
    align-items: flex-start;
    flex-direction: column;
  }

  .offer-filters .filter-chips {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.3rem;
    width: 100%;
  }

  .offer-filters label.filter-chip {
    justify-content: center;
  }

  /* 카드들이 스스로 선을 들므로 바깥 틀은 벗긴다. */
  .deal-offers .deal-table-wrap {
    overflow: visible;
    border: 0;
    border-radius: 0;
    background: transparent;
  }

  .deal-offer-table {
    display: block;
  }

  .deal-offer-table thead {
    display: none;
  }

  .deal-offer-table tbody {
    display: grid;
    gap: 0.65rem;
  }

  /* 한 줄 = 카드 한 장: 윗줄 매장, 가운데 조건 셋의 3열 격자, 아랫줄 날짜·원문 단추
     * (레거시 `.mobile-offers > li` 의 header·`.mobile-price-grid`·footer 차례). */
  .deal-offer-table tbody tr {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-areas:
      'store store store'
      'new port change'
      'checked checked out';
    padding: 0.9rem;
    border: 1px solid var(--board-line);
    border-radius: 0.75rem;
    background: var(--board-surface);
  }

  /* 칸 여백·칸 선은 카드가 맡는다 — 여백은 줄이, 선은 격자가 그린다. `table.` 은
     `.deal-table tbody tr + tr td`(0,1,4)의 윗선을 (0,1,5)로 누르려고 붙인다 — 안 누르면
     두 번째 카드부터 매장 이름 위에 줄이 선다. */
  table.deal-offer-table tbody tr > td {
    padding: 0;
    border: 0;
    white-space: normal;
  }

  .deal-offer-table td:nth-child(1) {
    grid-area: store;
    align-self: center;
    font-size: var(--board-size-meta);
    font-weight: var(--board-weight-normal);
    text-align: left;
  }

  /* 아랫줄 왼쪽은 레거시 footer 의 `<time>` — 「최근 가격표 게시 …」 문구까지 붙는다. */
  .deal-offer-table td:nth-child(5) {
    grid-area: checked;
    align-self: center;
    justify-self: start;
    color: var(--board-dim);
    font-size: var(--board-size-caption);
    text-align: left;
  }

  .deal-offer-table td:nth-child(5)::before {
    content: '최근 가격표 게시 ';
  }

  .deal-offer-table td:nth-child(6) {
    grid-area: out;
    display: flex;
    justify-content: flex-end;
  }

  .deal-offer-table .deal-outbound {
    min-height: 2.25rem;
  }

  /* 가운데 3열 격자 — 운영 `.mobile-price-grid`. 위아래 선과 칸 사이 왼쪽 선을 칸이 든다. */
  .deal-offer-table td:nth-child(2) {
    grid-area: new;
  }

  .deal-offer-table td:nth-child(3) {
    grid-area: port;
  }

  .deal-offer-table td:nth-child(4) {
    grid-area: change;
  }

  /*
   * 가입 방식을 고르면 남은 조건 칸 하나가 카드 가로를 다 쓰게 한다 — 숨긴 칸의 격자 자리를
   * 비워 두지 않기 위해 `grid-template-areas` 를 한 칸짜리로 바꾼다. `+` 형제의 왼쪽 선은
   * 숨긴 칸 기준으로도 그려지므로 남은 칸에서 뗀다.
   */
  .deal-detail:has(input[name='detail-type'][value='NEW']:checked) .deal-offer-table tbody tr,
  .deal-detail:has(input[name='detail-type'][value='PORT_IN']:checked) .deal-offer-table tbody tr,
  .deal-detail:has(input[name='detail-type'][value='DEVICE_CHANGE']:checked) .deal-offer-table tbody tr {
    grid-template-areas:
      'store store store'
      'picked picked picked'
      'checked checked out';
  }

  .deal-detail:has(input[name='detail-type'][value='NEW']:checked) .deal-offer-table td[data-type='NEW'],
  .deal-detail:has(input[name='detail-type'][value='PORT_IN']:checked) .deal-offer-table td[data-type='PORT_IN'],
  .deal-detail:has(input[name='detail-type'][value='DEVICE_CHANGE']:checked) .deal-offer-table td[data-type='DEVICE_CHANGE'] {
    grid-area: picked;
    border-left: 0;
  }

  .deal-offer-table .deal-offer-price {
    display: grid;
    grid-template-rows: auto 1fr;
    align-content: stretch;
    gap: 0.4rem;
    margin: 0.7rem 0;
    padding: 0.65rem 0.2rem;
    border-block: 1px solid var(--board-line);
    text-align: center;
  }

  .deal-offer-table .deal-offer-price + .deal-offer-price {
    border-left: 1px solid var(--board-line);
  }

  /* 마지막 카드: 넓은 표의 `tbody tr:last-child td{border-bottom:0}`(위)가 카드 칸의
     * `border-block` 아랫선까지 지워 1px 낮아진다 — 카드 모드에서 되돌린다. */
  .deal-offer-table tbody tr:last-child td.deal-offer-price {
    border-bottom: 1px solid var(--board-line);
  }

  .deal-offer-table .deal-offer-price::before {
    content: attr(data-label);
    color: var(--board-dim);
    font-size: var(--board-size-caption);
  }

  /* 폰의 가격 줄은 칸이 좁아 라벨 1rem 에 값을 눌러 담는다(운영 `mobileCarrierLabel` 자리). */
  .deal-offer-table .carrier-price-stack {
    width: 100%;
    align-self: start;
    gap: 0.35rem;
  }

  .deal-offer-table .carrier-price-line {
    grid-template-columns: 1rem minmax(0, 1fr);
    gap: 0.2rem;
    min-height: 1.3rem;
  }

  .deal-offer-table .carrier-price-line small {
    text-align: center;
  }

  /* 폰 카드는 한 글자 라벨로 바꿔 그린다(레거시 `mobileCarrierLabel` — S/K/L). */
  .deal-offer-table .carrier-price-line .carrier-name {
    display: none;
  }

  .deal-offer-table .carrier-price-line .carrier-initial {
    display: inline;
  }

  .deal-offer-table .carrier-price-line strong {
    font-size: clamp(0.78rem, 3.3vw, var(--board-size-meta));
  }

  /* 빈 가격 칸의 「-」는 레거시가 크기를 따로 두지 않아 body 의 1rem/1.6 = 16/25.6 을
     * 물려받는다(`PhoneDealDetailPage.vue:283` `.mobile-price-grid>div>.empty-price`) —
     * 여기는 칸이 `td` 라 표의 meta(14/22.4)를 받으므로 운영 높이로 되돌린다. */
  .deal-offer-table .deal-empty-price {
    display: grid;
    width: 100%;
    height: 100%;
    place-items: center;
    font-size: 1rem;
  }

  /* 560 이하는 운영 `--compare-inset` 이 .8rem 으로 준다(`_compare.scss:196` `below(sm)`). */
  @media (max-width: 35rem) {
    .offer-filters {
      padding: 0.7rem 0.8rem;
    }

    .deal-offer-table tbody tr {
      padding: 0.9rem 0.8rem;
    }
  }
}

/*
 * 태블릿 소(701~800px)의 필터 판 — 레거시 `below(tablet-wide)`(800 포함)가 칩 묶음을
 * 자동 맞춤 격자로 접고 칸 패딩·줄높이를 좁힌다(`_filters.scss:69-78`). 이 대에서도
 * `--compare-inset` 은 .9rem(`_compare.scss:181`)이라 판 안쪽 여백도 같이 준다.
 * 칩 높이는 2rem 유지 — `_filters.scss` 의 2.1rem 은 레거시에서 `.filter-group .filter-chip`
 * 의 2rem 에 지므로 여기서는 아예 적지 않는다.
 */
@media (min-width: 700.02px) and (max-width: 50rem) {
  /* 머리 카드의 좌우도 이 대의 `--compare-inset` .9rem — 레거시 `.detail-head` 의
     `padding: 1.1rem var(--compare-inset)`(`PhoneDealDetailPage.vue:278`)에
     `_compare.scss:182` 의 값. 700 이하는 위 43.75rem 블록의 1rem(`PhoneDealDetailPage.vue:283`)이 잡는다. */
  .deal-detail-head {
    padding-inline: 0.9rem;
  }

  .offer-filters {
    padding: 0.7rem 0.9rem;
  }

  .offer-filters .filter-chips {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(4.25rem, 1fr));
    gap: 0.3rem;
  }

  .offer-filters .filter-chips > * {
    min-width: 0;
    padding: 0.25rem 0.4rem;
    line-height: 1.3;
    white-space: normal;
  }
}

/*
 * 좁은 화면의 주의 문단 좌우 — `--compare-inset` 이 800 이하 .9rem, 560 이하 .8rem 으로 준다.
 * 공지 띠 링크도 같은 값 — 레거시 `.deal-notice a` 의 `padding: .5rem var(--compare-inset)`
 * (`PhoneDealNotices.vue:35`). 700 이하 블록이 이 링크는 건드리지 않으므로 561~700 도 .9rem 이다.
 */
@media (max-width: 50rem) {
  .deal-footnote {
    margin: 0.85rem 0.9rem;
  }

  .deal-detail .notice-strip a {
    padding-inline: 0.9rem;
  }
}

@media (max-width: 35rem) {
  .deal-footnote {
    margin: 0.85rem 0.8rem;
  }

  .deal-detail .notice-strip a {
    padding-inline: 0.8rem;
  }
}

@media (max-width: 50rem) {
  /*
   * 좁은 화면의 시세표 카드. 표 하나를 그대로 두고 줄 하나를 카드 한 장으로 접는다 —
   * 레거시가 `<table>` 과 `<ol>` 로 두 번 그리던 것을 CSS 만으로 흉내 낸다. 머리 줄은 감추고
   * 기기명·날짜를 첫 줄에, 구매 조건을 한 줄씩 아래에 둔다(운영 `.mobile-row` 모양).
   * 분기는 레거시 `below(tablet-wide)` = 800px 포함(`PhoneDealPage.vue:467`).
   */
  .deal-results .deal-table-wrap {
    overflow: visible;
    background: transparent;
    border: 0;
    border-radius: 0;
  }

  /* wrap 이 투명해져 감싸는 카드가 없다. 수집 기준은 자기 카드를 되찾는다. */
  .deal-results .deal-table-wrap > .compare-note {
    margin-top: 0.65rem;
    padding: 0.75rem 0.9rem;
    background: var(--board-surface);
    border: 1px solid var(--board-line);
    border-radius: 0.75rem;
  }

  .compare-note > summary {
    flex-wrap: wrap;
    gap: 0.35rem;
  }

  /* 요약 줄은 그림·제목·「자세히」가 첫 줄, 확인 날짜는 아래 줄을 다 쓴다. */
  .compare-note > summary > svg {
    order: 1;
  }

  .compare-note__title {
    order: 2;
  }

  .compare-note__toggle {
    order: 3;
  }

  .compare-note__meta {
    order: 4;
    flex: 1 1 100%;
    margin-top: 0.15rem;
    white-space: normal;
  }

  .compare-note__facts > div {
    grid-template-columns: 5.5rem minmax(0, 1fr);
  }

  .deal-price-table {
    display: block;
  }

  .deal-price-table thead {
    display: none;
  }

  .deal-price-table tbody {
    display: block;
    background: var(--board-surface);
    border: 1px solid var(--board-line);
    border-radius: 0.75rem;
  }

  .deal-price-table tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    padding: 0.6rem 0.9rem;
  }

  /* 카드 사이는 줄의 윗선 하나로 가른다 — 칸마다 붙던 아래선은 여기서 안 쓴다. */
  .deal-price-table tbody tr + tr {
    border-top: 1px solid var(--board-line);
  }

  .deal-price-table tbody tr + tr th,
  .deal-price-table tbody tr + tr td {
    border-top: 0;
  }

  /* 카드 안에서는 칸 여백·칸 테두리를 안 쓴다 — 여백은 줄이, 선은 카드가 맡는다. */
  .deal-table.deal-price-table tbody tr > *,
  .deal-table.deal-price-table tbody tr > *:first-child,
  .deal-table.deal-price-table tbody tr > *:last-child {
    padding: 0;
    border: 0;
  }

  .deal-price-table tbody th[scope='row'] {
    order: 1;
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.9375rem;
    font-weight: 600;
  }

  /* 날짜 둘은 기기명 옆으로 붙여 오른쪽 끝에 민다. */
  .deal-price-table .deal-checked {
    order: 2;
    flex: 0 0 auto;
    display: inline-flex;
    gap: 0.2rem;
    text-align: left;
  }

  .deal-price-table .deal-checked + .deal-checked {
    margin-left: 0.35rem;
  }

  .deal-checked__label {
    display: inline;
  }

  .deal-price-table tbody td.deal-price {
    order: 3;
    flex: 1 1 100%;
    margin-top: 0.3rem;
    text-align: left;
  }

  /* 운영은 값이 없는 구매 조건 줄을 아예 안 그린다. 표에서는 접어 감춘다. */
  .deal-price-table tbody td.deal-price-empty {
    display: none;
  }

  /* 좁은 화면 한 줄: 구매 조건 · 금액 · 통신사 순으로 붙인다. */
  .deal-price-table .price-cell {
    grid-template-columns: 3.6rem auto minmax(0, 1fr);
    align-items: baseline;
    gap: 0.4rem;
    justify-items: stretch;
    text-align: left;
  }

  .deal-price-table .price-cell__label {
    display: block;
  }

  .deal-price-table .price-cell__carriers {
    overflow: hidden;
    justify-content: flex-end;
  }

  .deal-price-table .price-cell__carrier {
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .compare-head {
    padding: 0 0.9rem;
  }

  .deal-filters {
    padding: 0.7rem 0.9rem 0.9rem;
  }

  .deal-filters > summary {
    margin: 0 0 0.6rem;
    padding: 0 0 0.55rem;
  }

  /* 좁은 화면의 머리에는 요약이 안 선다(운영). 「가격 조건 … 닫기」만 남는다. */
  .filter-summary {
    display: none;
  }

  .filter-rows {
    gap: 0.6rem;
  }

  .filter-row {
    grid-template-columns: 4.6rem minmax(0, 1fr);
    gap: 0.45rem;
    align-items: start;
  }

  /* 줄 높이가 아니라 이 여백이 이름과 첫 칩의 윗줄을 맞춘다(운영 6.08px). */
  .filter-row strong {
    margin-top: 0.38rem;
    font-size: 0.875rem;
  }

  .sub-region-row {
    padding: 0.45rem 0;
    box-shadow: 0 0 0 0.4rem var(--board-tint);
  }

  .filter-actions {
    align-items: flex-end;
    flex-direction: column;
  }

  .filter-row-pair {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.55rem;
  }

  .compare-toolbar {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.5rem;
    padding: 0.8rem 0.9rem 0.6rem;
  }

  .compare-toolbar__controls {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.45rem;
  }

  /* 칸이 절반이라 12rem 을 내려놓는다. 안 그러면 두 단추가 폭을 넘어 가로로 새어 나간다. */
  .select-trigger {
    min-width: 0;
  }
}

/*
 * 운영은 560(below(sm)) 에서 안쪽 여백 `--compare-inset` 을 .9 → .8rem 으로 한 번 더 줄인다
 * (`_compare.scss:196`). 시세 목록에서 그 값을 쓰는 자리만 같이 줄인다.
 */
@media (max-width: 35rem) {
  .compare-head {
    padding-inline: 0.8rem;
  }

  .deal-filters {
    padding-inline: 0.8rem;
  }

  .deal-results .deal-table-wrap > .compare-note {
    padding-inline: 0.8rem;
  }

  .deal-price-table tbody tr {
    padding-inline: 0.8rem;
  }

  .compare-note__facts > div {
    grid-template-columns: 1fr;
    gap: 0.2rem;
  }

  .compare-toolbar {
    padding-inline: 0.8rem;
  }
}

/*
 * 리뷰 본문의 시세 카드(`plugins/phonedeal/src/card.ts`). 레거시 `review-markdown/review.css` 311-390
 * 을 스킨 토큰으로 다시 짠다 — 알뜰폰·시세표와 같은 원칙이고, 값(테두리·바탕·글자)은 `--board-*`
 * 만 쓴다. 레거시가 준 파랑 기운(#d9e2ef·#f7fafd)은 스킨에 그 토큰이 없어 안 가져온다.
 *
 * **단추는 `a` 를 선택자에 박는다.** 스킨이 글 본문 링크에 밑줄과 글자색을 준다
 * (`.post .gb-body a`, 특이도 0,2,1). 클래스만으로는(0,2,0) 못 이겨서 밑줄이 단추 위에 남는다.
 * `a` 를 붙여 (0,2,1) 로 맞추면 이 파일이 스킨 시트 뒤에 실려(머리 주석) 차례로 이긴다 —
 * 남의 테마를 이기는 자리를 `!important` 대신 이렇게 잡는다. 값이 아니라 차례로 푸는 것이라
 * 다음 스킨이 같은 규칙을 갖고 오면 그때 다시 본다.
 */
.embed-phonedeal-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--board-space-4);
  border: 1px solid var(--board-line);
  border-radius: var(--board-radius);
  background: var(--board-tint);
  padding: var(--board-space-4) var(--board-space-4);
}

.embed-phonedeal-title {
  font-weight: var(--board-weight-bold);
  letter-spacing: -0.03em;
}

.embed-phonedeal-note {
  margin-top: var(--board-space-1);
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  word-break: keep-all;
}

.embed-phonedeal-card a.embed-phonedeal-button,
.embed-phonedeal-card span.embed-phonedeal-button {
  border-radius: 999px;
  background: var(--board-ink);
  color: var(--board-on-ink);
  padding: var(--board-space-2) var(--board-space-4);
  font-size: var(--board-size-meta);
  font-weight: var(--board-weight-bold);
  white-space: nowrap;
  text-decoration: none;
}

/* 값이 없는 자리에도 단추 모양은 서지만, 눌리는 자리가 아니라는 것만 손끝에 알린다. */
.embed-phonedeal-button-dead {
  cursor: default;
}

/*
 * 값이 채워진 카드. 껍데기와 같은 테두리 안이지만 값이 주인공이라 좌우로 안 가르고 값 줄을
 * 통째로 넓게 쓴다 — 단추는 값 아래로 내려간다.
 */
.embed-phonedeal-card.embed-phonedeal-live {
  flex-direction: column;
  align-items: stretch;
  gap: var(--board-space-3);
}

.embed-phonedeal-live .embed-phonedeal-body {
  width: 100%;
}

.embed-phonedeal-live .embed-phonedeal-button {
  align-self: flex-start;
}

.embed-phonedeal-device {
  margin-top: 2px;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

.embed-phonedeal-prices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--board-space-2);
  margin-top: var(--board-space-2);
}

/* 가입유형 한 칸. 폭을 안 고정한다 — 유형이 하나뿐인 기종도 흔하다(레거시 주석). */
.embed-phonedeal-price {
  flex: 1 1 7.25rem;
  border: 1px solid var(--board-line);
  border-radius: var(--board-radius);
  background: var(--board-surface);
  padding: var(--board-space-2) var(--board-space-3) var(--board-space-2);
}

.embed-phonedeal-price-type {
  display: block;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

.embed-phonedeal-price-amount {
  display: block;
  margin-top: 2px;
  color: var(--board-ink);
  font-size: var(--board-size-head);
  font-weight: var(--board-weight-bold);
  letter-spacing: -0.04em;
  /* 값은 자릿수로 읽는다. 폭이 흔들리면 위아래 칸이 어긋나 보인다. */
  font-variant-numeric: tabular-nums;
}

.embed-phonedeal-price-carrier {
  display: block;
  margin-top: 1px;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

/*
 * 리뷰 본문 블록(`plugins/review/src/blocks`). 레거시 `review-markdown/review.css` 에서 시세 카드
 * (310-387행)를 뺀 나머지를 옮긴다 — 클래스는 렌더러가 내는 이름(`embed-review-*`), 색은 스킨
 * 토큰(`--board-*`)이다. 톤과 강조색(썰 등뼈·결론 상자·도넛 조각·주황 경고)은 값으로 남긴다.
 *
 * **스킨이 글 본문에 다는 규칙과 부딪히는 자리가 있다.** `.post .gb-body` 아래 `p`·`a`·`blockquote`·
 * `table`·`th`·`td`·`img`·`pre` 규칙(모두 특이도 0,2,1)이 바탕·여백을 정하므로, 같은 속성을 만지는
 * 규칙은 선택자를 한 겹 더 얹어 (0,2,1)로 맞춰 이긴다 — 이 파일이 스킨 시트 뒤에 실려 차례로
 * 앞선다(머리 주석·시세 카드와 같은 방식). 안 부딪히는 규칙은 그대로 둔다.
 */

/* 모든 블록에 붙는 바깥 여백. */
.embed-review-block {
  margin: 1.6em 0;
}

/* 렌더러가 이름을 못 알아본 블록. 경고 톤(주황)이라 값으로 남긴다.
   `pre` 로 나오므로 스킨의 `.post .gb-body pre`(0,2,1) 바탕을 이겨야 한다. */
pre.embed-review-block.embed-review-unknown {
  background: #fff7ed;
  border: 1px solid #fdba74;
}

/* ── 도넛 대시보드 ─────────────────────────────────────────────── */
.embed-review-pie {
  border: 1px solid var(--board-line);
  border-radius: 17px;
  padding: var(--board-space-5);
  background: var(--board-tint);
}

.embed-review-pie-head {
  margin-bottom: var(--board-space-4);
}

.embed-review-pie-title {
  font-size: var(--board-size-head);
  font-weight: var(--board-weight-bold);
  letter-spacing: -0.03em;
}

.embed-review-pie-note {
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  margin-top: 2px;
}

.embed-review-pie-foot {
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  margin-top: var(--board-space-4);
  padding-top: var(--board-space-3);
  border-top: 1px solid var(--board-line);
}

/*
 * 판은 세 칸이고 좁아지면 한 칸으로 접는다. 접힌 뒤에는 도넛과 범례가 좌우로 서야
 * 세로가 무한정 길어지지 않는다.
 */
.embed-review-pie-grid {
  display: grid;
  /*
   * 세 판이 **한 줄에 서야** 대조가 보인다 ─ "좋다는 항목 / 아쉬운 항목 / 그래서 뭘
   * 권하나" 는 나란히 놓일 때 한눈에 읽히는 그림이고, 셋째가 아래로 접히면 그냥
   * 도넛 세 개가 된다.
   */
  grid-template-columns: repeat(auto-fit, minmax(152px, 1fr));
  gap: var(--board-space-2);
}

.embed-review-pie-card {
  background: var(--board-surface);
  border: 1px solid var(--board-line);
  border-radius: 14px;
  padding: var(--board-space-3) var(--board-space-3);
}

.embed-review-pie-ring-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: var(--board-space-3);
}

/* 가운데를 뚫는 것은 `inset` 원이다. 배경이 흰 카드라 흰 원이 구멍으로 읽힌다. */
.embed-review-pie-ring {
  width: 118px;
  height: 118px;
  border-radius: 50%;
  position: relative;
}

.embed-review-pie-ring::after {
  content: '';
  position: absolute;
  inset: var(--board-space-6);
  border-radius: 50%;
  background: var(--board-surface);
}

.embed-review-pie-center {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  text-align: center;
  padding: 0 var(--board-space-6);
  word-break: keep-all;
}

.embed-review-pie-center b {
  font-size: var(--board-size-read);
  color: var(--board-text);
  line-height: var(--board-leading-tight);
}

.embed-review-pie-legend {
  display: grid;
  grid-template-columns: 10px 1fr 34px;
  gap: var(--board-space-2);
  align-items: center;
  margin: var(--board-space-1) 0;
  font-size: var(--board-size-caption);
}

.embed-review-pie-swatch {
  width: 9px;
  height: 9px;
  border-radius: 3px;
}

.embed-review-pie-name {
  color: var(--board-text);
  word-break: keep-all;
}

.embed-review-pie-legend b {
  text-align: right;
}

/* ── 먼저 결론 ─────────────────────────────────────────────── */
/*
 * 결론 상자는 어두운 판이라 톤으로 남긴다 — 밝은 바탕 토큰으로 바꾸면 판이 사라진다.
 * 안쪽 `p` 는 스킨 `.post .gb-body p`(0,2,1)가 여백을 정하므로 선택자를 얹어 이긴다.
 */
.embed-review-finding {
  background: #1c1f24;
  color: #e9ebee;
  border-radius: 16px;
  padding: var(--board-space-5) var(--board-space-6);
}

.embed-review-finding-label {
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-bold);
  letter-spacing: 0.09em;
  color: #9aa3ad;
  margin-bottom: var(--board-space-2);
}

.embed-review-block.embed-review-finding p {
  margin: 0 0 var(--board-space-2);
  line-height: var(--board-leading-read);
}

.embed-review-block.embed-review-finding p:last-child {
  margin-bottom: 0;
}

/* 결론 상자는 먼저 결론과 같은 어둠을 쓰되, 마지막 상자라 조금 더 눌러 앉힌다. */
.embed-review-verdict {
  background: #14171b;
}

/* ── 썰 카드 ─────────────────────────────────────────────── */
/*
 * 320px 이면 넓은 화면에서 석 줄이 서고 한 장이 370px 가 된다. 카드는 훑는 물건이고,
 * 훑으려면 한 줄이 문장이어야 한다. 연달아 선 story 블록은 렌더러가 이 격자 하나로 합친다.
 */
.embed-review-story {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--board-space-3);
}

/*
 * **카드 바탕은 넷 다 흰색이다.** 톤마다 바탕을 칠했더니 열다섯 장이 초록·분홍·파랑
 * 조각보가 됐다. 카드가 스물이 넘게 늘어서는 글에서 바탕색은 신호가 아니라 얼룩이다.
 * 톤은 왼쪽 등뼈 한 줄과 꼬리표 글자색으로만 남긴다.
 */
.embed-review-story-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--board-line);
  border-left: 3px solid #c8ccd1;
  border-radius: 14px;
  padding: var(--board-space-4);
  background: var(--board-surface);
}

/* 등뼈와 꼬리표 색은 톤이라 값으로 남긴다. */
.embed-review-story-good {
  border-left-color: #4b7a63;
}
.embed-review-story-hot {
  border-left-color: #a05a52;
}
.embed-review-story-weird {
  border-left-color: #9a7b3f;
}
.embed-review-story-blue {
  border-left-color: #4a6382;
}

.embed-review-story-tag {
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  font-weight: var(--board-weight-bold);
}

.embed-review-story-good .embed-review-story-tag {
  color: #4b7a63;
}
.embed-review-story-hot .embed-review-story-tag {
  color: #a05a52;
}
.embed-review-story-weird .embed-review-story-tag {
  color: #9a7b3f;
}
.embed-review-story-blue .embed-review-story-tag {
  color: #4a6382;
}

.embed-review-story-headline {
  font-size: var(--board-size-read);
  font-weight: var(--board-weight-bold);
  line-height: var(--board-leading-tight);
  letter-spacing: -0.03em;
  margin: var(--board-space-1) 0 var(--board-space-2);
  word-break: keep-all;
}

/*
 * 카드 안의 인용은 본문 인용과 다른 물건이다. 왼쪽 굵은 선을 그대로 두면 카드 안에
 * 또 하나의 상자가 생겨 색이 두 겹으로 읽힌다. 여기서는 글자만 남긴다.
 *
 * **`.embed-review-block` 을 한 겹 더 얹은 것은 무게 때문이다.** 스킨이 글 본문 인용에
 * 바탕과 왼쪽 선을 준다(`.post .gb-body blockquote`, 0,2,1). 카드+인용(0,2,0)이면 그쪽이
 * 이겨 이 규칙이 통째로 무시되고 카드 안에 색 다른 상자가 또 생긴다.
 */
.embed-review-block .embed-review-story-card .embed-review-story-quote {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-size: var(--board-size-caption);
  color: var(--board-text);
  line-height: var(--board-leading-read);
  word-break: keep-all;
}

/* 발은 바닥에 붙인다. 격자가 카드를 같은 높이로 늘리므로, 안 붙이면 짧은 카드의
   출처 줄만 허공에 뜬다. */
.embed-review-story-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--board-space-1);
  margin-top: auto;
  padding-top: var(--board-space-2);
  font-size: var(--board-size-caption);
  color: var(--board-dim);
}

/* 출처 링크는 스킨의 `.post .gb-body a`(0,2,1)가 밑줄과 글자색을 준다.
   선택자를 한 겹 얹어 (0,2,1)로 맞춰 이기고 밑줄만 뗀다. */
.embed-review-block .embed-review-story-foot a {
  color: #496c97;
  text-decoration: none;
  white-space: nowrap;
}

/* ── 그림 ─────────────────────────────────────────────── */
.embed-review-image {
  margin: 1.6em 0;
}

/* 스킨이 글 본문 그림에 둥근 모서리를 준다(`.post .gb-body img`, 0,2,1).
   선택자를 얹어 이겨 카드와 같은 14px 로 맞춘다. */
.embed-review-block.embed-review-image img {
  width: 100%;
  border-radius: 14px;
  display: block;
}

.embed-review-image figcaption {
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  margin-top: var(--board-space-2);
  font-style: italic;
}

.embed-review-image-asset {
  font-style: normal;
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  background: var(--board-tint);
  border-radius: 5px;
  padding: 1px var(--board-space-1);
}

.embed-review-image-missing {
  border: 1px dashed var(--board-rule);
  border-radius: 14px;
  padding: var(--board-space-7);
  text-align: center;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

/* ── 막대 ─────────────────────────────────────────────── */
/* 막대는 길이로 순서를 읽는 그림이다. 이름·막대·수를 한 줄에 고정폭으로 세운다. */
.embed-review-bar {
  border: 1px solid var(--board-line);
  border-radius: 17px;
  padding: var(--board-space-5);
  background: var(--board-tint);
}

.embed-review-bar-rows {
  display: grid;
  gap: var(--board-space-2);
}

.embed-review-bar-row {
  display: grid;
  grid-template-columns: minmax(96px, 148px) 1fr 34px;
  align-items: center;
  gap: var(--board-space-2);
}

.embed-review-bar-label {
  font-size: var(--board-size-caption);
  color: var(--board-text);
  word-break: keep-all;
}

.embed-review-bar-track {
  background: var(--board-tint-2);
  border-radius: 999px;
  height: 15px;
}

.embed-review-bar-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
}

.embed-review-bar-value {
  font-size: var(--board-size-caption);
  text-align: right;
  color: var(--board-text);
}

/* ── 대조 ─────────────────────────────────────────────── */
.embed-review-compare {
  border: 1px solid var(--board-line);
  border-radius: 14px;
  padding: var(--board-space-4) var(--board-space-4);
  background: var(--board-surface);
}

.embed-review-cmp-title {
  font-weight: var(--board-weight-bold);
  font-size: var(--board-size-read);
  margin-bottom: var(--board-space-2);
  letter-spacing: -0.03em;
}

.embed-review-cmp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--board-space-2);
}

.embed-review-cmp-col {
  border-radius: 11px;
  padding: var(--board-space-3) var(--board-space-3);
  background: var(--board-tint);
}

/* 한국 쪽 강조는 톤이라 값으로 남긴다. */
.embed-review-cmp-col-kr {
  background: #eef4fb;
}

.embed-review-cmp-label {
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-bold);
  color: var(--board-dim);
}

.embed-review-cmp-value {
  font-size: var(--board-size-read);
  font-weight: var(--board-weight-bold);
  margin: 2px 0 var(--board-space-1);
  letter-spacing: -0.02em;
}

.embed-review-cmp-note {
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  line-height: var(--board-leading-ui);
  word-break: keep-all;
}

/* ── 지표 ─────────────────────────────────────────────── */
/* 왼쪽 굵은 선(남색)은 톤이라 값으로 남긴다. */
.embed-review-metric {
  display: flex;
  gap: var(--board-space-4);
  align-items: baseline;
  border-left: 3px solid #27364c;
  background: var(--board-tint);
  border-radius: 0 12px 12px 0;
  padding: var(--board-space-3) var(--board-space-4);
}

.embed-review-metric-value {
  font-size: var(--board-size-display);
  font-weight: var(--board-weight-bold);
  letter-spacing: -0.04em;
}

.embed-review-metric-label {
  font-weight: var(--board-weight-bold);
  font-size: var(--board-size-caption);
}

.embed-review-metric-note {
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  margin-top: 2px;
}

.embed-review-metric-src {
  font-size: var(--board-size-caption);
}

.embed-review-metric-compare {
  border: 1px solid var(--board-line);
  border-radius: 14px;
  padding: var(--board-space-4);
  background: var(--board-surface);
  overflow-x: auto;
}

/* 표는 스킨이 여백·테두리를 정한다(`.post .gb-body table`, 0,2,1). 선택자를 얹어 이긴다. */
.embed-review-block.embed-review-metric-compare table {
  width: 100%;
  border-collapse: collapse;
  margin-top: var(--board-space-2);
}

/*
 * 칸도 스킨이 여백·정렬·밑줄을 정한다(`.post .gb-body th, .post .gb-body td`, 0,2,1). 같은 이유로 얹는다.
 * 스킨의 `border-bottom` 은 지운다 ─ 레거시 줄은 `td` 윗줄뿐이라, 남기면 머리 밑과 끝 줄 밑에 선이 하나씩 는다.
 */
.embed-review-block.embed-review-metric-compare th {
  font-size: var(--board-size-caption);
  color: var(--board-dim);
  text-align: right;
  padding: var(--board-space-1) var(--board-space-2);
  border-bottom: 0;
}

.embed-review-block.embed-review-metric-compare th:first-child {
  text-align: left;
}

.embed-review-block.embed-review-metric-compare td {
  font-size: var(--board-size-caption);
  padding: var(--board-space-1) var(--board-space-2);
  border-top: 1px solid var(--board-line);
  border-bottom: 0;
  text-align: right;
}

.embed-review-block.embed-review-metric-compare td:first-child {
  text-align: left;
  color: var(--board-text);
}

/* ── 조사 노트와 출처 ─────────────────────────────────────────────── */
.embed-review-note {
  background: var(--board-tint);
  border-radius: 13px;
  padding: var(--board-space-4) var(--board-space-4);
}

.embed-review-note-label {
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-bold);
  letter-spacing: 0.06em;
  color: var(--board-dim);
  margin-bottom: var(--board-space-2);
}

/* 노트 문단도 스킨의 `.post .gb-body p`(0,2,1) 여백을 이겨야 한다. */
.embed-review-block.embed-review-note p {
  margin: 0 0 var(--board-space-2);
  font-size: var(--board-size-caption);
  color: var(--board-text);
  line-height: var(--board-leading-read);
}

.embed-review-block.embed-review-note p:last-child {
  margin-bottom: 0;
}

.embed-review-sources {
  border: 1px solid var(--board-line);
  border-radius: 13px;
  padding: var(--board-space-3) var(--board-space-4);
  background: var(--board-surface);
}

.embed-review-sources summary {
  font-weight: var(--board-weight-bold);
  font-size: var(--board-size-caption);
  cursor: pointer;
}

/* 목록 여백은 스킨의 `.post .gb-body ul`(0,2,1)이 정한다. 선택자를 얹어 이긴다. */
.embed-review-block.embed-review-sources ul {
  margin: var(--board-space-2) 0 0;
  padding-left: 0;
  list-style: none;
}

.embed-review-sources li {
  font-size: var(--board-size-caption);
  margin-bottom: var(--board-space-1);
  display: flex;
  gap: var(--board-space-2);
}

.embed-review-src-type {
  flex: none;
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-bold);
  color: var(--board-dim);
  background: var(--board-tint);
  border-radius: 5px;
  padding: 1px var(--board-space-1);
  height: fit-content;
}

/*
 * 관련글(`plugins/related`). 레거시 `PostDetailView.vue:115` 의 `.related-posts` 를 스킨 토큰으로
 * 다시 짠다 — `--color-muted` 는 `--board-dim`, `--color-line` 은 `--board-line`, 글자 크기는
 * `--board-size-*` 다(`--text-body-lg`=1.0625rem 는 `--board-size-read`, `--text-caption`=.8125rem 는
 * `--board-size-caption` 와 값이 같다).
 *
 * 코어가 이 슬롯 기여를 `<div class="slot slot-content.after plugin-related">` 로 씌워 글의
 * `.post` 안, `.gb-body` 밖에 놓는다. 스킨의 `.post .gb-body …`(0,2,1)와는 안 부딪히지만, 일반 `h2`
 * (0,0,1)와 `a`(0,0,1)는 이기도록 선택자를 `.related-posts` 아래로 잡는다.
 *
 * 읽음 표시(`.is-read`)는 안 옮긴다. 레거시는 브라우저에 남긴 읽은 글을 보고 제목을 흐리게
 * 했지만, 여기엔 그 기록이 없다.
 */
.related-posts header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--board-space-4);
  margin-bottom: var(--board-space-2);
}

.related-posts h2 {
  margin: 0;
  font-size: var(--board-size-read);
}

.related-posts header span {
  color: var(--board-dim);
  font-size: var(--board-size-meta);
}

.related-posts ul {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.related-posts li {
  border-top: 1px solid var(--board-line);
}

.related-posts li:first-child {
  border-top: 0;
}

.related-posts a {
  display: grid;
  /* 운영 3.2px — 레거시 `PostDetailView.vue` 의 `.related-posts a{gap:.2rem}` 그대로. */
  gap: 0.2rem;
  padding: var(--board-space-3) 2px;
}

/* 둘 다 grid 칸이라 `min-width: 0` 이 없으면 칸이 한 줄짜리 제목만큼 늘어나 말줄임이 안 된다. */
.related-posts strong {
  min-width: 0;
  overflow: hidden;
  font-size: var(--board-size-ui);
  font-weight: var(--board-weight-normal);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.related-posts a span {
  color: var(--board-dim);
  /* 게시판·날짜 줄은 운영 13px(`--text-caption`)이다 — `--board-size-meta`(14px)를 쓰면 줄 하나가 76px 로 운영 73.6 을 넘는다. */
  font-size: var(--board-size-caption);
}

/*
 * 디아블로2 아이템 DB(`plugins/d2r`). 화면 다섯 × 로케일 둘이 이 한 절을 쓴다.
 *
 * 앞의 둘과 달리 **여기는 레거시의 어두운 판을 그대로 들여온다.** 2026-09-16 에 뒤집은
 * 결정이다 — 그전에는 「보드는 밝은 바탕이라」 등급 색만 값으로 들고 어둠은 버렸는데,
 * 운영과 나란히 놓으면 같은 화면으로 안 보였다. 디아블로는 운영에서도 사이트의 다른 데와
 * 다른 판이고, 그 어둠이 등급 색을 읽히게 하는 바탕이다.
 *
 * 색은 레거시 값 그대로다. 등급 색은 장식이 아니라 정보이고 — 초록이면 세트, 금색이면
 * 유니크 — 어두운 바탕에서만 그 값이 원래 뜻대로 읽힌다.
 *
 * **판을 어둡게 하는 것은 스킨 토큰을 `.d2r` 에서 다시 정의하는 것 하나다.** 토큰은 가장
 * 가까운 곳의 값이 이기므로, 이 절의 나머지 규칙을 한 줄도 안 고치고 카드·선·글자가 전부
 * 돈다. 운영도 `body.page-theme-diablo` 에서 자기 `--color-*` 를 갈아 끼우는 같은 손이다.
 * 헤더와 페이지 바깥까지 도는 것은 `body:has(.d2r)` 다 — 이 화면에만 걸리고 스크립트가 없다.
 *
 * 선택자는 전부 `.d2r` 아래다. 안쪽 이름(`.grid`·`.stats`·`.content`)은 레거시 그대로라
 * 대조가 되지만 그만큼 흔한 이름이고, 뿌리를 안 씌우면 스킨·코어 마크업과 부딪힌다.
 *
 * **값은 운영 화면을 재서 쓴 게 아니라 레거시 원본을 옮긴 것이다**(2026-09-16). 원본은
 * 이 저장소 안에 있다 — `apps/frontend/app/components/diablo/*.vue` 와 `pages/diablo/*.vue`
 * 의 `<style scoped>`, 그리고 `app/assets/styles/{_tokens,_filters,_diablo}.scss`. 재서
 * 맞추면 78×104px 짜리 아이템 그림이 3.5rem 이 되는 식으로 조용히 틀린다. 고칠 일이
 * 생기면 화면을 재지 말고 그 `.vue` 를 열어라. SCSS 중첩은 펴고 `@include below(x)` 는
 * px 미디어로, `:deep(X)` 는 그냥 자손 선택자로 바꿨다.
 */
.d2r {
  /* 등급 색. 레거시 값 그대로다. */
  --d2r-base: #dddddd;
  --d2r-unique: #c7b377;
  --d2r-set: #00c400;
  --d2r-runeword: #d8b45c;
  --d2r-magic: #6969ff;
  --d2r-rare: #ffff64;
  --d2r-crafted: #ffa800;
  /* 판·선·금색. */
  --d2r-panel-strong: #101010;
  --d2r-panel: #171717;
  --d2r-panel-subtle: #1c1913;
  --d2r-line: #302d27;
  --d2r-line-strong: #49443a;
  --d2r-line-gold: #8e7339;
  --d2r-gold: #d8b45c;
  --d2r-gold-strong: #f0d898;
  --d2r-gold-soft: #b49b60;
  --d2r-text: #dddddd;
  --d2r-text-muted: #aaaaaa;
  --d2r-text-dim: #777777;
  --d2r-stat: #7da6ff;
  /*
   * 시세 신호 색 셋. 운영이 값으로 든 것이고 등급 색과 다른 계열이다 — 옵션에 따라 값이
   * 갈리는 것은 보라, 거래가 으뜸이거나 상급인 것은 주황 둘이다. 등급 색을 돌려 쓰면 범례에
   * 같은 색 점이 두 개 생긴다(「시세」 절의 `.dot` 주석).
   */
  --d2r-cond: #c98fe0;
  --d2r-market-top: #f0b35a;
  --d2r-market-high: #e0a84f;
  --d2r-set-bonus: #00c400;
  --d2r-shadow: rgb(0 0 0 / 33%);
  --d2r-shadow-strong: rgb(0 0 0 / 53%);
  --d2r-glow-gold: rgb(178 139 61 / 15%);
  /* 레거시 토큰 다리 — 옮겨 온 규칙이 쓰는 이름을 이 절 안에서만 정의한다(_tokens.scss 원본 값). */
  --text-caption: 0.8125rem;
  --text-meta: 0.875rem;
  --text-label: 0.9375rem;
  --text-body: 1rem;
  --text-body-lg: 1.0625rem;
  --text-subheading: 1.125rem;
  --text-section: 1.25rem;
  --text-title: 1.5rem;
  --text-title-lg: 1.75rem;
  --text-display: 2.25rem;
  --text-page: clamp(1.75rem, 3vw, 2.25rem);
  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800;
  --radius-sm: 0.4rem;
  --radius-md: 0.75rem;
  --radius-lg: 1rem;
  --radius-card: 0;
  --z-raised: 3;
  --content-width: 1180px;
  /*
   * 운영 헤더는 4rem 이고 우리 헤더는 그 아래에 실선 1px 이 더 있다. 붙는 자리가 1px 어긋난다.
   * 스킨의 headerAutohide 를 켜면 엔진 런타임이 `<html>` 의 --gb-header-offset 에 실측 높이를 쓰고
   * 헤더가 물러난 동안은 0 으로 둔다(레거시가 --app-header-offset 에 직접 쓰던 값,
   * AppHeader.vue `syncHeaderOffset`). 스크립트가 돌기 전·아예 안 도는 환경에선 그려진 65px 이다.
   */
  --app-header-offset: var(--gb-header-offset, 4.0625rem);
  --filter-label-width: 4.5rem;
  /*
   * 운영이 `body.page-theme-diablo` 에서 갈아끼우는 `--color-*` 다(`_themes.scss:16-28` 원본 값).
   * **이건 `--d2r-*` 의 다른 이름이 아니라 다른 값이다** — 칩·단추처럼 사이트 공통 규칙을 그대로
   * 옮긴 자리는 `--color-muted`(#aa9a73, 따뜻한 금갈색)를 쓰는데, 뜻이 비슷해 보이는
   * `--d2r-text-muted` 는 #aaa 회색이다. 옮길 때 `--d2r-*` 로 바꿔 쓰면 그 자리가 식는다.
   */
  --color-brand-50: #21190d;
  --color-brand-100: #392b13;
  --color-brand-500: #c9a227;
  --color-brand-600: #d6b85b;
  --color-brand-700: #f0cf78;
  --color-ink: #f6e7c2;
  --color-muted: #aa9a73;
  --color-line: rgb(201 162 39 / 18%);
  --color-surface: #17120d;
  --color-surface-subtle: #211a11;
  --color-canvas: #0d0a08;
  --color-on-brand: #fff;
  /* 스킨 토큰을 이 판의 값으로 다시 든다(머리의 셋째 단락). */
  --board-bg: var(--d2r-panel-strong);
  --board-surface: var(--d2r-panel);
  --board-tint: var(--d2r-panel-subtle);
  --board-tint-2: #23201a;
  --board-line: var(--d2r-line);
  --board-rule: var(--d2r-line-strong);
  --board-text: var(--d2r-text);
  --board-mid: var(--d2r-text-muted);
  --board-dim: var(--d2r-text-dim);
  --board-ink: var(--d2r-gold);
  --board-on-ink: #1a1208;
  --board-accent: var(--d2r-gold);
  --board-focus-line: initial;
  --board-focus-ring: initial;
  --board-on-accent: #1a1208;
  --board-accent-text: var(--d2r-gold);
  --board-count: var(--d2r-stat);
  --board-shadow: none;
  /* 판은 글 너비보다 좌우 16px 넓고, 위아래로는 본문 여백만큼 비어져 나가 밝은 띠를 안 남긴다. */
  min-height: 70vh;
  margin: calc(-1 * var(--board-space-6)) -1rem calc(-1 * var(--board-space-8));
  padding: 1.4rem 1rem 3rem;
  background: var(--d2r-panel-strong);
  color: var(--d2r-text);
}

/*
 * 레거시 `_reset.scss` 가 `ul, ol { margin:0; padding:0; list-style:none }` 으로 전부 초기화한다 —
 * 운영 D2R 화면엔 기본 여백·불릿 목록이 없다. 우리 시트엔 그 초기화가 없어 세트 보너스 목록
 * 같은 자리에 브라우저 기본값(위아래 1em·왼쪽 40px·불릿)이 살아 있었다. 자기 값을 주는 목록
 * (`.item-card .stats`·`.price-grid` 등)은 특이도가 더 높아 이 규칙에 안 밀린다.
 */
.d2r ul,
.d2r ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * 판 밖도 어두워야 판이 밝은 종이에 붙인 띠로 안 보인다. 헤더·푸터는 위와 같은 토큰 교체로
 * 돌고, 금색 그라디언트와 브랜드 색만 값으로 든다. `:has` 를 두 번 겹친 것은 스킨의 다크
 * 토큰(`:root:root`)보다 구체성이 낮아 그냥 쓰면 시스템 다크에서 밀리기 때문이다.
 */
body:has(.d2r):has(.d2r) {
  --board-bg: #0d0a08;
  --board-surface: #17120d;
  --board-tint: #211a11;
  --board-tint-2: #2a2115;
  --board-line: rgb(201 162 39 / 22%);
  --board-rule: rgb(201 162 39 / 34%);
  --board-text: #f6e7c2;
  --board-mid: #d8c9a2;
  --board-dim: #aa9a73;
  --board-ink: #d6b85b;
  --board-on-ink: #1a1208;
  --board-accent: #d6b85b;
  --board-focus-line: initial;
  --board-focus-ring: initial;
  --board-on-accent: #1a1208;
  --board-accent-text: #f0cf78;
  /* 브랜드 눈금 — 레거시 `body.page-theme-diablo`(`_themes.scss:15-19`). 판 밖 시세 띠 링크 같은 공통 부품이 읽는다. */
  --board-brand-50: #21190d;
  --board-brand-100: #392b13;
  --board-brand-500: #c9a227;
  --board-brand-700: #f0cf78;
  --board-shadow: 0 2px 8px rgb(0 0 0 / 35%);
  color-scheme: dark;
  background: radial-gradient(circle at 50% -10%, rgb(123 68 11 / 14%), rgb(0 0 0 / 0) 34rem), #0d0a08;
}

body:has(.d2r) .board-header {
  border-bottom-color: rgb(201 162 39 / 22%);
  background: linear-gradient(rgb(26 18 4 / 97%), rgb(18 13 8 / 96%));
  box-shadow: 0 0.5rem 2rem rgb(0 0 0 / 53%);
}

/* 운영은 브랜드 글자에 불꽃 그라디언트를 돌린다. 여기선 금색 한 톤으로 세운다 — 애니메이션은 안 옮긴다. */
body:has(.d2r) .gb-brand {
  color: #d6b85b;
}

body:has(.d2r) .board-menu a,
body:has(.d2r) .gb-sign-in {
  color: #e5d5b1;
}

body:has(.d2r) .board-menu a:hover,
body:has(.d2r) .board-menu a[aria-current] {
  color: #f1c75e;
}

body:has(.d2r) .sign-up {
  border-color: transparent;
  background: linear-gradient(#e7c568, #a87927);
  color: #1a1208;
}

body:has(.d2r) .gb-theme-toggle {
  border-color: rgb(201 162 39 / 24%);
  color: #d8b45c;
}

/*
 * 영문 다섯 화면의 전용 셸 — 레거시 `layouts/default.vue` 의 `.site-shell--diablo` 분기
 * (`<style scoped>` 마지막 열 줄)다. 이 셸이 그려지는 페이지는 `chrome: 'none'` 이라 스킨의
 * 헤더·슬롯·푸터가 없고, `.d2r` 판은 `.d2r-en-main` 안에 선다.
 *
 * 셸은 `.d2r` 의 겉이라 판이 정의한 `--d2r-*` 를 물려받지 못한다 — 헤더·푸터가 쓰는 다섯만
 * 같은 값으로 여기도 둔다.
 */
.d2r-en-shell {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  --d2r-panel-strong: #101010;
  --d2r-line-strong: #49443a;
  --d2r-gold: #d8b45c;
  --d2r-text-muted: #aaaaaa;
  --d2r-text-dim: #777777;
  --text-caption: 0.8125rem;
}

/*
 * `flex: 1` 이 먹으려면 셸까지 이어지는 마디마다 flex 여야 한다 — 몸(body flex column)과
 * 셸 사이에 `article.gb-plugin-page` 와 `.gb-body` 둘이 block 으로 끼어 있어, 둘을 같은 식으로
 * 잇는다. 이 화면들만 걸리도록 `:has(.d2r-en-shell)` 로 한정한다.
 */
.gb-plugin-page:has(> .gb-body > .d2r-en-shell),
.gb-plugin-page > .gb-body:has(> .d2r-en-shell) {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
}

/* 레거시 `.container`(`global.scss:17`). 갈림점 `tablet-narrow`(700px)는 아래 블록이 맡는다. */
.d2r-en-container {
  width: min(calc(100% - 2rem), 1180px);
  margin-inline: auto;
}

@media (max-width: 43.75rem) {
  .d2r-en-container {
    width: min(calc(100% - 1rem), 1180px);
  }
}

.d2r-en-header {
  border-bottom: 1px solid var(--d2r-line-strong);
  background: var(--d2r-panel-strong);
}

.d2r-en-header-inner,
.d2r-en-footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.8rem;
}

.d2r-en-brand {
  color: var(--d2r-gold);
  font-weight: 600;
}

.d2r-en-main {
  flex: 1 0 auto;
  padding-block: 1.4rem 3rem;
}

/*
 * 판이 화면 끝까지 칠해지는 손은 `.d2r` 절의 음수 여백 그대로다 — 좌우 -1rem(폰 -.5rem)·
 * 아래 -3rem·패딩 1rem 은 `.board-body` 대신 이 본문의 여백(1.4rem·1rem·3rem)과 어긋남 없이
 * 맞는다. 다른 것은 위쪽 하나다 — `.board-body` 윗여백 1.5rem 을 메우던 -1.5rem 을
 * 레거시 값 -1.4rem(`items/index.vue:314`, `level-items.vue` 의 같은 줄)으로 고친다.
 */
.d2r-en-main > .d2r {
  margin-top: -1.4rem;
}

.d2r-en-footer {
  margin-top: 2rem;
  border-top: 1px solid var(--d2r-line-strong);
  background: var(--d2r-panel-strong);
}

.d2r-en-footer-inner {
  flex-wrap: wrap;
}

.d2r-en-footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
}

.d2r-en-footer a {
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
}

.d2r-en-footer p {
  margin: 0;
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
}

.d2r .rarity-unique,
.d2r .rarity-normal.rarity-unique {
  color: var(--d2r-unique);
}
.d2r .rarity-set {
  color: var(--d2r-set);
}
.d2r .rarity-runeword {
  color: var(--d2r-runeword);
}
.d2r .rarity-magic {
  color: var(--d2r-magic);
}
.d2r .rarity-rare {
  color: var(--d2r-rare);
}
.d2r .rarity-crafted {
  color: var(--d2r-crafted);
}

/* 나침반. 세 화면이 같은 것을 인다. */
/*
 * 스킨은 form 의 제출 단추를 강조색으로 칠한다 (styles.ts 의
 * `button[type="submit"]:not(.gb-link):not(.gb-reaction):not(.gb-danger)`, 특이도 0,4,1). 이 판에서 강조색은
 * 금색이라, 그대로 두면 등급·분류·정렬 칩이 전부 금색으로 칠해진 판이 된다. 디아블로 화면에 칠해진
 * 단추는 없다 — 고른 것만 금 테두리와 금 글씨로 선다. 그래서 스킨과 같은 :not 사슬을 한 단 위에서
 * 되돌린다. `.d2r` 를 두 번 적은 것은 특이도를 한 칸 올리는 것 말고 뜻이 없다.
 * 아래 d2r 단추 규칙들은 이 규칙보다 뒤에 서야 하고, 색을 다시 정할 때는 사슬을 같이 적는다.
 */
.d2r.d2r button:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  border-color: var(--d2r-line);
  background: var(--d2r-panel);
  color: var(--d2r-text-muted);
}

.d2r.d2r button:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover {
  border-color: var(--d2r-line-gold);
  background: var(--d2r-panel);
  color: var(--d2r-gold);
  opacity: 1;
}

.d2r .d2r-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.d2r .d2r-nav a {
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.3rem;
  color: var(--d2r-text-muted);
}

/* 레거시는 vue-router 의 `.router-link-active` 를 쓴다. 여기는 스크립트가 없어 현재 화면을 `active` 클래스로 직접 표시한다(screen.tsx `Nav`). */
.d2r .d2r-nav a:hover,
.d2r .d2r-nav a.active {
  border-color: var(--d2r-line-gold);
  color: var(--d2r-gold);
}

/* 패치 번호는 지금 어느 판 자료인지가 곧 값이라, 나침반에서 혼자 금색으로 선다. */
.d2r .d2r-nav .patch {
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.3rem;
  background: var(--d2r-panel-subtle);
  color: var(--d2r-gold);
  font-size: var(--text-caption);
  font-weight: var(--weight-extrabold);
  white-space: nowrap;
}

.d2r .d2r-nav .locale {
  margin-left: auto;
}

/* ------------------------------------------------------------------ 목록 */

/* 머리는 가운데로 선다. 아이템 DB 는 글이 아니라 도구라, 제목이 자료의 문패 노릇을 한다. */
.d2r .page-head {
  text-align: center;
}

.d2r .page-head p {
  margin: 1rem 0 0.25rem;
  color: var(--d2r-gold-soft);
  font-size: var(--text-caption);
  font-weight: var(--weight-extrabold);
  letter-spacing: 0.16em;
}

/* 부제(`<span>`)는 원본에 표시 규칙이 없어 inline 으로 h1 아래 줄에 흐른다(16px/25.6 — 본문 값). */
.d2r .page-head span {
  margin: 0;
  color: var(--d2r-text);
  font-size: 1rem;
}

/* 제목 크기는 레거시 h1 의 `--text-page`(clamp 1.75~2.25rem, `_typography.scss:3`)다 — 고정 36 을 주면
 * 900px 처럼 3vw 가 그보다 작은 폭에서 머리가 10px 불었다. 굵기·줄높이는 같은 자리의 600·1.25. */
.d2r .page-head h1 {
  margin: 0;
  color: var(--d2r-gold);
  font-size: var(--text-page);
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  text-shadow: 0 0 1rem var(--d2r-glow-gold);
}

/* 검색은 페이지 폭을 다 쓰지 않는다. 한 줄 물음이라 44rem 이면 충분하고, 가운데 서면 머리와 한 덩어리로 읽힌다. */
.d2r .gb-search {
  max-width: 44rem;
  margin: 1.2rem auto;
}

.d2r .gb-search label {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--d2r-gold);
  font-size: var(--text-caption);
  font-weight: var(--weight-bold);
}

/* 칸과 단추는 한 몸이다 — 오른쪽 모서리만 단추가 잇고, 테두리는 1px 겹쳐 두 줄이 안 보인다. */
.d2r .search-control {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: stretch;
  border-radius: 0.4rem;
}

/* 스킨은 입력 칸 높이를 2.25rem 으로 못박는다. 여기선 여백이 높이를 정해야 해서 풀고, 운영과 같은
 * 53px 을 최소 높이로 준다 — 단추는 stretch 라 같이 53 이 된다. */
.d2r .search-control input {
  min-width: 0;
  height: auto;
  min-height: 3.3125rem;
  padding: 0.78rem 2.4rem 0.78rem 0.85rem;
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.4rem 0 0 0.4rem;
  background: var(--d2r-panel);
  color: var(--d2r-text);
}

.d2r.d2r .search-control button:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  position: relative;
  margin-left: -1px;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0 0.4rem 0.4rem 0;
  background: var(--d2r-panel-subtle);
  color: var(--d2r-gold);
  font-weight: var(--weight-bold);
  cursor: pointer;
}

/* 운영 `_diablo.scss:68` — hover 에 면이 한 단계 밝아지고(panel-subtle → panel) 테두리가 금색이 된다. */
.d2r.d2r .search-control button:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover {
  border-color: var(--d2r-gold);
  background: var(--d2r-panel);
  color: var(--d2r-gold-strong);
}

/* 지우기는 칸의 셋째 칸이 아니라 칸 위에 얹힌다 — 그래서 입력 칸 오른쪽 여백이 2.4rem 이다. */
.d2r .search-clear {
  z-index: 1;
  grid-area: 1 / 1;
  align-self: center;
  justify-self: end;
  margin-right: 0.6rem;
  color: var(--d2r-text-muted);
}

.d2r .search-help {
  margin: 0.4rem 0 0;
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
}

.d2r .search-help strong {
  color: var(--d2r-gold);
}

/* 범위는 칩이 아니라 밑줄 탭이다. 둘 중 어디를 보고 있나가 한눈에 서야 한다. */
.d2r .scope-tabs {
  display: flex;
  justify-content: center;
  margin: 0;
  border-bottom: 1px solid var(--d2r-line);
}

.d2r .scope-tabs a {
  display: grid;
  place-items: center;
  min-width: 8rem;
  padding: 0.65rem;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: none;
  color: var(--d2r-text-dim);
}

.d2r .scope-tabs a.active {
  border-bottom-color: var(--d2r-line-gold);
  color: var(--d2r-gold);
}

/*
 * 레벨별·시세 화면이 쓰는 칩 줄이다(목록 화면은 안 쓴다 — `.socket-filter`·`.gb-categories` 다른 단추를 쓴다).
 * `_filters.scss:29-33` 공통 값을 옮겼다.
 */
.d2r .filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

/*
 * 소켓 거르기는 원본에서 자기 테두리를 가진 판이다 — 등급 단추 밑에 떠 있는 상자 하나로 선다.
 * 버튼인 이유는 `plugins/d2r/src/screen.tsx` 머리에 적혀 있다 — 링크로 만들면 조건 조합이 전부
 * 크롤 대상이 된다.
 */
.d2r .socket-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 0.75rem;
  background: var(--d2r-panel);
  border: 1px solid var(--d2r-line);
  border-radius: 0.45rem;
}

.d2r .socket-filter strong {
  margin-right: 0.35rem;
  color: var(--d2r-gold-soft);
  font-size: var(--text-caption);
}

/*
 * 정렬 고르기. 원본은 `AppSelect` 드롭다운이다(`items/index.vue:77` 결과 머리, `:50` 폰 도구 줄;
 * 마크업·기본값은 `components/ui/AppSelect.vue:3-5,17-20`) — 「최신등록순 ⌄」 한 칸을 누르면
 * 항목 셋이 열린다. 스크립트 없는 `<details>` 로 같은 모양을 내고, 안의 폼이 `sort` 를 제출한다
 * (성지시세 `.compare-sort` 선례). 원본이 못 박은 폭은 결과 머리 쪽만 9.5rem 이다.
 */
.d2r .desktop-sort {
  width: 9.5rem;
  flex: 0 0 9.5rem;
}

/*
 * 트리거의 색은 운영의 디아블로 덮어쓰기다 — 결과 머리 `items/index.vue:314`
 * (`.result-head :deep(.select-trigger)`), 폰 도구 줄 `:336`(`.mobile-tools :deep(.select-trigger)`).
 * 높이·여백·flex 손은 위 공통 `.select-trigger` 가 이미 준다 — `min-width:12rem` 만 풀어
 * 원본 폭(9.5rem·내용만큼)이 산다.
 */
.d2r .select-trigger {
  min-width: 0;
  padding: 0.55rem 0.7rem;
  color: var(--d2r-text);
  background: var(--d2r-panel);
  border-color: var(--d2r-line-strong);
}

/*
 * 열린 판은 왼쪽 끝을 맞추고 색은 이 판 머리의 `--color-*` 다리를 쓴다 — `.d2r` 에서
 * `--color-surface` 는 #17120d, `--color-line` 은 금색 18% 다(원본 `_themes.scss:16-28`).
 * z-index 는 붙는 헤더(20) 위인 30. 나머지 치수는 위 공통 `.select[open] > .select-content` 가 준다.
 */
.d2r .select[open] > .select-content {
  left: 0;
  z-index: 30;
  border-color: var(--color-line);
  background: var(--color-surface);
  box-shadow: 0 14px 36px rgb(0 0 0 / 48%);
}

/*
 * 메뉴 항목(원본 `.select-item`, `AppSelect.vue:19`). `.d2r.d2r button:not(.gb-link)…`(0,5,1)이
 * 스킨의 단추 손을 되돌리는 규칙이라, 같은 사슬에 `.select-item` 을 얹어 한 단 위에서 쓴다 —
 * 안 그러면 패널 배경과 테두리가 씌워져 항목이 단추 행으로 보인다.
 */
.d2r.d2r .select-item:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: 0;
  border-radius: 0.3rem;
  background: transparent;
  color: var(--color-ink);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  text-align: left;
  cursor: pointer;
}

/* 가리킨 항목. 원본 `.select-item[data-highlighted]`(`AppSelect.vue:20`)의 디아블로 값 — 이 판에서 `--color-brand-50` 은 #21190d, `--color-brand-700` 은 #f0cf78 다. */
.d2r.d2r .select-item:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover,
.d2r.d2r .select-item:not(.gb-link):not(.gb-reaction):not(.gb-danger):focus-visible {
  background: var(--color-brand-50);
  color: var(--color-brand-700);
}

/* 등급 넷은 폭을 똑같이 나눈다. 고르는 것이 아니라 고를 것이 넷이라는 사실이 먼저 읽혀야 한다. */
.d2r .rarities {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem;
  margin: 1rem 0;
}

.d2r .rarities button {
  display: grid;
  place-items: center;
  min-height: 3rem;
  border: 1px solid var(--d2r-line);
  border-radius: 0.55rem;
  background: var(--d2r-panel);
  color: var(--d2r-text-muted);
  cursor: pointer;
}

/*
 * 등급 단추는 등급색으로 말한다. 위에서 되돌린 회색을 여기서 등급색으로 다시 올린다 — 운영도 같은
 * 자리에서 같은 짓을 한다(`body.page-theme-diablo.page-theme-diablo .rarity-unique`).
 */
.d2r.d2r .rarities button.rarity-base:not(.gb-link):not(.gb-reaction):not(.gb-danger) { color: var(--d2r-base); }
.d2r.d2r .rarities button.rarity-unique:not(.gb-link):not(.gb-reaction):not(.gb-danger) { color: var(--d2r-unique); }
.d2r.d2r .rarities button.rarity-set:not(.gb-link):not(.gb-reaction):not(.gb-danger) { color: var(--d2r-set); }
.d2r.d2r .rarities button.rarity-runeword:not(.gb-link):not(.gb-reaction):not(.gb-danger) { color: var(--d2r-runeword); }
.d2r.d2r .rarities button.rarity-magic:not(.gb-link):not(.gb-reaction):not(.gb-danger) { color: var(--d2r-magic); }
.d2r.d2r .rarities button.rarity-rare:not(.gb-link):not(.gb-reaction):not(.gb-danger) { color: var(--d2r-rare); }
.d2r.d2r .rarities button.rarity-crafted:not(.gb-link):not(.gb-reaction):not(.gb-danger) { color: var(--d2r-crafted); }

/* 고른 등급은 칠하지 않는다. 테두리가 금색이 되고 판이 한 칸 떠오른다 — 운영과 같다. */
.d2r.d2r .rarities button:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover,
.d2r.d2r .rarities button.active:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  border-color: var(--d2r-line-gold);
  background: var(--d2r-panel);
  box-shadow: 0 0.5rem 1.5rem var(--d2r-shadow);
  translate: 0 -1px;
}

/* 원본은 `.socket-filter button,.categories button` 을 한 규칙으로 묶는다. */
.d2r .socket-filter button {
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--d2r-line);
  border-radius: 0.3rem;
  background: var(--d2r-panel);
  color: var(--d2r-text-muted);
  cursor: pointer;
}

/*
 * `_filters.scss:34-48` 공통 칩 값이다. `--color-*` 를 그대로 쓴다 — 머리의 `--color-*` 다리가
 * 운영 디아블로 판의 값(#aa9a73·#17120d·금색 18%)을 주므로 원본을 한 글자도 안 고친다.
 * 예전에 이걸 `--d2r-text-muted`(#aaa) 로 바꿔 놨었는데 그러면 칩만 회색으로 식어 보였다.
 */
.d2r .filter-chip {
  min-height: 2.35rem;
  padding: 0 0.9rem;
  border-radius: var(--radius-sm);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  /* 원본은 줄높이를 따로 안 잡고 본문 값(1.6)을 물려받는다. 스킨은 단추에 1.3 을 걸어 놔서 다시 든다. */
  line-height: 1.6;
  cursor: pointer;
}

/*
 * 색만 따로, 그리고 특이도를 올려서 잡는다. 이 절 위쪽의
 * `.d2r.d2r button:not(.gb-link):not(.gb-reaction):not(.gb-danger)` 가 스킨의 단추 손을 이기려고 세워 둔
 * 규칙인데(0,5,1) 칩도 `<button>` 이라 같이 걸린다. `.d2r .filter-chip`(0,2,0) 으로는 못 이겨서
 * 칩이 회색으로 식었다. 운영엔 이런 규칙이 없다 — 스킨이 없으니 생길 이유가 없었다.
 */
.d2r.d2r .filter-chip:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  color: var(--color-muted);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
}

.d2r.d2r .filter-chip:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover {
  border-color: var(--color-brand-500);
  background: var(--color-surface);
  color: var(--color-brand-700);
}

.d2r.d2r .filter-chip:not(.gb-link):not(.gb-reaction):not(.gb-danger):focus-visible {
  outline: 2px solid var(--color-brand-500);
  outline-offset: 2px;
}

.d2r .filter-chip small {
  margin-left: 0.35rem;
  font-size: inherit;
  opacity: 0.65;
}

.d2r.d2r .socket-filter button.active:not(.gb-link):not(.gb-reaction):not(.gb-danger),
.d2r.d2r .gb-categories button.active:not(.gb-link):not(.gb-reaction):not(.gb-danger),
.d2r.d2r .filter-chip.active:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  border-color: var(--d2r-line-gold);
  background: var(--d2r-panel-subtle);
  color: var(--d2r-gold);
}

/* 고른 칩만 굵다(`_diablo.scss:71-76`). 스킨이 단추에 거는 굵기를 이기려고 특이도를 올렸다. */
.d2r.d2r .filter-chip.active:not(.gb-link):not(.gb-reaction) {
  font-weight: var(--weight-bold);
}

/*
 * 시세 화면 칩은 공통 칩 색이 아니라 자기 값이다 — `prices.vue:200` 이 글자
 * `--d2r-text-muted`(#aaa)·판 `none`·테두리 `--d2r-line-strong`(#49443a) 로 덮는다. 아래쪽
 * `.d2r-prices .filter-chip` 규칙이 같은 값을 들고 있지만 특이도(0,2,0)가 위쪽 `:not()` 사슬
 * (0,6,0)에 져서 못 쓰므로, 여기서 사슬을 하나 더 얹어 이긴다. 칩 안 `small` 은 글자색을
 * 물려받고 `opacity:.65`(`prices.vue:202`)라 색 규칙만 맞추면 운영과 같아진다.
 */
.d2r.d2r.d2r-prices .filter-chip:not(.gb-link):not(.gb-reaction):not(.gb-danger):not(.active) {
  color: var(--d2r-text-muted);
  background: none;
  border-color: var(--d2r-line-strong);
}

/*
 * hover 의 금색 두 개(`_filters.scss:45` 의 brand-500 선·brand-700 글자)는 그대로 두고 판만
 * 투명으로 되돌린다 — 운영은 scoped `background: none`(`prices.vue:200`)이 hover 에도 남는다.
 */
.d2r.d2r.d2r-prices .filter-chip:not(.gb-link):not(.gb-reaction):not(.gb-danger):not(.active):hover {
  background: none;
}

/*
 * 갈래 제목은 `prices.vue:207` 이 줄높이를 안 적어 h2 공통 1.35(`_typography.scss:4`)를 탄다 —
 * 20px×1.35=27px. 아래쪽 `.d2r .price-group h2` 의 1.3(26px)을 특이도 한 칸 올려 되돌린다.
 */
.d2r.d2r .price-group h2 {
  line-height: 1.35;
}

/* `.socket-filter` 자기 여백은 위 판 규칙에 없어 여기서 준다. `.rarities` 여백은 위 규칙(1rem)이 이미
 * 정했으니 여기서 다시 안 잡는다 — 값이 둘이면 나중 것(정의 안 된 토큰)이 이겨 깨진다. */
.d2r .socket-filter {
  margin: 0.8rem 0;
}

.d2r .filter-summary strong,
.d2r .filter-row strong {
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
  font-weight: var(--weight-normal);
}

/* `.filter-summary`·`.filter-reset` 은 원본 vue 에 없다 — 고른 조건을 한눈에 보여주는 우리 기능이다. */
.d2r .filter-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.8rem 0;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--d2r-line);
  border-radius: 0.35rem;
  background: var(--d2r-panel);
}

.d2r .filter-summary > div {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.d2r .filter-summary a {
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.3rem;
  background: var(--d2r-panel-subtle);
  color: var(--d2r-text);
  font-size: var(--text-caption);
}

.d2r .filter-reset {
  margin-left: auto;
  color: var(--d2r-text-dim);
}

/*
 * 왼쪽 분류 레일. **모바일에서도 안 숨긴다** — 레거시는 여기를 감추고 바텀시트를 열었는데
 * 그건 자바스크립트다. 좁아지면 위로 접혀 올라간다.
 */
.d2r .content {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: 1.2rem;
  margin-top: 1.1rem;
}

.d2r .content--sets {
  grid-template-columns: minmax(0, 1fr);
}

/*
 * 분류는 카드 한 장이다. 머리가 붙고 묶음 사이에 줄이 그어진다. 목록이 화면보다 길어서 스크롤을
 * 내려도 따라오게 붙여 두는데, 헤더 아래 0.75rem 에서 선다. 헤더가 물러나면 --app-header-offset 이
 * 0 이 돼 레일도 위로 붙고 높이가 늘어난다 — 운영과 같은 식이다
 * (`pages/diablo/items/index.vue:315-316`, 헤더 상태는 `--app-header-offset` 이 따라간다).
 */
.d2r .gb-categories {
  position: sticky;
  top: calc(var(--app-header-offset) + 0.75rem);
  align-self: start;
  min-width: 0;
  max-height: calc(100vh - var(--app-header-offset) - 1.5rem);
  transition: top 0.22s ease, max-height 0.22s ease;
  overflow: hidden auto;
  border: 1px solid var(--d2r-line);
  border-radius: 0.45rem;
  background: var(--d2r-panel);
  scrollbar-color: var(--d2r-panel-subtle) var(--d2r-panel);
}

.d2r .category-head {
  padding: 0.8rem;
  background: var(--d2r-panel);
  color: var(--d2r-gold);
  font-size: var(--text-meta);
  font-weight: var(--weight-extrabold);
}

.d2r .gb-categories form {
  display: block;
  margin: 0;
  padding: 0.65rem;
}

.d2r .gb-categories form + form {
  border-top: 1px solid var(--d2r-line);
}

.d2r .gb-categories h2 {
  margin: 0 0 0.35rem;
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.09em;
}

/* 분류 단추는 칩이 아니라 목록 줄이다 — 한 줄에 하나, 왼쪽 정렬, 테두리는 고를 때만 보인다. */
.d2r.d2r .gb-categories button:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  display: block;
  width: 100%;
  margin: 0.12rem 0;
  padding: 0.45rem 0.7rem;
  border-color: transparent;
  border-radius: 0.3rem;
  background: var(--d2r-panel);
  /* 원본은 크기·줄높이를 안 잡아 본문 16px/1.6 이다 — 스킨 단추 기본(13px/20.8)이 들어가 높이가 37 에 머물던 것을 42 로 돌린다. */
  font-size: 1rem;
  font-weight: var(--weight-normal);
  line-height: 1.6;
  text-align: left;
}

/*
 * 고른 분류는 왼쪽에 금색 막대가 서고 오른쪽에 체크가 붙는다. 원본에는 이 손이 없다 — 목록이
 * 길어 색만으로는 눈에 안 걸려서 우리가 더한 표식이다.
 */
.d2r.d2r .gb-categories button.active:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  box-shadow: inset 3px 0 var(--d2r-gold);
  font-weight: var(--weight-extrabold);
}

.d2r .gb-categories button.active::after {
  float: right;
  color: var(--d2r-gold);
  content: "✓";
}

/* 폰 도구 줄은 760 이하에서만 선다(원본 `.mobile-tools{display:none}`) — 넓은 화면의 분류·정렬은 곁칸과 결과 머리가 맡는다. */
.d2r .mobile-tools {
  display: none;
}

/* 필터 시트는 `<details>` 가 여는 판이다 — 닫혀 있으면 summary 만 보이고 안쪽은 그려지지 않는다. */
.d2r .filter-pop > summary {
  list-style: none;
  cursor: pointer;
}

.d2r .filter-pop > summary::-webkit-details-marker {
  display: none;
}

/*
 * 원본 `index.vue` 의 `@include below(tablet)`(760px) 분기다. 곁칸과 데스크톱 정렬이 접히고
 * 도구 줄이 선다 — 필터 단추가 시트를 열고, 정렬은 같은 GET 폼이 한 벌 더 있다.
 */
@media (max-width: 47.5rem) {
  .d2r .content {
    grid-template-columns: 1fr;
    margin-top: 0.75rem;
  }

  .d2r .gb-categories,
  .d2r .desktop-sort {
    display: none;
  }

  .d2r .mobile-tools {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 0.8rem;
  }

  /* 단추는 `<summary>` 다 — `<button>` 이 아니라 details 의 손잡이라 스킨의 단추 손이 안 닿는다. */
  .d2r .mobile-filter-button {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.55rem 0.7rem;
    color: var(--d2r-gold);
    background: var(--d2r-panel);
    border: 1px solid var(--d2r-line-gold);
    border-radius: 0.35rem;
  }

  /* 고른 조건 개수 뱃지. */
  .d2r .mobile-filter-button span {
    display: grid;
    place-items: center;
    min-width: 1.2rem;
    height: 1.2rem;
    color: var(--d2r-gold-soft);
    background: var(--d2r-panel-subtle);
    border-radius: 99px;
    font-size: var(--text-caption);
    font-weight: var(--weight-extrabold);
  }

  /* 본 규칙이 결과 머리의 기본 `min-height:3.5rem` 보다 앞에 서서 `.d2r.d2r` 로 특이도를 올린다. */
  .d2r.d2r .result-head {
    min-height: auto;
  }

  /*
   * 열린 details 의 판은 화면 아래에서 올라오는 시트다(원본 `.filter-dialog`/`.filter-sheet`).
   * z-index 는 원본의 `--z-sheet`(60)다 — 붙어 있는 헤더(20) 위로 덮어야 한다.
   */
  .d2r .filter-dialog {
    position: fixed;
    z-index: 60;
    inset: 0;
    display: flex;
    align-items: flex-end;
    background: var(--d2r-shadow-strong);
  }

  .d2r .filter-sheet {
    width: 100%;
    max-height: 78vh;
    overflow: auto;
    padding: 1rem;
    background: var(--d2r-panel);
    border-top: 1px solid var(--d2r-line-gold);
    border-radius: 1rem 1rem 0 0;
    box-shadow: 0 -1rem 3rem var(--d2r-shadow-strong);
  }

  .d2r .filter-sheet > header {
    display: flex;
    align-items: start;
    justify-content: space-between;
    margin-bottom: 0.8rem;
  }

  /* 스킨의 h2·p 바깥 여백을 지운다 — 원본엔 없어 머리 높이가 닫기 단추 높이(44.8)가 된다. */
  .d2r .filter-sheet h2 {
    margin: 0;
    font-size: var(--text-body-lg);
  }

  .d2r .filter-sheet header p {
    margin: 0;
    color: var(--d2r-gold-soft);
    font-size: var(--text-caption);
  }

  /* 닫기는 같은 주소로의 링크다 — 다시 읽으면 details 는 닫힌 채 그려진다(스크립트 없는 닫기).
   * 폭 2.5rem 은 운영 실측(40×44.8)이다 — 원본 단추의 글리프가 이 폰트의 × 보다 넓다. */
  .d2r .filter-sheet header a {
    width: 2.5rem;
    padding: 0.2rem 0;
    color: var(--d2r-text-muted);
    font-size: var(--text-title);
    text-align: center;
    text-decoration: none;
  }

  .d2r .filter-sheet form {
    margin: 0;
    padding: 0.7rem 0;
    border-top: 1px solid var(--d2r-line);
  }

  .d2r .filter-sheet h3 {
    margin-bottom: 0.45rem;
    color: var(--d2r-text-dim);
    font-size: var(--text-caption);
    font-weight: var(--weight-semibold);
    letter-spacing: 0.08em;
  }

  .d2r .filter-sheet form > div {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.35rem;
  }

  .d2r.d2r .filter-sheet button:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
    padding: 0.65rem;
    border: 1px solid var(--d2r-line);
    border-radius: 0.35rem;
    background: var(--d2r-panel);
    color: var(--d2r-text-muted);
    font-size: 1rem;
    font-weight: var(--weight-normal);
    line-height: 1.6;
    /* 스킨은 단추를 가운데 정렬 flex 로 둔다 — 원본은 왼쪽 정렬 블록이다. */
    justify-content: flex-start;
    text-align: left;
  }

  .d2r.d2r .filter-sheet button.active:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
    color: var(--d2r-gold);
    border-color: var(--d2r-line-gold);
    background: var(--d2r-panel-subtle);
  }
}

/* 개수와 정렬은 한 줄에서 양 끝으로 벌어진다. 3.5rem 을 비워 두는 것은 정렬 단추가 들어와도 줄이 안 흔들리게 하는 것이다. */
.d2r .result-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  min-height: 3.5rem;
  margin-bottom: 0.65rem;
  color: var(--d2r-text-muted);
}

.d2r .result-head > div:first-child {
  flex: 1 1 0;
  min-width: 0;
}

.d2r .result-head p {
  margin: 0;
  color: inherit;
}

.d2r .result-head strong {
  color: var(--d2r-gold);
}

.d2r .none {
  padding: 4rem 1rem;
  color: var(--d2r-text-dim);
  background: var(--d2r-panel);
  border: 1px solid var(--d2r-line);
  border-radius: 0.4rem;
  text-align: center;
}

.d2r .none strong {
  color: var(--d2r-text-muted);
}

.d2r .none p {
  margin: 0.35rem 0 1rem;
  font-size: var(--text-meta);
}

/* 원본은 여기가 `<button>` 이다. 우리 마크업은 목록 초기화가 그냥 링크(`<a>`)라 값만 그대로 옮긴다. */
.d2r .none a {
  display: inline-block;
  padding: 0.5rem 0.8rem;
  color: var(--d2r-gold);
  background: transparent;
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.35rem;
}

/* ------------------------------------------------------------------ 카드 */

/* 아이템은 한 줄에 한 장이다. 옵션 줄이 카드의 셋째 칸을 통째로 쓰기 때문에, 두 장을 나란히 놓으면 그 줄이 먼저 접힌다. */
.d2r .grid {
  display: grid;
  gap: 0.65rem;
}

/*
 * 레벨별 화면만 다르다 — 그 카드는 세로로 서는 좁은 카드(`.item-card.compact`)라 한 줄에
 * 셋이 들어간다. 로컬은 이 줄도 한 장씩 그려 레벨 하나가 화면 한 판이었다.
 */
.d2r .level-row .grid {
  grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
}

.d2r .level-row .grid .item-card {
  height: 100%;
}

/* 세트 목록은 원본 `items/index.vue:314` 처럼 정확히 두 열이다 — auto-fill 이라 1024 에서 네 칸이 됐다. */
.d2r .set-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem;
}

/* 관련 아이템은 원본 `D2RRelatedItems.vue` 처럼 정확히 두 열이다 — 폰에서 한 열로 접는 것은 아래 47.5rem 분기. */
.d2r .related-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem;
}

/* 카드 한 장이 세 칸이다 — 그림, 이름, 옵션. 이름 칸은 13~17rem 사이에서만 늘어나고 남는 폭은 옵션이 받는다. */
.d2r .item-card {
  position: relative;
  display: grid;
  grid-template-columns: 8.5rem minmax(13rem, 17rem) minmax(0, 1fr);
  gap: 1.15rem;
  min-height: 10.5rem;
  padding: 1rem 1.2rem;
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.45rem;
  background: var(--d2r-panel);
  transition: border-color 0.18s, background 0.18s;
}

.d2r .item-card:hover {
  border-color: var(--d2r-line-gold);
  background: var(--d2r-panel);
}

/* 카드 전체를 덮는 링크 한 장. 안에 링크를 여럿 두면 색인이 같은 주소를 여러 번 받는다. */
.d2r .card-link {
  position: absolute;
  z-index: 1;
  inset: 0;
}

.d2r .item-card .visual {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.5rem;
  min-width: 0;
  border-right: 1px solid var(--d2r-line);
}

/* 룬 무리는 카드를 덮는 링크(위 `.card-link`, z-index 1)보다 위에 서야 한다 — 원본 그대로다. */
.d2r .item-card .runes {
  position: relative;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem;
}

.d2r .item-card .runes span {
  display: grid;
  justify-items: center;
  color: var(--d2r-gold);
}

/* 룬은 운영과 같은 28px 이다. 1.1rem(17.6px)으로는 어느 룬인지 분간이 안 된다(2026-09-16 확인). */
.d2r .item-card .runes img {
  width: 28px;
  height: 28px;
  object-fit: contain;
  image-rendering: pixelated;
}

/* 룬 이름을 안 지운다. 아이콘이 없는 룬이 있고 그때 남는 건 이 글자뿐이다. 색은 위 `.runes span` 의 금색을 물려받는다. */
.d2r .item-card .runes small {
  font-size: var(--text-caption);
}

/* 아이템 그림은 원본 그대로 78×104px 다 — 도트 그림이라 늘리면 흐려진다. 픽셀을 그대로 키운다. */
.d2r .item-card .item-image {
  width: 78px;
  height: 104px;
  object-fit: contain;
  image-rendering: pixelated;
}

.d2r .gb-identity {
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  text-align: left;
}

.d2r .name-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.d2r .name-row h2 {
  margin: 0;
  font-size: var(--text-body-lg);
  line-height: 1.3;
}

/* 래더 전용 표식은 이름 옆 금색 테두리 칩이다. */
.d2r .name-row span {
  padding: 0.12rem 0.32rem;
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.2rem;
  color: var(--d2r-gold);
  font-size: var(--text-caption);
}

.d2r .name-en {
  margin: 0.15rem 0 0;
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
}

/* 어느 무기에 붙는 룬워드인지가 이 줄이다. 금색으로 서는 유일한 본문 줄이라 카드에서 먼저 읽힌다. */
.d2r .bases {
  margin: 0.5rem 0 0;
  color: var(--d2r-gold);
  font-size: var(--text-caption);
  line-height: 1.4;
}

.d2r .requirements {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.55rem;
  margin-top: 0.65rem;
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
}

/* 요구치는 쉼표가 아니라 가운뎃점으로 갈린다. */
.d2r .requirements span + span {
  position: relative;
  padding-left: 0.55rem;
}

.d2r .requirements span + span::before {
  position: absolute;
  left: 0;
  color: var(--d2r-gold-soft);
  content: '·';
}

.d2r .stat-groups {
  align-self: center;
  min-width: 0;
  text-align: left;
}

/*
 * 카드의 `.stats` 다. 상세 화면(`.detail-grid .stats`)도 같은 클래스를 쓰지만 레거시에서
 * 각자 컴포넌트 scoped 스타일이라 안 부딪혔다 — 우리는 시트가 하나라 `.item-card` 로 가른다.
 */
.d2r .item-card .stats {
  padding-left: 1rem;
  color: var(--d2r-stat);
  font-size: var(--text-meta);
  line-height: 1.5;
}

.d2r .item-card .stats li,
.d2r .piece-bonuses li {
  overflow-wrap: break-word;
}

/* 세트 조각 보너스 판. 위에 실선이 서고 이름 칸(5.5rem)과 목록 칸이 나란한 두 칸 표다 — 원본에 있던 판인데 우리 시트엔 빠져 있었다. */
.d2r .piece-bonuses {
  display: grid;
  gap: 0.35rem;
  margin-top: 0.65rem;
  padding-top: 0.65rem;
  border-top: 1px solid var(--d2r-line);
  font-size: var(--text-meta);
  line-height: 1.5;
}

.d2r .piece-bonuses > div {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  gap: 0.5rem;
}

.d2r .piece-bonuses strong {
  color: var(--d2r-text-muted);
}

.d2r .piece-bonuses ul {
  color: var(--d2r-set-bonus);
}

/* 아래 여백이 없는 게 원본(`D2RCard.vue` 의 `.set-count{margin-top:.6rem}`) — 스킨의 p 기본 아래 여백(12px)이 카드를 171.3 으로 키웠다. */
.d2r .set-count {
  margin: 0.6rem 0 0;
  color: var(--d2r-set-bonus);
  font-size: var(--text-caption);
}

/* 옵션 칸은 13rem 밑으로 못 내려간다. 그래서 960 아래는 세 칸을 두 칸으로 접고 옵션을 이름 밑으로 내린다. */
@media (max-width: 60rem) {
  .d2r .item-card:not(.compact) {
    grid-template-columns: 7rem minmax(0, 1fr);
  }

  .d2r .item-card:not(.compact) .stat-groups {
    grid-column: 2;
  }

  .d2r .item-card:not(.compact) .stats {
    padding-left: 0;
  }

  .d2r .item-card:not(.compact) .visual {
    grid-row: 1 / span 2;
  }

  .d2r .gb-identity {
    justify-content: start;
  }
}

@media (max-width: 37.5rem) {
  .d2r .item-card:not(.compact) {
    grid-template-columns: 5.5rem minmax(0, 1fr);
    gap: 0.75rem;
    min-height: auto;
    padding: 0.85rem;
  }

  .d2r .item-card:not(.compact) .visual {
    justify-content: start;
    border-right: 1px solid var(--d2r-line);
  }

  .d2r .item-card:not(.compact) .item-image {
    width: 58px;
    height: 76px;
  }

  .d2r .item-card:not(.compact) .runes img {
    width: 23px;
    height: 23px;
  }

  .d2r .item-card .stats {
    font-size: var(--text-caption);
  }
}

/*
 * 좁은 카드는 세로다 — 그림, 이름, 옵션이 위에서 아래로 선다. 로컬은 두 칸 격자에 옵션을
 * 아예 숨겼는데, 레벨별 화면에서 옵션은 그 레벨에 그 아이템을 드는 이유라 숨기면 카드에
 * 이름만 남는다. 운영은 최소 18rem 을 주고 셋을 다 싣는다.
 */
.d2r .item-card.compact {
  display: flex;
  min-height: 18rem;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.9rem;
}

.d2r .item-card.compact .visual {
  min-height: 5.2rem;
  border-right: 0;
  border-bottom: 1px solid var(--d2r-line);
}

.d2r .item-card.compact .item-image {
  width: 60px;
  height: 70px;
}

.d2r .item-card.compact .gb-identity {
  align-items: center;
  text-align: center;
}

.d2r .item-card.compact .name-row {
  justify-content: center;
}

.d2r .item-card.compact .requirements {
  justify-content: center;
  margin-top: 0.4rem;
}

.d2r .item-card.compact .stat-groups {
  align-self: stretch;
  text-align: center;
}

/* 가운데로 모은 줄에 점을 달면 점만 왼쪽 끝에 남는다. 운영도 좁은 카드에서만 점을 뗀다(원본 scss 엔 없고, 운영 계산 스타일 대조로 확인한 값). */
.d2r .item-card.compact .stats {
  padding: 0;
  list-style: none;
  font-size: var(--text-caption);
}

.d2r .item-card.compact .piece-bonuses {
  font-size: var(--text-caption);
}

.d2r .item-card.compact .piece-bonuses > div {
  grid-template-columns: 1fr;
}

/* 세트 요약 카드(조각 수만 보여줄 때, 옵션 없음)는 두 칸이다. 우리 시트엔 통째로 빠져 있었다. */
.d2r .item-card.set-summary {
  grid-template-columns: 7.5rem minmax(0, 1fr);
  min-height: 10.5rem;
}

.d2r .item-card.set-summary .gb-identity {
  align-items: flex-start;
}

.d2r .item-card.set-summary .item-image {
  width: 70px;
  height: 90px;
}

/* ------------------------------------------------------------------ 상세 */

.d2r.d2r-detail .back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.8rem 0;
  color: var(--d2r-text-muted);
}

.d2r .detail-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(16rem, 1fr);
  gap: 1rem;
  align-items: start;
}

/* 상세의 판 둘은 원본 값이다 — 1.5rem 여백, 0.5rem 둥근 모서리, 진한 테두리, 판 바탕(2026-09-16 운영 대조로 확인). */
.d2r .detail-grid > article,
.d2r .detail-grid > aside {
  padding: 1.5rem;
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.5rem;
  background: var(--d2r-panel);
}

.d2r .detail-grid > article {
  display: grid;
  grid-template-columns: 12rem minmax(0, 1fr);
  gap: 1.5rem;
}

/* `display: block` 은 레거시 `_reset.scss:6` 의 img 기본값이다 — inline 으로 두면 그림 아래 줄상자 틈(실측 7.6)이 생겨 `.visual`·article 이 커진다. */
.d2r .detail-grid .visual img {
  display: block;
  width: 100%;
  max-height: 16rem;
  object-fit: contain;
  image-rendering: pixelated;
}

.d2r .detail-grid .visual .runes {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-bottom: 0.7rem;
}

.d2r .detail-grid .visual .runes span {
  display: grid;
  justify-items: center;
  color: var(--d2r-gold);
  font-size: var(--text-caption);
}

/*
 * 룬 이름은 레거시 `_typography.scss` 의 `small { font-size: var(--text-caption) }` — 스킨은
 * `small` 에 더 작은 크기를 줘 룬 무리가 3.5px 낮아졌다(2026-09-17 실측 10.8px→13px).
 */
.d2r .detail-grid .visual .runes small {
  font-size: var(--text-caption);
}

.d2r .detail-grid .visual .runes img {
  width: 2rem;
  height: 2rem;
  object-fit: contain;
  image-rendering: pixelated;
}

.d2r .labels {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.d2r .labels span {
  padding: 0.15rem 0.4rem;
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.25rem;
  color: var(--d2r-gold);
  font-size: var(--text-caption);
}

/* 제목 아래 0.5rem 은 스킨 h1 기본값이다 — 레거시 `_reset.scss` 는 h1 여백이 0 이라 뗀다. 줄높이 1.25 는 `_typography.scss:3` 의 h1 값(스킨은 1.3 이라 36.4 로 나왔다 — 운영 35). */
.d2r.d2r-detail h1 {
  margin: 0;
  font-size: var(--text-title-lg);
  line-height: 1.25;
}

/* baseName·영문명·별칭 줄은 레거시에 전용 규칙이 없다 — `_reset.scss:8`(p 여백 0)과 본문 값(16px/1.6)을 그대로 받는다. */
.d2r .detail-grid > article > div > p:not(.base-types) {
  margin: 0;
}

/* 크래프트 가능 베이스 줄만 금색이다 — 원본 값. */
.d2r .base-types {
  margin-top: 0.8rem;
  color: var(--d2r-gold);
}

/*
 * 카드의 `.stats` 와 이름이 같지만 상세 전용이다(`.detail-grid` 안쪽으로 가른다). 옵션 목록엔
 * 위 여백도 줄 사이 여백도 없어야 하는데, 스킨의 기본 목록 여백이 살아 있으면 카드 쪽 높이가
 * 어긋난다 — 그래서 `ul.stats` 는 일단 0 으로 눕히고 상세만 원본 값(1rem)을 다시 올린다.
 */
.d2r ul.stats {
  margin: 0;
}

/* 줄머리 점도 들여쓰기도 없다 — 줄마다 알약이 붙는 목록이라 점이 있으면 줄이 어긋난다. */
.d2r .detail-grid .stats {
  margin-top: 1rem;
  padding-left: 0;
  color: var(--d2r-stat);
  line-height: 1.55;
  list-style: none;
}

/* 옵션 줄 끝의 「같은 옵션 보기」 알약(`D2RDetail.vue:31`). 여백은 아래 `li` 의 gap 이 준다. */
.d2r .option-link {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.25rem;
  min-height: 2rem;
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--d2r-line-gold);
  border-radius: 99px;
  color: var(--d2r-gold-soft);
  font-size: var(--text-caption);
  white-space: nowrap;
}

.d2r .option-link:hover {
  background: var(--d2r-panel-subtle);
  color: var(--d2r-gold);
}

/* 알약이 줄 오른쪽 끝에 서야 옵션 글자와 안 엉킨다. */
.d2r .detail-grid .stats li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.d2r .base-stats {
  margin-bottom: 1rem;
  padding-bottom: 0.8rem;
  color: var(--d2r-stat);
  border-bottom: 1px solid var(--d2r-line);
  font-size: var(--text-meta);
  line-height: 1.6;
}

/*
 * aside 의 머리(「기본 정보」)와, 상세 페이지 바로 아래 오는 section 들(세트 보너스·변형·구성원)의
 * 머리가 같은 값이다. `> h2` 로 좁히는 이유: 레거시는 scoped 라 이 규칙이 자식 컴포넌트 안의 h2
 * (관련 아이템 머리·카드 이름)까지 닿지 않았다 — 후손 선택자로 두면 카드 이름에 0.8rem 이 붙어
 * 카드가 13px 커진다(2026-09-17 실측).
 */
.d2r .detail-grid > aside h2,
.d2r.d2r-detail > section > h2 {
  margin-bottom: 0.8rem;
  color: var(--d2r-gold);
  font-size: var(--text-body-lg);
  /* `_typography.scss:4` 의 h2 줄높이다 — 스킨 1.3(22.1)이면 운영 22.95 보다 낮다. */
  line-height: 1.35;
}

.d2r .detail-grid dl {
  margin: 0;
}

/* 원본은 flex space-between 이다 — dt 폭은 글자대로, dd 는 오른쪽 끝에 붙는다. 6rem 격자로 두면 긴 dt(영문명 등)가 두 줄로 접힌다. */
.d2r .detail-grid dl > div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.48rem 0;
  border-top: 1px solid var(--d2r-line);
}

.d2r .detail-grid dt {
  color: var(--d2r-text-dim);
  /* 엔진의 dt 기본값(14px)을 누르고 본문 크기로 둔다 — 원본엔 전용 규칙이 없어 body 16px 이다. */
  font-size: var(--text-body);
}

.d2r .detail-grid dd {
  margin: 0;
  color: var(--d2r-text);
  text-align: right;
}

.d2r .set-link {
  display: block;
  margin-top: 1rem;
  padding: 0.65rem;
  color: var(--d2r-gold);
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.35rem;
  text-align: center;
}

/* 상세의 절(관련 아이템·세트 보너스·변형·구성원)은 위의 판 둘과 같은 표면이다 — 원본 `.d2r-detail > section` 이 같은 규칙에 묶여 있다. */
.d2r.d2r-detail > section {
  margin-top: 1rem;
  padding: 1.5rem;
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.5rem;
  background: var(--d2r-panel);
}

.d2r .set-bonuses > div,
.d2r .variants > div {
  display: grid;
  padding: 0.65rem 0;
  border-top: 1px solid var(--d2r-line);
}

.d2r .set-bonuses > div {
  grid-template-columns: 8rem minmax(0, 1fr);
}

.d2r .variants > div {
  grid-template-columns: 7rem minmax(0, 1fr);
}

.d2r .variants strong {
  color: var(--d2r-gold);
}

.d2r .set-bonuses li {
  color: var(--d2r-set-bonus);
}

.d2r .variants li {
  color: var(--d2r-stat);
}

.d2r .members {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.75rem;
}

/* 거래 정보. 레거시 `D2RTradeInfo.vue` — 접기(`.toggle`)만 `<details>` 로 바뀌었다. */
.d2r .trade-info {
  margin-top: 1.2rem;
}

.d2r .trade-info .shared {
  margin-bottom: 0.5rem;
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
}

.d2r .trade-info .entry {
  padding: 0.45rem 0;
  border-top: 1px solid var(--d2r-line);
}

.d2r .trade-info .entry-label {
  display: block;
  color: var(--d2r-text);
}

.d2r .trade-info .gb-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.3rem;
}

.d2r .trade-info .rule,
.d2r .trade-info .note {
  margin-top: 0.3rem;
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
  line-height: 1.5;
}

/* 레거시는 자바스크립트 토글 단추다. 여기는 `<details>` 라 여는 것은 기본 `summary` 가 한다 — 값은 원본 `.toggle`. */
.d2r .trade-info summary {
  margin-top: 0.6rem;
  padding: 0.45rem;
  color: var(--d2r-text-muted);
  border: 1px solid var(--d2r-line);
  border-radius: 0.3rem;
  cursor: pointer;
}

.d2r .trade-info summary:hover {
  color: var(--d2r-gold);
  border-color: var(--d2r-line-gold);
}

.d2r .trade-info .gb-more {
  display: block;
  margin-top: 0.7rem;
  padding: 0.55rem;
  color: var(--d2r-gold);
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.35rem;
  text-align: center;
}

/*
 * 꼬리표는 테두리를 글자색으로 받는다(`border: 1px solid currentcolor`). 그래서 아래가 색을
 * 하나씩만 든다. `.gb-tag.late`·`.cond`·`.cash`·`.market-*` 색은 시세 신호고 등급 색과 다른
 * 계열이다 — 값은 원본 그대로(카드 옵션 색 `--d2r-stat` 과 우연히 비슷하지만 다른 색이다).
 */
.d2r .gb-tag {
  padding: 0.05rem 0.35rem;
  border: 1px solid currentcolor;
  border-radius: 0.2rem;
  font-size: var(--text-caption);
  /*
   * 스킨의 `.gb-tag` 는 글 태그용 알약이다 — `min-height: 1.8125rem`, `border: 0`,
   * `border-radius: 999px`, 그리고 밝은 바탕(`--board-notice` #edf8f5)에 강조색 글자.
   * 여기 꼬리표는 테두리를 글자색으로 받는 얇은 상자라 그 셋을 되돌린다. 안 되돌리면
   * 어두운 판 위에 흰 알약이 서고 높이가 24px 대신 29px 이 된다.
   */
  min-height: 0;
  background: transparent;
  color: inherit;
}

.d2r .gb-tag.early {
  color: var(--d2r-gold);
}

.d2r .gb-tag.late {
  color: #7aa7ff;
}

.d2r .gb-tag.cond {
  color: var(--d2r-cond);
}

.d2r .gb-tag.cash {
  color: #6fcf97;
}

.d2r .gb-tag.market-low {
  color: #999;
}

.d2r .gb-tag.market-high {
  color: var(--d2r-market-high);
}

.d2r .gb-tag.market-top {
  color: var(--d2r-market-top);
}

/* 시세 화면의 「일반 시세」 태그 — 원본 `prices.vue` 에만 있고 다른 곳은 안 쓴다. */
.d2r .gb-tag.market {
  color: var(--d2r-text-muted);
}

.d2r .related-items header {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.8rem;
}

/*
 * 이 h2 는 레거시에서 별도 컴포넌트(`D2RRelatedItems.vue`) 안이라 상세의 `section h2` 규칙이
 * 안 닿고 전역 h2 값(`_typography.scss`: `--text-section`·1.35, `_reset.scss` margin 0)을
 * 받았다 — 우리 시트는 하나라 그 값을 여기서 다시 선언한다.
 */
.d2r .related-items header h2 {
  margin: 0;
  font-size: var(--text-section);
  font-weight: var(--weight-semibold);
  line-height: 1.35;
}

.d2r .related-items header p {
  margin: 0;
  color: var(--d2r-text-dim);
  font-size: var(--text-meta);
}

.d2r .related-items header > a {
  flex: none;
  padding: 0.35rem 0.55rem;
  color: var(--d2r-gold-soft);
  border: 1px solid var(--d2r-line-gold);
  border-radius: 0.35rem;
  font-size: var(--text-caption);
}

/* 룬워드 ↔ 베이스. 양쪽 다 한 화면에 수백 줄이라 `<details>` 안에서 연다. */
.d2r .runeword-bases {
  margin-top: 1rem;
  background: var(--d2r-panel);
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.5rem;
}

.d2r .runeword-bases summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  color: var(--d2r-gold);
  font-weight: var(--weight-bold);
  cursor: pointer;
}

.d2r .runeword-bases summary small {
  color: var(--d2r-gold-soft);
  font-weight: var(--weight-normal);
}

.d2r .base-content {
  display: grid;
  gap: 1.2rem;
  padding: 0 1.25rem 1.25rem;
  border-top: 1px solid var(--d2r-line);
}

.d2r .base-content section {
  padding-top: 1.1rem;
}

.d2r .base-content h3 {
  margin-bottom: 0.55rem;
  color: var(--d2r-gold);
  font-size: var(--text-meta);
}

.d2r .tier-head,
.d2r .family {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}

.d2r .tier-head {
  padding: 0.35rem 0.5rem;
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
  text-align: center;
}

.d2r .family + .family {
  margin-top: 0.45rem;
}

.d2r .base {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 4.2rem;
  padding: 0.5rem;
  color: var(--d2r-text);
  background: var(--d2r-panel);
  border: 1px solid var(--d2r-line);
  border-radius: 0.35rem;
}

.d2r .base:not(.gb-empty):hover {
  border-color: var(--d2r-line-gold);
}

.d2r .base img {
  width: 2.5rem;
  height: 3rem;
  flex: 0 0 2.5rem;
  object-fit: contain;
  image-rendering: pixelated;
}

.d2r .base > span:not(.mobile-tier) {
  display: grid;
  min-width: 0;
}

.d2r .base strong {
  font-size: var(--text-meta);
  font-weight: var(--weight-normal);
  line-height: 1.3;
}

.d2r .base small {
  margin-top: 0.15rem;
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
  line-height: 1.3;
}

.d2r .base.base-empty {
  justify-content: center;
  color: var(--d2r-text-dim);
  pointer-events: none;
}

/* 계층 이름은 넓은 화면에서 표 머리가 대신한다. 좁아지면 칸마다 다시 붙는다. */
.d2r .mobile-tier {
  display: none;
}

/* `.base-runewords` 는 자기 h2 를 금색·meta 크기로 따로 잡는다 — 위 aside/section 공통 규칙(body-lg)보다 늦게 서야 이긴다. */
.d2r .base-runewords {
  margin-top: 1rem;
  padding: 1.1rem 1.25rem 1.25rem;
  background: var(--d2r-panel);
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.5rem;
}

.d2r .base-runewords > header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.9rem;
}

.d2r .base-runewords > header h2 {
  margin: 0;
  color: var(--d2r-gold);
  font-size: var(--text-meta);
}

.d2r .base-runewords > header small {
  color: var(--d2r-gold-soft);
  font-size: var(--text-caption);
}

.d2r .socket-group + .socket-group {
  margin-top: 1rem;
}

.d2r .socket-group h3 {
  margin-bottom: 0.5rem;
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
}

.d2r .runeword-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.55rem;
}

.d2r .runeword {
  display: grid;
  gap: 0.3rem;
  padding: 0.6rem 0.7rem;
  color: var(--d2r-text);
  background: var(--d2r-panel-strong);
  border: 1px solid var(--d2r-line);
  border-radius: 0.35rem;
}

.d2r a.runeword:hover {
  border-color: var(--d2r-line-gold);
}

.d2r .runeword strong {
  color: var(--d2r-runeword);
  font-size: var(--text-meta);
  font-weight: var(--weight-normal);
  line-height: 1.3;
}

.d2r .runeword .runes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem;
}

.d2r .runeword .runes img {
  width: 1.15rem;
  height: 1.15rem;
  object-fit: contain;
  image-rendering: pixelated;
}

.d2r .runeword small {
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
  line-height: 1.3;
}

/* --------------------------------------------------------------- 레벨별 */

/*
 * 원본 `.levels` 의 풀블리드 래퍼(`min-height:70vh; margin:-1.4rem -1rem -3rem; ...`)는 안
 * 옮긴다 — 우리 페이지는 스킨 본문 안에 들어가 바깥 여백이 다르다(`.d2r-detail` 도 같다).
 */

/*
 * 머리는 한 줄에 제목과 부제, 그 아래 금색 선 하나다. 로컬은 선이 없고 제목이 26px/700 이라
 * 바로 아래 칩 판과 같은 층으로 읽혔다. 운영 값은 금색 28px/600 이다.
 */
.d2r-levels .level-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0;
  padding: 1rem 0 0.8rem;
  border-bottom: 1px solid var(--d2r-line-gold);
}

.d2r-levels .level-toolbar h1 {
  margin: 0;
  color: var(--d2r-gold);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.25;
}

.d2r-levels .level-toolbar p {
  margin: 0.25rem 0 0;
  color: var(--d2r-text-dim);
  font-size: var(--text-meta);
  line-height: 1.6;
}

/*
 * 거르는 판은 카드다 — 줄 넷을 두 칸에 나눠 담고 판 색과 밝은 테두리를 두른다. 로컬은
 * 테두리만 있는 한 칸이라 줄 넷이 200px 을 먹었다(운영은 106px). 머리에 붙어 따라오는 것도
 * 운영과 같다 — 스킨 머리띠가 `sticky` 라 그 높이(`styles.ts:212` 의 4rem)만큼 내려 둔다.
 */
.d2r .filter-panel {
  position: sticky;
  z-index: var(--z-raised);
  top: var(--app-header-offset);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: min-content;
  align-items: start;
  gap: 0.55rem 1.25rem;
  margin-bottom: 0.5rem;
  padding: 0.8rem !important;
  color: var(--d2r-text) !important;
  background: var(--d2r-panel) !important;
  border: 1px solid var(--d2r-line-strong) !important;
  backdrop-filter: blur(8px);
  transition: top 0.22s ease;
}

/*
 * 넓은 화면에선 판이 늘 펼쳐져 있고 토글은 안 보인다(원본 `level-items.vue:175` 의
 * `.filter-toggle{display:none}`). 마크업은 닫힌 `<details>` 인데, 닫힌 details 는 내용을
 * `::details-content` 에 `content-visibility: hidden` 으로 숨기므로 여기서 다시 보이게 한다.
 * `.level-head`·`.level-filters` 의 상자도 지운다 — 남아 있으면 판의 `position: sticky` 가
 * 짧은 부모 안에 갇혀 머리에 붙어 따라오지 못한다.
 */
@media (min-width: 800.02px) {
  .d2r-levels .level-head,
  .d2r-levels .level-filters {
    display: contents;
  }

  .d2r-levels .level-filters::details-content {
    content-visibility: visible;
  }
}

/*
 * `::details-content` 를 모르는 브라우저에선 위 규칙이 무시돼 판이 닫힌 채 남는다 — 그때는
 * 토글을 데스크톱에도 남겨 똑같이 열게 한다. 지원하면 판이 늘 열려 있으니 토글을 숨긴다.
 */
@supports selector(details::details-content) {
  @media (min-width: 800.02px) {
    .d2r-levels .level-filters > summary {
      display: none;
    }
  }
}

/* 이름과 칩이 두 칸이다. 이름 칸을 고정해 두면 줄 넷의 칩이 같은 자리에서 시작한다. */
.d2r .filter-row {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  align-items: center;
  gap: 1rem;
}

.d2r .filter-row > strong {
  color: var(--d2r-gold-soft);
  font-size: var(--text-caption);
  white-space: nowrap;
}

/* 판 안의 레벨별 칩은 한 치수 작다 — 줄이 넷이라 그만큼이 판 높이로 곱해진다. */
.d2r-levels .filter-chip {
  min-width: 2.2rem;
  min-height: 2.1rem;
  padding: 0.38rem 0.58rem;
  flex: 0 0 auto;
}

/* 레벨 점프 줄은 옆으로 민다 — 서른 칸이 넘어 접으면 판이 화면을 다 먹는다. */
.d2r-levels .jumps {
  overflow-x: auto;
}

/* 한 줄 안의 칩은 안 접고 옆으로 민다 — 레벨 점프는 서른 칸이 넘어 접으면 판이 화면을 다 먹는다. */
.d2r .filter-row .filter-chips {
  flex-wrap: nowrap;
  gap: 0.3rem;
  overflow-x: auto;
}

/* 점프 칸이 `#level-NN` 로 떨어진다. 머리에 여백을 두지 않으면 줄이 가장자리에 붙는다. */
.d2r .level-row {
  scroll-margin-top: calc(var(--app-header-offset) + 6rem);
  display: grid;
  grid-template-columns: 4.8rem minmax(0, 1fr);
  gap: 1rem;
  padding-top: 1.4rem;
}

/*
 * 레벨은 금색 명패다 — 줄 위에 얹혀 따라오고, 카드가 몇 장이든 위에서 4.5rem 만 쓴다. 로컬은
 * 흐린 회색 띠가 줄 전체 높이로 늘어나 어느 줄이 어느 레벨인지 훑기 어려웠다.
 */
.d2r .level {
  position: sticky;
  top: calc(var(--app-header-offset) + 6rem);
  align-self: start;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 4.5rem;
  border: 1px solid var(--d2r-line-gold);
  background: var(--d2r-panel);
  box-shadow: inset 0 0 1rem var(--d2r-glow-gold);
  color: var(--d2r-gold);
  transition: top 0.22s ease;
}

.d2r .level small {
  color: var(--d2r-text-dim);
  font-size: var(--text-caption);
  line-height: 1.6;
}

.d2r .level strong {
  color: var(--d2r-gold);
  font-size: 1.75rem;
  line-height: 1;
}

.d2r .rail-wrap {
  min-width: 0;
  padding: 2px;
}

.d2r .empty-state {
  padding: var(--board-space-7) var(--board-space-4);
  border: 1px dashed var(--board-line);
  border-radius: 0.45rem;
  color: var(--board-dim);
  text-align: center;
}

/* ----------------------------------------------------------------- 시세 */

/*
 * 머리 셋은 운영 값이다 — 제목이 금색 36px(`--text-page`), 부제는 안 흐린 본문 16px, 패치 줄만
 * 작고 흐리다. 로컬은 셋 다 한 단계씩 작고 부제까지 흐려서, 제목이 아래 표의 첫 줄처럼 읽혔다.
 */
.d2r-prices .prices-head {
  margin-bottom: 1rem;
}

.d2r-prices .prices-head h1 {
  margin: 0;
  color: var(--d2r-gold);
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  font-weight: 600;
  line-height: 1.25;
}

.d2r-prices .prices-head p {
  margin: 0.35rem 0 0;
  color: var(--d2r-text);
  font-size: var(--text-body);
  line-height: 1.6;
}

.d2r-prices .prices-head small {
  display: block;
  margin-top: 0.35rem;
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
  line-height: 1.6;
}

/*
 * 범례는 판에 담는다. 원본 마크업이 `<AppSurface class="legend">`(`prices.vue:10`) 라
 * 판 값은 그 컴포넌트가 주고 `.legend` 규칙엔 색이 없다 — 우리는 맨 `div` 라 여기서 준다.
 * 값은 운영 실측(#17120d · 금색 18%)이고 곧 `--color-surface`·`--color-line` 이다.
 */
.d2r .legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  margin: 0 0 1rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--color-line);
  background: var(--color-surface);
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
  line-height: 1.6;
}

.d2r .legend span {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

/*
 * 점 다섯의 색은 운영 값이고, 아래 꼬리표(`.gb-tag`)와 짝이다. 로컬은 초반을 초록, 후반과
 * 상급을 둘 다 금색으로 써서 범례에 같은 색 점이 두 개 있었다 — 색이 뜻을 나르는 자리에서
 * 그건 범례가 아니다.
 */
.d2r .dot {
  display: inline-block;
  flex: 0 0 auto;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--d2r-text-muted);
}

.d2r .dot.early {
  background: var(--d2r-gold);
}

.d2r .dot.late {
  background: var(--d2r-stat);
}

.d2r .dot.cond {
  background: var(--d2r-cond);
}

.d2r .dot.low {
  background: #999999;
}

.d2r .dot.top {
  background: var(--d2r-market-top);
}

/* 시세 화면은 칩 줄을 공통 값이 아니라 자기 값으로 완전히 덮는다 — 원본이 그렇다. */
.d2r-prices .filter-chips {
  gap: 0.4rem;
  margin-bottom: 0.55rem;
}

/*
 * 여기 칩은 패딩·색·테두리만 다시 잡는다. 최소 높이(2.35rem)는 **공통 칩 값 그대로 남는다** —
 * `prices.vue:200` 은 높이를 안 적는데 그건 안 준다는 뜻이 아니라 `_filters.scss` 값을
 * 물려받는다는 뜻이다. 예전에 이걸 「안 준다」로 읽고 `min-height: 0` 을 넣어 칩이 운영보다
 * 2px 낮았다(35.6 vs 37.6).
 */
.d2r-prices .filter-chip {
  padding: 0.4rem 0.7rem;
  color: var(--d2r-text-muted);
  background: none;
  border: 1px solid var(--d2r-line-strong);
  border-radius: 0.3rem;
}
/* 고른 칩 값(테두리·판 금색)은 위쪽 공통 `.filter-chip.active` 규칙이 이미 준다 — 여기서 또 안 잡는다. */

/* 아이템 한 줄의 태그 묶음. */
.d2r-prices .gb-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.25rem;
}

/*
 * 「저가 포함」은 칩 줄의 오른쪽 끝이다(운영 `.low-toggle { margin-left: auto }`). 운영은 칩과
 * 스위치가 한 폼인데 이쪽은 보내는 값이 달라 폼이 둘이라, 줄을 하나 만들어 둘을 담는다.
 * 좁은 화면에서는 줄을 바꿔 왼쪽에 붙는다.
 */
.d2r .price-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.55rem;
}

/*
 * 보내는 값이 달라 폼은 둘이지만 상자를 지우면(`display: contents`) 단추들이 위 줄의 칩으로
 * 직접 선다 — 운영의 한 `.filter-chips` 와 같은 나열이 된다. 폼 자기 margin 이 남아 줄 높이를
 * 밀던 것도 이걸로 사라진다.
 */
.d2r .price-filters > form {
  display: contents;
}

/* 「저가 포함」은 칩 줄의 오른쪽 끝이다(운영 `.low-toggle { margin-left: auto }`). */
.d2r .price-filters .low-toggle {
  margin-left: auto;
}

.d2r .low-hidden-note {
  margin: 0 0 1.5rem;
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
  line-height: 1.6;
}

/* 갈래 제목은 금색에 밑줄 한 줄이다. 로컬은 줄이 없어 아래 작은 제목과 같은 층으로 보였다. */
.d2r .price-group {
  margin-bottom: 2rem;
}

.d2r .price-group h2 {
  margin: 0;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--d2r-line-strong);
  color: var(--d2r-gold);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
}

.d2r .group-note {
  margin: 0.6rem 0;
  color: var(--d2r-text-muted);
  font-size: var(--text-caption);
  line-height: 1.6;
}

.d2r .section-title {
  margin: 1rem 0 0.55rem;
  color: var(--d2r-text-muted);
  font-size: var(--text-meta);
  /* `h3` 다. 원본은 굵기를 안 잡고 공통 제목 값(600)을 받는데 스킨은 700 을 건다. */
  font-weight: var(--weight-semibold);
  /* 원본은 줄높이도 안 잡는다 — 공통 `h3` 값 1.4 다(`_typography.scss`). 스킨은 1.3 을 건다. */
  line-height: 1.4;
}

.d2r .price-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 0.5rem;
  margin: 0.6rem 0 0;
  padding: 0;
  list-style: none;
}

.d2r .price-grid.wide {
  grid-template-columns: repeat(auto-fill, minmax(21rem, 1fr));
}

.d2r .price-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--d2r-line);
  border-radius: 0.35rem;
  background: var(--d2r-panel);
  transition: border-color 0.18s;
}

.d2r .price-item:hover {
  border-color: var(--d2r-line-gold);
}

.d2r .price-item .hit {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
}

/*
 * 스프라이트는 원래 크기가 작아 늘리면 뭉갠다. 운영은 34x40 에 `pixelated` 로 못을 박아 둔다 —
 * 도트 그림은 흐리게 늘리는 것보다 계단이 보이는 게 낫다.
 */
.d2r .price-item .gb-icon {
  width: 34px;
  height: 40px;
  flex: 0 0 auto;
  object-fit: contain;
  image-rendering: pixelated;
}

.d2r .price-item .gb-body {
  min-width: 0;
}

.d2r .price-item .name {
  display: block;
  line-height: 1.35;
  overflow-wrap: break-word;
}

/* 시세 규칙은 금색, 메모는 흐린 색. 둘 다 이름 아래 한 칸이다. */
.d2r .price-item .market-note,
.d2r .price-item .note {
  display: block;
  margin-top: 0.25rem;
  font-size: var(--text-caption);
  line-height: 1.4;
}

.d2r .price-item .market-note {
  color: var(--d2r-gold);
}

.d2r .price-item .note {
  color: var(--d2r-text-muted);
}

/* ------------------------------------------------------------- 좁은 화면 */

/* 목록 `.content` 는 60rem 에서 접지 않는다 — 원본 `index.vue` 는 760(`below(tablet)`) 이하에서만 한
 * 칸이 되고, 그 위에서는 14rem 곁칸이 남는다. 접히는 자리는 위쪽 47.5rem 판이다. */

/*
 * 원본 `level-items.vue` 의 `@include below(tablet-wide)`(800px) 분기다. 전에는 눈으로 잰
 * 40rem(640px) 이었다 — 원본 폭으로 바꿨다.
 */
@media (max-width: 800px) {
  /*
   * `_filters.scss:75` 의 `below(tablet-wide)`(800px) 분기다 — 이 폭에서 칩이 한 치수
   * 작아진다(높이 2.35→2.1rem, 줄높이 본문 1.6→1.3). 원본의 `padding:.25rem .4rem` 은
   * prices.vue 가 자기 칩 값(.4rem .7rem)으로 이기므로 여기서도 위쪽 `.d2r-prices .filter-chip`
   * 값이 그대로 선다.
   */
  .d2r-prices .filter-chip {
    min-width: 0;
    min-height: 2.1rem;
    line-height: 1.3;
    white-space: normal;
  }

  /*
   * 좁으면 판이 접힌다 — 원본 `level-items.vue:6,42,180` 의 `filter-toggle` 과
   * `filter-panel.open` 을 `details`/`summary` 로 옮겼다(스크립트 없음). details 의 상자를
   * 지우면(`display: contents`) 토글과 판이 `.level-head` 의 flex 줄에 직접 선다: 첫 줄은
   * 제목+토글이고, 열린 판은 다음 줄 전체 폭을 쓴다. 원본도 이 폭에서 판을 접고 단추로 연다 —
   * 조건이 걸린 주소도 처음엔 닫혀 있다(`filtersOpen = ref(false)`).
   */
  .d2r-levels .level-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    border-bottom: 1px solid var(--d2r-line-gold);
  }

  .d2r-levels .level-head .level-toolbar {
    flex: 1;
    min-width: 0;
    border-bottom: none;
  }

  .d2r-levels .level-filters {
    display: contents;
  }

  /* 토글 모양은 원본 `.filter-toggle`(`level-items.vue:175,180`) 그대로다. */
  .d2r-levels .filter-toggle {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex: none;
    min-height: 2.75rem;
    padding: 0.5rem 0.7rem;
    color: var(--d2r-gold);
    font-size: inherit;
    font-weight: inherit;
    background: var(--d2r-panel);
    border: 1px solid var(--d2r-line-gold);
    border-radius: 0.35rem;
    list-style: none;
    cursor: pointer;
  }

  .d2r-levels .filter-toggle::-webkit-details-marker {
    display: none;
  }

  /* 닫힘·열림 낱말 — 원본은 `filtersOpen` 에 따라 글자를 바꿨다. */
  .d2r-levels .level-filters .when-open {
    display: none;
  }

  .d2r-levels .level-filters[open] .when-closed {
    display: none;
  }

  .d2r-levels .level-filters[open] .when-open {
    display: inline;
  }

  /*
   * 열린 판은 다음 줄 전체 폭을 쓴다. flex 줄에 서는 것은 판 자체가 아니라 details 가 만드는
   * `::details-content` 상자다 — 판에 `flex-basis` 를 줘도 안 먹는다(실측).
   */
  .d2r-levels .level-filters::details-content {
    order: 3;
    flex-basis: 100%;
  }

  /* 열린 동안에도 금색 선은 제목 줄 아래에 그대로다 — 머리 선이 판 밑으로 내려가지 않게. */
  .d2r-levels .level-head:has(.level-filters[open]) {
    border-bottom: none;
  }

  .d2r-levels .level-head:has(.level-filters[open])::after {
    content: '';
    order: 2;
    flex-basis: 100%;
    border-top: 1px solid var(--d2r-line-gold);
  }

  .d2r .filter-panel {
    position: static;
    grid-template-columns: 1fr;
    margin-top: 0.5rem;
    padding: 0.7rem !important;
  }

  /* 판 안 줄은 원본 `_filters.scss:62-67` 그대로다 — 이름 칸을 남기고 칸 사이만 좁힌다. */
  .d2r .filter-row {
    align-items: start;
    gap: 0.45rem;
  }

  .d2r .filter-row > strong {
    margin-top: 0.38rem;
    font-size: var(--text-meta);
  }

  /* 칩은 옆으로 미는 대신 칸을 나눠 접는다 — 원본 `_filters.scss:70-75` 와 같은 손이다. */
  .d2r .filter-row .filter-chips {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(4.25rem, 1fr));
    overflow-x: visible;
  }

  .d2r-levels .filter-chip {
    min-height: 2.1rem;
    padding: 0.25rem 0.4rem;
    line-height: 1.3;
    white-space: normal;
  }

  /*
   * 레벨 줄 카드는 폰에서도 세로로 쌓인다 — 원본은 `level-items.vue:180` 의 모바일 분기가 옆
   * 스크롤(`scroll-snap`)을 넣지만, 바로 뒤 같은 파일 `:182` 의 범위 없는 규칙이
   * `overflow:visible`·wrap 격자로 덮어 실제 운영은 카드가 한 열로 늘어선다(운영 390 카드
   * x82.8·w289.2 실측과 일치). 전에는 이 분기로 옆 띠를 만들었다 — 지운다.
   */

  .d2r .level-row {
    grid-template-columns: 3.4rem minmax(0, 1fr);
    gap: 0.65rem;
    scroll-margin-top: calc(var(--app-header-offset) + 1rem);
  }

  .d2r .level {
    top: calc(var(--app-header-offset) + 1rem);
    min-height: 3.5rem;
  }

  .d2r .level strong {
    font-size: var(--text-title);
  }

  .d2r-levels .level-toolbar h1 {
    font-size: 1.25rem;
  }

  .d2r-levels .level-toolbar p {
    font-size: var(--text-caption);
  }
}

/* 원본 `prices.vue` 의 `@include below(mobile)`(600px) 분기 — 카드가 한 칸이 된다. */
@media (max-width: 600px) {
  .d2r .price-grid,
  .d2r .price-grid.wide {
    grid-template-columns: 1fr;
  }

  /* 원본 `below(mobile)`(600px) 의 `.low-toggle { margin-left: 0 }` — 좁으면 왼쪽에 붙는다. */
  .d2r .price-filters .low-toggle {
    margin-left: 0;
  }
}

/* 원본 `tablet-narrow`(700px) 분기 — 룬워드 베이스 계층표가 여기서 접힌다. 40rem(640px) 분기와 값이 달라 따로 둔다. */
@media (max-width: 700px) {
  .d2r .base-runewords {
    padding-inline: 0.8rem;
  }

  .d2r .runeword-grid {
    grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  }

  .d2r .base-content {
    padding-inline: 0.8rem;
  }

  .d2r .tier-head {
    display: none;
  }

  .d2r .family {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.3rem;
    padding: 0.35rem;
    background: var(--d2r-panel-strong);
    border: 1px solid var(--d2r-line);
    border-radius: 0.4rem;
  }

  .d2r .family + .family {
    margin-top: 0.7rem;
  }

  .d2r .base {
    min-height: 3.7rem;
  }

  .d2r .base.base-empty {
    display: none;
  }

  .d2r .mobile-tier {
    display: block;
    width: 4.2rem;
    flex: 0 0 4.2rem;
    color: var(--d2r-gold-soft);
    font-size: var(--text-caption);
  }
}

/* 폰에서는 판이 화면 끝까지 간다. 좌우 8px 를 남기면 어두운 판이 종이에 붙인 쪽지로 보인다. */
@media (max-width: 47.5rem) {
  .d2r {
    margin-inline: -0.5rem;
    padding-inline: 1rem;
  }

  /*
   * 시세만 예외다 — 원본 prices.vue 의 뿌리는 `.d2r` 가 아니라 `.prices` 라 판의 음수 마진·
   * 패딩을 안 받고 `.container`(좁으면 좌우 8px) 안에 그대로 선다. 그래서 운영 시세 폰 화면은
   * 다른 D2R 화면(x16)과 달리 x8 다.
   */
  .d2r.d2r-prices {
    margin-inline: 0;
    padding-inline: 0;
  }

  .d2r .page-head h1 {
    font-size: var(--text-title);
  }

  .d2r .gb-search {
    margin-top: 1rem;
  }

  .d2r .search-help {
    line-height: 1.45;
  }

  .d2r .rarities {
    gap: 0.3rem;
  }

  .d2r .rarities button {
    min-height: 2.7rem;
    font-size: var(--text-caption);
  }

  /* 원본 `D2RRelatedItems.vue` 의 `below(tablet)` 분기 — 관련 아이템이 한 열이 된다. */
  .d2r .related-grid {
    grid-template-columns: 1fr;
  }

  /* 같은 분기에서 세트 목록도 한 열이다(원본 `items/index.vue:316` 의 `below(tablet)` 안 `.set-grid{grid-template-columns:1fr}`). */
  .d2r .set-grid {
    grid-template-columns: 1fr;
  }

  /*
   * 상세 격자의 폰 분기는 원본 `D2RDetail.vue` 의 `@include below(tablet)`(760px)다 — 처음엔
   * `.content` 와 같이 60rem 에 묶여 있어 760~960 사이에서 한 칸으로 접혔다(900 실측).
   * 같은 분기의 나머지 손(article 한 칸·그림 12rem·세트/변형 한 칸)도 같이 온다.
   */
  .d2r .detail-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .d2r .detail-grid > article {
    grid-template-columns: minmax(0, 1fr);
  }

  .d2r .detail-grid .visual img {
    max-height: 12rem;
  }

  .d2r .set-bonuses > div,
  .d2r .variants > div {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* -------------------------------------------------------------- 해외반응 */

/*
 * 해외반응 목록 한 줄의 출처(레거시 `PostRows.vue:20-23,73-76`).
 *
 * 코어가 슬롯을 제목 링크 바깥, 행의 제목 아래에 놓으므로(`skins/board/src/index.tsx` 의
 * `listing.row`) 여기서 블록으로 세우면 제 줄을 갖는다. 색은 행의 meta 글과 같게 두고
 * 크기는 운영 실측대로 한 단계 작은 caption(13px)이다 — 제목 아래 보조 줄이라 meta 보다
 * 작아야 제목이 먼저 읽힌다.
 */
.row-source {
  display: block;
  /* 위 틈 0.2rem(3.2)과 줄높이 1.4(13px→18.2)는 레거시 `.row-source` 값 그대로다. */
  margin: 0.2rem 0 0;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  line-height: 1.4;
}

.row-source:hover {
  color: var(--board-text);
}

/*
 * 출처 줄이 붙은 행은 글이 두 줄이라 고정 높이 그림이 가운데 떠 보인다. 출처가 있을 때만
 * 그림을 4:3 으로 한 단계 키운다(레거시 `.thumbnail.match-lines`). 분기는 출처 줄과 같은
 * 조건(`:has`)을 쓴다 — 둘이 갈리면 어떤 행은 커지고 어떤 행은 안 커지는 이유를 알 수 없다.
 */
.title-row:has(.row-source) .gb-row-thumb {
  width: 60px;
  height: 45px;
  flex-basis: 60px;
}

/* 좁은 화면은 제목이 두 줄로 접혀 글 덩어리가 높아지므로 그림도 한 단계 더 키운다. 비율은 그대로. */
@media (max-width: 43.75rem) {
  .title-row:has(.row-source) .gb-row-thumb {
    width: 72px;
    height: 54px;
    flex-basis: 72px;
  }
}

/*
 * 홈 사이드바(인기·댓글·공지). 운영 카드는 자체 여백이 없다 — 칸마다 47px 제목 띠(16px/600,
 * 위아래 12px, 아래 선)가 카드 폭을 다 채우고, 줄은 12.8px 들어가며, 칸 사이는 선 하나다.
 * 사이드바 칸엔 더 보기 링크가 없다. 제목 좌우를 카드 여백만큼 당기는 띠 규칙은 스킨이 들고
 * 있다가 엔진 `98922f9a`(2026-09-28)에서 뺐다. 운영 모양이라 여기서 든다. 줄의 좌우는 레거시 `.mini` 의 `.8rem`
 * (`index.vue:74`, 모바일도 같은 값 — `:75` 의 `.side .mini` 는 아래만 바꾼다)이라 토큰을
 * .8rem 로 두고, 제목 띠만 레거시 `.side h2` 의 `.9rem` 을 따로 준다.
 */
.gb-area-page-sidebar {
  --board-card-pad: 0.8rem;
  padding-top: 0;
  padding-bottom: 0;
}
.gb-area-page-sidebar .box .box-title,
.gb-area-page-sidebar .gb-widget h2 {
  margin: 0 calc(-1 * var(--board-card-pad));
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
  padding-left: 0.9rem;
  padding-right: 0.9rem;
  border-bottom: 1px solid var(--board-line);
  font-size: var(--board-size-ui);
  line-height: 1.35;
  color: var(--board-ink);
  letter-spacing: 0;
}
/* 운영은 제목 띠 아래 첫 줄까지 4px 를 띄운다. */
.gb-area-page-sidebar .box .box-title + *,
.gb-area-page-sidebar .gb-widget h2 + * {
  margin-top: 0.25rem;
}
.gb-area-page-sidebar > .gb-widget-slot + .gb-widget-slot {
  /* 칸 사이는 선만 둔다 — 스킨의 20px 여백·안쪽선을 걷는다. */
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
/* 칸을 가르는 선은 레거시 `.side section+section` 처럼 칸 자체의 윗선이다 — 슬롯에 두면 칸 높이에서 빠진다. */
.gb-area-page-sidebar > .gb-widget-slot + .gb-widget-slot .gb-widget {
  border-top: 1px solid var(--board-line);
}
/*
 * 위젯의 목록 행에는 출처 줄을 그리지 않는다 — 읽을거리 같은 홈 티저는 제목만으로 충분하고,
 * 출처는 해외반응 목록·글 페이지에서 계속 나온다. `listing.row` 슬롯 전체를 숨긴다.
 */
.gb-widget .gb-slot-listing-row {
  display: none;
}
/*
 * 칸 아래 여백은 레거시 `.mini` 의 아래 padding(.55rem)이다(`index.vue:74`) — 칸 안쪽(`.gb-widget`)
 * 에 둬야 칸 높이가 운영과 같아진다. 슬롯에 두면 여백이 칸 밖으로 빠져 칸이 그만큼 짧게 잰다.
 */
.gb-area-page-sidebar .gb-widget {
  padding-bottom: 0.55rem;
}
/* 운영 `.mini a` 는 한 줄 36.8 — 스킨의 37px(2.3125rem)보다 0.2 작다. */
.gb-area-page-sidebar .box-compact .box-rows li {
  height: 2.3rem;
}
.gb-area-page-sidebar .box-more {
  display: none;
}

/* 운영의 더 보기 링크(전체·더보기·해외반응)는 굵은 말만 있다. 스킨이 붙이는 「›」를 뗀다. */
.box-more a {
  font-weight: 700;
}
.box-more a::after {
  content: none;
}

/*
 * 홈 섹션(최근·게시판·이미지·읽을거리·도구)을 레거시 `pages/index.vue:74-78` 로 맞춘다.
 * `.gb-area-page-*` 는 조립 페이지(`ComposedPage`)만 내므로 이 규칙들은 홈에만 닿는다.
 *
 * 칸 사이 틈은 `--gap-card`(.65rem=10.4) 하나다 — 스킨의 --board-space-3(12) 보다 좁다.
 * 본문↔곁칸·본문↔아래띠는 `.board-main` 격자가, 시세 카드 두 장 사이는 `.gb-area-page-main` 이,
 * 아래띠 안은 `.gb-area-page-bottom` 이 낸다.
 */
.board-main:has(> aside.gb-sidebar:not(:empty)):has(> .gb-area-page-main) {
  gap: 0.65rem;
  /*
   * 본문·곁칸의 열은 레거시 `.home-grid`(`index.vue:74` 의 `minmax(0,2.2fr) minmax(17rem,1fr)`)
   * 다. 스킨은 곁칸을 `--board-compose-w`(365px)로 못박고 60rem 이하에서는 아래로 내리는데
   * (스킨 `styles.ts` 의 조합 격자·60rem 판), 레거시는 760px(`below(tablet)`) 이하에서만 접는다.
   * 이 선택자가 스킨의 접힘 규칙보다 무거워 761~960 에서도 곁칸이 옆에 선다 — 운영 사이드 폭은
   * 768 에서 272(17rem 하한), 1024 에서 306.8 이다. 폰 접힘은 아래 47.5rem 판이 맡는다.
   */
  grid-template-columns: minmax(0, 2.2fr) minmax(17rem, 1fr);
  /*
   * 곁칸 카드는 왼쪽 칸(시세+최근) 아래 끝까지 늘어난다 — 레거시 `.side{grid-row:1/span 2}` 가 격자
   * 기본값 stretch 로 757.8 을 채운다. 스킨의 `align-items: start` 를 되돌리고 안쪽 카드가 곁칸을 채우게 한다.
   */
  align-items: stretch;
}
.board-main:has(> aside.gb-sidebar:not(:empty)):has(> .gb-area-page-main) > aside.gb-sidebar {
  display: flex;
  flex-direction: column;
}
.board-main:has(> aside.gb-sidebar:not(:empty)):has(> .gb-area-page-main) > aside.gb-sidebar > .gb-area-page-sidebar {
  flex: 1 0 auto;
}
.gb-area-page-main,
.gb-area-page-bottom {
  gap: 0.65rem;
}
/* 아래띠는 읽을거리 2fr · 도구 1fr(레거시 `.lower-grid`). 스킨의 3열+span2 와 같은 비율을 열 둘로 그린다. */
.gb-area-page-bottom {
  grid-template-columns: minmax(0, 2fr) minmax(15rem, 1fr);
}
.gb-area-page-bottom > .gb-widget-slot[data-span='2'] {
  grid-column: auto;
}

/*
 * 스킨의 폰 판은 47.99rem(767.84px) 이하, 레거시 홈의 접힘은 760px(`below(tablet)`) 이하다.
 * 그 사이 761~767 에서 스킨이 홈 격자를 먼저 접어 버리므로(스킨 `styles.ts` 의 47.99rem 판이
 * `area-page-*` 를 한 열로, 슬롯을 전폭으로, 타일·카드를 2열로 만든다) 운영의 넓은 배치를
 * 되돌린다 — 시세 두 칸은 `area-page-main` 2열에 span-1 슬롯이 나란히 서는 것이고,
 * 아래 띠의 열 자체는 위 `.gb-area-page-bottom` 규칙이 이기고 있어 span-1 슬롯만 되돌린다.
 */
@media (min-width: 760.02px) and (max-width: 47.99rem) {
  .gb-area-page-main {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .gb-area-page-main > .gb-widget-slot[data-span='1'],
  .gb-area-page-bottom > .gb-widget-slot[data-span='1'] {
    grid-column: auto;
  }

  /* 게시판 타일은 넓은 화면의 4열과 칸 사이 선을 그대로 둔다(레거시 `.board-grid`). */
  .gb-area-page-bottom .box-boards .board-tiles {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .gb-area-page-bottom .box-boards .board-tiles > li:not(:nth-child(4n + 1)) {
    border-left: 1px solid var(--board-line);
  }
  .gb-area-page-bottom .box-boards .board-tiles > li:nth-child(n + 5) {
    border-top: 1px solid var(--board-line);
  }
  .gb-area-page-bottom .box-boards .board-tiles > li:not(:nth-child(odd)) {
    border-left: 0;
  }
  .gb-area-page-bottom .box-boards .board-tiles > li:nth-child(n + 3) {
    border-top: 0;
  }

  /* 이미지 카드도 6열로 되돌린다(레거시 `.gallery-strip`) — 스킨 폰 판의 2열과 칸 사이 12px 를 걷는다. */
  .gb-area-page-bottom .box-cards.box-cards .board-grid.grid-cards {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 0;
  }
}

/*
 * 섹션 머리는 20px/27/600 한 줄에 아래 8.8(레거시 `.section-head{gap:.7rem;margin-bottom:.55rem}`).
 * 스킨 제목의 아래선과 8px 여백을 걷고, 머리 아래 선은 첫 줄의 윗선이 긋는다
 * (레거시 `.feed__row`·`.reading a` 의 border-top — 게시판·이미지 칸은 머리 아래 선이 없다).
 */
.gb-area-page-main .gb-widget .box-title,
.gb-area-page-bottom .gb-widget .box-title {
  margin: 0 0 0.55rem;
  padding: 0;
  border-bottom: 0;
  line-height: 1.35;
}
.gb-area-page-bottom .box-compact .box-rows > li:first-child {
  border-top: 1px solid var(--board-line);
}
/* 제목 오른쪽 링크는 제목 글줄(14px/22.4/700)에 맞춘다 — 인라인이면 상자가 글자만큼만 서서 위가 내려간다. */
.gb-area-page-main .gb-widget > .box-more,
.gb-area-page-bottom .gb-widget > .box-more {
  top: calc(var(--board-card-pad) + 0.2rem);
}
.gb-area-page-main .box-more > a,
.gb-area-page-bottom .box-more > a {
  display: block;
}

/*
 * 최근 줄은 72px 그림과 본문 사이 .75rem(레거시 `.feed__row`), 스킨의 16px 보다 좁다.
 * 스킨은 75px 줄 안에서 그림·본문을 가운데 정렬하는데(align-items:center), 레거시 `.feed__row` 는
 * `padding:.62rem 0` 만 두고 위에서부터 쌓는다 — 본문 덩어리가 그림보다 짧아 가운데 정렬은
 * 첫 글줄을 2.6px 내린다. 위 정렬+레거시 여백으로 되돌린다.
 * 줄 사이 선도 레거시처럼 「줄마다 윗선」이다 — 스킨은 아랫선(border-bottom, 마지막 줄 제외)이라
 * 둘째 줄부터 글이 1px 위로 붙었다. 윗선으로 바꾸면 모든 줄이 같은 자리에 선다.
 * 고정 높이도 뗀다 — 레거시는 내용이 높이를 정해 줄이 74.8 이다(윗선 1 + 여백 19.84 + 그림 54).
 */
.gb-area-page-main .box-digest .box-rows li {
  align-items: flex-start;
  gap: 0.75rem;
  height: auto;
  padding: 0.62rem 0;
  border-top: 1px solid var(--board-line);
  border-bottom: 0;
}
/* 썸네일 모서리 4px — 레거시 `.feed__thumb{border-radius:.25rem}`(`index.vue:74`). 스킨 기본은 --board-radius-s(3px)다. */
.gb-area-page-main .box-digest .digest-cover {
  border-radius: 0.25rem;
}
/* 게시판명과 제목 사이도 레거시 `.feed__title` 처럼 좁게 — 스킨의 8px 이면 제목이 1px 밀린다. */
/*
 * 스킨은 게시판명·제목을 baseline 으로 맞추는데 레거시 `.feed__title` 은 `align-items:center` —
 * 13px 게시판명이 제목 글줄의 가운데에 선다.
 */
.gb-area-page-main .digest-line {
  align-items: center;
  gap: 0.45rem;
}
/* 요약 위 여백 .2rem(레거시 `.feed__body p`) — 스킨은 `margin:0` 이라 제목 글줄에 붙는다. */
.gb-area-page-main .digest-summary {
  margin-top: 0.2rem;
}

/*
 * 스킨 `.box` 의 아래 여백(24)은 격자 행을 그만큼 부풀리고, 행을 채우는 `height:100%` 카드가
 * 늘어나며 아래가 빈다 — 홈은 칸 사이 틈(.65rem)이 이미 벌리므로 뗀다. 다른 박스는 스킨이
 * 이미 `margin:0` 을 줬는데(`.box-list, .box-cards, .box-compact, .box-digest`) 이것만 빠졌다.
 */
.gb-area-page-bottom .box-boards {
  margin-bottom: 0;
}

/* 게시판 타일은 레거시 `.board-grid>a{gap:.55rem;padding:.8rem}` — 위 여백은 머리 margin 이 낸다. */
.gb-area-page-bottom .box-boards .board-tiles {
  padding-top: 0;
}
.gb-area-page-bottom .board-tile {
  gap: 0.55rem;
  padding: 0.8rem;
}

/*
 * 머리 줄과 「전체」 링크는 레거시 `.section-head`(`index.vue:74`): `margin-bottom:.55rem`,
 * 끝 링크는 `color:muted;font-size:meta;font-weight:bold` 다. 스킨 `.box .box-title` 의 밑줄
 * (`styles.ts` 의 `.box .box-title` border-bottom)은 운영에 없고, `.box-more` 의 ` ›` 꼬리도 뺀다.
 * 링크 자리는 스킨이 이미 카드 머리 줄 오른쪽 끝에 절대 위치로 둔다(같은 파일 `.box-more`).
 */
.gb-area-page-bottom .box-boards .box-title {
  margin-bottom: 0.55rem;
  padding-bottom: 0;
  border-bottom: 0;
}
.gb-area-page-bottom .box-boards .box-more a {
  font-weight: 700;
}
.gb-area-page-bottom .box-boards .box-more a::after {
  content: none;
}

/* 게시판 이름 오른쪽의 작은 말(notes) — 레거시 `.board-top{display:flex;justify-content:space-between;gap:.4rem}` (`index.vue:74`). */
.gb-area-page-bottom .board-tile-top {
  gap: 0.4rem;
}

/*
 * 좁은 화면에서는 운영도 이 칸을 통째로 숨긴다 — 레거시 `@include below(tablet){.board-index{display:none}}`
 * (`index.vue:74`), tablet 은 760px(`_breakpoints.scss`).
 */
@media (max-width: 47.5rem) {
  .gb-area-page-bottom .box-boards {
    display: none;
  }
}

/*
 * 이미지 타일은 레거시 `.gallery-strip`: 안쪽 .35rem, 제목 위아래 .45rem, 제목 줄높이 1.6(16px→25.6).
 * 스킨은 타일에 세로 여백이 없고 제목이 20.8 로 붙는다 — 카드가 22px 짧은 게 이것이다.
 */
.gb-area-page-bottom .box-cards.box-cards .board-grid.grid-cards {
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0;
  padding-top: 0;
}
/* 레거시 이미지 칸은 그림·제목·메타뿐이다. 스킨 카드의 16:9 덮개와 요약 줄을 걷는다. */
.gb-area-page-bottom .box-cards.box-cards .cell-cover {
  aspect-ratio: 4 / 3;
}
.gb-area-page-bottom .box-cards.box-cards .cell-summary {
  display: none;
}
.gb-area-page-bottom .box-cards.box-cards .board-grid.grid-cards .cell {
  gap: 0;
  padding: 0.35rem;
}
/* 칸 사이 선은 오른쪽에 둔다(레거시 `.gallery-strip>a{border-right}`) — 첫 카드 안쪽 폭이 1px 줄어 운영 178.3 과 맞다. */
.gb-area-page-bottom .box-cards.box-cards .board-grid.grid-cards .cell {
  border-left: 0;
}
.gb-area-page-bottom .box-cards.box-cards .board-grid.grid-cards .cell:not(:last-child) {
  border-right: 1px solid var(--board-line);
}
.gb-area-page-bottom .box-cards.box-cards .cell-cover {
  border-radius: 0.25rem;
}
.gb-area-page-bottom .box-cards.box-cards .cell-head {
  margin: 0.45rem 0;
}
.gb-area-page-bottom .box-cards.box-cards .cell-title {
  line-height: 1.6;
}

/*
 * 홈 사이드바의 최근 댓글(home-widgets 플러그인). 한 줄에 하나, 넘치면 말줄임 — 레거시 홈과 같은
 * 밀도다. 두 줄로 접으면 일곱 개가 사이드바 절반을 먹는다.
 */
/* `contain` 가 없으면 한 줄로 묶인 글자 폭이 그리드 칸의 최소 폭이 되어 폰에서 페이지가 옆으로 늘어난다. */
.gb-widget-recent-comments .recent-comments {
  contain: inline-size;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* 운영 사이드바는 줄 사이 선이 없고 한 줄이 36.8px 이다 — 16px 글자의 25.6px 줄높이 위아래로 0.35rem(레거시 `.mini a`). */
.gb-widget-recent-comments .recent-comments a {
  display: block;
  padding: 0.35rem 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--board-text);
}

/*
 * 홈 아래 띠의 디아블로 DB 칸. 운영의 `tool-card` 다 — 검은 바탕에 금색 글자, 작은 「도구」, 큰
 * 제목, 회색 한 줄, 칸 전체가 링크. 조립 섹션은 마크다운 한 덩이라 클래스를 못 붙이므로 아래 띠의
 * 마크다운 칸으로 잡고, 링크는 `::after` 로 칸 전체를 덮는다. 색은 운영 값 그대로 두 테마에 같다.
 */
.gb-area-page-bottom .gb-widget-slot-markdown > .gb-widget {
  position: relative;
  display: grid;
  align-content: center;
  padding: 1.3rem;
  border-color: #171614;
  background: #171614;
  color: #aaaaaa;
  font-size: var(--board-size-ui);
}

.gb-area-page-bottom .gb-widget-slot-markdown p {
  margin: 0;
}

.gb-area-page-bottom .gb-widget-slot-markdown p:first-child {
  font-size: var(--board-size-caption);
  color: #f0d27b;
}

.gb-area-page-bottom .gb-widget-slot-markdown a {
  font-size: 1.25rem;
  font-weight: var(--board-weight-bold);
  color: #f0d27b;
  text-decoration: none;
}

.gb-area-page-bottom .gb-widget-slot-markdown a::after {
  content: '';
  position: absolute;
  inset: 0;
}

/*
 * 홈 시세 줄의 두 칸(폰덕·알뜰폰). 두 플러그인이 같은 뼈대를 내고 색·면은 토큰이 정한다 —
 * 폰덕은 phonedeal, 알뜰폰은 mvno 가 `home-market` 계열 클래스로 그린다. 카드 하나가 링크
 * 하나라 안쪽에 블록을 두지 않는다(레거시 `HomeMarket.vue` 의 `market__panel` 자리).
 *
 * 머리와 「더 보기」가 첫 행의 두 칸을 나눠 갖고, 시세 줄 셋이 그 아래를 가로지른다 — 운영
 * 카드의 격자와 같은 자리다. 시세 줄의 칸은 줄 묶음에 한 번만 두고 각 줄은 `display: contents`
 * 로 비켜선다 — 줄마다 제 격자를 가지면 칸 폭이 그 줄 내용에 맞춰져 곁줄·값의 x 가 줄마다
 * 흔들린다(레거시 `.market__items` / `.market__item`).
 *
 * 좁은 화면에서 넘치지 않게 하는 것이 이 블록의 절반이다. 이름·곁줄·값에 `nowrap` 이 걸려
 * 있으므로 `contain: inline-size` 로 카드가 그리드 칸을 밀어 넓히지 못하게 막는다 — 없으면
 * 한 줄로 묶인 글자 폭이 칸의 최소 폭이 되어 폰에서 페이지가 옆으로 늘어난다.
 */
.home-market {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  /* 틈 .5/.8 과 안쪽 여백 .9/1 은 레거시 `.market__panel` 값이다. */
  gap: 0.5rem 0.8rem;
  min-width: 0;
  /* 나란히 선 두 칸이 한 높이로 끝나게 한다 — 슬롯이 격자 stretch 로 늘어나도 카드가 따라간다. */
  height: 100%;
  /* 늘어난 높이는 아래에 남긴다 — 줄이 모자란 카드에서 기본 stretch 가 행을 벌려 값이 카드 한가운데 뜬다. */
  align-content: start;
  padding: 0.9rem 1rem;
  color: var(--board-text);
  background: var(--board-surface);
  border: 1px solid var(--board-line);
  border-radius: var(--board-radius-l);
  box-shadow: var(--board-shadow);
  /* `contain: inline-size` + 질의 컨테이너 — 아래 `@container` 가 이 카드를 잰다(레거시 `HomeMarket.vue:77` 의 `container-type`). */
  container-type: inline-size;
  font-size: var(--board-size-meta);
  text-decoration: none;
  /* hover 전환 폭·시간은 레거시 `HomeMarket.vue:88` 그대로다. */
  transition: border-color 0.15s, box-shadow 0.15s;
}

/*
 * 카드 hover — 운영 `.market__panel:hover`(`HomeMarket.vue:90`): 테두리 `--color-brand-600`
 * (--board-accent, #146c5a)에 `--shadow-md`(`_tokens.scss:24`) — `--site-shadow-md` 가 밝기를 따라간다.
 */
.home-market:hover {
  border-color: var(--board-accent);
  box-shadow: var(--site-shadow-md);
}

/* 머리 — 작은 아이콘, 굵은 이름, 흐린 확인 범위. 좁아지면 확인 범위가 먼저 접힌다. */
.home-market__head {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  min-width: 0;
}

/* 아이콘만 브랜드색을 쓴다 — 글자와 같은 색이면 그냥 기호로 읽힌다. `-text` 쪽을 쓰는 것은 어두운 면에서 밝아져야(`--board-accent` 는 3:1 이 안 된다) 그 선이 보이기 때문이다. */
.home-market__icon {
  flex: none;
  align-self: center;
  color: var(--board-accent-text);
}

.home-market__name {
  flex: none;
  margin-right: 0.1rem;
  color: var(--board-text);
  font-size: var(--board-size-head);
  font-weight: var(--board-weight-bold);
}

.home-market__facts {
  min-width: 0;
  overflow: hidden;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * 카드 안쪽 폭이 좁아지면 확인 범위를 접는다 — 뷰포트가 아니라 카드 자신의 폭에 반응해야,
 * 두 칸이 나란히 서는 1024 처럼 화면은 넓어도 칸이 좁은 자리에서 「N곳 중 M곳 · 날짜」가
 * 중간에서 잘리지 않는다(레거시 `HomeMarket.vue:177-179` 의 `@container (max-width: 19.5rem)`).
 * `.home-market` 의 `contain: inline-size` 가 곧 질의 컨테이너다.
 */
@container (max-width: 19.5rem) {
  .home-market__facts {
    display: none;
  }
}

/*
 * 「더 보기」 — 머리와 같은 행의 오른쪽 끝에 선다. 글자는 흐리고, 끝의 화살표가 「눌러서
 * 넘어간다」를 혼자 말한다. 손을 올리면 브랜드색으로 진해진다.
 */
.home-market__go {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  align-items: center;
  gap: 0.15rem;
  justify-self: end;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  /* 600 — 레거시 `--weight-semibold`. 토큰에 없는 굵기라 고정값이다. */
  font-weight: 600;
  white-space: nowrap;
}

.home-market:hover .home-market__go {
  color: var(--board-accent-text);
}

/*
 * 이름·곁줄·값이 줄마다 같은 칸(같은 x)에 서게 하는 것이 이 격자다. 줄은 `display: contents`
 * 로 비켜서고 자식들이 여기 둔 칸을 직접 차지한다(레거시 `.market__items`). 칸 사이는 gap 이
 * 아니라 곁줄·값의 `padding-left` 가 벌린다 — 값과 그 단위는 붙어 한 덩어리로 읽혀야 하는데
 * gap 은 칸마다 똑같이 벌어져 그 둘까지 떼어 놓는다.
 */
.home-market__rows {
  grid-column: 1 / -1;
  grid-row: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  column-gap: 0;
  row-gap: 0.35rem;
  min-width: 0;
}

/* 한 줄이 곧 한 기종이다 — 이름, 곁줄(통신사·판매처), 값이 한 줄에 나란히 선다. */
.home-market__row {
  display: contents;
}

.home-market__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.home-market__sub {
  min-width: 0;
  overflow: hidden;
  padding-left: 0.9rem;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * 이 줄에서 눈에 띄어야 하는 것은 값 하나다. 숫자는 크고 굵게, 통화 단위는 작고 흐리게 뒤에
 * 붙는다. `tabular-nums` 는 자리마다 숫자 폭이 달라도 값이 흔들리지 않게 한다.
 */
.home-market__value {
  justify-self: end;
  padding-left: 0.9rem;
  /* 운영 `--color-brand-700` — 가격표가 지원금에 쓰는 색과 같다. `--board-brand-700` 이 그 값이다. */
  color: var(--board-brand-700);
  /* 15px — 레거시 `--text-label`. 스킨 눈금(14px/16px) 사이의 값이라 고정값이다. */
  font-size: 0.9375rem;
  font-weight: var(--board-weight-bold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.home-market__unit {
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: 600;
}


/* 밑줄은 이름 하나에만. 카드 전체가 링크라 나머지 글자까지 밑줄이 그이면 값이 안 읽힌다. */
.home-market:hover .home-market__name {
  text-decoration: underline;
}

/*
 * 폰에서는 두 카드가 위아래로 쌓여 본문이 한 화면 아래로 밀린다. 운영도 좁은 화면에서 곁줄을
 * 접고 이름·값만 한 줄로 남긴다 — 그래도 시세 줄 셋은 다 그린다(레거시가 모바일에서 둘만
 * 그리던 것과 다르다).
 */
@media (max-width: 47.5rem) {
  .home-market__sub {
    display: none;
  }

  .home-market__label {
    font-size: var(--board-size-caption);
  }

  .home-market__value {
    font-size: var(--board-size-meta);
  }
}

/*
 * 홈 아래쪽을 운영과 맞춘다. 폰 헤더 햄버거에 게시판이 다 들어 있어 게시판 칸 섹션(`section-slot-boards`)
 * 을 폰에서 또 그리면 같은 목록이 두 번 나온다 — 운영도 이 섹션을 폰에서 안 그린다.
 * 여기 두 규칙은 운영이 정확히 760px(=47.5rem)에서 갈리므로 이 파일 다른 폰 블록의 44rem 을
 * 따르지 않고 47.5rem 을 그대로 쓴다.
 */
@media (width <= 47.5rem) {
  .gb-area-page-bottom > .gb-widget-slot-space-directory {
    display: none;
  }

  /*
   * 홈 이미지 섹션의 카드 격자를 운영처럼 한 줄짜리 옆으로 미는 띠로 바꾼다. `.board-grid.grid-cards` 는
   * 조립 섹션이 함께 쓰는 이름이라 `.box-cards` 아래로 묶어 이 섹션만 바뀌게 한다.
   *
   * 안쪽 여백은 운영 13.6px 인데 우리는 16px 로 둔다. 이 판의 여백은 스킨의
   * `.gb-widget:not(.gb-widget-hero)` 가 `--board-card-pad` 로 주는 값이라 `.box-cards` 한 겹으로는
   * 못 덮고(운영도 같은 이유로 `!important` 를 쓴다), 여기만 덮으면 같은 폰 화면의 다른 판들과
   * 안쪽선이 어긋난다. 섹션 높이는 16px 일 때 243px 로 운영 245px 에 오히려 더 가깝다.
   */
  .gb-area-page-bottom .box-cards.box-cards .board-grid.grid-cards {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: minmax(9.5rem, 44vw);
    gap: 0.5rem;
    max-width: none;
    margin-inline: -0.2rem;
    padding-inline: 0.2rem;
    overflow-x: auto;
    scroll-snap-type: x;
    scrollbar-width: none;
  }

  .box-cards.box-cards .board-grid.grid-cards::-webkit-scrollbar {
    display: none;
  }

  /* 띠로 접히면 타일 안쪽 여백과 칸 사이 선을 뗀다(레거시 `.gallery-strip>a{padding:0;border:0}`). */
  .gb-area-page-bottom .gb-widget-feed.box-cards.box-cards .board-grid.grid-cards .cell {
    padding: 0;
    border-left: 0;
    border-right: 0;
    scroll-snap-align: start;
  }

  .box-cards.box-cards .cell-cover {
    border-radius: 0.45rem;
  }

  /* 띠의 제목은 위 .4rem · 아래 .2rem(레거시 `.gallery-strip strong`) — 넓은 화면의 .45rem 보다 촘촘하다. */
  .gb-area-page-bottom .box-cards.box-cards .cell-head {
    margin: 0.4rem 0 0.2rem;
  }
}

/*
 * 운영 홈만 카드 안쪽 여백을 760px 미만에서 .85rem 로 줄인다
 * (`apps/frontend/app/pages/index.vue` 의 `.recent`·`.gallery-section`·`.lower-grid>.app-surface` —
 * 레거시 `below(tablet)`). 우리 홈에서 그 세 판은 최근(`.box-digest`)·이미지(`.box-cards`)·
 * 읽을거리(아래쪽 `.box-compact`)다. 사이드 칸(인기·댓글·공지)은 운영도 제외라 두고,
 * 게시판 칸은 이 폭에서 아예 안 그린다(위 블록).
 * 카드 여백은 `.gb-widget:not(.gb-widget-hero)` 가 `--board-card-pad` 로 주는 값이라 토큰을
 * 그 섹션에서만 바꾼다. 갈림점은 레거시 `below(tablet)` 의 `max-width: 760px` 다 — 경계 760 을
 * 포함하므로 47.5rem 그대로다(759.98px 로 두면 정확히 760 에서 운영보다 8px 두꺼운 여백이 남는다).
 */
@media (max-width: 47.5rem) {
  .gb-area-page-main .gb-widget-feed.box-digest,
  .gb-area-page-bottom .gb-widget-feed.box-cards,
  .gb-area-page-bottom .gb-widget-feed.box-compact {
    --board-card-pad: 0.85rem;
  }
}

/*
 * 게시글 머리 카드. 운영 값: 안쪽 17.6px(아래 20px), 게시판 칩은 13px 굵게 선 두른 옅은 바탕,
 * 제목은 36px/600 에 줄높이 1.35, 작성자 줄은 32px 아바타·16px 굵은 이름(초록 기운 먹색)에
 * 칸 사이 12.8px. 스킨의 `.post-meta .gb-avatar`(0,2,0) 등과 겨루지 않게 `.post-head` 를 앞에 붙인다.
 */
.post-head {
  padding: 1.1rem 1.1rem 1.25rem;
}
/*
 * 본문·댓글 카드도 같은 17.6px 안쪽이다. 스킨 기본값(20px)을 그대로 두면 글줄이 제목줄보다
 * 2.4px 안으로 들어가 카드 세 장의 왼쪽 선이 어긋난다. 본문 위쪽은 운영대로 3.2px —
 * 제목 카드와 사이가 이미 떠 있어 더 얹을 자리가 없다. 댓글 카드는 위쪽도 17.6 이다 —
 * 운영 `.comments-surface` 는 네 방향이 다 1.1rem 이다(레거시 `PostDetailView.vue`).
 */
.post-body {
  padding: 0.2rem 1.1rem 1.1rem;
}

/*
 * 본문 안 그림은 레거시 `PostContent.vue:190` 의
 * `.post-content :deep(img){display:block; margin:.5rem auto; border-radius:var(--radius-md)}` 다 —
 * 글칸 가운데에 놓고 위아래 .5rem, 모서리 12px. 스킨 `.post .gb-body img` 는 `margin:12px 0`(왼쪽)에
 * `--board-radius-s`(3px)를 박는다. 링크 카드 속 그림은 스킨이 더 무거운 선택자(0,3,1)로 이미
 * 0 을 박아 두어 이 규칙에 안 잡히고, 첨부 그림은 `.gb-body` 밖이라 애초에 안 닿는다.
 * 레거시는 이 규칙이 본문 모든 img 에 닿으므로 링크·figure 안 그림도 가운데다.
 */
.post-body .gb-body img {
  display: block;
  margin: 0.5rem auto;
  border-radius: 0.75rem;
}

/*
 * 본문 위 첨부 그림 사이의 세로 간격은 운영 24px 다 — 운영은 그림마다 `figure`(저장 본문 마크업의
 * 인라인 `margin: 0 0 24px`; 레거시 CSS 에 figure 규칙은 없고, 본문 그림의 컴포넌트 규칙은
 * `PostContent.vue:190` `.post-content :deep(img){margin:.5rem auto}` 뿐)으로 그려 그림 사이와
 * 마지막 그림 아래가 모두 24 이다. 스킨은 `styles.ts:1148` `.post-images .gb-attachments` 에
 * `gap:.5rem` 이라 세로만 1.5rem 으로 덮는다 — figure 아래 마진만 있는 운영처럼 가로 틈은
 * 그대로 둔다. 마지막 그림 아래 24 는 스킨의 `margin:0 0 1.5rem` 이 이미 맞추고 있다.
 */
.post-images .gb-attachments {
  row-gap: 1.5rem;
}

/*
 * 본문 글자 요소는 레거시 `PostContent.vue` 의 scoped 규칙(`:343-351`)과 전역 리셋·타이포
 * (`_reset.scss:8-9`, `_typography.scss:5`)을 옮긴 것이다. `.post-body .gb-body …`(0,2,1)은
 * 스킨의 `.post .gb-body > :first-child`(0,3,0)에 margin-top 이 밀리므로 `.post` 까지 붙여
 * (0,3,1)로 잡는다 — `.post-body` 는 `.post` 의 직계 자식이다.
 *
 * 본문 색은 레거시 `--color-reading`(#101716, `_tokens.scss:12`) — `--board-text` 보다 한 단계
 * 어두운 읽기 전용 색이다. `--site-prose-text` 가 밝기를 따라간다.
 */
/*
 * 글칸 자체의 상자 값은 레거시 `PostContent.vue:166-174` 의 `.post-content` 다 — 위아래 안쪽
 * 1.6rem, 최소 높이 12rem(운영 짧은 글 칸이 여백 포함 192px). box-sizing 은 레거시 전역 리셋의
 * border-box 다 — 여기선 padding 을 최소 높이 안에 넣으려고 명시한다. 여백이 있는 상자라 본문
 * 첫·마지막 자식의 margin 은 안에 갇혀 칸 밖으로 새지 않는다.
 */
.post .post-body .gb-body {
  box-sizing: border-box;
  min-height: 12rem;
  padding-block: 1.6rem;
  color: var(--site-prose-text);
}
/* 문단은 리셋의 `margin-block: 0` 에 이웃 문단 사이만 .9rem — 스킨의 `0 0 1em` 을 지운다. */
.post .post-body .gb-body p {
  margin: 0;
}
.post .post-body .gb-body p + p {
  margin-top: 0.9rem;
}
/*
 * 빈 문단은 쓴 사람의 빈 줄 — 마지막이 아니면 한 줄 높이를 지킨다(레거시 min-height: 1.75em).
 * 레거시는 본문을 링크 카드 자리에서 조각(`.post-content-chunk`, display:contents)으로 나눠서
 * (`PostContent.vue:3-5`, `splitContentAtOgCards`) 카드 바로 앞 빈 문단은 조각의 마지막 자식이
 * 되어 높이가 0 이다 — 조각이 없는 여기선 「다음이 링크 카드」로 같은 자리를 뺀다(5357572 카드 사이 19곳).
 */
.post .post-body .gb-body p:empty:not(:last-child):not(:has(+ .gb-link-card)) {
  min-height: 1.75em;
}
/* 스킨은 빈 문단에 줄 하나(`::before` nbsp)를 채우는데 레거시엔 없다 — 높이는 위 min-height 만 정한다. */
.post .post-body .gb-body p:empty::before {
  content: none;
}
/* 본문 첫 링크 카드도 위 1.1rem 을 지킨다 — 레거시 `.link-card{margin:1.1rem 0}`(`OgCard.vue:143-147`)는 첫 자식이어도 여백 칸 안에 남는다. 스킨의 `.post .gb-body > :first-child{margin-top:0}` 을 이 자리만 되돌린다. */
.post .post-body .gb-body > .gb-link-card:first-child {
  margin-top: 1.1rem;
}
.post .post-body .gb-body h2 {
  margin: 1.5rem 0 0.65rem;
  font-size: 1.25rem;
  line-height: 1.35;
}
/* h3 는 레거시에서 본문 규칙이 아니라 전역 타이포 값이다 — 크기 18/600/1.4, 여백은 리셋의 0. */
.post .post-body .gb-body h3 {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.4;
}
.post .post-body .gb-body ul,
.post .post-body .gb-body ol {
  margin: 0.8rem 0;
  padding-left: 1.5rem;
}
.post .post-body .gb-body ul {
  list-style: disc;
}
.post .post-body .gb-body ol {
  list-style: decimal;
}
.post .post-body .gb-body li + li {
  margin-top: 0.3rem;
}
.post .post-body .gb-body strong {
  font-weight: var(--board-weight-bold);
}
/*
 * 본문 링크는 레거시 `--color-brand-600` — 이 팔레트의 `--board-accent-text` 다. 링크 카드는
 * 통째로 <a> 인 상자라 레거시가 `:not(.link-card)` 로 뺐다 — 밑줄·링크 색이 카드 안 글자까지
 * 번지는 걸 막는 장치다. 시세 카드 단추(`a.embed-phonedeal-button`)도 같은 이유로 뺀다.
 *
 * `:where()` 는 특이도를 더하지 않아 이 규칙은 (0,3,0) 이다 — 스킨의 `.post .gb-body a`(0,2,1)는
 * 이기되 출처(`.source a`)·리뷰 꼬리(`.embed-review-story-foot a`) 같은 부품 링크 규칙(0,3,1)
 * 에는 진다. 부품이 자기 링크를 스스로 입히는 자리를 일반 링크 색이 덮지 않게 하는 장치다.
 */
.post .post-body .gb-body :where(a:not(.gb-link-card):not(.embed-phonedeal-button)) {
  color: var(--board-accent-text);
  text-decoration: underline;
  text-underline-offset: auto;
}
/*
 * 링크 카드는 레거시 `OgCard.vue` 의 `.link-card{color:inherit;text-decoration:none}` 다 —
 * 카드 안 글자는 링크색이 아니라 본문 읽기색을 따른다. `inherit` 이라 위의 `.gb-body` 색 규칙이
 * 어두울 때 `--board-text` 로 도는 것까지 그대로 탄다. 플러그인이 같은 규칙을 싣지만
 * `a.gb-link-card`(0,1,1)라 스킨 `.post .gb-body a`(0,2,1)에 밀리므로 여기서 다시 잡는다.
 * 카드 제목은 레거시 `--color-ink` — 이 팔레트의 `--board-text` 다.
 */
.post .post-body .gb-body a.gb-link-card {
  color: inherit;
  text-decoration: none;
}
.post .post-body .gb-body .gb-link-card-title {
  color: var(--board-text);
}
/*
 * 그림형 카드(`link-card--image`) 캡션의 제목 줄은 레거시 `OgCard.vue:256` 의
 * `.link-card-caption-title{font-weight:600}` 이다 — 스킨은 `--board-weight-bold`(700)를
 * 입히고(`styles.ts:950`), 보드 팔레트에 600 단계 토큰이 없어 고정값으로 둔다.
 * 본문 위 출처 카드는 `.gb-body` 밖 슬롯(`.gb-slot-content-body-before`)에 오므로 `.post` 아래
 * `.gb-plugin-og-card` 를 함께 잡아 스킨 규칙(0,2,0)을 덮는다.
 */
.post .gb-plugin-og-card .gb-link-card-caption-title,
.post .post-body .gb-body .gb-link-card-caption-title {
  font-weight: 600;
}
/*
 * 인라인 code 는 레거시가 아무 규칙도 두지 않았다 — 브라우저 기본값(고정폭, 크기·배경·패딩·
 * 모서리 없음)이다. 스킨이 입힌 장식만 걷는다. pre 안 code 는 어차피 스킨이 padding·배경을
 * 비우고, 여기서도 같은 값이라 pre 모양은 안 바뀐다.
 */
.post .post-body .gb-body code {
  font-family: monospace;
  font-size: inherit;
  padding: 0;
  background: none;
  border-radius: 0;
}
/*
 * 본문 인용은 레거시 `PostContent.vue:198` 의
 * `blockquote{margin:1rem 0; padding:.8rem 1rem; background:var(--color-surface-subtle);
 * border-left:3px solid var(--color-brand-600)}` 다 — #f5f8f7 면에 brand-600(#146c5a) 왼선
 * 3px, 글자는 본문색 그대로(레거시에 색 규칙 없음). 스킨은 잉크 왼선 2px 에 `--board-mid`
 * 글자다(`styles.ts:933`) — 면·선·글자색 전부 레거시 값으로 되돌린다.
 * 면·선은 토큰이라 다크를 따라간다.
 */
.post .post-body .gb-body blockquote {
  margin: 1rem 0;
  padding: 0.8rem 1rem;
  background: var(--board-tint);
  border-left: 3px solid var(--board-accent-text);
  color: inherit;
}
/*
 * 코드 블록은 레거시 `PostContent.vue:199` 의
 * `pre{max-width:100%; overflow:auto; padding:1rem; color:#eef8f5; background:#17211f;
 * border-radius:var(--radius-sm)}` 다 — 밝기와 무관하게 먹바탕 #17211f 에 #eef8f5 글자다.
 * 글꼴·크기·줄간격은 레거시가 규칙을 두지 않아 브라우저 기본(고정폭)·본문 상속이다 — 스킨의
 * mono·0.85em·leading-ui(`styles.ts:930`)를 걷는다. 밖 margin 은 레거시가 브라우저 기본
 * 1em 양쪽을 그대로 썼다(스킨은 위 0·아래 1em). pre 안 code 는 위 규칙이 배경·패딩을
 * 비워 그대로 상속된다.
 */
.post .post-body .gb-body pre {
  margin: 1em 0;
  padding: 1rem;
  max-width: 100%;
  overflow: auto;
  font-family: monospace;
  font-size: inherit;
  line-height: inherit;
  color: #eef8f5;
  background: #17211f;
  border-radius: 0.4rem;
  box-shadow: inset 0 0 0 1px var(--site-code-line);
}
/*
 * 본문 안 iframe·video 는 레거시 `PostContent.vue:206-231` — 글칸 가운데에 놓고(inline auto)
 * 위아래 margin 은 0, 첫 자식이 아니면 위만 1.25rem. 스킨의 `.post .gb-body iframe,…` 는
 * `margin: var(--board-space-3) 0`(12px)이라 아래 여백이 붙고 왼쪽에 붙는다 — 이 규칙(0,3,1)이
 * 거기(0,2,1)에 이긴다. 트윗·인스타 인용 묶음도 레거시가 같은 자리에서 위·아래 1.25rem 을
 * 준다(레거시의 .videos·.youtube-video·.video-item·.tiktok-embed 감싸개는 여기 마크업에 없다).
 */
.post .post-body .gb-body iframe,
.post .post-body .gb-body video {
  display: block;
  max-width: 100%;
  margin-block: 0;
  margin-inline: auto;
  border: 0;
}
.post .post-body .gb-body iframe:not(:first-child),
.post .post-body .gb-body video:not(:first-child),
.post .post-body .gb-body .gb-embed-frame:not(:first-child) {
  margin-top: 1.25rem;
}
/* X·인스타·레딧 카드는 제공자 틀과 그 아래 「원문 보기」를 감싼 `.gb-embed-frame` 이다(엔진 noriter-116). */
.post .post-body .gb-body .gb-embed-frame {
  margin-bottom: 1.25rem;
}
.post .post-body .gb-body .gb-embed-source {
  text-align: center;
}

/*
 * 글 태그 — 레거시 `PostDetailView.vue` 의 `.tags{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:1rem}`
 * 그대로다. 스킨은 `.post .gb-tags` 위 여백 12px, `.gb-tags` 칸 사이 4px 를 준다. 선택자를 `.post` 아래로
 * 좁혀 디아블로 화면의 `.gb-tags`(`.d2r …`)와 태그 목록 페이지에는 닿지 않게 한다.
 */
.post .gb-tags {
  gap: 0.4rem;
  margin-top: 1rem;
}
.gb-comments {
  padding: var(--board-card-pad);
}

/*
 * 댓글 제목줄 — 레거시 `PostDetailView.vue` 의 `.comment-section>header` 와 같은 줄이다:
 * 아이콘 19, 글자 17px/600·줄높이 1.35, 아이콘-글자 .45rem, 아래 .7rem 뒤 첫 댓글.
 * 스킨의 `.gb-comments h2`(위아래 8px 여백, 틈 8px)를 운영 값으로 덮는다. 직계 h2 만 잡아
 * 해외반응 절의 제목(`.gb-comment-section-title`)과 「댓글 작성」에는 닿지 않게 한다.
 */
.gb-comments > h2 {
  gap: 0.45rem;
  margin: 0 0 0.7rem;
  padding: 0;
  line-height: 1.35;
}

/*
 * 해외반응처럼 따로 모은 절이 댓글 위에 있으면 카드 안쪽 폭으로 선을 하나 긋는다 — 레거시
 * `.comment-section--separated`. 선 위의 24 는 스킨이 `.gb-comment-section` 에 둔 아래 여백
 * (--board-space-6)이 만들고, 선 아래의 24 는 여기 윗여백이다. 절이 없는 글은 이 선택자가
 * 잡히지 않아 카드 윗여백에서 바로 제목줄이 선다.
 */
.gb-comments > .gb-comment-section + h2 {
  padding-top: 1.5rem;
  border-top: 1px solid var(--board-line);
}
.post-head .post-chips {
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.85rem;
}
/* 레거시 `.badge--notice{color:#fff;background:#e48333;border-color:#e48333}`(PostDetailView.vue:114) — 다크 값이 따로 없던 주황 알약이다. */
.post-head .post-chips .gb-badge.gb-badge-notice {
  border-color: #e48333;
  background: #e48333;
  color: #fff;
}
.post-head .post-title {
  line-height: 1.35;
  letter-spacing: -0.035em;
}
.post-head .post-meta {
  margin-top: 1rem;
  gap: 0.5rem 0.8rem;
}
/*
 * 작성자 이름의 색은 목록의 작성자 링크와 같은 mix 다 — 레거시 `UserActionMenu.vue:5` 의
 * `.gb-author.interactive`(`color-mix(in srgb, var(--color-brand-600) 48%, var(--color-ink))`).
 * 링크든 아니든 `.gb-author` 에 걸고, 안의 `a` 는 상속으로 같은 값을 받는다.
 */
.post-head .post-meta .gb-author {
  gap: 0.4rem;
  font-size: 1rem;
  color: color-mix(in srgb, var(--board-accent) 48%, var(--board-ink));
}
.post-head .post-meta .gb-author a {
  color: inherit;
}
.post-head .post-meta .gb-avatar {
  width: 2rem;
  height: 2rem;
}
.post-head .post-meta .gb-avatar-initial {
  font-size: 1rem;
}

/*
 * 손님의 댓글 작성 칸. 운영은 카드 안쪽 17.6px, 제목 17px/600 아래 16px, 안내 상자는 높이 112px 에
 * 흐린 글씨, 오른쪽 로그인 단추는 41.6px 높이다.
 *
 * 제목 줄높이 1.35 는 레거시 전역 h2(`_typography.scss:4`) — 스킨 기본 1.3 이라 여기서만 좁혀 둔다.
 * 단추 안쪽 여백 .5rem .8rem 은 레거시 `.login-prompt strong`(`CommentForm.vue` scoped).
 */
.gb-comment-write {
  /*
   * 위아래 간격은 레거시 `.post-detail.stack` 의 줄간 `gap: var(--gap-card)` = .65rem
   * (`PostDetailView.vue:115`, `--gap-card: .65rem` 은 `_tokens.scss:29`) — 운영은 댓글 카드와
   * 이 카드 사이가 10.4 이고, 스킨 기본 margin 12/12 를 그 값으로 내린다.
   */
  margin: 0.65rem 0;
}
.gb-comment-write > h2,
.gb-comment-write > h3 {
  margin: 0 0 1rem;
  font-size: 1.0625rem;
}
.gb-comment-write > h2 {
  line-height: 1.35;
}
.gb-comment-write .gb-notice {
  min-height: 7rem;
  border-radius: 0.4rem;
  color: var(--board-dim);
}
.gb-comment-write .gb-notice .gb-btn {
  padding: 0.5rem 0.8rem;
  border-width: 0;
  border-radius: 0.4rem;
  line-height: 1.6;
  white-space: nowrap;
}

/*
 * 게시판 머리. 운영은 제목 아래 4px 에 「N개의 게시글」 한 줄뿐이다. 게시판 설명은 검색엔진 메타로만 쓴다.
 *
 * 제목 줄높이는 레거시 h1 의 1.25(`_typography.scss:3`) — 스킨의 tight 1.3 은 1280 에서
 * 46.4 로 운영 45 보다 크다. `.board-section .board-title` 은 스킨이 따로 1.35 로 두고
 * (0,2,0)라 여기엔 안 잡힌다.
 */
.board-title {
  line-height: 1.25;
}

/*
 * 운영 머리는 `.page-head` 유연 상자라 제목을 감싼 칸이 내용만큼 줄어든다 —
 * `PostListPage.vue:38` 의 `display:flex` 안에서 h1 상자는 글자 폭이다(링크도
 * 글자만큼만 눌린다). 스킨은 `.board-head` 가 통짜 블록이라 h1 이 기둥 폭을
 * 다 채운다. 태그 머리는 카드 안의 통짜 제목이라(레거시 `tags/[tag].vue:62`)
 * 여기서 빼고, 나머지 머리의 제목만 내용 폭으로 줄인다 — 폰의 격자 칸에서도
 * `width: fit-content` 는 늘어나지 않는다.
 */
.board-head:not(.tag-head) .board-title {
  width: fit-content;
}

.board-count {
  margin-top: 0.25rem;
}
.board-desc {
  display: none;
}

/*
 * 머리의 아래 여백은 운영에 없다 — `.page-head` 는 여백 없는 유연 상자고, 머리와 다음 줄
 * (검색 카드 또는 칩) 사이의 10.4 는 `.stack` 격자의 .65rem(`global.scss:26`, `--gap-card` 는
 * `_tokens.scss:29`)이 낸다. 스킨은 그 간격을 `.board-head` 의 아래 안쪽 여백(16)으로 만들어
 * 머리 상자가 74.6 이 아니라 92 가 된다. 여백은 지우고 10.4 는 다음 줄의 윗마진이 낸다 —
 * 이웃 마진은 상쇄돼 어느 줄이 와도 .65rem 하나다. 태그 머리(`.tag-head`)는 카드라 스킨의
 * 1.1rem 안쪽 여백을 지키고(0,2,0), 그 화면의 간격은 격자 규칙이 따로 낸다.
 */
.board-head {
  padding-bottom: 0;
}
.board-head:not(.tag-head) ~ .board-list {
  margin-top: 0.65rem;
}

/*
 * 폰에서 머리 오른쪽에 서는 검색 열기 단추는 운영 `.mobile-search-toggle` 이다
 * (`PostListPage.vue` 의 `below(mobile)` 블록) — 42.4 네모에 표면 배경·1px 선·모서리
 * --radius-sm(.4rem). 스킨은 헤더 단추 몸담(40, 원형, 배경 없음)을 빌려 그리므로 운영 값으로
 * 덮는다. 마크업·여닫이 동작(label + 체크상자 ~ 선택자)은 스킨이 이미 가졌다(`styles.ts:763-768`).
 * 열린 검색 카드 안은 운영이 한 열 격자(`grid-template-columns:1fr; gap:.5rem`)라 세로로 쌓고,
 * 선택 상자는 칸 폭을 다 쓴다.
 */
@media (max-width: 37.5rem) {
  .board-search-open {
    width: 2.65rem;
    height: 2.65rem;
    border-radius: 0.4rem;
    background: var(--board-surface);
  }
  /*
   * 아래쪽의 모든 화면용 `.board-search { gap: .55rem }`(운영 데스크톱 `.search` 의 값)이
   * 나중에 있어 같은 선택자로는 진다 — 폰의 .5rem 을 살리려고 특이도를 한 계단 올린다.
   */
  form.board-search {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
  }
  /*
   * 스킨은 폰에서 입력을 한 줄 배치용으로 `width: 0` 으로 누른다 — 세로로 쌓는 운영에서는
   * 칸 폭(336.8)을 다 쓴다. 높이는 입력칸 토큰(--board-control-h)이 준다.
   */
  form.board-search input[type="search"] {
    width: auto;
  }
  .board-search select {
    width: auto;
  }
}

/* ------------------------------------------------------------------------- *
 * 「예전 게시판」. 마크업은 `site/pages/legacy-boards.tsx`, 값은 운영 실측(1280, 2026-09-16).
 *
 * 이 화면은 게시판 머리를 안 쓴다 — 운영이 `.page-head` 로 따로 그리고, 표가 아니라 2단
 * 링크 목록이다. 목록 클래스만 운영과 이름이 다르다: 운영은 `board-list` 인데 그건 스킨이
 * 글 목록 카드에 쓰는 이름이라(`skins/board/src/styles.ts:572`) `legacy-list` 로 바꿨다.
 *
 * 줄높이는 운영이 전부 1.6 이다. 스킨의 `--board-leading-ui` 는 1.5 라 줄마다 직접 적는다.
 * ------------------------------------------------------------------------- */
.legacy-page {
  padding-block: 1rem 3rem;
}
/* 운영 `.stack` — 머리와 흰 판 사이 10.4px 하나. */
.legacy-page.stack {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.65rem;
}
.legacy-page .app-surface,
.site-info .app-surface,
.legal-page .app-surface {
  padding: var(--board-card-pad);
  border: 1px solid var(--board-line);
  border-radius: var(--board-radius-l);
  background: var(--board-surface);
  box-shadow: var(--board-shadow);
}
.legacy-page .page-head p {
  margin: 0;
  /* 글자로 쓰는 녹색은 `--board-accent-text` 다 — 어두운 면에서 `#146c5a` 는 대비가 3:1 이 안 된다(위 다크 블록). */
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 800;
  line-height: 1.6;
  letter-spacing: 0.12em;
}
.legacy-page .page-head h1 {
  margin: 0.2rem 0;
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  line-height: 1.25;
  letter-spacing: normal;
}
.legacy-page .page-head span {
  display: block;
  color: var(--board-dim);
  font-size: var(--board-size-ui);
  line-height: 1.6;
}

/*
 * 한 줄에 이름 + 주소 조각 + 「N개」 가 서고 날짜는 두 칸을 다 써서 아래로 내려간다.
 * 줄 높이를 84px 로 못 박아 스무 줄이 두 단으로 가지런히 선다.
 */
.legacy-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 1.25rem;
}
.legacy-list a {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-content: center;
  gap: 0.2rem 1rem;
  min-height: 5.25rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--board-line);
  color: var(--board-text);
  text-decoration: none;
}
.legacy-list a:hover strong,
.legacy-list a:focus-visible strong {
  color: var(--board-accent-text);
}
.legacy-list div {
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  min-width: 0;
}
.legacy-list strong {
  overflow: hidden;
  font-size: var(--board-size-ui);
  font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.legacy-list small,
.legacy-list time {
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  line-height: 1.6;
}
.legacy-list > a > span {
  /* 운영은 여기만 `--color-brand-700` 이다 — `--board-brand-700` 이 그 값. */
  color: var(--board-brand-700);
  font-size: var(--board-size-meta);
  font-weight: 700;
  line-height: 1.6;
}

.legacy-list time {
  grid-column: 1 / -1;
}
.legacy-empty {
  margin: 0;
  color: var(--board-dim);
  font-size: var(--board-size-ui);
  line-height: 1.6;
}

/* 운영은 정확히 700px 에서 한 단으로 접고, 이름과 주소 조각도 위아래로 쌓는다. */
@media (width <= 43.75rem) {
  .legacy-page {
    padding-top: 0.25rem;
  }
  .legacy-list {
    grid-template-columns: 1fr;
  }
  .legacy-list a {
    min-height: 5rem;
  }
  .legacy-list div {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.1rem;
  }
}

/* ------------------------------------------------------------------------- *
 * 안내 화면 넷. 마크업은 `site/pages/static.tsx`, 값은 전부 운영 실측(1280, 2026-09-16)이다.
 *
 * 운영 토큰은 이 시트 앞쪽의 다리로 옮겼다 — `--color-brand-600` = `--board-accent`,
 * `--color-line` = `--board-line`, `--color-muted` = `--board-dim`,
 * `--radius-card` = `--board-radius-l`(0), `--shadow-sm` = `--board-shadow`.
 * 없는 단계는 섞어 만든다: `--color-brand-50 #edf8f5` ≈ 강조 8% 를 흰 면에.
 * 리터럴로 적으면 다크모드에서 연초록 판이 그대로 남으므로 섞는 쪽이어야 한다.
 * (`--color-brand-700` 은 `--board-brand-700` 이 그 값이다.) 1.2rem·0.75rem·2.6rem 과 굵기 600·800 은 스킨에 토큰이
 * 없어 그대로 적는다(이 시트의 기존 관례).
 *
 * `.hero`·`.card`·`.grid`·`.contact` 는 운영 이름 그대로인데 흔한 이름이다. 운영은 Vue 의
 * `data-v-` 로 범위를 잡지만 우리 시트는 전역이라 **두 겉껍질(`.site-info`·`.legal-page`)
 * 아래로만** 건다. 스킨에는 이 이름들이 없다(`.card` 는 `.card-grid .card` 뿐).
 * ------------------------------------------------------------------------- */

/* 소개·편집 원칙 (운영 `div.site-info`, 폭 896) */
.site-info {
  max-width: 56rem;
  margin-inline: auto;
  padding: 0.4rem 0 2rem;
}
/* 오른쪽 위에 강조색 원 하나를 옅게 얹은 뒤 대각선으로 흰 면에서 연초록으로 간다. */
.site-info .hero {
  padding: 2.8rem 3rem 2.35rem;
  border: 1px solid var(--board-line);
  border-radius: 1.2rem;
  background:
    radial-gradient(circle at 88% 14%, color-mix(in srgb, var(--board-accent) 15%, transparent) 0 4.6rem, transparent 4.7rem),
    linear-gradient(135deg, var(--board-surface), color-mix(in srgb, var(--board-accent) 8%, var(--board-surface)));
}
.site-info .eyebrow {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 800;
  line-height: 1.6;
  letter-spacing: 0.12em;
}
.site-info .hero h1 {
  margin: 1rem 0 0;
  font-size: clamp(2rem, 4vw, 2.7rem);
  line-height: 1.25;
  letter-spacing: -0.045em;
}
.site-info .hero > p {
  margin: 1rem 0 0;
  color: var(--board-dim);
  font-size: var(--board-size-read);
  line-height: 1.6;
}
.site-info .hero nav {
  display: flex;
  gap: 0.5rem;
  margin-top: 1.8rem;
}
/*
 * `line-height` 를 적는 이유: 스킨의 `--board-leading-ui` 가 1.5(24px)인데 운영 링크는 1.6
 * (25.6px)이다. 안 적으면 알약 단추가 45px 대신 44px 로 서고 히어로 전체가 1px 짧아진다.
 * 아래 `.legal-hero nav a`·`.card a` 도 같은 이유다.
 */
.site-info .hero nav a {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.55rem 0.85rem;
  border: 1px solid var(--board-line);
  border-radius: 999px;
  background: var(--board-surface);
  font-weight: var(--board-weight-bold);
  line-height: 1.6;
}
/*
 * 지금 보는 탭. 운영은 글자를 `--color-brand-700` 으로 쓴다 — `--board-brand-700` 이 그 값이다.
 * 테두리는 `--color-brand-600` — `--board-accent-text` 가 그 값이다. `--board-accent` 로 두면
 * 어두운 면에서 알약 테두리가 안 보여 지금 쪽을 알 수 없다.
 */
.site-info .hero nav a.active {
  border-color: var(--board-accent-text);
  background: color-mix(in srgb, var(--board-accent) 8%, var(--board-surface));
  color: var(--board-brand-700);
}

.site-info .grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.85rem;
  margin-top: 1rem;
}
/* 아이콘 칸과 글 칸. 최소 높이는 운영 값이라 글이 짧아도 넉 장이 같은 키로 선다. */
.site-info .card {
  display: grid;
  grid-template-columns: 2.6rem minmax(0, 1fr);
  gap: 0.9rem;
  min-height: 11.5rem;
}
.site-info .card-icon {
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 0.75rem;
  background: color-mix(in srgb, var(--board-accent) 8%, var(--board-surface));
  color: var(--board-accent-text);
}
.site-info .card h2,
.site-info .contact h2 {
  margin: 0 0 0.45rem;
  font-size: var(--board-size-read);
  line-height: 1.35;
}
.site-info .card p,
.site-info .contact p {
  margin: 0;
  color: var(--board-dim);
  line-height: 1.7;
}
.site-info .card a,
.site-info .contact > a {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.75rem;
  color: var(--board-accent-text);
  font-weight: var(--board-weight-bold);
  line-height: 1.6;
}
.site-info .contact {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 1rem;
}
.site-info .contact > div {
  flex: 1;
}
/*
 * 운영이 정확히 700px 에서 갈린다. 이 시트 다른 폰 블록의 44rem 을 따르지 않고 그 값을 쓴다 —
 * 카드가 두 단으로 남는 폭이 그거고, 여기만 다르게 끊으면 한 단으로 떨어지는 지점이 어긋난다.
 */
@media (width <= 43.75rem) {
  .site-info .hero {
    padding: 2rem 1.4rem;
  }
  .site-info .grid {
    grid-template-columns: 1fr;
  }
  .site-info .contact {
    flex-wrap: wrap;
    align-items: flex-start;
  }
  .site-info .contact > a {
    width: 100%;
    margin-left: 3.6rem;
  }
}

/* 이용약관·개인정보처리방침 (운영 `div.legal-page`, 폭 896) */
.legal-page {
  display: grid;
  gap: 1rem;
  max-width: 56rem;
  margin-inline: auto;
}
/* 약관 쪽 히어로는 원이 없고 대각선 하나뿐이다. 모서리도 1.2rem 이 아니라 1rem. */
.legal-hero {
  padding: 2.2rem 2.4rem;
  border: 1px solid var(--board-line);
  border-radius: 1rem;
  background: linear-gradient(135deg, var(--board-surface), color-mix(in srgb, var(--board-accent) 8%, var(--board-surface)));
}
.legal-hero > p {
  margin: 0;
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: 800;
  line-height: 1.6;
  letter-spacing: 0.14em;
}
.legal-hero h1 {
  margin: 0.45rem 0 0;
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  line-height: 1.25;
  letter-spacing: normal;
}
.legal-hero > span {
  display: block;
  margin-top: 0.55rem;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  line-height: 1.6;
}
.legal-hero nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.4rem;
}
.legal-hero nav a {
  display: flex;
  align-items: center;
  min-height: 2.65rem;
  padding: 0.5rem 0.8rem;
  border: 1px solid var(--board-line);
  border-radius: 999px;
  background: var(--board-surface);
  font-weight: 600;
  line-height: 1.6;
}
.legal-hero nav a.active,
.legal-hero nav a:hover {
  border-color: var(--board-accent);
  background: var(--board-accent);
  color: var(--board-on-accent);
}
.legal-section > h2 {
  margin: 0 0 0.85rem;
  font-size: 1.5rem;
  line-height: 1.35;
}
.legal {
  display: grid;
  gap: 0.8rem;
}
.legal section {
  padding: 1rem;
  border: 1px solid var(--board-line);
  border-radius: 0.4rem;
}
.legal h3 {
  margin: 0 0 0.45rem;
  /* 운영은 `--color-brand-700` — `--board-brand-700` 이 그 값. */
  color: var(--board-brand-700);
  font-size: 1.125rem;
  line-height: 1.4;
}

.legal p,
.legal ul {
  margin: 0;
  line-height: 1.7;
}
.legal ul {
  /* 레거시 `_reset.scss:9` 가 `ul, ol` 의 점을 전부 지웠다 — 운영도 list-style: none 이다. */
  list-style: none;
  padding-left: 1.2rem;
}
.legal li {
  margin: 0;
}
/* 이쪽은 운영이 600px 에서 갈린다. 조항 상자가 두 겹으로 겹쳐 있어 안쪽 여백을 같이 줄인다. */
@media (width <= 37.5rem) {
  .legal-hero {
    padding: 1.5rem 1.2rem;
  }
  .legal-hero h1 {
    font-size: 1.75rem;
  }
  .legal-page .legal-section {
    padding: 0.85rem;
  }
  .legal section {
    padding: 0.85rem;
  }
}

/*
 * 로그인·가입 카드. 운영의 카드는 모달 틀 `AppModal.vue` 의 `.modal-content` 다 —
 * 테두리가 없고 `box-shadow: var(--shadow-md)`(`_tokens.scss`: `0 10px 30px rgb(15 37 32 / 10%)`)만
 * 띄운다. 스킨은 여기에 `--board-line` 테두리와 `--board-shadow`(0 1px 2px)를 쓰므로 두 값을 운영 값으로
 * 돌린다. 폭·모서리·안쪽 여백은 이미 운영과 같다.
 *
 * 입력은 `AppInput.vue` 의 `.app-input` 이다 — 치수는 스킨 입력칸 토큰이 운영 값(45.2·패딩
 * 8.8/11.2)으로 준다. 주 단추 치수는 스킨 단추 토큰이 준다.
 */
.gb-auth {
  border: 0;
  box-shadow: var(--site-shadow-md);
}

/*
 * 로그인 카드 안쪽 배치는 레거시 모달 `AuthDialog.vue` 의 `.auth-form` 이다 — 폼 줄간격 .8rem
 * (`AuthDialog.vue:58` `.auth-form { display: grid; gap: .8rem }`, 스킨은 --board-space-4=1rem).
 * 입력 글자 굵기는 레거시가 label 의 `--weight-bold`(700)를 입력이 물려받은 값이다 — 스킨이
 * 입력에 따로 굵기를 주지 않아 그대로 이어진다.
 * `로그인 유지` 줄은 레거시 `.check`(같은 줄 `display: flex; align-items: center;
 * font-weight: var(--weight-medium)`)다 — 스킨의 세로 쌓기·700 을 풀고 체크박스는 자기 크기(13×13)로 둔다.
 */
.gb-auth .gb-auth-form {
  gap: 0.8rem;
}
.gb-auth .gb-auth-form label.gb-auth-remember {
  flex-direction: row;
  align-items: center;
  gap: 0;
  font-weight: 500;
}
.gb-auth .gb-auth-form label.gb-auth-remember input {
  flex: none;
}

/*
 * 약관 동의 줄(`auth.requireTerms`)은 auth-remember 와 같은 체크박스 행인데 클래스가 없어
 * 스킨의 세로 쌓기를 그대로 타서 문구 아래 체크박스가 떨어진다. 엔진 요청으로 클래스가
 * 붙으면 이 규칙은 그 선택자로 갈아탄다 — 지금은 `checkbox input 을 품은 label` 로 잡는다.
 */
.gb-auth .gb-auth-form label:has(> input[type="checkbox"]) {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
}
.gb-auth .gb-auth-form label:has(> input[type="checkbox"]) input {
  flex: none;
}

/*
 * 제목 아래 안내 줄(`p.gb-auth-lead`, 메시지 `auth_sign_in_lead` 가 찼을 때만 그려진다)은 레거시
 * `AppModal.vue:21` 의 `.modal-description` 이다 — margin .4rem 0 1rem, 색 --color-muted.
 * 운영 모달엔 닫기 단추가 든 머리 줄(높이 31.2)이 제목을 2.1 아래로 밀어 안내 줄이 y56.8 에 선다.
 * 카드엔 그 줄이 없으니, 안내 줄이 있는 카드(로그인뿐)만 제목 아래 여백을 10.6px 로 줄여 같은 자리에
 * 둔다 — 가입·비밀번호 찾기처럼 안내 줄 없는 카드는 스킨의 제목→폼 간격(16)을 그대로 쓴다.
 */
.gb-auth h1:has(+ .gb-auth-lead) {
  margin-bottom: 0.6625rem;
}
.gb-auth .gb-auth-lead {
  margin: 0.4rem 0 1rem;
  color: var(--board-dim);
}

/*
 * 폼 아래 링크 줄은 레거시 `.switches`(`AuthDialog.vue:58` `display: flex; justify-content:
 * space-between`)다 — 「비밀번호 찾기」 왼쪽 끝·「회원가입」 오른쪽 끝, 링크 색은 --color-brand-600.
 * 운영은 reCAPTCHA 문구·소셜 단추를 사이에 두고 폼 안에서 .8rem 간격으로 붙는데 이 카드엔 그 둘이
 * 없으니 레거시 폼 간격 .8rem 만 남긴다. 스킨이 `.gb-auth > p:last-child` 에 준 윗선·안쪽 여백·
 * 가운데 정렬·2rem 여백은 걷는다 — 엔진 기본 `.gb-auth-links`(flex 양끝)는 보드 스킨이 테마를
 * 갈아 끼워(replacesTheme) 실리지 않는다.
 */
.gb-auth p.gb-auth-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.3rem 0.9rem;
  margin: 0.8rem 0 0;
  padding: 0;
  border: 0;
  text-align: left;
  color: inherit;
}

/*
 * 오류 판. 운영은 내용을 창 높이에 비례해 세로로 가운데 둔다 — 레거시 `error.vue` 의
 * `.gb-error-page` 가 `min-height: 65vh`·`display: grid`·`align-content: center`·`gap: .8rem` 이다.
 * 스킨은 위아래 `clamp(3rem,14vh,8rem)` 여백으로 밀 뿐이라 내용이 위로 몰리고 판이 일찍 끝난다.
 * 자식 사이 간격도 스킨의 margin(.8/.75/1.5rem)이 아니라 균일한 .8rem 이다. 상태 숫자는
 * 운영 `.code` 의 `clamp(4rem,12vw,8rem)` — 바닥값 4rem 이라 폰에서도 스킨의 4rem 과 같다.
 */
.gb-error-page {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 0.8rem;
  min-height: 65vh;
  padding-block: 0;
}
.gb-error-page .gb-status,
.gb-error-page h1,
.gb-error-page .gb-text {
  margin: 0;
}
.gb-error-page .gb-status {
  font-size: clamp(4rem, 12vw, 8rem);
}
/*
 * 판 아래 남는 높이는 판이 아니라 레이아웃이 든다 — 레거시 `default.vue:61` 의
 * `.page { min-height: calc(100vh - 10rem) }`. 이 값이 있어야 푸터가 운영 자리(1280 에서
 * y857, 폰에서 y824)에 선다. 오류 판을 담은 본문에만 걸어 다른 화면의 푸터는 안 움직인다.
 */
.board-body:has(.gb-error-page) {
  min-height: calc(100vh - 10rem);
}

/*
 * 게시판 표. 운영 칸 폭은 번호 120·작성자 144·작성일 104·조회 67·추천 67 이고 제목이 나머지를 먹는다.
 * 머리칸은 위아래 11.5px, 줄칸은 12.5px(줄 높이 51px), 좌우 8.8px. 번호·작성자·날짜·수는 먹색 14px.
 * 휴대폰은 머리줄이 숨고 칸이 쌓이는 스킨 배치라 넓은 화면에서만 건다.
 */
@media (min-width: 700.02px) {
  .board-table th {
    padding: 0.72rem 0.55rem;
  }
  .board-table td {
    padding: 0.78rem 0.55rem;
  }
  /*
   * 스킨은 제목 칸을 100% 로 잡아 나머지 칸 폭을 짓누른다. 제목은 남는 폭만 먹는다.
   * `table-layout: fixed` 로 둔다 — auto 면 아래에서 한 줄로 만든 제목의 min-content 가
   * 표를 카드 밖으로 밀어(701 에서 표 898) 다른 칸의 정한 폭까지 눌러 버린다. fixed 면
   * 머리줄에 정한 폭이 그대로 서고 제목 칸이 나머지를 먹는다 — 운영 768 의 제목 칸 196 도
   * 이 계산이다(700.8 - 고정 폭 합 502.4).
   */
  .board-table { table-layout: fixed; }
  .board-table th.col-title,
  .board-table td.col-title { width: auto; }
  .board-table th.col-no { width: 7.5rem; }
  .board-table th.col-author { width: 9rem; }
  .board-table th.col-date { width: 6.5rem; }
  .board-table th.col-views,
  .board-table th.col-score { width: 4.2rem; }
  .board-table td.col-no,
  .board-table td.col-author,
  .board-table td.col-date,
  .board-table td.col-views,
  .board-table td.col-score {
    color: var(--board-ink);
  }

  /*
   * 회원 작성자 이름은 초록 48% 섞인 잉크색 — 레거시 `UserActionMenu.vue:5` 의
   * `.gb-author.interactive`(`color-mix(in srgb, var(--color-brand-600) 48%, var(--color-ink))`)다.
   * 스킨은 회원이면 이름을 `/profile/N` 링크로 싼다(`skins/board/src/list.tsx:114`).
   * 비회원은 링크가 아니라 칸 글자색(위 잉크) 그대로다.
   */
  .board-table td.col-author a[href] {
    color: color-mix(in srgb, var(--board-accent) 48%, var(--board-ink));
  }
  .board-table td.col-author a[href]:hover,
  .board-table td.col-author a[href]:focus-visible {
    color: var(--board-accent);
  }

  /*
   * `listBoard: 'number'` 로 번호 칸에 들어온 게시판 이름. 운영 `.board-tag` 는 캡션
   * 크기의 흐린 글자다 — 스킨은 칸 글자색을 따라 번호보다 진하게 나오므로 덮는다.
   * 줄높이는 칸의 1.55 를 타서 13px 에 20.15 가 된다.
   */
  .board-table td.col-no a.row-board {
    color: var(--board-dim);
    font-size: var(--board-size-caption);
  }

  /*
   * 표 모드의 제목은 한 줄 말줄임이다 — 레거시 `PostRows.vue:47` 의 `.title-copy`(min-width:0
   * overflow:hidden)와 `.title-text`(nowrap ellipsis)다. 레거시는 제목과 댓글 수 `<b>(3)</b>` 가
   * `.title-text` 안 한 덩어리로 같이 잘리고, 스킨은 `.title-main` 에 아무 처리가 없어 제목이
   * 칸 폭만큼 줄바꿈돼 행이 100~250px 로 불어난다.
   * `.title-main` 은 `.title-row` 의 flex 아이템이라 이미 블록화된 상자다 — 여기서 nowrap
   * ellipsis 를 주면 첫 줄의 인라인 흐름(제목·댓글 수·N 표시)이 한 줄로 잘리고, 블록 자식인
   * 출처 줄(`.row-source`)은 그 다음 줄에 그대로 선다. 스킨이 이미 둔 `min-width: 0` 이
   * 칸 폭 아래로 줄 수 있게 한다.
   */
  .board-table .title-main {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  /* 출처 줄은 자기 줄에 서되, 위의 nowrap 을 물려받아 못 접게 둔다 — 길면 제목처럼 잘린다. */
  .board-table .title-main .row-source {
    text-overflow: ellipsis;
    overflow: hidden;
  }
}

/*
 * 칸의 글줄은 레거시 `PostRows.vue` `td { line-height: 1.55 }` 다. 넓은 화면에서 16px 칸이 24.8,
 * 14px 칸이 21.7 로 운영과 같아지고, 좁은 화면의 제목(16px→24.8)과 메타 줄(13px→20.15)도 같은 값이다.
 */
.board-table td {
  line-height: 1.55;
}

/*
 * 마지막 행의 밑줄도 운영에 남아 있다 — 레거시 `PostRows.vue:47-48` 은 모든 `td` 에
 * `border-bottom: 1px solid var(--color-line)` 을 걸고 마지막 행을 빼지 않는다. 운영은 표를
 * 감싼 상자에 테두리가 없어(`table-wrap` border 0) 이 선이 표를 닫는 선이다. 스킨은 카드
 * 아래쪽이 카드 테두리로 닫히므로 마지막 행의 선을 지운다(`styles.ts:624`) — 같은 선택자로
 * 되돌린다. 빈 목록 행(`tr.row-empty`)은 뺀다 — 운영은 빈 목록에 표를 그리지 않아
 * 문단 아래 설 선이 없다. 좁은 화면에서는 선이 칸이 아니라 행에 있어 아래 접힌-화면
 * 블록에서 따로 켠다.
 */
@media (min-width: 700.02px) {
  .board-list .board-table tr:last-child:not(.row-empty) td {
    border-bottom: 1px solid var(--board-line);
  }
}

/*
 * 운영은 글 행에 hover 색이 없다 — 레거시 `PostRows.vue` 에 `:hover` 규칙 자체가 없어 행과
 * 칸 모두 투명하다. 스킨의 `tr.row:hover td`(`styles.ts:599`)가 칸을 tint 로 칠하므로 지운다.
 * 공지 줄의 배지색과 지금 보는 글의 면은 hover 에도 지킨다(각각 운영의 그 상태 그대로).
 */
.board-table tr.row:hover td {
  background: transparent;
}
.board-table tr.row-notice:hover td {
  background: var(--board-notice);
}
/*
 * 글 아래 목록에서 지금 보는 글의 행 — 운영은 공지 행과 같은 brand-50 면이다(레거시
 * `PostRows.vue:49` `.current-row{background:var(--color-brand-50)}`). 스킨은 더 깊은
 * `tint-2` 를 쓰므로(`styles.ts:623`) `--board-notice` 로 되돌린다. hover 에도 지켜야 하므로
 * 스킨과 같이 hover 변형까지 둘 다 적는다.
 */
.board-table tr.is-current td,
.board-table tr.is-current.row:hover td {
  background: var(--board-notice);
}
/* 좁은 화면에선 스킨이 칸이 아니라 행에 면을 칠하고 양옆 그림자로 카드 끝까지 번지게 한다(`styles.ts:818`) — 같은 모양으로 토큰만 `--board-notice` 로. */
@media (max-width: 43.75rem) {
  .board-table tr.is-current {
    background: var(--board-notice);
    box-shadow: calc(-1 * var(--board-card-pad)) 0 0 var(--board-notice), var(--board-card-pad) 0 0 var(--board-notice);
  }
}

/*
 * 좁은 화면의 한 줄은 레거시 `PostRows.vue` 의 `below(tablet-narrow)` 블록이다 — 칸 안쪽 13.6/3.2,
 * 제목은 댓글 수까지 한 덩어리로 두 줄 자름, 메타 줄은 그림 밑 칸 왼쪽 끝에서 시작한다.
 * 스킨은 그림을 절대 위치로 띄우고 행 전체에 그림 몫의 왼쪽 여백을 준다 — 그러면 메타 줄까지 제목만큼
 * 밀리고 그림이 글 덩어리와 세로로 어긋난다. 그림을 흐름 안으로 돌리면 `.title-row` 의 flex 가운데
 * 맞춤이 그림과 글 덩어리를 운영처럼 붙이고, 메타 줄은 칸 끝에서 시작한다. 접히는 폭은 스킨이 접는
 * 43.75rem 에 맞춘다 — 레거시 `below(tablet-narrow)` 의 700px 과 같은 값이다.
 */
@media (max-width: 43.75rem) {
  .board-table tr {
    row-gap: 0.25rem;
    padding: 0.85rem 0.2rem;
  }

  .board-table tr:not(.row-notice):has(.gb-row-thumb) {
    position: static;
    min-height: 0;
    padding-left: 0.2rem;
  }
  .board-table tr:not(.row-notice):has(.gb-row-thumb) .gb-row-thumb {
    position: static;
  }

  /*
   * 제목·댓글 수·N 표시는 한 인라인 흐름으로 두 줄까지. 레거시 `.title-text` 는
   * -webkit-line-clamp 를 쓰지만, 그러려면 -webkit-box 가 필요하고 -webkit-box 는 자식
   * 요소(제목 링크·댓글 수 링크·N 표시)를 한 줄씩 따로 세워 댓글 수가 제목 밖으로 떨어진다.
   * 대신 상자 높이를 두 줄로 잘라 붙인다 — 댓글 수가 두 줄 안에 못 들어가면 레거시처럼
   * 같이 잘린다. 다만 잘림 끝의 「…」는 나오지 않는다(line-clamp 없이는 넣을 수 없다).
   * 출처 줄은 같은 `.title-main` 안에 있어 같이 잘리므로 흐름에서 빼 아래에 절대로 둔다.
   * 기준 상자는 `.title-main` 이 아니라 `.title-row` 다 — `.title-main` 에 닻으면
   * overflow:hidden 이 출처 줄까지 잘라 버린다. 자리는 `.title-main` 의 아래 마진으로
   * 벌려 둔다(틈 3.2 + 줄 18.2) — 마진은 flex 아이템이라 상쇄되지 않고 덩어리 높이에 들어간다.
   * 공지 줄은 뺀다 — 스킨이 공지 뱃지를 float 로 제목 옆에 붙이는데 BFC 로 만들면
   * 뱃지를 피해 제목이 아래로 떨어진다.
   */
  .board-table tr:not(.row-notice) .title-row {
    position: relative;
  }
  .board-table tr:not(.row-notice) .title-main {
    overflow: hidden;
    max-height: 49.6px;
  }
  /*
   * `listBoard: 'number'` 는 좁은 화면에서 게시판 이름을 제목 앞 블록(`a.row-board-tag`)
   * 으로 둔다. 태그가 한 줄(20.15)과 아래 틈(0.8)을 먹으므로 두 줄 자름 높이에 같이
   * 더해 줘야 제목이 두 줄 그대로 보인다.
   */
  .board-table tr:not(.row-notice) .title-main:has(a.row-board-tag) {
    max-height: 70.6px;
  }
  .board-table tr:not(.row-notice) .title-main:has(.row-source) {
    margin-bottom: 21.4px;
  }
  /* 출처 줄은 슬롯 래퍼(.gb-slot-listing-row) 안에 들어 있어 후손 선택자다. */
  .board-table tr:not(.row-notice) .title-main .row-source {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    margin: 0;
  }
  /* 그림 있는 줄은 출처가 그림이 아니라 제목 밑에 간다 — 제목과 같은 왼쪽(그림 72 + 틈 8). */
  .board-table tr:not(.row-notice) .title-row:has(.gb-row-thumb) .row-source {
    left: calc(72px + var(--board-space-2));
  }

  /* 메타 줄은 전부 흐린색 — 스킨은 글쓴이를 accent 로 두지만 레거시 `.mobile-meta` 는 한 색이다. */
  .board-table td.col-author,
  .board-table td.col-author a {
    color: var(--board-dim);
  }

  /*
   * 회원 링크만은 폰에서도 흐리지 않는다 — 레거시 `.mobile-meta` 는
   * `.author:not(.interactive)` 만 muted 다(`PostRows.vue:48`).
   */
  .board-table td.col-author a[href] {
    color: color-mix(in srgb, var(--board-accent) 48%, var(--board-ink));
  }

  /* 「조회 5」 라벨과 수 사이는 글자 사이 한 칸 — 스킨 여백으로는 붙어 보인다(운영 실측). */
  .board-table .col-label {
    margin-right: 0.25em;
  }

  /*
   * 마지막 행 밑줄은 좁은 화면에서도 남는다 — 레거시 `PostRows.vue` 의 `below(tablet-narrow)`
   * 는 칸 여백만 바꾸고 밑줄을 지우지 않는다(운영 폰 목록 마지막 글 아래에 선이 있다).
   * 이 폭에서는 선이 칸이 아니라 행에 있고, 스킨이 마지막 행의 것을 지우므로(`styles.ts:857`)
   * 되돌린다. 빈 목록 행은 위 넓은-화면 규칙과 같은 이유로 뺀다.
   */
  .board-list .board-table tr:last-child:not(.row-empty) {
    border-bottom: 1px solid var(--board-line);
  }
}

/*
 * 목록 카드의 위·아래 여백도 운영 `AppSurface` 값 17.6 이다 — 좌우는 `--board-card-pad` 가 이미
 * 맞춘다. 스킨은 위를 0(말머리 탭이 카드 맨 위에 붙는 자리), 아래를 8px 로 두는데, 운영은 탭이
 * 있어도 카드 안쪽에 들어가므로 위도 17.6 이다. 말머리를 쓰는 글 밑 목록은 스킨의
 * `.post-listing:has(.gb-categories)`(0,2,0)가 여전히 이겨 위 0 을 지킨다.
 */
.board-list {
  padding-top: 1.1rem;
  padding-bottom: 1.1rem;
}

/*
 * 빈 목록은 운영이 표를 그리지 않는다 — `AppSurface` 안에 문단 하나다(`PostListPage.vue:4`
 * `<p class="empty-state">게시글이 없음.</p>`). 스킨은 머리줄을 남기고 `tr.row-empty` 한 행을
 * 그리므로 머리를 숨긴다. 칸의 안쪽 여백·흐린 글자·가운데는 스킨의 빈 상태 규칙이
 * `--board-empty-pad`(레거시 `.empty-state` 의 2.5rem 1rem)와 `--board-dim` 으로 주므로
 * 여기선 여백 상쇄와 줄높이만 남긴다. 격자(갤러리)는 `p.grid-empty` 가 같은 자리다.
 */
.board-table:has(.row-empty) thead {
  display: none;
}
/* 폰에서 행이 칸의 상자가 되는 배치(`styles.ts` 의 접힌 `tr` 여백 .85rem)는 빈 행에도 남아
   문단을 27.2 키운다 — 빈 행의 상자 여백은 칸(문단)의 안쪽 여백이 이미 맡으므로 지운다. */
.board-table tr.row-empty {
  padding: 0;
}
.board-table .row-empty td,
.board-list .grid-empty {
  margin: 0;
  line-height: 1.6;
}

/*
 * 쪽번호 줄과 마지막 줄 사이의 틈은 운영의 `.pagination { margin-top: 1.2rem }` 이다 — 스킨은
 * `.board-foot` 의 윗여백 12px 로 만들므로 1.2rem 로 올린다. 아래 여백은 카드의 아래쪽 안쪽
 * 여백(17.6)이 이미 맡으므로 foot 의 아래 여백은 0 으로 둔다 — 둘을 얹으면 운영보다 깊어진다.
 * 쪽번호 nav 는 운영처럼 카드 안쪽 폭을 다 쓴다 — 단추들은 그 안 가운데서 움직이지 않는다.
 */
.board-list .board-foot {
  padding: 1.2rem 0 0;
}
.board-list .board-foot .gb-pagination {
  width: 100%;
}

/*
 * 쪽번호 hover 는 레거시 `AppPagination.vue` 의 `.pagination a:hover` 다 — 글자
 * `--color-brand-600`(--board-accent-text), 배경 `--color-surface-subtle`(--board-tint,
 * 어두운 면에서 둘 다 #202a28), 밑줄 없음. 스킨은 글자만 바꾸고 배경은 화살표 칸에만 둔다.
 */
.gb-pagination-strip a:hover,
.gb-pagination-line a:hover {
  color: var(--board-accent-text);
  background: var(--board-tint);
  text-decoration: none;
}

/*
 * D2R 판의 같은 hover — 운영은 테마 변수를 따라 `--color-brand-600`(#d6b85b) 글자에
 * `--color-surface-subtle`(#211a11) 바탕이다(`_themes.scss:19,25`). 이 값들은 `.d2r` 안
 * `--color-*` 다리에 있다 — `--board-accent-text`·`--board-tint` 는 판 값(#d8b45c·#1c1913)으로
 * 갈려 있어 그대로 쓰면 한 단계 어긋난다.
 */
.d2r .gb-pagination-strip a:hover,
.d2r .gb-pagination-line a:hover {
  color: var(--color-brand-600);
  background: var(--color-surface-subtle);
}

/*
 * 못 누르는 칸(1쪽의 처음·이전, 마지막 쪽의 다음)은 운영 `.pagination .disabled` 한 줄이다 —
 * opacity .38, cursor default(레거시 `AppPagination.vue:84`). 우리 마크업은 링크 대신
 * `span[aria-disabled]` 를 찍고 스킨은 색만 dim 으로 두므로 여기서 흐림을 입힌다.
 * `.gb-pagination` 아래 strip·line 어느 줄에 있어도 같은 규칙이 닿는다.
 */
.gb-pagination [aria-disabled] {
  opacity: 0.38;
  cursor: default;
}

/*
 * 목록 위 검색 카드의 위아래 간격은 운영 `.stack` 의 .65rem — 머리·칩·목록 카드와의 사이가
 * 전부 10.4 다. 스킨은 아래만 20(칩이 붙으면 12)으로 두는데, 다음 줄의 윗마진
 * (.board-chips 등)과 상쇄돼 어느 순서로 와도 .65rem 하나로 떨어진다. 안쪽 여백은 카드 토큰이 준다.
 */
.board-search {
  margin: 0.65rem 0;
}
.board-search:has(+ .board-chips) {
  margin-bottom: 0.65rem;
}

/*
 * 검색 카드 안 컨트롤. 운영은 한 줄 `.search` 격자에 열 사이 .55rem(`PostListPage.vue` 의
 * `.search { gap: .55rem }`), 높이는 따로 두지 않고 padding .55rem + 줄높이 1.6 + 선 2px 이
 * 만드는 45.2 다(레거시 `AppInput`·`AppSelect`·`AppButton` 전부 `padding:.55rem` 에
 * `min-height:2.55rem`) — 스킨 입력칸·단추 토큰이 같은 값을 주고, 선(--board-line)과
 * 포커스(--board-focus-line/ring)도 스킨 규칙이 이 사이트 토큰으로 잇는다.
 * 단추만 글자줄이 1.2(`AppButton.vue:15` 의 `line-height:1.2`, 19.2)라 다른 컨트롤보다
 * 낮다 — 운영은 격자가 늘려 같은 높이로 맞추므로 여기선 stretch 로 맞춘다.
 */
.board-search {
  align-items: stretch;
  gap: 0.55rem;
}

/*
 * 카테고리 칩 줄도 `.stack` 의 한 칸이다 — 위(검색 카드 또는 머리)와 아래(목록 카드)가
 * 전부 .65rem. 스킨의 아래 20 을 운영 값으로 돌리고, 검색 카드가 폰에서 숨는 때를 위해
 * 윗마진도 둔다(이웃 마진 상쇄로 데스크톱에선 합쳐져 .65rem 이다).
 */
.board-chips {
  margin: 0.65rem 0;
}

/*
 * 갤러리형 게시판(`/posts/gallery`·`/posts/humor`)의 격자와 카드.
 *
 * 격자 상자 자체의 위·아래 여백: 스킨은 `.board-list .board-grid` 에 위 `--board-card-pad`(17.6)·
 * 아래 `--board-space-2`(8)를 둔다(엔진 `styles.ts:575`). 레거시 `GalleryRows.vue` 의
 * `.gallery-grid` 는 padding 이 없다 — 위는 카드 안쪽 여백(1.1rem)이, 아래는 쪽번호 줄의
 * 윗여백(1.2rem, 위의 `.board-list .board-foot` 규칙)이 간격을 낸다.
 */
.board-list .board-grid.grid-framed {
  padding: 0;
}

/*
 * 카드 안은 스킨의 `.grid-framed`(엔진 `skins/board/src/styles.ts:665`~)를 레거시
 * `GalleryRows.vue:41-42` 의 `.gallery-card` 값으로 맞춘다 — 제목 줄높이·통계 여백·카드 안쪽
 * 여백이 다르다.
 *
 * 제목: 운영은 16px/1.6(25.6, 스킨의 tight 1.3 = 20.8 대신). 제목 위 틈은 레거시 strong 의
 * `padding-top:.1rem`, 아래는 0 — 스킨의 `margin:2px 0` 를 지운다. 늘어난 줄높이는 통계 줄의
 * 윗여백(.5→.35rem, 레거시 `>span{padding-block:.35rem .55rem}`)과 카드 아래 안쪽 여백
 * (.6→.55rem)이 벌충해 1280 카드 높이가 그대로다.
 */
.grid-framed .cell-head {
  margin: 0.1rem 0 0;
  line-height: 1.6;
}
.grid-framed .cell-stats {
  padding-top: 0.35rem;
}
.grid-framed .cell-body {
  padding-bottom: 0.55rem;
}
/*
 * 카드 통계 아이콘은 운영 13px(레거시 `GalleryRows.vue:16` lucide `:size="13"`) — 스킨
 * `styles.ts:697` 도 .8125rem 으로 같은 값이지만 `icons.tsx` 태그 속성 14 가 새지 않게
 * 갤러리 카드 안에만 명시한다. 400px 아래에서 운영 12px(레거시 `GalleryRows.vue:42`
 * `below(xs)` 의 `svg{width:12px}`, 스킨 `styles.ts:720` 도 .75rem)은 아래 25rem 블록이 단다.
 */
.grid-framed .cell-stats svg {
  width: 13px;
  height: 13px;
}

/*
 * 공지 카드의 「공지」는 레거시 `GalleryRows.vue:13` 의 `<small>공지</small>` 다 — 제목 위에 독립
 * 줄로 서는 회색 작은 라벨(보통 굵기의 닉네임 자리에 「공지」를 쓴다). 스킨 기본 `.mark-notice` 는
 * 제목 안 초록 알약(엔진 `styles.ts:640`)이라 갤러리 카드 안에서만 알약을 걷고 라벨로 돌린다.
 * 색은 레거시 `--color-muted` 에 대응하는 `--board-dim`, 크기는 `--text-caption` 에 대응하는
 * `--board-size-caption`(.8125rem), 굵기는 보통. `display:block` 이라 제목 글자는 라벨 아래
 * 줄에서 시작하고, 줄높이는 `.cell-head` 의 것을 그대로 잇는다.
 * 레거시는 저 자리에 닉네임 대신 「공지」를 쓰므로(같은 줄의 `:small` 삼항) 공지 칸의 글쓴이
 * 줄은 숨긴다 — 남겨 두면 라벨이 한 줄 더해져 카드가 21px 커지고 같은 줄의 카드들이 같이 늘어난다.
 */
.grid-framed .cell-notice .cell-author {
  display: none;
}
.grid-framed .cell-notice .mark-notice {
  display: block;
  margin: 0;
  padding: 0;
  border-radius: 0;
  background: none;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-normal);
  line-height: inherit;
  vertical-align: baseline;
}

/*
 * 태블릿(레거시 `below(tablet)` 760px, 스킨 기준 47.5rem)에서는 레거시 `below(tablet)` 규칙: 안쪽 좌우 여백 .5rem, 제목은 두 줄
 * 자리 — 줄높이 1.35(21.6)·min-height 2.65rem(42.4), 통계 사이 틈 .4rem. 레거시 `below(xs)`
 * (400px)에서는 통계 틈이 .3rem(4.8)으로 한 번 더 좁아진다.
 *
 * 제목 위 .1rem 은 margin 이 아니라 padding 으로 둔다 — 레거시 strong 은 `padding-top:.1rem` 이
 * `min-height:2.65rem`(border-box) 안에 들어가 제목 칸이 42.4 인데, margin 으로 두면
 * 1.6+42.4=44 로 카드가 2px 커진다(390 카드 232→230).
 */
@media (max-width: 47.5rem) {
  .grid-framed .cell-body {
    padding-inline: 0.5rem;
  }
  .grid-framed .cell-head {
    margin-top: 0;
    padding-top: 0.1rem;
    line-height: 1.35;
    min-height: 2.65rem;
  }
  .grid-framed .cell-stats {
    gap: 0.4rem;
  }
}
@media (max-width: 25rem) {
  .grid-framed .cell-stats {
    gap: 0.3rem;
  }
  .grid-framed .cell-stats svg {
    width: 12px;
    height: 12px;
  }
}

/*
 * 폰 쪽번호 아랫줄(처음·이전·번호 칸·다음). 운영 칸은 사방 .35rem 안쪽 여백에 아이콘 16×16,
 * 아이콘·글자 사이 .1rem(레거시 `AppPagination.vue` `.pagination__mobile-nav`)이다 — 스킨은
 * 세로 여백 없이 .4rem·아이콘 13(.8125rem)이라 셋을 같이 덮는다. 칸 사이 틈은 운영의 .15rem
 * (같은 파일 `.pagination__mobile`)이고, 번호 칸은 양옆 .2rem 을 띄우며(레거시 `label` 의
 * margin-inline) 입력 안쪽은 .2rem(레거시 `input`). */
@media (max-width: 43.75rem) {
  .gb-pagination-line {
    gap: 0.15rem;
  }
  .gb-pagination-line a,
  .gb-pagination-line span {
    gap: 0.1rem;
    padding: 0.35rem;
  }
  .gb-pagination-line .gb-icon {
    width: 1rem;
    height: 1rem;
  }
  .gb-pagination-line .gb-pagination-jump {
    margin-inline: 0.2rem;
  }
  .gb-pagination-jump input {
    --board-input-pad-x: 0.2rem;
  }
}

/*
 * 본문 끝 출처 줄. 플러그인이 아니라 글 마크다운이 `<p class="source">출처: <a>…</a></p>` 로
 * 찍어 `.post-body > .gb-body` 의 마지막에 온다. 스킨의 `.post .gb-body p`(0,2,1)와 `.post .gb-body a`
 * (0,2,1)를 이겨야 해서 `.post-body` 까지 붙여 (0,3,0)/(0,3,1) 로 잡는다.
 *
 * 위로 글을 가르는 실선 하나, 라벨은 `--board-dim` 14px, 링크는 `--board-accent-text` 에
 * 밑줄 없이 두고 hover 에서만 긋는다.
 *
 * 위 간격·선 안쪽 여백은 레거시 `.post-content :deep(.source)` 의 `margin-top:1.5rem`·
 * `padding-top:.75rem`(`PostContent.vue:255-262`)이다 — `--board-space-6`·`--board-space-3`
 * 이 그 값이다. `PostDetailView.vue:114` 의 `footer.source` 는 본문에 `class="source"` 가
 * 이미 박힌 글에서는 그려지지 않는다(`hasLegacySource`) — 이 선택자가 겨냥하는 판이다.
 *
 * 마크다운이 찍는 건 `<p class="source">` 라 위의 `p + p`(0,3,2)가 margin-top 을 덮어 쓴다 —
 * 선택자에 `p` 를 붙여 (0,3,2)로 맞추고 이 파일에서 더 뒤에 선언해 이긴다. 선·색·크기는
 * 태그를 가리지 않게 원래 선택자에 둔다.
 */
.post-body .gb-body .source,
.post .post-body .gb-body p.source {
  margin-top: var(--board-space-6);
  padding-top: var(--board-space-3);
  border-top: 1px solid var(--board-line);
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  /* 레거시 `PostContent.vue:258-262` 의 `.source{line-height:1.6}` — 두지 않으면 본문 1.75 를 상속한다. */
  line-height: 1.6;
}

/*
 * 그림·동영상 출처는 같은 펜스가 `<p class="image-source">`/`<p class="video-source">` 로 찍는다
 * (코어 `renderer.ts` sourceHtml) — 링크 규칙은 세 종류가 같이 쓴다. 레거시는 셋 다
 * `--color-brand-600`·`--weight-medium`(500)·밑줄 없음에 hover 밑줄이다
 * (`PostContent.vue:245-252,263-264`). `.video-source a`·`.image-source a` 는 이 선택자에만
 * 기대므로, 본문 링크 규칙(0,3,0)보다 한 단계 위인 (0,3,1)을 유지한다.
 */
.post-body .gb-body .source a,
.post-body .gb-body .gb-image-source a,
.post-body .gb-body .gb-video-source a {
  color: var(--board-accent-text);
  font-weight: 500;
  text-decoration: none;
}

.post-body .gb-body .source a:hover,
.post-body .gb-body .gb-image-source a:hover,
.post-body .gb-body .gb-video-source a:hover {
  text-decoration: underline;
}

/*
 * 해외반응(`plugins/overseas`). 코어가 이 묶음을 `.gb-comments` 안의
 * `<section class="comment-section" data-section="overseas">` 로 그린다 — 스킨의 댓글 부품을
 * 그대로 쓰되 토큰만 다시 입힌다.
 *
 * 하나하나가 스킨의 기본값을 이겨야 한다. 제목의 무거운 잉크 선은 `.gb-comments h2`(0,1,1)가
 * `.gb-comment-section-title`(0,1,0)을 제치고 남긴 것이라 `.gb-comments h2.…`(0,2,1) 로 지운다.
 * 점수 배지도 스킨의 `.gb-badge.tone-info`(0,2,0)를 이겨야 해서 섹션·항목까지 붙여 (0,4,0) 로
 * 잡는다. 점수 마크업(`<span class="badge tone-info">▲ 22</span>`) 자체는 플러그인 테스트가
 * 단언하므로 그대로 두고, 테두리·여백·바탕만 걷어 인라인 글자로 만든다.
 */
/*
 * 운영은 옅은 상자가 제목과 처음 몇 줄만 감싸고, 「더 보기」 단추는 상자 밖 아래에 둔다. 코어는
 * 접힌 줄을 `<details class="comment-section-more">` 로 같은 섹션 안에 그리므로, 섹션 자체에
 * 바탕을 칠하면 단추까지 상자 안에 든다. 그래서 섹션을 한 줄 격자로 세우고 바탕은 `::before` 가
 * 제목·첫 목록 두 행에만 깐다. 격자 칸이 겹쳐도 `::before` 가 문서 순서상 먼저라 글자가 위에 온다.
 */
.gb-comment-section[data-section='overseas'] {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

/* 상자 모서리는 운영의 --radius-sm(.4rem) 이다 — 스킨 기본 --board-radius(8px)는 더 둥글다. */
.gb-comment-section[data-section='overseas']::before {
  content: '';
  grid-area: 1 / 1 / 3 / 2;
  border-radius: 0.4rem;
  background: var(--board-tint);
}

/*
 * 제목줄 — 레거시 `.comment-section>header` 는 `align-items:end; justify-content:space-between`
 * 이다. 코어 마크업은 아이콘·제목·수·캡션이 한 줄의 나란한 자식이라, 스킨이 둔 캡션의
 * `margin-left:auto` 가 오른쪽 끝을 만들고 아이콘-제목 사이는 아이콘의 오른쪽 여백이 .45rem 을
 * 낸다. 「해외반응 6」의 제목-숫자 사이는 마크업의 보통 띄어쓰기 한 칸이다 — 격자 틈을 두지 않는다.
 * 상자 안쪽 여백 1rem 은 제목이 위·좌·우를, 목록이 좌·우·아래를 나눠 든다.
 */
.gb-comment-section[data-section='overseas'] > .gb-comment-section-title {
  grid-row: 1;
  grid-column: 1;
  align-items: flex-end;
  gap: 0;
  margin: 0 0 0.7rem;
  padding: 1rem 1rem 0;
  line-height: 1.35;
}

/* 아이콘만 줄 가운데 — flex-end 는 캡션을 제목줄 아래끝에 붙이려는 것이라 아이콘은 따로 뺀다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-icon {
  align-self: center;
  margin-right: 0.45rem;
}

/* 띄어쓰기는 줄 끝에서 접혀 숫자가 제목에 붙는다 — 한 칸 폭(.25em)을 여백으로 돌려준다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-count {
  margin-left: 0.25em;
}

.gb-comment-section[data-section='overseas'] > :not(.gb-comment-section-title, .gb-comment-section-more) {
  grid-row: 2;
  grid-column: 1;
  padding: 0 1rem 1rem;
}

.gb-comment-section[data-section='overseas'] > .gb-comment-section-more {
  grid-row: 3;
  grid-column: 1;
}

.gb-comments h2.gb-comment-section-title {
  border-bottom: 0;
}

/* 운영은 개수도 제목 글과 같은 색·굵기다(`PostDetailView.vue:28`) — 스킨의 accent·bold 를 되돌린다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-count {
  color: inherit;
  font-weight: inherit;
}

/* 캡션 — 운영 13px/1.6. 오른쪽 끝은 스킨의 margin-left:auto, 아래끝은 flex-end 가 맞춘다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-caption {
  line-height: 1.6;
}

/*
 * 스킨은 이름 위 줄에 점수를 따로 그리고 항목마다 아래 실선을 긋는다. 운영은 이름 옆에
 * 붙은 작은 강조 글자고 구분은 여백이다. flex 로 순서를 바꿔 이름(`p.gb-meta`)을 먼저,
 * 점수(`.gb-slot`)를 그 옆에, 본문(`.gb-body`)을 다음 줄로 내린다.
 */
.gb-comment-section[data-section='overseas'] .gb-comment-section-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  /* 이름-본문 .35rem, 이름-점수 .5rem — 운영 CommentItem 의 틈이다. */
  gap: 0.35rem var(--board-space-2);
  border-bottom: 0;
}

/* 이름은 운영대로 16px/700·줄높이 1.6 — 스킨의 .gb-comment .gb-meta(14px)를 덮는다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-item > .gb-meta {
  order: 0;
  margin: 0;
  font-size: 1rem;
  line-height: 1.6;
}

.gb-comment-section[data-section='overseas'] .gb-comment-section-item > .gb-slot {
  order: 1;
}

/* 본문 16px/1.6. 아래 .45rem 은 레거시의 빈 액션줄(좋아요·답글 줄)이 서던 자리다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-item > .gb-body {
  order: 2;
  flex-basis: 100%;
  margin-bottom: 0.45rem;
  font-size: 1rem;
  line-height: 1.6;
}

.gb-comment-section[data-section='overseas'] .overseas-score {
  margin: 0;
}

.gb-comment-section[data-section='overseas'] .overseas-score .gb-badge {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  vertical-align: baseline;
}

/* 구분선은 이미 걷었으니 남는 건 항목 위아래 .8rem 여백뿐이다 — 운영 CommentItem 의 안쪽이다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-list > li {
  padding: 0.8rem 0;
}

/*
 * 운영의 더 보기 단추는 상자 밖 가운데 놓인 흰 단추 하나다 — 레거시 `AppButton` 의 quiet 판
 * (320 한정 폭, min-height 2.55rem = 40.8, 여백 .55/.9, 모서리 .4rem). 위 14.4 는 운영의
 * 카드 격자 틈 24 에서 9.6 을 뺀 값(`.overseas-more` 의 `margin-top:-.6rem`)이다. 펼친 줄은
 * 단추 아래에 같은 옅은 상자로 한 번 더 깐다 — 자바스크립트 없이 `<details>` 가 여는 자리다.
 */
.gb-comment-section[data-section='overseas'] .gb-comment-section-more > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  width: min(20rem, 100%);
  min-height: 2.55rem;
  margin: 0.9rem auto 0;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--board-line);
  border-radius: 0.4rem;
  background: var(--board-surface);
  list-style: none;
  cursor: pointer;
  font-size: var(--board-size-ui);
  line-height: 1.2;
  font-weight: var(--board-weight-bold);
  color: var(--board-ink);
}

.gb-comment-section[data-section='overseas'] .gb-comment-section-more > summary::-webkit-details-marker {
  display: none;
}

/* 펼친 상자는 제목이 없어 위아래가 항목 여백(.8rem)만이다 — .2rem 을 얹어 상자와 같은 16 을 맞춘다. */
.gb-comment-section[data-section='overseas'] .gb-comment-section-more[open] > .gb-comment-section-list {
  margin-top: var(--board-space-3);
  padding: 0.2rem 1rem;
  border-radius: 0.4rem;
  background: var(--board-tint);
}

/*
 * 좁은 화면(레거시 `below(mobile)` = 600px 미만): 상자 안쪽 여백이 .7rem 로 줄고 캡션은
 * 제목 밑으로 내린다. 레거시는 헤더를 세로로 돌리지만(`flex-direction:column`) 코어 마크업은
 * 펼친 한 줄이라, 캡션만 다음 줄로 넘겨 같은 모양을 만든다 — 위 1rem 은 헤더의 격자 틈이다.
 */
@media (max-width: 599.98px) {
  .gb-comment-section[data-section='overseas'] > .gb-comment-section-title {
    flex-wrap: wrap;
    row-gap: 1rem;
    padding: 0.7rem 0.7rem 0;
  }

  .gb-comment-section[data-section='overseas'] > :not(.gb-comment-section-title, .gb-comment-section-more) {
    padding: 0 0.7rem 0.7rem;
  }

  .gb-comment-section[data-section='overseas'] .gb-comment-section-caption {
    flex-basis: 100%;
    margin-left: 0;
  }
}

/*
 * 좁은 화면의 좌우 여백 8px. 레거시 `.container` 는 `below(tablet-narrow)`(700px) 아래에서
 * `calc(100% - 1rem)` 으로 준다(`global.scss:42`, 갈림점은 `_breakpoints.scss`). 셸·머리 줄·
 * 바닥 줄, 쌓인 칸 사이가 모두 `--board-gap` 하나를 쓰므로 그 값만 줄인다 — 700 과 스킨의
 * 48rem(768) 사이에서는 여백이 16 을 유지해야 운영과 같다.
 */
@media (max-width: 43.75rem) {
  :root {
    --board-gap: 0.5rem;
  }
}

/*
 * 푸터 링크 hover — 운영 `.site-footer__links a:hover`(`AppFooter.vue:42`): 글자
 * `--color-brand-600`(--board-accent-text)에 밑줄과 .2rem 오프셋. 스킨은 밑줄만 준다.
 * 다크에서 `--board-accent-text` 가 #56b89f 라 면 위 대비가 유지된다.
 */
.gb-footer-links a:hover {
  color: var(--board-accent-text);
  text-decoration: underline;
  text-underline-offset: 0.2rem;
}

/*
 * 같은 갈림점에서 푸터 링크가 두 줄로 갈라질 때의 줄 사이 — 레거시 `below(tablet-narrow)` 의
 * `.site-footer__links { gap: .55rem 1rem }`(`AppFooter.vue:30`). 스킨 기본은 행·열 모두
 * `--board-space-4`(1rem)라 두 줄이 41.6 으로 벌어진다; 25.6(줄높이) + 8.8 = 34.4 가 운영이다.
 * 링크 묶음과 저작권 줄 사이는 거꾸로 레거시 `.site-footer__inner { gap: 1rem }` 이라 스킨
 * `.footer-row` 의 행 간격 `--board-space-2`(.5rem)보다 넓다 — 운영 푸터 높이 144.2.
 */
@media (max-width: 43.75rem) {
  .gb-footer-links,
  .gb-footer-links nav {
    gap: 0.55rem 1rem;
  }
  .footer-row {
    row-gap: 1rem;
  }
}

/*
 * 폰 홈(390px). 운영 값:
 * - 좌우 여백 8px — 위 43.75rem 블록이 `--board-gap` 을 줄인다(레거시 `below(tablet-narrow)`).
 * - 시세 카드는 한 줄짜리 띠다. 왼쪽 3px 브랜드색 선, 이름 옆에 시세를 이어 쓰고 그 아래 흐린
 *   안내 한 줄. 확인 범위(개수·날짜)는 접고, 한 줄에 안 들어가는 시세는 다음 줄로 넘겨 가린다.
 * - 최근은 60px 네모 그림 옆에 게시판 이름을 위, 제목을 아래(두 줄까지)에 두고 요약은 접는다.
 *   댓글 수는 오른쪽 가운데.
 * - 사이드바는 칸마다 따로 카드이고, 인기·댓글은 다섯 줄까지만 보인다.
 */
@media (max-width: 47.5rem) {
  .home-market {
    /*
     * 이름 칸은 4.6rem 으로 못박는다 — 내용에 맡기면 「폰덕」(두 자)과 「알뜰폰」(세 자)의 폭이
     * 달라 두 카드의 값이 서로 다른 자리에서 시작한다(레거시 `below(tablet)` 블록).
     */
    grid-template-columns: 4.6rem minmax(0, 1fr);
    align-items: center;
    gap: 0.1rem 0.55rem;
    min-height: 3.25rem;
    padding: 0.5rem 0.7rem 0.5rem 0.55rem;
    border-left: 3px solid var(--board-accent-text);
  }

  .home-market__head {
    grid-column: 1;
    /* 첫 행에만 둔다 — 두 행을 걸치면 머리가 카드 가운데로 내려와 운영(첫 줄에 가운데 맞춤)과 어긋난다. */
    grid-row: 1;
    align-items: center;
    gap: 0.25rem;
  }

  .home-market__name {
    font-size: var(--board-size-meta);
  }

  .home-market__facts {
    display: none;
  }

  .home-market__rows {
    grid-column: 2;
    grid-row: 1;
    display: flex;
    flex-wrap: wrap;
    column-gap: 0.55rem;
    /*
     * 값은 한 줄에 들어가는 만큼만 선다 — 넘치는 값은 다음 줄로 흘러 1.4rem 에서 잘린다.
     * 줄 간격을 넉넉히 두는 것은 둘째 줄이 실오라기만큼도 비치지 않게 하려는 것이다(레거시).
     */
    row-gap: 1rem;
    max-height: 1.4rem;
    overflow: hidden;
  }

  .home-market__row {
    display: flex;
    flex: none;
    align-items: baseline;
    gap: 0.25rem;
  }

  .home-market__label {
    overflow: visible;
    color: var(--board-text);
  }

  /* 좁은 화면에서도 값 색은 그대로 둔다(레거시가 브랜드색을 유지하던 자리). 여백만 되돌린다. */
  .home-market__value {
    padding-left: 0;
  }

  .home-market__go {
    grid-column: 2;
    grid-row: 2;
    /* 상자는 칸 끝까지 늘린다(넓은 화면의 `end` 를 되돌림) — 글자는 왼쪽, 줄은 오른쪽 끝까지 닿는다. */
    justify-self: stretch;
    gap: 0;
    font-weight: var(--board-weight-normal);
  }

  .home-market__go svg {
    width: 0.9rem;
    height: 0.9rem;
  }

  /*
   * 시세 두 칸 사이는 .45rem(레거시 모바일 `.market{gap:.45rem}`) — `.gb-area-page-main` 격자의
   * .65rem 보다 좁으므로 둘째 칸을 3.2px 당긴다. 최근 카드와의 간격(.65rem)은 그대로다.
   */
  .gb-area-page-main > .gb-widget-slot:has(.home-market) + .gb-widget-slot:has(.home-market) {
    margin-top: -0.2rem;
  }

  /*
   * 폰 홈 섹션 머리(레거시 모바일 `.section-head`). 제목은 18px(--text-subheading)/24.3,
   * 위 8 · 아래 12.8 — 스킨 20px 머리가 넓은 화면과 같은 자리에 서면 첫 줄이 10px 위로 붙는다.
   */
  .gb-area-page-main .gb-widget .box-title,
  .gb-area-page-bottom .gb-widget .box-title {
    margin: 0.5rem 0 0.8rem;
    font-size: 1.125rem;
  }
  /* 제목 오른쪽 링크는 40px 터치 상자(레거시 `.section-head>a{min-height:2.5rem}`). */
  .gb-area-page-main .gb-widget > .box-more,
  .gb-area-page-bottom .gb-widget > .box-more {
    top: calc(var(--board-card-pad) + 0.05rem);
  }
  .gb-area-page-main .box-more > a,
  .gb-area-page-bottom .box-more > a {
    display: flex;
    align-items: center;
    min-height: 2.5rem;
    padding-inline: 0.25rem;
  }

  .gb-area-page-main .box-digest .box-rows li {
    /* 레거시 모바일 `.feed__row`: 최소 80px, 위아래 10.4, 그림과 글 사이 11.2. */
    height: auto;
    min-height: 5rem;
    padding: 0.65rem 0;
    gap: 0.7rem;
    /* 폰에서는 위의 넓은-화면 위 정렬을 되돌린다 — 레거시 모바일 `.feed__row{align-items:center}` 처럼 가운데. */
    align-items: center;
  }

  /* 넓은 화면의 4px 규칙보다 특이성을 맞춰 폰의 6.4px 를 지킨다. */
  .gb-area-page-main .box-digest .digest-cover {
    width: 3.75rem;
    height: 3.75rem;
    border-radius: 0.4rem;
  }

  .gb-area-page-main .digest-line {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.1rem 0.75rem;
  }

  .digest-space {
    grid-column: 1;
    grid-row: 1;
    justify-self: start;
  }

  .digest-title {
    grid-column: 1;
    grid-row: 2;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    white-space: normal;
    font-weight: var(--board-weight-normal);
    line-height: 1.4;
  }

  .digest-line .box-count {
    grid-column: 2;
    grid-row: 1 / span 2;
  }

  .digest-summary {
    display: none;
  }

  /* 곁칸도 여기서 본문 아래로 내린다 — 레거시 `below(tablet)` 의 `.home-grid` 1열. */
  .board-main:has(> aside.gb-sidebar:not(:empty)):has(> .gb-area-page-main) {
    grid-template-columns: minmax(0, 1fr);
  }

  /* 아래띠는 폰에서 한 열 — 넓은 화면의 2fr/1fr 을 되돌린다(스킨 모바일 규칙과 같은 뜻, 우리 쪽이 뒤에 와야 먹는다). */
  .gb-area-page-bottom {
    grid-template-columns: minmax(0, 1fr);
  }

  /* 읽을거리 줄은 폰에서 42.4(레거시 `.reading a{min-height:2.65rem;align-items:center}`) — 스킨의 39px 고정을 푼다. */
  .gb-area-page-bottom .box-compact .box-rows li {
    height: auto;
    min-height: 2.65rem;
  }

  /* 도구 카드는 폰에서 112px(레거시 `.tool-card{min-height:7rem;padding:1rem 1.15rem}`). 읽기 줄높이(1.75)를 1.6 으로 낮춰야 안에 든다. */
  .gb-area-page-bottom .gb-widget-slot-markdown > .gb-widget {
    min-height: 7rem;
    padding: 1rem 1.15rem;
    line-height: 1.6;
  }

  .gb-area-page-sidebar {
    /* 칸 사이는 .55rem(레거시 모바일 `.side{gap:.55rem}`) — `--board-gap` 은 700 초과에서 16 이라 넓다. */
    gap: 0.55rem;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
  }

  .gb-area-page-sidebar > .gb-widget-slot,
  .gb-area-page-sidebar > .gb-widget-slot + .gb-widget-slot {
    margin: 0;
    /* 아래 .65rem 은 레거시 모바일 `.side .mini{padding-bottom:.65rem}` — 스킨의 space-2(8) 보다 넓다. */
    padding: 0 var(--board-card-pad) 0.65rem;
    background: var(--board-surface);
    border: 1px solid var(--board-line);
    border-radius: var(--board-radius-l);
    box-shadow: var(--board-shadow);
  }

  .gb-area-page-sidebar .box-rows > li:nth-child(n + 6),
  .gb-area-page-sidebar .recent-comments > li:nth-child(n + 6) {
    display: none;
  }

  /* 제목 띠는 폰에서 .7rem/.85rem 으로 조금 얇아진다(레거시 모바일 `.side h2`). */
  .gb-area-page-sidebar .box .box-title,
  .gb-area-page-sidebar .gb-widget h2 {
    padding: 0.7rem 0.85rem;
  }

  /*
   * 줄은 폰에서 37.6 — 레거시 모바일 `.mini a{min-height:2.35rem;align-items:center}` 다
   * (넓은 화면의 36.8 과 다르다). 댓글 링크는 블록이라 위아래 패딩을 대신 늘려 가운데를 맞춘다.
   */
  .gb-area-page-sidebar .box-compact .box-rows li {
    height: auto;
    min-height: 2.35rem;
  }
  .gb-area-page-sidebar .recent-comments a {
    padding-block: 0.375rem;
  }
}

/*
 * 게시글 반응 줄과 댓글. 운영 값:
 * - 반응 아이콘은 윤곽선(lucide 의 thumbs-up·thumbs-down·bookmark)이고, 단추는 아이콘에 말과 수를
 *   같이 쓴다 — 「좋아요 0」「싫어요 0」(13px 굵게, 아이콘 17px). 말은 `gbun.config.ts` 가 바꾼다.
 * - 손님에게도 흐리게 죽인 단추가 아니라 보통 단추로 보인다. 로그인 안내는 곁의 링크가 맡는다.
 * - 댓글 사이엔 선이 없고 위아래 11.2px 로 띄운다. 답글은 8px 들여 왼쪽에 2px 옅은 선을 두르고,
 *   누구에게 단 답글인지는 들여쓰기가 말하므로 「↳ 이름」은 뗀다.
 * - 댓글의 반응은 15px 아이콘과 13px 흐린 수, 칸 사이 12.8px.
 */
:root {
  --board-icon-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z'/%3E%3Cpath d='M7 10v12'/%3E%3C/svg%3E");
  --board-icon-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z'/%3E%3Cpath d='M17 14V2'/%3E%3C/svg%3E");
  --board-icon-bookmark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z'/%3E%3C/svg%3E");
}

.post-vote .gb-reaction:is(.gb-reaction-like, .gb-reaction-value-1, .gb-reaction-value-neg1) {
  gap: 0.35rem;
  font-size: var(--board-size-caption);
}

.post-vote .gb-reaction:is(.gb-reaction-like, .gb-reaction-value-1, .gb-reaction-value-neg1)::before,
.post-vote .gb-bookmark.gb-hint::before,
.post-vote .gb-bookmark button::before {
  width: 1.0625rem;
  height: 1.0625rem;
}

/*
 * 저장 단추에는 보이는 말이 없다(`font-size: 0`) — 하지만 「저장」 글자 노드가 flex 칸으로 남아
 * 칸 사이 4px(--board-space-1)를 먹어 단추가 45.38px 로 나간다. 운영 41.38px(아이콘 17 +
 * 좌우 11.2 + 선 2)에 맞추려면 그 틈을 지운다. 스킨의 같은 규칙(0,4,1)과 무게를 맞춰 둔다.
 */
.post-vote .gb-bookmark.gb-hint,
.post-vote .gb-bookmark button[type="submit"]:not(.gb-link) {
  gap: 0;
}

.post-vote .gb-reaction .gb-count {
  font-size: inherit;
}

.post-vote .gb-reaction:disabled,
.gb-comment .gb-reaction:disabled {
  opacity: 1;
}

/*
 * 추천 줄 단추의 높이·줄높이는 운영 실측이다 — 높이 37.6(스킨 최소 2.375rem=38), 글자
 * 13px/20.8px bold(레거시 `PostActions.vue` 의 `--text-meta` + `body{line-height:1.6}`).
 * 스킨은 버튼 계열에 `--board-leading-tight`(1.3)이 물려 16.9 로 나간다. `font-size:0` 인
 * 저장 단추는 어차피 글자가 안 보이지만 같이 걸어 높이를 맞춘다.
 */
.post-vote .gb-reaction:is(.gb-reaction-like, .gb-reaction-value-1, .gb-reaction-value-neg1),
.post-vote .gb-bookmark.gb-hint,
.post-vote .gb-bookmark button[type="submit"]:not(.gb-link),
.post-vote .gb-share {
  min-height: 2.35rem;
  line-height: 1.6;
}

/* 공유 아이콘도 운영 17px — 위에서 추천·저장 아이콘만 1.0625rem 으로 올렸고 이것만 1rem 이었다. */
.post-vote .gb-share svg {
  width: 1.0625rem;
  height: 1.0625rem;
}

/*
 * 눌린 반응 — 레거시 `PostActions.vue:5` 의 `.post-actions button.active`: 글자 brand-700 · 면
 * brand-50 · 선 brand-600. 스킨은 눌림을 accent 채움 + 흰 글자로 그린다(`styles.ts:971`).
 * 눌린 상태의 hover 도 같은 모양이다 — 운영엔 이 단추의 hover 규칙이 없다. 저장 단추는 `.gb-reaction`
 * 클래스가 없어 스킨의 주 단추 규칙(`styles.ts:207`, 0,4,1)과 그 hover 채움(0,5,1)이 닿는다 —
 * `[type='submit']:not(.gb-link)` 를 얹어 둘 다 넘는 무게로 둔다. 비추천은 레거시에서 `active` 와
 * `danger` 가 같이 붙지만 `active`(0,2,1)가 `danger`(0,2,0)를 이겨 같은 녹색이다.
 */
.post-vote .gb-reaction[aria-pressed='true'],
.post-vote .gb-reaction[aria-pressed='true']:hover,
.post-vote .gb-bookmark button[type='submit']:not(.gb-link)[aria-pressed='true'],
.post-vote .gb-bookmark button[type='submit']:not(.gb-link)[aria-pressed='true']:hover {
  background: var(--board-brand-50);
  border-color: var(--site-pressed-line);
  color: var(--board-brand-700);
}

/*
 * 작성자 카드(`skin:board.authorCard`, 레거시 `PostAuthorCard.vue`)의 간격을 운영 값으로 —
 * 본문 카드와의 사이는 10.4px(.65rem, 스킨 기본 `--board-space-3`=12), 안쪽 여백은 카드
 * 토큰이 준다. 아바타 모서리는 레거시 프로필 사진의
 * `--radius-md`(.75rem=12px, 스킨 기본 `--board-radius`=8). 배경·선·그림자는 스킨이 이미
 * `--board-surface`·`--board-line`·`--board-shadow` 를 쓰므로 다크 모드도 그대로 탄다.
 */
.author-card {
  margin-top: 0.65rem;
}

.author-card-avatar {
  border-radius: 0.75rem;
}

/* 깊이0 댓글 줄의 위아래 여백은 운영과 같은 .8rem — 레거시 `.comment>.comment__main{padding:.8rem 0}`. */
.gb-comment-list > li {
  padding: 0.8rem 0;
  border-bottom: 0;
}

/*
 * 대댓글 들여쓰기 — 프리셋이 트리(`gbun.config.ts` 의 `comments.mode: 'tree'`)라 코어가 답글을
 * 부모 `li` 안의 중첩 `.gb-comment-list` 로 그린다. 운영은 깊이가 하나 늘 때마다 왼쪽이 8px 씩
 * 들어간다(레거시 `CommentItem.vue` 의 `.comment__children{margin:.15rem 0 0 .5rem}`). 스킨
 * 기본은 단계마다 4px 마진 + 2px 선 + 16px 안쪽 여백(합 22px)이라 목록의 선과 여백은 지우고
 * 8px 마진 하나만 남긴다 — 답글 몸통의 선은 목록이 아니라 각 답글의 몸통 부품에 둔다(아래).
 */
.gb-comment-list .gb-comment-list {
  margin: 0.15rem 0 0 0.5rem;
  padding: 0;
  border-left: 0;
}

/*
 * 답글 줄의 위아래 여백은 운영 답글과 같은 .7rem — 레거시
 * `.comment--reply>.comment__main{padding:.7rem 0 .7rem .65rem}`. 스킨의 중첩 줄 기본 .5rem 과
 * 마지막 줄 `padding-bottom:0` 을 덮는다(운영은 마지막 답글도 .7rem 이다).
 */
.gb-comment-list .gb-comment-list > li,
.gb-comment-list .gb-comment-list > li:last-child {
  padding: 0.7rem 0;
}

/*
 * 자식 목록을 가진 줄 — 부모 `li` 의 아래 패딩은 자식 목록 **뒤**에 서서 깊이마다 한 번씩
 * 더해진다(중첩 목록이 부모 `li` 안에 있으므로). 운영은 세로 패딩을 몸통 상자
 * (`.comment__main`)에만 두고 자식 목록 상자(`.comment__children{margin:.15rem 0 0 .5rem}`)와는
 * 마진으로만 떼므로, 부모의 아래 패딩을 지우고 그 값을 자식 목록의 위쪽 마진에 얹는다 —
 * 깊이0 부모는 .8rem, 답글 부모는 .7rem. 위의 마지막-답글 규칙(`li:last-child`)이
 * (0,3,1)이라 `.gb-comment` 를 붙여 같은 점수로 맞추고, 이 블록이 뒤에 있어 이긴다.
 */
.gb-comment-list > li.gb-comment:has(> .gb-comment-list) {
  padding-bottom: 0;
}

.gb-comment-list > li:has(> .gb-comment-list) > .gb-comment-list {
  margin-top: calc(0.8rem + 0.15rem);
}

.gb-comment-list .gb-comment-list > li:has(> .gb-comment-list) > .gb-comment-list {
  margin-top: calc(0.7rem + 0.15rem);
}

/*
 * 답글 몸통의 왼쪽 선 — 레거시 `CommentItem.vue` 는 `.comment--reply>.comment__main` 안의
 * `.comment__body`(머리줄·본문·반응을 묶은 상자)에 `margin-left:-.65rem; padding-left:.65rem;
 * border-left:2px solid var(--color-line)` 을 둔다. 상자 x 는 깊이0 과 같고, 선은 상자 왼쪽
 * 가장자리에 서며 글자는 선 오른쪽 .65rem 에서 시작한다.
 * 코어는 그 몸통 상자 없이 `li.gb-comment` 안에 `.gb-meta`·`.gb-body`·`.gb-reactions`·`.gb-actions`(와 slot
 * 산출물)을 중첩 `.gb-comment-list` 와 나란히 둔다 — `li` 자체에 선을 두면 선이 자식 목록을 따라
 * 끝까지 내려가므로, 몸통 부품 각각에 선과 안쪽 여백을 둔다. 부품 사이의 세로 마진은 선을
 * 끊으므로 같은 값의 padding 으로 옮겨 한 줄로 이어지게 한다.
 * `.gb-actions` 는 inline-flex 라 `.gb-reactions` 와 같은 줄에 선다 — 선을 두면 비추천 옆에 가운데
 * 막대가 서므로 선·여백 대상에서 뺀다(좁아져 다음 줄로 밀리는 드문 경우엔 그 줄에 선이 없다).
 * 회원 전용 행을 싸는 `div[data-viewer-branch]` 는 상자가 아니라 표시 갈림이라 contents 로 지운다.
 */
.gb-comment-list .gb-comment-list > li.gb-comment > :not(.gb-comment-list):not(.gb-actions) {
  border-left: 2px solid var(--board-line);
  padding-left: 0.65rem;
}

.gb-comment-list .gb-comment-list > li.gb-comment > [data-viewer-branch] {
  display: contents;
}

.gb-comment-list .gb-comment-list > li.gb-comment > .gb-meta {
  margin-bottom: 0;
  padding-bottom: 0.35rem;
}

.gb-comment-list .gb-comment-list > li.gb-comment > .overseas-score {
  padding-bottom: 0.75rem;
}

.gb-comment-list .gb-comment-list > li.gb-comment > .gb-tombstone {
  margin-bottom: 0;
}

.gb-comment-list .gb-comment-list > li.gb-comment > .gb-reactions {
  margin-top: 0;
  padding-top: 0.45rem;
}

.gb-comment-list .gb-comment-list > li.gb-comment > .gb-attachments {
  margin-top: 0;
  margin-bottom: 0;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

/* 첨부 아래 마진을 안쪽 여백으로 옮겼으니 뒤 부품의 위쪽 여백은 뺀다 — 겹치면 틈이 두 개가 된다. */
.gb-comment-list .gb-comment-list > li.gb-comment > .gb-attachments + .gb-reactions {
  padding-top: 0;
}

/*
 * 폰에서는 깊이 5(40px)에서 더 들어가지 않는다 — 레거시엔 폰 상한이 없었고, 그 이상은
 * 390px 에서 본문이 화면 밖으로 밀린다. 일곱 번째 `.gb-comment-list`(깊이 6 이상을 담는
 * 중첩 목록)부터 왼쪽 마진을 없앤다.
 */
@media (max-width: 47.99rem) {
  .gb-comment-list .gb-comment-list .gb-comment-list .gb-comment-list .gb-comment-list .gb-comment-list .gb-comment-list {
    margin-left: 0;
  }
}

.gb-comment .gb-meta {
  gap: 0.6rem;
  margin-bottom: 0.35rem;
}

.gb-comment .gb-meta .gb-parent {
  display: none;
}

/*
 * 댓글 본문 글자는 운영 16px/25.6 — 레거시 `CommentItem.vue` 의 `.comment__content` 는 본문
 * 상속값(1rem/1.6)을 그대로 썼다. 스킨 `.gb-comment .gb-body` 의 읽기 크기(17px/1.75)를 덮는다.
 * 해외반응 항목(`.gb-comment-section-item`)은 제 규칙이 따로 있어 `.gb-comment-normal` 로 좁힌다.
 */
.gb-comment-list .gb-comment-normal .gb-body {
  font-size: var(--board-size-ui);
  line-height: 1.6;
}

/*
 * 댓글 본문 문단 여백 — 운영 `.comment__content > p`(`CommentItem.vue`)는 margin 0 이라 문단
 * 사이가 줄높이로만 떨어지고 빈 `<p></p>` 는 높이 0 으로 지나간다. 스킨의 `p { margin: 0 0
 * var(--board-space-3) }`(`styles.ts:142`)이 댓글 문단에도 12px 씩 붙여 본문이 운영보다 길어진다.
 * `.gb-comment-list` 로 좁혀 해외반응(`.gb-comment-section-list`)과 글 본문(`.post-body`)엔 안 닿는다.
 */
.gb-comment-list .gb-comment .gb-body p {
  margin: 0;
}

.gb-comment .gb-reactions {
  gap: 0.8rem;
  margin-top: 0.45rem;
}

.gb-comment .gb-reaction {
  gap: 0.2rem;
  padding: 0.15rem;
  color: var(--board-dim);
}

.gb-comment .gb-reaction:is(.gb-reaction-like, .gb-reaction-value-1, .gb-reaction-value-neg1)::before {
  width: 0.9375rem;
  height: 0.9375rem;
}

.gb-comment .gb-reaction .gb-count {
  font-size: var(--board-size-caption);
}

/*
 * 댓글의 눌린 추천 — 레거시 `CommentItem.vue:94` 의 `.comment-action.selected` 와
 * `.comment__actions :deep(.selected)`: 글자 brand-700 + 면 brand-50(선은 운영도 없다).
 * 스킨은 눌림을 `--board-text` 글자로만 표시한다(`styles.ts:1071`). hover 도 같은 모양.
 */
.gb-comment .gb-reaction[aria-pressed='true'],
.gb-comment .gb-reaction[aria-pressed='true']:hover {
  color: var(--board-brand-700);
  background: var(--board-brand-50);
}


/*
 * 반응 단추를 싼 `form.gb-inline` 은 `.gb-reactions` 줄의 flex 항목이라 display 가 block 으로 굳고,
 * 그 안에 생긴 줄 상자(스트럿)가 줄 전체를 27.1 로 키운다 — 운영 `.comment__actions` 는 25.6 이다.
 * 상자를 contents 로 없애 단추가 줄의 직접 항목이 되면 줄 높이는 단추 높이 25.6 그대로다.
 */
.gb-comment-list .gb-comment .gb-reactions > form {
  display: contents;
}

/*
 * 이웃 글 줄. 격자와 단추 값은 레거시 `PostNavigation.vue:19` 한 줄에서 왔다 —
 * `.post-navigation{display:grid;grid-template-columns:repeat(3,max-content);justify-content:end;
 * gap:.5rem;margin-top:1rem}` 을 `.post-nav-links` 의 격자와 `.post-nav` 의 margin-top 으로 나눠 담고,
 * 단추는 `display:flex;…gap:.35rem;min-height:2.65rem;padding:.5rem .8rem;color:ink;background:surface;
 * border:1px solid line;border-radius:radius-sm;font-weight:bold` 다.
 *
 * 위 여백만 운영과 다르게 둔다: 운영은 `.post-detail.stack` 줄간 .65rem(10.4)에
 * `.post-navigation` 의 margin-top 1rem(16)이 더해져 카드 아래 26.4(`PostDetailView.vue:115`)인데,
 * 여기는 위 형제와 margin 이 상쇄되므로 margin-top 1rem 은 운영 계산값 그대로 두고 몫이던 10.4 를
 * padding-top 으로 옮겨 단추 위 거리 26.4 를 맞춘다.
 */
.post-nav {
  margin-top: 1rem;
  padding-top: .65rem;
}

.post-nav-links {
  display: grid;
  grid-template-columns: repeat(3, max-content);
  justify-content: end;
}

/*
 * 이웃 글 단추 치수는 스킨이 `.post-nav` 의 `--board-control-*` 토큰으로 준다(운영 43.6,
 * 1280·640·390 실측). 여기는 가운데 정렬과 아이콘 간격만 남긴다.
 */
.post-nav-links > .gb-newer,
.post-nav-links > .gb-older,
.post-nav-links > .gb-list {
  justify-content: center;
  gap: .35rem;
}

/*
 * 폰에서 이웃 글 단추는 이전글이 제 폭, 다음글이 나머지를 채우고 목록으로가 아랫줄을 통째로 쓴다.
 * 분기점은 레거시 `below(sm)` = 560px(PostNavigation.vue:19 — `max-content minmax(0,1fr)` 격자와
 * `.nav-next{width:100%}`, `.nav-list` 의 `grid-column:1/-1;grid-row:2` 에 해당).
 */
@media (max-width: 35rem) {
  .post-nav-links {
    grid-template-columns: max-content minmax(0, 1fr);
    justify-content: stretch;
  }

  .post-nav-links > .gb-older {
    width: 100%;
  }

  .post-nav-links > .gb-list {
    grid-column: 1 / -1;
    grid-row: 2;
    width: 100%;
  }
}

/*
 * 로그인·가입 카드. 사이트는 카드 모서리를 0 으로 두지만(`:root` 의 `--board-radius-l`),
 * 운영 로그인 창은 12px 로 둥글린 대화상자다. 폰에서는 헤더 바로 아래(운영 26px)에서 시작하고
 * 좌우 16px 을 띄운다 — 뼈대 여백 8px 에 8px 을 더한다.
 */
.gb-auth {
  border-radius: 12px;
}

@media (max-width: 47.99rem) {
  .gb-auth {
    margin: 1.625rem 0.5rem var(--board-space-6);
  }
}

/*
 * 태그 화면 머리(`/tags/<이름>`). 운영의 `.tag-head` 한 자리다 — 레거시
 * `apps/frontend/app/pages/tags/[tag].vue:3-7`(마크업)과 `:62`(스타일),
 * 줄높이 1.25 는 `_typography.scss:3` 의 h1 에서 왔다.
 *
 * 스킨의 `.board-title` 은 모든 게시판 머리가 나눠 쓰는 공통 규칙이라(`styles.ts:549`)
 * 제목 크기는 `:root` 에서 덮은 `--board-size-title`(운영 `--text-page` 값)이 맞춘다 —
 * 여기선 줄높이·여백만 남긴다.
 */
.tag-head .board-title {
  margin: 0.25rem 0;
  line-height: 1.25;
}

/* 운영은 눈썹 글(「태그」)에 여백이 없다 — 위아래 간격은 전부 h1 의 .25rem 이 만든다. */
.tag-head .board-eyebrow {
  margin: 0;
}

/* 운영은 span 이 inline 으로 제목 아랫줄에 흐른다(`[tag].vue:6`). block p 의 위 여백 7px 은 없다. */
.tag-head .board-subtitle {
  display: inline;
  margin: 0;
}

/*
 * 머리 카드와 목록 카드 사이. 운영에서 이 간격은 `.tag-head` 의 아래 여백이 아니라
 * `.stack` 격자의 .65rem(`global.scss:26`, `--gap-card` 는 `_tokens.scss:29`)이 만든다 —
 * 그래서 운영의 margin-bottom 은 0 이다. 이 마크업에는 스택이 없어 같은 .65rem 을
 * 부모 격자가 대신 낸다. `.board-content` 에는 태그 화면에서 머리와 목록 둘뿐이다.
 */
.board-content:has(> .tag-head) {
  display: grid;
  gap: 0.65rem;
}

.board-head.tag-head {
  margin-bottom: 0;
}

/*
 * 공개 프로필(`/profile/<id>`). 운영은 카드 한 장이고 우리는 카드 아래에 「쓴 글/댓글」
 * 탭과 글 목록이 더 있지만, 카드 모양과 기둥 폭(46rem 가운데)은 레거시다 —
 * `apps/frontend/app/pages/profile/[id].vue:45-47`(`below(sm)` = 560 포함). 탭·목록의
 * 모양은 스킨 그대로 두고 폭만 같은 기둥에 묶는다. 스킨 기본(skin-board
 * `styles.ts:1144-1168`)은 아바타 4rem 원형에 메타 줄이 전폭 행이라 칸·크기를 다시 정한다.
 */
.gb-profile,
.gb-profile-tabs,
.gb-profile-posts,
.gb-profile-comments {
  max-width: 46rem;
  margin-inline: auto;
}

/*
 * 레거시는 오른쪽 글줄을 div 하나에 묶어 위로 붙인다(7rem | 1fr, 사이 1.5rem). 우리 마크업엔 그 묶음이
 * 없어 격자로 두면 아바타가 걸친 행들이 아바타 높이만큼 늘어 글줄이 벌어진다(1fr 행을 둬도 크롬이
 * 여백 없이 잰 값으로 fr 을 잡아 20px 남짓 남는다). DOM 에서 h1 이 아바타보다 먼저라 float 도 제목
 * 아래로 밀린다. 그래서 글줄은 블록으로 쌓고 아바타는 왼쪽 안쪽 여백(2rem + 7rem + 1.5rem) 자리에
 * 절대 위치로 박는다 — 글이 짧아도 카드는 아바타 높이(7rem + 위아래 2rem)보다 줄지 않는다.
 */
.gb-profile {
  display: block;
  position: relative;
  min-height: 11rem;
  padding: 2rem 2rem 2rem 10.5rem;
}

/* 아바타는 7rem 네모 — 모서리는 레거시 `--radius-lg`(1rem), 글자는 `--text-page`.
 * 두 레거시 토큰 다리는 `.d2r` 안에만 있어 전역 이름으로 적는다. */
.gb-profile .gb-avatar {
  position: absolute;
  top: 2rem;
  left: 2rem;
  width: 7rem;
  height: 7rem;
  margin-right: 0;
  border-radius: 1rem;
  font-size: var(--board-size-title);
  font-weight: var(--board-weight-bold);
}

.gb-profile h1 {
  margin-top: 0.25rem;
  font-size: var(--board-size-title);
  line-height: 1.25;
}

/* 가입일·글 수 줄은 레거시 dl 모양 — 위 1rem, 항목 사이 .5rem 1.2rem, 메타 크기. */
.gb-profile ul.gb-meta {
  margin-top: 1rem;
  gap: 0.5rem 1.2rem;
  font-size: var(--board-size-meta);
}

/* 스킨이 항목마다 앞에 붙이는 「·」은 레거시에 없다. */
.gb-profile ul.gb-meta > li::before {
  content: none;
}

/* 소제목 — 레거시 `.eyebrow`. 밝을 때 accent-text 는 brand-600(#146c5a), 어두울 때는 읽히는 초록이다. */
.gb-profile::before {
  content: "노리터 회원";
  display: block;
  color: var(--board-accent-text);
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-bold);
  line-height: 1.6;
}

/* 운영은 로그인 아이디를 보이지 않는다 — 엔진 38370db6 이후 프로필이 @핸들을 아예 렌더하지
 * 않는다(아이디는 본인·운영자 계정 화면에만). identity 줄은 뱃지·정지 표시 때문에 남기되
 * 비었을 때 여백이 안 남게 위 여백을 지운다(왼쪽 여백은 위 규칙 것). */
.gb-profile .gb-identity {
  margin-top: 0;
}

/* 자기소개는 레거시 `.description` — 위 1rem, muted, 줄높이 1.7(pre-line 은 스킨 그대로). */
.gb-profile .gb-bio {
  margin-top: 1rem;
  color: var(--board-dim);
  line-height: 1.7;
}

/* 동작 줄은 레거시 nav — 링크 사이 .5rem 1rem. 위 여백 1.2rem 은 컨테이너가
 * 아니라 링크 쪽에 준다: 방문자에겐 링크가 전부 숨어 컨테이너가 0 이어야 한다.
 * 슬롯 감싸개(div.gb-slot… > div)는 contents 로 없애 링크가 flex 직접 항목이 되게 한다. */
.gb-profile-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1rem;
}

.gb-profile-actions > div {
  display: contents;
}

.gb-profile-actions a.gb-profile-edit-link,
.gb-profile-actions a.message-author {
  margin-top: 1.2rem;
  color: var(--board-accent-text);
  font-size: 1rem;
  font-weight: 600;
}

/*
 * 프로필 댓글 탭은 레거시 「내 댓글」(`me.vue` `.item-list`)의 한 줄 목록이다 — 글 제목이
 * 왼쪽에 먹색 굵게, 시간이 오른쪽에 메타 크기로, 다음 행에 댓글 본문 한 줄 말줄임.
 * 행 사이 선은 쓴 글 탭 목록과 같은 아래 선이다(아래 규칙).
 * 글 상세의 댓글 모양은 건드리지 않도록 `.gb-profile-comments` 안으로 좁힌다.
 */
.gb-profile-comments .gb-comment-list > li.gb-comment {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.25rem 1rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--board-line);
}

/* 행 사이 선은 쓴 글 탭 목록과 같은 아래 선 — 마지막 행은 뺀다. */
.gb-profile-comments .gb-comment-list > li.gb-comment:last-child {
  border-bottom: 0;
}

.gb-profile-comments .gb-comment-post {
  grid-column: 1;
  grid-row: 1;
  margin: 0;
}

.gb-profile-comments .gb-comment-post a {
  color: var(--board-text);
  font-weight: 600;
}

.gb-profile-comments .gb-comment .gb-meta {
  grid-column: 2;
  grid-row: 1;
  margin: 0;
  font-size: var(--board-size-meta);
  color: var(--board-dim);
}

/* 작성자는 이 페이지 주인이라 같은 이름·얼굴이 매 행 반복된다 — 쓴 글 탭도 스킨이
 * 작성자를 숨긴다(`.gb-profile-posts .gb-content-list .gb-author`). */
.gb-profile-comments .gb-comment .gb-meta .gb-author,
.gb-profile-comments .gb-comment .gb-meta .gb-avatar {
  display: none;
}

.gb-profile-comments .gb-comment .gb-body {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--board-dim);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  overflow: hidden;
}

.gb-profile-comments .gb-comment .gb-body > * {
  margin: 0;
}

.gb-profile-comments .gb-comment .gb-body img,
.gb-profile-comments .gb-comment .gb-body video,
.gb-profile-comments .gb-comment .gb-body iframe {
  display: none;
}

/* 반응·동작 줄과 첨부는 레거시 목록에 없다 — 글로 들어가면 있다. */
.gb-profile-comments .gb-comment .gb-reactions,
.gb-profile-comments .gb-comment .gb-actions,
.gb-profile-comments .gb-comment .gb-attachments {
  display: none;
}

@media (max-width: 35rem) {
  /* 한 칸 — DOM 은 h1 이 아바타보다 먼저라 세로 flex 로 세우고 아바타를 맨 앞으로 당긴다. */
  .gb-profile {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    padding: 1.25rem;
  }

  .gb-profile .gb-avatar {
    position: static;
    order: -1;
    align-self: flex-start;
    width: 5rem;
    height: 5rem;
  }

  /* 아바타 아래 24 — 소제목이 첫 글줄이 됐으니 제목이 아니라 소제목 위 여백이 낸다. */
  .gb-profile::before {
    margin-top: 1.5rem;
  }

  .gb-profile-comments .gb-comment-list > li.gb-comment {
    grid-template-columns: minmax(0, 1fr);
  }

  /* 한 칸에서는 시간이 맨 아래 행으로 내린다 — 제목 1행, 내용 2행(자동), 시간 3행. */
  .gb-profile-comments .gb-comment .gb-meta {
    grid-column: 1;
    grid-row: 3;
  }
}

/*
 * 글쓰기 폼 — 레거시 `PostForm.vue`·`AppInput.vue`·`AppSelect.vue`·`PostEditor.vue` 값.
 *
 * 폭: 레거시 폼 카드(AppSurface)는 컨테이너 전폭이라 스킨의 `max-width: 52rem`
 * (`skins/board/src/styles.ts:1252`)을 푼다 — 목록 카드와 같은 1180 내용폭이 된다.
 * 칸 사이 간격은 레거시 `.post-form { display: grid; gap: 1rem }`.
 */
.gb-content-form {
  max-width: none;
  gap: 1rem;
}

/*
 * label — 레거시는 `display: grid; gap: .4rem` 에 굵기만 bold 로 올리고 크기·색은 본문
 * (1rem/잉크)을 물려받는다. 스킨은 meta(0.875rem)·`--board-mid` 로 작고 흐리다.
 * checkbox 행 label 의 가로 방향은 스킨 규칙(`.gb-content-form label.gb-checkbox`)이 따로 잡는다.
 */
.gb-content-form label {
  gap: 0.4rem;
  font-size: var(--board-size-ui);
  color: var(--board-text);
}

/*
 * 「본문」 label 은 `for` 로 에디터를 가리켜 `.gb-editor` 와 형제로 선다(코어 `compose.tsx`).
 * label 아래 여백(테마 0.85rem)을 지우고, 폼 간격 1rem 과 레거시 간격 .4rem 의 차만큼
 * 에디터를 당겨 label-입력칸 간격을 .4rem 으로 맞춘다.
 */
.gb-content-form label[for] {
  margin-bottom: 0;
}

.gb-content-form label[for] + .gb-editor {
  margin-top: calc(0.4rem - 1rem);
}

/*
 * 입력칸·편집기 박스의 선·모서리·포커스는 스킨이 입력칸 토큰(--board-control-*·
 * --board-input-pad-x)과 이 사이트의 --board-focus-line/ring 으로 운영 값을 준다 —
 * 여기서 따로 두지 않는다. 본문 최소높이 18rem 도 엔진 값 그대로다.
 */

/*
 * 쪽지 화면(plugins/messaging `pages.tsx`). 플러그인이 본문에 `<style>` 을 심어 이 파일보다
 * 뒤에 서므로 같은 특이도면 그쪽이 이긴다 — 전부 `section.messages` 로 한 단계 세게 둔다.
 * 모양은 레거시 `me.vue` 의 `.tabs`·`.message-head`·`.item-list > .message`·`.compose-form`·
 * `.local-pagination` 과 `global.scss:31` 의 `.empty-state` 에서 왔다.
 */

/*
 * 탭 — 레거시 `.tabs`(me.vue:88): flex·간격 .35rem·가로 스크롤, 항목은 flex none·
 * padding .65rem .9rem·muted 글자·surface 면·1px line·999px 알약. 현재 탭은 흰 글자에
 * brand-600(`--board-accent`) 면·선. 카드와의 사이는 운영 `.stack` 간격 .65rem(global.scss:26).
 */
section.messages nav.boxes {
  flex-wrap: nowrap;
  gap: 0.35rem;
  margin: 0 0 0.65rem;
  padding-bottom: 0.2rem;
  overflow-x: auto;
}

section.messages nav.boxes a {
  flex: none;
  padding: 0.65rem 0.9rem;
  border: 1px solid var(--board-line);
  border-radius: 999px;
  background: var(--board-surface);
  color: var(--board-dim);
  font-weight: var(--board-weight-normal);
  text-decoration: none;
}

section.messages nav.boxes a[aria-current='page'] {
  border-color: var(--board-accent);
  background: var(--board-accent);
  color: var(--board-on-accent);
  font-weight: var(--board-weight-normal);
  text-decoration: none;
}

/*
 * 받은 쪽지 도구줄 — 레거시 `.message-head > div` 의 quiet 단추들이 오른쪽에 선다
 * (me.vue:25 `.message-head` justify-content: space-between 의 오른쪽 묶음). 단추 모양은
 * 마크업의 `.gb-btn`·`.gb-btn-quiet`·`.gb-danger` 와 스킨 단추 토큰이 준다.
 */
section.messages .toolbar {
  justify-content: flex-end;
  gap: 0.5rem;
  margin: 0 0 0.8rem;
  font-size: var(--board-size-ui);
}

section.messages .toolbar a[aria-pressed],
section.messages article.message .gb-actions > a {
  text-decoration: none;
}

/*
 * 눌린 「안 읽은 쪽지만」 — 운영의 눌린 반응 단추와 같은 값: brand-50 면·brand-600 선·
 * brand-700 글자(PostActions.vue:5 `.active`).
 */
section.messages .toolbar a[aria-pressed='true'],
section.messages .toolbar a[aria-pressed='true']:hover {
  border-color: var(--site-pressed-line);
  background: var(--board-brand-50);
  color: var(--board-brand-700);
}

/*
 * 행 — 레거시 `.item-list > .message`(me.vue:88): 위쪽 1px 선으로 갈린 행,
 * padding .85rem 0. 첫 행은 카드 윗선과 겹치지 않게 선이 없다. 첫 줄에 제목·「안 읽음」
 * 알약·오른쪽 시각, 둘째 줄에 보낸/받는 사람. 제목이 길면 줄임표로 줄어들어 시각을
 * 밀어내지 않는다(최소폭 0 + ellipsis).
 */
section.messages ul.gb-list > li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.35rem;
  padding: 0.85rem 0;
  border-bottom: 0;
  border-top: 1px solid var(--board-line);
}

section.messages ul.gb-list > li:first-child {
  border-top: 0;
}

section.messages ul.gb-list .subject {
  min-width: 0;
  overflow: hidden;
  color: var(--board-ink);
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

section.messages ul.gb-list .when {
  order: 1;
  flex: none;
  margin-left: auto;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
}

section.messages ul.gb-list .who {
  order: 2;
  flex-basis: 100%;
  color: var(--board-dim);
  font-size: var(--board-size-ui);
  opacity: 1;
}

/*
 * 상태 칸 — 받은 쪽지의 안 읽음은 레거시 `새 쪽지` 알약(me.vue:88 `.message i`:
 * padding .15rem .35rem·흰 글자·brand-600 면·999px·caption 크기)으로 제목 바로 뒤에 선다.
 * 받은 쪽지의 「읽음」은 운영이 그리지 않으므로 숨기고, 보낸 쪽지의 상태는 알약이 아니라
 * 작은 흐린 글자다.
 */
section.messages[data-view='inbox'] ul.gb-list .state.is-unread {
  flex: none;
  padding: 0.15rem 0.35rem;
  border-radius: 999px;
  background: var(--board-accent);
  color: var(--board-on-accent);
  font-size: var(--board-size-caption);
  font-weight: var(--board-weight-bold);
}

section.messages[data-view='inbox'] ul.gb-list .state.is-read {
  display: none;
}

section.messages[data-view='sent'] ul.gb-list .state {
  flex: none;
  color: var(--board-dim);
  font-size: var(--board-size-caption);
}

/*
 * 쪽번호 — 레거시 `.local-pagination`(me.vue:88): 가운데·간격 .7rem·margin-top 1rem,
 * 단추는 padding .45rem .7rem·잉크 글자·surface 면·1px line·radius-sm.
 */
section.messages .pager {
  justify-content: center;
  gap: 0.7rem;
  margin-top: 1rem;
}

section.messages .pager a {
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--board-line);
  border-radius: 0.4rem;
  background: var(--board-surface);
  color: var(--board-ink);
  text-decoration: none;
}

/*
 * 쪽지 쓰기 — 카드는 운영 모달 폭 40rem. 폼은 레거시 `.compose-form`(me.vue:88):
 * 격자 간격 .7rem, label 은 격자 간격 .35rem 에 굵은 글자. 입력칸 모양(선·모서리·패딩·
 * 포커스)은 스킨 입력칸 토큰과 --board-focus-line/ring 이 준다. textarea 는 최소높이 10rem.
 * 받는 사람이 정해져 있으면 input 대신 output 이 선다 — 같은 칸 모양으로.
 */
section.messages[data-view='compose'] .messages-body {
  max-width: 40rem;
}

section.messages form.compose {
  gap: 0.7rem;
}

section.messages form.compose label {
  display: grid;
  gap: 0.35rem;
  font-weight: var(--board-weight-bold);
}

section.messages form.compose input,
section.messages form.compose textarea {
  display: block;
  width: 100%;
}

section.messages form.compose output {
  display: block;
  width: 100%;
  min-height: var(--board-control-h);
  padding: var(--board-control-pad-y) var(--board-input-pad-x);
  border: 1px solid var(--board-line);
  border-radius: var(--board-control-radius);
  background: var(--board-surface);
  color: var(--board-text);
}

section.messages form.compose textarea {
  min-height: 10rem;
}

/* 「보내기」는 운영의 block 주 단추 — 폼 전체 폭. 채움은 스킨의 submit 규칙이 이미 준다. */
section.messages form.compose > button[type='submit'] {
  width: 100%;
}

/* 오류 글자 — 플러그인 기본 #b00020 대신 사이트 danger 토큰. */
section.messages .gb-error {
  color: var(--board-danger);
}

/*
 * 쪽지 보기 — 메타 줄은 흐린 글자, 본문은 운영 `.message-content`(me.vue:88)의
 * min-height 8rem·pre-wrap. 아래 동작 줄은 오른쪽 정렬 flex 한 줄: 목록·삭제는
 * quiet 단추 (삭제는 danger 글자 — 운영 모달의 danger 변형이 채운 단추였지만 새
 * 화면은 초록 채움이 아닌 것만 확정), 답장은 주 단추. `div.gb-actions` 안의 항목
 * 사이 공백 문자는 flex 에서 익명 항목이 되지 않으니 gap 만 적용된다.
 */

section.messages article.message > h2 {
  margin-top: 0;
}

section.messages article.message .gb-meta {
  gap: 1rem;
  color: var(--board-dim);
  font-size: var(--board-size-meta);
  opacity: 1;
}

section.messages article.message .gb-text {
  min-height: 8rem;
}

section.messages article.message .gb-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1rem;
}

/*
 * 폰(운영 tablet-narrow 이하, me.vue:89 `@include below(tablet-narrow)`) — 탭은 wrap,
 * 행은 한 줄 격자라 시각이 셋째 줄로 내려간다.
 */
@media (max-width: 47.99rem) {
  section.messages nav.boxes {
    flex-wrap: wrap;
    overflow-x: visible;
  }

  /*
   * 행은 한 줄 격자 — 운영도 `.message{grid-template-columns:1fr}` 이다. block 으로 돌리면
   * 제목이 여러 줄로 흐르고 「안 읽음」 알약이 제목 마지막 글자 뒤에 붙는다(운영은 strong 안의
   * inline i 다). 보낸/받는 사람과 시각이 그 아래 한 줄씩 선다.
   */
  section.messages ul.gb-list > li {
    display: block;
  }

  section.messages ul.gb-list .subject {
    display: inline;
    overflow: visible;
    white-space: normal;
  }

  section.messages ul.gb-list .state {
    display: inline-block;
  }

  section.messages ul.gb-list .who {
    display: block;
    margin-top: 0.25rem;
  }

  section.messages ul.gb-list .when {
    display: block;
    margin-left: 0;
  }
}

/* 소셜 로그인 버튼 — 레거시 `SocialLoginButtons.vue` 의 브랜드 색과 아이콘. 엔진은
   `<button class="provider provider-<id>">` 만 내니 색은 사이트 몫이다. 아이콘은 운영과 같은
   `apps/frontend/public/images/{naver,kakao}.svg` 를 `site/public/images/` 에 옮긴 것.
   색 규칙은 스킨의 `button[type="submit"]:not(.gb-link):not(.gb-reaction):not(.gb-danger)`(0,4,1)을
   이겨야 해서 같은 :not 사슬에 `.gb-providers` 를 얹어 0,5,1 로 올린다(d2r 단추 되돌림과 같은 수법). */
/* 소제목과 윗 구분선은 운영 `SocialLoginButtons.vue` 그대로다. 아랫선은 두지 않는다 — 뒤에 오는
   `.gb-auth > p:last-child`(링크 줄)이 스킨에서 이미 윗선을 그으니 겹쳐 두 줄이 된다. */
.gb-providers {
  margin-top: 20px;
  padding: 20px 0 0;
  border-top: 1px solid var(--gb-border);
  gap: 10px;
}
.gb-providers::before {
  content: "소셜 로그인";
  text-align: center;
  color: var(--gb-text-soft);
  font-size: var(--gb-size-s);
}
.gb-providers .gb-provider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  /* 스킨은 --board-radius(8px)를 주지만 같은 카드의 단추들은 --board-control-radius(6.4px)다. */
  border-radius: var(--board-control-radius);
}
.gb-providers .gb-provider::before {
  content: "";
  width: 24px;
  height: 24px;
  background: center / contain no-repeat;
}
.gb-providers button.gb-provider-naver:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  border-color: transparent;
  background: #03c75a;
  color: #fff;
}
.gb-providers .gb-provider-naver::before { background-image: url("/images/naver.svg"); }
.gb-providers button.gb-provider-naver:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover { background: #02b351; }
.gb-providers button.gb-provider-kakao:not(.gb-link):not(.gb-reaction):not(.gb-danger) {
  border-color: transparent;
  background: #fee500;
  color: #3c1e1e;
}
.gb-providers .gb-provider-kakao::before { background-image: url("/images/kakao.svg"); }
.gb-providers button.gb-provider-kakao:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover { background: #fdd835; }
