/* EXESALUS 사용자 클라이언트. 디자인 시스템.
 *
 * 참조 프론트의 디자인 언어를 계승함: 주색 #0969ff, 넉넉한 라운드.
 * Pretendard 는 SIL OFL 오픈폰트라 직접 반입함(assets/fonts/ · CDN 미사용).
 * 모바일 우선. 이 화면은 이후 안드로이드 앱으로 이전됨.
 */

/* ── Pretendard 반입 ─────────────────────────────────────
 * 참조본 디자인 언어가 전제하는 글꼴임. CDN 이 아니라 파일로 반입함. 키오스크가
 * 오프라인일 수 있고 외부 참조를 두지 않는다는 원칙 때문임(frontend/CLAUDE.md).
 * SIL OFL 1.1 · 원문은 assets/fonts/LICENSE-Pretendard.txt 에 동봉함.
 * font-display: swap. 폰트 적재를 기다리며 화면이 비어 있는 시간을 만들지 않음.
 */
@font-face {
  font-family: "Pretendard";
  src: url("./assets/fonts/Pretendard-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Pretendard";
  src: url("./assets/fonts/Pretendard-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Pretendard";
  src: url("./assets/fonts/Pretendard-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Pretendard";
  src: url("./assets/fonts/Pretendard-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* 참조본(exesalus.com)의 Mantine `myColor` 램프 원문. 주색 인덱스 6 이 #0969ff 임.
   * 종전에는 3개만 두었는데 랜딩·차트에서 중간 단계가 필요해 전 단계를 가져옴. */
  --p0: #e5f4ff;
  --p1: #cde2ff;
  --p2: #9bc2ff;
  --p3: #64a0ff;
  --p4: #3984fe;
  --p5: #1d72fe;
  --p6: #0969ff;
  --p7: #0058e4;
  --p8: #004ecc;
  --p9: #0043b5;
  --primary: var(--p6);
  --primary-dark: var(--p8);
  --primary-soft: var(--p0);
  --bg: #f5f7fa;
  --surface: #ffffff;
  --border: #e5e9f0;              /* 장식용 구분선. 비텍스트 대비 요건 대상 아님 */
  /* 조작 요소의 경계는 그 자체가 정보임(입력란이 어디까지인지). WCAG 1.4.11 이 3:1 을
   * 요구하므로 장식 구분선과 **다른 토큰**으로 분리함. 측정 3.27:1. */
  --border-strong: #868f9c;
  --text: #1a1d23;
  --text-dim: #575f6b;            /* 종전 #6b7684 은 페이지 배경에서 4.3:1 로 미달이었음 */
  /* 상태색은 **채움용과 텍스트용을 분리**함. 원래 값(#12b886·#f08c00)은 흰 배경에서
   * 2.5:1 수준이라 글자로 쓰면 읽히지 않음. 밝은 값을 버리지 않고 용도를 나눔. */
  --good: #12b886;
  --good-text: #087f5b;
  --warn: #f08c00;
  --warn-text: #a35200;
  /* 연한 바탕. 종전에는 배지마다 생 색상값이 흩어져 있어(`#e6f7ee`·`#ffecec`) 새 칩을
   * 만들 때 값을 베껴 쓰게 되고, 대비 검사도 그 조합을 보지 못했음. 토큰으로 모음. */
  --good-soft: #e6f7ee;
  --warn-soft: #fff3e0;
  --danger-soft: #ffecec;
  --danger: #d12b2b;              /* 종전 #e03131 은 페이지 배경에서 4.21:1 */
  /* 링크·강조 **글자**용 주색. 채움용 --primary(#0969ff)는 연한 배경에서 4.37:1 로
   * 미달이라 글자에 쓸 수 없음. 버튼 배경 등 채움은 그대로 --primary 를 씀. */
  --primary-text: var(--p7);
  --radius: 14px;
  --radius-sm: 9px;
  --shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 4px 12px rgba(16, 24, 40, 0.04);
  --appbar-h: 52px;
  /* 타입 스케일. 종전에는 화면마다 px 를 직접 박아 128개 선언이 제각각이었음.
     본문을 15px→16.5px 로 올림(고령 이용자 대상 요건, 목표는 17px 이상 단계 도입). */
  /* 글자 크기 3단 토글. 배율 하나로 전 단계를 함께 옮김 —
   * 단계마다 6개 값을 따로 적으면 한 곳을 빠뜨려 비율이 깨짐.
   * `data-fs` 가 root 에 붙으면 이 배율만 바뀌고 아래 계산식이 따라감.
   *   보통(기본) 1.0 · 크게 1.12 · 아주 크게 1.26
   * 배율을 1.3 이상으로 올리지 않는 이유: 390px 폭에서 버튼 문구가 두 줄로 넘어가
   * 손가락 타겟 배치가 깨짐(렌더 실측으로 확인함). */
  --fs-scale: 1;
  --fs-xs: calc(13.5px * var(--fs-scale));
  --fs-sm: calc(15px * var(--fs-scale));
  --fs-base: calc(17px * var(--fs-scale));   /* 고령 이용자 요건. 목표치 도달 */
  --fs-md: calc(18px * var(--fs-scale));
  --fs-lg: calc(21px * var(--fs-scale));
  --fs-xl: calc(26px * var(--fs-scale));
  /* 간격 스케일. 종전 0개. 리듬이 없어 화면마다 여백이 달랐음 */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  /* 아이콘. 인라인 SVG(js/icons.js). 이모지·기하문자를 대체함 */
  /* 글자 옆에 붙는 최소 크기. 게시판 메타(상대시각·댓글 수)·이메일 줄에 씀.
   * 없어서 사고가 났음 — `icon-xs` 클래스가 정의되지 않아 SVG 가 크기 없이 렌더되어
   * 카드 하나를 다 차지했고, 옆의 글자는 폭이 없어 한 글자씩 세로로 쪼개졌음.
   * 렌더 검증(대비·타겟)은 이것을 잡지 못했고 화면을 보고서야 알았음. */
  --icon-xs: 13px;
  --icon-sm: 16px;
  --icon-md: 20px;
  --icon-lg: 28px;
  --tabbar-h: 62px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--text);
  /* Pretendard 를 앞세우고, 적재 실패 시에도 한글이 깨지지 않게 대체군을 남김. */
  font-family: "Pretendard", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Noto Sans KR", "Malgun Gothic", sans-serif;
  font-size: var(--fs-base);
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
  padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
}

/* ── 앱바 ─────────────────────────────────────────────── */
/* 삶의 질 '지난번 대비' 한 줄(views/casp.js compareLine) */
.casp-compare { margin: 8px 0 0; font-weight: 700; color: var(--primary-text); }

/* 운동 프로그램 — 추천 목록·실행(views/program.js, docs/48 06·12번) */
.pg-filters { display: flex; flex-direction: column; gap: 8px; margin: 8px 0 12px; }
.pg-list { display: flex; flex-direction: column; gap: 8px; }
.pg-row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pg-row-title { font-size: var(--fs-md); }
.pg-row-sub { font-size: var(--fs-sm); color: var(--text-dim); }
.pg-now { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.pg-now-sub { font-size: var(--fs-sm); color: var(--text-dim); }
.pg-plan-sub { font-size: var(--fs-xs); color: var(--text-dim); }

/* 테스트 서버 띠(js/staging.js). 운영 주소에서는 붙지 않음 */
.staging-ribbon {
  padding: 6px 16px; text-align: center;
  background: #7a2e00; color: #fff;
  font-size: var(--fs-xs); font-weight: 700; line-height: 1.4;
}

.appbar {
  position: sticky;
  top: 0;
  z-index: 20;
  height: var(--appbar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.appbar-brand {
  /* 홈으로 돌아가는 상시 링크임. 글자 크기만으로는 26px 였어 규격 미달이었음 */
  display: inline-flex; align-items: center; gap: 7px; min-height: 44px;
  font-weight: 900;
  letter-spacing: 0.06em;
  /* 레거시 로고(아령 + EXESALUS)는 본문색이었음(2026-10-01 복원, ADR-175).
   * 종전에는 글자만 주색이었고 아령이 없었음. */
  color: var(--text);
  text-decoration: none;
  font-size: 18px;
  /* 종전에는 '사용자' 칩이 오른쪽을 밀어냈음. 칩을 걷어 내면서 그 역할을 로고가 맡음 */
  margin-right: auto;
}
/* 아령 표식. 로고의 일부라 글자보다 조금 크게 둠 */
.brand-mark { width: 1.35em; height: 1.35em; stroke-width: 2; }
.appbar-role {
  font-size: var(--fs-xs);
  color: var(--text-dim);
  max-width: 50%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 본문 폭. 종전에는 720px 고정이라 2560px 화면에서 모바일 컬럼 하나가 회색 바다에 떠
 * 있었음(눈으로 확인함). 폭을 단계로 넓히되 읽는 글의 줄 길이는 지키기 위해 본문
 * 텍스트 블록에는 별도 상한을 둠(`.prose`). 참조본도 `lg:max-w-`·`xl:max-w-` 로 단계를
 * 두었으므로 이것이 계승 방향에 맞음. */
/* ── 기록·검사 화면 사이 바로가기 줄 ────────────────────── */
/* 옆으로 미는 대신 줄을 바꿈(main.js SECTION_LINKS 참조). 손가락 타겟 44px 을 지킴. */
.sectionnav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 12px 14px 0;
  max-width: 720px;   /* .outlet 과 같은 폭·여백이어야 줄이 어긋나 보이지 않음 */
  margin: 0 auto;
}

@media (min-width: 1024px) {
  .sectionnav { max-width: 960px; padding: 18px 22px 0; }
}

@media (min-width: 1440px) {
  .sectionnav { max-width: 1180px; padding: 22px 26px 0; }
}

.chip-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  font-size: var(--fs-sm);
}

.chip-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.chip-link-on {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary-text);
  font-weight: 700;
}

@media print { .sectionnav { display: none !important; } }

/* `hidden` 속성이 실제로 감추게 함.
   `.sectionnav{display:flex}` 처럼 클래스가 display 를 지정하면 `[hidden]` 의 기본
   `display:none` 을 이김 — 바로가기 줄을 넣자 그 줄이 없어야 하는 화면에서도 빈 띠가
   12px 남았음(홈 높이가 그만큼 늘어 실측으로 잡음. 2026-09-27, ADR-171).
   같은 함정을 콘솔에서 먼저 밟았고 한 시간 만에 이쪽에서 되풀이했음. */
[hidden] { display: none !important; }

.outlet { padding: 14px 14px 24px; max-width: 720px; margin: 0 auto; }
@media (min-width: 1024px) {
  .outlet { max-width: 960px; padding: 22px 22px 32px; }
}
@media (min-width: 1440px) {
  .outlet { max-width: 1180px; padding: 26px 26px 40px; }
}
/* 읽는 글은 넓어져도 65자 안쪽에 두어야 함. 카드가 넓어지는 것과 글줄이 길어지는 것은
 * 다른 문제임 — 폭을 늘린 뒤 약관·안내문이 한 줄 120자가 되어 읽기 어려워졌음. */
.prose { max-width: 62ch; }
.view { display: flex; flex-direction: column; gap: 14px; }

/* ── 카드 ─────────────────────────────────────────────── */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 13px 16px 0;
}
.card-head h2 { font-size: 14px; font-weight: 700; color: var(--text-dim); letter-spacing: 0.01em; }
.card-body { padding: 12px 16px 16px; display: flex; flex-direction: column; gap: 12px; }

/* ── 통계 ─────────────────────────────────────────────── */
.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.stat { display: flex; flex-direction: column; gap: 2px; }
.stat-label { font-size: var(--fs-xs); color: var(--text-dim); }
.stat-value { font-size: 21px; font-weight: 700; font-variant-numeric: tabular-nums; }
.stat-sub { font-size: var(--fs-xs); color: var(--text-dim); min-height: 1em; }

/* ── 주간 캘린더 ──────────────────────────────────────── */
.week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.day {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 8px 0; border-radius: var(--radius-sm); background: var(--bg);
}
.day-done { background: var(--primary-soft); }
.day-label { font-size: var(--fs-xs); color: var(--text-dim); }
.day-dot { font-size: var(--fs-xs); color: var(--border); }
.day-done .day-dot { color: var(--primary-text); }

/* ── 버튼 ─────────────────────────────────────────────── */
.btn {
  appearance: none;
  /* 높이는 전역 접근성 절에서 44px 를 보장하고, 폭은 여기서 둠:
   * 짧은 문구 버튼(예: '1')이 43px 로 1px 미달이었음 */
  min-width: 44px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 11px 16px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-block { display: block; width: 100%; }
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--primary-dark); }
.btn-ghost { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.btn-ghost:hover:not(:disabled) { border-color: var(--primary); color: var(--primary-text); }
.btn-danger { background: var(--surface); color: var(--danger); border-color: var(--border-strong); }
.btn-danger:hover:not(:disabled) { border-color: var(--danger); }

.cta { display: flex; flex-direction: column; gap: 8px; }
.quick { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }

/* ── 폼 ───────────────────────────────────────────────── */
/* 체크·라디오는 라벨 전체가 타겟임(브라우저가 라벨 클릭을 입력에 전달함). 그런데 라벨에
 * 스타일이 없으면 인라인 높이(약 21px)라 실제 타겟이 규격에 미달함. 라벨을 규격의 주체로
 * 삼고, 상자 자체도 24px 로 키워 눈으로 찾기 쉽게 함(기본값은 13px). */
.opt {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 2px 0; cursor: pointer;
}
.opt input[type="checkbox"], .opt input[type="radio"] {
  width: 24px; height: 24px; flex: none; accent-color: var(--primary);
}
.field { display: flex; flex-direction: column; gap: 5px; }
.field-label { font-size: var(--fs-xs); color: var(--text-dim); font-weight: 600; }
.input {
  width: 100%;
  /* 손가락 타겟 44px. 종전 렌더 실측이 input 42px · select 39px 였음 */
  min-height: 44px;
  padding: 10px 12px;
  font: inherit;
  color: var(--text);
  background: var(--surface);
  /* 입력란의 경계는 "여기가 입력란"이라는 정보 자체임. 3:1 을 만족하는 토큰을 씀 */
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.input:focus { outline: 3px solid var(--primary); outline-offset: 1px;
  border-color: var(--primary); }

.divider { display: flex; align-items: center; gap: 10px; color: var(--text-dim); font-size: var(--fs-xs); }
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* ── 안내 ─────────────────────────────────────────────── */
.notice {
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  border: 1px solid var(--border);
  background: var(--bg);
}
.notice-error { color: var(--danger); border-color: #ffd5d5; background: #fff5f5; }
.notice-warn { color: #8a5300; border-color: #ffe8b8; background: #fff9e8; }
.notice-info { color: var(--text-dim); }
/* 성공·완료 상태. 경고와 색으로 확실히 구분되어야 오인이 없음. */
.notice-ok { color: #0a6b3d; border-color: #b9e6cd; background: #f0fbf5; }

/* ── 운동 루틴(#/exercise/routine) ─────────────────────
 * 참조본은 넓은 화면에 본문·웹캠·목록을 3단으로 폈음. 모바일 세로에서는 그 폭이 없으므로
 * 위에서 아래로 쌓고, 대신 **진행 상태**(몇 번째인지)를 항상 위에 고정해 보여 줌. */
.routine-bar { display: flex; align-items: center; gap: 10px; }
.routine-step { font-size: 13px; font-weight: 800; color: var(--primary-text); white-space: nowrap; }
.routine-track { flex: 1; height: 6px; border-radius: 999px; background: var(--border); overflow: hidden; }
.routine-fill { width: 0; height: 100%; background: var(--primary); transition: width 0.25s ease; }
/* 그만두기는 글자 단추임 — 종전 30px '×' 는 손가락 타겟 미달이고 무엇인지 글로 드러나지 않았음. */
.routine-quit {
  appearance: none; border: 1px solid var(--border); background: var(--surface);
  color: var(--text-dim); border-radius: 999px; min-width: 44px; min-height: 44px;
  padding: 0 14px; font: inherit; font-weight: 700; line-height: 1;
  white-space: nowrap; cursor: pointer; flex: 0 0 auto;
}
.routine-quit:disabled { opacity: 0.55; cursor: default; }
.routine-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 8px; border: 0; border-bottom: 1px solid var(--border);
  background: transparent; font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.routine-item:last-child { border-bottom: 0; }
.routine-current { background: var(--p0); border-radius: var(--radius-sm); }
.routine-mark {
  flex: 0 0 24px; text-align: center; font-size: 13px; font-weight: 800; color: var(--text-dim);
}
.routine-current .routine-mark { color: var(--primary-text); }
.routine-name { flex: 1; min-width: 0; word-break: keep-all; }

/* ── 가입 동의(#/login) ────────────────────────────────
 * 참조본은 체크박스를 주석 처리해 두어 사실상 묻지 않았음. 여기서는 반드시 보이며,
 * 각 문서로 가는 링크를 같은 줄에 둠(읽지 않고 동의하게 만들지 않기 위함). */
.agree-box { display: flex; flex-direction: column; gap: 8px; padding: 4px 2px; }
/* 약관 동의 행. **라벨 전체가 타겟**이 되게 44px 를 보장함 — 필수 동의라 여기서 못 누르면
 * 가입이 막힘. 종전에는 체크박스 18px·"보기" 링크 23x21 로 둘 다 규격 미달이었음. */
.agree { display: flex; align-items: center; gap: 10px; min-height: 44px; }
.check {
  width: 24px; height: 24px; accent-color: var(--primary); flex: 0 0 auto;
}
.agree-label {
  flex: 1; font-size: var(--fs-sm); line-height: 1.5; cursor: pointer;
  /* 라벨을 눌러도 체크되게 되어 있으므로 라벨이 실제 타겟임 */
  display: flex; align-items: center; min-height: 44px;
}
.agree-link {
  font-size: var(--fs-xs); color: var(--primary-text); text-decoration: underline;
  white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px;
}

/* ── 운영진 명단(#/lab) ────────────────────────────────
 * 참조본은 3열 그리드에 원형 사진을 썼음. 모바일 세로가 기준이라 1열로 쌓되, 사진
 * 자산이 없으므로 이름 첫 글자 표식으로 자리를 지킴(자산 확보 시 그대로 교체 가능). */
.op-grid { display: flex; flex-direction: column; gap: 14px; }
.op { display: flex; gap: 12px; align-items: flex-start; }
.op-face {
  flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--p0); color: var(--p8); font-weight: 900; font-size: 18px;
}
/* 사진이 지정된 사람. 증명사진이라 얼굴이 위쪽에 있으므로 위 기준으로 자름
 * (가운데 기준이면 이마가 잘림). */
.op-face-photo { overflow: hidden; background: var(--bg); line-height: 0; }
.op-face-icon .icon { width: 26px; height: 26px; stroke-width: 1.9; }
.op-face-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 22%; }
.op-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.op-name { font-size: 16px; font-weight: 800; }
.op-cur { font-size: 13px; font-weight: 700; color: var(--text-dim); word-break: keep-all; }
.op-desc { font-size: 13px; line-height: 1.6; word-break: keep-all; }
/* 이메일 줄. 긴 주소를 끊어 주되(`break-all`) **글자 쪽에 폭을 남겨야** 함 —
 * flex 안에서 글자 칸이 0 으로 줄면 한 글자씩 세로로 쌓임(실측으로 겪었음). */
.op-mail {
  font-size: var(--fs-xs); color: var(--text-dim);
  display: flex; align-items: flex-start; gap: 4px;
}
.op-mail > span { min-width: 0; word-break: break-all; }
.op-mail > .icon { margin-top: 2px; }

/* ── 뱃지·운동 검색(#/exercise/search) ─────────────────
 * 참조본은 Mantine Badge 를 썼음. 크기(size="lg")와 색 대응(저=초록·중=파랑·고=빨강)을
 * 그대로 옮기되, 이 클라이언트에는 컴포넌트 라이브러리가 없으므로 클래스로 재현함. */
.badge {
  display: inline-flex; align-items: center;
  padding: 3px 10px; border-radius: 999px;
  font-size: 13px; font-weight: 700; line-height: 1.5;
  white-space: nowrap;
}
.badge-ok { background: var(--good-soft); color: #0a6b3d; }
.badge-info { background: var(--p0); color: var(--p8); }
.badge-danger { background: var(--danger-soft); color: #b42318; }
.badge-plain { background: var(--bg); color: var(--text-dim); border: 1px solid var(--border); }

.ex-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  width: 100%; padding: 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  text-align: left; cursor: pointer; font: inherit; color: inherit;
}
.ex-card:active { background: var(--p0); }
.ex-title { font-size: 16px; font-weight: 700; line-height: 1.4; word-break: keep-all; }
.ex-badges { display: flex; flex-wrap: wrap; gap: 6px; }
.ex-badges-top { padding: 0 2px 4px; }
/* 게시글 본문은 문단 단위로 끊어 넣음. 마크업을 넣지 않으므로 간격을 여기서 줌. */
.ex-line { margin: 0 0 8px; line-height: 1.7; word-break: keep-all; }
.ex-line:last-child { margin-bottom: 0; }

/* ── 월간 리포트(#/report) ─────────────────────────────
 * 참조본은 A4 한 장 분량의 인쇄물을 화면에 그대로 보였음. 모바일에서는 그 폭을 낼 수
 * 없으므로 화면은 카드로 쌓고, 인쇄할 때만 종이 문서처럼 보이게 함. */
.sheet { display: flex; flex-direction: column; gap: 14px; }
.sheet-head {
  display: flex; flex-direction: column; gap: 8px;
  padding: 16px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.sheet-title { margin: 0; font-size: 22px; font-weight: 900; word-break: keep-all; }
.sheet-meta { display: flex; flex-direction: column; gap: 2px; font-size: 13px; color: var(--text-dim); }
.sheet-mark { display: flex; align-items: baseline; gap: 8px; padding-top: 4px; }
.sheet-brand { font-weight: 900; color: var(--primary-text); letter-spacing: -0.02em; }
.sheet-org { font-size: var(--fs-xs); color: var(--text-dim); }
.sheet-foot { margin: 0; padding: 4px 2px 8px; font-size: var(--fs-xs); color: var(--text-dim); }
.chart { display: block; width: 100%; }

/* 리포트의 접은 기록. 기본은 닫혀 있고 인쇄 직전에 코드가 펼침(views/report.js). */
.rep-more { margin-top: 6px; }

.rep-more-sum {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--primary-text);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.rep-more-sum::-webkit-details-marker { display: none; }
.rep-more-sum:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.rep-more[open] .rep-more-sum { margin-bottom: 10px; }
.rep-more-body { display: flex; flex-direction: column; gap: 10px; }

/* 워치 원자료 그래프(ADR-195, js/watch-chart.js). 그래프 색은 캔버스가 정하고 여기서는 범례·표·접힘만 정함. */
.wseries { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.wseries-canvas { width: 100%; height: 210px; display: block; }
.wseries-legend { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 0; font-size: var(--fs-xs); color: var(--text-dim); }
.wseries-key::before { content: ''; display: inline-block; width: 16px; height: 0; margin-right: 6px; vertical-align: middle; border-top: 3px solid; }
.wseries-key-line::before { border-top-color: #0969ff; }
.wseries-key-avg::before { border-top: 2px dashed #a35200; }
.wseries-key-max::before { width: 9px; height: 9px; border: 0; border-radius: 50%; background: #b42318; }
.wseries-key-band::before { height: 10px; border: 1px dashed rgba(9, 105, 255, 0.5); background: rgba(9, 105, 255, 0.1); }
.wseries-raw > summary, .rep-watch > summary {
  cursor: pointer; min-height: 44px; display: flex; align-items: center;
  color: var(--primary-text); font-size: var(--fs-sm); font-weight: 600;
}
.wseries-raw > summary:focus-visible, .rep-watch > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.wseries-table { width: 100%; border-collapse: collapse; font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.wseries-table th, .wseries-table td { text-align: left; padding: 4px 6px; border-bottom: 1px solid var(--border); }
.wseries-table td.num { text-align: right; }
.rep-watch { margin-top: 4px; }

.rep-item { padding: 12px 0; border-bottom: 1px dashed var(--border); }
.rep-item:last-child { border-bottom: 0; }
.rep-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.rep-what { color: var(--primary-text); font-weight: 900; }
.rep-when { font-size: 13px; color: var(--text-dim); }
.rep-score { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 8px; }
.rep-score-sub { font-size: var(--fs-xs); color: var(--text-dim); }
.rep-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px 10px; padding-top: 8px; font-size: 14px; }
.rep-fact { display: flex; gap: 4px; min-width: 0; }
.rep-article { margin: 8px 0 0; padding: 8px 10px; background: var(--p0); border-radius: var(--radius-sm); font-size: 14px; }
.rep-actions { padding-top: 8px; }
/* 실제로는 버튼임(누르면 이동함). 규격 대상. 종전 렌더 실측 117x32 였음 */
.link-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 6px 16px; border-radius: 999px;
  background: var(--primary); color: #fff; font-size: 13px; font-weight: 700;
  text-decoration: none;
}
.link-row-actions { display: flex; gap: 8px; padding-top: 4px; }
.badge-dark { background: #1a1d23; color: #fff; }

/* 인쇄. 참조본과 같이 리포트 영역만 종이에 남김. 화면용 껍데기(앱바·탭바·버튼)를
 * 함께 인쇄하면 한 장이 두 장이 되고 잉크만 씀. */
@media print {
  .appbar, .tabbar, .sitefoot, .cta, .btn, .link-row-actions, .field { display: none !important; }
  body { background: #fff; }
  .outlet { padding: 0; max-width: none; }
  .sheet { gap: 10px; }
  .card, .sheet-head { border: 0; box-shadow: none; break-inside: avoid; }
  .rep-item { break-inside: avoid; }
}

/* ── 설치 안내(#/download) ───────────────────────────── */
.install-box { display: flex; flex-direction: column; gap: 8px; }
.tabpanel { padding-top: 10px; }
.steps { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 10px; }
.steps li { line-height: 1.6; }
.loading, .empty { font-size: 13px; color: var(--text-dim); padding: 8px 0; }
.hint { font-size: var(--fs-xs); color: var(--text-dim); }

/* ── 목록·칩 ──────────────────────────────────────────── */
.chip-list { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  font-size: var(--fs-xs); padding: 4px 10px; border-radius: 999px;
  background: var(--primary-soft); color: var(--primary-dark); font-weight: 600;
}
.kv { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; }
.kv-key { color: var(--text-dim); }
.kv-value { font-weight: 600; text-align: right; }

.perm-list { list-style: none; display: flex; flex-direction: column; gap: 6px; font-size: 14px; }
.perm-list li { display: flex; align-items: center; gap: 8px; }
.perm-mark { font-size: var(--fs-xs); }
.perm-on .perm-mark { color: var(--good-text); }
.perm-off { color: var(--text-dim); }
.perm-off .perm-mark { color: var(--border); }

/* ── 막대 ─────────────────────────────────────────────── */
.bars { display: flex; flex-direction: column; gap: 7px; }
.bar-row { display: grid; grid-template-columns: 82px 1fr 46px; align-items: center; gap: 8px; }
.bar-label { font-size: var(--fs-xs); color: var(--text-dim); }
/* 가로 진행 막대. 종전에는 같은 구실의 `.pt-track`·`.pt-fill` 이 따로 있었음
 * (포인트 화면에서 12px 로 쓰려고 새로 만든 것). 크기 변형(`.bar-lg`)으로 합침 —
 * 같은 모양을 두 이름으로 두면 한쪽만 고쳐 어긋남.
 * `.goalbar-*` 는 **세로** 막대라 합치지 않음(구실이 다름). */
.bar-track { height: 8px; background: var(--bg); border-radius: 999px; overflow: hidden; }
.bar-fill { height: 100%; border-radius: 999px; background: var(--primary); min-width: 3px; }
.bar-lg { height: 12px; }
.bar-good { background: var(--good-text); }
.bar-mid { background: var(--primary); }
.bar-low { background: var(--warn-text); }
.bar-value { font-size: var(--fs-xs); text-align: right; font-variant-numeric: tabular-nums; }

/* ── 로그인 ───────────────────────────────────────────── */
.view-login { padding-top: 22px; }
.login-hero { text-align: center; padding: 10px 0 6px; }
.login-title { font-size: 30px; font-weight: 800; color: var(--primary-text); letter-spacing: 0.04em; }
.login-sub { font-size: 13px; color: var(--text-dim); margin-top: 4px; }

.greeting { padding: 2px 2px 0; }
.greeting-title { font-size: 21px; font-weight: 700; }
.greeting-sub { font-size: 13px; color: var(--text-dim); }

/* ── 하단 탭 ──────────────────────────────────────────── */
.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 20;
  height: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--border);
}
.tab {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  text-decoration: none;
  color: var(--text-dim);
  font-size: var(--fs-xs);
}
.tab-icon { font-size: 17px; line-height: 1; }
.tab-active { color: var(--primary-text); font-weight: 700; }

/* ── 분절 선택(강도·부위·컨디션) ──────────────────────── */
.seg { display: flex; flex-wrap: wrap; gap: 6px; }
.seg-btn {
  flex: 1 1 auto;
  min-width: 62px;
  min-height: 44px;
  padding: 9px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.seg-active { background: var(--primary-soft); color: var(--primary-dark); border-color: var(--primary); font-weight: 700; }

/* 2열 격자. **고정 2열이 아니라 최소 폭을 둠** — 글자 크기를 올리면 `datetime-local` 같은
 * 넓은 입력이 반 폭에 들어가지 못해 화면이 가로로 넘침(아주 크게 단계에서 실측으로 확인함).
 * 최소 폭에 못 미치면 1열로 접힘. */
.grid2 {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
}
/* 입력이 격자 칸보다 넓어지지 않게 함. `width:100%` 만으로는 내용 최소 폭이 칸을 밀어냄 */
.grid2 > .field { min-width: 0; }
.grid2 .input { min-width: 0; }

/* ── 실시간 채점 ──────────────────────────────────────── */
.run-head { display: flex; align-items: center; justify-content: space-between; }
.timer { font-size: 15px; font-variant-numeric: tabular-nums; color: var(--text-dim); }
.verdict { font-size: 15px; font-weight: 700; color: var(--text-dim); }
.verdict-good { color: var(--good-text); }
.verdict-bad { color: var(--warn-text); }

/* 게이지: conic-gradient 로 그림. 캔버스·SVG 없이 값 하나(--v)로 갱신됨 */
.gauge {
  --v: 0;
  position: relative;
  width: 168px;
  height: 168px;
  margin: 4px auto 0;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(closest-side, var(--surface) 78%, transparent 79%),
    conic-gradient(var(--primary) calc(var(--v) * 360deg), var(--bg) 0);
  transition: background 0.2s linear;
}
.gauge-good { background:
    radial-gradient(closest-side, var(--surface) 78%, transparent 79%),
    conic-gradient(var(--good-text) calc(var(--v) * 360deg), var(--bg) 0); }
.gauge-bad { background:
    radial-gradient(closest-side, var(--surface) 78%, transparent 79%),
    conic-gradient(var(--warn-text) calc(var(--v) * 360deg), var(--bg) 0); }
.gauge-value { font-size: 40px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.gauge-label { font-size: var(--fs-xs); color: var(--text-dim); margin-top: 2px; }
.cue { text-align: center; font-size: 15px; font-weight: 600; min-height: 1.6em; }

.preview { display: flex; justify-content: center; }
.preview-img { width: 100%; max-width: 420px; border-radius: var(--radius-sm); background: #0e1218; }


/* ── 차트 ─────────────────────────────────────────────── */
.chart { width: 100%; display: block; }
.chart[hidden] { display: none; }
.input-inline { width: auto; min-width: 118px; padding: 6px 10px; font-size: 13px; }

/* 선택 상자(`<select>`) — 브라우저 기본 모양이 그 아래 분절 버튼과 전혀 달라 같은 화면에
 * 두 디자인이 섞여 보였음(측정 진입 화면에서 눈으로 확인함). 화살표를 직접 그려
 * 입력란·버튼과 같은 테두리·반경·높이를 쓰게 함. `appearance: none` 이 없으면 플랫폼마다
 * 다르게 보임. */
select.input {
  appearance: none; -webkit-appearance: none;
  padding-right: 40px; cursor: pointer;
  /* 화살표는 배경 SVG 로 그림. 외부 파일·폰트를 쓰지 않음(오프라인 자립 요건) */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23575f6b' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}
select.input::-ms-expand { display: none; }

@media (min-width: 720px) {
  .quick { grid-template-columns: repeat(4, 1fr); }
}



/* ── 도전과제 ─────────────────────────────────────────── */
.day-num { font-size: var(--fs-xs); color: var(--text-dim); }
.ach-list { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.ach { display: grid; grid-template-columns: 22px 1fr auto; align-items: center; gap: 10px; }
.ach-mark { font-size: 17px; color: var(--border); }
.ach-on .ach-mark { color: var(--primary-text); }
.ach-body { display: flex; flex-direction: column; }
.ach-title { font-size: 14px; font-weight: 600; }
.ach-off .ach-title { color: var(--text-dim); font-weight: 500; }
.ach-sub { font-size: var(--fs-xs); color: var(--text-dim); }
.ach-diff { font-size: var(--fs-xs); color: var(--warn-text); letter-spacing: -1px; }

/* ── 시퀀스 목록 ──────────────────────────────────────── */
.seq-list { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.seq { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.seq-main { display: flex; flex-direction: column; min-width: 0; }
.seq-title { font-size: 14px; font-weight: 600; }
.seq-sub { font-size: var(--fs-xs); color: var(--text-dim); }
.seq-actions { display: flex; gap: 6px; flex-shrink: 0; }
.seq-actions .btn { padding: 6px 12px; font-size: 13px; }
.kv-list { display: flex; flex-direction: column; gap: 5px; }

/* ── 커뮤니티 ─────────────────────────────────────────── */
.art-list { list-style: none; display: flex; flex-direction: column; }
.art { border-bottom: 1px solid var(--border); }
.art:last-child { border-bottom: 0; }
/* 참조본 NewsCard 는 썸네일과 본문을 가로로 두었음(썸네일이 없으면 본문만).
 * 우리는 세로 1열이라 목록이 글자만 있는 표처럼 보였음. */
.art-link {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px 0; text-decoration: none; color: inherit;
  min-height: 44px;                     /* 손가락 타겟 */
}
.art-link:hover { background: var(--bg); }
.art-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }
.art-thumb {
  flex: 0 0 60px; width: 60px; height: 60px; line-height: 0;
  border-radius: var(--radius-sm); overflow: hidden; background: var(--bg);
}
.art-thumb img { width: 100%; height: 100%; object-fit: cover; }
.art-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px 7px;
  font-size: var(--fs-xs); color: var(--text-dim);
}
.art-when { white-space: nowrap; }
.art-dot { color: var(--border-strong); }
/* 댓글 수. 참조본은 아이콘 + 숫자였고 숫자를 본문색으로 두어 눈에 걸리게 했음 */
.art-comments { display: inline-flex; align-items: center; gap: 3px; color: var(--text); }
.art-expiry { display: inline-flex; align-items: center; gap: 3px; }
.art-title {
  font-size: 15px; font-weight: 650; line-height: 1.45;
  /* 참조본은 한 줄로 잘랐음(`truncate`). 두 줄까지 허용함 — 한국어 제목은 한 줄에
   * 들어가지 않는 것이 흔하고, 잘린 제목만으로는 무슨 글인지 알 수 없음. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.art-title-gone { color: var(--warn-text); font-weight: 600; }
.art-excerpt {
  font-size: var(--fs-xs); color: var(--text-dim); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.art-author { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-xs); }
.art-static { cursor: default; }
.art-gone .art-link:hover { background: transparent; }
.art-head { font-size: 19px; font-weight: 700; line-height: 1.4; }
/* 상세 머리. 참조본은 상대시각을 위, 아바타+닉네임을 아래에 두었음 */
.art-byline { display: flex; flex-direction: column; gap: 6px; }
.art-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.art-hero {
  line-height: 0; border-radius: var(--radius); overflow: hidden; background: var(--bg);
}
.art-hero img { width: 100%; height: auto; display: block; max-height: 320px; object-fit: cover; }
.cmt-list { display: flex; flex-direction: column; gap: 10px; }
.cmt { display: flex; flex-direction: column; gap: 2px; }
.cmt-head { font-size: var(--fs-xs); color: var(--text-dim); }
.cmt-body { font-size: 14px; white-space: pre-wrap; word-break: break-word; }

/* 화면 전환 안내. 두 화면(사용자/운영 콘솔)을 명시 링크로만 오감 */
.switch-hint { text-align: center; font-size: var(--fs-xs); color: var(--text-dim); padding: 4px 0 8px; }
.switch-hint a {
  color: var(--primary-text); font-weight: 600;
  /* 콘솔로 가는 링크. 손가락 타겟 규격을 맞춤(종전 90x39) */
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 8px;
}

/* ── 캘리브레이션 ─────────────────────────────────────── */
.sub-title { font-size: 13px; font-weight: 700; color: var(--text-dim); margin-top: 2px; }
.preset-list { display: flex; flex-direction: column; gap: 8px; }
.preset {
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  padding: 11px 13px; font: inherit; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.preset:hover { border-color: var(--primary); }
.preset-active { background: var(--primary-soft); border-color: var(--primary); }
.preset-title { font-size: 14px; font-weight: 700; }
.preset-active .preset-title { color: var(--primary-dark); }
.preset-desc { font-size: var(--fs-xs); color: var(--text-dim); }

/* ── 개발 전용 로그인(접이식) ─────────────────────────── */
.dev-box {
  background: var(--surface);
  border: 1px dashed var(--border-strong, var(--border));
  border-radius: var(--radius-sm);
  padding: 10px 13px;
  font-size: 13px;
}
.dev-box summary { cursor: pointer; color: var(--text-dim); font-weight: 600; }
.dev-body { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }

/* ── K-POMS 기분상태 설문 ─────────────────────────────────
 * 58문항을 모바일에서 한 화면씩 넘기지 않고 한 줄에 문항+선택지 5개로 배치함.
 * 참조 프론트가 한 페이지 방식이라 그 조작감을 유지하되, 응답한 행을 시각적으로
 * 구분해 남은 문항을 눈으로 찾을 수 있게 함(58문항에서 진행률만으로는 부족함).
 */
/* 설문 화면 공용 클래스. 척도가 둘(K-POMS·K-CASP-16)이 되어 `casp-` 별칭을 함께 둠.
 * 손가락 타겟·초점 표시 규격이 이 규칙에 걸려 있어, 별칭 없이 새 클래스를 쓰면
 * 렌더 검증의 타겟 실측에서 미달이 남(ADR-109). */
.kpoms-progress, .casp-progress {
  height: 8px; background: var(--border); border-radius: 999px;
  overflow: hidden; margin-top: 4px;
}
.kpoms-progress-fill, .casp-progress-fill {
  height: 100%; width: 0; background: var(--primary);
  border-radius: 999px; transition: width 0.18s ease;
}
.kpoms-progress-text, .casp-progress-text {
  display: block; margin-top: 5px; font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums; color: var(--text-dim);
}

.kpoms-legend, .casp-legend {
  display: flex; flex-wrap: wrap; gap: 4px 10px; margin-bottom: 10px;
  font-size: var(--fs-xs); color: var(--text-dim);
}
.kpoms-legend-item, .casp-legend-item { white-space: nowrap; }

.kpoms-list, .casp-list { list-style: none; display: flex; flex-direction: column; gap: 2px; }
.kpoms-item, .casp-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 7px 6px; border-radius: var(--radius-sm);
  border-bottom: 1px solid var(--border);
}
.kpoms-item:last-child, .casp-item:last-child { border-bottom: 0; }
/* 응답한 행은 옅게 눌러 미응답 행이 눈에 남게 함. */
.kpoms-answered, .casp-answered { background: var(--primary-soft); border-bottom-color: transparent; }

.kpoms-text, .casp-text { display: flex; align-items: baseline; gap: 7px; font-size: 14px; min-width: 0; }
.kpoms-num, .casp-num {
  flex: none; width: 22px; text-align: right;
  font-size: var(--fs-xs); font-variant-numeric: tabular-nums; color: var(--text-dim);
}

.kpoms-opts, .casp-opts { display: flex; gap: 3px; flex: none; }
.kpoms-opt, .casp-opt {
  min-width: 44px; min-height: 44px;   /* 접근성. 손가락 타겟 최소 규격 */
  /* 44px 미만이면 손가락으로 누르기 어려움. 모바일 최소 터치 영역을 지킴. */
  width: 32px; height: 34px; padding: 0;
  font: inherit; font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
  color: var(--text-dim); cursor: pointer;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.kpoms-opt:hover, .casp-opt:hover { border-color: var(--primary); }
.kpoms-opt-on, .casp-opt-on {
  background: var(--primary); border-color: var(--primary);
  color: #fff; font-weight: 700;
}
/* 미완 상태의 제출 버튼. 비활성으로 만들지 않음. 누르면 남은 문항으로 데려가므로
 * 그 통로를 막으면 사용자가 어디가 비었는지 알 수 없음. */
.btn.is-incomplete { background: var(--text-dim); border-color: var(--text-dim); }

@media (max-width: 360px) {
  .kpoms-opt { width: 44px; height: 44px; }   /* 좁은 화면에서도 44px 유지 */
  .kpoms-text { font-size: 13px; }
}

/* ── depth(RGB-D) 표시 ─────────────────────────────────────
 * depth 경로가 붙었을 때만 내용이 생김. 비어 있으면 아예 숨김. 자리를 남기면
 * depth 없는 세션에서 '측정했는데 값이 없다'로 읽힘.
 */
.depth-live:empty { display: none; }
.depth-live {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 12px 14px; margin-bottom: 12px;
}
.depth-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.depth-cell { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.depth-label { font-size: var(--fs-xs); color: var(--text-dim); }
.depth-value { font-size: 17px; font-variant-numeric: tabular-nums; }
.depth-sub { font-size: var(--fs-xs); color: var(--text-dim); }
.depth-hint {
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border);
  font-size: var(--fs-xs); color: var(--text-dim);
}

/* ── 게시판 첨부 (ADR-035) ────────────────────────────────── */
.attach-list { display: flex; flex-direction: column; gap: 5px; margin: 8px 0; }
.attach-list:empty { display: none; }
.attach-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 9px; font-size: var(--fs-xs);
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.attach-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attach-size { flex: none; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.attach-remove {
  flex: none; width: 22px; height: 22px; padding: 0; line-height: 1;
  font: inherit; font-size: 15px; cursor: pointer; color: var(--text-dim);
  background: transparent; border: 1px solid var(--border); border-radius: 6px;
}
.attach-remove:hover { color: var(--danger); border-color: var(--danger); }

/* ── 게시글 첨부 이미지 ───────────────────────────────────── */
.art-gallery { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.art-shot { display: block; line-height: 0; }
.art-shot img {
  width: 104px; height: 104px; object-fit: cover;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg);
}

/* ── 페이지 이동 ─────────────────────────────────────────── */
.pager { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-top: 12px; }
.page-btns { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
.page-btn {
  /* 손가락 타겟 44px. 종전 34px 였고, 뒤따르던 min-width: 34px 선언이 이 값을 덮어
     실측 폭이 34px 로 남아 있었음(페이지 버튼이 두 개 이상 그려질 때만 드러남). */
  min-width: 44px; min-height: 44px; padding: 0 8px;
  font: inherit; font-size: 13.5px; font-variant-numeric: tabular-nums; cursor: pointer;
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.page-btn:hover:not(:disabled) { border-color: var(--primary); }
.page-btn:disabled { cursor: default; }
.page-active { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 700; }
.page-gap { align-self: center; color: var(--text-dim); font-size: 13px; padding: 0 2px; }

/* ── 댓글 트리·관리 ───────────────────────────────────────── */
/* 대댓글은 1단만. 깊이가 늘면 모바일에서 본문 폭이 사라짐. */
.cmt-reply {
  margin-left: 20px;
  border-left: 2px solid var(--border);
  padding-left: 10px;
}
.cmt-actions { display: flex; gap: 8px; margin-top: 4px; }
.cmt-actions:empty { display: none; }
.cmt-act {
  padding: 0; font: inherit; font-size: var(--fs-xs); cursor: pointer;
  color: var(--text-dim); background: none; border: 0;
  text-decoration: underline; text-underline-offset: 2px;
}
.cmt-act:hover { color: var(--primary-text); }
.cmt-danger:hover { color: var(--danger); }
.reply-note {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin: 8px 0 4px; padding: 6px 10px; font-size: var(--fs-xs);
  background: var(--primary-soft); border-radius: var(--radius-sm); color: var(--primary-dark);
}

/* ── 반복 횟수 ─────────────────────────────────────────────
 * 기준 동작이 없으면 서버가 값을 보내지 않으므로 비어 있음. 그때는 숨김.
 */
.rep-live:empty { display: none; }
.rep-live {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 10px 14px; margin-bottom: 12px;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.rep-inner { display: flex; align-items: baseline; gap: 7px; }
.rep-label { font-size: var(--fs-xs); color: var(--text-dim); }
.rep-count { font-size: 26px; font-variant-numeric: tabular-nums; line-height: 1.1; }
.rep-unit { font-size: 13px; color: var(--text-dim); }
/* 1회 완료 순간의 강조. 숫자만 바뀌면 알아채기 어려움. */
.rep-hit { background: var(--primary-soft); border-color: var(--primary); }
.rep-hit .rep-count { color: var(--primary-dark); }

/* ══════════════════════════════════════════════════════════
 * 기존 사이트(exesalus.com) 계승 화면
 * 참조본은 Tailwind 그라디언트를 쓰나 여기는 빌드 도구가 없어 같은 결과를
 * 순수 CSS 로 재현함. 색 계열·배치·문구는 참조본 그대로임.
 * ══════════════════════════════════════════════════════════ */

/* ── 상단 알림 배너 ─────────────────────────────────────── */
.banner {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 12px 15px; margin-bottom: 10px;
  font: inherit; font-size: 14px; font-weight: 600; text-align: left;
  border-radius: var(--radius); border: 1px solid transparent; cursor: pointer;
  text-decoration: none;
}
.banner-icon { font-size: 16px; flex: none; }
.banner-warn { background: #fff9db; border-color: #ffe066; color: #8a6d1f; }
.banner-danger { background: #fff5f5; border-color: #ffc9c9; color: #b02121; }
.banner-row { display: flex; flex-direction: column; gap: 8px; }
@media (min-width: 560px) { .banner-row { flex-direction: row; } .banner-row .banner { margin-bottom: 0; } }

/* ── 표제 ──────────────────────────────────────────────── */
.hero { text-align: center; padding: 22px 0 10px; }
.hero-title { font-size: 30px; font-weight: 900; line-height: 1.25; letter-spacing: -0.5px; }
/* 좁은 폭에서는 숨김 — 세로로 쌓이면 부호가 혼자 떠서 오류 문자로 보임.
 * 데스크톱 분기에서 히어로가 2단이 될 때 다시 보임. */
.hero-x { display: none; font-size: 20px; color: var(--text-dim); margin: 10px 0; }
.hero-mark {
  display: inline-flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 10px 20px; border: 2px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.hero-mark-main { font-size: 17px; font-weight: 800; letter-spacing: -0.3px; }
.hero-mark-sub { font-size: var(--fs-xs); color: var(--text-dim); }

/* ── 주 메뉴 타일(참조본 그라디언트 버튼 재현) ──────────── */
.tiles { display: flex; flex-direction: column; gap: 12px; padding: 14px 0; }
.tiles-greet { font-size: 14px; color: var(--text-dim); text-align: center; }
/* 계승분과 증축분을 나누는 표식. 색만으로 구분하면 색을 구분하기 어려운 이용자에게
 * 전달되지 않으므로 글자로 적음. */
.tiles-divider {
  margin: 6px 0 0; text-align: center; font-size: var(--fs-xs);
  color: var(--text-dim); font-weight: 700; letter-spacing: 0.04em;
}
.tile-row { display: flex; gap: 12px; }
.tile-row .tile { flex: 1 1 0; min-width: 0; }
.tile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  width: 100%; padding: 16px; cursor: pointer; font: inherit; color: #fff;
  border: 0; border-radius: var(--radius); text-align: left;
  transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}
.tile:hover { transform: scale(1.02); opacity: 0.94; }
.tile:active { transform: scale(0.99); }
.tile-label {
  width: 100%; text-align: right; font-size: 17px; font-weight: 900;
  /* 2열 타일에서 '나의 월간 운동 리포트' 가 한 글자만 다음 줄로 떨어지는 것을 막음.
   * 단어 단위로 끊고 줄바꿈 지점을 넉넉히 둠. */
  word-break: keep-all; line-height: 1.25;
}
.tile-row .tile-label { font-size: 15px; }
.tile-wide .tile-label { font-size: 24px; }
/* 아이콘 크기는 `.icon-xl` 이 정함(SVG). 컨테이너는 정렬만 맡음 */
.tile-icon { display: flex; align-items: center; line-height: 1; }
.tile-sub { width: 100%; font-size: var(--fs-xs); font-weight: 500; opacity: 0.92; }
/* 타일 색 — 주색 램프 하나로 통일함(2026-08-27, ADR-079).
 *
 * 종전에는 참조본의 Tailwind 색을 그대로 계승해 청록·자주·파랑·빨강·주황·슬레이트·녹색
 * 7계열이 한 화면에 섞여 있었음. 참조본이 그랬으므로 계승은 충실했으나, 결과가
 * **색 체계 없는 화면**이었고 화면마다 주된 색이 달라(랜딩 다색 / 행동지표 녹색) 같은
 * 서비스로 읽히지 않았음. 눈으로 확인하고 나서야 드러난 문제임.
 *
 * 위계를 **명도가 아니라 채도**로 줌. "연한 파랑 + 흰 글자" 는 대비가 나오지 않아
 * (이 프로젝트 기준 4.5:1) 쓸 수 없기 때문임. 그래서
 *   - 증축분(신규 기능): 주색 램프. 채도가 높아 눈에 먼저 들어옴
 *   - 계승분(참조본 기능): 파랑 기미 중성. 어둡고 조용해 배경으로 물러남
 *   - 상태색(good/warn/danger): 뜻이 있는 곳에만 예외로 씀
 * 색 계열이 하나이므로 화면이 바뀌어도 같은 서비스로 읽힘.
 *
 * 양쪽 끝 모두 흰 글자 4.5:1 을 넘음(`tools/contrast_check.py` 가 매번 재측정함). */

/* 증축분 — 주색. 깊은 곳에서 주색으로 올라옴 */
.tile-accent { background: linear-gradient(to top right, #062a6b, #0058e4); }
/* 증축분 보조 — 같은 램프의 한 단 얕은 자리. 주 타일과 형제로 읽힘 */
.tile-accent-2 { background: linear-gradient(to top right, #0a2f78, #0a5fd6); }
/* 계승분 — 파랑 기미 중성. 채도를 낮춰 조용하게 둠 */
.tile-quiet { background: linear-gradient(to top right, #1b2537, #33455f); }
.tile-quiet-2 { background: linear-gradient(to top right, #202b3d, #3a4d68); }

/* 상태 타일 — 뜻이 색에 있는 것만. 남용하면 통일이 무너짐 */
.tile-good { background: linear-gradient(to top right, #0a3d2f, #12664d); }
.tile-warn { background: linear-gradient(to top right, #5a3407, #8a5209); }

/* 증축분 별칭(참조본에 없던 타일). 주색 램프를 그대로 가리킴 */
.tile-teal   { background: linear-gradient(to top right, #062a6b, #0058e4); }
.tile-purple { background: linear-gradient(to top right, #0a2f78, #0a5fd6); }
.tile-slate  { background: linear-gradient(to top right, #202b3d, #3a4d68); }

/* 레거시 5계열 복원(2026-10-01, ADR-175 가 ADR-079 의 이 부분을 대체함).
 *
 * 사업 수행 측이 "레거시(exesalus.com)의 외형·아이콘 참조가 가장 필요하다" 고 밝혔고,
 * 레거시 공개 화면을 정본으로 삼기로 했음. ADR-079 는 통일의 대가로 "색 식별이 사라졌음"
 * 을 적어 두었는데, 레거시 이용자에게는 그 색이 곧 메뉴의 이름이었음.
 *
 * 레거시 원색(Tailwind 400~600)은 흰 글자 대비가 1.5~2.3:1 이라 그대로 쓸 수 없음. 같은
 * 계열을 700~800 단으로 어둡게 해 양 끝 모두 4.5:1 을 넘김(`tools/contrast_check.py` 가
 * 매번 잰다). 괄호는 레거시 원색 → 복원색.
 *   운동 루틴   blue-600→sky-400   → blue-700→sky-700     (6.70 / 5.93)
 *   월간 리포트 red-600→orange-400 → red-700→orange-700   (6.47 / 5.18)
 *   K-POMS      orange-500→yellow-400 → amber-700→yellow-700 (5.02 / 4.92)
 *   직접 검색   black→slate-600    → 그대로               (21.0 / 7.58)
 *   공지사항    emerald-600→green-400 → emerald-700→green-700 (5.48 / 5.02) */
.tile-blue   { background: linear-gradient(to top right, #1d4ed8, #0369a1); }
.tile-red    { background: linear-gradient(to top right, #b91c1c, #c2410c); }
.tile-orange { background: linear-gradient(to top right, #b45309, #a16207); }
.tile-dark   { background: linear-gradient(to top right, #000000, #475569); }
.tile-green  { background: linear-gradient(to top right, #047857, #15803d); }

/* 신규 개발분 표식. 참조본에 없던 기능임을 타일 위에서 바로 알 수 있게 함.
 * 색만으로 구분하면 색을 구분하기 어려운 이용자에게 전달되지 않으므로 글자로 적음. */
.tile-new {
  position: absolute; top: 10px; left: 12px;
  padding: 2px 8px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.22);
  font-size: var(--fs-xs); font-weight: 800; letter-spacing: 0.02em;
}
.tile { position: relative; }

/* ── 근거 카드 ─────────────────────────────────────────── */
.evidence { padding: 30px 0 10px; display: flex; flex-direction: column; gap: 18px; }
.evidence-head { font-size: 22px; font-weight: 900; text-align: center; line-height: 1.35; }
.evi {
  padding: 18px; border-radius: var(--radius); background: #f1f5f9;
  box-shadow: 0 8px 20px rgba(100, 116, 139, 0.16);
  font-size: 14px; line-height: 1.6;
}
.evi-title { font-size: 16px; font-weight: 700; padding-bottom: 4px; }
.evi-left { text-align: left; margin-right: 22px; }
.evi-right { text-align: right; margin-left: 34px; }
.closing { padding: 28px 0 10px; font-size: 22px; font-weight: 900; text-align: center; }

/* ── 연구실 소개 ───────────────────────────────────────── */
.page-head { font-size: 22px; font-weight: 800; margin: 4px 0 12px; }
/* 제목 앞 표식(연구실 소개의 시험관 등). 레거시가 제목 앞에 붙이던 이모지 자리를 대신함 */
.page-head-icon { display: flex; align-items: center; gap: 8px; }
.page-head-icon .icon { color: var(--primary-text); }
.place { padding: 6px 0; }
.place + .place { border-top: 1px solid var(--border); margin-top: 8px; }
.place-head { display: flex; align-items: baseline; gap: 10px; }
.place-tel, .contact-link {
  /* 전화·메일은 이 화면의 주 동작임(누르면 전화 앱이 열림). 규격 필수 */
  display: inline-flex; align-items: center; gap: 5px; min-height: 44px;
  font-size: 13px; color: var(--primary-dark); text-decoration: none;
}
.place-addr { font-size: 13.5px; color: var(--text-dim); margin-top: 2px; }
.prof { display: flex; flex-direction: column; align-items: center; gap: 8px; }
/* 사진 묶음·약력 묶음. 모바일에서는 세로로 쌓이고 데스크톱에서 나란해짐 */
.prof-figure { display: flex; flex-direction: column; align-items: center; gap: 8px; position: relative; }
.prof-body { display: flex; flex-direction: column; gap: 2px; width: 100%; }
.prof-field-sep { color: var(--text-dim); }
/* 참조본은 여기에 교수 사진을 둠. 자산 확보 시 배경 이미지만 넣으면 됨. */
/* 참조본은 3:4 세로 패널(350×500)이었음. 원형 아바타로 두면 자산을 넣어도 참조본과
 * 같은 화면이 되지 않고 세로 사진이 잘림. 비율을 참조본에 맞춤. */
.prof-photo {
  width: 210px; height: 280px; border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  background: var(--primary-soft); border: 2px solid var(--p2); overflow: hidden;
  color: var(--primary-dark); font-weight: 800; font-size: 17px;
}
/* 이름판. 레거시는 사진 오른쪽 아래에 흰 바탕 이름판을 겹쳐 두었음(2026-09-30 대조, ADR-175) */
.prof-name {
  position: absolute; right: 0; bottom: 0;
  padding: 6px 14px; background: #fff; border-top-left-radius: var(--radius-sm);
  font-size: 20px; font-weight: 900; color: var(--text);
}
.degree-list { list-style: none; text-align: center; margin: 12px 0; }
.degree-list li { font-size: 14px; color: var(--text-dim); padding: 2px 0; }
.degree-top { font-size: 17px !important; font-weight: 900; color: var(--text) !important; }
.prof-field { text-align: center; font-size: 14px; margin: 8px 0; }
.prof-field-icon { color: var(--primary-text); margin-right: 4px; }
.prof-contact { display: flex; justify-content: center; gap: 16px; font-size: 13.5px; }
.prof-contact a { color: var(--primary-dark); text-decoration: none; }
.paper { padding: 8px 0; font-size: 13.5px; line-height: 1.6; }
.paper + .paper { border-top: 1px solid var(--border); }
.paper-cite { color: var(--text); }
.paper-title { color: var(--text-dim); }
.patent { padding: 8px 0; font-size: 13.5px; }
.patent + .patent { border-top: 1px solid var(--border); }
.patent-no { color: var(--text-dim); margin-left: 6px; font-variant-numeric: tabular-nums; }

/* ── 약관·처리방침 ─────────────────────────────────────── */
.legal-sec + .legal-sec { margin-top: 18px; }
.legal-h { font-size: 15.5px; font-weight: 700; margin-bottom: 6px; }
.legal-list { list-style: disc; margin-left: 18px; }
.legal-list li { font-size: 13.5px; line-height: 1.7; color: var(--text-dim); padding: 2px 0; }
.legal-list li strong { color: var(--text); }
.legal-guard {
  margin-top: 12px; padding: 12px 14px; font-size: 13.5px; line-height: 1.6;
  background: var(--primary-soft); border-radius: var(--radius-sm); color: var(--primary-dark);
}
.legal-foot { margin-top: 12px; font-size: var(--fs-xs); color: var(--text-dim); text-align: center; }

/* ── 전역 푸터 ─────────────────────────────────────────── */
.sitefoot {
  margin-top: 26px; padding: 18px 16px calc(18px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border); background: var(--surface);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.sitefoot-copy { font-size: var(--fs-xs); color: var(--text-dim); }
/* 바닥 로고. 레거시 푸터는 로고 아래에 저작권 문구를 두었음 */
.sitefoot-brand-wrap { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.sitefoot-brand {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  font-weight: 900; letter-spacing: 0.06em; font-size: 16px;
  color: var(--text); text-decoration: none;
}
.sitefoot-links { display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; }
.sitefoot-links a {
  /* flex 자식은 display 가 블록화되므로 인라인 예외에 해당하지 않음. 규격을 맞춤 */
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 6px;
  font-size: var(--fs-xs); color: var(--text-dim); text-decoration: none;
}
.sitefoot-links a:hover { color: var(--primary-text); text-decoration: underline; }

/* ── 목록형 링크 ───────────────────────────────────────── */
.link-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 15px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); text-decoration: none; color: var(--text); font-size: 14.5px;
}
.link-row:hover { border-color: var(--primary); }
.link-arrow { color: var(--text-dim); font-size: 18px; }


/* ── 아이콘 (js/icons.js) ─────────────────────────────────────────────────
   크기를 CSS 로만 정함. 인라인 width/height 를 박으면 글자 크기 조절과 어긋남. */
.icon { display: inline-block; vertical-align: -0.18em; flex: none; }
.icon-xs { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 1.9; }
.icon-sm { width: var(--icon-sm); height: var(--icon-sm); }
.icon-md { width: var(--icon-md); height: var(--icon-md); }
.icon-lg { width: var(--icon-lg); height: var(--icon-lg); }
/* 타일용. 참조본이 FontAwesome 을 text-4xl/5xl 로 키워 쓴 자리를 대신함 */
.icon-xl { width: 34px; height: 34px; stroke-width: 1.5; }
.tile-wide .icon-xl { width: 44px; height: 44px; }

/* 탭바에 아이콘이 들어가면서 세로 정렬이 필요해짐 */
.tab { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.tab .icon { color: inherit; }
.tab-ico { line-height: 1; }

/* 지표 타일 머리에 아이콘을 붙여 훑을 때 구분되게 함 */
.stat-head { display: flex; align-items: center; gap: var(--sp-2); }
.stat-head .icon { color: var(--brand, currentColor); opacity: .85; }

/* 지표 목록의 키에 아이콘이 들어가면서 정렬이 필요해짐 */
.kv-key { display: inline-flex; align-items: center; gap: var(--sp-1); }
.kv-key .icon { color: var(--brand, currentColor); opacity: .8; }

/* ── 접근성 ─────────────────────────────────────────────────────────────────
   왜 `:focus-visible` 인가: `:focus` 만 쓰면 마우스 클릭에도 테두리가 남아 시각 소음이 되고,
   그것을 없애려 `outline:none` 을 쓰면 키보드 사용자가 위치를 잃음. 키보드 조작일 때만 보이는
   `:focus-visible` 이 두 요구를 함께 만족함. 종전 선언은 `.input` 1건뿐이었음. */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.btn:focus-visible,
.tab:focus-visible,
.page-btn:focus-visible,
.kpoms-opt:focus-visible, .casp-opt:focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm, 4px);
}

/* 상호작용 요소의 최소 타겟을 전역으로 보장함(개별 선언 누락에 대한 안전망) */
.btn, .page-btn, .tab, .kpoms-opt, .casp-opt { min-height: 44px; }

/* 동작 저감. 어지럼증·전정 장애 이용자 보호. 고령 참여자 대상이라 특히 필요함 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 주별 목표 달성 막대 ──────────────────────────────────
 * 캔버스 차트(lineChart)를 쓰지 않는 이유: 항목이 8개뿐이라 눈금·축이 필요 없고,
 * DOM 막대는 스크린리더가 숫자를 읽을 수 있음(캔버스는 읽지 못함). */
.goalbars {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: 6px; align-items: end; height: 132px; margin-top: 4px;
}
.goalbar { display: flex; flex-direction: column; align-items: center; gap: 3px; height: 100%; }
.goalbar-track {
  flex: 1; width: 100%; display: flex; align-items: flex-end;
  background: var(--bg); border-radius: var(--radius-sm);
}
/* 0 회인 주도 흔적을 남김. 막대가 아예 없으면 "데이터 없음"과 구분되지 않음 */
.goalbar-fill { width: 100%; min-height: 3px; border-radius: var(--radius-sm); }
.goalbar-num { font-size: var(--fs-xs); font-weight: 700; color: var(--text); }
.goalbar-week { font-size: var(--fs-xs); color: var(--text-dim); }

/* ── 의견 보내기 ──────────────────────────────────────────
 * 별점은 라디오로 둠. 눌린 상태가 스크린리더에 그대로 전달되고 라벨이 44px 타겟이 됨.
 * 별 모양만 있는 버튼은 무엇을 뜻하는지 소리로 전달되지 않음. */
.fb-stars { display: flex; flex-wrap: wrap; gap: 6px; }
.fb-star {
  flex: 1 1 auto; justify-content: center; gap: 6px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 0 8px; font-weight: 700;
}
.fb-star:has(input:checked) {
  background: var(--primary-soft); border-color: var(--primary);
  color: var(--primary-text);
}
/* 구분선으로 나뉜 목록 행. 종전에는 `.fb-item`(세로 쌓기)과 `.pt-item`(가로 배치)이
 * 따로 있었음. 테두리·여백 규칙이 같으므로 하나로 두고 방향만 변형으로 나눔. */
.list-row {
  padding: 10px 0; border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 5px;
}
.list-row:first-child { border-top: 0; }
/* 한 줄에 라벨·값·시각을 늘어놓는 변형(포인트 적립 내역 등) */
.list-row-flat { flex-direction: row; align-items: center; gap: 10px; padding: 9px 0; }
.fb-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* 짧은 상태 라벨. `.chip` 과 모양이 같으나 글자색이 다름(`--primary-text` vs
 * `--primary-dark`) — 이쪽이 대비 기준을 통과하는 값임. `.chip` 은 참조본 계승 자리에만
 * 남기고 새 자리에는 이것을 쓸 것. */
.badge-soft {
  padding: 2px 8px; border-radius: 999px; font-size: var(--fs-xs); font-weight: 700;
  background: var(--primary-soft); color: var(--primary-text);
}
.fb-score { font-weight: 700; font-variant-numeric: tabular-nums; }
/* 목록 행의 시각 표기. `.fb-when`·`.pt-when` 을 합침 */
.row-when { font-size: var(--fs-xs); color: var(--text-dim); }
/* 사용자가 쓴 글이므로 줄바꿈을 보존함. 눌러 버리면 문단이 뭉개짐 */
.fb-body { margin: 0; white-space: pre-wrap; word-break: break-word; }

/* ── 포인트 ──────────────────────────────────────────────
 * 다른 화면과 달리 숫자를 크게 보임. 이 화면의 목적이 참여 유도이기 때문임.
 * 다만 연구 지표가 아니라는 고지를 규칙 카드에 함께 둠(서버가 준 문장). */
.pt-hero { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.pt-total {
  font-size: 44px; font-weight: 800; line-height: 1.05;
  color: var(--primary-text); font-variant-numeric: tabular-nums;
}
.pt-unit { font-size: var(--fs-md); color: var(--text-dim); }
/* 등급 구간 안에서의 진행률. 총점 대비로 그리면 등급이 오를수록 막대가 거의 안 움직임 */
.pt-bar { margin-top: 10px; }
.pt-reason { flex: 1; }
.pt-amount {
  font-weight: 800; color: var(--good-text); font-variant-numeric: tabular-nums;
}
.pt-rules { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 4px; }

/* 근거 카드의 제목 아이콘. 참조본은 제목 앞에 이모지를 붙였고 그 자리를 SVG 로 대신함 */
.evi-title { display: flex; align-items: center; gap: 7px; }
.evi-icon { color: var(--primary-text); flex: none; }
/* 아이콘 + 글자 링크. 아이콘이 글자 기준선에 맞게 붙음 */
.link-with-icon { display: inline-flex; align-items: center; gap: 7px; }

/* 도전과제 별. 활자 부호(★)를 SVG 로 바꾼 자리. 달성 여부를 색과 채움으로 함께 구분함
 * (색만으로 구분하면 색을 구분하기 어려운 이용자에게 전달되지 않으므로 aria-label 을 둠) */
.ach-mark.ach-on  { color: var(--warn-text); }
.ach-mark.ach-on  svg { fill: currentColor; }
.ach-off { color: var(--border-strong); }
.ach-diff { display: inline-flex; gap: 1px; color: var(--warn-text); }
.ach-diff svg { fill: currentColor; }

/* ── 글자 크기 단계 ─────────────────────────────────────
 * `document.documentElement.dataset.fs` 로 붙음. 값이 없으면 기본(1.0)임 —
 * 저장된 설정이 없을 때 조용히 다른 크기로 뜨지 않게 함. */
:root[data-fs="large"] { --fs-scale: 1.12; }
:root[data-fs="xlarge"] { --fs-scale: 1.26; }

/* 크기 고르개. 세 칸이 같은 폭을 갖게 해 어느 것이 켜졌는지 위치로도 알 수 있게 함 */
.fs-picker { display: flex; gap: 6px; }
.fs-opt {
  flex: 1 1 0; min-height: 44px; display: flex; align-items: center;
  justify-content: center; gap: 8px; cursor: pointer;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface);
}
.fs-opt:has(input:checked) {
  background: var(--primary-soft); border-color: var(--primary);
  color: var(--primary-text); font-weight: 800;
}
/* 보기 글자. 각 칸의 실제 크기를 미리 보임 — 이름만으로는 얼마나 커지는지 알 수 없음 */
.fs-sample-s { font-size: 15px; }
.fs-sample-m { font-size: 17px; }
.fs-sample-l { font-size: 19px; }

/* 로그인·가입 전환 안내. 분절 버튼(두 칸 중 하나를 고름)을 대신함 —
 * 지금 어느 화면인지는 카드 제목이 말하고, 이 줄은 "다른 일을 하려면" 만 안내함. */
.auth-switch {
  margin: 4px 0 0; text-align: center; font-size: var(--fs-sm); color: var(--text-dim);
}
.auth-switch a {
  color: var(--primary-text); font-weight: 700; text-decoration: underline;
  /* 손가락 타겟. 문단 안 인라인 링크라 44px 규격 예외이나, 이 링크는 화면의 주 동작에
   * 가까우므로 여백으로 누를 면적을 넓힘 */
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 8px;
}

/* ── 3단 흐름 단계 표시 ────────────────────────────────
 * 루틴은 중간에 놓치면 처음부터 다시 해야 하는 구조라 현재 위치가 보여야 함.
 * 색만으로 표시하지 않음 — 번호를 함께 두고 `aria-current` 로 소리에도 전달함. */
.steps {
  list-style: none; margin: 0 0 4px; padding: 0;
  display: flex; gap: 6px; align-items: stretch;
}
.step {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 8px 4px; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--border);
  font-size: var(--fs-xs); color: var(--text-dim);
}
.step-num {
  width: 24px; height: 24px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg); color: var(--text-dim); font-weight: 800;
}
.step-label { text-align: center; word-break: keep-all; line-height: 1.3; }
/* 지난 단계. 흐릿하게 두지 않고 완료로 표시함 — 흐릿함은 '못 씀' 으로 읽힘 */
.step-done { border-color: var(--good-text); color: var(--good-text); }
.step-done .step-num { background: var(--good-text); color: #fff; }
/* 현재 단계 */
.step-on {
  border-color: var(--primary); background: var(--primary-soft);
  color: var(--primary-text); font-weight: 800;
}
.step-on .step-num { background: var(--primary); color: #fff; }

/* 설문 쪽 넘김. 58문항 × 5선택 = 290버튼이 한 화면에 있던 것을 10문항씩 나눔.
 * 문항·순서·척도는 그대로임(검증된 도구라 배정을 바꾸면 과거 응답의 의미가 달라짐). */
/* `[hidden]` 은 UA 규칙이라 클래스의 `display` 에 덮임(`.kpoms-item { display: flex }`).
 * 명시적으로 막지 않으면 감춘 문항이 그대로 보이고, 손가락 타겟 실측에도 계속 잡힘.
 * 실측으로 확인함 — 쪽을 나눴는데 조작 요소가 294개로 그대로였음.
 *
 * **선택자 목록에서 한정자는 항목마다 따로 붙여야 함.** 이 줄이 한동안
 * `.kpoms-item, .casp-item[hidden]` 이었고, 그것은 "모든 `.kpoms-item`" 과
 * "`[hidden]` 인 `.casp-item`" 을 뜻함 — **K-POMS 문항 58개가 통째로 사라져 있었음**
 * (2026-09-22 제보). 같은 실수가 이 파일에 네 군데 있었고 전부 고쳤음. */
.kpoms-item[hidden], .casp-item[hidden] { display: none; }

.kpoms-pager {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding-top: 12px; margin-top: 10px; border-top: 1px solid var(--border);
}
.kpoms-page-label {
  flex: 1; text-align: center; font-size: var(--fs-sm); font-weight: 700;
  color: var(--text-dim); font-variant-numeric: tabular-nums;
}

/* ── 정적 자산 자리표시 ──────────────────────────────────
 * 참조본 번들에 `public/` 이 없어 이미지가 실물로 존재하지 않음. 깨진 이미지를 보이면
 * 고장으로 읽히므로 글자 표식으로 자리·비율을 지킴. 파일을 넣으면 그림으로 바뀜.
 * 넣을 파일 목록은 `assets/images/README.md` 임. */
.asset { display: flex; align-items: center; justify-content: center; }
.asset-img { display: block; max-width: 100%; height: auto; }
/* 사진 자리를 꽉 채움(비율이 다른 원본이 와도 자리 모양이 유지되어야 함) */
.prof-photo .asset-img { width: 100%; height: 100%; object-fit: cover; }
.asset-ph {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; width: 100%; height: 100%;
  /* 점선으로 "여기에 자산이 들어올 자리" 임을 알림. 실선으로 두면 완성된 요소로 보임 */
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text-dim);
}
.asset-ph-main { font-weight: 800; color: var(--text); }
.asset-ph-sub { font-size: var(--fs-xs); }
/* 자산이 들어오면 자리표시의 테두리·배경이 필요 없음 */
.asset-ready { border: 0; background: none; }
.asset-ready .asset-ph { display: none; }

/* 설치 안내 스크린샷 띠. 자산이 없으면 자식이 빈 상자라 높이가 0 이 되어 아무것도
 * 보이지 않음(그림 없이도 성립하는 화면이라 자리표시를 두지 않음 — `js/views/download.js`). */
.shot-strip { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.shot-strip:empty { display: none; }
.shot { flex: 1 1 150px; max-width: 240px; }
.shot .asset-img { border: 1px solid var(--border); border-radius: var(--radius-sm); }

/* 로그인 화면의 접힘 안내(비밀번호 분실 등). 기본 화살표를 그대로 쓰되 손가락 타겟을
 * 확보함 — details/summary 는 기본 높이가 작아 44px 요건에 미달함. */
.auth-help { margin-top: 4px; }
.auth-help > summary {
  display: flex; align-items: center; min-height: 44px; padding: 0 2px;
  cursor: pointer; color: var(--primary-text); font-size: var(--fs-sm); font-weight: 700;
}
.auth-help > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.auth-help p { margin: 4px 2px 0; }

/* ══════════════════════════════════════════════════════════════════════
 * 데스크톱 레이아웃은 **파일 맨 끝**에 둠.
 *
 * 미디어쿼리는 특정도를 올려 주지 않음. 그래서 `@media` 안의 `.tiles` 를 파일 중간에
 * 두었을 때, 뒤쪽(885줄 부근)의 평범한 `.tiles { display: flex }` 가 같은 특정도로
 * **나중에 나와서 이겼음** — 넓은 화면에서 격자가 전혀 적용되지 않았고, 1440px 로 렌더해
 * 눈으로 보고서야 알았음. 셀렉터를 억지로 무겁게 만들지 않고 순서로 해결함.
 *
 * 이 아래에 평범한 규칙을 추가하지 말 것. 추가하면 같은 함정에 다시 빠짐.
 * ══════════════════════════════════════════════════════════════════════ */
/* ── 데스크톱 레이아웃 ─────────────────────────────────────
 * 종전에는 데스크톱 분기가 위 한 줄(`.quick` 4열)뿐이었음. 나머지는 모바일 컬럼을
 * 그대로 늘려 놓은 상태라, 넓은 화면에서 빈 여백만 커졌음.
 * 모바일 우선 구조는 유지하고 넓어질 때만 얹음(작은 화면 동작은 바뀌지 않음). */
@media (min-width: 1024px) {
  /* 히어로: 표제와 로고를 나란히. 종전에는 세로로 쌓여 화면 첫 화면이 비어 보였음 */
  /* 표제 · 곱셈기호 · 로고 세 칸. 종전에 2칸으로 두었더니 자식이 셋이라 기호가
   * 다음 줄로 밀려 화면에서 사라졌음(1440px 렌더로 확인함). */
  .hero {
    display: grid; grid-template-columns: 1fr auto auto; align-items: center;
    gap: 24px; text-align: left; padding: 34px 0 18px;
  }
  .hero-title { font-size: 40px; }
  /* 두 대상이 나란해졌으므로 이제 뜻이 있음 */
  .hero-x { display: block; margin: 0; align-self: center; font-size: 24px; }
  .hero-mark { min-width: 220px; }

  /* 타일(`/about`): 모바일과 같은 **줄 구조**를 넓은 화면에서도 그대로 씀 — 빈칸이 구조상 생기지 않음.
   *
   * 종전에는 `.tile-row` 를 `display: contents` 로 풀어 2열(1440px 부터 4열) 격자에 흘렸고, 빈칸이
   * 생기지 않는 것은 "묶음마다 칸 수가 열 수의 배수" 라는 **손으로 센 약속**에 기대고 있었음. 그 약속이
   * 두 번 조용히 깨졌음 — 삶의 질 검사 타일을 계승 줄에 넣었을 때(ADR-109)와 플레이리스트 운동 넓은
   * 타일을 신규 묶음에 더했을 때(ADR-176). 2026-10-18 계산(현황검토 A24): 신규 6칸 · 기존 7칸(로그인
   * 9칸)이라 2열에서 끝에 1칸, 4열에서는 신규 묶음 끝에 2칸·기존 묶음 끝에 1~3칸이 비었음.
   *
   * 지금은 `.tile-row` 한 줄이 곧 화면의 한 줄임(flex 행, 자식이 폭을 나눠 가짐). 넓은 타일은 홈('/')의
   * 큰 타일처럼 한 줄을 다 씀. 한 줄의 타일 수·로그인 여부가 바뀌어도 빈칸이 생길 수 없으므로 칸 수를
   * 셀 필요가 없음. 레거시 첫 화면도 '넓은 타일 하나 + 두 개씩 나란한 줄' 의 줄 구조였음.
   * 폭은 근거 카드 절(`.evidence`)과 같은 860px 로 묶음 — 묶지 않으면 1440px 에서 넓은 타일이 1128px
   * 띠가 됨. 가운데 정렬은 `align-self` 로 함(아래 `.seg`·`.cta` 주석과 같은 이유). */
  .tiles { gap: 14px; width: 100%; max-width: 860px; align-self: center; }
  .tile-row { gap: 14px; }
  .tile-wide .tile-label { font-size: 27px; }
  /* 넓은 화면에서는 타일 높이를 키움(같은 줄의 타일은 가장 큰 것에 맞춰 늘어남). 안쪽 배치를
   * 위·아래로 벌려 제목과 설명이 붙어 보이지 않게 함 */
  .tiles .tile { justify-content: space-between; min-height: 116px; }
  .tiles .tile-wide { min-height: 132px; }

  /* 데이터 카드: 두 벌로 나눠 스크롤을 줄임. 넘치는 카드는 통째로 한 줄을 씀 */
  .view-2col {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px; align-items: start;
  }
  .view-2col > .col-full { grid-column: 1 / -1; }

  /* 분절 버튼·행동 버튼: 폭을 다 먹지 않게 함. 1000px 짜리 알약은 조작으로 읽히지 않음.
   * 왼쪽에 붙이면 화면 축과 어긋나 보이므로 **가운데**에 둠(`.view` 가 flex 컬럼이라
   * auto 마진은 폭을 줄여 버림 — `align-self` 를 씀). */
  .seg { width: 100%; max-width: 620px; align-self: center; }
  .cta { width: 100%; max-width: 460px; align-self: center; }
  .cta .btn-block { width: 100%; }
}
@media (min-width: 1440px) {
  .hero-title { font-size: 46px; }
}

@media (min-width: 1024px) {
  /* 근거 카드 — 좌/우 번갈아 배치는 참조본 계승분임(`landing.js` EVIDENCE 주석).
   *
   * **카드가 아니라 절을 묶음.** 카드에 `max-width` + `margin-left: auto` 를 주었더니
   * 카드가 내용 폭으로 쪼그라들고 세로 간격이 벌어졌음 — flex 자식에 auto 마진을 주면
   * 그 축에서 늘어나기를 멈추기 때문임(1440px 렌더로 확인함). 절 폭만 좁히면 카드는
   * 그대로 늘어나고, 계승한 좌/우 마진이 모바일과 같은 리듬으로 읽힘. */
  .evidence { max-width: 860px; margin-left: auto; margin-right: auto; }

  /* 연구실 소개로 가는 줄은 `.cta` 안에 있음(`landing.js`). 그 폭은 위 `.cta` 규칙이
   * 정하므로 여기서 따로 잡지 않음 — 두 곳에서 잡으면 어느 쪽이 이겼는지 알기 어려워짐. */
}

/* ── 헤더 회원 메뉴 ────────────────────────────────────────
 * 참조본 헤더의 로그인·계정·로그아웃·관리 진입을 되살린 것(`js/main.js` paintAccount).
 * 드롭다운이 아니라 버튼 나열임 — 고령 이용자 대상이라 접었다 펴는 단계를 늘리지 않음.
 * 좁은 폭에서는 라벨이 길어 넘치므로 앱바가 접히게 두고 타겟 높이는 유지함. */
.appbar-account { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.appbar-btn {
  display: inline-flex; align-items: center; justify-content: center;
  /* 손가락 타겟 44px. 36px 로 두었더니 렌더 검사가 잡았음 — 앱바 높이(52px) 안에
   * 들어가면서 44px 을 만족하는 값임. */
  min-height: 44px; padding: 0 12px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none; cursor: pointer; white-space: nowrap;
}
.appbar-btn:hover { border-color: var(--primary); color: var(--primary-text); }
.appbar-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.appbar-btn-primary {
  background: var(--primary); border-color: var(--primary); color: #fff;
}
.appbar-btn-primary:hover { background: var(--primary-dark); color: #fff; }
/* 좁은 폭: 역할 표기를 숨겨 자리를 버는 것이 조작 버튼보다 뒤임(조작이 먼저 보여야 함) */
@media (max-width: 560px) {
  .appbar-role { display: none; }
  /* 좁은 폭에서도 높이는 줄이지 않음. 가로 여백과 글자만 줄임 */
  .appbar-btn { padding: 0 9px; font-size: var(--fs-xs); }
}
@media (min-width: 1024px) {
  .appbar-btn { padding: 0 14px; }
}

/* ── 측정 중 전체화면 ──────────────────────────────────────
 * 참조본은 실시간 화면에서 헤더·푸터를 렌더하지 않았음(`useAutoHideUI.ts`).
 * 우리는 한 화면에서 설정과 측정을 다 하므로 세션 상태로 토글함
 * (`js/views/exercise.js` 의 `setMeasuringChrome`).
 *
 * 왜 필요한가: 앱바 52px + 탭바 62px + 푸터가 측정 중에도 남아 390px 기기에서 미리보기와
 * 게이지·교정 문구가 같은 화면에 들어가기 어려웠음. 측정 중에는 탐색이 필요하지 않고
 * 화면이 필요함.
 *
 * 탐색을 없애는 대신 화면 안에 '종료' 버튼이 있음(측정 카드의 조작부). 그것이 없으면
 * 이용자가 갇히므로, 이 규칙을 손댈 때 그 버튼이 남아 있는지 함께 확인할 것. */
body.measuring .appbar,
body.measuring .tabbar,
body.measuring .sitefoot { display: none; }
body.measuring { padding-bottom: 0; }
body.measuring .outlet { padding-top: 10px; max-width: 900px; }
/* 측정 카드가 화면 높이를 쓰게 함. 게이지·미리보기가 접히지 않고 한눈에 들어와야 함 */
body.measuring .view { gap: 10px; }

@media (min-width: 1024px) {
  /* 참조본이 데스크톱 2열·3열로 지정한 세 곳. 종전에는 폭이 아무리 넓어져도 모바일
   * 세로 1열로 남아, 1180px 에서 운영진이 7단으로 늘어져 참조본보다 훨씬 긴 스크롤이
   * 됐음(참조본 근거: LandingLabIntroduction.tsx:56 `lg:flex-row` · :115
   * `lg:grid-cols-3` · footer.tsx:34 `lg:flex-row`).
   *
   * 교수 소개: 사진 왼쪽 + 약력 오른쪽. 참조본은 3:4 세로 패널이었으므로 원형 아바타를
   * 세로 패널로 바꿈 — 자산을 넣었을 때 참조본과 같은 화면이 되어야 함. */
  /* 사진 왼쪽 + 약력 오른쪽. 참조본 비율(3:4 세로 패널)을 지킴 */
  .prof { flex-direction: row; align-items: flex-start; gap: 28px; }
  .prof-figure { flex: 0 0 auto; align-items: flex-start; }
  .prof-photo { width: 300px; height: 400px; border-radius: var(--radius); }
  .prof-body { flex: 1 1 0; min-width: 0; text-align: left; }
  .prof-body .degree-list { text-align: left; margin-top: 0; }
  /* 약력과 같은 왼쪽 정렬(종전에는 이 줄만 가운데라 어긋나 보였음) */
  .prof-body .prof-field { text-align: left; }
  .prof-body .prof-contact { justify-content: flex-start; }

  /* 운영진 3열 */
  .op-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; }

  /* 푸터 좌우 배치(레거시와 같게 로고·저작권은 왼쪽, 약관 링크는 오른쪽) */
  .sitefoot { flex-direction: row; justify-content: space-between; align-items: center; }
  .sitefoot-brand-wrap { align-items: flex-start; }
}

/* 설치 안내 — 단계와 그림을 짝지어 보임(`js/views/download.js`).
 * 참조본은 각 단계 옆에 그 단계의 스크린샷을 뒀음. 그림이 없으면 문장만 남고 자리도
 * 차지하지 않음(그림 없이도 따라갈 수 있게 만든 성질을 유지함). */
.steps-shot { display: flex; flex-direction: column; gap: 14px; }
.steps-shot > li { display: flex; flex-direction: column; gap: 8px; }
.step-shot:empty { display: none; }
.step-shot .asset-img {
  max-width: 100%; border: 1px solid var(--border); border-radius: var(--radius-sm);
}
@media (min-width: 1024px) {
  /* 넓은 화면에서는 문장 왼쪽 · 그림 오른쪽. 참조본 데스크톱 배치와 같은 성질임 */
  .steps-shot > li {
    flex-direction: row; align-items: flex-start; gap: 18px;
  }
  .steps-shot .step-text { flex: 1 1 0; min-width: 0; }
  .steps-shot .step-shot { flex: 0 0 300px; }
}

/* 랜딩 안의 연구실 소개 절. `/lab` 과 같은 생성부를 쓰므로 그쪽 스타일이 그대로 적용됨.
 * 랜딩에서는 페이지 제목이 아니라 절 제목이라 위 여백만 벌림. */
.lab-inline { padding-top: 10px; }
.lab-inline .view { gap: 14px; }

/* 처리방침·약관 절의 도입문. 목록 앞에 오는 문장이라 목록과 시각적으로 구분되어야 함
 * (참조본은 `<br/>` 로 띄웠음). */
.legal-lead { margin: 2px 0 8px; line-height: 1.7; }

/* K-POMS 평가 기준(척도 앵커). 참조본은 문항 위에 항상 띄워 두었음.
 * 종전에는 버튼 `title` 에만 있어 터치 기기에서 숫자의 뜻을 알 수 없었음. */
.kpoms-legend, .casp-legend {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px;
  padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--primary-soft); font-size: var(--fs-sm);
}
.kpoms-legend-head, .casp-legend-head { font-weight: 800; color: var(--primary-text); }
.kpoms-legend-items, .casp-legend-items { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.kpoms-legend-item, .casp-legend-item { white-space: nowrap; }

@media (min-width: 1024px) {
  /* 인증·설문 폼의 폭 제한.
   *
   * 종전에는 상한이 없어 데스크톱에서 이메일·비밀번호 입력칸이 1000px 가까이 늘어났음.
   * 입력칸이 길면 어디를 보고 채워야 하는지 흐려지고, 참조본도 `container` 로 폭을
   * 묶고 있었음(tailwind.config.js 의 sm 640 ~ xl 1280 단계).
   *
   * 카드째로 묶음 — 입력 하나씩 잡으면 라벨과 어긋남. */
  .view-login > .card,
  .view-login > .auth-switch,
  .view-login > .cta,
  .view-login > * { width: 100%; max-width: 460px; align-self: center; }
  /* 설문은 문항이 길어 폼보다 넓게 두되 글줄 길이는 지킴 */
  .view-kpoms > .card { width: 100%; max-width: 860px; align-self: center; }
}

/* 거울(전면 카메라 미리보기). 참조본의 '보면서 따라 하기' 를 되살린 것(`js/mirror.js`).
 * 켜기 전에는 자리만 지킴 — 카드가 빈 상자로 보이면 고장으로 읽힘. */
.mirror { display: flex; flex-direction: column; gap: 10px; }
.mirror-slot {
  position: relative; width: 100%; aspect-ratio: 3 / 4;
  max-height: 380px; overflow: hidden;
  border-radius: var(--radius); border: 1px dashed var(--border-strong);
  background: var(--bg);
  display: flex; align-items: center; justify-content: center;
}
.mirror-slot::after {
  content: '카메라를 켜면 여기에 내 모습이 보입니다';
  padding: 0 16px; text-align: center;
  color: var(--text-dim); font-size: var(--fs-sm);
}
.mirror-slot.mirror-on { border-style: solid; border-color: var(--border); background: #000; }
.mirror-slot.mirror-on::after { content: none; }
.mirror-video {
  width: 100%; height: 100%; object-fit: cover; display: none;
  /* 거울이므로 좌우를 뒤집음. 뒤집지 않으면 "오른손을 드세요" 가 화면에서 왼쪽으로 보임 */
  transform: scaleX(-1);
}
.mirror-on .mirror-video { display: block; }
@media (min-width: 1024px) {
  /* 넓은 화면에서는 가로가 더 자연스러움(참조본도 가로 화면을 권했음) */
  .mirror-slot { aspect-ratio: 4 / 3; max-height: 420px; }
}

/* 리포트 기관 로고. 참조본은 머리·꼬리 양쪽에 140×140 로 두었음.
 * 인쇄물이므로 자산이 없을 때도 발행 주체가 글자로 남아야 함(자리표시가 그 역할). */
.sheet-logo { width: 120px; max-width: 34vw; }
.sheet-logo .asset-ph { min-height: 64px; padding: 8px; }
.sheet-tail { display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; }
.sheet-tail .sheet-foot { margin: 0; }
@media print {
  /* 인쇄에서는 로고가 확실히 나와야 함(배경 그림이 아니라 <img> 이므로 기본으로 나옴) */
  .sheet-logo { width: 110px; }
}

/* 루틴 수행 중 하단 고정 액션바. 참조본은 '다음 운동' 을 화면 하단에 고정해 설명을
 * 스크롤하다가도 바로 넘어갈 수 있었음. 종전에는 문서 맨 끝에 있어 매번 끝까지 내려야 했음.
 *
 * 탭바(62px) 위에 얹되, 측정 중에는 탭바가 없으므로 그때는 바닥까지 내려감. */
.cta-fixed {
  position: fixed; left: 0; right: 0; bottom: var(--tabbar-h);
  z-index: 5; margin: 0; padding: 10px 14px;
  background: var(--surface); border-top: 1px solid var(--border);
  box-shadow: 0 -4px 14px rgba(16, 24, 40, 0.06);
  display: flex; flex-direction: column; gap: 8px;
}
body.measuring .cta-fixed { bottom: 0; }
/* 문서 끝의 자리 — 고정 버튼이 마지막 내용을 가리지 않게 함. 버튼 수에 따라 높이가
 * 달라지므로 넉넉히 둠(가려지는 것보다 여백이 남는 편이 안전함). */
.cta-fixed-spacer { height: 168px; }
@media (min-width: 1024px) {
  /* 넓은 화면에서는 본문 폭 안에 맞춰 가운데로. 화면 전폭 띠는 데스크톱에서 과함 */
  .cta-fixed {
    left: 50%; right: auto; transform: translateX(-50%);
    width: min(560px, calc(100% - 44px));
    border: 1px solid var(--border); border-radius: var(--radius);
    bottom: calc(var(--tabbar-h) + 12px);
  }
  .cta-fixed-spacer { height: 140px; }
}

@media (min-width: 1024px) {
  /* 운동 검색 결과 — 참조본은 데스크톱에서 격자였음(우리는 세로 1열이라 결과가 많으면
   * 스크롤만 길어졌음). 카드가 작아 3열, 넓은 화면에서 4열. */
  .ex-results { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
  .ex-results > .card { grid-column: 1 / -1; }
  .ex-results .ex-card { height: 100%; }
}
@media (min-width: 1440px) {
  .ex-results { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* K-POMS 응답 결과 원자료. 전송될 58자 문자열을 그대로 보임(참조본과 같음).
 * 등폭 글꼴로 두어 자릿수를 셀 수 있게 함. 길어서 반드시 줄바꿈되어야 함. */
.kpoms-raw-text, .casp-raw-text {
  display: block; padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--bg); border: 1px solid var(--border);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fs-sm); line-height: 1.8;
  word-break: break-all; letter-spacing: 1px;
}

/* 로그인 화면의 전환 안내(기존 사이트는 닉네임 로그인이었음). 입력란 바로 아래에 두어
 * 무엇을 넣어야 하는지 채우기 전에 읽히게 함. */
.auth-note { margin-top: 2px; }

/* 차트 범례. 계열이 둘 이상인 차트(심박+칼로리, 수축기+이완기 혈압)에 붙음.
 * 색만으로 구분하지 않도록 이름을 함께 적음 — 흑백 인쇄와 색각 이상 모두 대응. */
.chart-legend { display: flex; flex-wrap: wrap; gap: 8px 18px; padding-top: 8px; }
.chart-legend-item {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-sm); color: var(--text-dim);
}
.chart-legend-dot {
  width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
  border: 1px solid rgba(0, 0, 0, 0.14);
}

/* 절차 문장 안에서 눌러야 할 UI 이름. 참조본은 파란 칩으로 지목했음.
 * 평문이면 어느 것을 눌러야 하는지 문장 안에서 튀지 않음. */
.ui-chip {
  display: inline-block; padding: 1px 7px; margin: 0 1px;
  border-radius: 6px; background: var(--primary-soft); color: var(--primary-text);
  font-weight: 700; white-space: nowrap;
}

/* ── 서식 있는 본문(richtext.js) ───────────────────────── */
/* 참조본은 TipTap 으로 저장한 HTML 을 그대로 렌더했음(굵게·목록·표·이미지·영상).
 * 우리는 평문만 보이다가 정화기를 두면서 서식을 되살렸음. 여기가 그 표현 규칙임.
 *
 * 회원이 쓴 본문이 우리 화면 구조를 흔들지 못하게 **범위를 `.rt` 안으로 한정**함.
 * 정화기가 클래스를 걸러내지만(허용 목록), 태그 자체는 통과하므로 표현은 여기서 잠금. */
.rt { font-size: 15.5px; line-height: 1.75; word-break: break-word; }
.rt > *:first-child { margin-top: 0; }
.rt > *:last-child { margin-bottom: 0; }
.rt p { margin: 0 0 0.85em; }
.rt h1, .rt h2, .rt h3, .rt h4, .rt h5, .rt h6 {
  margin: 1.4em 0 0.5em; line-height: 1.35; font-weight: 750;
}
/* 본문 제목이 화면 제목(.page-head 19px)보다 커지지 않게 눌러 둠 — 회원이 h1 을 쓰면
 * 글이 화면 제목보다 크게 보여 어디가 화면 제목인지 알 수 없어짐. */
.rt h1 { font-size: 18px; }
.rt h2 { font-size: 17px; }
.rt h3 { font-size: 16px; }
.rt h4, .rt h5, .rt h6 { font-size: 15.5px; }
.rt ul, .rt ol { margin: 0 0 0.85em; padding-left: 1.4em; }
.rt li { margin: 0.2em 0; }
.rt ul { list-style: disc; }
.rt ol { list-style: decimal; }
.rt strong, .rt b { font-weight: 750; }
.rt a { color: var(--primary-text); text-decoration: underline; text-underline-offset: 2px; }
.rt blockquote {
  margin: 0 0 0.85em; padding: 2px 0 2px 12px;
  border-left: 3px solid var(--border-strong); color: var(--text-dim);
}
.rt pre {
  margin: 0 0 0.85em; padding: 10px 12px; overflow-x: auto;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--fs-sm);
}
.rt code {
  padding: 1px 5px; border-radius: 4px; background: var(--bg);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.92em;
}
.rt pre code { padding: 0; background: none; }
.rt img {
  max-width: 100%; height: auto; display: block;
  margin: 0.6em 0; border-radius: var(--radius-sm);
}
.rt figure { margin: 0.8em 0; }
.rt figcaption { font-size: var(--fs-xs); color: var(--text-dim); padding-top: 4px; }
.rt hr { border: 0; border-top: 1px solid var(--border); margin: 1.2em 0; }
.rt mark { background: var(--warn-soft); color: var(--warn-text); padding: 0 2px; }
/* 표는 좁은 화면에서 넘칠 수 있음. 본문이 옆으로 흐르지 않게 표만 스크롤시킴. */
.rt table {
  display: block; overflow-x: auto; width: 100%; max-width: 100%;
  border-collapse: collapse; margin: 0 0 0.85em; font-size: var(--fs-sm);
}
.rt th, .rt td { border: 1px solid var(--border); padding: 6px 9px; text-align: left; }
.rt th { background: var(--bg); font-weight: 700; }
.rt-left { display: block; text-align: left; }
.rt-center { display: block; text-align: center; }
.rt-right { display: block; text-align: right; }
.rt-mention { color: var(--primary-text); font-weight: 700; }
.rt-highlight { background: var(--warn-soft); }
.rt-block { display: block; }

/* 영상 파사드. 누를 때까지 외부에 아무 요청도 보내지 않음(richtext.js 머리말 참조). */
.rt-video { margin: 0.8em 0; }
.rt-video-play {
  width: 100%; aspect-ratio: 16 / 9; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--bg); cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  font: inherit; font-weight: 700; color: var(--text);
}
.rt-video-play:hover { background: var(--p0); border-color: var(--primary); }
/* 재생 삼각형. 아이콘 세트를 쓰지 않는 이유: 크게 보여야 하고 채워진 도형이라야
 * '재생' 으로 읽힘(우리 아이콘은 선 기반임). */
.rt-video-tri {
  width: 0; height: 0; border-style: solid;
  border-width: 13px 0 13px 22px;
  border-color: transparent transparent transparent var(--primary);
}
.rt-video-frame { width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: var(--radius); }
.rt-video-note { font-size: var(--fs-xs); color: var(--text-dim); padding-top: 5px; }
.rt-video-note a { color: var(--primary-text); }

/* 운동 설명 본문. 본문 서식을 쓰되 글자를 조금 크게 둠 — 운동하면서 보는 글임. */
.ex-body { font-size: 16px; }
.ex-excerpt {
  font-size: var(--fs-xs); color: var(--text-dim); line-height: 1.5; text-align: left;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ── 아바타(ui.js) ─────────────────────────────────────── */
/* 참조본은 Mantine 의 빈 회색 원을 썼음. 사진이 없으므로 머리글자를 넣음 —
 * 빈 원을 나란히 두면 글쓴이 구분이 되지 않아 장식만 됨.
 * 색조만 닉네임 해시로 바꾸고 채도·명도는 고정함(명도대비 검사를 통과한 조합 유지). */
.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; flex: 0 0 auto; font-weight: 800; line-height: 1;
  background: hsl(var(--avatar-hue, 210) 62% 92%);
  color: hsl(var(--avatar-hue, 210) 72% 26%);
}
.avatar-xs { width: 18px; height: 18px; font-size: 10.5px; }
.avatar-sm { width: 26px; height: 26px; font-size: 13px; }
.avatar-md { width: 40px; height: 40px; font-size: 18px; }

/* 칩 색 변형. 강도 배지(저·중·고)가 참조본에서 녹·청·적이었음.
 * 생 색상값을 박지 않고 토큰을 씀 — 명도대비 검사를 통과한 조합을 유지하기 위함. */
.ui-chip.chip-good { background: var(--good-soft); color: var(--good-text); }
.ui-chip.chip-info { background: var(--primary-soft); color: var(--primary-text); }
.ui-chip.chip-warn { background: var(--warn-soft); color: var(--warn-text); }

/* 안드로이드 APK 안내. 사이드로드라 설치 시 경고가 뜨므로 그것을 미리 밝히는 자리임.
 * `details` 로 접어 두는 이유: 대부분은 받기만 하면 되고, 무결성 값은 확인하려는
 * 사람에게만 필요함. 처음부터 펼치면 64자 해시가 안내문을 밀어냄. */
.apk-note { padding-top: 4px; }
.apk-note > summary {
  cursor: pointer; padding: 8px 2px; min-height: 44px;
  display: flex; align-items: center;
  font-size: var(--fs-sm); font-weight: 700; color: var(--primary-text);
}
.apk-note > p { font-size: var(--fs-sm); line-height: 1.7; padding: 4px 2px; }
.apk-hash {
  display: block; padding: 8px 10px; margin: 4px 0;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; line-height: 1.6; word-break: break-all;
}

/* ── 알림 ──────────────────────────────────────────────── */
/* 앱바 종. 안 읽은 건수가 없으면 숫자를 붙이지 않음 — 0 을 표시하면 확인했는데 없는
 * 것처럼 보임(그래서 이용자가 종을 다시 누르지 않음). */
.appbar-bell { position: relative; display: inline-flex; align-items: center; gap: 5px; }
.appbar-bell.has-unread { color: var(--primary-text); font-weight: 700; }
.appbar-bell-count {
  min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 9px; background: var(--danger); color: #fff;
  font-size: 11px; font-weight: 800; line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* 좁은 화면에서는 '알림' 글자를 감추고 종만 둠. 앱바에 버튼이 셋 이상 들어가면
 * 390px 에서 줄바꿈이 생겨 헤더 높이가 두 줄이 됨. */
@media (max-width: 420px) {
  .appbar-bell-label { display: none; }
}

.notif-list { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.notif {
  display: flex; flex-direction: column; gap: 3px;
  width: 100%; padding: 11px 12px; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); text-align: left; font: inherit; color: inherit;
}
/* 안 읽은 것은 왼쪽 띠로 구분함. 색만으로 구분하지 않는 이유: 색각 이상에서 구분되지
 * 않고, 흑백 인쇄에서도 사라짐. 굵기까지 함께 바꿈. */
.notif-unread { border-left: 3px solid var(--primary); background: var(--p0); }
.notif-unread .notif-title { font-weight: 750; }
.notif-link { cursor: pointer; }
.notif-link:hover { border-color: var(--primary); }
.notif-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: var(--fs-xs); color: var(--text-dim);
}
.notif-kind { display: inline-flex; align-items: center; gap: 4px; }
.notif-when { white-space: nowrap; }
.notif-title { font-size: 15px; font-weight: 650; line-height: 1.45; }
.notif-body { font-size: var(--fs-sm); color: var(--text-dim); line-height: 1.6; }

/* 앱바 버튼의 글자. 좁은 화면에서 감춰 44x44 아이콘 버튼으로 만듦.
 *
 * 왜 필요한가: 알림 종을 더하니 관리자 앱바가 390px 에서 넘쳤음(운영 콘솔·종·내 정보·
 * 로그아웃 4개). 렌더 검증이 가로넘침과 작은 타겟을 함께 잡았음. 글자를 감추면 들어감.
 * 감춰도 뜻이 전달되는 것은 아이콘과 `aria-label` 이 함께 있기 때문임(`main.js` 의
 * `appbarBtn` 이 그것을 강제함).
 *
 * 480px 을 경계로 삼은 근거: 기준 글자 크기에서 브랜드(90px) + 아이콘 버튼 3개(132px) +
 * 로그아웃(44px) + 여백이 390px 안에 들어감. 로그인 버튼은 하나뿐이라 글자를 유지함. */
@media (max-width: 480px) {
  .appbar-btn-label { display: none; }
  .appbar-btn { min-width: 44px; padding: 0 8px; }
  .appbar-btn-wide .appbar-btn-label,
  .appbar-btn-wide { display: inline-flex; }
}
/* 넓은 화면에서는 아이콘과 글자를 함께 보임 */
.appbar-btn { gap: 5px; }
.appbar-bell { min-width: 44px; }

/* ── 신체 측정(내 화면) ─────────────────────────────────── */
/* 계획서 §6 Pre/Post 주 결과지표를 이용자가 보는 자리임. 시작 → 최근을 나란히 두어
 * "달라졌는가" 가 한눈에 읽히게 함. 남과 비교하지 않음(순위표를 두지 않은 것과 같은 판단). */
.ms-cat { display: flex; align-items: center; gap: 6px; font-size: 16px; font-weight: 750; }
.ms-list { list-style: none; display: flex; flex-direction: column; gap: 10px; padding-top: 4px; }
.ms-row { display: flex; flex-direction: column; gap: 5px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.ms-row:last-child { border-bottom: 0; padding-bottom: 0; }
.ms-row-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.ms-row-name { font-size: 15px; font-weight: 650; }
.ms-row-values { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* 값은 등폭 숫자로 두어 시작·최근이 자릿수로 어긋나 보이지 않게 함 */
.ms-val { display: inline-flex; align-items: baseline; gap: 5px; font-variant-numeric: tabular-nums; }
.ms-val strong { font-size: 17px; }
.ms-val-tag { font-size: var(--fs-xs); color: var(--text-dim); }
.ms-arrow { color: var(--border-strong); font-size: 15px; }

/* ── 시범영상(video.js · views/videos.js) ─────────────────── */
/* 목록은 제목·길이만, 플레이어는 누를 때 그 자리에. 47개 <video> 를 한 번에 만들면
 * preload=metadata 만으로 요청 47건이 나가고 모바일 스크롤이 무거워짐. */
.vid-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.vid-row {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 48px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); text-align: left; font: inherit; color: inherit; cursor: pointer;
}
.vid-row:hover { border-color: var(--primary); }
.vid-row[aria-expanded="true"] { border-color: var(--primary); background: var(--p0); }
.vid-row-off { color: var(--text-dim); }
.vid-code { flex: 0 0 auto; font-variant-numeric: tabular-nums; font-weight: 800; color: var(--primary-text); min-width: 2.6em; }
.vid-row-title { flex: 1 1 auto; min-width: 0; font-weight: 650; }
.vid-dur { flex: 0 0 auto; font-size: var(--fs-xs); color: var(--text-dim); font-variant-numeric: tabular-nums; }
.vid-slot { padding: 6px 0 2px; }
.vid { display: flex; flex-direction: column; gap: 6px; }
.vid-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.vid-title { font-weight: 700; }
/* 종횡비를 JS 가 메타에서 미리 잡아 로드 뒤 레이아웃이 튀지 않게 함. 세로(9:16)도 폭에 맞춤. */
.vid-player { width: 100%; max-height: 70vh; background: #000; border-radius: var(--radius); display: block; }
.vid-compact .vid-player { max-height: 56vh; }
/* 측정 중엔 플레이어를 만들지 않음(video.js 가 판정). 크롬이 걷힌 화면에 겹치지 않게 함. */
body.measuring .vid { display: none; }

/* ── 측정 결과: 참여자용 구성 (ADR-124) ─────────────────────────────────────
 * 종전에는 "전체 유사도 25%"·"채점 프레임 300" 이 그대로 나왔음. 참여자에게 뜻이 없고,
 * 합격선이 아직 보정되지 않아 수치가 낮게 나오므로 열심히 한 사람에게 낮은 점수를 내미는
 * 셈이었음. 한 일과 쌓인 것을 앞에 두고 수치는 접어 둠. */
.result-lead { font-size: var(--fs-lg); font-weight: 700; margin: 0 0 var(--sp-3); color: var(--ink); }

.posture { border-radius: var(--radius); padding: var(--sp-3) var(--sp-4); margin: var(--sp-3) 0 0;
  border: 1px solid var(--border); background: var(--surface-2); }
.posture-good { border-color: var(--good); background: var(--good-soft); }
.posture-head { margin: 0; font-weight: 700; font-size: var(--fs-md); color: var(--ink); }
.posture-good .posture-head { color: var(--good-text); }
.posture-cue { margin: var(--sp-1) 0 0; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.6; }

.award { margin-top: var(--sp-4); }
.award-t { margin: 0 0 var(--sp-2); font-weight: 700; color: var(--ink); }
.chip-award { background: var(--warn-soft); border-color: var(--warn); color: var(--warn-text); font-weight: 700; }

/* 측정 상세. 값을 숨기는 것이 아니라 뒤에 두는 것임 — 누르면 전부 보임. */
.detail-box > summary { cursor: pointer; font-weight: 700; color: var(--primary-text);
  padding: var(--sp-2) 0; min-height: 44px; display: flex; align-items: center; }
.detail-body { padding-top: var(--sp-2); }
.detail-row { display: flex; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); }
.detail-row:last-of-type { border-bottom: 0; }
.detail-k { color: var(--ink-2); font-size: var(--fs-sm); }
.detail-v { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ── 오늘까지 쌓인 것: 계속하게 만드는 자리 (ADR-126) ────────────────────────
 * 다음 한 걸음만 보임. 총점보다 "하루만 더 하면" 이 사람을 움직임. */
.motive-row { display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--border); }
.motive-row:last-of-type { border-bottom: 0; }
.motive-main { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); }
.motive-v { font-size: var(--fs-lg); font-weight: 700; color: var(--ink); }
.motive-k { color: var(--ink-2); font-size: var(--fs-sm); }
.motive-bar { height: 10px; border-radius: 999px; background: var(--surface-2);
  overflow: hidden; border: 1px solid var(--border); }
.motive-fill { height: 100%; background: var(--primary); border-radius: 999px;
  transition: width .4s ease; }
.motive-next { margin: var(--sp-3) 0 0; color: var(--ink-2); font-size: var(--fs-sm);
  padding: var(--sp-2) var(--sp-3); background: var(--surface-2); border-radius: var(--radius-sm); }
@media (prefers-reduced-motion: reduce) { .motive-fill { transition: none; } }

/* ── 별 판정 (ADR-129) ───────────────────────────────────────────────────────
 * 숫자는 "몇 점짜리 사람" 으로 읽혀 낮으면 그만두게 됨. 별은 같은 정보를 담으면서
 * 다음 칸을 채우고 싶게 만듦. 가장 낮은 단계에도 하나는 줌. */
.stars { display: flex; gap: var(--sp-1); font-size: 30px; line-height: 1; margin-bottom: var(--sp-2); }
.star { color: var(--border); }
.star-on { color: #f0a500; }
.posture-sub { margin: var(--sp-1) 0 0; color: var(--ink-2); font-size: var(--fs-sm); }
.posture-cue { margin: var(--sp-3) 0 0; padding-top: var(--sp-2);
  border-top: 1px solid var(--border); }

/* ── 이번 주 요일 띠 (ADR-130) ───────────────────────────────────────────────
 * 숫자 하나보다 칸이 채워지는 그림이 잘 읽힘. 작은 화면에서 흘끗 볼 때 특히 그럼.
 * 7칸이 360px 에서도 넘치지 않도록 고정 너비 대신 균등 분할을 씀. */
.week-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); }
.wk { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; padding: var(--sp-2) 0; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--border); min-height: 46px; }
.wk-on { background: var(--good-soft); border-color: var(--good); }
.wk-d { font-size: var(--fs-xs, 13px); color: var(--ink-2); }
.wk-on .wk-d { color: var(--good-text); font-weight: 700; }
.wk-m { font-size: var(--fs-sm); line-height: 1; color: var(--good-text); font-weight: 700; }

/* ── 홈 '오늘' 블록·측정 진행·포인트 내역 (ADR-139) ─────────────────────────
 * 돌아온 사람이 첫 화면에서 자기 기록을 못 보면 쌓은 것이 사라진 것과 같음. */
.today-head { margin: 0; font-size: var(--fs-lg); font-weight: 700; color: var(--ink); }
.today-sub { margin: var(--sp-1) 0 var(--sp-3); color: var(--ink-2); font-size: var(--fs-sm); }
.today-week { margin: var(--sp-3) 0 var(--sp-2); font-weight: 700; color: var(--ink); }

/* 끝이 보이면 버티고, 끝을 모르면 중간에 그만둠. */
.goal-progress { display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); margin-bottom: var(--sp-3); }

/* 무엇을 잘해서 받았는지. 합계만 보이면 다음에 무엇을 반복할지 알 수 없음. */
.point-items { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.point-items li { display: flex; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); color: var(--ink-2);
  font-size: var(--fs-sm); }
.point-items li:last-child { border-bottom: 0; }
.point-items strong { color: var(--good-text); font-variant-numeric: tabular-nums; }

/* 골격 덧그림 (ADR-148).
 *
 * 미디어와 캔버스를 같은 상자에 겹침. 캔버스는 화면 픽셀 크기를 JS 가 맞추므로
 * 여기서는 자리만 잡음. `pointer-events: none` 이 없으면 미리보기를 가려 눌러지지 않음. */
.preview-stack { position: relative; display: inline-block; line-height: 0; }
.preview-overlay { position: absolute; left: 0; top: 0; pointer-events: none; }
.overlay-pick { display: flex; align-items: center; gap: 10px; margin: 8px 0 2px; flex-wrap: wrap; }
.overlay-pick .hint { margin: 0; }
.seg-sm { display: inline-flex; gap: 6px; }
.seg-sm button { padding: 7px 14px; font-size: 14px; min-height: 44px; }
.seg-sm button.on { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 700; }

/* 몸 지도 (ADR-149).
 *
 * 사람 그림 + 고칠 곳 목록. 좁은 화면에서는 세로로 쌓고 넓으면 나란히 둠 -
 * 390px 에서 나란히 두면 그림이 엄지손톱만 해져 색을 구분할 수 없음. */
.bodymap { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.bodymap-svg { width: 104px; height: auto; flex: 0 0 auto; }
.bodymap-svg .bodymap-side { font-size: 9px; fill: var(--text-dim); }
.bodymap-side-col { flex: 1 1 200px; min-width: 190px; }
.bodymap-cue { margin: 0 0 8px; font-size: 16px; font-weight: 700; line-height: 1.5; }
.bodymap-cue:empty { display: none; }
.bodymap-fixes { list-style: none; margin: 0; padding: 0; }
.bodymap-fixes li { display: flex; align-items: center; gap: 8px; padding: 5px 0;
  font-size: 15.5px; line-height: 1.5; }
.bodymap-fixes .bodymap-ok { color: var(--good-text); font-weight: 700; }
.bodymap-dot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; }
.bodymap-legend { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px;
  font-size: 12.5px; color: var(--text-dim); }
.bodymap-legend span { display: inline-flex; align-items: center; gap: 4px; }
.bodymap-legend i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.bodymap-detail { list-style: none; margin: 10px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 3px 10px;
  font-size: 12.5px; color: var(--text-dim); }

/* 미리보기를 가로로 꽉 채움. 운동은 팔다리를 좌우로 벌리므로 세로 상자에서는
 * 손발이 화면 밖으로 나가고, 나간 관절은 채점에서 빠짐. */
.preview { display: block; }
.preview-stack { display: block; width: 100%; }
.preview-img { width: 100%; max-width: none; }

/* 측정 무대 — 따라 할 동작과 내 모습을 나란히 (ADR-152).
 *
 * 좁은 화면에서는 위아래로 쌓음. 390px 에서 좌우로 두면 둘 다 엄지손톱만 해져
 * 자세를 볼 수 없고, 그러면 두 판을 둔 뜻이 사라짐. */
.stage { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 760px) { .stage { grid-template-columns: 1fr 1fr; align-items: start; } }
.ref-holder { line-height: 0; border-radius: var(--radius-sm); overflow: hidden; background: #0e1218; }
.ref-video { width: 100%; display: block; }
.ref-bar { position: relative; height: 8px; border-radius: 999px; background: var(--line-2);
  margin: 10px 0 6px; overflow: hidden; }
.ref-bar-me { position: absolute; top: 0; bottom: 0; width: 4px; border-radius: 999px;
  background: var(--primary); left: 0; transition: left 120ms linear; opacity: 0; }
.ref-bar.on .ref-bar-me { opacity: 1; }
.ref-hint { margin: 0; }
.ref-holder { position: relative; }
.ref-replay { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: rgba(10, 14, 20, 0.78); color: #fff; border: 0; border-radius: 10px;
  padding: 14px 20px; font-size: 16px; font-weight: 700; min-height: 44px; cursor: pointer; }
.ref-replay[hidden] { display: none; }

/* 측정 화면 재배치 (ADR-162).
 *
 * 영상 두 판을 맨 위에 크게 두고, 점수·몸 지도를 한 대시보드로 모음. 종전에는 큰 원형
 * 점수판이 화면의 3분의 1을 먹고 정작 따라 할 동작이 엄지손톱만 했음. */
.stage-top { margin-bottom: 12px; }
.stage-top .card { margin: 0; }

/* 점수 + 몸 지도 한 줄. 좁은 화면에서는 게이지를 왼쪽에 작게 두고 지도를 옆에 붙임 -
 * 세로로 쌓으면 다시 화면을 내려야 어디가 문제인지 보임. */
.dash { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.dash-gauge { flex: 0 0 auto; }
.dash-gauge .gauge { width: 132px; height: 132px; }
.dash-body { flex: 1 1 210px; min-width: 190px; }
@media (max-width: 400px) { .dash-gauge .gauge { width: 108px; height: 108px; } }

/* 기준 영상 위의 본 덧그림과 조작 단추. */
.ref-overlay { position: absolute; left: 0; top: 0; pointer-events: none; }
.ref-overlay[hidden] { display: none; }
.ref-tools { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0 4px; }
.ref-tools button { min-height: 44px; padding: 8px 14px; font-size: 14px; }
.ref-tools button.on { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 700; }

/* 전체화면일 때 영상이 화면을 채우게 함. 기본값은 요소 크기를 유지해 검은 여백이 생김. */
/* 전체보기. 두 판이 같은 규칙을 씀 — 기준 영상판과 내 모습판 어느 쪽을 키워도
 * 화면을 다 쓰게 함. `.ref-holder` 만 적어 두면 내 모습은 원래 크기 그대로 검은
 * 바탕 위에 작게 뜸(선택자 목록에 한정자를 하나만 붙이는 실수와 같은 종류임). */
.ref-holder:fullscreen,
.preview:fullscreen { width: 100vw; height: 100vh; display: flex; align-items: center; background: #000; }
.ref-holder:fullscreen .ref-video,
.preview:fullscreen .preview-img { width: 100%; height: 100%; object-fit: contain; }
/* 덧그림 캔버스는 영상 상자를 그대로 덮음. 좌표는 JS 가 `contentBox()` 로 맞춤. */
.ref-holder:fullscreen .ref-overlay,
.preview:fullscreen .preview-overlay { width: 100%; height: 100%; }

/* ── 루틴 판·운동 묶음 (ADR-163) ───────────────────────────────────────
 *
 * 색으로만 상태를 말하지 않음 — 칸마다 점수(또는 '진행 중'·'대기')를 글자로 적음.
 * 색각 이상에서도 읽히고, 스크린샷을 인쇄해도 뜻이 남음. */
.rdash-stats { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; }
.rdash-stat { display: flex; flex-direction: column; min-width: 84px; }
.rdash-stat strong { font-size: 20px; line-height: 1.2; }
.rdash-list { display: flex; flex-direction: column; gap: 6px; }
.rdash-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 44px; padding: 8px 12px; text-align: left;
  background: var(--surface); color: var(--text); cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.rdash-no {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg); font-size: 13px; font-weight: 700;
}
.rdash-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rdash-score { flex: 0 0 auto; font-size: 14px; color: var(--text-dim); }
.rdash-done { border-color: var(--good); }
.rdash-done .rdash-no { background: var(--good); color: #fff; }
.rdash-done .rdash-score { color: var(--good-text); font-weight: 700; }
.rdash-now { border-color: var(--primary); border-width: 2px; }
.rdash-now .rdash-no { background: var(--primary); color: #fff; }
.rdash-now .rdash-score { color: var(--primary-text); font-weight: 700; }

.pl-preview { margin: 8px 0 0; padding-left: 20px; }
.pl-preview li { margin: 2px 0; }
.pl-items { display: flex; flex-direction: column; gap: 10px; margin-bottom: 10px; }
.pl-item {
  padding: 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg);
}
.pl-item-head { display: flex; align-items: center; gap: 8px; }
.pl-item-no {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface); border: 1px solid var(--border); font-weight: 700;
}
.pl-nums { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.pl-num { display: flex; flex-direction: column; gap: 2px; flex: 1 1 88px; }
/* 숫자 칸은 좁아도 손가락 규격을 지켜야 함(44px). 폭만 줄임. */
.input-sm { min-height: 44px; padding: 8px 10px; }
.pl-item-acts { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.pl-item-acts .btn { flex: 1 1 auto; min-width: 72px; }

/* ── 플레이리스트 운동 (#/workout, ADR-176) ────────────────────────────────
 *
 * 편집 영상 한 편을 따라 하며 구간마다 채점받는 화면. 따라 할 영상이 주인공이라 맨 위·가장 크게
 * 두고, 내 모습(카메라)과 점수는 그 옆(넓은 화면) 또는 아래(휴대폰)에 둠. 조작은 세 개만
 * (일시정지·다음 동작·그만두기) — 연구원 의견서 5항 "운동 중 화면 최소화". */
.back-link {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 2px;
  color: var(--primary-text); text-decoration: none; font-weight: 600;
}
.wk-start { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 52px; font-size: 17px; }
.wk-list { display: flex; flex-direction: column; gap: 12px; }
.wk-row { gap: 10px; margin-top: 8px; }
.wk-row:first-child { margin-top: 0; }
.wk-row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.wk-row-title { font-size: 16px; }
.wk-row-sub { font-size: var(--fs-xs); color: var(--text-dim); }
.wk-row-go { color: var(--primary-text); display: inline-flex; }
.wk-quick-out { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.wk-quick-pick { font-size: 15px; font-weight: 600; }
.wk-head { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.wk-head .page-head { margin-bottom: 0; }
.wk-badges { display: flex; flex-wrap: wrap; gap: 6px; }
.wk-plan { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.wk-plan-item {
  display: grid; grid-template-columns: 30px minmax(0, 1fr) auto auto; align-items: center; gap: 8px;
  padding: 8px 0; border-top: 1px solid var(--border);
}
.wk-plan-item:first-child { border-top: 0; }
.wk-plan-no {
  width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center;
  justify-content: center; background: var(--primary-soft); color: var(--primary-text);
  font-weight: 800; font-size: 13px;
}
.wk-plan-name { min-width: 0; overflow-wrap: anywhere; }
.wk-plan-len { font-variant-numeric: tabular-nums; color: var(--text-dim); font-size: var(--fs-xs); }

.wk-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.wk-phase {
  padding: 4px 12px; border-radius: 999px; font-weight: 800; font-size: 14px;
  background: var(--bg); color: var(--text); border: 1px solid var(--border-strong);
}
.wk-phase-work { background: var(--primary); color: #fff; border-color: var(--primary); }
.wk-phase-rest { background: var(--good-soft); color: var(--good-text); border-color: var(--good-soft); }
.wk-now { font-size: 19px; line-height: 1.3; min-width: 0; overflow-wrap: anywhere; }
.wk-remain { margin-left: auto; font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; }
.wk-next { font-size: var(--fs-xs); color: var(--text-dim); min-height: 1.4em; }
.wk-stage { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.wk-main { position: relative; }
.wk-video { width: 100%; aspect-ratio: 16 / 9; background: #000; border-radius: var(--radius-sm); display: block; }
.wk-campane { display: flex; flex-direction: column; gap: 8px; }
.wk-cam { position: relative; width: 100%; line-height: 0; min-height: 90px; background: #0e1218; border-radius: var(--radius-sm); overflow: hidden; }
.wk-camvideo, .wk-camimg { width: 100%; display: block; }
.wk-camimg:not([src]) { display: none; }
.wk-cam-wait {
  line-height: 1.5; color: #e7ecf3; font-size: var(--fs-xs); padding: 30px 12px; text-align: center;
}
.wk-camimg[src] ~ .wk-cam-wait { display: none; }
.wk-score { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.wk-score-label { font-size: var(--fs-xs); color: var(--text-dim); font-weight: 700; }
.wk-score-value { font-size: 34px; font-weight: 900; font-variant-numeric: tabular-nums; }
.wk-score-good .wk-score-value { color: var(--good-text); }
.wk-cue { font-size: 15px; min-height: 1.4em; }
.wk-controls { display: flex; flex-wrap: wrap; gap: 8px; }
.wk-controls .btn { flex: 1 1 140px; min-height: 48px; }
.wk-pause { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.wk-overall { display: flex; align-items: center; gap: 10px; }
.wk-progress { flex: 1 1 auto; height: 8px; border-radius: 999px; background: var(--border); overflow: hidden; }
.wk-progress-bar { height: 100%; width: 0; background: var(--primary); transition: width 0.2s linear; }
.wk-total { font-size: var(--fs-xs); color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.wk-alerts { display: flex; flex-direction: column; gap: 6px; }
.wk-chips { list-style: none; display: flex; flex-direction: column; gap: 4px; }
.wk-chip {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: var(--radius-sm);
}
.wk-chip-no { font-weight: 800; color: var(--text-dim); text-align: center; }
.wk-chip-name { min-width: 0; overflow-wrap: anywhere; }
.wk-chip-val { font-weight: 700; font-variant-numeric: tabular-nums; }
.wk-chip-now { background: var(--primary-soft); }
.wk-chip-now .wk-chip-no { color: var(--primary-text); }
.wk-chip-done .wk-chip-val { color: var(--good-text); }
.wk-result { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 10px; }
.wk-result-item { display: flex; flex-direction: column; gap: 2px; padding: 10px; border-radius: var(--radius-sm); background: var(--bg); }
.wk-result-item span { font-size: var(--fs-xs); color: var(--text-dim); }
.wk-result-item strong { font-size: 19px; }
@media (min-width: 900px) {
  .wk-stage { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); align-items: start; }
}
.wk-entry { border-color: var(--primary); background: var(--primary-soft); }
.wk-entry-main { display: flex; align-items: center; gap: 10px; min-width: 0; color: var(--primary-text); }
.wk-entry-main .wk-row-title { color: var(--text); }

/* ── 설문 시행 조건 안내 (ADR-182, 연구원 의견서 8) ──────────────────────
 * 운동 전에는 조건 선택 대신, 운동 후에는 결과 아래에 놓임. 설문이 둘이면 칸이 둘임. */
.sg-card { border-color: var(--primary); }
.sg-item { display: flex; flex-direction: column; gap: 8px; padding: 12px 0; border-top: 1px solid var(--border); }
.sg-item:first-of-type { border-top: 0; padding-top: 4px; }
.sg-item-main { display: flex; flex-direction: column; gap: 2px; }
.sg-item-title { font-size: 16px; }
.sg-back { margin-top: 10px; }
/* 운동을 마친 화면에서는 결과 카드와 단추 사이에 끼므로 위아래를 띄움(`.wk-slot` 은 간격 규칙이 없음). */
.wk-slot > .sg-card { margin: 14px 0; }

/* ── 로그인 전 소개 화면 (#/, 연구원 의견서 1-2) ──────────────────────────
 * 로고 · 말풍선 다섯이 차례로 · 같은 크기 세로 단추 둘. 움직임을 줄이도록 설정한 기기에서는
 * 말풍선이 처음부터 다 보임(흔들리는 화면이 어지러운 이용자가 있음). */
.view-intro { display: flex; flex-direction: column; gap: 18px; padding-top: 14px; max-width: 520px; width: 100%; margin: 0 auto; }
.intro-logo {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  font-size: 34px; font-weight: 900; letter-spacing: 0.06em; color: var(--text);
}
.intro-logo .intro-logo-mark { width: 46px; height: 46px; stroke-width: 2; color: var(--primary-text); }
.intro-chat { display: flex; flex-direction: column; gap: 10px; }
.intro-bubble {
  align-self: flex-start; max-width: 88%; padding: 12px 16px;
  border-radius: 18px 18px 18px 6px; background: var(--surface); border: 1px solid var(--border);
  font-size: 17px; line-height: 1.45; word-break: keep-all;
  animation: intro-in 0.45s ease both; animation-delay: var(--d, 0s);
}
.intro-bubble-me {
  align-self: flex-end; border-radius: 18px 18px 6px 18px;
  background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 800;
}
@keyframes intro-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .intro-bubble { animation: none; } }
.intro-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.intro-btn { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 56px; font-size: 18px; }
.intro-hint { text-align: center; }
.intro-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px 16px; }
.intro-links a {
  display: inline-flex; align-items: center; gap: 5px; min-height: 44px;
  color: var(--primary-text); text-decoration: none; font-size: var(--fs-xs); font-weight: 600;
}

/* ── 로그인 후 홈 (#/, 연구원 의견서 2·6) ─────────────────────────────── */
.view-start { display: flex; flex-direction: column; gap: 12px; }
.home-greet { text-align: left; font-size: 16px; margin: 2px 0; }
.home-tile { min-height: 128px; justify-content: space-between; }
.home-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-bottom: 10px; }
.home-stat { display: flex; flex-direction: column; gap: 2px; padding: 12px; border-radius: var(--radius-sm); background: var(--bg); }
.home-stat span { font-size: var(--fs-xs); color: var(--text-dim); }
.home-stat strong { font-size: 24px; font-weight: 900; font-variant-numeric: tabular-nums; }
.home-month .bars { margin: 6px 0 10px; }
.home-more { margin-top: 4px; }

/* ── 챗봇 자리 (#/chatbot, 연구원 의견서 9) ────────────────────────────── */
.chat-log { display: flex; flex-direction: column; gap: 10px; }
.chat-bubble {
  align-self: flex-start; max-width: 90%; padding: 10px 14px; line-height: 1.55;
  border-radius: 16px 16px 16px 6px; background: var(--bg); word-break: keep-all;
}
.chat-bubble-me { align-self: flex-end; border-radius: 16px 16px 6px 16px; background: var(--primary-soft); }
.chat-go {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; margin-top: 2px;
  color: var(--primary-text); font-weight: 700; text-decoration: none;
}
.chat-questions { display: flex; flex-wrap: wrap; gap: 8px; }
.chat-q { font: inherit; font-size: var(--fs-sm); cursor: pointer; text-align: left; }

/* ── 내 정보 바로 가기 ─────────────────────────────────────────────────── */
.profile-go-list { display: flex; flex-direction: column; gap: 8px; }
