/* ===========================================================
   랜딩 (/) — 2026-08-22 리디자인 시안 이식
   토큰은 common/style.css 의 :root 에 있다. 여기서 색을 새로 만들지 않는다.
   =========================================================== */

/* 랜딩은 자체 헤더·푸터를 쓴다. common 의 .header 는 4칸 앱 헤더라 구조가 다르다. */
.lp {
  flex-grow: 1;
  font-size: var(--t-15);
  color: var(--ink-500);
  -webkit-font-smoothing: antialiased;
}

/* ── 12칼럼 그리드 ────────────────────────────────────────
   섹션마다 폭을 따로 잡지 않는다. 거터는 하나뿐이고 폭은 span 으로만 정하므로,
   어느 섹션에 있든 같은 span 이면 같은 폭이다. 같은 행의 카드는 grid 기본값
   (stretch)으로 높이도 자동으로 맞는다. */
.lp-wrap { max-width: var(--wrap); margin: 0 auto; }

/* 가입 직후 한 번 뜨는 안내(쿠폰을 드렸습니다 등) */
.lp-notice {
  margin: 20px 0 0;
  padding: 12px 16px;
  border: 1px solid var(--ok);
  border-radius: 6px;
  background: var(--ok-soft);
  color: var(--ok);
  font-size: var(--t-14);
}
.lp-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gutter);
}
.lp-c3  { grid-column: span 3; }   /* 한 행에 4개 */
.lp-c5  { grid-column: span 5; }
.lp-c6  { grid-column: span 6; }   /* 한 행에 2개 */
.lp-c7  { grid-column: span 7; }
.lp-c12 { grid-column: span 12; }

/* ── 되풀이되는 조각 ──────────────────────────────────── */
.lp-eyebrow {
  font-size: var(--t-11);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}
.lp-h2 {
  font-size: var(--t-26);
  line-height: 1.3;
  font-weight: 700;
  color: var(--ink-900);
  letter-spacing: -0.025em;
  margin: 0 0 12px;
}
.lp-lead {
  font-size: var(--t-15);
  line-height: 1.8;
  color: var(--ink-500);
  max-width: 620px;
  text-wrap: pretty;
  margin: 0;
}
/* 코스 이름 강조(2026-09-15). 커리큘럼 리드의 「마스터 프로그래머 코스」 ·
   「게임 프로그래머 올인원 코스」 둘이 쓴다.
   ⚠ .lp-lead strong 전체에 걸지 않는다 - 다른 리드 넷(차별화된 교육법 · 방향 ·
     엄선된 문제집 · 자동 채점)이 이미 strong 을 쓰고 있어 색이 한꺼번에 바뀐다.
   ⚠ 굵기는 브라우저 기본 bold 를 그대로 쓴다. 색만 얹는다. */
.lp-lead strong.accent { color: var(--accent); }

/* padding 을 기본값으로 두지 않는다 — 히어로 스크린샷 카드는 0 이어야 한다 */
.lp-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.lp-card-pad { padding: 24px; }
.lp-mono { font-family: var(--font-mono); }

.lp-btn {
  height: 50px;
  padding: 0 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  font-size: var(--t-15);
  font-weight: 600;
  background: var(--ink-900);
  color: var(--surface);
  border: 1px solid transparent;
}
.lp-btn:hover { background: var(--ink-hover); }
.lp-btn.ghost {
  background: var(--surface);
  color: var(--ink-700);
  border-color: var(--line-strong);
}
.lp-btn.ghost:hover { background: var(--surface-sunken); }
.lp-btn.on-ink { background: var(--surface); color: var(--ink-900); }
.lp-btn.on-ink:hover { background: var(--surface-fill); }
.lp-btn.ghost-on-ink {
  background: transparent;
  color: var(--surface);
  border-color: var(--ink-700);
}
.lp-btn.ghost-on-ink:hover { background: rgba(255, 255, 255, .07); }

/* ── 주 CTA 의 코발트 후광 (2026-09-15) ───────────────────
   가만히 있을 때 강조돼야 한다. 호버로만 강조하면 마우스를 얹기 전에는
   그냥 검은 버튼이고, 모바일에는 호버 자체가 없다.

   ⚠ 검정을 코발트로 바꾸지 않는다. 15장 「확정된 결정」이 「잉크빛 검정이
     GO HARD 의 인상이라 지킨다」고 못 박아 두었다 - 채움은 그대로 두고
     바깥 빛으로만 강조한다.

   ⚠ 색은 --accent(#1257CC)와 --accent-soft(#EDF3FE) 둘뿐이다. 새 색을
     만들지 않고 투명도만 바꾼다. box-shadow 는 토큰을 못 받으므로 그 둘의
     RGB 를 그대로 적는다 - 토큰 값을 바꾸면 여기도 함께 고친다.

   ⚠ 가장 어두울 때도 8% 를 남긴다. 0 으로 내리면 그 순간 버튼이 후광 없던
     때와 똑같아져, 절반의 시간 동안 강조가 없는 셈이 된다.

   ⚠ 번짐 반경과 투명도를 함께 움직인다. 투명도만 바꾸면 밝기만 변하고
     「번진다」는 느낌이 안 난다.

   ⚠ 호버에서 멈추지 않는다. 한때 멈추게 해 두었는데 마우스가 지나갈 때마다
     끊겨 「무한반복이 아닌 것」처럼 보였다. 버튼이 움직이는 것이 아니라 후광
     밝기만 변하므로 누르는 데 걸리지 않고, 호버 표시는 바탕색이 짙어지는
     것으로 이미 있다. */
@keyframes lp-btn-blink {
  from { box-shadow: 0 0 3px 0 rgb(18 87 204 / 8%),   0 1px 2px rgb(16 35 59 / 18%); }
  to   { box-shadow: 0 0 9px 2px rgb(18 87 204 / 42%), 0 1px 2px rgb(16 35 59 / 18%); }
}
/* ⚠ 어두운 배너(.lp-cta)에서는 코발트가 잉크에 묻힌다 - #1257CC 와 #10233B 가
     둘 다 짙은 남색이다. 그쪽만 --accent-soft(푸른 기 도는 흰빛)로 바꾼다. */
@keyframes lp-btn-blink-ink {
  from { box-shadow: 0 0 3px 0 rgb(237 243 254 / 10%), 0 1px 2px rgb(0 0 0 / 30%); }
  to   { box-shadow: 0 0 9px 2px rgb(237 243 254 / 46%), 0 1px 2px rgb(0 0 0 / 30%); }
}
/* ⚠ 사인파다. 「반주기 + alternate + 사인 이징」으로 낸다.
     키프레임은 밑 ↔ 꼭대기 둘뿐이고 1초에 한쪽씩 오가므로 한 바퀴가 2초다.

     왜 이 방식인가. 봉우리와 골을 둥글리려면 보통 사인 곡선을 키프레임 열몇
     개로 쪼개 찍어야 하는데, alternate 는 되돌아오는 회차에서 이징도 함께
     뒤집으므로 반주기짜리 사인 이징 하나가 저절로 온전한 사인파가 된다.
     cubic-bezier(.37, 0, .63, 1) 은 사인 이징(easeInOutSine)의 표준 근사다.

     ⚠ 여기까지 온 길 - ease-in-out 은 양 끝에 머물러 「켜짐/꺼짐」으로 읽혔고,
       linear 는 이어지되 봉우리와 골에서 방향이 즉시 뒤집히는 삼각파였다.
     ⚠ 주기를 바꿀 때는 이 값이 반주기임을 잊지 않는다. 적은 값의 두 배가
       한 바퀴다 - 한 바퀴 2초를 내려고 1s 를 적었다. */
.lp-btn { animation: lp-btn-blink 1s cubic-bezier(.37, 0, .63, 1) infinite alternate; }
.lp-btn.on-ink { animation-name: lp-btn-blink-ink; }
/* ⚠ 곁들이 버튼(요금 살펴보기)에는 안 두른다. 둘 다 빛나면 무엇이 주인지
     사라진다. 이 줄이 빠지면 화면은 멀쩡히 뜨고 강조만 무의미해진다. */
.lp-btn.ghost, .lp-btn.ghost-on-ink { animation: none; box-shadow: none; }

/* ⚠ 초점 표시는 outline 으로 따로 띄운다. box-shadow 로 겹치면 후광에 묻혀
     키보드로 어디에 있는지 안 보인다. :focus-visible 이라 마우스로 누를
     때는 안 뜬다 - :focus 로 하면 클릭할 때마다 테가 남는다. */
.lp-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.lp-btn.on-ink:focus-visible,
.lp-btn.ghost-on-ink:focus-visible { outline-color: var(--surface); }

/* ⚠ 움직임을 줄여 달라고 한 사람에게는 깜빡임을 멈춘다. 후광은 남긴다 -
     빛이지 움직임이 아니라 어지럼증과 상관이 없고, 없애면 그 사람만 강조
     없는 버튼을 보게 된다. 남는 값은 깜빡임의 중간쯤이다. */
@media (prefers-reduced-motion: reduce) {
  .lp-btn {
    animation: none;
    box-shadow: 0 0 6px 1px rgb(18 87 204 / 26%), 0 1px 2px rgb(16 35 59 / 18%);
  }
  .lp-btn.on-ink { box-shadow: 0 0 6px 1px rgb(237 243 254 / 28%), 0 1px 2px rgb(0 0 0 / 30%); }
  .lp-btn.ghost, .lp-btn.ghost-on-ink { box-shadow: none; }
}

/* ── 섹션 ─────────────────────────────────────────────── */
.lp-section {
  padding: 80px 40px;
  border-bottom: 1px solid var(--line);
}
.lp-section.sunken { background: var(--surface-sunken); }
.lp-hero {
  padding: 88px 40px 72px;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--line);
}

.lp-hero h1 {
  font-size: var(--t-40);
  line-height: 1.28;
  font-weight: 700;
  color: var(--ink-900);
  letter-spacing: -0.032em;
  text-wrap: pretty;
  margin: 0 0 22px;
}
.lp-hero h1 .accent { color: var(--accent); }
.lp-hero-sub {
  font-size: var(--t-16);
  line-height: 1.85;
  color: var(--ink-500);
  max-width: 540px;
  text-wrap: pretty;
  margin: 0 0 32px;
}
.lp-hero-sub strong { color: var(--ink-900); }
.lp-hero-actions { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.lp-note { display: flex; align-items: center; gap: 8px; font-size: var(--t-13); color: var(--ink-400); }
.lp-note svg { flex-shrink: 0; }

/* ── 히어로 시각물 — 강사 약력 (2026-09-15) ────────────────
   예전에는 제품 화면 축약(.lp-shot 일습)이 있었다. Online Judge 절이 같은
   것을 네 장으로 더 크게 보여 주게 되면서 히어로에서 되풀이할 까닭이 없어졌다.
   창틀 조각(.lp-shot-bar/-dot/-url)은 디스코드 갈무리가 그대로 쓰므로 남는다. */

/* ⚠ .lp-card 에는 padding 이 없다(기본값을 두면 갈무리 카드가 깨진다).
     그래서 여백을 여기서 준다. */
.lp-bio { padding: 26px 28px; }
.lp-bio-eyebrow {
  font-size: var(--t-11); font-weight: 600; letter-spacing: 0.14em;
  color: var(--accent); margin-bottom: 10px;
}
.lp-bio-name {
  font-size: var(--t-20); font-weight: 700; color: var(--ink-900);
  letter-spacing: -0.02em; margin: 0 0 4px;
}
.lp-bio-name span { font-size: var(--t-13); font-weight: 500; color: var(--ink-400); margin-left: 6px; }
.lp-bio-lead {
  font-size: var(--t-13); line-height: 1.8; color: var(--ink-400);
  margin: 0 0 20px; word-break: keep-all;
}

/* 연차를 앞세운다. 숫자를 먼저 읽게 해 히어로 왼쪽 큰 글자와 무게를 맞춘다. */
.lp-bio-rows { display: grid; gap: 14px; }
.lp-bio-row { display: flex; align-items: baseline; gap: 14px; }
/* ⚠ nowrap 이 있어야 「년 이상」이 숫자 밑으로 안 떨어진다. min-width 는 가장
     긴 「6년 이상」에 맞춘 값이다 - 모자라면 그 줄만 밀려 세 줄의 시작점이 어긋난다. */
.lp-bio-num {
  flex: 0 0 auto; min-width: 68px;
  white-space: nowrap;
  font-size: var(--t-26); font-weight: 700; color: var(--accent);
  line-height: 1; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.lp-bio-num i { font-size: var(--t-13); font-style: normal; font-weight: 600; margin-left: 2px; }
.lp-bio-what {
  font-size: var(--t-14); line-height: 1.6; color: var(--ink-700);
  word-break: keep-all;
}
.lp-bio-total {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
  display: flex; align-items: baseline; gap: 8px;
  font-size: var(--t-13); color: var(--ink-400);
}
.lp-bio-total b { font-size: var(--t-17); font-weight: 700; color: var(--ink-900); }

/* ── 들어오는 차례 ──────────────────────────────────────
   머리 세 줄은 늘 떠 있고, 그 아래 세 줄이 아래에서 위로 하나씩 올라온다.
   합계는 움직이지 않고 밝아지기만 한다 - 앞의 셋을 더한 값이라 같이 움직이면
   네 번째 항목처럼 읽힌다.

   ⚠ 한 바퀴(8초)를 키프레임 안에 통째로 담는다. animation-delay 는 첫 바퀴에만
     걸리므로, 되풀이하면서 차례를 지키려면 이 방법뿐이다 - 네 요소의 길이가
     같아 시작 간격(0.5초)이 영원히 유지된다. 지연만 붙여 infinite 로 돌리면
     둘째 바퀴부터 셋이 한꺼번에 깜빡인다.
   ⚠ 구간마다 가속을 따로 준다. 8초짜리에 곡선 하나를 걸면 그 곡선이 구간을
     통째로 늘였다 줄여 올라오는 맛이 사라진다. 바깥은 linear 로 둔다.
   ⚠ 스크립트를 쓰지 않는다. 자바스크립트가 막혀도 그대로 돈다.
   ⚠ both 가 있어야 기다리는 동안 0% 를 붙들고 있는다. 빼면 지연 시간 내내
     다 보이다가 뒤늦게 한 번 깜빡인다. */
@keyframes lp-bio-cycle {
  0%   { opacity: 0; transform: translateY(10px);
         animation-timing-function: cubic-bezier(.22, 1, .36, 1); }
  14%  { opacity: 1; transform: translateY(0); }
  85%  { opacity: 1; transform: translateY(0);
         animation-timing-function: ease; }
  92%  { opacity: 0; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(10px); }
}
@keyframes lp-bio-cycle-fade {
  0%   { opacity: 0; animation-timing-function: ease-out; }
  14%  { opacity: 1; }
  85%  { opacity: 1; animation-timing-function: ease; }
  92%  { opacity: 0; }
  100% { opacity: 0; }
}
.lp-bio-row { animation: lp-bio-cycle 8s linear infinite both; }
.lp-bio-row:nth-child(1) { animation-delay: 0s; }
.lp-bio-row:nth-child(2) { animation-delay: .5s; }
.lp-bio-row:nth-child(3) { animation-delay: 1s; }
.lp-bio-total { animation: lp-bio-cycle-fade 8s linear 1.5s infinite both; }

/* ⚠ 마우스를 얹거나 포커스가 들어오면 멈추고 전부 보인다. 되풀이되는 것이라
     이게 없으면 읽고 싶은 순간에 글이 사라진다 - Online Judge 슬라이드를
     멈추게 한 것과 같은 까닭이다. play-state 로 세우지 않는 이유는 사라지는
     중에 얹으면 반쯤 흐린 채로 굳기 때문이다. */
.lp-bio:hover .lp-bio-row,
.lp-bio:hover .lp-bio-total,
.lp-bio:focus-within .lp-bio-row,
.lp-bio:focus-within .lp-bio-total { animation: none; }

/* ⚠ 움직임을 줄여 달라고 한 사람에게는 안 돌린다. 되풀이되는 움직임은
     전정기관 질환이 있는 사람에게 실제로 어지럼증을 일으킨다.
     animation 을 끄면 평소 모습(다 보이는 상태)으로 남는다. */
@media (prefers-reduced-motion: reduce) {
  .lp-bio-row, .lp-bio-total { animation: none; }
}

/* 창틀 — 디스코드 갈무리(.pv-shot)가 쓴다 */
.lp-shot-bar {
  height: 34px;
  background: var(--surface-fill);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  padding: 0 12px;
  gap: 6px;
}
.lp-shot-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); }
.lp-shot-url { font-size: var(--t-11); color: var(--ink-300); margin-left: 10px; }

/* ── 커리큘럼 카드 ────────────────────────────────────── */
.lp-course-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.lp-course-no { font-family: var(--font-mono); font-size: var(--t-11); color: var(--accent); }

/* 이수 구분. 카드마다 하나뿐이라 조용한 톤으로 둔다 */
.lp-course-tag {
  flex-shrink: 0;
  padding: 2px 8px;
  border-radius: 4px;
  background: var(--surface-fill);
  color: var(--ink-400);
  font-size: var(--t-11);
  font-weight: 600;
  white-space: nowrap;
}

/*
  공개 예정. 점선으로 "있지만 아직 아니다" 를 말한다 — 감추면 물어보게 되고
  공개로 두면 눌렀을 때 빈 화면이 나온다.
*/
.lp-card.soon {
  border-style: dashed;
  border-color: var(--line-strong);
  background: #FAFBFD;
}

.lp-card.soon .lp-course-no { color: var(--ink-300); }
.lp-card.soon .lp-course-name { color: var(--ink-700); }
.lp-card.soon .lp-course-meta { color: var(--ink-400); font-weight: 600; }
.lp-course-name { font-size: var(--t-16); font-weight: 600; color: var(--ink-900); margin-bottom: 6px; }
.lp-course-meta { font-size: var(--t-12); color: var(--ink-400); margin-bottom: 14px; }
.lp-course-desc { font-size: var(--t-12); line-height: 1.75; color: var(--ink-500); text-wrap: pretty; }


/* ── 학습 방식 ────────────────────────────────────────── */
.lp-way-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 14px 0 5px;
}

.lp-way-name { font-size: var(--t-16); font-weight: 600; color: var(--ink-900); }

/* 준비 중인 카드는 아이콘도 함께 가라앉힌다 — 이름만 흐리면 따로 논다 */
.lp-card.soon .lp-way-name { color: var(--ink-700); }
.lp-card.soon > svg { opacity: 0.55; }
.lp-way-tag {
  font-size: var(--t-11);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--accent);
  margin-bottom: 9px;
}
.lp-way-desc { font-size: var(--t-13); line-height: 1.8; color: var(--ink-500); text-wrap: pretty; }

/* ── 요금 ─────────────────────────────────────────────── */
.lp-checks { display: flex; flex-direction: column; gap: 12px; }
.lp-check { display: flex; align-items: flex-start; gap: 10px; }
.lp-check svg { flex-shrink: 0; margin-top: 3px; }
.lp-check span { font-size: var(--t-14); line-height: 1.7; color: var(--ink-500); }
.lp-check strong { color: var(--ink-900); }

.lp-price { padding: 28px; box-shadow: 0 1px 3px rgba(16, 35, 59, .07); }
.lp-price-label { font-size: var(--t-13); font-weight: 600; color: var(--ink-400); margin-bottom: 12px; }
.lp-price-row { display: flex; align-items: baseline; gap: 6px; margin-bottom: 6px; }
.lp-price-num { font-size: var(--t-40); font-weight: 700; color: var(--ink-900); letter-spacing: -0.03em; }
.lp-price-unit { font-size: var(--t-16); color: var(--ink-400); }
.lp-price-note { font-size: var(--t-13); color: var(--ink-400); margin-bottom: 10px; }
.lp-price-save {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 22px;
  padding: 9px 12px;
  background: var(--accent-soft);
  border-radius: 7px;
  font-size: var(--t-12);
  font-weight: 500;
  color: var(--accent);
}
.lp-price-save svg { flex-shrink: 0; }
.lp-price .lp-btn { width: 100%; }
.lp-price-foot { text-align: center; margin-top: 14px; font-size: var(--t-12); color: var(--ink-400); }

/* ── 마지막 CTA ───────────────────────────────────────── */
.lp-cta { padding: 72px 40px; background: var(--ink-900); }
.lp-cta h2 {
  font-size: var(--t-26);
  line-height: 1.35;
  font-weight: 700;
  color: var(--surface);
  letter-spacing: -0.025em;
  margin: 0 0 10px;
}
.lp-cta p {
  font-size: var(--t-14);
  line-height: 1.75;
  color: var(--ink-300);
  max-width: 520px;
  text-wrap: pretty;
  margin: 0;
}
.lp-cta-actions { display: flex; gap: 12px; justify-content: flex-end; flex-wrap: wrap; }

/* ── 푸터 ─────────────────────────────────────────────── */
.lp-footer {
  border-top: 1px solid var(--line);
  background: var(--surface-sunken);
  padding: 36px 40px;
}
.lp-footer-brand {
  font-size: var(--t-15);
  font-weight: 700;
  color: var(--ink-900);
  letter-spacing: -0.02em;
  margin-bottom: 12px;
}
.lp-biz { font-size: var(--t-11); line-height: 1.95; color: var(--ink-400); }
.lp-footer-cols { display: flex; gap: 48px; justify-content: flex-end; flex-wrap: wrap; }
.lp-footer-col { display: flex; flex-direction: column; gap: 9px; }
.lp-footer-head {
  font-size: var(--t-11);
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--ink-300);
}
.lp-footer-col a { font-size: var(--t-12); color: var(--ink-500); }
.lp-footer-col a:hover { color: var(--ink-900); text-decoration: underline; }

/* ── 반응형 ───────────────────────────────────────────── */
/* 태블릿 — 4개짜리는 2개씩, 좌우 분할은 위아래로 */
@media (max-width: 1023px) {
  .lp-c3 { grid-column: span 6; }
  .lp-c5, .lp-c6, .lp-c7 { grid-column: span 12; }
  .lp-cta-actions { justify-content: flex-start; }
  .lp-footer-cols { justify-content: flex-start; }
}
/* 모바일 — 전부 한 줄에 하나 */
@media (max-width: 639px) {
  .lp-grid { gap: 16px; }
  .lp-c3, .lp-c5, .lp-c6, .lp-c7 { grid-column: span 12; }
  .lp-hero { padding: 56px 20px 48px; }
  .lp-section, .lp-cta { padding: 56px 20px; }
  .lp-footer { padding: 28px 20px; }
  .lp-hero h1 { font-size: var(--t-32); }
  .lp-hero-actions { flex-direction: column; align-items: stretch; }
  /* 약력 카드 — 여백만 줄인다. 글자는 그대로 둔다 */
  .lp-bio { padding: 22px 20px; }
  .lp-bio-num { min-width: 62px; font-size: var(--t-24); }
}

/* ─────────────────────────────────────────────────────────────
   후기 판 (2026-09-07)

   상위 3개만 펴고 더보기로 3개씩 늘린다. 정렬·과목 필터는 브라우저가
   건다 - 자세한 까닭은 home/landing 의 주석에 있다.

   ⚠ 글자 크기는 13단(11·12·13·14·15·16·17·20·24·26·32·40·44) 밖으로
     나가지 않는다. 평점만 그 밖인데, 이 절의 주인공이라 40 을 쓴다.
   ───────────────────────────────────────────────────────────── */
.rb { margin-top: 28px; }

/* ── 평점 요약 ── */
.rb-summary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 22px 0 24px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 20px;
}

/* 이 절에서 가장 먼저 읽혀야 하는 값이다. */
.rb-score {
  font-size: var(--t-40);
  font-weight: 700;
  line-height: 1;
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
}

/* 빈 별 위에 채운 별을 폭으로 잘라 얹는다. 4.7 을 다섯 개로 반올림해
   보이면 그건 과장이다 - 실제 비율만큼만 채운다.
   ⚠ 색을 쓰지 않는다. 글리프 자체가 채움/빈칸으로 갈려 색 없이도 읽힌다
     (fragments/review 의 별점과 같은 판단이다). */
.rb-stars {
  position: relative;
  display: inline-block;
  font-size: var(--t-17);
  letter-spacing: 0.08em;
  line-height: 1;
  white-space: nowrap;
}

.rb-stars-off { color: var(--line-strong); }

.rb-stars-on {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  width: 0;
  color: var(--ink-900);
}

.rb-count {
  font-size: var(--t-12);
  color: var(--ink-400);
}

/* ── 필터와 정렬 ── */
.rb-controls {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

.rb-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.rb-chip {
  height: var(--control-sm);
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-500);
  font-family: inherit;
  font-size: var(--t-12);
  cursor: pointer;
}

.rb-chip:hover { border-color: var(--line-strong); color: var(--ink-900); }

.rb-chip.on {
  border-color: var(--ink-900);
  background: var(--ink-900);
  color: var(--surface);
}

/* 정렬은 접어 둔다. 세 값을 늘 펴 두면 필터 칩과 무게가 같아져
   무엇이 거르는 것이고 무엇이 세우는 것인지 헷갈린다. */
.rb-sort { position: relative; flex: 0 0 auto; }

.rb-sort > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--control-sm);
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-500);
  font-size: var(--t-12);
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
}

.rb-sort > summary::-webkit-details-marker { display: none; }
.rb-sort > summary::after { content: "▾"; font-size: var(--t-11); color: var(--ink-300); }
.rb-sort[open] > summary::after { content: "▴"; }
.rb-sort > summary:hover { border-color: var(--line-strong); color: var(--ink-900); }

.rb-sort-menu {
  position: absolute;
  right: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  min-width: 140px;
  margin-top: 4px;
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 6px 20px rgb(16 35 59 / 10%);
}

.rb-sort-menu button {
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--ink-500);
  font-family: inherit;
  font-size: var(--t-12);
  text-align: left;
  cursor: pointer;
}

.rb-sort-menu button:hover { background: var(--surface-fill); color: var(--ink-900); }
.rb-sort-menu button[aria-current="true"] { color: var(--ink-900); font-weight: 600; }

/* ── 더보기 ── */
.rb-more {
  display: block;
  width: 100%;
  height: var(--control-md);
  margin-top: 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-700);
  font-family: inherit;
  font-size: var(--t-13);
  font-weight: 600;
  cursor: pointer;
}

.rb-more:hover { border-color: var(--ink-900); color: var(--ink-900); }

/* ⚠ display 를 준 요소는 hidden 속성을 이긴다. 이 줄이 없으면 더보기 버튼이
   다 편 뒤에도 남고, 접힌 후기가 그대로 보여 판이 통째로 무의미해진다.
   모달에서 겪은 것과 같은 함정이다(summary.md 13장 「Thymeleaf 함정」 아래). */
.rb-more[hidden] { display: none; }
.rb .rv[hidden] { display: none; }

@media (max-width: 639px) {
  .rb-controls { flex-direction: column; align-items: stretch; }
  .rb-sort > summary { justify-content: space-between; }
  .rb-sort-menu { left: 0; right: 0; }
}

/* ─────────────────────────────────────────────────────────────
   정가 취소선 · 할인 배지 (2026-09-07)
   fragments/price-tag 가 쓴다. 랜딩과 요금이 같은 모양이어야 해서
   공통 이름(pt-)으로 둔다 — 요금 화면 CSS 도 이 파일을 안 읽으므로
   같은 규칙을 common/style.css 에 둔다. 여기는 랜딩 배치만 잡는다.
   ───────────────────────────────────────────────────────────── */
.lp-price .pt { margin-bottom: 6px; }

/* ─────────────────────────────────────────────────────────────
   가격 플로팅 바 (2026-09-07)

   맨 위에서부터 보이고, 요금 카드가 보이면 툭 떨어진다.
   ⚠ transform 으로 내린다. display 를 건드리면 되돌아올 때 애니메이션이
     걸리지 않는다 — 없던 것이 갑자기 나타난다.
   ───────────────────────────────────────────────────────────── */
.lp-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  padding: 26px 24px calc(26px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line);
  background: rgb(255 255 255 / 92%);
  backdrop-filter: blur(10px);
  box-shadow: 0 -6px 24px rgb(16 35 59 / 8%);
  transition: transform .32s cubic-bezier(.22, 1.2, .36, 1), opacity .22s ease;
}

/* 「툭」 — 아래로 떨어지며 사라진다. 되돌아올 때는 같은 곡선으로 올라온다 */
.lp-bar.dropped {
  transform: translateY(115%);
  opacity: 0;
  pointer-events: none;
}

.lp-bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: var(--wrap);
  margin: 0 auto;
}

.lp-bar-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
}

/* 이미 산 사람에게 가격 대신 서는 인사말.
   ⚠ 값이 아니므로 .lp-bar-now(40px)만큼 키우지 않는다 — 인사가 그 자리를
     차지하면 바가 여전히 무언가를 파는 것처럼 읽힌다.
   ⚠ 긴 이름이 CTA 를 밀어내지 않게 한 줄로 자른다. 좁은 화면에서 문구를
     접는 것과 같은 이유다. */
.lp-bar-greet {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-26);
  font-weight: 600;
  color: var(--ink-900);
}

/* 이 바에서 가장 먼저 읽혀야 하는 값이다.
   ⚠ line-height 를 1 로 고정한다. 기본값(normal)이면 글꼴에 따라 줄 높이가
     달라져 바 높이가 브라우저마다 흔들린다. */
.lp-bar-now {
  font-size: var(--t-40);
  line-height: 1;
  font-weight: 700;
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
}

.lp-bar-unit {
  font-size: var(--t-26);
  color: var(--ink-400);
}

/* 정가와 배지는 바 안에서만 키운다 — 랜딩 카드와 /pricing 은 그대로 둔다.
   ⚠ 11px 의 두 배인 22px 은 13단에 없다. 배지는 20 으로 둔다 — 24 로 올리면
     단위(26)와 무게가 같아져 무엇이 값이고 무엇이 딱지인지 흐려진다. */
.lp-bar .pt-list { font-size: var(--t-26); }
.lp-bar .pt-badge { padding: 4px 14px; font-size: var(--t-20); }

.lp-bar-side {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
}

.lp-bar-notice {
  font-size: var(--t-24);
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
}

/* 높이·글자를 따로 정하지 않는다 — 랜딩의 기본 버튼(.lp-btn, 50px/15px)을
   그대로 쓴다. 바가 커지면서 예전의 36px 축소가 필요 없어졌고, 새 숫자를
   지어내는 것보다 이미 있는 크기에 맞추는 편이 낫다. */
.lp-bar-cta {
  display: inline-flex;
  align-items: center;
}

/* 바가 마지막 줄을 가린다. 푸터 아래에 바 높이만큼 자리를 낸다 */
/*
  바 높이 = 26(위) + 50(CTA) + 26(아래) + 1(테두리) = 약 103px. 예전 57px 의
  약 1.8배다 — 글자는 정확히 두 배인데 높이가 딱 두 배가 아닌 것은 CTA 때문이다.
  36px 버튼을 72px 로 만들면 바가 아니라 벽이 된다. 그래서 축소를 걷어내
  랜딩 기본 버튼(50px)에 맞추고 모자란 만큼을 여백으로 채웠다.

  ⚠ 여기 값은 바 높이보다 커야 한다. 모자라면 푸터 마지막 줄이 바 뒤에 깔린다.
*/
body.lp-has-bar { padding-bottom: 124px; }

/* 좁은 화면은 덜 키운다. 같은 배로 키우면 바 하나가 화면의 4분의 1을 먹는다 */
@media (max-width: 639px) {
  .lp-bar { padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px)); }
  .lp-bar-inner { gap: 10px; }
  .lp-bar-now { font-size: var(--t-26); }
  .lp-bar-greet { font-size: var(--t-17); }
  .lp-bar-unit { font-size: var(--t-15); }
  .lp-bar .pt-list { font-size: var(--t-15); }
  .lp-bar .pt-badge { padding: 2px 10px; font-size: var(--t-13); }
  /* 좁은 화면에서는 문구를 접는다 — 접지 않으면 CTA 가 밀려 나간다 */
  .lp-bar-notice { display: none; }
  .lp-bar-cta { height: var(--control-lg); padding: 0 16px; font-size: var(--t-14); }
  body.lp-has-bar { padding-bottom: 88px; }
}


/* ═══════════════════════════════════════════════════════════════
   밀착 관리 · Online Judge (2026-09-07)

   static/pilot/landing-pilot.html 에서 옮겨 왔다. 파일럿에서 모양을
   정하고 그 <style> 블록을 통째로 여기로 옮기는 방식이다.

   ⚠ 글자 크기는 13단 밖으로 나가지 않는다. 색은 :root 토큰만 쓴다.
   ═══════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════
   파일럿에서 새로 만든 것만 여기 있다. 옮길 때는 이 블록만 간다.
   ⚠ 글자 크기는 13단(11·12·13·14·15·16·17·20·24·26·32·40·44) 밖으로
     나가지 않는다. 색은 :root 토큰만 쓴다 - 새 색을 만들지 않는다.
   ═══════════════════════════════════════════════════════════ */


/* ── 밀착 관리 ─────────────────────────────────────────── */

/* 「무엇이 제공되는가」를 세어 보이는 자리. 카드가 아니라 목록이다 -
   카드로 만들면 학습 방식 카드와 무게가 같아져 절이 반복처럼 읽힌다. */
.pv-list { display: flex; flex-direction: column; gap: 14px; margin-top: 26px; }
.pv-item { display: flex; gap: 12px; align-items: flex-start; }
.pv-item svg { flex-shrink: 0; margin-top: 3px; }
.pv-item-name { font-size: var(--t-15); font-weight: 600; color: var(--ink-900); }
.pv-item-desc { font-size: var(--t-13); line-height: 1.75; color: var(--ink-500); margin-top: 3px; }

/* 디스코드 갈무리. 창틀(.lp-shot-bar/-dot/-url)을 히어로의 제품 화면에서
   물려받았다 - 랜딩이 이미 쓰고 있는 언어라 새 모양을 만들 이유가 없다.
   ⚠ 2026-09-15 에 히어로가 약력으로 바뀌면서 그 창틀을 쓰는 곳은 여기뿐이다. */
.pv-shot { overflow: hidden; box-shadow: 0 1px 3px rgb(16 35 59 / 7%); }
.pv-shot img { display: block; width: 100%; height: auto; }

/* 화면 아래로 갈수록 흐려지게 둔다 - 갈무리가 잘린 티가 덜 난다 */
.pv-shot-frame { position: relative; }
.pv-shot-frame::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 56px;
  background: linear-gradient(transparent, var(--surface));
  pointer-events: none;
}

/* ── Online Judge 슬라이드 ────────────────────────────── */

/* 지금 풀 수 있는 문제 수. 리드 바로 아래에서 한 번 더 못을 박는다 -
   숫자는 CatalogStatsService 가 DB 에서 세어 준다.
   ⚠ 새 글자 단을 만들지 않는다. 20 은 13단 안에 있는 값이다. */
.oj-count {
  margin-top: 14px;
  font-size: var(--t-15);
  color: var(--ink-500);
}
.oj-count strong {
  font-size: var(--t-20);
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.oj { margin-top: 32px; }

.oj-stage {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  overflow: hidden;
  box-shadow: 0 1px 3px rgb(16 35 59 / 7%);
}

/* 창틀. 히어로와 같은 모양이되 슬라이드마다 주소가 바뀐다 */
.oj-bar {
  height: 34px; display: flex; align-items: center; gap: 6px;
  padding: 0 12px;
  background: var(--surface-fill); border-bottom: 1px solid var(--line);
}
.oj-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); }
.oj-url {
  margin-left: 10px; font-family: var(--font-mono);
  font-size: var(--t-11); color: var(--ink-300);
}

/* ⚠ 높이를 고정한다. 슬라이드마다 내용 길이가 달라 안 고정하면 넘길 때마다
     절 전체가 출렁이고, 아래 절이 위아래로 튄다.
   ⚠ 가장 긴 장(02 문제)에 맞춘다. 모자라면 overflow: hidden 이 아래를
     잘라 내는데, 잘린 티가 안 나서 눈으로는 못 잡는다. */
.oj-slides { position: relative; height: 560px; }

.oj-slide {
  position: absolute; inset: 0;
  padding: 20px;
  overflow: hidden;
  opacity: 0;
  transform: translateX(14px);
  transition: opacity .34s ease, transform .34s ease;
  pointer-events: none;
}
.oj-slide.on { opacity: 1; transform: none; pointer-events: auto; }

/* 슬라이드 설명 — 무엇을 보고 있는지 한 줄로 말한다 */
.oj-cap {
  display: flex; align-items: baseline; gap: 8px;
  margin-bottom: 14px; padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.oj-cap-step {
  font-family: var(--font-mono); font-size: var(--t-11);
  font-weight: 600; color: var(--accent);
}
.oj-cap-text { font-size: var(--t-13); color: var(--ink-500); }

/* ── 슬라이드 1 · 문제 목록 ── */
.oj-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.oj-chip {
  padding: 3px 10px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-500); font-size: var(--t-11);
}
.oj-chip.on { border-color: var(--ink-900); background: var(--ink-900); color: var(--surface); }

.oj-table { width: 100%; border-collapse: collapse; font-size: var(--t-12); }
.oj-table th {
  text-align: left; padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-400); font-size: var(--t-11); font-weight: 600;
}
.oj-table td { padding: 9px 10px; border-bottom: 1px solid var(--line); color: var(--ink-700); }
.oj-table .num { font-family: var(--font-mono); color: var(--ink-400); }
.oj-table .name { color: var(--ink-900); font-weight: 500; }
.oj-badge {
  display: inline-block; padding: 1px 7px; border-radius: 4px;
  font-size: var(--t-11); font-weight: 600;
}
.oj-badge.easy   { background: var(--ok-soft);     color: var(--ok); }
.oj-badge.normal { background: var(--warn-soft);   color: var(--warn); }
.oj-badge.hard   { background: var(--danger-soft); color: var(--danger); }
.oj-badge.solved { background: var(--ok-soft);     color: var(--ok); }
.oj-badge.trying { background: var(--info-soft);   color: var(--info); }

/* ── 슬라이드 2 · 문제 ── */
.oj-prob-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 4px; }
.oj-prob-code { font-family: var(--font-mono); font-size: var(--t-12); color: var(--accent); }
.oj-prob-title { font-size: var(--t-17); font-weight: 700; color: var(--ink-900); }
.oj-prob-meta { font-size: var(--t-11); color: var(--ink-400); margin-bottom: 14px; }

.oj-prob-body { display: grid; grid-template-columns: 1.35fr 1fr; gap: 16px; }
.oj-sec-title {
  font-size: var(--t-11); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-400); margin-bottom: 6px;
}
.oj-sec + .oj-sec { margin-top: 14px; }
.oj-sec-body {
  font-size: var(--t-12); line-height: 1.85; color: var(--ink-700);
  white-space: pre-wrap; word-break: keep-all;
}
.oj-io {
  font-family: var(--font-mono); font-size: var(--t-11); line-height: 1.7;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--surface-sunken); color: var(--ink-700); white-space: pre;
}

/* ── 슬라이드 3 · 제출 ── */
.oj-tabs { display: flex; gap: 4px; margin-bottom: 10px; }
.oj-tab {
  padding: 5px 12px; border: 1px solid var(--line); border-bottom: 0;
  border-radius: 6px 6px 0 0; background: var(--surface-sunken);
  font-family: var(--font-mono); font-size: var(--t-11); color: var(--ink-400);
}
.oj-tab.on { background: var(--surface-code); color: #C9D6E5; border-color: var(--surface-code); }
.oj-editor {
  background: var(--surface-code); border-radius: 0 6px 6px 6px;
  padding: 14px 16px; overflow: hidden;
}
.oj-editor pre {
  margin: 0; font-family: var(--font-mono); font-size: var(--t-11);
  line-height: 1.8; color: #C9D6E5; white-space: pre;
}
.oj-editor .kw  { color: #7FA8D9; }
.oj-editor .fn  { color: #9CC7A0; }
.oj-editor .num { color: #E0A46A; }
.oj-editor .cm  { color: #5B7392; }

/* ── 슬라이드 4 · 채점 결과 ── */
.oj-verdict {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px; border-radius: 8px;
  background: var(--ok-soft); border: 1px solid #BFE3D2; margin-bottom: 14px;
}
.oj-verdict-main { font-size: var(--t-20); font-weight: 700; color: var(--ok); }
.oj-verdict-meta { font-family: var(--font-mono); font-size: var(--t-11); color: var(--ink-500); }

.oj-cases { display: flex; flex-direction: column; gap: 6px; }
.oj-case {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border: 1px solid var(--line); border-radius: 6px;
  font-size: var(--t-12); color: var(--ink-700);
}
.oj-case-no { font-family: var(--font-mono); font-size: var(--t-11); color: var(--ink-400); width: 52px; }
.oj-case-ok { color: var(--ok); font-weight: 600; }
.oj-case-time { margin-left: auto; font-family: var(--font-mono); font-size: var(--t-11); color: var(--ink-400); }
.oj-case.hidden-case .oj-case-no { color: var(--ink-300); }

/* ── 슬라이드 조작 ── */
.oj-nav {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  margin-top: 16px;
}
.oj-arrow {
  width: var(--control-sm); height: var(--control-sm);
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: 50%;
  background: var(--surface); color: var(--ink-500);
  font-family: inherit; font-size: var(--t-13); cursor: pointer;
}
.oj-arrow:hover { border-color: var(--ink-900); color: var(--ink-900); }

.oj-dots { display: flex; gap: 8px; }
.oj-dotbtn {
  width: 9px; height: 9px; padding: 0; border: 0; border-radius: 50%;
  background: var(--line-strong); cursor: pointer;
  transition: background .2s ease, transform .2s ease;
}
.oj-dotbtn.on { background: var(--ink-900); transform: scale(1.25); }

@media (max-width: 1023px) {
  .oj-prob-body { grid-template-columns: 1fr; }
  .oj-slides { height: 700px; }
}
@media (max-width: 639px) {
  .oj-slides { height: 760px; }
  .oj-slide { padding: 14px; }
  .oj-table th:nth-child(4), .oj-table td:nth-child(4) { display: none; }
}

/* ⚠ 움직임을 줄여 달라고 한 사람에게는 넘김 애니메이션과 자동 넘김을 멈춘다 */
@media (prefers-reduced-motion: reduce) {
  .oj-slide { transition: none; }
}
