/* Reaction Benchmark — base + 공용 부품. 색은 전부 토큰에서만.
   방향: 계측 장비. 숫자는 고정폭·tabular, 라벨은 작은 대문자, 면은 얇은 격자 위에 앉는다. */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font: var(--text-md)/1.65 var(--font-sans);
  /* 계기판 격자 — 아주 옅게, 배경에만 */
  background-image:
    linear-gradient(var(--color-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--color-grid) 1px, transparent 1px);
  background-size: 64px 64px, 64px 64px;
  background-position: -1px -1px;
}
img, canvas, svg { max-width: 100%; }
/* 모바일 탭 하이라이트 제거 — 탭마다 웹킷 기본 반투명 사각형이 번쩍인다(사장님 제보 2026-08-03).
   피드백은 우리 연출(팝·링·:active)이 담당. :hover 규칙은 전부 (hover: hover) 가드 — 터치에서
   탭 순간 hover 스타일이 번쩍 얹혔다 눌러붙는 것(sticky hover)도 같은 제보의 원인이었다. */
html { -webkit-tap-highlight-color: transparent; }
a { color: var(--color-link); text-decoration: none; }
/* 본문 속 링크는 색만으로 구분되면 안 된다(WCAG 1.4.1) — 밑줄을 기본으로 둔다. */
p a, li a, article a { text-decoration: underline; text-underline-offset: 3px; }
/* 행 전체가 링크인 곳은 밑줄을 끈다(텍스트 속 링크가 아니라 목록 항목이다) */
.test-list a, .records-grid a, .nav-links a, .brand { text-decoration: none; }
@media (hover: hover) { a:hover { text-decoration: underline; } }
:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* 디테일 — 드래그 선택은 브랜드 앰버, 스크롤바는 배경 톤에 맞춘다(밝은 기본 스크롤바가 다크 판에서 튐) */
::selection { background: var(--color-primary); color: var(--color-on-primary); }
html { scrollbar-color: var(--color-outline) var(--color-bg); }

h1 { font-size: var(--text-xl); line-height: 1.2; margin: 0 0 var(--space-2); letter-spacing: -.01em; }
h2 { font-size: var(--text-lg); margin: var(--space-5) 0 var(--space-2); letter-spacing: -.01em; }
h3 { font-size: var(--text-md); margin: var(--space-4) 0 var(--space-2); }
p { margin: 0 0 var(--space-3); }
.muted { color: var(--color-text-muted); font-size: var(--text-sm); }
/* 데스크톱에서 내용이 화면 절반에 웅크리지 않게 판을 넓힌다(2026-08-02 개편).
   본문 산문은 아래 article 폭 제한이 따로 지킨다 — 판이 넓다고 줄이 길어지면 안 된다. */
.wrap { max-width: 960px; margin: 0 auto; padding: 0 var(--space-3); }
/* 글줄 폭 제한 없음 — 본문도 사이트 폭(.wrap 960px)을 다 쓴다(사장님 2026-09-28 "사이트 폭을 다 쓰면 안되는거야? 모바일만 따로").
   예전엔 76ch로 좁혀 판 안에서 글만 웅크려 보였다. 긴 줄의 가독성은 본문 글자·행간을 키워 받친다(article.prose). */

/* 작은 대문자 라벨 — 계측기 눈금판의 글씨 */
.eyebrow {
  font: 600 var(--text-xs)/1 var(--font-mono);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--color-text-muted); margin: 0 0 var(--space-2);
}

/* 가이드 글 발행일·수정일 줄 (build.mjs datesLine이 h1 아래에 넣는다) */
.dates { font: var(--text-xs)/1.4 var(--font-mono); color: var(--color-text-muted); margin: 0 0 var(--space-3); }

/* nav */
.site-head { border-bottom: 1px solid var(--color-outline); background: var(--color-bg); }
.nav { max-width: 960px; margin: 0 auto; padding: var(--space-3);
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); align-items: center; }
.brand { font: 700 var(--text-md)/1 var(--font-mono); color: var(--color-text); letter-spacing: -.02em;
  display: inline-flex; align-items: center; gap: var(--space-2); }
.brand-mark { width: 22px; height: 22px; }
.brand b { font-weight: 400; color: var(--color-text-muted); }
/* 두 줄 헤더(2026-09-26): 1줄 = 브랜드 … 언어 토글, 2줄 = 메뉴(글자가 브랜드와 같은 선에서 시작).
   한 줄로 두던 때는 메뉴 13개가 960px 칸을 넘어(실측 EN 약 1,150px·KO 약 1,000px) 창 폭에 따라
   메뉴 줄이나 토글만 제멋대로 아래로 떨어졌다(사장님 제보). 모바일과 같은 구조라 전 폭·전 언어가 한 모양이다. */
.nav-links { display: flex; flex-wrap: wrap; gap: var(--space-1); order: 3; flex: 1 1 100%;
  margin-left: calc(-1 * var(--space-2)); }
.nav-links a { color: var(--color-text-muted); font: 500 var(--text-sm)/1 var(--font-mono);
  padding: var(--space-2); border-radius: var(--radius-sm); min-height: 44px;
  display: inline-flex; align-items: center; }
@media (hover: hover) { .nav-links a:hover { color: var(--color-text); background: var(--color-surface-raised); text-decoration: none; } }
.nav-run { color: var(--color-text) !important; font-weight: 700; }
/* ─── 좁은 폭 네비(≤920px — 영어 메뉴 한 줄이 약 850px라 그 아래로는 칩 바로. 720이던 때 태블릿 폭에서 메뉴가 두 줄로 접혔다, 2026-09-26) — PC 상단 바를 구겨 넣지 않는다(사장님 2026-08-03 "각 버전에 최적화").
   1줄: 브랜드 + 언어 토글 · 2줄: 가로 스와이프 칩 바(알약 테두리 = 눌린다는 신호,
   끝에 반쯤 걸린 칩 = 더 있다는 신호). JS 0 — 앱들의 상단 카테고리 칩 관습. */
@media (max-width: 920px) {
  .nav { padding: var(--space-2) var(--space-3); row-gap: var(--space-2); }
  .nav-links { flex-wrap: nowrap; overflow-x: auto; margin-left: 0; gap: var(--space-2); scrollbar-width: none; }
  .nav-links::-webkit-scrollbar { display: none; }
  .nav-links a { white-space: nowrap; border: 1px solid var(--color-outline); border-radius: 999px;
    padding: 0 var(--space-3); min-height: 38px; font-size: var(--text-sm); }
  .nav-run { border-color: var(--color-primary) !important; }
}
/* 언어 토글 — 다른 항목과 같은 줄 높이의 알약. 예전엔 큰 상자라 줄에서 삐죽 튀어나왔다. */
.lang-toggle { border: 1px solid var(--color-outline); border-radius: 999px;
  color: var(--color-text-muted) !important; margin-left: auto;
  padding: 0 var(--space-3) !important; min-height: 32px !important; align-self: center; }
@media (hover: hover) { .lang-toggle:hover { border-color: var(--color-primary); color: var(--color-text) !important; background: none !important; } }

main.wrap { padding-top: var(--space-5); padding-bottom: var(--space-6); }

/* footer — 브랜드 + 링크 그룹 + SNS 공유. 고정 카본 배경 + 앰버 상단 라인(테마 무관 마감 앵커,
   F1 야간 카드와 같은 계열 — 2026-08-04 사장님 "푸터 색 안 넣어도 되나"). */
.site-foot { background: var(--foot-bg); border-top: 3px solid var(--color-primary);
  padding-top: var(--space-5); padding-bottom: var(--space-6); margin-top: var(--space-6);
  font-size: var(--text-sm); color: var(--foot-muted); }
.foot-brand { display: inline-flex; align-items: center; gap: var(--space-2);
  font: 700 var(--text-md)/1 var(--font-mono); color: var(--foot-text); letter-spacing: -.02em; }
.foot-brand b { font-weight: 400; color: var(--foot-muted); }
.foot-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-4) var(--space-5); margin-top: var(--space-4); }
.foot-col h3 { font: 600 var(--text-xs)/1 var(--font-mono); letter-spacing: .14em;
  text-transform: uppercase; color: var(--foot-muted); margin: 0 0 var(--space-3); }
.foot-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.foot-col a { color: var(--foot-muted); text-decoration: none; transition: color .15s ease; }
@media (hover: hover) { .foot-col a:hover { color: var(--foot-text); text-decoration: none; } }
/* SNS 원형 버튼 — 플랫폼 로고는 그쪽 브랜드색이 식별 신호라 예외적으로 색을 쓴다 */
.share-circles { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.sc { width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--foot-outline);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer; padding: 0;
  transition: transform .15s ease; }
@media (hover: hover) { .sc:hover { transform: scale(1.1); } }
.sc:active { transform: scale(.95); }
.sc svg { width: 17px; height: 17px; display: block; }
.sc-x { background: var(--brand-x); color: var(--brand-on); }
.sc-fb { background: var(--brand-facebook); color: var(--brand-on); }
.sc-th { background: var(--brand-x); color: var(--brand-on); }
.sc-nv { background: var(--brand-naver); color: var(--brand-on); }
.sc-kakao { background: var(--brand-kakao); color: var(--brand-kakao-text); }
.sc-copy { background: var(--foot-outline); color: var(--foot-text); }
.share-msg { display: block; margin-top: var(--space-2); font: 600 var(--text-xs)/1.4 var(--font-mono);
  color: var(--foot-text); min-height: 1.2em; }
.foot-copy { margin-top: var(--space-5); padding-top: var(--space-3);
  border-top: 1px solid var(--foot-outline); }
/* 운영자 트래픽 제외 상태 표시(head.html의 notrack 스위치) */
.notrack-note { font: 600 var(--text-xs)/1.5 var(--font-mono); color: var(--color-signal-text); }

/* 버튼 4종 — 높이·곡률·크기는 여기서만 정한다 */
/* ★ hidden 속성이 항상 이긴다.
   브라우저 기본 [hidden]{display:none}은 특이도가 0이라, .btn-secondary처럼 display를 정하는
   클래스가 있으면 그쪽이 이긴다. 그래서 startBtn.hidden = true가 화면에 아무 효과가 없었고
   일곱 게임 전부에서 Start 버튼이 플레이 중에도 남아 있었다(2026-08-02, 사장님 신고).
   JS가 hidden을 켜면 반드시 사라져야 한다 — 여기서 못 박는다. */
[hidden] { display: none !important; }

.btn, .btn-secondary, .btn-quiet {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 44px; padding: 0 var(--space-4); border-radius: var(--radius-md);
  font: 600 var(--text-sm)/1 var(--font-mono); letter-spacing: .02em;
  cursor: pointer; border: 1px solid transparent; }
.btn { background: var(--color-primary); color: var(--color-on-primary); }
@media (hover: hover) { .btn:hover { filter: brightness(1.08); } }
.btn-secondary { background: none; border-color: var(--color-outline); color: var(--color-text); }
@media (hover: hover) { .btn-secondary:hover { border-color: var(--color-primary); } }
.btn-quiet { background: none; color: var(--color-text-muted); }
@media (hover: hover) { .btn-quiet:hover { color: var(--color-text); } }

/* 눌림 피드백 — 반응은 release가 아니라 press에서. 터치에는 hover가 없어 이게 유일한 즉시 피드백.
   게임 타일은 제외(pointerdown에서 JS 연출이 이미 즉답 — 이중 피드백 금지). */
.btn:active, .btn-secondary:active, .btn-quiet:active,
.mode-btn:active, .lang-toggle:active { transform: scale(.97); }
.test-list a:active, .daily-card:active, .variant-card:active, .record:active { transform: scale(.99); }

/* 디테일 — 상호작용 요소는 상태 변화가 뚝 끊기지 않게(색·테두리·눌림만, 레이아웃 속성 금지) */
.test-list a, .record, .daily-card, .variant-card, .btn, .btn-secondary, .btn-quiet, .mode-btn, .tile, .lang-toggle {
  transition: background-color .15s ease, border-color .15s ease, color .15s ease, transform .1s ease-out; }

/* 본문 표 — 비교표(순서↔시각 등)에 쓴다. 넘치면 표만 가로 스크롤. */
article table { border-collapse: collapse; width: 100%; margin: var(--space-3) 0;
  font-size: var(--text-sm); display: block; overflow-x: auto; }
article th, article td { border: 1px solid var(--color-outline); padding: var(--space-2) var(--space-3);
  text-align: left; vertical-align: top; }
article th { background: var(--color-surface); font-weight: 600; white-space: nowrap; }

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

/* 오류 표시 — 색만으로 전달 금지: 아이콘+테두리 동반 */
.error-note { border: 1px solid var(--color-danger); border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3); font-size: var(--text-sm); }
.error-note::before { content: "⚠ "; }

/* 카드 */
.card { background: var(--color-surface); border: 1px solid var(--color-outline);
  border-radius: var(--radius-lg); padding: var(--space-4); }

/* 홈 히어로 — 이 사이트의 주장을 먼저 말한다.
   넓은 화면에선 주장(왼쪽) + 명판(오른쪽) 2단: 계측기의 스펙 플레이트처럼.
   예전엔 좁은 기둥 하나라 1440px에서 오른쪽 절반이 죽은 공간이었다(2026-08-02 개편). */
.hero { border-bottom: 1px solid var(--color-outline); padding-bottom: var(--space-5); }
.hero .eyebrow { color: var(--color-signal-text); }
.hero h1 { font-size: var(--text-hero); max-width: 16ch; letter-spacing: -.02em; line-height: 1.1; }
.hero-claim { font-size: var(--text-md); color: var(--color-text-muted); max-width: 52ch; }
.hero-cta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4);
  margin-top: var(--space-4); }
/* 설명은 히어로가 아니라 링크 뒤에 산다 — 후킹(버튼)과 방법(조용한 링크)의 자리 구분 */
.hero-how { font: 500 var(--text-xs)/1.4 var(--font-mono); letter-spacing: .04em;
  color: var(--color-text-muted); text-decoration-color: var(--color-outline); }
@media (hover: hover) { .hero-how:hover { color: var(--color-text); } }
/* 히어로 데모 릴(2026-09-28) — 기능 세 칸(도전장·가입 없음·오늘의 도전)을 걷어내고 테스트 10개를 차례로 보여준다.
   사장님 "굳이 저걸 넣어야하나" → "반응속도만 반복하지말고 나머지 테스트들이 차례대로 데모 영상처럼".
   장면 전환·재생은 home.js(탭이 숨으면 멈춤, 동작 줄이기면 첫 장면에 멈춤). 그림은 홈 카드와 같은 thumbs.js.
   06 §3: transform·opacity만 움직인다(배경색 전환 금지 — 층을 겹쳐 투명도로 바꾼다). */
/* 데모 상자 — 홈 히어로(.hero-demo)와 게임 면 "하는 법"(.howto)이 같이 쓴다. 장면 = demos.js, 재생 = reel.js */
.hero-demo { margin-top: var(--space-4); max-width: 360px; }
.demo-box { position: relative; display: block; width: 100%;
  aspect-ratio: 16 / 10; border-radius: var(--radius-lg); overflow: hidden; text-decoration: none !important;
  background: var(--color-bg); border: 1px solid var(--color-outline); box-shadow: var(--shadow-pop);
  transition: transform .12s ease-out; }
/* 화면 전체 = 재생 토글(사장님 9/28 "누르면 일시정지, 다시 누르면 재개"). 멈추면 가운데에 재생 표시가 뜬다.
   이동은 왼쪽 위 이름표(링크)가 맡는다 — 화면 자체가 링크면 멈출 수가 없다. */
.hd-toggle { position: absolute; inset: 0; z-index: 1; padding: 0; border: 0; background: none; cursor: pointer; }
.hd-toggle:focus-visible { outline: 3px solid var(--color-link); outline-offset: -3px; border-radius: var(--radius-lg); }
.hd-state { position: absolute; left: 50%; top: 50%; width: 52px; height: 52px; margin: -26px 0 0 -26px; border-radius: 50%;
  background: var(--color-surface); box-shadow: var(--shadow-pop); opacity: 0; transform: scale(.7);
  transition: opacity .18s ease, transform .18s ease; }
.hd-state::after { content: ""; position: absolute; left: 20px; top: 16px; border-style: solid;
  border-width: 10px 0 10px 16px; border-color: transparent transparent transparent var(--color-text); }
.demo-box.is-paused .hd-state { opacity: 1; transform: scale(1); }
.demo-box.is-paused .hd-scene * { animation-play-state: paused !important; }
.hd-scene { position: absolute; inset: 0; opacity: 0; transition: opacity .45s ease; }
.hd-scene.is-active { opacity: 1; }
.demo-box:not(.is-ready) .hd-scene:first-child { opacity: 1; } /* 스크립트 전에도 빈 상자로 안 보이게 */
.hd-scene svg { display: block; width: 100%; height: 100%; }
/* 반응속도 장면 — 빨강 → 초록 → 248 ms 한 번(4.2초, 장면이 켜질 때마다 처음부터) */
.hd-layer { position: absolute; inset: 0; display: grid; place-items: center;
  font: 700 clamp(1.3rem, 3.2vw, 1.7rem)/1 var(--font-sans); color: var(--color-on-stage); }
.hd-wait { background: var(--color-stage-wait); }
.hd-go { background: var(--color-stage-go); opacity: 0; }
.hd-score { position: absolute; left: 50%; bottom: 22%; transform: translateX(-50%);
  padding: 6px 14px; border-radius: 999px; background: var(--color-surface); color: var(--color-text);
  font: 700 var(--text-md)/1 var(--font-mono); opacity: 0; }
.hd-cursor { position: absolute; left: 62%; top: 30%; width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid var(--color-on-stage); opacity: 0; }
.hd-react.is-run .hd-go { animation: hd-go 4.2s forwards; }
.hd-react.is-run .hd-score { animation: hd-score 4.2s forwards; }
.hd-react.is-run .hd-cursor { animation: hd-tap 4.2s forwards; }
@keyframes hd-go { 0%, 44% { opacity: 0; } 46%, 100% { opacity: 1; } }
@keyframes hd-tap { 0%, 50% { opacity: 0; transform: scale(1.4); } 54% { opacity: .9; transform: scale(1); } 62%, 100% { opacity: 0; transform: scale(.8); } }
@keyframes hd-score { 0%, 56% { opacity: 0; transform: translate(-50%, 8px); } 64%, 100% { opacity: 1; transform: translate(-50%, 0); } }
/* 나머지 장면 — 각 게임 한 판을 몇 초로 줄인 재연(사장님 9/28 "실제 플레이 화면이 아니라서 별로" →
   "반응속도 데모 퀄리티 정도면 돼"). 실제 게임의 색·모양(격자 칸·과녁·F1 신호등)을 그대로 쓰고, 시점은 --d(지연)로만 준다.
   06 §3: transform·opacity만 움직인다. 재생 = .is-run(home.js). */
.hd-stage { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding-top: 18px; background: var(--color-surface); }
.hd-grid { display: grid; gap: 6px; grid-template-columns: repeat(var(--n), var(--s)); }
.hd-grid > b { position: relative; width: var(--s); height: var(--s); border-radius: var(--radius-md);
  background: var(--color-surface-raised); border: 1px solid var(--color-outline); }
.hd-grid i { position: absolute; inset: -1px; border-radius: inherit; display: grid; place-items: center; font-style: normal; }
.hd-lit, .hd-hold, .hd-keep, .hd-ctile { background: var(--color-primary); opacity: 0; }
.hd-ctile, .hd-lit { color: var(--color-on-primary); font: 700 var(--text-sm)/1 var(--font-mono); }
.hd-ctile { opacity: 1; }
.hd-ctile u { text-decoration: none; }
.hd-ring { inset: -5px !important; border: 2px solid var(--color-text); opacity: 0; }
.hd-grid > b:has(.hd-oddtile), .hd-grid:has(.hd-oddtile) > b { background: var(--color-primary); border-color: transparent; }
.hd-oddtile { background: color-mix(in oklab, var(--color-primary) 72%, var(--color-surface)); }
.hd-okmark { outline: 2px solid var(--color-success); outline-offset: -2px; color: var(--color-on-primary);
  font: 700 var(--text-sm)/1 var(--font-sans); opacity: 0; }
.hd-scene.is-run .hd-lit { animation: hd-flash .5s var(--d) both; }
.hd-scene.is-run .hd-hold { animation: hd-hold 1.5s .2s both; }
.hd-scene.is-run .hd-keep, .hd-scene.is-run .hd-okmark { animation: hd-in .25s var(--d) both; }
.hd-scene.is-run .hd-ring { animation: hd-ring .4s var(--d) both; }
.hd-scene.is-run .hd-ctile { animation: hd-dim .2s var(--d) both; }
.hd-scene.is-run .hd-ctile u { animation: hd-dim-out .1s 1.1s both; }
/* 에임 — 과녁 셋 + 조준점. 조준점은 무대 크기 층을 translate(%)로 옮겨 과녁 자리로 간다 */
.hd-tg { position: absolute; left: var(--x); top: var(--y); width: 30px; height: 30px; margin: -15px 0 0 -15px;
  border-radius: 50%; background: var(--color-primary); border: 2px solid var(--color-on-primary); opacity: 0; }
.hd-aimpath { position: absolute; inset: 0; pointer-events: none; transform: translate(55%, 85%); }
.hd-crs { position: absolute; left: 0; top: 0; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;
  border: 2px solid var(--color-text); }
.hd-scene.is-run .hd-tg { animation: hd-tg 1.1s var(--d) both; }
.hd-scene.is-run .hd-aimpath { animation: hd-aim 3.2s both; }
/* 숫자 기억 — 보여주기(시간 막대가 준다) → 입력 칸에 한 자리씩 → ✓ */
.hd-num-show, .hd-num-ans { position: absolute; inset: 18px 0 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; }
.hd-digits { font: 800 1.9rem/1 var(--font-mono); letter-spacing: .08em; color: var(--color-text); }
.hd-bar { width: 130px; height: 4px; border-radius: 2px; background: var(--color-primary); transform-origin: left; }
.hd-num-ans { flex-direction: row; opacity: 0; }
.hd-typed { min-width: 140px; padding-bottom: 4px; border-bottom: 2px solid var(--color-primary); text-align: center;
  font: 800 1.6rem/1.2 var(--font-mono); letter-spacing: .08em; color: var(--color-text); }
.hd-typed i, .hd-over i { font-style: normal; }
.hd-ok { color: var(--color-success); font: 800 1.4rem/1 var(--font-sans); }
.hd-scene.is-run .hd-num-show { animation: hd-phase-a 3.2s both; }
.hd-scene.is-run .hd-bar { animation: hd-shrink 3.2s linear both; }
.hd-scene.is-run .hd-num-ans { animation: hd-phase-b 3.2s both; }
.hd-scene.is-run .hd-typed i, .hd-scene.is-run .hd-over i { animation: hd-op .08s var(--d) both; }
.hd-scene.is-run .hd-ok, .hd-scene.is-run .hd-pill { animation: hd-in .3s var(--d) both; }
/* 단어 기억 — 단어 셋이 차례로, 버튼이 눌린다 */
.hd-words { position: relative; width: 100%; height: 2.4rem; }
.hd-words b { position: absolute; inset: 0; display: grid; place-items: center; font: 800 1.7rem/1 var(--font-sans); color: var(--color-text); opacity: 0; }
.hd-btns { display: flex; gap: 8px; }
.hd-btn { padding: 7px 12px; border-radius: var(--radius-md); background: var(--color-primary); color: var(--color-on-primary);
  font: 700 var(--text-xs)/1 var(--font-sans); }
.hd-scene.is-run .hd-w1 { animation: hd-w1 4.4s both; }
.hd-scene.is-run .hd-w2 { animation: hd-w2 4.4s both; }
.hd-scene.is-run .hd-w3 { animation: hd-w3 4.4s both; }
.hd-scene.is-run .hd-new { animation: hd-press .3s 1.1s, hd-press .3s 2.6s; }
.hd-scene.is-run .hd-seen { animation: hd-press .3s 3.7s; }
/* 타자 — 흐린 문장 위에 같은 문장이 한 글자씩 진해진다 */
.hd-typeline { position: relative; padding-bottom: 6px; border-bottom: 2px solid var(--color-primary);
  font: 700 1.05rem/1.3 var(--font-sans); white-space: nowrap; }
.hd-base { color: var(--color-text-muted); opacity: .55; }
.hd-over { position: absolute; left: 0; top: 0; color: var(--color-text); }
.hd-pill { padding: 5px 12px; border-radius: 999px; background: var(--color-primary); color: var(--color-on-primary);
  font: 700 var(--text-sm)/1 var(--font-mono); }
/* F1 — 신호등 다섯 개가 하나씩 켜지고 한꺼번에 꺼진다 */
.hd-f1 { background: var(--f1-track); }
.hd-gantry { display: flex; gap: 8px; padding: 10px 12px; border-radius: 12px; background: var(--f1-gantry); }
.hd-gantry b { position: relative; width: 26px; height: 26px; border-radius: 50%; background: var(--f1-light-off); }
.hd-gantry i { position: absolute; inset: 0; border-radius: 50%; background: var(--f1-red); opacity: 0; }
.hd-f1score { background: var(--f1-gantry); color: var(--f1-text); }
.hd-gantry s { position: absolute; inset: 0; border-radius: 50%; }
.hd-scene.is-run .hd-gantry i { animation: hd-op .06s var(--d) both; }
.hd-scene.is-run .hd-gantry s { animation: hd-dim-out .05s 2.8s both; } /* 전부 켜진 뒤 한꺼번에 소등 */
@keyframes hd-flash { 0% { opacity: 0; } 15%, 70% { opacity: 1; } 100% { opacity: 0; } }
@keyframes hd-hold { 0% { opacity: 0; } 8%, 80% { opacity: 1; } 100% { opacity: 0; } }
@keyframes hd-in { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: none; } }
@keyframes hd-op { from { opacity: 0; } to { opacity: 1; } }
@keyframes hd-ring { 0% { opacity: 0; } 1% { opacity: .9; transform: scale(.7); } 100% { opacity: 0; transform: scale(1.25); } } /* 첫 칸을 투명으로 — fill both가 지연 동안 첫 칸을 붙들어 링이 누르기 전부터 보였다 */
@keyframes hd-dim { from { opacity: 1; } to { opacity: .15; } }
@keyframes hd-dim-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes hd-tg { 0% { opacity: 0; transform: scale(.3); } 12%, 76% { opacity: 1; transform: scale(1); } 90%, 100% { opacity: 0; transform: scale(1.5); } }
@keyframes hd-aim { 0% { transform: translate(55%, 85%); } 22%, 32% { transform: translate(25%, 34%); } 56%, 66% { transform: translate(72%, 56%); } 90%, 100% { transform: translate(42%, 76%); } }
@keyframes hd-phase-a { 0%, 48% { opacity: 1; } 54%, 100% { opacity: 0; } }
@keyframes hd-phase-b { 0%, 52% { opacity: 0; } 58%, 100% { opacity: 1; } }
@keyframes hd-shrink { from { transform: scaleX(1); } 48%, to { transform: scaleX(0); } }
@keyframes hd-w1 { 0% { opacity: 0; } 4%, 27% { opacity: 1; } 31%, 100% { opacity: 0; } }
@keyframes hd-w2 { 0%, 31% { opacity: 0; } 35%, 61% { opacity: 1; } 65%, 100% { opacity: 0; } }
@keyframes hd-w3 { 0%, 65% { opacity: 0; } 69%, 100% { opacity: 1; } }
@keyframes hd-press { 50% { transform: scale(.88); } }
/* 이름표·진행 점 */
.hd-caption { position: absolute; z-index: 2; left: 10px; top: 10px; text-decoration: none !important; padding: 5px 10px; border-radius: 999px;
  background: var(--color-surface); color: var(--color-text); font: 700 var(--text-xs)/1 var(--font-sans);
  border: 1px solid var(--color-outline); }
.hd-dots { position: absolute; z-index: 2; pointer-events: none; left: 0; right: 0; bottom: 8px; display: flex; justify-content: center; gap: 5px; }
.hd-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--color-outline); transition: transform .2s ease; }
.hd-dots i.is-on { background: var(--color-primary); transform: scale(1.3); }
@media (hover: hover) { .hd-caption:hover { border-color: var(--color-primary); } }
@media (prefers-reduced-motion: reduce) {
  .hd-scene { transition: none; }
  .hd-react .hd-go, .hd-react .hd-score { opacity: 1; animation: none !important; }
}
@media (min-width: 860px) {
  .hero { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 340px); column-gap: var(--space-6); align-items: center; }
  .hero > * { grid-column: 1; }
  .hero > .hero-demo { grid-column: 2; grid-row: 1 / span 4; align-self: center; margin: 0; }
}

/* 테스트 목록 — 카드 격자가 아니라 계기 목록(순서가 아니라 종류다) */
.test-list { list-style: none; padding: 0; margin: var(--space-4) 0 0;
  border-top: 1px solid var(--color-outline); }
.test-list li { border-bottom: 1px solid var(--color-outline); }
.test-list a { display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: var(--space-3); padding: var(--space-3) var(--space-2); color: var(--color-text); }
@media (hover: hover) { .test-list a:hover { background: var(--color-surface); text-decoration: none; } }
/* 아이콘은 계기 눈금판 타일 — 크기·테두리를 통일해 글리프가 '디자인된 아이콘'으로 읽히게 한다 */
.test-list .t-icon { display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border: 1px solid var(--color-outline); border-radius: var(--radius-md);
  background: var(--color-surface); color: var(--color-signal-text);
  font: 400 var(--text-lg)/1 var(--font-mono); }
.test-list .t-name { font-weight: 600; }
.test-list .t-desc { display: block; color: var(--color-text-muted); font-size: var(--text-sm); font-weight: 400; }
.test-list .t-meta { font: 500 var(--text-xs)/1.6 var(--font-mono); letter-spacing: .06em;
  text-transform: uppercase; color: var(--color-text-muted); text-align: right; white-space: nowrap; }
.test-list .t-meta b { display: block; color: var(--color-data); font-weight: 600; }
@media (max-width: 520px) {
  .test-list a { grid-template-columns: auto 1fr; }
  .test-list .t-meta { grid-column: 2; text-align: left; }
}

/* 버튼 + 설명 한 줄 — 단어 간격에 기대지 않는다(버튼과 글이 붙어 보이던 원인). */
.run-cta { display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-3) var(--space-4); margin: var(--space-4) 0 0; }
.run-cta .muted { max-width: 44ch; }

/* 오늘의 도전 — 하루 한 번의 사건. 앰버 스트라이프가 목록 위에서 오늘을 가리킨다. */
.daily-card { display: grid; grid-template-columns: auto 1fr auto;
  gap: var(--space-3) var(--space-4);
  align-items: center; margin: var(--space-5) 0 calc(-1 * var(--space-2));
  padding: var(--space-4); border: 1px solid var(--color-outline);
  border-left: 3px solid var(--color-primary); border-radius: var(--radius-lg);
  background: var(--color-surface); color: var(--color-text); text-decoration: none !important; }
@media (hover: hover) { .daily-card:hover { border-color: var(--color-primary); } }
.daily-card .eyebrow { margin: 0; color: var(--color-signal-text); }
.daily-main b { display: block; font-size: var(--text-lg); }
.daily-sub { display: block; color: var(--color-text-muted); font-size: var(--text-sm); }
.daily-count { font: 600 var(--text-xs)/1.4 var(--font-mono); letter-spacing: .06em;
  text-transform: uppercase; color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
@media (max-width: 520px) {
  .daily-card { grid-template-columns: auto 1fr; }
  .daily-cta { grid-column: 2; }
}
/* 스테이지의 회차 스탬프(데일리 모드) */
.daily-badge { position: absolute; top: var(--space-2); left: var(--space-2); z-index: 1;
  font: 700 var(--text-xs)/1 var(--font-mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--color-signal-text); padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-outline); border-radius: var(--radius-sm); background: var(--color-bg); }
/* 종합 측정 유형 총평 — 일곱 개를 다 돌았을 때의 한 장 판정 */
.run-type { border: 1px solid var(--color-outline); border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-lg); padding: var(--space-4); margin: var(--space-4) 0; }
.run-type .eyebrow { margin-bottom: var(--space-1); }
.run-type-title { font: 800 var(--text-xl)/1.3 var(--font-sans); margin: 0 0 var(--space-2); }
.run-type .muted { margin: 0; max-width: 60ch; }
/* 종합 합산 점수(2026-09-28) — 유형 상자 아래, 같은 틀. 숫자가 주인공이라 크게 */
.run-score { border: 1px solid var(--color-outline); border-radius: var(--radius-lg); background: var(--color-surface);
  padding: var(--space-4); margin: var(--space-3) 0; }
.run-score .eyebrow { margin-bottom: var(--space-1); }
.run-score-value { font: 800 var(--text-hero)/1.1 var(--font-mono); font-variant-numeric: tabular-nums; margin: 0 0 var(--space-2); }
.run-score .muted { margin: 0; max-width: 60ch; }
.run-pts { font: 700 var(--text-xs)/1 var(--font-mono); color: var(--color-signal-text); }
#run > .rank-box { margin: var(--space-3) 0; }

/* 결과 패널의 데일리 블록 */
.daily-result { border: 1px solid var(--color-outline); border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-md); padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm); color: var(--color-text-muted); }

/* 업적 토스트(결과 화면) + 홈 마일스톤 배지 줄 */
.ach-toast { border: 1px solid var(--color-outline); border-left: 3px solid var(--color-success);
  border-radius: var(--radius-md); padding: var(--space-2) var(--space-3);
  font: 600 var(--text-sm)/1.5 var(--font-sans); color: var(--color-text);
  animation: tile-pop 200ms cubic-bezier(.34, 1.56, .64, 1); }
.ach-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-top: var(--space-3); }
.ach-label { font: 600 var(--text-xs)/1 var(--font-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--color-text-muted); margin-right: var(--space-1); }
.ach-chip { display: inline-flex; align-items: center; gap: var(--space-1);
  border: 1px solid var(--color-outline); border-radius: 999px;
  padding: var(--space-1) var(--space-3); font-size: var(--text-xs);
  color: var(--color-text-muted); opacity: .45; }
.ach-chip.is-won { opacity: 1; color: var(--color-text); border-color: var(--color-primary); }
.ach-chip.is-won .ach-glyph { color: var(--color-signal-text); }
.daily-result b { color: var(--color-signal-text); font-family: var(--font-mono); }
/* 데일리 결과 글리프 줄 — 공유되는 모양 그대로 보여준다 */
.daily-grid { display: inline-block; margin-top: var(--space-1);
  font: 600 var(--text-md)/1.4 var(--font-mono); letter-spacing: .1em; color: var(--color-text); }

/* 테스트 스테이지 — 계측 패널 */
.test-stage { position: relative; background: var(--color-surface);
  border: 1px solid var(--color-outline); border-radius: var(--radius-lg);
  min-height: 360px; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: var(--space-3); text-align: center;
  touch-action: manipulation; user-select: none; -webkit-user-select: none;
  cursor: pointer; padding: var(--space-4); overflow: hidden; }
/* 스테이지 색에는 전환을 걸지 않는다.
   반응속도 자극이 120ms에 걸쳐 서서히 나타나면 "언제 초록이 됐는가"가 흐려지고
   그 시간이 측정값에 얹힌다 — 측정 도구에서 눈요기보다 즉시성이 먼저다(2026-08-02). */
.test-stage .stage-msg { font: 700 var(--text-xl)/1.2 var(--font-sans); margin: 0; max-width: 100%; overflow-wrap: anywhere; }
/* 외워야 할 숫자 — 고정폭으로, 화면 폭에 맞춰 줄어든다.
   고정 크기로 두면 16자리부터 좁은 화면에서 잘려 나갔다(2026-08-02 실측). */
.test-stage .stage-msg.is-digits {
  font: 800 clamp(1.4rem, 7vw, 2.2rem)/1.2 var(--font-mono);
  font-variant-numeric: tabular-nums; letter-spacing: .06em; }
.test-stage .stage-sub { color: var(--color-text-muted); font: 500 var(--text-xs)/1 var(--font-mono);
  letter-spacing: .12em; text-transform: uppercase; margin: 0; }
/* 계측 프레임 — 뷰파인더식 모서리 눈금. 빈 상자가 아니라 측정 시야라는 뜻을 준다.
   재생 중(is-wait/is-go)에는 배경이 신호색이 되므로 눈금을 치운다. */
.test-stage::before { content: ""; position: absolute; inset: 10px; pointer-events: none;
  background:
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) top left / 14px 1px,
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) top left / 1px 14px,
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) top right / 14px 1px,
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) top right / 1px 14px,
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) bottom left / 14px 1px,
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) bottom left / 1px 14px,
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) bottom right / 14px 1px,
    linear-gradient(var(--color-text-muted), var(--color-text-muted)) bottom right / 1px 14px;
  background-repeat: no-repeat; opacity: .5; }
.test-stage.is-wait { background: var(--color-stage-wait); border-color: var(--color-stage-wait); }
.test-stage.is-go { background: var(--color-stage-go); border-color: var(--color-stage-go); }
.test-stage.is-wait::before, .test-stage.is-go::before { content: none; }
.test-stage.is-wait .stage-msg, .test-stage.is-go .stage-msg,
.test-stage.is-wait .stage-sub, .test-stage.is-go .stage-sub { color: var(--color-on-stage); }
.test-stage > .btn, .test-stage > .btn-secondary { position: relative; z-index: 1; }

/* 시작 전 화면(pre-start) — 명세 2026-08-12-prestart-spec.md.
   측정 시작 전에만 보인다(Start의 hidden을 따라간다). 도형은 전부 CSS — 이미지 자산 0. */
.stage-prestart { position: relative; z-index: 1; display: flex; flex-direction: column;
  align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.stage-prestart[hidden] { display: none; }
.stage-rival { margin: 0; color: var(--color-signal-text);
  font: 700 var(--text-md)/1.35 var(--font-sans); text-align: center; max-width: 30ch;
  letter-spacing: -.01em; }
.stage-best { margin: 0; color: var(--color-text-muted);
  font: 600 var(--text-xs)/1 var(--font-mono); letter-spacing: .04em; }

.stage-preview { display: flex; align-items: center; justify-content: center; gap: var(--space-3); }

/* 숫자가 보였다 가려지는 데모 — 이 게임이 실제로 하는 일이다.
   3.2초 주기: 보임 → 가려짐 → 쉼. 측정 전 화면이라 기록에 닿지 않는다(Start를 누르면 사라진다). */
@keyframes pv-flash {
  0%, 34% { opacity: 1; }
  40%, 88% { opacity: 0; }
  94%, 100% { opacity: 1; }
}
/* 침팬지 — 실제 타일 크기로. 켜진 상태의 재질(깊이·테두리 강조)까지 준다. */
.pv-tiles .pv-tile { width: clamp(52px, 15vw, 76px); aspect-ratio: 1; border-radius: var(--radius-md);
  background: var(--color-surface-raised); border: 2px solid var(--color-outline);
  box-shadow: 0 6px 14px var(--f1-socket);
  display: flex; align-items: center; justify-content: center; }
.pv-tiles .pv-tile span { color: var(--color-primary);
  font: 700 var(--text-xl)/1 var(--font-mono);
  animation: pv-flash 3.2s cubic-bezier(.4, 0, .2, 1) infinite; animation-delay: calc(var(--i) * 90ms); }
/* 숫자 기억 — 한 줄로 크게. 같은 데모(보였다 사라진다). */
.pv-digits { gap: var(--space-2); }
.pv-digits .pv-digit { min-width: clamp(30px, 9vw, 44px); padding: var(--space-2) 0;
  border-bottom: 3px solid var(--color-outline); display: flex; justify-content: center; }
.pv-digits .pv-digit span { color: var(--color-primary);
  font: 700 var(--text-2xl, var(--text-xl))/1 var(--font-mono);
  animation: pv-flash 3.2s cubic-bezier(.4, 0, .2, 1) infinite; animation-delay: calc(var(--i) * 90ms); }

/* 줄이기 신호 존중 — 깜빡임을 멈추고 숫자를 계속 보여준다(정보는 남기고 모션만 뺀다). */
@media (prefers-reduced-motion: reduce) {
  .pv-tiles .pv-tile span, .pv-digits .pv-digit span { animation: none; opacity: 1; }
}
/* 스테이지 아래 도구 줄 — 판 안에는 게임만. 왼쪽 난이도, 오른쪽 다시하기·소리.
   스테이지에 바짝 붙인다 — 컨트롤은 영향을 주는 대상 곁에(grouping, 2026-08-04). */
.stage-tools { display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); margin-top: var(--space-1); min-height: 40px; }
.stage-tools-side { display: flex; align-items: center; gap: var(--space-2); }
.stage-tools-side:last-child { margin-left: auto; }
.stage-tool { width: 40px; min-height: 40px; padding: 0; font-size: var(--text-lg);
  color: var(--color-text-muted); position: relative; }
@media (hover: hover) { .stage-tool:hover { color: var(--color-text); } }
/* 소리 끔 상태는 사선+흐림 (컬러 이모지 🔊는 흑백 글리프 통일 원칙에 어긋나 쓰지 않는다) */
.sound-toggle.is-off { opacity: .55; }
.sound-toggle.is-off::after { content: ''; position: absolute; left: 9px; right: 9px;
  top: 50%; height: 2px; background: currentColor; transform: rotate(-45deg); }
/* 소리 설정 패널 — ♪ 아래에 떠서 효과음·배경 음악을 각각 조절 */
.stage-tools-side { position: relative; }
.sound-panel { position: absolute; top: 44px; right: 0; z-index: 5;
  background: var(--color-surface); border: 1px solid var(--color-outline);
  border-radius: var(--radius-md); padding: var(--space-3); display: grid; gap: var(--space-2);
  box-shadow: var(--shadow-pop); }
/* 팝오버 등장 — 트리거(♪) 쪽에서 자라난다(공간적 연결). 닫힘은 즉답(비대칭 타이밍).
   @starting-style 미지원 브라우저는 지금처럼 즉시 표시(점진 향상). */
@media (prefers-reduced-motion: no-preference) {
  .sound-panel { transform-origin: top right;
    transition: opacity .16s ease-out, transform .16s ease-out; }
  @starting-style { .sound-panel { opacity: 0; transform: scale(.95); } }
}
.sound-row { display: grid; grid-template-columns: auto 64px 110px; align-items: center;
  gap: var(--space-2); font: 500 var(--text-xs)/1 var(--font-mono); color: var(--color-text);
  white-space: nowrap; cursor: pointer; }
.sound-row input[type="range"] { width: 110px; accent-color: var(--color-primary); }
.sound-row input[type="checkbox"] { accent-color: var(--color-primary); width: 16px; height: 16px; }

/* 에임 타깃 — 크기는 난이도가 인라인으로 정한다(보통 48px) */
.aim-target { position: absolute; width: 48px; height: 48px; border-radius: 50%;
  background: var(--color-primary); border: 2px solid var(--color-on-primary); cursor: crosshair; }

/* 난이도 선택 — 도구 줄 왼쪽에 산다. 데일리·종합 측정 중에는 아예 만들지 않는다(page.js). */
.mode-select { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.mode-btn { min-height: 36px; padding: 0 var(--space-3); border-radius: var(--radius-md);
  font: 600 var(--text-xs)/1 var(--font-mono); letter-spacing: .04em;
  background: none; border: 1px solid var(--color-outline); color: var(--color-text-muted); cursor: pointer; }
@media (hover: hover) { .mode-btn:hover { color: var(--color-text); border-color: var(--color-primary); } }
.mode-btn[aria-pressed="true"] { color: var(--color-signal-text); border-color: var(--color-primary);
  background: var(--color-bg); font-weight: 700; }

/* 격자(순서·색) */
/* 칸 크기는 src/js/lib/grid.js가 --cols/--tile로 정한다(SSOT).
   여기서 min-width로 따로 바닥을 깔면 트랙보다 타일이 커져 서로 겹친다 — 실제로 겪었다. */
.tile-grid { display: grid; gap: var(--space-2); margin: 0 auto;
  grid-template-columns: repeat(var(--cols, 3), var(--tile, 44px)); }
.tile { width: var(--tile, 44px); height: var(--tile, 44px); border-radius: var(--radius-md);
  background: var(--color-surface-raised); border: 1px solid var(--color-outline);
  cursor: pointer; position: relative; }
.tile.is-lit { background: var(--color-primary); border-color: var(--color-on-primary); }
@keyframes tile-pop { from { transform: scale(.82); } }
@keyframes tile-shake { 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }
/* 정답 탭 손맛 — 얇은 링 하나가 퍼지고 끝(transform/opacity만 애니메이트, 무끊김 원칙).
   번쩍이는 색 반전 대신 미니멀한 파동으로 "맞았다"를 준다. */
@keyframes hit-ring { from { transform: scale(.92); opacity: .9; } to { transform: scale(1.18); opacity: 0; } }
.tile.is-hit { animation: tile-pop 160ms cubic-bezier(.34, 1.56, .64, 1); }
.tile.is-hit::before { content: ""; position: absolute; inset: -3px; border-radius: inherit;
  border: 2px solid var(--color-primary); pointer-events: none;
  animation: hit-ring 340ms ease-out forwards; }
/* 침팬지: 맞힌 칸은 조용히 물러난다 — 표식을 얹는 대신 무대에서 빠지는 쪽이 차분하다 */
.tile.is-done { opacity: .22; transition: opacity 160ms ease-out; }
.tile.is-answer { animation: tile-pop 120ms ease-out; }
.tile.is-wrong { animation: tile-shake 160ms ease-in-out; }
/* 정답 표식(✓) — 색만으로 알리지 않기 위한 접근성 장치. 톤은 낮춘다(번쩍임 금지). */
.tile.is-answer { outline: 2px solid var(--color-success); outline-offset: -2px; position: relative; }
.tile.is-answer::after { content: "✓"; position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center; color: var(--color-success); opacity: .9;
  font: 600 var(--text-sm)/1 var(--font-mono); }
.tile.is-wrong { outline: 2px solid var(--color-danger); outline-offset: -2px; }

/* ─── 침팬지 스테이지 연출(2026-08-03) — 판의 세 박자: 숫자 깔림·가림·판 통과.
   transform만 쓴다: 시간제 노출(0.65초)에서 opacity 연출은 숫자 판독 시간을 깎는다.
   깔림은 전 타일 동시 팝 — 순서대로 시차를 주면 순서 정보가 시간축으로 새서 과제가 쉬워진다(측정 동등성). */
/* 2차(같은 날): "티가 잘 안 난다"(사장님) — 전부 크고 길게. 1차의 소심한 수치(스케일 .86~1.07,
   170~320ms)는 44px 타일에서 안 읽혔다. 시간제 모드만 짧게 유지(판독 시간 보호). */
@media (prefers-reduced-motion: no-preference) {
  .tile.is-enter { animation: tile-enter 280ms cubic-bezier(.34, 1.56, .64, 1); }
  .tile-grid.is-timed .tile.is-enter { animation-duration: 120ms; }
  .tile.is-mask { animation: tile-mask 300ms ease-in-out; } /* 세로 블링크 — "닫혔다"가 보인다 */
  .tile-grid.is-clear { animation: grid-clear 420ms cubic-bezier(.2, .9, .3, 1.4); }
  .tile-grid.is-clear .tile.is-done { animation: tile-clear-pop 420ms ease-out; }
}
@keyframes tile-enter { from { transform: scale(.45); } 62% { transform: scale(1.12); } }
@keyframes tile-mask { 45% { transform: scaleY(.08); } }
@keyframes grid-clear { 30% { transform: translateY(-6px) scale(1.03); } 60% { transform: translateY(0) scale(.99); } }
@keyframes tile-clear-pop { 25% { opacity: .75; transform: scale(1.22); } 100% { opacity: .22; } }

/* ─── 타자 스테이지 — 한국 타자연습 정석 2줄 대응: 제시문 배너 + 바로 아래 보이는 입력줄.
   숨은 입력(1px·투명, Monkeytype식)은 한글 IME에서 공식 고장이라 폐기(research-2026-08-03-typing-ux.md).
   치는 글자가 입력줄에 그대로 보여 조용한 죽음이 구조적으로 불가능하다. */
.type-line { position: relative; font: 600 var(--text-lg)/1.8 var(--font-sans); max-width: 44ch;
  margin: var(--space-4) auto 0; padding: var(--space-3) var(--space-4);
  background: var(--color-surface-raised); border: 1px solid var(--color-outline);
  border-radius: var(--radius-md); text-align: left; user-select: none;
  color: var(--color-text-muted); }
.type-line .t-ok { color: var(--color-text); }
.type-line .t-bad { color: var(--color-danger); text-decoration: underline; text-underline-offset: 3px; }
/* IME 조합 중 글자 — 판정 전이지만 "입력이 들어오고 있다"를 즉시 보여준다 */
.type-line .t-composing { color: var(--color-text); border-bottom: 2px dotted var(--color-primary); }
/* 미끄러지는 캐럿 — 현재 글자 위치로 transition(프리미엄 감의 절반은 이 장치 하나).
   이동은 left/top이 아니라 transform으로 — 키 입력마다 움직이는 최고 빈도 지점이라
   레이아웃 속성 애니메이션은 금물(컴포지터 전용, 2026-08-04 애니메이션 감사). */
.type-caret { position: absolute; left: 0; top: 0; width: 2px; background: var(--color-primary); pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  .type-caret { transition: transform 80ms ease-out; animation: caret-blink 1.1s step-end infinite; }
}
@keyframes caret-blink { 50% { opacity: .25; } }
/* 유령 페이스 캐럿 — 최고 기록 속도가 달리는 청록 바 + ▾ 표식(깜빡임 없음 — 진짜 캐럿과 구분).
   1차(회색 점선만)는 "버그 같다" 판정(사장님) — 표식 없는 유령은 유령이 아니라 얼룩이다. */
.type-ghost { background: none; border-left: 2px solid var(--color-data); width: 0; opacity: .6; animation: none; }
.type-ghost::before { content: "▾"; position: absolute; top: -1em; left: -0.34em;
  color: var(--color-data); font-size: .72em; line-height: 1; opacity: .95; }
@media (prefers-reduced-motion: no-preference) {
  .type-ghost { transition: transform .24s linear; }
}
/* 순위판 난이도 탭 — 난이도마다 별도 보드(사장님 2026-08-04). 누른 탭만 강조 */
.rank-tabs { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: var(--space-1) 0 var(--space-2); }
.rank-tab { font: 600 var(--text-xs)/1 var(--font-mono); padding: 4px 10px;
  border: 1px solid var(--color-outline); border-radius: var(--radius-sm);
  background: none; color: var(--color-text-muted); cursor: pointer;
  transition: border-color .15s ease, color .15s ease, transform .1s ease-out; }
@media (hover: hover) { .rank-tab:hover { color: var(--color-text); } }
.rank-tab:active { transform: scale(.97); }
.rank-tab[aria-pressed="true"] { border-color: var(--color-primary); color: var(--color-text); font-weight: 700; }

/* 허브의 게임별 순위판 그리드 — rank-box 부품 재사용, 폭 제한만 해제 */
.boards-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: var(--space-3); margin-top: var(--space-3); }
.boards-grid .rank-box { margin-top: 0; max-width: none; }

/* 결과 타수-시간 그래프 — 이번 판 곡선 + 최고 기록 점선 */
.typing-graph { margin: var(--space-3) 0 0; }
.typing-graph svg { width: 100%; max-width: 320px; height: 64px; display: block; }
.typing-graph .g-pace { stroke: var(--color-data); stroke-width: 2; fill: none; }
.typing-graph .g-best { stroke: var(--color-outline); stroke-width: 1.5; stroke-dasharray: 5 4; }
.typing-graph figcaption { font: var(--text-xs)/1.5 var(--font-mono); color: var(--color-text-muted);
  margin-top: 2px; }

/* 입력줄 — 밑줄형(한컴 계열). 포커스는 밑줄 색으로 말한다(기본 outline도 유지). */
.type-input { display: block; width: 100%; max-width: 44ch; margin: var(--space-3) auto 0;
  padding: var(--space-2) 2px; font: 500 var(--text-lg)/1.5 var(--font-sans);
  color: var(--color-text); background: none; border: 0; border-radius: 0;
  border-bottom: 2px solid var(--color-outline); }
.type-input:focus { border-bottom-color: var(--color-primary); }
/* 다음 문장 미리보기 — 전환이 끊기지 않게 반 박자 먼저 보여준다 */
.type-next { font: var(--text-sm)/1.6 var(--font-sans); color: var(--color-text-muted);
  max-width: 44ch; margin: var(--space-3) auto 0; text-align: left; opacity: .65; }

/* 에임 명중 링 — 타깃이 사라진 자리에서 파동 하나 */
.hit-ring { position: absolute; border-radius: 50%; border: 2px solid var(--color-primary);
  pointer-events: none; animation: hit-ring 340ms ease-out forwards; }
.tile.is-lit::after { content: attr(data-step); position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--color-on-primary); font: 700 var(--text-md)/1 var(--font-mono); }

/* 입력 */
.field { display: flex; gap: var(--space-2); justify-content: center; flex-wrap: wrap; max-width: 100%; }
.field input { background: var(--color-bg); color: var(--color-text);
  border: 1px solid var(--color-outline); border-radius: var(--radius-md);
  min-height: 44px; padding: 0 var(--space-3);
  font: 700 var(--text-xl)/1 var(--font-mono); font-variant-numeric: tabular-nums;
  width: min(12ch, 100%); text-align: center; letter-spacing: .08em; }

/* 결과 판독부 */
#result { margin-top: var(--space-4); }
.readout { border-color: var(--color-outline); }
.result-value { font: 800 var(--text-readout)/1 var(--font-mono);
  font-variant-numeric: tabular-nums; letter-spacing: -.03em; margin: 0; }
.result-pct { color: var(--color-text-muted); margin: var(--space-2) 0 var(--space-3);
  font-size: var(--text-sm); }
.result-pct b { color: var(--color-data); font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; }
.result-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: var(--space-4) 0 var(--space-3); }
/* 한 줄 판정 — 점수 밑의 펀치라인. 큰 숫자(고정폭) 다음에 오는 사람 말이라 산세리프로 구분한다. */
.verdict { font: 600 var(--text-md)/1.5 var(--font-sans); color: var(--color-text);
  margin: var(--space-2) 0 0; max-width: 52ch;
  white-space: pre-line; /* page.js가 문장 사이에 \n을 넣는다 — 문장 단위 두 줄 표시(사장님 지적: 중간 끊김 가독성) */ }
/* 상황 부제(도박·신기록 격려·재시도·새벽) — 티어 멘트를 대체하지 않고 아래 작은 줄로 얹는다 */
.verdict-sub { font: var(--text-sm)/1.5 var(--font-sans); color: var(--color-text-muted);
  margin: 4px 0 0; max-width: 52ch; }
/* 등급명 배지 — 판정 문장 위의 한 단어 해석층(신기록 .badge와 같은 칩 결, 색만 링크 계열로 구분) */
.tier-chip { display: inline-block; border: 1px solid var(--color-link); color: var(--color-link);
  border-radius: var(--radius-sm); margin: var(--space-2) 0 0; padding: 2px var(--space-2);
  font: 700 var(--text-xs)/1.4 var(--font-mono); letter-spacing: .1em; }
/* 한국어는 단어(어절) 단위로만 줄을 꺾는다 — 기본값은 "골든타/임"처럼 아무 글자에서나 자른다. */
:root:lang(ko) { word-break: keep-all; overflow-wrap: break-word; }
/* 데일리 리더보드 — 계기판 전광판. 순위·점수는 고정폭, 이름과 점수는 점선 리더로 잇는다.
   메달색(금=신호 앰버·은·동)은 Pro Max 리더보드 관례를 토큰으로 이식(--rank-*). */
.rank-box { margin-top: var(--space-4); border: 1px solid var(--color-outline);
  border-radius: var(--radius-lg); padding: var(--space-3) var(--space-4) var(--space-4);
  background: var(--color-surface); max-width: 38ch; }
.rank-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); }
.rank-title { margin: 0; font: 700 var(--text-xs)/1.6 var(--font-mono); color: var(--color-signal-text);
  text-transform: uppercase; letter-spacing: .08em; }
.rank-title a { color: inherit; text-decoration: none; }
@media (hover: hover) { .rank-title a:hover { text-decoration: underline; } }
.rank-more { display: inline-block; margin-top: var(--space-3);
  font: 600 var(--text-sm)/1.4 var(--font-mono); color: var(--color-link); text-decoration: none; }
@media (hover: hover) { .rank-more:hover { text-decoration: underline; } }
.rank-total { font: 600 var(--text-xs)/1.6 var(--font-mono); color: var(--color-text-muted);
  font-variant-numeric: tabular-nums; }
.rank-list { list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.rank-list li { display: flex; align-items: baseline; gap: var(--space-2);
  padding: 6px 0; font: var(--text-sm)/1.5 var(--font-mono); font-variant-numeric: tabular-nums; }
.rank-list li + li { border-top: 1px solid var(--color-grid); }
.rank-no { min-width: 2ch; text-align: right; font-weight: 700; color: var(--color-text-muted); }
/* 닉네임은 전부 보인다 — 8자 제한(한글 모노폭 ≈ 16ch)이 18ch 안에 항상 들어온다.
   말줄임은 제한이 12자였던 시절의 옛 기록용 안전망일 뿐이다(사장님 "풀네임" 2026-08-03). */
.rank-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 18ch; }
.rank-list li i { flex: 1; border-bottom: 1px dotted var(--color-grid); transform: translateY(-4px); }
.rank-list li b { font-weight: 600; }
.rank-list li:nth-child(1) .rank-no, .rank-list li.is-first b { color: var(--rank-gold); }
.rank-list li:nth-child(2) .rank-no { color: var(--rank-silver); }
.rank-list li:nth-child(3) .rank-no { color: var(--rank-bronze); }
.rank-list li.is-ghost { color: var(--color-text-muted); opacity: .5; }
.rank-list li.is-ghost .rank-no { color: inherit; }
.rank-note { margin: var(--space-2) 0 0; font: var(--text-sm)/1.5 var(--font-sans); color: var(--color-text-muted); }
.rank-note.is-you { color: var(--color-signal-text); font: 700 var(--text-sm)/1.5 var(--font-mono); }
.rank-form { justify-content: flex-start; margin-top: var(--space-3); }
/* 닉네임 칸은 글자 입력이다 — 숫자 답 칸(.field input: 굵은 고정폭·가운데·자간)을 물려받아 자리표시자가 잘려 보였다(2026-09-28) */
.rank-form input { flex: 1 1 12ch; width: auto; min-width: 0; font: 500 var(--text-md)/1.2 var(--font-sans); letter-spacing: 0; text-align: left; }
.home-rank { margin: var(--space-3) 0 var(--space-2); max-width: none; }
/* 행 등장 — 8px 떠오름 + 50ms 스태거(툴킷 모션 규칙: transform/opacity만·감속 이징·reduced-motion 존중) */
@media (prefers-reduced-motion: no-preference) {
  .rank-list li { animation: rank-in .4s cubic-bezier(.2, .7, .3, 1) backwards; }
  .rank-list li:nth-child(2) { animation-delay: .05s; }
  .rank-list li:nth-child(3) { animation-delay: .1s; }
  .rank-list li:nth-child(4) { animation-delay: .15s; }
  .rank-list li:nth-child(5) { animation-delay: .2s; }
}
@keyframes rank-in { from { opacity: 0; transform: translateY(8px); } }

/* ─── 결과 보상 연출(2026-08-03) — transform/opacity만, reduced-motion 존중 ─── */
#result { position: relative; }
.rb-mascot { position: absolute; top: var(--space-3); right: var(--space-4);
  width: 72px; height: 72px; pointer-events: none; } /* 얼굴 마크판 — 풀바디는 AI 아트로 재도전(사장님 퀄 판정) */
.rb-mascot svg { width: 100%; height: 100%; display: block; }
.rb-mascot[data-mood="smug"] svg { transform: rotate(-6deg); }
@media (prefers-reduced-motion: no-preference) {
  /* 1차는 "빨라서 효과가 있는지도 모르겠다"(사장님) — 전부 길고 크게.
     2차(같은 날): 등장 후에도 상시 미세 모션 — 멈춘 마스코트는 스티커지 캐릭터가 아니다. */
  .rb-mascot svg { transform-origin: 50% 92%; } /* 스쿼시&스트레치의 축 = 발바닥 */
  .rb-mascot .m-eyes { transform-box: fill-box; transform-origin: 50% 50%;
    animation: mascot-blink 3.4s ease-in-out infinite; } /* 깜빡임 — 살아 있음의 최소 신호 */
  .rb-mascot[data-mood="wow"] svg { animation: mascot-pop .8s cubic-bezier(.2, .9, .3, 1.45), mascot-bounce 1.7s .9s cubic-bezier(.4, 0, .3, 1) infinite; }
  .rb-mascot[data-mood="wow"] .m-banana { transform-box: fill-box; transform-origin: 50% 95%;
    animation: banana-wave 1s .35s cubic-bezier(.4, 0, .3, 1.3) 3; }
  .rb-mascot[data-mood="smug"] svg { animation: mascot-tilt .7s ease-out, mascot-sway 3.2s .8s ease-in-out infinite; }
  .rb-mascot[data-mood="base"] svg { animation: mascot-breathe 3s ease-in-out infinite; }
  /* 결과 요소 순차 등장 — 14px 떠오름, 스태거 ≤6 */
  #result.is-reveal > * { animation: result-rise .5s cubic-bezier(.2, .7, .3, 1) backwards; }
  #result.is-reveal > :nth-child(2) { animation-delay: .07s; }
  #result.is-reveal > :nth-child(3) { animation-delay: .14s; }
  #result.is-reveal > :nth-child(4) { animation-delay: .21s; }
  #result.is-reveal > :nth-child(5) { animation-delay: .28s; }
  #result.is-reveal > :nth-child(6) { animation-delay: .35s; }
  .badge { animation: badge-pop .65s cubic-bezier(.2, .9, .3, 1.6); }
}
@keyframes mascot-pop { 0% { transform: scale(.3); } 55% { transform: scale(1.25); } 100% { transform: scale(1); } }
@keyframes mascot-tilt { from { transform: rotate(14deg); } to { transform: rotate(-6deg); } }
/* 스쿼시&스트레치 바운스 — 착지에서 눌리고 뜰 때 늘어난다(애니메이션 기본기, 밋밋한 상하이동 금지) */
@keyframes mascot-bounce {
  0%, 100% { transform: translateY(0) scale(1, 1); }
  28% { transform: translateY(-9px) scale(.97, 1.05); }
  46% { transform: translateY(0) scale(1.07, .9); }
  62% { transform: translateY(-4px) scale(.99, 1.02); }
  76% { transform: translateY(0) scale(1.03, .96); }
}
@keyframes mascot-sway { 0%, 100% { transform: rotate(-7deg) translateX(0); } 50% { transform: rotate(-1deg) translateX(1.5px); } }
@keyframes mascot-breathe { 0%, 100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-2.5px) scale(1.025, 1.035); } }
@keyframes banana-wave { 0%, 100% { transform: rotate(0); } 45% { transform: rotate(-26deg); } 70% { transform: rotate(6deg); } }
@keyframes mascot-blink { 0%, 91%, 100% { transform: scaleY(1); } 94.5% { transform: scaleY(.08); } 98% { transform: scaleY(1); } }
@keyframes result-rise { from { opacity: 0; transform: translateY(14px); } }
@keyframes badge-pop { from { transform: scale(.3); } 55% { transform: scale(1.3); } to { transform: scale(1); } }
/* 신기록 스파크 — 앰버 점 12개가 크게 흩어지며 사라진다(1회성, blur 없음) */
#result-value { position: relative; }
.spark-burst { position: absolute; left: 1.2em; top: .5em; width: 0; height: 0; pointer-events: none; }
.spark-burst i { position: absolute; width: 9px; height: 9px; border-radius: 50%;
  background: var(--color-primary); animation: spark-fly 1.05s cubic-bezier(.2, .7, .4, 1) forwards; }
@keyframes spark-fly { from { opacity: 1; transform: translate(0, 0) scale(1.1); }
  to { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.15); } }
@media (max-width: 520px) { .rb-mascot { width: 56px; height: 56px; } }
/* 등급 구간 — 분포에서 유도한 값이라 백분위가 있을 때만 나온다.
   색만으로 뜻을 전하지 않게 글자를 함께 쓴다. */
.band { display: inline-block; vertical-align: middle; margin-left: var(--space-2);
  border: 1px solid var(--color-outline); border-radius: var(--radius-sm);
  padding: 2px var(--space-2); font: 700 var(--text-xs)/1.4 var(--font-mono);
  letter-spacing: .08em; color: var(--color-text-muted); cursor: help; }
.band-top, .band-strong { color: var(--color-data); border-color: var(--color-data); }
@keyframes stamp { from { transform: scale(1.7); opacity: 0; } }
.badge { animation: stamp 220ms ease-out; display: inline-block; vertical-align: middle; border: 1px solid var(--color-success);
  color: var(--color-success); border-radius: var(--radius-sm); margin-left: var(--space-2);
  padding: 2px var(--space-2); font: 700 var(--text-xs)/1.4 var(--font-mono); letter-spacing: .1em; }
.meta-line { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.history { list-style: none; padding: 0; margin: 0; font: 400 var(--text-sm)/1 var(--font-mono);
  font-variant-numeric: tabular-nums; color: var(--color-text-muted); }
.history li { padding: var(--space-2) 0; border-bottom: 1px solid var(--color-outline); }

/* 라운드 상세 — 중앙값이 어디서 나왔는지 */
.rounds { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-2); }
.rounds-label { font: 600 var(--text-xs)/1 var(--font-mono); letter-spacing: .16em;
  text-transform: uppercase; color: var(--color-text-muted); }
.round-chip { font: 500 var(--text-xs)/1 var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--color-text-muted); border: 1px solid var(--color-outline);
  border-radius: var(--radius-sm); padding: var(--space-1) var(--space-2); }
.round-chip.is-median { color: var(--color-text); border-color: var(--color-primary); font-weight: 700; }
.round-spread { font: 500 var(--text-xs)/1 var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--color-text-muted); margin-left: auto; }

/* 순위 행 기기 표시 — 터치/마우스 유불리 맥락(사장님 2026-08-04). 옛 기록은 표시 없음 */
.rank-dev { margin-left: 6px; flex: none; display: inline-flex; align-items: center; color: var(--color-text-muted); opacity: .75; cursor: help; }
.dev-ic { vertical-align: -.12em; } /* 부제 등 텍스트 흐름 속 정렬 — 보드 행은 flex라 무해 */

/* 단어 기억 — 단어는 판독 대상이라 크게, 판정 버튼 2개는 엄지 폭으로 */
.stage-msg.is-word { font-size: var(--text-xl); letter-spacing: .01em; }
.verbal-btns { display: flex; gap: var(--space-3); justify-content: center; }
.verbal-btns .btn { min-width: 128px; }

/* 숫자 기억 오답 대조 — 정답/내 입력 겹줄, 틀린 자리만 빨간 취소선 */
.digit-diff { display: inline-grid; grid-template-columns: auto auto;
  gap: 2px var(--space-3); align-items: baseline; text-align: left; margin-top: var(--space-1); }
.digit-diff-label { font: 600 var(--text-xs)/1.4 var(--font-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--color-text-muted); }
.digit-diff-digits { font: 700 var(--text-md)/1.4 var(--font-mono); letter-spacing: .14em;
  font-variant-numeric: tabular-nums; color: var(--color-text); }
.digit-diff-digits .is-off { color: var(--color-danger);
  text-decoration: line-through; text-decoration-thickness: 2px; }

/* 다음 테스트 고리 */
.next-up { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  margin: var(--space-4) 0 0; padding-top: var(--space-3); border-top: 1px solid var(--color-outline); }
.next-up .eyebrow { margin: 0; }
.next-link { text-decoration: none !important; }

/* 홈 — 내 기록 */
#records { margin-top: var(--space-6); }
.records-head { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.records-head h2 { margin: 0; }
.records-streak { font: 600 var(--text-xs)/1 var(--font-mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--color-signal-text); margin: 0; }
.records-grid { list-style: none; padding: 0; margin: var(--space-3) 0 var(--space-2);
  display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--space-2); }
.records-grid li { display: flex; }
/* 카드 높이를 한 줄 안에서 맞춘다 — 백분위 줄이 있는 카드만 키가 커져 줄이 들쭉날쭉했다(2026-09-28) */
.record { flex: 1; display: flex; flex-direction: column; gap: var(--space-1);
  border: 1px solid var(--color-outline); border-radius: var(--radius-md);
  padding: var(--space-3); color: var(--color-text); }
@media (hover: hover) { .record:hover { border-color: var(--color-primary); text-decoration: none; } }
.record-name { font-size: var(--text-sm); color: var(--color-text-muted); }
.record-value { font: 700 var(--text-lg)/1 var(--font-mono); font-variant-numeric: tabular-nums; }
.record-value.is-empty { color: var(--color-text-muted); font-size: var(--text-sm); font-weight: 400; }

/* 시그니처: 분포 곡선 — 결과 화면의 주인공답게 굵고 또렷하게(2026-08-03 개편).
   창 크기가 바뀌어 SVG가 늘어나도 선 굵기는 유지된다(vector-effect). */
.curve-wrap { margin: var(--space-3) 0 var(--space-2); }
.curve { width: 100%; height: 132px; display: block; }
.curve-line, .curve-axis, .curve-tick, .curve-you { vector-effect: non-scaling-stroke; }
.curve-line { fill: none; stroke: var(--color-data); stroke-width: 2.5; stroke-linejoin: round; }
.curve-area { fill: var(--color-data-fill); stroke: none; }
.curve-axis { stroke: var(--color-outline); stroke-width: 1; }
.curve-tick { stroke: var(--color-text-muted); stroke-width: 1.5; }
.curve-dot { fill: var(--color-data); opacity: .8; }
.curve-you { stroke: var(--color-primary); stroke-width: 2.5; }
.curve-you-dot { fill: var(--color-primary); stroke: var(--color-surface); stroke-width: 2; }
.curve-you-label, .curve-label { fill: var(--color-text-muted);
  font: 700 11px var(--font-mono); letter-spacing: .08em; text-transform: uppercase; }
.curve-you-label { fill: var(--color-primary); }
.curve-caption { color: var(--color-text-muted); font-size: var(--text-xs);
  font-family: var(--font-mono); margin: 0; }

/* 본문 아티클 */
article { margin-top: var(--space-6); border-top: 1px solid var(--color-outline); padding-top: var(--space-4); }
article ul { padding-left: var(--space-4); }
/* 산문 목록 — article 밖(홈 등)에서도 아티클과 같은 들여쓰기·간격을 쓴다 */
.prose-list { padding-left: var(--space-4); color: var(--color-text-muted); }
.prose-list li + li, .prose-list ul { margin-top: var(--space-2); }
article h2:first-of-type { margin-top: var(--space-3); }

.lives { font-size: var(--text-md); }

/* 도전장 — 스테이지 배너·대결 비교·보내기 박스 (명세: 2026-08-04-duel-spec.md) */
.duel-banner { border: 1px solid var(--color-outline); border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-lg); background: var(--color-surface);
  padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3);
  display: flex; flex-direction: column; gap: var(--space-1); }
.duel-banner .eyebrow { margin: 0; }
.duel-banner b { font: 700 var(--text-lg)/1.5 var(--font-mono); }
.duel-banner .muted { margin: 0; font-size: var(--text-sm); }

.duel-box { border: 1px solid var(--color-outline); border-radius: var(--radius-lg);
  background: var(--color-surface); padding: var(--space-4); margin-bottom: var(--space-4);
  text-align: center; }
.duel-stamp { margin: 0 0 var(--space-3); font: 800 var(--text-hero)/1.1 var(--font-mono);
  letter-spacing: .12em; text-transform: uppercase; }
.duel-stamp.is-win { color: var(--color-success); }
.duel-stamp.is-lose { color: var(--color-danger); }
.duel-stamp.is-draw { color: var(--color-text-muted); }
@media (prefers-reduced-motion: no-preference) {
  /* 도장이 위에서 크게 찍힌다 — 오버슈트로 눌린 뒤 제자리(모션 규칙: 처음부터 크게) */
  .duel-stamp { animation: duel-stamp .45s cubic-bezier(.2, 1.55, .4, 1) both; }
}
@keyframes duel-stamp { 0% { transform: scale(2.4) rotate(-6deg); opacity: 0; }
  62% { transform: scale(.94) rotate(1deg); opacity: 1; } 100% { transform: scale(1) rotate(0deg); } }
.duel-rows { display: flex; flex-direction: column; gap: var(--space-2); max-width: 26ch; margin: 0 auto; }
.duel-row { display: flex; justify-content: space-between; gap: var(--space-3); margin: 0;
  font: 600 var(--text-md)/1.5 var(--font-mono); color: var(--color-text-muted); }
.duel-row b { font-variant-numeric: tabular-nums; }
.duel-row.is-ahead { color: var(--color-text); }
.duel-row.is-ahead b { color: var(--color-success); }
.duel-more { display: inline-block; margin-top: var(--space-3);
  font: 600 var(--text-sm)/1.4 var(--font-mono); color: var(--color-link); text-decoration: none; }
@media (hover: hover) { .duel-more:hover { text-decoration: underline; } }

.duel-send { margin-top: var(--space-4); border: 1px solid var(--color-outline);
  border-radius: var(--radius-lg); padding: var(--space-3) var(--space-4) var(--space-4);
  background: var(--color-surface); max-width: 38ch; }
.duel-send-title { margin: 0; font: 700 var(--text-xs)/1.6 var(--font-mono);
  color: var(--color-signal-text); text-transform: uppercase; letter-spacing: .08em; }
.duel-send .muted { margin: var(--space-1) 0 var(--space-3); font-size: var(--text-sm); }
.duel-send-row { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.btn-kakao { background: var(--brand-kakao); color: var(--brand-kakao-text); }
.btn-kakao svg { width: 18px; height: 18px; flex: none; }
@media (hover: hover) { .btn-kakao:hover { filter: brightness(.96); } }
.duel-send-row input { flex: 1 1 12ch; min-width: 0; }
.duel-send-note { display: block; margin-top: var(--space-2);
  font: 600 var(--text-sm)/1.5 var(--font-mono); color: var(--color-success); }
.duel-rematch-go { align-self: flex-start; margin-top: var(--space-2); }

/* F1 변형 — 신호등 5등(점등=빨강). 전환 금지: 소등이 측정 자극이다 */
.f1-lights { display: flex; gap: var(--space-2); justify-content: center; margin-bottom: var(--space-3); }
.f1-light { width: clamp(28px, 8vw, 48px); aspect-ratio: 1; border-radius: 50%;
  background: var(--color-bg); border: 2px solid var(--color-outline); }
.f1-light.is-on { background: var(--color-danger); border-color: var(--color-danger); }

/* F1 변형 스테이지 — 야간 그리드. 색 전환 금지 원칙 그대로(소등이 측정 자극). */
.f1-stage { background: var(--f1-track); border-color: var(--f1-gantry); }
.f1-stage .stage-msg { color: var(--f1-text); }
.f1-stage .stage-sub { color: var(--f1-text); opacity: .55; }
/* 체커 스트립 — 스테이지 하단(코너 마크 ::before와 공존하도록 ::after 사용) */
.f1-stage::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 14px;
  background: repeating-conic-gradient(var(--f1-check) 0% 25%, transparent 0% 50%) 0 0 / 14px 14px;
  pointer-events: none; }
/* 신호등 거치대 — 하우징에 담긴 5등. 켜지면 레이싱 레드 + 글로우(1차부터 크게) */
.f1-stage .f1-lights { background: var(--f1-gantry); border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4); gap: var(--space-3); }
.f1-stage .f1-light { width: clamp(34px, 9vw, 58px); background: var(--f1-light-off); border: 0; }
.f1-stage .f1-light.is-on { background: var(--f1-red);
  box-shadow: 0 0 22px 6px var(--f1-red-glow), inset 0 0 10px 2px var(--f1-red-glow); }

/* 홈 변형 카드 — 세트(8종) 밖의 테마 변형 진입로. F1 야간 룩, v6 확정(머신 실루엣+광 트레일).
   v1~v5 불꽃 계열 규칙은 2026-08-04 애니메이션 감사에서 삭제(죽은 규칙 정리). */
.variant-card { display: block; margin-top: var(--space-3); text-decoration: none;
  position: relative; overflow: visible; }
.variant-body { display: flex; align-items: center; gap: var(--space-3); position: relative;
  padding: var(--space-3) var(--space-4); padding-right: 200px; background: var(--f1-track);
  border-radius: var(--radius-lg); overflow: hidden; }
.variant-card .vlights { display: flex; gap: 6px; flex: none; }
.variant-card .vlights span { width: 14px; height: 14px; border-radius: 50%;
  background: var(--f1-red); box-shadow: 0 0 8px 2px var(--f1-red-glow); }
.variant-card b { color: var(--f1-text); font: 700 var(--text-md)/1.4 var(--font-sans); display: block; }
.variant-card .variant-sub { color: var(--f1-text); opacity: .6; font: 500 var(--text-sm)/1.5 var(--font-sans); }
.variant-card .eyebrow { margin: 0; }
@media (hover: hover) { .variant-card:hover b { text-decoration: underline; } }

/* 데일리 완료 카드 — 연속 출석 표시 + "다음 추천"(별개 행동 — 도전은 하루 한 게임) */
.daily-streak { font-weight: 700; }
.daily-upnext-label { display: block; font: 600 var(--text-xs)/1.6 var(--font-mono);
  color: var(--color-text-muted); text-transform: uppercase; letter-spacing: .08em; }
.daily-cta .daily-upnext { text-decoration: none; }
div.daily-card { cursor: default; }

/* 데일리 완료 카드 CTA — 라벨/버튼/카운트다운을 세로 스택으로(인라인 흐름이면 좁은 화면에서
   카운트다운이 버튼 옆에 붙어 두 동강 난다 — 사장님 모바일 실측 2026-08-04) */
.daily-cta { display: flex; flex-direction: column; align-items: flex-end;
  justify-content: center; gap: var(--space-1); }
@media (max-width: 520px) { .daily-cta { align-items: flex-start; margin-top: var(--space-2); } }

/* F1 5쌍 갠트리 — 기둥(등 2개)이 한 단위로 켜진다(실제 절차의 "five pairs") */
.f1-stage .f1-col { display: flex; flex-direction: column; gap: 6px; }
.f1-stage .f1-col .f1-light { width: clamp(26px, 7vw, 44px); }
.f1-stage .f1-col.is-on .f1-light { background: var(--f1-red);
  box-shadow: 0 0 18px 5px var(--f1-red-glow), inset 0 0 8px 2px var(--f1-red-glow); }
/* 소등 순간 대형 GO — 즉시 등장(전환 금지 원칙 유지), 초록 글로우만 */
.f1-stage .stage-msg.is-go-big { font-size: var(--text-hero); font-weight: 800;
  color: var(--color-stage-go); text-shadow: 0 0 28px var(--color-stage-go); letter-spacing: .04em; }

/* F1 페이지 머리 — 레이싱 레드 바 + 체커 깃발 칩(본문 결은 그대로, 머리만 테마) */
.f1-title { border-left: 6px solid var(--f1-red); padding-left: var(--space-3); }
.f1-title::after { content: ""; display: inline-block; width: 22px; height: 15px; margin-left: 10px;
  background: repeating-conic-gradient(var(--color-text) 0% 25%, transparent 0% 50%) 0 0 / 8px 8px;
  border: 1px solid var(--color-outline); }
/* F1 스테이지의 버튼 = 레이싱 레드 + 글로우(야간 스테이지 위 주황 이질감 제거) */
.f1-stage .btn { background: var(--f1-red); color: var(--f1-text);
  box-shadow: 0 0 18px 2px var(--f1-red-glow); }

/* F1 신호등 실물감 — 등이 소켓에 파묻히고(안쪽 그림자), 켜지면 전구처럼 중심이 뜨겁다 */
.f1-stage .f1-lights { border-radius: 14px;
  box-shadow: inset 0 -5px 12px var(--f1-socket), 0 8px 22px var(--f1-socket); }
.f1-stage .f1-col .f1-light {
  background: radial-gradient(circle at 50% 32%, var(--f1-light-off), var(--f1-gantry) 78%);
  box-shadow: inset 0 3px 7px var(--f1-socket); }
.f1-stage .f1-col.is-on .f1-light {
  background: radial-gradient(circle at 50% 32%, var(--f1-red-hot), var(--f1-red) 72%);
  box-shadow: 0 0 18px 5px var(--f1-red-glow), inset 0 2px 5px var(--f1-socket); }

/* 카드 아트 — 광 트레일 3줄 + 머신 실루엣. SVG 그라디언트 색은 아래 stop 클래스가 SSOT */
.variant-flames { position: absolute; right: 6px; bottom: 4px; width: 320px; height: auto;
  z-index: 1; pointer-events: none; }
.vf-stop-red { stop-color: var(--f1-red); }
.vf-stop-org { stop-color: var(--f1-flame); }
.vf-stop-hot { stop-color: var(--f1-flame-hot); }
.f1-wheel { fill: var(--f1-light-off); }
@media (prefers-reduced-motion: no-preference) {
  .f1-streaks rect { animation: f1-streak 1.4s ease-in-out infinite; }
  .f1-streaks rect:nth-child(2) { animation-delay: .45s; }
  .f1-streaks rect:nth-child(3) { animation-delay: .9s; }
  .f1-car { animation: f1-bob 1.1s ease-in-out infinite alternate; }
}
@keyframes f1-streak { 0% { transform: translateX(-26px); opacity: 0; } 35% { opacity: 1; } 100% { transform: translateX(16px); opacity: 0; } }
@keyframes f1-bob { from { transform: translateY(0); } to { transform: translateY(-1.5px); } }
@media (max-width: 640px) {
  .variant-body { flex-direction: column; align-items: flex-start; gap: var(--space-2);
    padding-right: var(--space-4); padding-bottom: 78px; }
  .variant-flames { width: 210px; right: 8px; bottom: 8px; }
}

/* ── 게임 면 본문 개편 시범(2026-09-28, 명세 2026-09-28-test-page-layout-pilot-spec.md) ──
   사장님: "글 폭이나 이런거 좀 맞추고 여백이랑 공백 배치도 신경쓰고 … 너무 투박하지 않게",
   "박스랑 글이 너무 붙어있지 않게 적당한 여백을". 시범이라 .page-head·article.prose를 단 면에만 걸린다 —
   승인되면 나머지 면에 클래스만 붙여 넓힌다(규칙을 다시 쓰지 않는다).
   배치 원칙: ①글줄과 박스가 **사이트 폭 전체(.wrap)**의 한 기둥에 선다(사장님 2026-09-28 — 좁은 기둥 45rem에서 넓힘)
   ②박스는 위 24px·아래 40px 떨어뜨린다(글 → 박스 → 글의 숨) ③박스 안쪽은 20px. */
.page-head { margin-bottom: var(--space-5); }
.page-head h1 { font-size: clamp(1.75rem, 4.5vw, 2.25rem); line-height: 1.15; letter-spacing: -.02em; margin-bottom: var(--space-2); }
.page-head .dates { margin-bottom: var(--space-4); }
.page-head .muted { font-size: var(--text-md); margin-bottom: var(--space-2); }

article.prose { --box-pad: 20px; margin-top: var(--space-6); padding-top: var(--space-5); }
article.prose p, article.prose li { font-size: 1.0625rem; line-height: 1.8; }
:root:lang(en) article.prose p { font-size: 1.125rem; line-height: 1.75; }
article.prose > p { margin-bottom: var(--space-3); }
article.prose h2 { font-size: 1.5rem; line-height: 1.25; letter-spacing: -.02em; margin: var(--space-6) 0 var(--space-3); }
article.prose h2:first-of-type { margin-top: 0; }
article.prose h3 { font-size: 1.0625rem; line-height: 1.4; }
/* 박스(단계·표·카드·FAQ·관련 목록) — 글과 붙지 않게 위아래 숨 */
article.prose > .steps, article.prose > .table-box, article.prose > .tip-grid,
article.prose > .faq-list, article.prose > .test-list { margin: var(--space-4) 0 var(--space-5); }
article.prose > h2 + .steps, article.prose > h2 + .faq-list, article.prose > h2 + .test-list { margin-top: var(--space-3); }
article.prose > :last-child { margin-bottom: 0; }

/* 하는 법(2026-09-28 개편 — 사장님 "방법 설명하는 섹션도 퀄리티 업그레이드") — 왼쪽 = 그 게임 플레이 데모, 오른쪽 = 세로 번호 흐름.
   번호 원을 잇는 선이 "차례대로"를 보여준다(가로 카드 4장은 순서가 안 읽혔다). 좁으면 데모 위·단계 아래. */
.howto { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-5); align-items: center;
  margin: var(--space-3) 0 var(--space-5); }
.howto-demo { margin: 0; } /* 단계 목록 가운데 높이에 고정 — 스크롤을 따라다니지 않는다(사장님 9/28 종합 측정 8단계에서 "따라 움직이는데 그렇게 하지말고 딱 가운데에") */
.howto-demo .demo-box { box-shadow: none; }
/* 상자가 넓으면(게임 면 ~440px) 장면 부품도 키운다 — 홈 히어로(340px) 크기로 짠 픽셀 값이라 넓은 상자에선 작아 보였다.
   위치(%)로 놓이는 것(에임 과녁·조준점)은 zoom을 걸면 자리가 어긋나 크기만 따로 준다. */
.demo-box { container-type: inline-size; }
@container (min-width: 400px) {
  .hd-grid, .hd-words, .hd-btns, .hd-typeline, .hd-pill, .hd-gantry, .hd-digits, .hd-bar, .hd-typed, .hd-ok { zoom: 1.3; }
  .hd-tg { width: 40px; height: 40px; margin: -20px 0 0 -20px; }
  .hd-crs { width: 20px; height: 20px; margin: -10px 0 0 -10px; }
  .hd-layer { font-size: 2rem; } .hd-score { font-size: var(--text-lg); }
}
.howto-demo figcaption { margin-top: var(--space-2); font: 500 var(--text-xs)/1.4 var(--font-sans); color: var(--color-text-muted); text-align: center; }
.steps { list-style: none; padding: 0; margin: 0; display: grid; gap: 0; counter-reset: step; }
.steps li { counter-increment: step; position: relative; display: flex; flex-direction: column; gap: 4px;
  padding: 4px 0 var(--space-4) 52px; min-height: 34px; }
.steps li:last-child { padding-bottom: 0; }
.steps li::before { content: counter(step); position: absolute; left: 0; top: 0; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; background: var(--color-primary); color: var(--color-on-primary);
  font: 800 var(--text-sm)/1 var(--font-mono); }
.steps li::after { content: ""; position: absolute; left: 16px; top: 40px; bottom: 6px; width: 2px; border-radius: 1px; background: var(--color-outline); }
.steps li:last-child::after { content: none; }
.steps b { font-size: var(--text-md); line-height: 1.35; }
article.prose .steps li span { font-size: var(--text-sm); line-height: 1.65; color: var(--color-text-muted); }
@media (max-width: 760px) {
  .howto { grid-template-columns: 1fr; gap: var(--space-4); }
  .howto-demo { max-width: 420px; }
}

/* 등급표 — 한 기둥 폭, 좁으면 두 줄 배치(아래 미디어 쿼리) */
.table-box { border: 1px solid var(--color-outline); border-radius: var(--radius-lg);
  overflow-x: auto; background: var(--color-surface); }
article.prose .table-box table { display: table; margin: 0; font-size: var(--text-sm); }
article.prose .table-box th, article.prose .table-box td { border: 0; border-bottom: 1px solid var(--color-outline);
  padding: 14px var(--box-pad); line-height: 1.6; vertical-align: middle; }
article.prose .table-box tr:last-child td { border-bottom: 0; }
article.prose .table-box th { font: 600 var(--text-xs)/1.4 var(--font-mono); letter-spacing: .08em;
  text-transform: uppercase; color: var(--color-text-muted); background: transparent; padding-top: 12px; padding-bottom: 12px; }
.table-box td:first-child { font: 700 var(--text-sm)/1.6 var(--font-mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
.table-box .tier-chip { margin: 0; white-space: nowrap; }

/* 기록 줄이는 법 — 카드 2열. 화면당 카드 묶음은 이것 하나(06 §5-1 A 예외 사유는 명세 §1-2) */
.tip-grid { display: grid; gap: var(--space-3); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 600px) { .tip-grid { grid-template-columns: 1fr; } }
.tip-grid section { border: 1px solid var(--color-outline); border-radius: var(--radius-lg);
  background: var(--color-surface); padding: var(--box-pad); }
/* 카드가 홀수면 마지막 한 장이 반쪽에 혼자 남는다 — 전폭으로 닫는다 */
.tip-grid section:last-child:nth-child(odd) { grid-column: 1 / -1; }
article.prose .tip-grid h3 { margin: 0 0 var(--space-2); font-size: var(--text-md); }
article.prose .tip-grid p { font-size: var(--text-sm); line-height: 1.7; color: var(--color-text-muted); margin: 0; }

/* 자주 묻는 질문 — 접는 질문. 선으로만 나누고, 열림 표시는 회전하는 꺾쇠(transform만) */
.faq-list { border-top: 1px solid var(--color-outline); }
details.faq { border-bottom: 1px solid var(--color-outline); }
details.faq summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--space-3);
  justify-content: space-between; padding: 18px 4px; }
details.faq summary::-webkit-details-marker { display: none; }
details.faq summary::after { content: ''; flex: none; width: 8px; height: 8px; margin-right: 4px;
  border-right: 2px solid var(--color-text-muted); border-bottom: 2px solid var(--color-text-muted);
  transform: rotate(45deg) translateY(-2px); transition: transform .15s ease-out; }
details.faq[open] summary::after { transform: rotate(-135deg) translateY(-2px); }
article.prose details.faq h3 { margin: 0; font-size: var(--text-md); font-weight: 600; }
details.faq > p { margin: 0; padding: 0 4px 22px; }
details.faq summary:focus-visible { outline: 2px solid var(--color-link); outline-offset: 2px; }
@media (hover: hover) { details.faq summary:hover h3 { color: var(--color-link); } }
@media (prefers-reduced-motion: reduce) { details.faq summary::after { transition: none; } }

/* 한글에는 대문자 라벨용 자간을 걸지 않는다 — "인 간 초 월"처럼 글자가 흩어진다(2026-09-28 미리보기 실측) */
:root:lang(ko) article.prose .table-box th, :root:lang(ko) .table-box .tier-chip { letter-spacing: 0; }

/* 좁은 화면 — 박스 안쪽 16px, 등급표는 기록·등급 한 줄 + 뜻 아래 전폭(세 칸이면 "뜻"이 몇 글자 폭으로 눌린다) */
@media (max-width: 520px) {
  article.prose { --box-pad: 16px; }
  article.prose .table-box thead { display: none; }
  article.prose .table-box tr { display: grid; grid-template-columns: auto 1fr; align-items: center;
    gap: 6px var(--space-3); padding: 14px var(--box-pad); border-bottom: 1px solid var(--color-outline); }
  article.prose .table-box tr:last-child { border-bottom: 0; }
  article.prose .table-box td { border: 0; padding: 0; }
  article.prose .table-box td:last-child { grid-column: 1 / -1; color: var(--color-text-muted); }
}

/* 기록 카드(홈 내 기록·종합 결과)의 아이콘 — icons.js SVG를 글자 높이에 맞춘다 */
.record-name { display: flex; align-items: center; gap: 6px; }
.record-name .t-icon { display: inline-flex; color: var(--color-signal-text); }
.record-name .t-icon svg { width: 16px; height: 16px; }
/* 단계 제목 안의 테스트 아이콘(종합 측정 진행 순서) */
.steps b svg { width: 18px; height: 18px; vertical-align: -3px; margin-right: 4px; color: var(--color-signal-text); }

/* ── 한글 자간 규칙(2026-09-28, 마스터 명세 묶음 B) ──
   영어 대문자 라벨용 양수 자간이 30곳 가까이 있고, 한글이 들어가면 "에 임 테 스 트"처럼 글자가 흩어진다
   (오늘의 도전 순위표 제목·난이도 탭·표 머리·eyebrow에서 실측). 규칙마다 고치면 새 라벨에서 또 샌다 →
   한국어 면에서는 자간을 한 곳에서 0으로 되돌린다. 예외 = 숫자 비교용 자간(digit-diff) · 큰 제목의 좁은 자간. */
:root:lang(ko) body *:not(.digit-diff-digits) { letter-spacing: 0; }
:root:lang(ko) .page-head h1, :root:lang(ko) .hero h1, :root:lang(ko) article.prose h2 { letter-spacing: -.02em; }

/* ── 결과 공유 메뉴(2026-09-28 결과 화면 개편, 마스터 명세 묶음 D) ──
   버튼 다섯이 같은 무게로 늘어서 있던 것을 "다시 하기"(주 행동) + "결과 공유" 메뉴 하나로.
   <details> 기반이라 JS 없이도 열리고 닫힌다(바깥 클릭·Esc 닫기만 page.js). 메뉴는 버튼 아래로 자란다(06 §3-1 ⑦). */
.share-menu { position: relative; }
.share-menu > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; }
.share-menu > summary::-webkit-details-marker { display: none; }
.share-menu > summary::after { content: ''; width: 7px; height: 7px; margin-top: -3px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform .15s ease-out; }
.share-menu[open] > summary::after { transform: rotate(-135deg); margin-top: 3px; }
.share-sheet { position: absolute; z-index: 5; top: calc(100% + 8px); left: 0; min-width: 200px;
  display: flex; flex-direction: column; gap: 6px; padding: 8px;
  background: var(--color-surface); border: 1px solid var(--color-outline); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-pop); transform-origin: top left; animation: sheet-in .14s ease-out; }
.share-sheet > .btn-secondary { width: 100%; justify-content: flex-start; border-color: transparent; }
@media (hover: hover) { .share-sheet > .btn-secondary:hover { border-color: var(--color-outline); } }
@keyframes sheet-in { from { opacity: 0; transform: translateY(-4px) scale(.98); } }
@media (prefers-reduced-motion: reduce) { .share-sheet { animation: none; } .share-menu > summary::after { transition: none; } }
/* 좁은 화면의 결과 버튼 — 다시 하기·결과 공유를 나란히, 공유 메뉴는 버튼 줄 아래 전체 폭으로 연다 */
@media (max-width: 520px) {
  .result-actions { position: relative; }
  .result-actions > .btn, .share-menu { flex: 1 1 0; }
  .share-menu > summary { width: 100%; justify-content: center; }
  .share-menu { position: static; }
  .share-sheet { position: absolute; top: calc(100% + 6px); left: 0; right: 0; margin-top: 0; box-shadow: var(--shadow-pop); }
}
/* 버튼 라벨은 한 줄로 — 좁은 칸에서 "결과 / 공유"처럼 꺾이면 버튼 모양이 무너진다 */
.share-menu > summary, .result-actions > .btn { white-space: nowrap; }
/* 좁은 화면의 도전장 닉네임 칸 — 안내 글자("닉네임 (한글 8자·영문 16자)")가 잘리지 않게 한 줄을 다 쓴다 */
@media (max-width: 520px) { .duel-send-row input { flex-basis: 100%; } }
/* "다음 테스트" 링크의 아이콘 */
.next-link { display: inline-flex; align-items: center; gap: 8px; }
.next-link .t-icon { display: inline-flex; color: var(--color-signal-text); }
.next-link .t-icon svg { width: 18px; height: 18px; }

/* ── 홈 게임 카드(2026-09-28, 마스터 명세 묶음 E) ──
   줄 목록 → 미리보기 그림 카드. 그림은 thumbs.js(색은 아래 .th-* 가 토큰으로). 카드 도배 예외 사유:
   게임 목록은 그림이 곧 정보다(무슨 게임인지 읽기 전에 보인다). 넓으면 3열(9개 = 3×3), 태블릿 2열, 휴대폰 2열 압축. */
.game-grid { list-style: none; padding: 0; margin: var(--space-3) 0 0; display: grid; gap: var(--space-3);
  grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 860px) { .game-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* F1(변형) — 정식 9개(3×3) 아래 전폭 가로 카드: 왼쪽 미리보기, 오른쪽 글. 5열로 10장을 한 줄에 넣었더니 카드가 좁아
   이름·설명이 어색하게 끊겼다(사장님 9/28 "전에 디자인이 좋은거 같은데") → 3열 유지, 10번째는 가로 카드 */
.game-grid li.is-wide { grid-column: 1 / -1; }
.game-grid li.is-wide .game-card { flex-direction: row; align-items: stretch; }
.game-grid li.is-wide .game-thumb { flex: 0 0 28%; border-bottom: 0; border-right: 1px solid var(--color-outline); display: flex; align-items: center; }
.game-grid li.is-wide .game-body { justify-content: center; padding: 16px 20px; }
.game-grid li.is-wide .game-desc { flex: 0; } /* 설명이 남은 높이를 다 먹으면 시간 표시만 바닥으로 떨어진다 — 글을 한 덩어리로 가운데에 */
/* 2열(≤860px)에서는 F1도 보통 카드로 — 10장이 2×5로 딱 맞는다(가로 카드는 3열에서만 빈자리를 메운다) */
@media (max-width: 860px) {
  .game-grid li.is-wide { grid-column: auto; }
  .game-grid li.is-wide .game-card { flex-direction: column; }
  .game-grid li.is-wide .game-thumb { flex: none; border-right: 0; border-bottom: 1px solid var(--color-outline); }
  .game-grid li.is-wide .game-body { justify-content: flex-start; padding: 14px 16px 16px; }
}
@media (max-width: 520px) { .game-grid li.is-wide .game-body { padding: 10px 12px 12px; } }
.game-grid li { display: flex; }
.game-card { flex: 1; display: flex; flex-direction: column; border: 1px solid var(--color-outline);
  border-radius: var(--radius-lg); background: var(--color-surface); color: var(--color-text);
  text-decoration: none !important; overflow: hidden;
  transition: border-color .15s ease, transform .1s ease-out; }
@media (hover: hover) { .game-card:hover { border-color: var(--color-primary); } }
.game-card:active { transform: scale(.985); }
.game-thumb { display: block; background: var(--color-bg); border-bottom: 1px solid var(--color-outline); }
.game-thumb svg { display: block; width: 100%; height: auto; }
.game-body { display: flex; flex-direction: column; gap: 4px; padding: 14px 16px 16px; flex: 1; }
.game-body b { font-size: var(--text-md); line-height: 1.3; }
.game-desc { font-size: var(--text-sm); line-height: 1.55; color: var(--color-text-muted); flex: 1; }
.game-meta { font: 500 var(--text-xs)/1.4 var(--font-mono); color: var(--color-text-muted); margin-top: 6px; }
@media (max-width: 520px) {
  .game-grid { gap: 10px; }
  .game-body { padding: 10px 12px 12px; }
  .game-desc { display: none; } /* 휴대폰 2열에서는 그림+이름+시간만 — 설명은 게임 면에 있다 */
}
/* 미리보기 그림 칠 — 토큰만 */
.th-panel { fill: var(--color-surface-raised); }
.th-cell { fill: var(--color-surface); stroke: var(--color-outline); stroke-width: 1; }
.th-cell-s { fill: none; stroke: var(--color-outline); stroke-width: 2; }
.th-acc { fill: var(--color-primary); }
.th-col { fill: var(--color-primary); fill-opacity: .55; }
.th-odd { fill: var(--color-primary); fill-opacity: .8; }
.th-go { fill: var(--color-stage-go); }
.th-red { fill: var(--color-danger); }
.th-txt { fill: var(--color-text); }
.th-on { fill: var(--color-on-primary); font-weight: 700; }
.th-onstage { fill: var(--color-on-stage); font: 700 22px var(--font-mono); }
.th-mono { font-family: var(--font-mono); font-weight: 700; letter-spacing: .08em; }
.th-stroke { stroke: var(--color-text-muted); stroke-width: 1.5; stroke-dasharray: 3 4; fill: none; }
text.th-txt, text.th-on { font-family: var(--font-mono); font-weight: 700; }
.th-word { fill: var(--color-text); font-family: var(--font-sans); font-weight: 700; }
.th-mute { fill: var(--color-text-muted); font-weight: 500; }
.th-caret { fill: var(--color-primary); font-weight: 400; }
text.th-btn { font-family: var(--font-sans); font-weight: 700; fill: var(--color-text); }
text.th-btn.th-on { fill: var(--color-on-primary); }

/* 메뉴의 현재 위치(build.mjs가 aria-current="page"를 붙인다 — 2026-09-28 묶음 F) */
.nav-links a[aria-current="page"] { color: var(--color-text); background: var(--color-surface-raised); font-weight: 700; }
@media (max-width: 920px) {
  .nav-links a[aria-current="page"] { border-color: var(--color-text); background: var(--color-surface); }
}

/* ── 랭킹 페이지(2026-09-28 — 옛 오늘의 도전 허브를 합침) ──
   게임 탭(칩) → 보드 한 장: 머리(게임 이름·참여 수) · 난이도 탭 · 내 자리 · 시상대 1~3위 · 4~50위 목록 · 하러 가기.
   색은 토큰만(금·은·동 = --rank-gold/silver/bronze). 시상대는 넓으면 2-1-3 배치, 좁으면 1-2-3 세로. */
.ranking { margin-top: var(--space-5); }
.rk-games { display: flex; flex-wrap: wrap; gap: 8px; }
.rk-game { display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 14px;
  border: 1px solid var(--color-outline); border-radius: 999px; background: var(--color-surface);
  color: var(--color-text-muted); font: 600 var(--text-sm)/1 var(--font-sans); cursor: pointer;
  transition: border-color .15s ease, color .15s ease, transform .1s ease-out; }
.rk-game .t-icon { display: inline-flex; }
.rk-game .t-icon svg { width: 16px; height: 16px; }
@media (hover: hover) { .rk-game:hover { color: var(--color-text); border-color: var(--color-text-muted); } }
.rk-game:active { transform: scale(.97); }
.rk-game[aria-selected="true"] { color: var(--color-text); border-color: var(--color-primary);
  box-shadow: inset 0 0 0 1px var(--color-primary); }
.rk-game[aria-selected="true"] .t-icon { color: var(--color-signal-text); }
@media (max-width: 720px) {
  .rk-games { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin: 0 calc(-1 * var(--space-3)); padding: 2px var(--space-3); }
  .rk-games::-webkit-scrollbar { display: none; }
  .rk-game { flex: none; }
}
.rk-board { margin-top: var(--space-4); border: 1px solid var(--color-outline); border-radius: var(--radius-lg);
  background: var(--color-surface); padding: var(--space-4); }
.rk-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.rk-title { margin: 0; font-size: 1.35rem; letter-spacing: -.01em; }
.rk-total { font: 600 var(--text-sm)/1.4 var(--font-mono); color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.rk-modes { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--space-2); }
.rk-mine { margin: var(--space-3) 0 0; padding: 10px 14px; border-radius: var(--radius-md);
  background: var(--color-bg); color: var(--color-text-muted); font: 600 var(--text-sm)/1.5 var(--font-mono); }
.rk-mine.is-set { color: var(--color-text); border-left: 3px solid var(--color-primary); }
/* 시상대 */
.rk-podium { list-style: none; padding: 0; margin: var(--space-4) 0 0; display: grid; gap: var(--space-3);
  grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: end; }
.rk-step { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center;
  border: 1px solid var(--color-outline); border-radius: var(--radius-lg); background: var(--color-bg);
  padding: var(--space-3) var(--space-2); min-width: 0; }
.rk-step-1 { order: 2; padding-top: var(--space-5); padding-bottom: var(--space-4); border-color: var(--rank-gold); }
.rk-step-2 { order: 1; border-color: var(--rank-silver); }
.rk-step-3 { order: 3; border-color: var(--rank-bronze); }
.rk-place { font: 800 1.6rem/1 var(--font-mono); }
.rk-step-1 .rk-place { font-size: 2.1rem; color: var(--rank-gold); }
.rk-step-2 .rk-place { color: var(--rank-silver); }
.rk-step-3 .rk-place { color: var(--rank-bronze); }
.rk-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: 600 var(--text-sm)/1.4 var(--font-mono); }
.rk-score { font: 700 var(--text-md)/1.3 var(--font-mono); font-variant-numeric: tabular-nums; }
.rk-dev { display: inline-flex; color: var(--color-text-muted); }
.rk-step.is-ghost { opacity: .45; }
@media (max-width: 520px) {
  .rk-podium { grid-template-columns: 1fr; gap: 8px; }
  .rk-step { order: 0 !important; flex-direction: row; justify-content: flex-start; gap: 12px; text-align: left; padding: 12px 14px !important; }
  .rk-step .rk-place, .rk-step-1 .rk-place { font-size: 1.4rem; min-width: 1.4em; }
  .rk-score { margin-left: auto; }
}
/* 4위 이하 목록 — 번호가 4부터라 "첫 세 줄 금·은·동" 규칙을 끈다 */
.rk-rest-label { margin: var(--space-4) 0 0; font: 600 var(--text-xs)/1.4 var(--font-mono); color: var(--color-text-muted); }
.rk-rest { margin-top: var(--space-2); }
.rk-rest li:nth-child(-n+3) .rank-no, .rk-rest li.is-first b { color: var(--color-text-muted); }
.rk-rest li .rank-name { max-width: none; }
.rk-play { margin-top: var(--space-4); display: inline-flex; }
