/* =====================================================================
   neu.css — Toss 스타일 평면 디자인 토큰(TDS: Toss Design System 색·반경·
   여백·타이포)과 컴포넌트 스타일. 캔버스·카드는 흰 바탕 + 1px 테두리(그림자
   없음), "잠긴/읽기전용" 블록만 --surface-2(#f2f4f6)로 구분하며 편집 가능한
   카드·입력칸에는 쓰지 않는다. 읽기 전용 정보는 불릿 대신 좌측 라벨 / 우측
   값의 "리스트 행"(.lrows/.lrow)으로 쌓는다. 여백은 4·6·8·16·24·32 여섯
   값만 쓴다. 색·대비 기준은 각 --토큰 선언 옆 주석 참고.

   ── 상태 표시 규칙(tools/test_create.js가 ①②④를 실측해서 실패시킨다) ──
     ① 본문(--ink)·보조문(--sub)은 흰 캔버스 기준 대비 7:1 이상을 유지한다.
     ② 버튼·입력칸·포커스는 그림자가 아니라 배경색/테두리/outline으로
        상태를 만든다.
     ③ 그림자만으로 상태를 표현하지 않는다 — 색·테두리·글자로 한 번 더
        말한다.
     ④ 터치 타깃 44×44 이상.

   ── 반경 — TDS: 작은 요소 sm(4)/md(6), 버튼 크기별 small(8)/medium(10)/
      large(14)/xlarge(16), 카드 16~20. 알약형(999px) 칩·원형 아바타는 이
      스케일과 무관한 별도 형태 언어다.

   ── 타이포 스케일(5단, --fs-* 변수) — 큰 제목 32/700/-.02em(줄간격 1.3) ·
      섹션 제목 18~20/700(1.3) · 본문 15~16/400(1.6) · 라벨 13~14/600 ·
      보조문 13~14/400. 칩·배지 등 본문이 아닌 부속 표시는 스케일 바깥의
      --fs-micro(12px) 하나로 모은다.
   ── 숫자 자리맞춤(tabular-nums) — input/select/textarea·.btn은 font:inherit
      가 font-variant를 초기화해 body의 tabular-nums 상속이 끊긴다. 그래서
      이 규칙들과 숫자가 나오는 요소(.cnt·.rtable·.lrow-r·.sum dd·.out .m·
      .dt-prev 등)엔 font-variant-numeric:tabular-nums를 다시 명시한다.

   ── 하위 단계 스테퍼(지하철 노선도형) — 상단 진행 막대(.prog) 밑에 선택된
      큰 단계의 하위 단계를 동그라미+선으로 그린다. 버튼 자체를 44×44 히트
      영역으로 두고 그 안에 28px 시각 원(.sdot i)을 얹는 이중 구조. 상태
      3종(지난·지금·아직)은 색뿐 아니라 테두리 굵기·채움·기호로도 같이
      말한다(규칙③).
   ===================================================================== */

:root{
  --wrap:1180px;

  /* 캔버스 · 표면 — 토스: 캔버스도 카드도 흰색. --surface-2는 "잠긴/읽기전용" 전용이다.
     편집 가능한 카드 · 입력칸에는 절대 쓰지 않는다 — 섞이면 "눌러도 되나?"를 헷갈리게 만든다. */
  --canvas:#ffffff;
  --surface:#ffffff;
  --surface-2:#f2f4f6;
  --border:#e5e8eb;         /* TDS 공식 border — 카드 · 표 · 구분선 · 하단 CTA 위 경계선 */
  --border-input:#d6dbe1;   /* 입력칸처럼 "조작 가능"을 말해야 하는 경계 — TDS가 별도 토큰을 안 줘서
                                카드 보더(e5e8eb)보다 한 단 진한 값을 프로젝트에서 파생했다 */

  --ink:#191f28;    /* TDS foreground — 본문 대비 16.55:1 (흰 캔버스 기준) */
  --sub:#4e5968;    /* TDS body-text — 보조문 대비 7.11:1. 이보다 밝히면 7:1 기준이 깨진다 */
  --mute:#8b95a1;   /* TDS muted — 대비 3.04:1. 본문 · 보조문 금지, 비활성 라벨 · 구분 아이콘 전용 */

  --accent:#1b64da;         /* TDS weak-fg — 글자가 얹히는 곳: 버튼 배경 · 링크 · 포커스 링 · 숫자 배지 */
  --accent-hover:#1755b9;   /* accent보다 한 단 어둡게(호버/눌림) — 흰 글자 6.92:1 */
  --accent-bright:#3182f6;  /* TDS primary 원값 — 글자가 없는 곳 전용: 진행 막대 · 토글 켜짐 · 장식 채움 */
  --accent-weak:#e8f3ff;    /* TDS weak-bg — 액센트 배경(연). 그 위 글자는 --accent(4.82:1) */

  --danger:#a81a25;      /* 글자 · 아이콘 전용(에러 문구 · 필수* · 삭제 아이콘) — TDS danger(e42939)는
                             흰 배경에서 4.4919:1로 4.5 미달이라 어둡혀 썼다 */
  --danger-line:#e42939; /* TDS 공식 danger 원값 — 테두리 등 비문자 요소 전용(3:1 기준엔 충분) */
  --danger-weak:#fdecea;

  --ok:#0f6b43;    --ok-weak:#e4f3ec;
  --warn:#7a5400;  --warn-weak:#fbf1dc;

  --rad-4:4px; --rad-6:6px; --rad-8:8px; --rad-10:10px; --rad-14:14px; --rad-16:16px; --rad-20:20px;

  /* 타이포 스케일(5단) — 파일 머리말 참고 */
  --fs-h1:32px; --fs-h2:20px; --fs-body:16px; --fs-body-sm:15px; --fs-label:14px; --fs-sub:14px; --fs-micro:12px;
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:var(--canvas); color:var(--ink);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Pretendard,Roboto,"Apple SD Gothic Neo","Malgun Gothic",sans-serif;
  font-size:var(--fs-body); line-height:1.6; -webkit-font-smoothing:antialiased;
  font-variant-numeric:tabular-nums;   /* 숫자 자리맞춤 기본값(아래 input/.btn엔 재선언 — 헤더 참고) */
}
h1,h2,h3{letter-spacing:-.02em; margin:0; line-height:1.3}
a{color:var(--accent)}
.sr{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap}
.hide{display:none !important}
.sp{flex:1}  /* 범용 flex 스페이서 — navbar뿐 아니라 카드 헤더 등에서도 쓴다 */

/* 예전 유틸(현재 화면에서 쓰이진 않지만 남겨 둔다) */
.neu{background:var(--surface); border:1px solid var(--border); border-radius:var(--rad-16)}
/* ── 레이아웃 ──────────────────────────────────────────────────────── */
.wrap{max-width:var(--wrap); margin:0 auto; padding:0 24px}
.topbar{position:sticky; top:0; z-index:20; background:var(--canvas); padding:16px 0; border-bottom:1px solid var(--border)}
.topbar .row{display:flex; align-items:baseline; gap:8px; margin-bottom:8px}
.topbar .row b{font-size:var(--fs-label); font-weight:700}
.topbar .row .now{font-size:var(--fs-sub); color:var(--sub)}
/* 하단 고정 바 실제 높이를 JS(app.js syncNavHeight)가 --navh로 채운다 — 값이 오기 전 대비용 기본값.
   #main은 일부러 id 선택자다 — <main class="wrap" id="main">에서 `.wrap{padding:0 24px}`(클래스
   선택자, 특이도 0,0,1,0)을 이겨야 padding-bottom이 살아남는다(`main{}` 같은 태그 선택자로
   되돌리면 다시 죽는다). */
#main{padding:32px 0 calc(var(--navh, 88px) + 32px)}

/* 진행 막대 — 파인 트랙 + 액센트 채움. 채움은 그 위에 글자가 없으니 accent-bright(장식 채움 전용) */
.prog{display:flex; gap:8px}
.prog .seg{flex:1; height:8px; border-radius:99px; background:var(--surface-2); border:1px solid var(--border)}
/* 채움은 빨리 나갔다 부드럽게 멎는다 — 앞이 가파른 곡선. */
.prog .seg i{display:block; height:100%; width:0; border-radius:99px; background:var(--accent-bright);
  transition:width .55s cubic-bezier(.16,1,.3,1)}
.prog .seg.done i{width:100%}
/* 지금 단계 칸은 하위 화면 위치만큼 찬다 — app.js paintProg()가 --fill을 넣는다.
   값이 없을 때만 절반으로 물러선다. */
.prog .seg.now i{width:var(--fill,50%)}
/* ── 하위 단계 스테퍼(지하철 노선도형) ── 파일 머리말 참고. .substepper-wrap이 큰 단계가
   없는 화면(시작·만들기)에서 hide로 접힌다(app.js paintSubstepper). 가로로 넘칠 만큼 하위 단계가
   많아지면(예: 차시를 많이 늘렸을 때) 스크롤로 흘려보낸다 — 줄바꿈하면 노선도 느낌이 깨진다. */
.substepper-wrap{margin-top:12px; overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch}
.substepper{list-style:none; margin:0; padding:4px 2px; display:flex; align-items:flex-start; min-width:min-content}
.substepper .sitem{flex:0 0 auto; width:64px; display:flex; flex-direction:column; align-items:center}
.substepper .sline{flex:1 1 20px; min-width:12px; height:2px; margin-top:22px; background:var(--border)}
.substepper .sline.done{background:var(--accent-bright)}
.substepper .sdot{width:44px; height:44px; flex:none; border:none; border-radius:50%; background:transparent;
  padding:0; margin:0; display:grid; place-items:center; cursor:pointer}
.substepper .sdot:disabled{cursor:default}
.substepper .sdot:focus-visible{outline:2px solid var(--accent); outline-offset:2px}   /* 규칙②: outline, 그림자 아님 */
.substepper .sdot i{width:28px; height:28px; border-radius:50%; font-style:normal; font-size:12px; font-weight:800;
  display:grid; place-items:center; border:2px solid var(--border-input); background:var(--surface); color:var(--sub);
  font-variant-numeric:tabular-nums; transition:background .12s,border-color .12s,color .12s}
.substepper .sitem.done .sdot i{background:var(--accent); border-color:var(--accent); color:#fff}
.substepper .sitem.now .sdot i{background:var(--surface); border-color:var(--accent); border-width:3px; color:var(--accent)}
.substepper .slab{margin-top:4px; font-size:var(--fs-micro); color:var(--sub); white-space:nowrap}
.substepper .sitem.now .slab{color:var(--ink); font-weight:700}
@media (max-width:560px){ .substepper .slab{display:none} .substepper .sitem{width:auto; padding:0 2px} }

/* ── 카드 ── 흰 바탕 + 1px 테두리, 그림자 없음 ──────────────────────────── */
.card{background:var(--surface); border:1px solid var(--border); border-radius:var(--rad-20); padding:32px; margin-bottom:32px}
.card>h1{font-size:var(--fs-h1); line-height:1.3; margin:0 0 8px; font-weight:700; letter-spacing:-.02em}
.card>h2{font-size:var(--fs-h2); line-height:1.3; margin:32px 0 8px; font-weight:700}
.card .kick{font-size:var(--fs-label); font-weight:800; color:var(--accent); letter-spacing:.03em; margin-bottom:8px}
.card .lead{font-size:var(--fs-body); line-height:1.6; color:var(--sub); margin:0 0 32px}
.card .lead b{color:var(--ink)}
/* 섹션 소제목 바로 아래 붙는 한 줄 힌트 — .lead(제목 아래 리드)보다 한 단 작다. 반복되는 사실을
   되풀이하지 않는다(토스 라이팅 원칙 "빈 문장 제거") — 남은 것은 새 정보를 주는 문장뿐이다. */
.card .sect-hint{font-size:var(--fs-sub); color:var(--sub); line-height:1.6; margin:0 0 16px}
@media (max-width:760px){ .card{padding:24px} .card>h1{font-size:28px} .wrap{padding:0 16px} }

/* 소제목 구분 — 선 하나로(카드 안을 그림자로 구획하지 않는다) */
.sect{margin:32px 0 16px; padding-bottom:8px; border-bottom:1px solid var(--border);
  font-size:var(--fs-h2); line-height:1.3; font-weight:700; display:flex; align-items:center; gap:8px; flex-wrap:wrap}
.substep:first-child .sect{margin-top:0}   /* 하위 단계 화면의 첫 sect는 카드 맨 위 바로 아래라 위 여백이 필요 없다 */
.sect .n{width:26px; height:26px; border-radius:50%; background:var(--accent); color:#fff;
  font-size:13px; font-weight:800; font-variant-numeric:tabular-nums; display:grid; place-items:center; flex:none}
.sect-action{margin-left:auto}
.sect-sub{font-weight:500; font-size:var(--fs-sub); color:var(--sub)}

/* ── 입력칸 ─── 규칙②: 뉴모피즘 아님. 흰 면 + 보이는 테두리 ───────────────── */
.f{display:block; margin-bottom:16px}
.f>.lab{display:block; font-size:var(--fs-label); font-weight:600; margin-bottom:6px}
.f>.lab.chiponly{margin-bottom:6px}
.f>.lab .req{color:var(--danger); margin-left:4px}
.f>.lab .hint{display:block; font-weight:500; font-size:var(--fs-sub); color:var(--sub); margin-top:4px}
input[type=text],input[type=number],input[type=date],input[type=time],input[type=email],select,textarea{
  width:100%; font:inherit; font-size:var(--fs-body); color:var(--ink);
  padding:8px 16px; min-height:48px;
  background:var(--surface); border:1.5px solid var(--border-input); border-radius:var(--rad-10);
  font-variant-numeric:tabular-nums;   /* font:inherit가 위 body의 값을 되돌리므로 다시 명시(헤더 참고) */
}
textarea{line-height:1.6; resize:vertical; min-height:120px; padding:16px}
/* 차시 "프로그램 설명"은 rows=2로 짧게 시작하고 넘치는 내용은 내부 스크롤로 본다. 전역
   min-height:120px가 이 의도를 덮어쓰므로 속성 선택자로만 걷어낸다 — rows="2"인 textarea만
   걸리고(fields.js textarea()가 rows 옵션을 attribute로 그대로 씀), 인사말처럼 rows=9인 긴 글
   칸은 120px 최소값을 유지한다. resize:vertical은 전역 규칙 그대로라 필요하면 늘릴 수 있다. */
textarea[rows="2"]{min-height:0; overflow-y:auto}
input::placeholder,textarea::placeholder{color:var(--mute)}
input:focus,select:focus,textarea:focus{
  outline:2px solid var(--accent); outline-offset:2px;   /* 규칙②: 포커스 링은 그림자가 아니다 */
  border-color:var(--accent);
}
/* 잠긴 입력칸도 --surface-2 표면을 쓴다 — --sub는 --surface-2 위에서 대비 기준에 못 미치므로
   글자색은 --sub가 아니라 --ink를 쓴다 */
input:disabled,textarea:disabled,select:disabled{color:var(--ink); background:var(--surface-2); border-style:dashed; opacity:1}
.f.bad input,.f.bad textarea{border-color:var(--danger-line)}
.f.bad .msg{color:var(--danger); font-size:var(--fs-sub); font-weight:700; margin-top:6px}

/* 짧은 필드를 여러 개 나란히(서로 다른 필드일 때만) */
.pair{display:grid; grid-template-columns:1fr 1fr; gap:16px}
.pair3{display:grid; grid-template-columns:1fr 1fr 1fr; gap:16px}
@media (max-width:760px){ .pair,.pair3{grid-template-columns:1fr} }
.tag-lang{display:inline-block; font-size:var(--fs-micro); font-weight:800; letter-spacing:.04em;
  color:var(--accent); background:var(--accent-weak); border-radius:99px; padding:4px 8px; margin-left:6px}
.chip{display:inline-block; font-size:var(--fs-micro); font-weight:700; letter-spacing:.01em; color:var(--sub);
  background:var(--surface-2); border:1px solid var(--border); border-radius:99px; padding:4px 8px; margin-left:6px}
/* .pair(2열) 안에서 칩이 붙은 라벨과 안 붙은 라벨은 높이가 달라 입력칸 상단이 어긋난다 — 칩이
   있는 라벨 높이만큼 min-height를 고정해 칩 유무와 무관하게 입력칸 시작 y를 맞춘다. */
.pair-chiprow > .f > .lab{min-height:30px}

/* ── 한/영 짝 필드(F.bi) ── 라벨은 한 번만, 칩으로 언어만 구분 ──
   짧은 짝은 .bi-grid로 두 개씩 나란히(넓은 화면 2열), 긴 글(long)은 항상 혼자 한 줄 전체 폭. */
.bi{margin-bottom:16px}
.bi-h{font-size:var(--fs-label); font-weight:600; margin-bottom:8px}
.bi-h .hint{display:block; font-weight:500; font-size:var(--fs-sub); color:var(--sub); margin-top:4px}
.bi .f{margin-bottom:8px}
.bi .f:last-child{margin-bottom:0}
.bi-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:4px 24px}
.bi-grid>.bi-long{grid-column:1/-1}  /* 방어용 — 긴 글은 혹시 grid 안에 들어와도 항상 전체 폭 */
@media (max-width:760px){ .bi-grid{grid-template-columns:1fr} }
/* 국문·영문을 한 줄에 2열로(짧은 값 전용 — 지금은 차시 "프로그램 이름"만 쓴다). 라벨은 위에
   한 줄로 걸치고 그 아래 두 입력칸이 나란히 앉는다. 다른 F.bi() 호출은 그대로 stacked(위아래)라
   이 규칙은 .bi-row가 붙은 곳에만 적용된다. */
.bi-row{display:grid; grid-template-columns:1fr 1fr; gap:4px 16px}
.bi-row>.bi-h{grid-column:1/-1}
.bi-row .f{margin-bottom:0}
@media (max-width:560px){ .bi-row{grid-template-columns:1fr} }

/* 날짜+시간/기간 선택(증빙 제출 기한 · 비한국인 청소 대체 기간) */
.dt-row{display:flex; gap:8px; flex-wrap:wrap}
.dt-row input[type=date]{flex:1 1 190px}
.dt-row input[type=time]{flex:0 1 130px}
.dt-prev{margin-top:8px; display:flex; flex-direction:column; gap:6px}
.dt-prev>div{display:flex; align-items:baseline; gap:8px; font-size:var(--fs-sub); color:var(--ink); font-variant-numeric:tabular-nums}
.dt-prev .tag-lang{margin-left:0; flex:none}

/* 글자수 카운터 — 색 + 글자 + 막대 세 가지로 상태를 말한다(규칙③). 막대 채움은 글자가 없는 장식이라
   기본은 accent-bright, warn/over 상태는 색으로 한 번 더 말해야 하니 danger-line(장식)을 쓴다.
   숫자가 늘 바뀌는 곳이라 tabular-nums로 자리를 고정한다. */
.cnt{display:flex; justify-content:flex-end; gap:6px; font-size:var(--fs-sub); color:var(--sub); margin-top:4px; font-variant-numeric:tabular-nums}
.cnt.warn{color:var(--warn); font-weight:700}
.cnt.over{color:var(--danger); font-weight:800}
.cnt .bar{width:96px; height:6px; align-self:center; border-radius:99px; background:var(--surface-2); border:1px solid var(--border)}
.cnt .bar i{display:block; height:100%; border-radius:99px; background:var(--accent-bright); transition:width .15s}
.cnt.warn .bar i{background:var(--warn)}
.cnt.over .bar i{background:var(--danger-line)}

/* ── 버튼 ─── 규칙②: 배경/테두리로 상태를 만든다. 그림자는 아예 없다 ──────────
   크기 3단: sm(작은 보조 44px/rad 8) · 기본(48px/rad 10) · CTA(56px/rad 14, 하단 바 주 버튼·#btnGo).
   버튼 글자는 15~17px/600(TDS 확정 범위). */
.btn{font:inherit; font-size:15px; font-weight:600; border-radius:var(--rad-10); cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  padding:8px 24px; min-height:48px; border:1.5px solid var(--border-input); background:var(--surface); color:var(--ink);
  transition:background .12s, border-color .12s, color .12s;
  font-variant-numeric:tabular-nums;   /* font:inherit가 body의 값을 되돌리므로 다시 명시(헤더 참고) */
}
.btn:hover{background:var(--surface-2); border-color:var(--mute)}
.btn:active{background:var(--surface-2)}
.btn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.btn.primary{background:var(--accent); color:#fff; border-color:var(--accent)}
.btn.primary:hover{background:var(--accent-hover); border-color:var(--accent-hover)}
.btn.primary:disabled{background:var(--surface-2); color:var(--mute); border-color:var(--border); cursor:not-allowed}
.btn.line{background:transparent; border-color:var(--accent); color:var(--accent)}
.btn.line:hover{background:var(--accent-weak)}
.btn.sm{padding:6px 16px; min-height:44px; border-radius:var(--rad-8)}
.btn.danger{border-color:var(--danger-line); color:var(--danger)}
.btn.danger:hover{background:var(--danger-weak)}

/* 하단 고정 바 — 토스식: 진행 버튼은 결과를 말한다. 배경 흰색 + 위쪽 1px 테두리, 그림자 금지(확정).
   주 버튼(다음 · #btnGo)은 56px/반경14/17px·600 — 모바일 폭에서는 가로 꽉 채움. */
.navbar{position:fixed; left:0; right:0; bottom:0; z-index:30; background:var(--surface); border-top:1px solid var(--border)}
.navbar .in{max-width:var(--wrap); margin:0 auto; padding:16px 24px; display:flex; align-items:center; gap:16px}
.navbar .msg{font-size:var(--fs-sub); color:var(--sub)}
.navbar .msg.block{color:var(--danger); font-weight:700}
.navbar .btn.primary,#btnGo{min-height:56px; padding:0 32px; border-radius:var(--rad-14); font-size:17px; font-weight:600}
@media (max-width:760px){
  .navbar .in{flex-direction:column; align-items:stretch; gap:8px; padding:16px}
  .navbar .msg{order:-1; text-align:center}
  .navbar .sp{display:none}
  .navbar #btnPrev{order:2; width:100%}
  .navbar .btn.primary{order:3; width:100%}
}

/* ── 고르는 카드 ─── 선택은 테두리+체크+배경 3중 표시(규칙③) ──────────────── */
.picks{display:grid; gap:16px}
.picks.two{grid-template-columns:1fr 1fr}
.picks.three{grid-template-columns:repeat(3,1fr)}
@media (max-width:760px){ .picks.two,.picks.three{grid-template-columns:1fr} }
.pick{position:relative; text-align:left; width:100%; font:inherit; color:inherit; cursor:pointer;
  background:var(--surface); border:1.5px solid var(--border); border-radius:var(--rad-16); padding:24px}
.pick:hover{border-color:var(--border-input)}
.pick:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.pick.sel{border-color:var(--accent); background:var(--accent-weak)}
.pick.sel::after{content:'✓'; position:absolute; top:8px; right:8px; width:24px; height:24px;
  border-radius:50%; background:var(--accent); color:#fff; font-size:14px; font-weight:800; display:grid; place-items:center}
.pick .t{font-size:var(--fs-h2); font-weight:800; margin-bottom:4px; display:flex; align-items:center; gap:8px}
.pick .d{font-size:var(--fs-sub); color:var(--sub); line-height:1.6}
.pick:disabled,.pick.off{cursor:not-allowed; opacity:.65; background:var(--surface-2)}
.pick .soon{font-size:var(--fs-micro); font-weight:800; color:var(--sub); background:var(--surface-2); border:1px solid var(--border);
  border-radius:99px; padding:4px 8px}

/* ── 스위치 ─── 켜짐을 색+글자로 말한다. 트랙 채움은 글자가 없는 장식이라 accent-bright ────────── */
.sw{display:flex; align-items:center; gap:16px; padding:16px; border-radius:var(--rad-16);
  background:var(--surface); border:1.5px solid var(--border); margin-bottom:16px; cursor:pointer; min-height:56px}
.sw .track{position:relative; width:52px; height:30px; border-radius:99px; background:var(--border-input); flex:none; transition:background .15s}
.sw .track i{position:absolute; top:3px; left:3px; width:24px; height:24px; border-radius:50%;
  background:#fff; box-shadow:0 1px 2px rgba(15,23,42,.25); transition:left .15s}
.sw input{position:absolute; opacity:0; width:0; height:0}
.sw.on .track{background:var(--accent-bright)}
.sw.on .track i{left:25px}
.sw input:focus-visible+.track{outline:2px solid var(--accent); outline-offset:2px}
.sw .tx{flex:1}
.sw .tx b{display:block; font-size:var(--fs-body); font-weight:700}
.sw .tx span{font-size:var(--fs-sub); color:var(--sub)}
.sw .state{font-size:13px; font-weight:800; color:var(--sub)}
.sw.on .state{color:var(--accent)}
/* 차시 카드 안의 작은 토글(전기·후기 분리가 차시마다 하나씩) */
.sw.sm{padding:8px 16px; min-height:44px; gap:8px; margin-bottom:16px}
.sw.sm .track{width:40px; height:24px}
.sw.sm .track i{width:18px; height:18px; top:3px; left:3px}
.sw.sm.on .track i{left:19px}
.sw.sm .tx b{font-size:var(--fs-label)}

/* ── 알림 ─── 색 + 글자 + 테두리 ────────────────────────────────────────── */
.note{border-radius:var(--rad-16); padding:16px; font-size:var(--fs-body-sm); margin:16px 0; border:1.5px solid}
.note b{font-weight:800; margin-right:4px}
.note ul{margin:6px 0 0; padding-left:16px} .note li{margin:4px 0}
.note.info{background:var(--accent-weak); border-color:#b9cde6; color:var(--accent)}
.note.ok{background:var(--ok-weak); border-color:#a9d3be; color:var(--ok)}
.note.warn{background:var(--warn-weak); border-color:#e0cb94; color:var(--warn)}
.note.err{background:var(--danger-weak); border-color:#e3b0ab; color:var(--danger)}

/* 편집 가능한 묶음 상자 — 잠긴 것(.locked)과 모양이 달라야 한다.
   .locked는 --surface-2라 물러나 보이고(=만질 수 없음), .group은 흰 면이라 도드라진다(=만질 수 있음)
   — 그림자가 아니라 배경색·테두리 스타일로 구분한다. */
.group{background:var(--surface); border:1.5px solid var(--border); border-radius:var(--rad-16); padding:24px; margin-bottom:24px}
.group>.gh{display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-bottom:16px}
.group>.gh .gh-t{font-size:var(--fs-h2); font-weight:800}   /* 차시 하나 = 화면 하나라 사실상 그 화면의 제목이므로 섹션 제목급 크기를 쓴다 */
.group>.gh .prog-date{width:auto; flex:0 0 auto; min-width:150px}
.progtag{margin:16px 0 8px; font-weight:800; font-size:var(--fs-sub); color:var(--accent);
  background:var(--accent-weak); display:inline-block; padding:4px 8px; border-radius:99px}
/* '두 반 공통' 표시 — 반별 태그(액센트색)와 구분되게 회색 계열로 */
.progtag.alt{color:var(--sub)}

/* 잠긴 기본값 — 바깥 틀은 --surface-2로 "여긴 못 건드려요"를 말한다. --sub는 흰 캔버스 기준으로
   대비를 맞춘 값이라 --surface-2 위에서는 기준에 못 미친다 — 그래서 실제 내용은 항상 흰 속판
   (.lrows, 아래 정의)에 얹어 보조문 7:1을 지킨다. "고정" 칩을 누르면 담당자 연락처가 펼쳐진다
   (details/summary). */
.locked{background:var(--surface-2); border:1px solid var(--border); border-radius:var(--rad-16); padding:16px; margin-bottom:16px}
.locked .h{display:flex; align-items:center; gap:8px; flex-wrap:wrap; font-size:17px; font-weight:800;
  letter-spacing:-.01em; color:var(--ink); margin-bottom:12px}
.locked .h>span:first-child{flex:1}

/* ── 정보 팝오버(말풍선) ── "고정" 칩 · 사진 안내 칩이 공통으로 쓰는 오버레이 컴포넌트
   (fields.js popover()). <details>와 달리 열려도 주변 레이아웃을 밀지 않는다 — 그 자리 위에
   뜬다. 열림 상태는 aria-expanded뿐 아니라 테두리·배경색으로도 같이 말한다(그림자만으로 상태
   표현 금지, 규칙③). 이 프로젝트는 그림자를 전역적으로 쓰지 않으므로(파일 머리말) 말풍선도
   그림자 대신 --accent 테두리로 캔버스에서 도드라지게 한다. */
.pop{position:relative; display:inline-flex; vertical-align:middle}
/* 탭 영역은 44px(접근성 하한)를 지키되 보이는 알약은 26px 높이로 줄인다. 바깥 여백은 투명한
   손가락 자리다. */
/* ::before는 절대배치라 z-index 없이도 흐름 콘텐츠 위에 그려진다. 자식 요소엔 z-index:1을
   줄 수 있지만 "고정" 같은 텍스트 노드에는 줄 수 없다(텍스트 노드는 요소가 아니라 선택자가
   안 닿는다) — 그래서 트리거를 쌓임 맥락(isolation:isolate)으로 만들고 ::before를 -1로
   내린다. 이 두 선언이 없으면 텍스트가 알약 배경 뒤로 숨는다. */
.pop-trig{cursor:pointer; font-family:inherit; font-size:12px; font-weight:700; color:var(--sub);
  background:none; border:none; padding:9px 0; border-radius:99px;
  display:inline-flex; align-items:center; gap:4px; min-height:44px;
  position:relative; isolation:isolate}
.pop-trig>*{position:relative; z-index:1}
.pop-trig::before{content:''; position:absolute; z-index:-1; left:-10px; right:-10px; top:9px; bottom:9px;
  border:1px solid var(--border-input); border-radius:99px; background:var(--surface);
  transition:border-color .12s, background .12s}
.pop-trig:hover{color:var(--accent)} .pop-trig:hover::before{border-color:var(--accent)}
.pop-trig:focus-visible{outline:none}
.pop-trig:focus-visible::before{outline:2px solid var(--accent); outline-offset:2px}
.pop-trig[aria-expanded="true"]{color:var(--accent)}
.pop-trig[aria-expanded="true"]::before{background:var(--accent-weak); border-color:var(--accent)}
/* 아이콘 하나만 있는 트리거(사진 안내 칩) — 44×44 원형, 텍스트 트리거(고정 칩)와 같은 높이 규칙 */
/* 접근성 하한(44×44 탭 영역)은 그대로 두고 보이는 동그라미만 26px로 줄인다. 바깥 44px는
   투명한 손가락 자리다. */
.pop-trig.icon-only{width:44px; height:44px; padding:0; justify-content:center; border:none;
  background:none; font-size:13px; position:relative}
.pop-trig.icon-only>*{position:relative; z-index:1}
.pop-trig.icon-only::before{content:''; position:absolute; z-index:-1; left:50%; top:50%; width:26px; height:26px;
  transform:translate(-50%,-50%); border:1px solid var(--border-input); border-radius:50%;
  background:var(--surface); transition:border-color .12s, background .12s}
.pop-trig.icon-only:hover::before{border-color:var(--accent)}
.pop-trig.icon-only[aria-expanded="true"]::before{border-color:var(--accent); background:var(--accent-weak)}
.pop-trig.icon-only:focus-visible{outline:none}
.pop-trig.icon-only:focus-visible::before{outline:2px solid var(--accent); outline-offset:2px}
.pop-bubble{position:absolute; z-index:45; top:calc(100% + 10px); width:min(320px,86vw);
  background:var(--surface); border:1.5px solid var(--accent); border-radius:var(--rad-14);
  padding:16px; font-size:var(--fs-sub); font-weight:500; color:var(--sub); line-height:1.6}
.pop-bubble p{margin:0 0 8px} .pop-bubble p:last-child{margin-bottom:0}
.pop-bubble a{color:var(--accent); font-weight:700}
.pop-bubble.align-left{left:0}
.pop-bubble.align-right{right:0}
.pop-bubble::before{content:''; position:absolute; top:-6px; width:11px; height:11px; background:var(--surface);
  border-left:1.5px solid var(--accent); border-top:1.5px solid var(--accent); transform:rotate(45deg)}
.pop-bubble.align-left::before{left:18px}
.pop-bubble.align-right::before{right:18px}

/* ── 리스트 행(list row) ── 읽기 전용 정보는 불릿 대신 이 패턴으로 쌓는다. 좌측 라벨(--sub) ·
   우측 값(--ink) · 행 사이 구분선 · 행 높이 52px 이상. --sub는 흰 캔버스 기준 대비 값이라
   --surface-2 위에서는 기준에 못 미친다 — 그래서 항상 흰 면(.lrows) 위에서만 그린다. .locked
   안(잠긴 출결 기준·대체 절차)과 4단계 리포트 요약 · 1~3단계 정리 화면(.sum)에서 재사용한다.
   값 칸은 숫자가 잦아 tabular-nums로 고정한다. */
.lrows{background:var(--surface); border:1px solid var(--border); border-radius:var(--rad-16); overflow:hidden}
.lrow{display:flex; align-items:center; justify-content:space-between; gap:16px; min-height:52px; padding:8px 16px; border-bottom:1px solid var(--border)}
.lrow:last-child{border-bottom:none}
.lrow-l{color:var(--sub); font-size:var(--fs-body-sm)}
.lrow-r{color:var(--ink); font-size:var(--fs-body-sm); font-weight:700; text-align:right; font-variant-numeric:tabular-nums}
.lrow-r.warn{color:var(--danger)}
.lrow-r.ok{color:var(--ok)}
.lrow.full{display:block; padding:16px}  /* 라벨/값으로 못 나눈 줄 — 한 문단 전체 폭 */
.lrow.full .lrow-l{display:block; color:var(--ink); font-weight:500}

/* 면담·면담비 주제별 묶음 — 접을 수 있는 details, 그룹 이름은 페이지 번호가 아니라 주제 */
.adv-group{background:var(--surface); border:1.5px solid var(--border); border-radius:var(--rad-16); margin-bottom:16px; overflow:hidden}
.adv-group>summary{list-style:none; cursor:pointer; padding:16px; display:flex; align-items:center; gap:8px; min-height:44px}
.adv-group>summary::-webkit-details-marker{display:none}
.adv-group>summary:focus-visible{outline:2px solid var(--accent); outline-offset:-2px}
.adv-gt{flex:1; font-size:var(--fs-body); font-weight:800}
.adv-gc{font-size:12px; font-weight:700; color:var(--sub); background:var(--surface-2); border:1px solid var(--border);
  border-radius:99px; padding:4px 8px; font-variant-numeric:tabular-nums}
.adv-gv{color:var(--sub); transition:transform .15s}
.adv-group[open] .adv-gv{transform:rotate(180deg)}
.adv-gb{padding:0 16px 16px}

/* ── 사진 슬롯(F.photo) ── 업로드 전에도 실제 기본 이미지를 보여 주고, 호버/포커스로 "변경"
   오버레이가 뜬다. 상태는 칩 글자 + 테두리로도 같이 말한다(그림자만으로 상태 표현 금지 규칙 —
   오버레이 자체도 색+투명도로 나타나 그림자에 기대지 않는다).
   #photoBox는 사진 줄(.photo-row)을 세로로 쌓는다. 한 줄 안의 칸 너비는 app.js가 그림의
   가로/세로 비대로 나눠 넣으므로(grid-template-columns를 인라인으로) 칸 높이가 서로 같아진다.
   각 칸(.pslot-btn)의 aspect-ratio도 그림 비율이라 레터박스 없이 꽉 찬다. */
.photo-row{display:grid; gap:24px; align-items:start; margin-bottom:24px}
@media (max-width:640px){ .photo-row{grid-template-columns:1fr !important} }
.pslot{display:flex; flex-direction:column}
/* align-items가 baseline이 아니라 center인 이유 — 라벨 옆 44px 안내 칩(.pop-trig)이 있어서
   텍스트 기준선 정렬이면 칩이 어긋나 보인다. */
/* 헤더는 한 줄 고정(44px = 안내 칩 높이) — 줄바꿈을 허용하면 좁은 칸에서만 두 줄이 되어 칸마다
   사진 상자의 아랫변이 어긋난다. 라벨이 길면 라벨 쪽이 줄어든다. */
.pslot-h{display:flex; align-items:center; gap:8px; flex-wrap:nowrap; min-height:44px}
.pslot-h .pslot-lab{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* 태그 전용 줄 — 태그가 없어도 높이를 예약해 모든 칸이 같은 높이를 갖는다. */
.pslot-lab{font-size:var(--fs-label); font-weight:600}
.pslot-tag{font-size:12px; font-weight:700; color:var(--sub)}
.pslot-tag.req{color:var(--danger)}
.pslot-btn{position:relative; display:block; width:100%; aspect-ratio:4/3; border:1.5px solid var(--border);
  border-radius:var(--rad-16); background:var(--surface-2); overflow:hidden; padding:0; margin:0; cursor:pointer; text-align:left}
.pslot-btn.req{border-color:var(--danger-line); border-style:dashed}
.pslot-btn:hover{border-color:var(--border-input)}
.pslot-btn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.pslot-img{width:100%; height:100%; object-fit:cover; display:block}
.pslot-empty{position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  color:var(--mute); font-size:13px; font-weight:600; text-align:center; padding:16px}
.pslot-ov{position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  background:rgba(25,31,40,.6); color:#fff; font-size:var(--fs-sub); font-weight:700; opacity:0; transition:opacity .12s}
.pslot-btn:hover .pslot-ov, .pslot-btn:focus-visible .pslot-ov{opacity:1}
/* '지우기'는 사진이 있을 때만 보이는데(.pslot-del.hide) 그 줄의 높이가 그때만 생기면 단장 칸과
   전경 칸의 아랫변이 어긋난다. 버튼 유무와 무관하게 줄 높이를 예약한다. */
.pslot-meta{display:flex; justify-content:flex-end; align-items:center; gap:4px; margin-top:6px; min-height:44px}
.pslot-del{font-size:var(--fs-micro); font-weight:700; color:var(--danger); background:none; border:none; cursor:pointer;
  min-height:44px; padding:8px}
/* 전경 사진을 올릴 때 자르기 창을 거치므로, 올린 뒤에도 창을 다시 열 길이 필요하다. 원본
   파일을 들고 있을 때만 보인다(새로고침하면 사라진다 — app.js CROP_SRC). */
.pslot-again{font-size:var(--fs-micro); font-weight:700; color:var(--accent); background:none; border:none; cursor:pointer;
  min-height:44px; padding:8px; text-decoration:underline; text-underline-offset:3px}

/* 얼굴 사진 zip 미리보기 그리드 — 디자이너도 같은 칸으로 */
.pvgrid{display:grid; grid-template-columns:repeat(auto-fill,minmax(78px,1fr)); gap:8px; margin-top:16px}
.pvgrid-sep{grid-column:1/-1; font-size:var(--fs-micro); font-weight:800; color:var(--sub); margin-top:8px; padding-top:8px; border-top:1px dashed var(--border)}
/* 디자이너 명단이 아직 없을 때(조용히 사라지는 대신 안내를 남긴다) */
.pvgrid-empty{grid-column:1/-1; font-size:var(--fs-sub); color:var(--sub); padding:4px 0 8px}
.pvgrid .c{text-align:center; font-size:var(--fs-micro); color:var(--sub)}
.pvgrid .c .sq{width:100%; aspect-ratio:3/4; border-radius:var(--rad-6); border:1px solid var(--border); margin-bottom:4px;
  background:var(--surface-2) center/cover no-repeat}
.pvgrid .c.miss .sq{border:2px solid var(--danger-line)}
.pvgrid .c.miss{color:var(--danger); font-weight:700}

/* ── 파일 넣는 곳 ──────────────────────────────────────────────────────── */
.drop{border:1.5px dashed var(--border-input); border-radius:var(--rad-16); padding:24px; text-align:center;
  background:var(--surface-2); cursor:pointer; min-height:110px; display:flex; flex-direction:column; align-items:center; justify-content:center}
.drop:hover,.drop.drag{border-color:var(--accent); background:var(--accent-weak)}
.drop:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.drop.ok{border-style:solid; border-color:var(--ok); background:var(--ok-weak)}
.drop .big{font-size:var(--fs-body); font-weight:800; margin-bottom:4px}
.drop .sm{font-size:var(--fs-sub); color:var(--sub)}
.fstat{font-size:var(--fs-sub); margin-top:8px; min-height:20px}
.fstat.ok{color:var(--ok); font-weight:700}
.fstat.err{color:var(--danger); font-weight:700}

/* ── 표 편집기(마일리지 등수↔상품) ───────────────────────────────────────── */
.rows{display:grid; gap:8px}
.row{display:grid; gap:8px; align-items:end}
.row .x{width:44px; height:44px; border-radius:var(--rad-8); border:1.5px solid var(--danger-line); color:var(--danger);
  background:var(--surface); font-size:18px; cursor:pointer; flex:none}
.row .x:hover{background:var(--danger-weak)}
.rowhead{display:grid; gap:8px; font-size:13px; font-weight:800; color:var(--sub); margin-bottom:4px}

/* ── 반별 강의실 표 ── 표 하나 + 화살표/Tab 이동. 칸마다 반 번호(작게,좌측)+입력칸이 한 셀에.
   숫자(반 번호)가 있는 표라 tabular-nums로 자리를 고정한다. ── */
.rtable{width:100%; border-collapse:collapse; border:1px solid var(--border); border-radius:var(--rad-8); overflow:hidden; font-variant-numeric:tabular-nums}
.rtable td.rc{border:1px solid var(--border); padding:0; background:var(--surface)}
.rtable td.rc-empty{background:var(--surface-2)}
.rcell{display:flex; align-items:center; gap:6px; padding:0 4px 0 16px}
.rn{font-size:13px; color:var(--sub); font-weight:700; flex:none}
.rtable input[type=text]{border:none; background:transparent; min-height:44px; padding:6px 8px 6px 4px; font-size:var(--fs-body-sm); border-radius:0}
.rtable input[type=text]:focus{outline:2px solid var(--accent); outline-offset:-2px; border-color:transparent}

/* ── 정리(1~3단계) ── 리스트 행 재사용: dt=라벨(--sub) / dd=값(--ink), 행 높이 52px, 구분선.
   값 칸(dd)에 숫자가 자주 나와 tabular-nums로 고정한다. ────── */
.sum{background:var(--surface); border:1px solid var(--border); border-radius:var(--rad-16); padding:0 24px}
.sum dl{display:grid; grid-template-columns:180px 1fr; column-gap:16px; margin:0; font-size:var(--fs-body-sm)}
.sum dt{color:var(--sub); font-weight:500; min-height:52px; display:flex; align-items:center; border-bottom:1px solid var(--border)}
.sum dd{margin:0; color:var(--ink); font-weight:700; min-height:52px; display:flex; align-items:center; border-bottom:1px solid var(--border); font-variant-numeric:tabular-nums}
.sum dt:last-of-type,.sum dd:last-of-type{border-bottom:none}
.sum dd.empty{color:var(--danger); font-weight:700}
@media (max-width:760px){
  .sum dl{grid-template-columns:1fr}
  .sum dt{min-height:0; padding:16px 0 0; border-bottom:none}
  .sum dd{min-height:0; padding:0 0 16px}
}

/* ── 4단계 정리 = 리포트 ── "한 반의 교수님/프락터 명단·사진이 맞게 매칭되는지" 한 번에 보는 화면.
   요약 수치는 옛 타일 그리드 대신 위 .lrows/.lrow(리스트 행)를 그대로 쓴다. */
.rpt-sect{margin-bottom:32px}
.rpt-sect:last-child{margin-bottom:0}
.rpt-h{font-size:var(--fs-h2); font-weight:800; margin-bottom:16px; display:flex; align-items:baseline; gap:8px; flex-wrap:wrap}
.rpt-h .hint{font-size:13px; font-weight:500; color:var(--sub)}
.rpt-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(270px,1fr)); gap:16px}
.rpt-grid-narrow{grid-template-columns:repeat(auto-fill,minmax(210px,1fr))}

.ccard{background:var(--surface); border:1px solid var(--border); border-radius:var(--rad-16); padding:16px}
.ccard-h{font-weight:800; font-size:var(--fs-body-sm); margin-bottom:8px; padding-bottom:8px; border-bottom:1px solid var(--border); font-variant-numeric:tabular-nums}
.prow{display:flex; align-items:center; gap:8px; margin-bottom:8px}
.prow:last-child{margin-bottom:0}
.ppic{width:42px; height:42px; border-radius:50%; background:var(--surface-2) center/cover no-repeat; flex:none; border:1px solid var(--border)}
.ppic.empty{display:flex; align-items:center; justify-content:center}
.ppic.empty svg{width:22px; height:22px; fill:none; stroke:var(--mute); stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.pinfo{flex:1; min-width:0}
.pinfo b{display:block; font-size:var(--fs-label); font-weight:700; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pinfo b.miss{color:var(--mute); font-weight:600}
.pinfo span{display:block; font-size:12px; color:var(--sub); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pinfo .pmiss{color:var(--danger); font-weight:700; font-style:normal}
.prole{font-size:var(--fs-micro); color:var(--sub); flex:none}

/* ── 만들기 결과 ───────────────────────────────────────────────────────── */
@media (max-width:760px){ .outs{grid-template-columns:1fr} }
.out{border-radius:var(--rad-16); background:var(--surface); border:1.5px solid var(--border); padding:16px}
.out.done{border-color:var(--ok)}
.out.fail{border-color:var(--danger)}
.out h3{font-size:17px; margin-bottom:4px}
.out .m{font-size:var(--fs-sub); color:var(--sub); min-height:20px; font-variant-numeric:tabular-nums}   /* 쪽수·용량 숫자가 나오는 줄 */
.out .bar{height:8px; border-radius:99px; background:var(--surface-2); border:1px solid var(--border); margin:16px 0 8px; overflow:hidden}
.out .bar i{display:block; height:100%; width:0; background:var(--accent-bright); transition:width .2s}
.thumbs img{width:100%; border-radius:var(--rad-4); border:1px solid var(--border); display:block; background:var(--surface)}

/* ── 움직임 ─────────────────────────────────────────────────────────
   ① 막대는 처음에 빨리 나갔다가 끝에서 부드럽게 멎는다 — cubic-bezier(.16,1,.3,1)은 앞이
      가파르고 뒤가 완만한 곡선이라 그 느낌이 그대로 난다.
   ② 새로 나타나는 것은 10px 아래에서 올라오며 밝아진다(.fx-in). 한 화면 안에서 여러 덩어리가
      함께 뜰 때는 --fx-i를 하나씩 늘려 45ms씩 늦춘다(.fx-stagger, app.js fxIn).
   끝나면 transform이 남지 않는다(to{transform:none}) — 남으면 그 안의 position:fixed가 어긋난다.
   맨 아래 prefers-reduced-motion에서 전부 끈다. */
@keyframes fpdRise{ from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none} }
@keyframes fpdFade{ from{opacity:0} to{opacity:1} }
@keyframes fpdPop{ from{opacity:0; transform:translateY(8px) scale(.98)} to{opacity:1; transform:none} }
.fx-in{animation:fpdRise .34s cubic-bezier(.16,1,.3,1) both}
.fx-stagger>*{animation:fpdRise .34s cubic-bezier(.16,1,.3,1) both; animation-delay:calc(var(--fx-i,0) * 45ms)}
.crop-ov{animation:fpdFade .16s ease-out both}
.crop-modal{animation:fpdPop .26s cubic-bezier(.16,1,.3,1) both}

@media (prefers-reduced-motion:reduce){
  *{transition:none !important}
  /* 움직임을 아예 없애지 않고 **자리 이동만** 없앤다 — 그래도 뭔가 바뀌었다는 신호는 남는다. */
  .fx-in,.fx-stagger>*,.crop-ov,.crop-modal{animation:fpdFade .01s linear both !important}
}


/* ── 표지 직접 올리기 ───────────────────────────────────────────────
   기본은 접어 둔다(대부분은 세트를 고른다). 슬롯은 사진 업로더와 같은 문법:
   미리보기 위에 올리면 '바꾸기'가 뜬다. */
.upcover{margin-top:16px;border:1px solid var(--border);border-radius:var(--rad-16);padding:16px 24px;background:var(--surface-2)}
.upcover>summary{cursor:pointer;font-weight:600;font-size:var(--fs-body-sm);color:var(--accent);list-style:none}
.upcover>summary::-webkit-details-marker{display:none}
.upcover>summary::before{content:'＋ ';font-weight:700}
.upcover[open]>summary::before{content:'－ '}
/* 속표지는 두 쪽(4394×2669)이라 앞·뒤와 같은 칸에 두면 납작하게 눌린다. 앞·뒤를 윗줄에
   1:1로, 속표지를 아랫줄 전체 폭으로 내려 길게 본다. */
.upgrid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px}
.upgrid .upslot.wide{grid-column:1 / -1}
@media (max-width:760px){.upgrid{grid-template-columns:1fr} .upgrid .upslot.wide{grid-column:auto}}
.upslot{border:1px solid var(--border);border-radius:12px;background:var(--canvas);overflow:hidden}
.upslot .uh{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;font-size:var(--fs-sub);font-weight:600;color:var(--ink)}
.upslot .uh em{font-style:normal;font-weight:500;color:var(--sub);font-size:var(--fs-micro);font-variant-numeric:tabular-nums}  /* 치수(2197×2669) 표시 — 숫자 자리맞춤 */
/* 액자(.uf)가 칸 가로를 꽉 채우고 세로는 판형 비율대로 늘어난다 — 미리보기는 "이만한 지면에
   이렇게 앉는다"를 보여 주는 것이 목적이라 실제 크기를 최대한 크게 보여 준다. 그래서 높이를
   고정하지 않는다 — 앞·뒤 표지는 폭×1.215, 속표지는 폭÷1.646으로 칸 높이가 스스로 정해진다.
   클릭 영역은 액자와 같아진다(칸 전체 = 액자). */
.upslot .ub{position:relative;width:100%;
  background:var(--canvas);display:flex;align-items:center;justify-content:center}
.upslot .uf{width:100%;background:var(--surface-2);border-radius:8px;overflow:hidden;
  display:flex;align-items:center;justify-content:center}
.upslot .ub img{width:100%;height:100%;object-fit:cover;display:block}
.upslot .ub .ph{color:var(--mute);font-size:13px;padding:0 10px;text-align:center}
.upslot .ov{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:8px;opacity:0;
  background:rgba(25,31,40,.55);color:#fff;font-size:var(--fs-sub);font-weight:600;transition:opacity .12s}
.upslot .ub:hover .ov,.upslot .ub:focus-within .ov{opacity:1}
.upslot input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
.upslot-actions{display:flex;gap:8px;margin:0 16px 12px}
.upslot-actions .btn{flex:1;min-width:0}

/* ── 올린 표지 자르기(crop) 모달 ─────────────────────────────────────
   진입 즉시 뜨는 모달이 아니라 파일을 고른 "결과"로 뜬다. 캔버스 흰 카드 + 1px 테두리, 그림자
   없음(프로젝트 공통 규칙). Esc로 닫힘 = 취소, 배경 스크롤은 열려 있는 동안 JS가
   documentElement.style.overflow로 막는다. */
.crop-ov{position:fixed;inset:0;z-index:100;background:rgba(25,31,40,.6);
  display:flex;align-items:center;justify-content:center;padding:16px}
.crop-modal{background:var(--surface);border:1px solid var(--border);border-radius:var(--rad-20);
  padding:24px;width:min(520px,100%);max-height:calc(100vh - 32px);overflow:auto}
.crop-modal:focus{outline:none}  /* 포커스는 모달 안으로만 옮기는 용도 — 링은 안의 버튼·슬라이더에서 보인다 */
.crop-title{font-size:var(--fs-h2);font-weight:800;margin:0 0 4px}
.crop-guide{font-size:var(--fs-sub);color:var(--sub);line-height:1.6;margin:0 0 16px}
/* 자리 안내 — 지면에서 글자가 얹히는 곳·잘려 나가는 곳을 그림 위에 겹쳐 보여 준다.
   끌기를 가로채면 안 되므로 pointer-events를 끈다. */
.crop-guide-box{position:absolute;box-sizing:border-box;border:2px dashed rgba(255,255,255,.9);
  background:rgba(20,28,45,.22);border-radius:6px;pointer-events:none;display:flex;align-items:flex-start;justify-content:center}
.crop-guide-box>span{font-size:11px;font-weight:700;color:#fff;background:rgba(20,28,45,.72);
  padding:2px 8px;border-radius:0 0 6px 6px;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.crop-stage{display:flex;justify-content:center;margin-bottom:16px}
.crop-frame{position:relative;overflow:hidden;border-radius:var(--rad-10);border:1px solid var(--border);
  background:var(--surface-2);touch-action:none;cursor:grab}
.crop-frame:active{cursor:grabbing}
.crop-img{position:absolute;left:0;top:0;max-width:none;user-select:none;-webkit-user-drag:none}
.crop-zoom{display:flex;align-items:center;gap:12px;margin-bottom:24px;min-height:44px}
.crop-zoom label{font-size:var(--fs-sub);font-weight:600;color:var(--ink);flex:none}
.crop-actions{display:flex;justify-content:flex-end;gap:8px;flex-wrap:wrap}
.crop-actions .btn{min-width:96px}

/* 확대·축소 슬라이더 — 시각 트랙은 가늘지만 히트 영역(input 박스 자체)은 44px를 채운다 */
.crop-zoom input[type=range]{-webkit-appearance:none;appearance:none;flex:1;height:44px;background:transparent;cursor:pointer}
.crop-zoom input[type=range]::-webkit-slider-runnable-track{height:4px;border-radius:99px;background:var(--border-input)}
.crop-zoom input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:20px;height:20px;
  border-radius:50%;background:var(--accent);border:3px solid #fff;margin-top:-8px}
.crop-zoom input[type=range]::-moz-range-track{height:4px;border-radius:99px;background:var(--border-input)}
.crop-zoom input[type=range]::-moz-range-thumb{width:20px;height:20px;border-radius:50%;background:var(--accent);border:3px solid #fff}
.crop-zoom input[type=range]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}


/* ── 만들기 화면 ───────────────────────────────────────────────────
   책마다 카드를 두지 않고 통합 진행바 하나 + 흐르는 로그 한 줄로 합쳤다.
   PDF 내려받기는 없다(html2canvas 래스터라 폰트·아이콘이 깨졌다). */
.bld{margin-top:24px}
.bld-bar{height:10px;border-radius:99px;background:var(--surface-2);overflow:hidden}
.bld-bar>i{display:block;height:100%;width:0;border-radius:99px;background:var(--accent);
  transition:width .45s cubic-bezier(.16,1,.3,1)}   /* 상단 진행 막대와 같은 곡선 */
.bld-pct{margin-top:8px;font-size:14px;font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums}
/* 로그 한 줄 — 내용이 바뀔 때 살짝 흐려졌다 다시 또렷해진다(AI 답변이 갈아 끼워지듯) */
.bld-log{margin-top:6px;min-height:22px;font-size:14px;color:var(--sub);
  opacity:1;transform:translateY(0);transition:opacity .14s ease, transform .14s ease}
.bld-log.out{opacity:0;transform:translateY(-4px)}

/* 다 만든 뒤에만 보이는 안내 — 미리 렌더하면 빈 여백을 예약한다 */
.done-box{margin-top:32px;padding:24px;border:1px solid var(--border);border-radius:var(--rad-16);
  background:var(--canvas)}
.done-box h2{font-size:20px;font-weight:700;color:var(--ink);margin:0 0 8px}
.done-box .lead{margin:0 0 16px}
.print-guide{display:block;width:100%;max-width:640px;margin:0 auto 24px;
  border:1px solid var(--border);border-radius:var(--rad-16)}
.print-links{display:grid;grid-template-columns:1fr 1fr;gap:8px}
@media (max-width:640px){.print-links{grid-template-columns:1fr}}
.print-btn{display:flex;flex-direction:column;align-items:flex-start;gap:4px;
  height:auto;min-height:56px;padding:8px 16px;text-align:left}
.print-btn .pl-t{font-size:15px;font-weight:600}
.print-btn .pl-d{font-size:13px;font-weight:400;opacity:.85;font-variant-numeric:tabular-nums}

/* 저장 버튼 — 중앙 정렬 + 왜 필요한지 한 줄 */
.save-wrap{margin-top:32px;padding-top:24px;border-top:1px solid var(--border);text-align:center}
.save-hint{margin:8px 0 0;font-size:13px;line-height:1.6;color:var(--sub)}

/* 전체 하단 연락처 */
.site-foot a{color:var(--accent);font-weight:600}


/* ── 하단 바 가운데 연락처 ───────────────────────────────────────────
   검증 메시지(navMsg)가 뜨면 연락처를 감춘다 — 같은 자리를 두고 다투지 않게. */
.navbar .in{display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:16px}
.nav-mid{min-width:0; display:flex; justify-content:center}
.nav-contact{display:flex; align-items:center; gap:10px; font-style:normal;
  font-size:12px; line-height:1.35; color:var(--sub); text-align:left}
.nav-contact .nc-k{font-weight:800; color:var(--ink); font-size:13px;
  padding-right:10px; border-right:1px solid var(--border)}
.nav-contact .nc-v{display:flex; flex-direction:column}
.nav-contact .nc-role{color:var(--sub)}
.nav-contact .nc-who{color:var(--ink); font-weight:600}
.nav-contact a{color:var(--accent); font-weight:600}
.navbar .msg:not(:empty)~.nav-contact{display:none}
@media (max-width:760px){ .nav-contact{display:none} }
