/* 푸드테크 대시보드 스타일
 *
 * ┌─ 출처와 원칙 ────────────────────────────────────────────────────────────┐
 * │ 출처: HeejeongH/foodtech-dashboard 의 index.html <style> 블록.            │
 * │                                                                          │
 * │ **1·2·3부는 원본에서 값을 하나도 안 고치고 그대로 옮긴 것이다.**          │
 * │ 색·간격·반경·폰트를 눈대중으로 다시 지으면 개별 값은 그럴듯해도 합쳐진   │
 * │ 인상이 완전히 달라진다(실제로 한 번 그렇게 갈라졌다). 고치지 말 것.      │
 * │ 클래스 이름도 원본을 따른다 — 랩실이 원본 index.html 을 보며 Events·     │
 * │ Programs 섹션을 만들 때 이름이 맞아야 그대로 따라 쓸 수 있다.            │
 * │                                                                          │
 * │ 4부만 우리 것이다(원본에 짝이 없는 컴포넌트). 새 색을 만들지 않고        │
 * │ 원본 토큰(--danger-500 등)으로만 정의한다.                               │
 * └──────────────────────────────────────────────────────────────────────────┘
 *
 * 원본에는 테마가 두 겹 있다. 전역 :root + 범용 컴포넌트(1·2부)와
 * `.snu-hero-page` 스코프(3부)다. **대시보드 화면의 디자인은 3부**이고
 * 3부가 1부 토큰을 참조하므로 둘 다 필요하다. 한쪽만 가져오면 색이 안 맞는다.
 *
 * 가져오지 않은 원본 규칙: 도넛·캘린더·AI 챗·program-card·event-card·
 * breadcrumb·autocomplete — 이 화면에 없는 요소들이다. 필요해지면 원본에서 뜬다.
 */

/* ==========================================================================
 * 1부 — 원본 전역 토큰 (그대로)
 * ========================================================================== */

:root {
  /* ── WFT26 ConfEx 색상 팔레트 ── */
  --ink-025: rgba(154, 124, 194, 0.04);
  --ink-050: #f0f0f8;
  --ink-100: #ddddf0;
  --ink-200: #b8b8d8;
  --ink-300: #8888bb;
  --ink-500: #6666a0;
  --ink-600: #4a4a88;
  --ink-700: #2e2e6e;
  --ink-800: #1a1a50;
  --ink-900: #0b122c;
  --brand-500: #005cb9; /* WFTC 메인 블루 */
  --brand-600: #0050a3;
  --brand-700: #003d80;
  --accent-gold: #ffd338; /* WFT 골드 액센트 */
  --accent-purple: #9a7cc2; /* 퍼플 서브 */
  --accent-coral: #ff6d64; /* 버튼 코랄 */
  --success-500: #10b981;
  --success-700: #047857;
  --warn-500: #d97706;
  --warn-700: #a16207;
  --danger-500: #ef4444;
  --bg: #0e1535; /* 딥 다크 네이비 */
  --bg-card: #161d40; /* 카드 다크 */
  --bg-card-light: #1e2650;
  --shadow-card:
    0 2px 8px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
  --r-sm: 6px;
  --r-md: 10px;
  --s-xs: 4px;
  --s-sm: 8px;
  --s-md: 16px;
  --s-lg: 24px;
  --s-xl: 32px;
}

body {
  margin: 0;
  background: var(--bg);
  color: #e0e4f0;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", "Pretendard", "Noto Sans KR", sans-serif;
  font-size: 14px;
}

.t-body {
  font-size: 14px;
  color: #9090b8;
}
.t-small {
  font-size: 12px;
}
.t-micro {
  font-size: 11px;
  color: #7878a8;
  letter-spacing: 0.04em;
}

/* ==========================================================================
 * 2부 — 원본 범용 컴포넌트 (그대로)
 * ========================================================================== */

.data-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--bg-card);
  border-radius: var(--r-md, 8px);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  border: 1px solid rgba(154, 124, 194, 0.15);
}
.data-table th {
  text-align: left;
  padding: 12px 14px;
  background: rgba(154, 124, 194, 0.1);
  font-size: 12px;
  font-weight: 600;
  color: #9a7cc2;
  border-bottom: 1px solid rgba(154, 124, 194, 0.2);
  position: sticky;
  top: 0;
  z-index: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  /* T-030: 좁은 열에서 '장소'가 두 줄로 찢어졌다. 머리글은 한 덩어리로 —
     넘치면 .table-wrap 이 가로로 스크롤한다. */
  white-space: nowrap;
}
.data-table td {
  padding: 12px 14px;
  font-size: 13px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
  color: #c8cce8;
}
.data-table tr:hover td {
  background: rgba(154, 124, 194, 0.07);
}

/* T-030: 표 안의 사람 링크. 원본에는 이 자리가 없었다 — 원본은 행 전체가 라우터 링크였고
   우리는 표 안에서 사람만 따로 열기 때문이다. 브라우저 기본 파랑은 이 어두운 판에서
   읽히지 않아 잉크 색을 그대로 쓰고 밑줄로만 구분한다. */
.snu-link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(154, 124, 194, 0.6);
  cursor: pointer;
}
.snu-link:hover {
  color: #fff;
  text-decoration-color: var(--snu-gold);
}

.table-wrap {
  overflow-x: auto;
  border-radius: var(--r-md, 8px);
}

/* 폼 — 원본은 .filter-bar 와 .form-* 가 같은 입력 스타일을 공유한다.
 * (원본 125행 placeholder 색이 `#5555888` 8자리라 무효였다 → `#555588`. 유일한 수정.) */
.filter-bar {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.filter-bar input,
.filter-bar select,
.form-input,
.form-select,
.form-textarea {
  padding: 8px 12px;
  border: 1px solid rgba(154, 124, 194, 0.25);
  border-radius: var(--r-sm, 6px);
  font-size: 13px;
  background: #1e2650;
  color: #e0e4f0;
  font-family: inherit;
}
.filter-bar input::placeholder,
.form-input::placeholder {
  color: #555588;
}
.filter-bar input:focus,
.filter-bar select:focus,
.form-input:focus,
.form-select:focus {
  outline: none;
  border-color: #9a7cc2;
  box-shadow: 0 0 0 3px rgba(154, 124, 194, 0.15);
}
.filter-bar .count-badge {
  padding: 6px 12px;
  background: rgba(154, 124, 194, 0.15);
  border: 1px solid rgba(154, 124, 194, 0.25);
  border-radius: 999px;
  font-size: 12px;
  color: #9a7cc2;
  font-weight: 500;
}

.form-field label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: #9a7cc2;
  margin-bottom: 4px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.form-input,
.form-select,
.form-textarea {
  width: 100%;
  box-sizing: border-box;
}
.form-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 20px;
}
.form-hint {
  font-size: 11px;
  color: #7878a8;
  margin-top: 4px;
}

/* 등급 칩은 이걸 쓴다 — 다섯 등급에 다섯 변종이 1:1로 맞는다(4부 매핑 주석 참고) */
.status-pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  /* T-030: 좁은 표 열에서 '가입 완료'가 두 줄로 찢어졌다. 칩은 한 덩어리로 읽혀야 한다 —
     넘치면 줄을 접는 게 아니라 표가 가로로 스크롤되는 쪽이 맞다(.table-wrap). */
  white-space: nowrap;
}
.status-joined {
  background: rgba(16, 185, 129, 0.18);
  color: #34d399;
  border: 1px solid rgba(16, 185, 129, 0.25);
}
.status-none {
  background: rgba(255, 255, 255, 0.06);
  color: #8888bb;
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.status-pending {
  background: rgba(255, 211, 56, 0.15);
  color: #ffd338;
  border: 1px solid rgba(255, 211, 56, 0.25);
}
.status-scheduled {
  background: rgba(0, 92, 185, 0.2);
  color: #60a5fa;
  border: 1px solid rgba(0, 92, 185, 0.3);
}
.status-cancelled {
  background: rgba(239, 68, 68, 0.15);
  color: #f87171;
  border: 1px solid rgba(239, 68, 68, 0.2);
}

.empty-msg {
  padding: 40px;
  text-align: center;
  color: var(--ink-500);
  font-size: 14px;
  background: var(--bg-card);
  border-radius: var(--r-md, 8px);
  box-shadow: var(--shadow-card);
}
.empty-msg .cta {
  margin-top: 12px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: var(--r-sm, 6px);
  border: 1px solid rgba(154, 124, 194, 0.3);
  background: rgba(154, 124, 194, 0.1);
  color: #c8cce8;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s;
  font-family: inherit;
}
.btn:hover {
  background: rgba(154, 124, 194, 0.2);
}
.btn-primary {
  background: linear-gradient(90deg, #ff6d64 0%, #ffd338 100%);
  color: #0b122c;
  border-color: transparent;
  font-weight: 600;
}
.btn-primary:hover {
  filter: brightness(1.08);
}
.btn-ghost {
  border-color: rgba(255, 255, 255, 0.2);
  background: transparent;
  color: #c8cce8;
}

/* ==========================================================================
 * 3부 — 원본 `.snu-hero-page` 스코프 테마 (그대로)
 *
 * 이 화면의 디자인은 사실상 전부 여기다. 페이지 전체를 이 클래스로 감싸므로
 * --snu-* 변수가 모달까지 닿는다.
 * ========================================================================== */

.snu-hero-page {
  --snu-navy: #0b122c; /* 딥 다크 배경 */
  --snu-navy-2: #0e1535;
  --snu-navy-3: #080f24;
  --snu-gold: #ffd338; /* WFT 골드 */
  --snu-gold-soft: #ffe580;
  --snu-cream: #f0f0f8;
  --snu-ink: #e0e4f0;
  --snu-ink-2: #b8bce0;
  --snu-ink-3: #8888bb;
  --snu-line: rgba(154, 124, 194, 0.2);
  --snu-line-2: rgba(154, 124, 194, 0.12);
  --snu-surface: #0e1535;
  --snu-surface-2: #161d40;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", "Pretendard", "Noto Sans KR", sans-serif;
  color: var(--snu-ink);
  width: 100%;
}
.snu-hero-page * {
  box-sizing: border-box;
}

/* ---- Hero ---- */
.snu-hero {
  background:
    radial-gradient(ellipse 70% 50% at 80% 20%, rgba(154, 124, 194, 0.25), transparent 55%),
    radial-gradient(ellipse 50% 60% at 10% 80%, rgba(0, 92, 185, 0.2), transparent 55%),
    radial-gradient(ellipse 40% 40% at 90% 90%, rgba(255, 109, 100, 0.12), transparent 50%),
    linear-gradient(135deg, #080f24 0%, #0b122c 50%, #0d1540 100%);
  color: #fff;
  padding: 44px 40px 56px;
  position: relative;
  overflow: hidden;
}
.snu-hero::before {
  /* subtle grid pattern */
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 32px 32px;
  pointer-events: none;
}
.snu-hero-inner {
  position: relative;
  z-index: 1;
  max-width: 1240px;
  margin: 0 auto;
}
.snu-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #9a7cc2;
  margin-bottom: 20px;
}
.snu-eyebrow::before {
  content: "";
  width: 24px;
  height: 1px;
  background: #9a7cc2;
}
.snu-hero h1.snu-headline {
  margin: 0 0 12px;
  font-size: clamp(30px, 4vw, 46px);
  line-height: 1.12;
  font-weight: 700;
  letter-spacing: -0.02em;
  max-width: 720px;
  text-wrap: pretty;
}
.snu-hero h1.snu-headline .accent {
  color: var(--snu-gold-soft);
}
.snu-hero .snu-lead {
  font-size: 15px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.75);
  max-width: 620px;
  margin: 0 0 32px;
}

/* Hero pipeline: the star of the page */
.snu-pipeline {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  padding: 24px 28px 20px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.snu-pipeline-title {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: 16px;
  font-weight: 600;
}
.snu-pipeline-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}
.snu-stage {
  position: relative;
  padding: 6px 4px 4px 0;
}
.snu-stage-label {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: 6px;
  font-weight: 500;
}
.snu-stage-value {
  font-size: 30px;
  font-weight: 700;
  color: #fff;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.snu-stage-value .unit {
  font-size: 13px;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.55);
}
.snu-stage.final .snu-stage-value {
  color: var(--snu-gold-soft);
}

/* 단계 연결 화살표 — **원본에서 값 그대로 떴다** (2026-08-24, T-040).
 *
 * T-027 때는 일부러 안 가져왔다. 히어로에 넣은 넷(편·명·건·초)이 단위가 다르고 인과도 없어서
 * 화살표를 그리면 없는 관계를 그리는 거짓말이 되기 때문이었고, 그때 주석에
 * "깔때기 데이터가 생기면 원본에서 그 두 규칙을 그대로 뜨면 된다"고 적어뒀다.
 * 05 파이프라인(수집→분류→조립→발송)이 그 깔때기다 — 단계가 실제로 이어진다.
 *
 * ⚠️ **`.chained` 로 좁힌 것이 이 규칙의 유일한 변경이다.** 값은 원본 그대로다.
 * 히어로 카드도 같은 `.snu-stage` 를 쓰는데 거기 넷(구독자·편·열람률·클릭률)은 인과가 없다 —
 * 전역으로 넣었더니 `34명 → 1편 → — → —` 이 그려졌다. 스크린샷 검수에서 잡았다.
 *
 * **비율 막대(`.snu-stage-bar`)** 도 같은 이유로 안 가져왔었다 — 160건 수집 → 29건 저장까지는
 * 비율이 성립하지만 25통(수신자 수)은 기사 수가 아니라 사람 수라 한 축에 못 놓는다.
 * 2026-08-25(T-030) 히어로가 **원본의 '가입 파이프라인'으로 돌아오면서** 그 조건이 성립해
 * 원본에서 값 그대로 떠 왔다: 수강생 → 권유 → 신청 → 완료는 같은 사람들의 부분집합이다.
 * 05 파이프라인은 여전히 막대를 쓰지 않는다(`.chained` 만 붙인다). */
.snu-pipeline-row.chained .snu-stage + .snu-stage::before {
  content: "→";
  position: absolute;
  left: -14px;
  top: 18px;
  color: rgba(255, 255, 255, 0.28);
  font-size: 16px;
}

/* 비율 막대 — 원본 값 그대로 (T-030에서 되찾음). 마지막 칸이 골드인 것과 짝이다. */
.snu-stage-bar {
  margin-top: 10px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.1);
  overflow: hidden;
}
.snu-stage-bar > span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--snu-gold) 0%, var(--snu-gold-soft) 100%);
  border-radius: 2px;
  transition: width 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* CTAs under hero */
.snu-hero-ctas {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 24px;
}
.snu-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.12s, background 0.12s, border-color 0.12s;
  font-family: inherit;
}
.snu-btn-primary {
  background: linear-gradient(90deg, #ff6d64 0%, #ffd338 100%);
  color: #0b122c;
}
.snu-btn-primary:hover {
  filter: brightness(1.1);
  transform: translateY(-1px);
}
.snu-btn-ghost {
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.3);
}
.snu-btn-ghost:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.5);
}
.snu-btn-arrow::after {
  content: "→";
}

/* ---- Content sections below hero ---- */
.snu-content {
  max-width: 1240px;
  margin: 0 auto;
  padding: 56px 40px 48px;
  background: var(--snu-surface);
}
.snu-section {
  margin-bottom: 56px;
}
.snu-section:last-child {
  margin-bottom: 0;
}

.snu-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
}
.snu-section-title {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #e0e4f0;
  margin: 0;
}
.snu-section-title .num {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  color: #9a7cc2;
  margin-right: 12px;
  letter-spacing: 0.12em;
  vertical-align: middle;
  transform: translateY(-2px);
}
.snu-section-sub {
  font-size: 14px;
  color: var(--snu-ink-3);
  margin: 6px 0 0;
}
.snu-section-link {
  font-size: 13px;
  font-weight: 600;
  color: var(--snu-navy);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.snu-section-link:hover {
  color: var(--snu-gold);
}

/* Stat grid */
.snu-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0;
  border: 1px solid var(--snu-line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--snu-surface);
}
/* T-030: KPI가 다섯을 넘으면 원본의 minmax(220px) 로는 1440px 에서 5+1 로 접힌다.
   원본 값을 바꾸지 않고 변종을 둔다 — 네 칸 이하는 원본 그대로가 제일 보기 좋다. */
.snu-stat-grid.compact {
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}
.snu-stat-grid.compact .snu-stat {
  padding: 20px 22px;
}
.snu-stat-grid.compact .snu-stat-value {
  font-size: 28px;
}

.snu-stat {
  padding: 24px 28px;
  border-right: 1px solid var(--snu-line);
  cursor: pointer;
  transition: background 0.12s;
  position: relative;
}
.snu-stat:last-child {
  border-right: none;
}
.snu-stat:hover {
  background: var(--snu-surface-2);
}
.snu-stat-label {
  font-size: 12px;
  font-weight: 500;
  color: var(--snu-ink-3);
  letter-spacing: 0.04em;
  margin-bottom: 8px;
}
.snu-stat-value {
  font-size: 34px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--snu-ink);
}
/* T-030: 밝은 판 위의 KPI 단위. 히어로의 `.snu-stage-value .unit` 은 네이비 배경 전용이라
   (흰 글자 55% 투명) 여기서 쓰면 안 보인다 — 같은 크기·굵기로 잉크 색만 바꾼다. */
.snu-stat-value .unit {
  font-size: 13px;
  font-weight: 400;
  color: var(--snu-ink-3);
  margin-left: 4px;
}
.snu-stat-sub {
  font-size: 12px;
  color: var(--snu-ink-3);
  margin-top: 8px;
}
@media (max-width: 700px) {
  .snu-stat {
    border-right: none;
    border-bottom: 1px solid var(--snu-line);
  }
  .snu-stat:last-child {
    border-bottom: none;
  }
}

/* Events section: 2-column layout */
.snu-events-layout {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 24px;
}
@media (max-width: 900px) {
  .snu-events-layout {
    grid-template-columns: 1fr;
  }
}

.snu-top-presenters {
  background: var(--snu-navy);
  color: #fff;
  border-radius: 12px;
  padding: 24px 26px;
  position: relative;
  overflow: hidden;
}
.snu-top-presenters::before {
  content: "";
  position: absolute;
  top: -30%;
  right: -20%;
  width: 180px;
  height: 180px;
  background: radial-gradient(circle, rgba(212, 160, 23, 0.18) 0%, transparent 70%);
  pointer-events: none;
}
.snu-top-title {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--snu-gold-soft);
  margin: 0 0 18px;
  font-weight: 600;
  position: relative;
}
.snu-presenter {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  cursor: pointer;
  position: relative;
  transition: transform 0.12s;
}
.snu-presenter:last-child {
  border-bottom: none;
}
.snu-presenter:hover {
  transform: translateX(2px);
}
.snu-presenter .rank {
  font-size: 12px;
  font-weight: 700;
  color: var(--snu-gold-soft);
  font-variant-numeric: tabular-nums;
  opacity: 0.8;
}
.snu-presenter .info .name {
  font-size: 14px;
  font-weight: 600;
}
.snu-presenter .info .org {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.55);
  margin-top: 2px;
}
.snu-presenter .count {
  font-size: 13px;
  font-weight: 700;
  color: var(--snu-gold-soft);
  font-variant-numeric: tabular-nums;
}
.snu-presenter .count .u {
  font-size: 10px;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.55);
  margin-left: 2px;
}

/* Two-column detail row */
.snu-detail-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}
@media (max-width: 900px) {
  .snu-detail-row {
    grid-template-columns: 1fr;
  }
}

.snu-panel {
  background: var(--snu-surface);
  border: 1px solid var(--snu-line);
  border-radius: 12px;
  padding: 24px 26px;
}
.snu-panel-title {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--snu-ink-3);
  margin: 0 0 18px;
  font-weight: 600;
}

.snu-modal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}
.snu-modal-head h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
}
.snu-modal-close {
  background: none;
  border: none;
  color: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.6;
  padding: 4px;
}
.snu-modal-close:hover {
  opacity: 1;
}

.snu-hbar-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
  font-size: 13px;
}
.snu-hbar-row .lbl {
  width: 100px;
  flex-shrink: 0;
  color: var(--snu-ink-3);
}
.snu-hbar-row .bar {
  flex: 1;
  height: 8px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 4px;
  overflow: hidden;
}
.snu-hbar-row .bar > span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--brand-500), var(--accent-gold));
  border-radius: 4px;
}
.snu-hbar-row .n {
  width: 28px;
  text-align: right;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: no-preference) {
  .snu-hero-inner > * {
    animation: snu-fade-in 0.5s ease both;
  }
  .snu-hero .snu-eyebrow {
    animation-delay: 0.04s;
  }
  .snu-hero h1 {
    animation-delay: 0.12s;
  }
  .snu-hero .snu-lead {
    animation-delay: 0.18s;
  }
  .snu-pipeline {
    animation-delay: 0.24s;
  }
  .snu-hero-ctas {
    animation-delay: 0.32s;
  }
  @keyframes snu-fade-in {
    from {
      opacity: 0;
      transform: translateY(6px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

/* 팝오버 — 머리·닫기·본문·액션의 시각 언어는 원본 그대로다.
 * **폭과 위치만 4부에서 덮는다**: 원본 .snu-popover 는 width:min(440px,…) 짜리
 * 앵커 팝오버라 6열 회원 표가 안 들어간다. 우리는 중앙 정렬 다이얼로그로 쓴다. */
.snu-popover-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(3, 20, 40, 0.35);
  z-index: 900;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.snu-popover {
  background: var(--snu-surface);
  border-radius: 14px;
  box-shadow: 0 24px 56px rgba(0, 20, 40, 0.25);
  overflow: hidden;
}
.snu-popover-header {
  background: linear-gradient(135deg, var(--snu-navy) 0%, var(--snu-navy-2) 100%);
  color: #fff;
  padding: 20px 24px 16px;
  position: relative;
}
.snu-popover-header h3 {
  margin: 0 0 6px;
  font-size: 18px;
  font-weight: 700;
  line-height: 1.3;
}
.snu-popover-header .meta {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.72);
  font-variant-numeric: tabular-nums;
}
.snu-popover-close {
  position: absolute;
  top: 12px;
  right: 12px;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s;
}
.snu-popover-close:hover {
  background: rgba(255, 255, 255, 0.22);
}
.snu-popover-body {
  padding: 18px 24px 22px;
}
.snu-popover-actions {
  display: flex;
  gap: 10px;
  padding: 12px 24px 20px;
  justify-content: flex-end;
  background: var(--snu-surface-2);
  border-top: 1px solid var(--snu-line);
}

/* ==========================================================================
 * 4부 — 우리 것 (원본에 짝이 없는 컴포넌트)
 *
 * 여기서도 **새 색을 만들지 않는다** — 1·3부 토큰만 쓴다. 하드코딩한 색이 늘면
 * 나중에 테마를 못 바꾼다. 원본에 짝이 생기면 이 블록에서 지우고 위로 옮긴다.
 *
 * 등급 칩 매핑(dashboard.js 의 tierChip): 원본 .status-* 를 그대로 쓴다.
 *   active → .status-joined(초록) / warm → .status-pending(골드)
 *   dormant → .status-none(회색) / unknown → .status-scheduled(파랑, 판단 보류)
 *   unsubscribed → .status-cancelled(빨강)
 * ========================================================================== */

/* 히어로 숫자 줄 (T-067). 원본 '가입 파이프라인' 깔때기를 대신한다.
 *
 * 깔때기(.snu-pipeline)는 지우지 않았다 — **05 파이프라인이 같은 클래스를 쓴다.**
 * 화면에서만 내렸다.
 *
 * 새 색을 만들지 않는다. 숫자는 히어로 본문색, 단위·라벨은 흐린 값을 쓴다. */
.snu-hero-totals {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 36px;
  align-items: baseline;
  margin-top: 4px;
}
.snu-total b {
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.02em;
}
.snu-total .unit {
  font-size: 15px;
  font-weight: 600;
  margin-left: 3px;
  color: rgba(255, 255, 255, 0.65);
}
/* 라벨은 숫자 뒤에 붙는다 — 위에 얹으면 세 덩어리가 각자 두 줄이 되어 히어로가 길어진다. */
.snu-total .lbl {
  font-size: 13px;
  margin-left: 8px;
  color: rgba(255, 255, 255, 0.55);
}
@media (max-width: 700px) {
  .snu-hero-totals {
    gap: 6px 22px;
  }
  .snu-total b {
    font-size: 26px;
  }
}

/* 히어로의 '오늘 편' 한 줄 (T-064).
 *
 * 원본 히어로에는 없는 물건이라 4부다. **새 색을 만들지 않는다** — 상태 칩은 원본
 * .status-* 를 그대로 쓰고(dashboard.js 의 TODAY_PILL), 판은 옆의 .snu-pipeline 과
 * 같은 유리판 값을 쓴다. 히어로 안에서 두 판이 다른 재질이면 하나가 이물질로 보인다.
 *
 * 손봐야 할 때만 골드 테두리가 붙는다(.needs-you) — 늘 강조하면 강조가 아니다. */
.snu-today {
  margin-top: 14px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  padding: 14px 18px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.snu-today.needs-you {
  border-color: var(--snu-gold);
  background: rgba(255, 211, 56, 0.08);
}
.snu-today-label {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  font-weight: 600;
  white-space: nowrap;
}
/* 제목이 길어도 한 줄을 밀어내지 않는다 — 밀리면 버튼이 다음 줄로 떨어진다. */
.snu-today-subject {
  flex: 1 1 240px;
  min-width: 0;
  font-weight: 600;
  color: var(--snu-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.snu-today-note {
  font-size: 12.5px;
  color: var(--snu-ink-3);
  white-space: nowrap;
}
/* 폰에서는 한 줄에 다 안 들어간다. 제목을 통째로 내려 접는다. */
@media (max-width: 700px) {
  .snu-today-subject {
    flex-basis: 100%;
    white-space: normal;
  }
  .snu-today-note {
    white-space: normal;
  }
}

/* 팝오버를 중앙 정렬 다이얼로그로 쓰기 위한 덮어쓰기 (위 주석 참고) */
.snu-popover-backdrop {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 5vh 16px;
  overflow-y: auto;
}
.snu-popover {
  width: min(1000px, 100%);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
}
.snu-popover-body {
  overflow-y: auto;
}

/* 인라인 알림. 원본 .toast 와는 다른 물건이다 — 원본은 우하단에 떠서 사라지는
 * position:fixed 토스트고, 이건 모달 본문 맨 위에 남는 배너다. 이름을 겹치게 두면
 * 원본 규칙이 덮어써서 안내가 통째로 안 보인다(실제로 그럴 뻔했다). */
.alert {
  margin-bottom: var(--s-md);
  padding: 10px 14px;
  border-radius: var(--r-sm);
  font-size: 13px;
  border: 1px solid var(--snu-line);
  background: var(--snu-surface-2);
}
.alert-ok {
  color: var(--success-500);
  border-color: rgba(16, 185, 129, 0.45);
}
.alert-bad {
  color: var(--danger-500);
  border-color: rgba(239, 68, 68, 0.45);
}
/* 판정이 갈렸다 (T-060) — 위험도 통과도 아닌 '혼자 믿지 마라'. 원본 토큰 --warn-500. */
.alert-warn {
  color: var(--warn-700);
  border-color: rgba(217, 119, 6, 0.45);
}

/* 히어로 카드 각 칸의 집계 범위. 구독자는 전체 3,400여 명이고 참여율은 파일럿
 * 25명 기준이다 — 범위 없이 나란히 놓으면 거짓말이 된다(T-027에서 나온 결론). */
/* 표 안의 링크 (T-041) — **원본엔 이 규칙이 없다.** 원본 표는 링크 대신 `tr.row-clickable`
 * 로 행 전체를 누르게 해서 `<a>` 가 등장하지 않기 때문이다. 우리 뉴스 표는 제목이 원문으로
 * 나가는 링크라 색이 필요하다. 안 주면 브라우저 기본 파랑이 깔려 **남색 배경에서 안 보인다**
 * (스크린샷 검수에서 잡았다). 토큰은 `.foot a` 가 쓰는 것과 같은 걸 쓴다.
 */
.data-table a {
  color: var(--snu-ink-2);
  text-decoration: none;
  border-bottom: 1px solid rgba(184, 188, 224, 0.25);
}
.data-table a:hover {
  color: var(--snu-gold-soft);
  border-bottom-color: var(--snu-gold-soft);
}

/* 파이프라인 신호등 (T-040) — 원본에 짝이 없는 우리 컴포넌트.
 * 색은 **원본 토큰만 쓴다**: 성공/경고/위험은 1부의 --success-500/--warn-500/--danger-500.
 * '모름'은 새 색을 만들지 않고 회색조로 둔다 — 측정 안 된 것을 초록으로도 빨강으로도
 * 보이게 하면 안 된다. */
.pipe-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: 1px;
  background: rgba(255, 255, 255, 0.28);
}
.pipe-dot.ok {
  background: var(--success-500);
}
.pipe-dot.warn {
  background: var(--warn-500);
}
.pipe-dot.bad {
  background: var(--danger-500);
}
.snu-stage-value.unknown {
  color: rgba(255, 255, 255, 0.4);
  font-size: 15px;
}

.snu-stage-note {
  font-size: 10.5px;
  color: rgba(255, 255, 255, 0.45);
  margin-top: 6px;
  line-height: 1.45;
}

/* 아직 아무도 안 만든 섹션. 형태를 Newsletter 와 같게 두어 무엇이 들어올 자리인지 보이게 한다. */
.placeholder {
  border: 1px dashed var(--snu-line);
  border-radius: 12px;
  padding: 40px 24px;
  text-align: center;
  color: var(--snu-ink-3);
}
.placeholder .who {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 700;
  border: 1px dashed var(--snu-line);
  border-radius: 999px;
  padding: 4px 12px;
  margin-bottom: 12px;
}
/* 우리가 곧 채우는 자리. 남이 채울 자리와 형태로 구분한다 — 페이지만 봐도 계획이 읽힌다. */
.placeholder.next {
  border-color: var(--snu-gold);
  background: rgba(255, 211, 56, 0.06);
  color: var(--snu-ink-2);
}
.placeholder.next .who {
  border-style: solid;
  border-color: var(--snu-gold);
  color: var(--snu-gold);
}
/* 힌트는 공백 없는 긴 파일 경로다 — 좁은 화면에서 안 쪼개지면 페이지를 옆으로 민다. */
.placeholder .hint {
  font-size: 11.5px;
  color: var(--snu-ink-3);
  margin-top: 10px;
  opacity: 0.85;
  overflow-wrap: anywhere;
}

.state {
  padding: 28px 24px;
  text-align: center;
  color: var(--snu-ink-3);
  font-size: 13.5px;
}
.state.error {
  color: var(--danger-500);
}

/* 로딩 중임을 형태로도 알린다 — 숫자 자리가 비어 있는 것과 구분되어야 한다 */
.skeleton {
  height: 8px;
  border-radius: 4px;
  background: var(--snu-surface-2);
  animation: pulse 1.4s ease-in-out infinite;
  margin-bottom: var(--s-sm);
}
@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}

/* 개발 모드 배너 — 인증이 꺼진 상태를 화면에서 숨기지 않는다 */
.dev-banner {
  background: var(--warn-500);
  color: #221500;
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  padding: 9px 16px;
  line-height: 1.5;
}
/* 스위치로 끈 경우(T-052)는 **운영에서도 열려 있는** 상태라 개발 모드보다 위험하다.
 * 주황(경고)과 빨강(위험)을 구분한다 — 같은 색이면 둘 다 안 읽힌다. */
.dev-banner-danger {
  background: var(--danger-500);
  color: #fff;
}
.dev-banner-danger code {
  background: rgba(255, 255, 255, 0.18);
  padding: 1px 5px;
  border-radius: 4px;
}

/* 모달 안 컨트롤 한 줄 */
.row {
  display: flex;
  gap: var(--s-sm);
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: var(--s-md);
}

/* 순위 목록의 등급 칩 — 이름과 같은 줄에 붙는다(dashboard.js 주석 참고). */
.snu-presenter .name .status-pill {
  margin-left: 8px;
  vertical-align: 1px;
  font-weight: 500;
}

/* 순위 목록을 옆 판들의 글자 크기·행 리듬에 맞춘다.
 *
 * 원본 값은 이름 14px/600 · 행 43px 인데, 옆 `.snu-panel` 의 막대 행은 13px/400 · 29px 다.
 * 원본에서 이 카드는 15px 짜리 행사 목록(`.snu-event-name`) 옆에 있었으니 그쪽에선 맞았지만,
 * 우리는 막대 판 셋과 나란히 두기 때문에 1px 차이가 굵기·대비와 겹쳐 "글씨가 훨씬 크다"로 읽힌다.
 *
 * 크기와 행 높이만 맞추고 **색과 굵기는 건드리지 않는다** — 이 카드는 화면의 초점이라
 * 네이비+골드로 도드라지는 게 맞다. 없애야 할 건 크기 차이지 존재감이 아니다.
 * (3부 원본 규칙은 그대로 두고 여기서 덮는다.) */
.snu-presenter .info .name {
  font-size: 13px;
}
.snu-presenter {
  padding: 7px 0;
}

/* 판 안의 마지막 줄은 아래 여백을 지운다 — 판 자체 패딩과 겹쳐 빈 띠가 생긴다. */
.snu-panel .row:last-child {
  margin-bottom: 0;
}

/* 원본 .btn 은 <button> 기준이라 링크로 쓸 때 밑줄이 남는다(발송 검토의 [미리보기]가 그랬다). */
a.btn,
a.snu-btn {
  text-decoration: none;
}

/* 원본 .form-input/.form-select 는 `width:100%`(세로로 쌓는 .form-grid 용)다.
 * 우리 .row 는 가로로 늘어놓는 줄이라 그대로 두면 입력 하나가 줄을 다 차지하고
 * 나머지가 아래로 밀린다. 이 줄 안에서만 auto 로 되돌린다. */
.row .form-input,
.row .form-select {
  width: auto;
}

/* 원본 .data-table 은 `width:100%` 라서 좁은 화면에서 칸이 짜부라지고 .table-wrap 의
 * 가로 스크롤이 아예 발동하지 않는다 — 기존 관리자 표가 그래서 모바일에서 못 쓸
 * 상태였다(T-027 Verification 2). min-width 를 얹어 스크롤이 살아나게 한다. */
.table-wrap .data-table {
  min-width: 620px;
}

.btn-sm {
  font-size: 12px;
  padding: 5px 11px;
}
.btn-danger {
  color: #f87171;
  border-color: rgba(239, 68, 68, 0.45);
  background: rgba(239, 68, 68, 0.1);
}
.btn-danger:hover {
  background: rgba(239, 68, 68, 0.2);
}
.btn-on {
  color: #34d399;
  border-color: rgba(16, 185, 129, 0.45);
  background: rgba(16, 185, 129, 0.1);
}
.btn-on:hover {
  background: rgba(16, 185, 129, 0.2);
}
/* 명단엔 있는데 수신거부라 실제로는 안 나가는 상태 — 초록(정상)과 구분해야 한다 */
.btn-warn {
  color: var(--accent-gold);
  border-color: rgba(255, 211, 56, 0.45);
  background: rgba(255, 211, 56, 0.1);
}
.btn-warn:hover {
  background: rgba(255, 211, 56, 0.2);
}
/* 잠긴 버튼 — 작업 중이거나(중복 실행 방지) 조건이 안 맞아 못 누르는 상태.
 * 어느 쪽이든 "지금은 안 된다"가 맞는 뜻이라 not-allowed 로 통일한다. */
.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-md);
  margin-top: var(--s-md);
  font-size: 13px;
  color: var(--snu-ink-3);
}

.foot {
  max-width: 1240px;
  margin: 0 auto;
  border-top: 1px solid var(--snu-line);
  padding: 22px 40px 56px;
  color: var(--snu-ink-3);
  font-size: 12.5px;
}
.foot a {
  color: var(--snu-ink-2);
}

/* ==========================================================================
 * 4부 — T-051 (행사 목록 2열 정렬 · 필터 · 기수 칩 · 모바일)
 * ========================================================================== */

/* 행사 목록을 오른쪽 기둥 높이에 **맞춘다**.
 *
 * `height:0; min-height:100%` 는 격자 칸 높이를 다른 칸이 정하게 하는 방법이다.
 * height:0 이라 이 칸은 줄 높이 계산에 안 끼고, min-height:100% 는 그렇게 정해진
 * 칸 높이를 그대로 받는다. 결과: **왼쪽 목록이 오른쪽 기둥보다 길어질 수 없다.**
 * (max-height 로 눈대중 값을 박으면 오른쪽 항목이 늘 때마다 어긋난다.) */
.snu-events-panel {
  height: 0;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* min-height:0 이 없으면 flex 자식이 내용 높이 밑으로 안 줄어 스크롤이 안 생긴다. */
.snu-events-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
/* 표 머리는 스크롤해도 남는다 — 25행을 내리다 보면 어느 칸인지 잊는다. */
.snu-events-scroll .data-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}
.snu-events-side {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* 목록 위 필터 줄. 값은 화면에서만 걸린다(서버 왕복 없음). */
.snu-filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
}
.snu-filter-bar .form-select {
  width: auto;
  font-size: 13px;
  padding: 6px 10px;
}
/* 거른 뒤 몇 건인지 — 필터가 걸렸는데 표가 짧으면 "자료가 없다"로 오해한다. */
.snu-filter-count {
  margin-left: auto;
  font-size: 12px;
  color: var(--snu-ink-3);
  font-variant-numeric: tabular-nums;
}

/* 기수 칩. `+N` 은 사람에 못 붙은 등록 행이다 — 명수(사람)와 단위가 달라 흐리게 뗀다. */
.snu-cohort-chips {
  margin-top: 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.chip-extra {
  opacity: 0.6;
  font-weight: 400;
}

/* 02 발표자 TOP 10 은 `.who`, 04 참여도 TOP 은 `.info` 를 쓴다.
 * 원본에는 `.info` 규칙만 있어서 `.who` 쪽 이름이 기본 크기(16px)로 떨어졌다 —
 * 같은 모양의 카드 둘이 글자 크기만 달랐다. `.info` 와 같은 값으로 맞춘다. */
.snu-presenter .who .name {
  font-size: 13px;
  font-weight: 600;
}
.snu-presenter .who .org {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.55);
  margin-top: 2px;
}

/* 견줘 읽는 KPI 는 폰에서도 한 행 (T-051 — 수강생·강사·기수 / 구독자·발송·열람·클릭).
 * 아래 700px 미디어 쿼리가 `.snu-stat` 을 세로로 쌓는데, 그 규칙을 이 격자에서만 되돌린다.
 * 좁아지는 만큼 글씨가 줄지만, 넷이 흩어져 세로로 네 배 길어지는 것보다 낫다. */
.snu-stat-grid.row-sm.cols-3 {
  grid-template-columns: repeat(3, 1fr);
}
.snu-stat-grid.row-sm.cols-4 {
  grid-template-columns: repeat(4, 1fr);
}

/* 원본에 없는 반응형 보강.
 * 원본 .snu-pipeline-row 는 repeat(4,1fr) 고정이라 폰 폭에서 네 칸이 짜부라진다
 * (원본은 이 카드를 모바일에서 검증하지 않은 듯하다). 표는 .table-wrap 이 가로로
 * 스크롤하므로 표에 width 100% 를 강제하지 않는다 — 그러면 스크롤이 안 발동한다. */
@media (max-width: 700px) {
  .snu-pipeline-row {
    grid-template-columns: repeat(2, 1fr);
  }
  /* 2×2 격자에서는 화살표가 거짓말이 된다 — 3번째 칸이 줄 맨 앞인데
   * `.snu-stage + .snu-stage` 라 왼쪽(빈 여백)을 가리키는 → 가 붙는다.
   * 두 줄로 접힌 순간 사슬은 시각적으로 성립하지 않으므로 아예 뺀다. */
  .snu-pipeline-row.chained .snu-stage + .snu-stage::before {
    display: none;
  }
  .snu-hero {
    padding: 32px 20px 40px;
  }
  .snu-content {
    padding: 28px 16px 32px;
  }
  .foot {
    padding: 22px 16px 40px;
  }

  /* ---- T-051 모바일: 세로 길이를 줄인다 ----
   *
   * 원본은 데스크톱 여백(판 24px·섹션 56px)을 폰에서도 그대로 쓴다. 섹션 넷이면
   * 여백만으로 화면 두 개 분량이라, **값이 아니라 빈 곳을 스크롤하게 된다.**
   * 글자 크기는 건드리지 않는다 — 줄이는 건 여백이지 읽을 것이 아니다. */
  .snu-section {
    margin-bottom: 32px;
  }
  .snu-section-head {
    margin-bottom: 16px;
  }
  .snu-section-title {
    font-size: 20px;
  }
  .snu-panel {
    padding: 16px 16px;
  }
  .snu-panel-title {
    margin-bottom: 12px;
  }
  .snu-stat {
    padding: 14px 14px;
  }
  .snu-stat-value {
    font-size: 26px;
  }
  .snu-events-layout,
  .snu-events-side {
    gap: 16px;
  }

  /* 한 행으로 두기로 한 격자는 여기서도 쌓지 않는다 — 대신 칸을 좁게 만든다.
   * 위 `.snu-stat { border-right:none; border-bottom:… }` 도 되돌려야 격자가 격자로 보인다. */
  .snu-stat-grid.row-sm .snu-stat {
    padding: 12px 8px;
    border-right: 1px solid var(--snu-line);
    border-bottom: none;
  }
  .snu-stat-grid.row-sm .snu-stat:last-child {
    border-right: none;
  }
  .snu-stat-grid.row-sm .snu-stat-label {
    font-size: 11px;
    letter-spacing: 0;
    margin-bottom: 4px;
  }
  .snu-stat-grid.row-sm .snu-stat-value {
    font-size: 20px;
  }
  .snu-stat-grid.row-sm.cols-4 .snu-stat-value {
    font-size: 17px;
  }
  .snu-stat-grid.row-sm .snu-stat-value .unit {
    font-size: 11px;
    margin-left: 2px;
  }

  /* 부차적인 칸은 접는다 (`ui.js` 의 `minor`). 접힌 칸의 값은 행을 눌러 모달에서 본다.
   * 남는 칸이 적어지므로 `.data-table` 의 min-width:620px 도 함께 풀어야
   * 가로 스크롤이 사라진다 — 안 풀면 3칸이 620px 안에서 늘어날 뿐이다. */
  .table-wrap.compact-sm .col-minor {
    display: none;
  }
  .table-wrap.compact-sm .data-table {
    min-width: 0;
  }
  .table-wrap.compact-sm .data-table th,
  .table-wrap.compact-sm .data-table td {
    padding-left: 8px;
    padding-right: 8px;
  }

  /* 2열이 1열로 접히면 높이를 맞출 짝(오른쪽 기둥)이 없다 — 대신 **화면 높이**에 맞춘다.
   * 여기서 상한을 풀면 행사 25건이 그대로 펼쳐져 폰 페이지의 절반이 표 하나가 된다
   * (실측 1,800px). 필터가 있으니 좁혀서 보는 길도 있다. */
  .snu-events-panel {
    height: auto;
    min-height: 0;
  }
  .snu-events-scroll {
    max-height: 55vh;
    -webkit-overflow-scrolling: touch;
  }

  /* 발표자 TOP 10 — 폰에서 한 단계 더 줄인다. 10줄이 통째로 화면을 먹던 자리다. */
  .snu-top-presenters {
    padding: 16px 16px;
  }
  .snu-top-title {
    margin-bottom: 12px;
  }
  .snu-presenter {
    padding: 6px 0;
    gap: 8px;
  }
  .snu-presenter .who .name,
  .snu-presenter .info .name {
    font-size: 12px;
  }
  .snu-presenter .who .org {
    font-size: 10px;
  }
  .snu-presenter .count {
    font-size: 12px;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

/* 안 재는 단계 (T-058) — 0 과 같은 밝기로 그리면 "아무도 없다"로 읽힌다.
   색은 새로 만들지 않고 기존 토큰의 불투명도만 낮춘다. */
.snu-stage.unmeasured {
  opacity: 0.45;
}
.snu-stage.unmeasured .snu-stage-bar span {
  background: var(--snu-ink-3);
}

/* 예정표 요일 칸 (T-072) — 체크박스와 글자를 한 덩어리로 눌리게 한다.
   폰에서 7칸이 두 줄로 접히므로 `flex-wrap` 은 호출부에 있다. */
.sch-daybox {
  display: inline-flex;
  gap: 5px;
  align-items: center;
  font-size: 13px;
  cursor: pointer;
  user-select: none;
}
.sch-daybox input {
  cursor: pointer;
}
