/* ============================================================================
 * Figma "공통 Component" 클래스 라이브러리 (2026-08-26)
 * ============================================================================
 * 출처: Figma 8qAqeXw50F8GKDGkeW0Pua, node 2058:222503("공통 Component") 산하
 * 16개 스펙 시트를 전수 조사(병렬 에이전트 조사, 사용자 확인 거침). 여기 담긴
 * 클래스는 화면 어디서든 재사용 가능한 "카탈로그" 클래스다 — 기존 화면별
 * BEM 클래스(.post-row, .page-hero__search 등)를 대체하지 않는다(사용자
 * 확인: "이름이 정확히 같을 때만 지우고 새로 만든다" — 개념이 같아도 이름이
 * 다르면 공존시킨다).
 *
 * GNB(사이드바)·Header/Footer·Popup(.mili-login-modal 등)·Alert(.notif-panel*)·
 * List Item(.post-row*)·Syllabus(.mili-learning-chapter-* )는 이번 조사에서
 * 값이 이미 정확히 일치하거나(대부분), Figma 레이어 이름 자체가 자동 생성
 * 프레임 번호뿐이라 새 클래스명을 지을 재료가 없어 제외했다 — 상세 근거는
 * 각 섹션 조사 기록 참고.
 * ============================================================================ */

/* ---------------------------------------------------------------------------
 * Typography — node 2051:217181(레이어명 "Color"로 잘못 붙었지만 실제 내용은
 * Typography 스펙 시트). H1~H4는 Bold(700)/SemiBold(600)/Medium(500) 3벌만
 * 존재하고 Regular(400)는 없다. B1~B3는 반대로 SemiBold(600)/Medium(500)/
 * Regular(400) 3벌만 있고 Bold(700)는 없다(2026-08-26 사용자 확인 — 실재하는
 * 굵기만 클래스화, 존재하지 않는 조합은 만들지 않는다).
 * -------------------------------------------------------------------------- */
.h1_b, .h1_s, .h1_m,
.h2_b, .h2_s, .h2_m,
.h3_b, .h3_s, .h3_m,
.h4_b, .h4_s, .h4_m,
.b1_s, .b1_m, .b1_r,
.b2_s, .b2_m, .b2_r,
.b3_s, .b3_m, .b3_r,
.caption_s, .caption_r {
    font-family: var(--mili-font-sans);
    letter-spacing: -0.02em;
}

.h1_b, .h1_s, .h1_m { font-size: 2.25rem; line-height: 3.15rem; }
.h1_b { font-weight: var(--mili-font-weight-bold); }
.h1_s { font-weight: var(--mili-font-weight-semibold); }
.h1_m { font-weight: var(--mili-font-weight-medium); }

.h2_b, .h2_s, .h2_m { font-size: 2rem; line-height: 2.8rem; }
.h2_b { font-weight: var(--mili-font-weight-bold); }
.h2_s { font-weight: var(--mili-font-weight-semibold); }
.h2_m { font-weight: var(--mili-font-weight-medium); }

.h3_b, .h3_s, .h3_m { font-size: 1.5rem; line-height: 2.1rem; letter-spacing: 0; }
.h3_b { font-weight: var(--mili-font-weight-bold); }
.h3_s { font-weight: var(--mili-font-weight-semibold); }
.h3_m { font-weight: var(--mili-font-weight-medium); }

.h4_b, .h4_s, .h4_m { font-size: 1.25rem; line-height: 1.75rem; letter-spacing: 0; }
.h4_b { font-weight: var(--mili-font-weight-bold); }
.h4_s { font-weight: var(--mili-font-weight-semibold); }
.h4_m { font-weight: var(--mili-font-weight-medium); }

.b1_s, .b1_m, .b1_r { font-size: 1.125rem; line-height: 1.575rem; letter-spacing: 0; }
.b1_s { font-weight: var(--mili-font-weight-semibold); }
.b1_m { font-weight: var(--mili-font-weight-medium); }
.b1_r { font-weight: var(--mili-font-weight-regular); }

.b2_s, .b2_m, .b2_r { font-size: 1rem; line-height: 1.6rem; letter-spacing: 0; }
.b2_s { font-weight: var(--mili-font-weight-semibold); }
.b2_m { font-weight: var(--mili-font-weight-medium); }
.b2_r { font-weight: var(--mili-font-weight-regular); }

.b3_s, .b3_m, .b3_r { font-size: 0.875rem; line-height: 1.1375rem; letter-spacing: 0; }
.b3_s { font-weight: var(--mili-font-weight-semibold); }
.b3_m { font-weight: var(--mili-font-weight-medium); }
.b3_r { font-weight: var(--mili-font-weight-regular); }

/* Caption 굵기 표기가 시안 내부에서도 이중(스크린샷 라벨 "Medium" vs 바인딩된
   실제 스타일 "Semibold")이라 재확인이 필요 — 일단 실제 바인딩값(Semibold)을
   따른다. 재확인되면 이 두 줄만 고치면 된다. */
.caption_s, .caption_r { font-size: 0.75rem; line-height: 0.975rem; letter-spacing: 0; }
.caption_s { font-weight: var(--mili-font-weight-semibold); }
.caption_r { font-weight: var(--mili-font-weight-regular); }

/* ---------------------------------------------------------------------------
 * Button — node 2042:215427. 색상은 전부 primitives.css 토큰과 정확히
 * 일치(리터럴 없음). Primary 변형은 다크/라이트가 배경·글자색이 반전되는데,
 * 홈 CTA 전용 토큰(--mili-btn-light/dark-*, variables.css)과 개념은 비슷하지만
 * 사용자 확인에 따라 이번 컴포넌트는 **독립된 값**으로 정의한다(공유하지 않음).
 * -------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--mili-space-1);
    border-radius: var(--mili-radius-button);
    border: 1px solid transparent;
    font-family: var(--mili-font-sans);
    font-weight: var(--mili-font-weight-medium);
    /* 2026-09-18 Figma 재실측(팝업/모달 버튼, Body/B3/Medium 스타일 메타) — 전역 버튼 자간
       -0.28px(사용자 확인, 사이트 전체 버튼에 적용). */
    letter-spacing: -0.28px;
    white-space: nowrap;
    cursor: pointer;
    /* 2026-08-27 — <a class="btn"> 가 밑줄 없이 나오도록 여기서 직접 끊는다. 예전엔 부트스트랩
       .btn 규칙에 얹혀 있었는데, 버튼 표준 일괄적용에서 그쪽 재테마를 걷어내며 이 카탈로그가
       부트스트랩 없이도 홀로 성립해야 하는 정본이 됐다. */
    text-decoration: none;
}

/* 2026-08-26 — 옛 Bootstrap 재테마(components.css, 삭제됨)가 다크 전용으로 갖고 있던
   .btn-outline-*:disabled 리터럴 보정을 일반화한다. 이 클래스 체계는 --bs-btn-* 변수를
   쓰지 않아 그 방식을 그대로 옮길 수 없어 variant 와 무관한 공용 규칙으로 대체했다. */
.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn.small {
    height: 28px;
    padding: 5px 9px;
    font-size: var(--mili-caption-size);
    line-height: var(--mili-caption-line);
    font-weight: var(--mili-font-weight-semibold);
}

/* 2026-08-26 재실측(Plugin API 직접 조회, node 1743:2583/2585) — padding
   12px/8px(가로/세로), font는 Small과 동일한 Caption/Semibold(12px/600/130%)
   다. Small(28px 높이)과 Medium(36px 높이)이 글자 스타일까지 똑같은 건
   Figma 스펙 자체의 특이점이지만, 실측값을 그대로 따른다. */
.btn.medium {
    height: 36px;
    padding: 8px 12px;
    font-size: var(--mili-caption-size);
    line-height: var(--mili-caption-line);
    font-weight: var(--mili-font-weight-semibold);
}

/* Large 텍스트 스타일 자체의 line-height(160%)가 --mili-body-b2-line(130%)과
   달라 리터럴로 둔다 — 버튼 전용 line-height 토큰을 새로 만들지는 사용자
   재확인 후 결정. */
.btn.large {
    height: 52px;
    padding: 12px 20px;
    font-size: var(--mili-body-b2-size);
    line-height: 1.6;
}

/* 2026-08-26 정정 — 기존 components.css의 .btn-outline-secondary(2026-08-25 보정, 다크는
   테두리·글자 공통 #BFC0C2 = --mili-neutral-550, 라이트는 테두리 --mili-neutral-550·글자
   --mili-neutral-800, 양쪽 다 배경 없음)와 값을 맞춘다. 다크 테두리를 -700 으로,
   라이트에 흰 배경을 넣은 건 근거 없는 값이었다. */
.btn.neutral {
    border-color: var(--mili-neutral-550);
    color: var(--mili-neutral-550);
    background: transparent;
}

.mili-light .btn.neutral {
    background: transparent;
    border-color: var(--mili-neutral-550);
    color: var(--mili-neutral-800);
}

/* hover 는 옛 .btn-outline-secondary 규칙(components.css, 삭제됨)에서 그대로 옮김 —
   대응 토큰이 없어 리터럴을 유지한다. */
.btn.neutral:hover {
    color: var(--mili-fg);
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.2);
}

.mili-light .btn.neutral:hover {
    color: var(--mili-text);
    background: var(--mili-surface-interactive);
    border-color: var(--mili-neutral-550);
}

/* 2026-08-26 정정 — 기존 components.css의 .btn-outline-primary(QA28, 다크는 border만
   Primary/700 #70AA0D 로 보정하고 글자는 --mili-brand 유지, 라이트는 --mili-brand 공유
   규칙 그대로)와 값을 맞춘다. --mili-brand 가 실제로 참조하는 스텝은 다크 Primary/500,
   라이트 Primary/600 이라 primitives 표기와 다크/라이트가 서로 다른 스텝이다 — 처음엔
   양쪽 다 -700 을 썼는데 라이트 실측이 어긋나 있었다. 배경도 기존처럼 투명 유지
   (라이트에 흰 배경을 넣은 건 근거 없는 추가였다). */
.btn.outline {
    border-color: var(--mili-primary-700);
    color: var(--mili-primary-500);
    background: transparent;
}

.mili-light .btn.outline {
    background: transparent;
    border-color: var(--mili-primary-600);
    color: var(--mili-primary-600);
}

/* hover 는 옛 .btn-outline-primary 규칙(components.css, 삭제됨)에서 그대로 옮김 — 다크·라이트
   공통(--mili-brand 는 테마별로 자동 스왑). */
.btn.outline:hover,
.mili-light .btn.outline:hover {
    background: var(--mili-brand);
    border-color: var(--mili-brand);
    color: var(--mili-brand-on);
}

/* Default — 다크(흰 배경/검정 글자) ↔ 라이트(검정 배경/흰 글자) 반전.
   2026-08-26 정정: 시안 State 헤더 라벨은 "Default"인데, 그 아래 실제 심볼 인스턴스 이름은
   "States=Primary"라 내부적으로 표기가 어긋나 있었다. 처음엔 심볼 이름을 그대로 따 .btn.primary로
   붙였으나, 사용자 확인(2026-08-26): "figma가 정본이긴 함. 그러나 figma엔 primary라는 버튼이 없음"
   — 사이트의 실제 주요 CTA(브랜드 그린, .btn-primary, QA21)와 이름이 겹쳐 혼동을 낳으므로 .default로
   바로잡는다. 홈 CTA 토큰과는 여전히 공유하지 않고 독립된 값이다. */
.btn.default {
    background: var(--mili-neutral-50);
    border-color: var(--mili-neutral-300);
    color: var(--mili-neutral-950);
}

.mili-light .btn.default {
    background: var(--mili-neutral-950);
    border-color: var(--mili-neutral-850);
    color: var(--mili-neutral-50);
}

/* hover·disabled 는 2026-08-27 버튼 표준 일괄적용 1단계에서 옛 `.btn-primary`
   (theme/components.css, 삭제됨)에서 그대로 옮겨 온 것이다 — 두 클래스의 기본 상태 값이
   픽셀 단위로 같았는데 상태 규칙만 옛 쪽에 있어서, 클래스를 통합하면서 함께 넘겼다.
   hover 는 한 단계 어두워지는 방향(다크 neutral-50→300, 라이트 neutral-950→850)이다. */
.btn.default:hover,
.btn.default:focus-visible {
    background: var(--mili-neutral-300);
    border-color: var(--mili-neutral-300);
    color: var(--mili-neutral-950);
}

.mili-light .btn.default:hover,
.mili-light .btn.default:focus-visible {
    background: var(--mili-neutral-850);
    border-color: var(--mili-neutral-850);
    color: var(--mili-neutral-50);
}

/* 채움 버튼은 공용 `.btn:disabled`(opacity .5)만으로는 다크에서 여전히 눌러 보인다 —
   흰 판이 반투명해질 뿐 밝은 덩어리로 남기 때문이다. 옛 `.btn-primary:disabled` 처럼
   판 자체를 죽인다(PBL·VOD 학습 화면의 이전/다음 끝, "학습 완료됨" 버튼이 이 상태를 쓴다). */
.btn.default:disabled {
    background: rgba(255, 255, 255, 0.04);
    border-color: rgba(255, 255, 255, 0.08);
    color: var(--mili-fg-faint);
    opacity: 1;
}

.mili-light .btn.default:disabled {
    background: rgba(var(--mili-fg-rgb), 0.06);
    border-color: rgba(var(--mili-fg-rgb), 0.12);
    color: var(--mili-fg-faint);
    opacity: 1;
}

/* 2026-08-26 정정 — 시안 실측은 #FF3939 단일값(--mili-status-error, primitives.css)이지만
   QA28(theme/components.css .btn-outline-danger 주석)에서 앱 전역 에러색 통일을 위해 이미
   --mili-error(다크 #FF8790/라이트 #BA3B45)를 쓰기로 확정했다. 클래스명만 전환하고 색은
   그 결정을 그대로 따른다(--mili-status-error로 바꾸지 않는다). */
.btn.error {
    border-color: var(--mili-error);
    color: var(--mili-error);
    background: transparent;
}

/* hover 는 옛 .btn-outline-danger 규칙(components.css, 삭제됨)에서 그대로 옮김 — 다크·라이트
   공통으로 채워지고 글자는 흰색(2026-08-25 다크 전용 보정을 라이트에도 함께 적용, 값 자체는
   그대로 유지). */
.btn.error:hover,
.mili-light .btn.error:hover {
    background: var(--mili-error);
    border-color: var(--mili-error);
    color: var(--mili-neutral-50);
}

.btn.text {
    border: none;
    background: none;
    padding: 12px 5px;
    color: var(--mili-neutral-100);
}

.mili-light .btn.text {
    color: var(--mili-neutral-800);
}

/* hover 는 옛 .btn-link 규칙(components.css, 삭제됨)에서 그대로 옮김 — 색은 그대로, 밑줄만 켠다. */
.btn.text:hover,
.btn.text:focus-visible {
    text-decoration: underline;
}

/* ---------------------------------------------------------------------------
 * Tag — node 2042:215476 (2026-08-28 전수 재실측).
 *
 * 시안은 한 이름 아래 성격이 다른 두 벌이다 — 섞어 쓰면 안 된다:
 *   콘텐츠 태그 (VOD/프로젝트/로드맵/URL) : 높이 32px · pl 6 / pr 10 / py 4 · SemiBold(600)
 *                                          · 테두리 1px · 그림자 · **유형색 원형 아이콘 배지 필수**
 *   상태 태그   (Neutral/Inverse/Accent)  : 높이 자유 · px 8 / py 4 · Medium(500)
 *                                          · 테두리 없음(라이트 Accent 만 예외) · 아이콘 없음
 *
 * 이전 판은 둘을 .tag 하나로 뭉뚱그리고 색만 분기해, 콘텐츠 태그의 굵기·높이·패딩·그림자·
 * 아이콘이 통째로 빠져 있었다. 색도 네 곳이 어긋나 있었다(아래 각 규칙 주석 참고).
 *
 * Level Badge(초급~전문가)는 같은 프레임에 있지만 .catalog-card__level-badge 로 이미
 * 정확히 구현돼 있어 여기서 다루지 않는다.
 * -------------------------------------------------------------------------- */
.tag {
    display: inline-flex;
    align-items: center;
    gap: var(--mili-space-1);
    padding: 0.25rem var(--mili-space-2);
    border-radius: var(--mili-radius-pill);
    border: 1px solid transparent;
    font-size: var(--mili-body-b3-size);
    line-height: 1.3;
    font-weight: var(--mili-font-weight-medium);
}

/* ⚠️ 2026-09-04 재정정(node 3542:125093 "TodayLearningBlock" 인기 학습 강좌, 사용자 지적):
   Tag 그림자는 실측 근거가 없었다 — 이 노드의 다크·라이트 Tag export 어디에도 drop-shadow
   클래스가 없다. 예전 다크 노드(2224:105209)의 drop-shadow-[2px_2px_10px_rgba(0,0,0,0.1)]를
   콘텐츠 태그 4종 공통값으로 잘못 일반화했던 것 — 걷어낸다. */
.tag:is(.vod, .pbl, .roadmap, .url) {
    height: 2rem; /* 32px */
    justify-content: center;
    padding: 0.25rem 0.625rem 0.25rem 0.375rem; /* 4 / 10 / 4 / 6 */
    font-weight: var(--mili-font-weight-semibold);
}

/* 콘텐츠 태그의 원형 아이콘 배지. 시안은 12px 아이콘 + 사방 4px = 20px 원이고, 원의 배경이
   유형색이다. 다크에서는 그 색이 글자색과 같아 currentColor 로 따라가고, 라이트에서는
   글자색보다 한 단 밝은 별도 색이라 아래에서 유형별로 덮는다.
   2026-08-27 에 mypage/learning.css 가 .learn-card__kind-icon 으로 이 배지를 먼저 구현하면서
   "공용 .tag 를 바꾸면 카탈로그·프로젝트 목록까지 바뀐다 — 사용자 확인 필요"로 남겨 뒀는데,
   표준 확인(2026-08-28)으로 여기 공용 규칙이 되었다. */
.tag__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: var(--mili-radius-pill);
    background: currentColor;
}

/* 2026-09-22 재실측(node 2042:215476 "Tag" 공용 컴포넌트 시트, get_design_context — Dark 행
   강의/프로젝트/로드맵/URL 4종 SVG 를 전부 다운받아 stroke 값 대조, 실제 화면 노드(강의 목록
   4038:312653·강의 상세 4038:312685 추천 카드 등)도 같은 아이콘 에셋으로 확인) — 다크에서
   원형 배지 위 아이콘 글리프는 흰색이 아니라 Neutral/900(#0e1013)이다. 2026-09-04 주석
   ("다크에서도 흰색 확인")은 당시 잘못 읽은 값이었다 — 그 라운드가 근거로 든 node 3249:63731
   자체가 라이트 전용 노드였는데 다크까지 같다고 오판했던 것으로 보인다. 라이트는 그 주석대로
   흰색(Neutral/50)이 맞다(이번 재실측에서도 동일 확인). */
.tag__icon > i,
.tag__icon > svg {
    font-size: 0.75rem; /* 12px */
    line-height: 1;
    color: var(--mili-neutral-900);
}

.mili-light .tag__icon > i,
.mili-light .tag__icon > svg {
    color: var(--mili-neutral-50);
}

/* SVG 아이콘(로드맵 태그의 lucide route 등)은 font-size 로 크기가 정해지지 않으므로 1em
   정사각형을 직접 준다 — 위 규칙의 font-size 를 그대로 따라가 <i> 아이콘과 같은 12px 이 된다.
   stroke="currentColor" 인 SVG 라 색은 위 color 를 상속한다(원형 배지 위 흰 선). */
.tag__icon > svg {
    width: 1em;
    height: 1em;
}

/* 콘텐츠 태그 배경·테두리는 4종이 같다. 다크 배경은 Neutral/870 이다 —
   이전 판의 --mili-neutral-850(#1c1f23)은 한 단 밝아 실측(#15181c)과 어긋났다. */
.tag:is(.vod, .pbl, .roadmap, .url) {
    background: var(--mili-neutral-870);
    border-color: var(--mili-neutral-800);
}

.mili-light .tag:is(.vod, .pbl, .roadmap, .url) {
    background: var(--mili-neutral-50);
    border-color: var(--mili-neutral-300);
}

/* 2026-09-22 재실측(node 2042:215476 "Tag" 공용 컴포넌트 시트 Dark/Light 행 + 실제 화면
   노드 4038:312653 강의 목록·4038:312685 강의 상세 추천 카드, get_design_context) — "강의"
   태그는 다크·라이트 둘 다 Green 계열이 아니라 Primary/500 그대로다(다크 #85f686·라이트
   #1a987f). 아이콘 배경은 currentColor 라 글자색을 따라간다. 이전 2026-08-28 라운드(node
   2723:87939)는 재설계 이전 구 노드 값(#2F871D)이었다 — 다크 쪽 green-500(#46d559)도 같은
   시기의 옛 값으로 추정된다(당시 다크 쪽은 별도 재실측 없이 추정치로 남아 있었다). */
.tag.vod {
    color: var(--mili-primary-500);
}

.mili-light .tag.vod {
    background: var(--mili-neutral-50);
    border-color: var(--mili-neutral-300);
    color: var(--mili-primary-500);
}

.mili-light .tag.vod .tag__icon {
    background: var(--mili-primary-500);
}

.tag.pbl {
    color: var(--mili-sky-500);
}

/* 시안 Sky/800 #166f9f ↔ 우리 --mili-sky-800 #217cac (팔레트 생성 오차 수준). */
.mili-light .tag.pbl {
    color: var(--mili-sky-800);
}

.mili-light .tag.pbl .tag__icon {
    background: var(--mili-sky-700);
}

.tag.roadmap {
    color: var(--mili-purple-400);
}

/* 2026-08-27 로드맵 목록 카드 배지 재실측(node 2769:97687) — 라이트 글자색이 Purple/600
   (#a323d9)이었다. 가장 가까운 기존 프리미티브 --mili-purple-600(#a628dc)으로 맞춘다. */
.mili-light .tag.roadmap {
    color: var(--mili-purple-600);
}

.mili-light .tag.roadmap .tag__icon {
    background: var(--mili-purple-500);
}

.tag.url {
    color: var(--mili-orange-400);
}

/* 시안 Orange/700 #b24e15 ↔ 우리 --mili-orange-700 #b9551d (팔레트 생성 오차 수준). */
.mili-light .tag.url {
    color: var(--mili-orange-700);
}

.mili-light .tag.url .tag__icon {
    background: var(--mili-orange-500);
}

/* ── 상태 태그 3종 — 아이콘 없음, 기본 패딩(px 8 / py 4)과 Medium 을 그대로 쓴다. ── */
.tag.neutral {
    background: var(--mili-neutral-750);
    color: var(--mili-neutral-50);
}

.mili-light .tag.neutral {
    background: var(--mili-neutral-300);
    color: var(--mili-neutral-950);
}

.tag.inverse {
    background: var(--mili-neutral-50);
    color: var(--mili-neutral-950);
}

.mili-light .tag.inverse {
    background: var(--mili-neutral-950);
    color: var(--mili-neutral-50);
}

.tag.accent {
    background: var(--mili-primary-900);
    color: var(--mili-primary-500);
}

.mili-light .tag.accent {
    background: var(--mili-primary-50);
    border-color: var(--mili-primary-300);
    color: var(--mili-neutral-950);
}

/* ---------------------------------------------------------------------------
 * Tab — node 2042:215373(2026-08-27 개정판 전수 반영). 서비스 전 화면의 탭은
 * 아래 두 벌이 정본이다.
 *
 *   .tab-line  Type 1 (Level 1) — 밑줄형. 다른 화면·다른 목록으로 가는 주 탭.
 *              (커뮤니티 게시판, 역량진단, 내 학습, 관심목록, 로드맵 구분, 레벨 필터)
 *   .tab-pill  Type 2 (Level 2) — 알약형. 같은 화면 안에서 범위를 좁히는 보조 탭.
 *              (분야 필터, 로드맵 콘텐츠 세부 유형)
 *
 * ⚠️ 개정 전(2026-08-12 QA node 1638:2738 "전체 탭을 밑줄로 통일")과 달라진 점 둘 —
 *   ① 활성 탭 글자색이 브랜드 라임이 <b>아니다</b>. 글자는 중성 최대대비(다크 흰색·
 *      라이트 검정)로 두고 브랜드는 밑줄에만 남긴다. 예전 .line-tabs__link--active 는
 *      글자까지 라임이었다.
 *   ② 알약 활성이 브랜드 틴트가 아니라 <b>명암 반전</b>이다(다크: 흰 알약 + 검은 글자,
 *      라이트: 검은 알약 + 흰 글자). 예전 .filter-chip--active 는 라임 틴트였다.
 *   두 규칙 다 "브랜드색은 활성 표시의 액센트일 뿐 글자를 물들이지 않는다"는 한 방향이다.
 *
 * 여기로 흡수돼 사라진 이름(theme/components.css 에서 제거): .line-tabs · .app-subtabs ·
 * .community-tabs · .level-filter__pill · .filter-chip / .filter-chips.
 * 학습 플레이어·작업 패널 <b>내부</b> 탭(.work-tabs__btn · .mili-learning-tool-tabs ·
 * .mili-learning-output-tabs)은 좁은 열 전용 축소형(13px·균등분할)이라 클래스와 치수는
 * 그대로 두고 색·굵기만 위 규칙에 맞췄다(2026-08-27 사용자 확인).
 * -------------------------------------------------------------------------- */

/* ----- Type 1 (Level 1) — 밑줄형 -----
   실측: 항목 높이 49px, 패딩 12/20/13px, B2(16px), 항목 간 gap 0.
   gap 이 0이어야 각 항목의 border-bottom 이 서로 붙어 밑줄 한 줄로 이어진다.
   좁은 화면에서는 가로 스크롤한다.

   높이를 min-height 로 못박는 이유: 시안의 텍스트 line-height 는 1.6(25.6px)인데 이
   저장소의 B2 토큰은 130%(20.8px)라 패딩만으로는 49px 가 안 나온다(46.8px). B2 토큰을
   건드리면 그걸 쓰는 다른 화면이 전부 흔들리므로 탭에서만 높이를 고정한다. */
/* 2026-09-18 QA(node 3931:115706, "카테고리 탭 스크롤 시 스크롤바 노출 → 미노출로 변경 필요")
   — .tab-pill--scroll 과 동일하게 스크롤 기능은 유지한 채 스크롤바만 숨긴다. */
.tab-line {
    display: flex;
    gap: 0;
    margin-bottom: var(--mili-space-3);
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
}

.tab-line::-webkit-scrollbar {
    display: none;
}

.tab-line__link {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    min-height: 3.0625rem;                 /* 49px */
    padding: 0.75rem 1.25rem 0.8125rem;    /* 12 / 20 / 13px */
    border: 0;
    border-bottom: 1px solid var(--mili-neutral-700);
    border-radius: var(--mili-radius-none);
    background: transparent;
    color: var(--mili-neutral-600);
    font-size: var(--mili-body-b2-size);
    font-weight: var(--mili-font-weight-regular);
    line-height: var(--mili-body-b2-line);
    white-space: nowrap;
    text-decoration: none;
    transition: border-color 160ms ease, color 160ms ease;
}

/* "가로로 꽉 차도록(Fill)" 수식자 — 역량진단 2탭(Figma QA node 3418:65483, 2026-08-31)에서
   시작해 강의/프로젝트/내 학습/로드맵 상세 탭까지 확장(2026-09-08, "탭 있으면 좌우 스크롤
   안 되고 꽉 차게" 사용자 요청). .tab-line 은 커뮤니티·VOD·PBL 등 다른 여러 화면이 공유하는
   전역 컴포넌트라 기본값(가로 스크롤)은 그대로 두고, 이 수식자를 붙인 화면만 항목이 폭을
   균등하게 채운다. white-space:normal 로 바꿔 긴 라벨은 말줄임(…) 대신 줄바꿈되게 한다 —
   2026-09-03 course-detail 에서 균등폭+nowrap 조합이 라벨을 잘라 되돌렸던 문제의 재발
   방지(2026-09-08 사용자 확인 후 fill 우선으로 재적용).

   2026-09-11 재확정(Figma QA node 2224:89232, 관심목록, 사용자 확인) — 2026-09-08 결정("PC/모바일
   구분 없이 항상 Fill")을 PC 폭에서는 뒤집는다: **데스크톱(≥768px)은 기본 .tab-line 동작(좌측
   정렬·자연폭·필요시 가로 스크롤)으로 되돌리고, 모바일(≤767.98px)만 이 Fill 균등폭을 유지**한다.
   이 클래스는 5개 화면이 공유한다 — 역량진단(common/_diagnosis-tabs.jsp), 내 로드맵
   (mypage/roadmap.jsp), 관심목록(mypage/wishlist.jsp), 내 학습(mypage/_learning-tabs.jsp),
   프로젝트 상세(pbl/project-detail.jsp). 전부 이 공용 규칙 하나로 함께 바뀐다(화면별 개별
   확인 없이 일괄 적용 — 사용자 확인, 2026-09-11). */
/* 2026-09-15 사용자 지적("강의 상세 탭 좌우 여백") — 지금까지는 Fill 이 부모 폭 안에서만
   균등폭을 줬을 뿐, 그 부모(.app-page)가 이미 --mili-page-padding 만큼 좌우 여백을 갖고
   있어 뷰포트 기준으로는 여전히 안쪽에 갇혀 있었다. VOD 상세(course-detail.css)가 먼저
   쓰던 음수 마진 기법(표지 .detail-hero 와 같은 패턴)을 이 공용 클래스에도 적용해, Fill 이
   붙은 탭바(5개 화면 전부)가 뷰포트 끝까지 실제로 채워지게 한다. 컨테이너에 되돌림 패딩을
   주지 않는다 — VOD 에서 패딩을 되돌렸다가 글자 위치가 그대로라 "안 바뀐 것처럼 보인다"는
   재지적을 받은 적이 있다(각 .tab-line__link 자체의 패딩만으로 안쪽 여백을 만든다). */
@media (max-width: 767.98px) {
    .tab-line--fill {
        margin-inline: calc(var(--mili-page-padding) * -1);
        overflow-x: hidden;
    }

    .tab-line--fill .tab-line__link {
        flex: 1 1 0;
        min-width: 0;
        white-space: normal;
        text-align: center;
    }
}

.tab-line__link:hover,
.tab-line__link:focus-visible {
    border-bottom-color: var(--mili-neutral-500);
    color: var(--mili-neutral-50);
}

.tab-line__link--active,
.tab-line__link--active:hover,
.tab-line__link--active:focus-visible {
    border-bottom-color: var(--mili-primary-500);
    color: var(--mili-neutral-50);
    font-weight: var(--mili-font-weight-semibold);
}

.mili-light .tab-line__link {
    border-bottom-color: var(--mili-neutral-500);
    color: var(--mili-neutral-700);
}

.mili-light .tab-line__link:hover,
.mili-light .tab-line__link:focus-visible {
    border-bottom-color: var(--mili-neutral-700);
    color: var(--mili-neutral-950);
}

/* 라이트 활성만 밑줄이 2px 다(시안 실측 — 다크는 1px). 늘어난 1px 은 padding-bottom 에서
   도로 빼 항목 높이가 비활성과 어긋나지 않게 한다. 브랜드색도 다크는 primary-500,
   라이트는 primary-700 로 갈린다(라이트 primary-500 #afe57e 는 흰 배경에서 너무 옅다). */
.mili-light .tab-line__link--active,
.mili-light .tab-line__link--active:hover,
.mili-light .tab-line__link--active:focus-visible {
    padding-bottom: 0.75rem;
    border-bottom: 2px solid var(--mili-primary-700);
    color: var(--mili-neutral-950);
}

/* 탭 줄 오른쪽에 정렬 드롭다운 같은 컨트롤이 붙는 화면(내 학습 · 강의/프로젝트 목록).
   탭은 왼쪽, 컨트롤은 오른쪽으로 밀고 좁은 폭에서는 줄을 바꾼다. */
.tabs-bar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--mili-space-3);
    margin-bottom: var(--mili-space-6);
}

.tabs-bar > .tab-line {
    margin-bottom: 0;
    min-width: 0;
}

/* ----- Type 2 (Level 2) — 알약형 -----
   실측: 패딩 12/15px, radius pill(9999px), B3(14px), 항목 간 gap 8px.
   시안의 줄은 한 줄 고정이지만 여기서는 flex-wrap 을 켠다 — 분야 필터처럼 항목이 10개를
   넘는 줄이 있어 한 줄로 두면 오른쪽이 잘려 보인다(2026-08-12 QA21 과 같은 사유). */
.tab-pill {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--mili-space-2);
    margin-bottom: var(--mili-space-4);
}

/* 분야 필터(_category-chips.jsp)만의 예외 — 2026-08-27 사용자 재지적으로 되돌림(Figma node
   2224:95762 실측): 분야 칩은 한 줄로 두고 넘치는 만큼 가로 스크롤한다. 위 flex-wrap:wrap 을
   켠 QA21 사유는 이 컴포넌트엔 적용하지 않는다 — 다른 .tab-pill 사용처(커뮤니티/마이페이지
   탭 등)는 계속 줄바꿈한다. */
/* 2026-09-11 사용자 지적 — 가로 스크롤바가 칩 아래쪽을 가려 잘려 보였다. 스크롤바 두께(윈도우
   기본 ~17px)가 padding-bottom 보다 커서 칩의 아래 모서리를 덮었던 것 — 시안에도 이 줄엔
   보이는 스크롤바가 없으므로, 스크롤 동작은 유지한 채 스크롤바만 시각적으로 숨긴다. */
.tab-pill--scroll {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
}

.tab-pill--scroll::-webkit-scrollbar {
    display: none;
}

.tab-pill--scroll .tab-pill__link {
    flex: 0 0 auto;
}

.tab-pill__link {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.375rem;
    padding: 0.75rem 0.9375rem;            /* 12 / 15px */
    border: 1px solid var(--mili-neutral-800);
    border-radius: var(--mili-radius-pill);
    background: var(--mili-neutral-900);
    color: var(--mili-neutral-400);
    font-size: var(--mili-body-b3-size);
    font-weight: var(--mili-font-weight-regular);
    line-height: var(--mili-body-b3-line);
    white-space: nowrap;
    text-decoration: none;
    transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease;
}

.tab-pill__link:hover,
.tab-pill__link:focus-visible {
    background: var(--mili-neutral-850);
}

/* 활성은 테두리가 사라지지만 border-width 를 0 으로 만들지 않는다 — 그러면 항목이 2px
   작아져 옆 항목과 높이가 어긋난다. 색만 투명으로 돌린다. */
.tab-pill__link--active,
.tab-pill__link--active:hover,
.tab-pill__link--active:focus-visible {
    border-color: transparent;
    background: var(--mili-neutral-50);
    color: var(--mili-neutral-950);
    font-weight: var(--mili-font-weight-semibold);
}

.mili-light .tab-pill__link {
    border-color: var(--mili-neutral-400);
    background: var(--mili-neutral-50);
    color: var(--mili-neutral-870);
}

.mili-light .tab-pill__link:hover,
.mili-light .tab-pill__link:focus-visible {
    background: var(--mili-neutral-100);
}

.mili-light .tab-pill__link--active,
.mili-light .tab-pill__link--active:hover,
.mili-light .tab-pill__link--active:focus-visible {
    border-color: transparent;
    background: var(--mili-neutral-950);
    color: var(--mili-neutral-50);
}

/* 알약 탭의 하위 줄(대분류를 고르면 그 아래에 세부 분야가 펼쳐진다 — _category-chips.jsp).
   시안에는 없는 변형이라 크기·들여쓰기로만 층을 구분하고 배색은 위 규칙 그대로 쓴다. */
.tab-pill--sub {
    margin-top: -0.5rem;
    padding-left: var(--mili-space-4);
    border-left: 2px solid var(--mili-neutral-800);
}

.mili-light .tab-pill--sub {
    border-left-color: var(--mili-neutral-400);
}

.tab-pill__link--sm {
    padding: 0.3125rem 0.75rem;
}

/* ----- 전역 hover 밝기 필터 무효화(두 유형 공통) -----
   reference.css 의 `.mili-app-transition :is(button, a, [role="button"], [role="tab"]):hover
   { filter: brightness(1.045) }` 가 탭에도 걸린다. 라이트에서 이게 치명적이다 —
     · 알약 탭 hover 배경 #f8f9fa 에 1.045 를 곱하면 기본 상태 #ffffff 로 도로 날아가
       hover 가 아예 보이지 않는다(2026-08-27 사용자 지적, /pbl 분야 필터에서 확인).
     · 마우스를 뗄 때 필터(a 규칙의 0.18s)와 배경색(아래 160ms)이 서로 다른 속도로 풀려
       그 사이 회색(#f8f9fa)이 한 번 번쩍인다 — "벗어날 때 깜박"의 정체다.
   탭은 배경색·글자색·밑줄로 이미 hover 를 표현하므로 밝기 필터는 걸지 않는다.
   reference.css 는 참고 이식본이라 손대지 않고 여기서 !important 로만 무효화한다
   (theme/components.css 의 .app-icon-btn·.roadmap-add__item 과 같은 처리). */
.mili-app-transition .tab-line__link:hover,
.mili-app-transition .tab-line__link:focus-visible,
.mili-app-transition .tab-pill__link:hover,
.mili-app-transition .tab-pill__link:focus-visible {
    filter: none !important;
}

/* ---------------------------------------------------------------------------
 * Pagination — node 2051:218398(2026-08-27 개정, 이전 리비전 2051:218395).
 * 기존 `.page-link`(Bootstrap 계열)와 개념은 겹치지만 이름이 다르므로 공존시킨다
 * (사용자 확인: 이름이 같을 때만 삭제).
 *
 * 2026-08-27 — 시안 개정으로 hover·active 가 라임 브랜드에서 중성 팔레트로 바뀌었다.
 *   기본    배경·테두리 없음 + --mili-pagination-fg  16px Regular
 *   hover   --mili-pagination-hover-bg 채움 + --mili-pagination-on
 *   활성    hover 와 같은 배경 + --mili-pagination-active-border 1px + 16px SemiBold
 * 값 자체는 theme/variables.css 의 --mili-pagination-* 가 테마별로 다 갖고 있어
 * .mili-light 오버라이드가 따로 필요 없다. 기하값(40×40·5px·16px)은 개정 전과 같다. */
.pagination-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* components.css 의 .page-link 와 같은 --mili-control-height-lg 를 쓴다 — 리터럴 40px 이
       우연히 같은 값이 아니라 같은 토큰에서 나오게 해 두 계층이 어긋날 여지를 없앤다(2026-09-02). */
    width: var(--mili-control-height-lg);
    height: var(--mili-control-height-lg);
    border-radius: var(--mili-radius-button);
    border: 1px solid transparent;
    font-size: var(--mili-body-b2-size);
    line-height: 1.6;
    font-weight: var(--mili-font-weight-regular);
    background: transparent;
    color: var(--mili-pagination-fg);
}

.pagination-btn:hover {
    background: var(--mili-pagination-hover-bg);
    color: var(--mili-pagination-on);
}

.pagination-btn.active {
    background: var(--mili-pagination-active-bg);
    border-color: var(--mili-pagination-active-border);
    color: var(--mili-pagination-on);
    font-weight: var(--mili-font-weight-semibold);
}

/* 2026-08-26 — 처음/이전/1~5/다음/끝(9개) 버튼이 40px 고정폭 그대로면 모바일(≤767px)에서
   한 줄에 다 안 들어가 마지막 버튼(끝, 더블 화살표)이 다음 줄로 밀린다(실측 확인, 390px에서
   재현). 시안은 이 좁은 폭을 다루지 않아 우리 판단으로 축소한다 — 값 자체(색·라운드 등)는
   그대로 두고 크기만 줄인다.

   ⚠️ 2026-08-27 — 이 규칙만으로는 안 먹는다. theme/components.css 의
   `.mili-theme-dark .page-link { min-width: 40px }` 가 (0,2,0)이고 그 파일이 이 파일보다
   나중에 로드돼 (0,1,0)인 여기를 이긴다 — 실제로 2026-08-26~27 내내 390px 에서 두 줄로
   밀려 있었다. 그래서 <b>실제로 먹는 축소는 components.css 쪽</b>에 있다(간격도 같이 줄인다).
   여기는 .page-link 가 아닌 곳에 .pagination-btn 만 쓰는 경우를 위해 남겨 둔다. */
@media (max-width: 767.98px) {
    .pagination-btn {
        width: var(--mili-control-height);
        height: var(--mili-control-height);
    }
}

/* ---------------------------------------------------------------------------
 * Search — node 2042:217006. 알약형 검색 필드(입력 왼쪽, 아이콘 오른쪽).
 * 예전 .page-hero__search*(common/_page-hero.jsp 공용, vod/course-list·
 * pbl/project-list·search/index 등 다수 화면)를 이 클래스로 흡수했다
 * (2026-08-26, Phase 4) — components.css 의 옛 규칙은 삭제.
 * -------------------------------------------------------------------------- */
.search-box {
    display: flex;
    align-items: center;
    gap: var(--mili-space-3);
    width: min(100%, var(--mili-search-field-width));
    height: var(--mili-search-field-height);
    padding-inline: var(--mili-space-4);
    border: 1px solid var(--mili-search-border);
    border-radius: var(--mili-radius-pill);
    background: var(--mili-search-bg);
}

.search-box:focus-within {
    border-color: var(--mili-brand-border);
}

.search-box__input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--mili-ink);
    font-size: var(--mili-text-md);
    caret-color: var(--mili-brand);
    outline: none;
}

.search-box__input::placeholder {
    color: var(--mili-search-placeholder);
}

/* 아이콘이 곧 제출 버튼이다(별도 "검색" 버튼을 두지 않는다). 아이콘 stroke 는
   다크 #F8F9FA(=--mili-ink 다크와 일치), 라이트 #0E1013(=--mili-neutral-900과
   일치, --mili-ink 라이트 #1E2227 는 근사치라 별도 오버라이드가 필요하다). */
.search-box__submit {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--mili-ink);
    font-size: var(--mili-body-b1-size);
    line-height: 1;
    cursor: pointer;
}

.mili-light .search-box__submit {
    color: var(--mili-neutral-900);
}

.search-box__submit:hover,
.search-box__submit:focus {
    color: var(--mili-brand);
}

/* 모바일 실측(Figma "모바일 공통_타이틀/설명/검색", node 2859:104694 다크·2859:109520 라이트,
   get_design_context) h-[44px] — 데스크톱 --mili-search-field-height(52px)보다 낮다. 다른 노드
   (3535:140296, docs/design/figma-common/19-search-mobile.md)도 같은 44px를 독립 실측해둔 값과
   일치한다(2026-09-03 사용자 확인, 반영). */
/* QA(Figma 8qAqeXw50F8GKDGkeW0Pua node 3533:102274, 2026-09-04) — LNB 검색창에서 16px 폰트가
   영역보다 커 placeholder 가 잘렸다. 실측(node I3533:107122;...;3535:140350)도 Pretendard
   Regular 14px 라 모바일 공용 규칙으로 반영한다(19-search-mobile.md 의 미반영 항목 해소). */
@media (max-width: 767.98px) {
    .search-box {
        height: 44px;
    }

    .search-box__input {
        font-size: var(--mili-text-sm);
    }
}
