/* public/css/teacher-touch.css
 * 교사 화면 태블릿·터치 공용 레이어. **교사 트리 최초의 공용 스타일시트다.**
 *
 * 왜 있는가:
 *   교사 페이지는 로컬 스타일시트를 하나도 싣지 않고 페이지마다 인라인 <style>에
 *   전부 들어 있다(최대 829행). 터치 대응 한 벌을 9곳에 복붙하면 즉시 갈라진다 —
 *   --t-* 토큰이 17개 파일에 복붙돼 이미 값이 충돌한 것과 같은 경로다.
 *
 * ── 로드 위치 ────────────────────────────────────────────────────────────
 *   각 모듈의 </style> **뒤**, </head> 직전. 인라인 <style>과 링크된 파일은
 *   동률 특이도에서 **소스 순서**로 갈리므로, 모듈의 기존 규칙을 이기려면
 *   뒤에 와야 한다. 선례: speaking.html 이 report-components.css 를 </style>
 *   뒤에 싣는다(반대로 writing.html:16 은 앞에 두어 모듈이 이기게 한 의도적 배치).
 *
 * ── 이 파일에 넣지 않는 것 ───────────────────────────────────────────────
 *   ① --t-* 토큰. 값이 충돌한다 — --t-coral 은 #B4552F(home·management)와
 *      #FF7A55(speaking), --t-purple 은 #5C42D4(home)와 #7C3AED(10개 파일).
 *      게다가 grammar.html 이 정의하지 않은 --t-purple-* 와 --t-mint-* 를 읽어
 *      **현재 무효 선언**이라, 여기서 그 이름을 정의하면 꺼져 있던 배지가 켜진다.
 *      토큰 통합은 PC 를 바꾸는 작업이므로 별건으로만 한다.
 *   ② body 의 height/display/overflow/margin/padding. 이 파일이 인라인 뒤에
 *      오므로, 무조건 선언하면 모듈의 @media print 리셋보다 나중이 되어 동률
 *      속성을 이기고 워크시트 인쇄를 깨뜨린다.
 *   ③ @media print. 인쇄는 각 모듈이 자기 파일에서만 다룬다.
 *
 * ── 예외로 들어온 컴포넌트 ───────────────────────────────────────────────
 *   워크시트 인쇄 / 회원 전송 버튼(아래). 원래 터치 레이어 전용 파일이지만,
 *   그 두 버튼이 다섯 파일에 복붙된 채 서로 갈라진 것이 실제 결함으로 드러나
 *   (활성/비활성 크기 차이·인쇄와 전송의 아랫변 불일치·speaking 만 2px 작음)
 *   한 곳으로 모았다. ①의 예외가 아니다 — **색은 여기서 정의하지 않고**
 *   각 모듈이 --btn-accent / --btn-accent-dark 두 개로 넘긴다.
 *
 * ── ★ 미디어 쿼리 규칙 ───────────────────────────────────────────────────
 *   폭·높이 쿼리는 반드시 `screen and (...)`. A4 인쇄 페이지 박스는
 *   210mm − 여백 30mm = 180mm = **680px** 이라, screen 한정이 없으면 max-width
 *   쿼리가 인쇄 중에 참이 된다. (저장소에 이미 그 버그가 있다:
 *   css/writing-maps.css:319,325,356 — 학생 인쇄 맵이 항상 축소된다.)
 *   `hover`/`pointer` 는 폭이 아니므로 이 제약과 무관하다.
 *
 * ── 왜 폭이 아니라 pointer 로 분기하는가 ─────────────────────────────────
 *   모듈은 iframe 안에서 돌고, iframe 안의 폭 쿼리는 **iframe 박스** 기준이다.
 *   그래서 `min-width:1024px` 는 iPad 에서 영원히 참이 되지 않는다. 반면
 *   hover/pointer 같은 입력 미디어 특성은 UA 수준이라 프레임을 관통해 실제
 *   기기를 알려준다. 기기 폭 판단은 최상위인 dashboard.html 에서만 한다.
 */

/* ══ 무조건 적용 (PC 무영향) ══════════════════════════════════════════════ */

/* 넓은 표를 감싸는 가로 스크롤러. 내용이 들어가면 스크롤바가 나타나지 않으므로
   브레이크포인트가 필요 없다. 표 자동 레이아웃이 열을 짜부라뜨리는 것보다
   가로로 미는 것이 낫다. */
[data-t-scroll] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;   /* iOS 관성 스크롤 */
    overscroll-behavior-x: contain;      /* 끝에서 셸로 제스처가 전파되지 않게 */
}

/* WebKit 텍스트 자동 확대(폰트 부스팅) 차단. 저장소에 이 선언이 0건이었다.
   ②의 예외인 이유: 인쇄 리셋이 건드리는 속성이 아니라 충돌할 수 없다. */
html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

/* ══ 워크시트 인쇄 / 회원 전송 ═══════════════════════════════════════════
 * .btn-common 은 voca·sentence·grammar·writing·speaking **다섯 곳에서만** 쓰인다
 * (dashboard·home·magic·management·teacher 에는 없다). 이 파일은 그 다섯 곳 모두에
 * 인라인 <style> 뒤에 링크되므로 동률 특이도(0,1,0)를 소스 순서로 이긴다.
 *
 * ★ 왜 명시 높이를 주는가 — 다섯 파일 모두 *{box-sizing:border-box} 인데도
 *   테두리가 크기를 바꿨다. box-sizing 은 **명시적 width/height 가 있을 때만**
 *   의미가 있고, 높이 auto 상자에서는 테두리가 언제나 바깥으로 더해진다.
 *   그래서 테두리 있는 인쇄(37px)와 없는 전송이 어긋났고, speaking 은 아이콘이
 *   인라인 SVG(15px)라 FontAwesome(라인박스 17px)인 다른 모듈보다 2px 작았다.
 *   height 를 박으면 네 조합(인쇄/전송 × 활성/비활성)이 기하적으로 같아진다.
 *
 * ★ box-shadow 를 끄는 이유 — 전송 버튼의 `0 2px 0` 밑단은 상자 **밖으로**
 *   2px 뻗는데 :disabled 는 none 이었다. 그래서 활성화될 때마다 시각 높이가
 *   37 → 39px 로 커져 옆 인쇄 버튼과 아랫변이 어긋났다. 평면 + 눌림으로 간다.
 *
 * 크기·모양은 .btn-print/.btn-assign 에만 준다. .btn-ai·.btn-ghost·.wv2-* 도
 * .btn-common 을 쓰지만 맥락이 다른 보조 컨트롤이라 건드리지 않는다.
 * ═════════════════════════════════════════════════════════════════════════ */
.btn-print,
.btn-assign {
    height: 36px;
    padding: 0 14px;
    border-radius: 9px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    line-height: 1;
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    /* 높이를 36px 로 박았으므로 줄바꿈을 허용하면 글자가 상자를 넘는다.
       좁은 폭(실측 500px)에서 「워크시트 인쇄」가 두 줄로 감겨 넘쳤다. */
    white-space: nowrap;
    cursor: pointer;
    box-shadow: none;
    transition: background .12s, border-color .12s, color .12s, transform .08s;
}

/* 보조 — 흰 바탕 + 테두리 */
.btn-print {
    background: var(--t-surface);
    border: 1px solid var(--t-border);
    color: var(--t-ink-2);
}
.btn-print:hover:not(:disabled) {
    background: var(--t-bg);
    border-color: var(--t-border-2);
}

/* 주 — 모듈 강조색 단색. 배경과 같은 색 1px 테두리를 두어 인쇄 버튼과
   border-box 기하를 완전히 같게 만든다(내용상자 폭·글자 기준선까지). */
.btn-assign {
    background: var(--btn-accent);
    border: 1px solid var(--btn-accent);
    color: #fff;
}
.btn-assign:hover:not(:disabled) {
    background: var(--btn-accent-dark);
    border-color: var(--btn-accent-dark);
}

/* 눌림은 transform 만 — 레이아웃에 영향이 없다 */
.btn-print:active:not(:disabled),
.btn-assign:active:not(:disabled) { transform: translateY(1px); }

/* 비활성 — 크기를 바꾸는 속성은 하나도 건드리지 않는다 */
.btn-print:disabled,
.btn-assign:disabled {
    background: #EFEFEA;
    border-color: #E5E5DF;
    color: var(--t-mute);
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
}

/* ══ 터치 기기 (마우스가 없다) ════════════════════════════════════════════ */
@media (pointer: coarse) {

    /* ★ iOS Safari 는 font-size 가 16px 미만인 입력에 포커스가 가면 페이지를
       확대한다. 이 앱의 폼 컨트롤은 전부 12~14px 이고, iframe 안 입력이어도
       **최상위 뷰포트가** 확대된다. dashboard.html 은 overflow:hidden 이라
       스크롤로 되돌릴 수도 없다. 16px 이 유일한 해법이다(maximum-scale 로는
       막을 수 없고 접근성만 해친다).

       ★★ 특이도 주의 — 처음에 `input, select, textarea` 로 썼다가 **한 개도
          적용되지 않았다.** 그 선택자는 (0,0,1) 인데 이 앱의 컨트롤은 전부
          클래스로 스타일된다 — .form-control·.form-input-modal (0,1,0),
          .sets-toolbar .form-control (0,2,0), .student-select (0,1,0) …
          소스 순서는 **동률일 때만** 의미가 있으므로 클래스가 항상 이겼다.
          실측 결과 7개 모듈 텍스트 입력 53개가 전부 16px 미만으로 남아 있었다.

          `:not()` 은 인자의 특이도를 더하므로 아래는 (0,2,1) 이 되어 클래스
          규칙을 이긴다. 그리고 같은 장치로 checkbox/radio 를 제외한다 —
          그건 확대 대상이 아니고, 키우면 겉모습이 바뀐다.
          ※ 이 목록을 손볼 때 특이도가 (0,1,0) 이하로 내려가면 규칙 전체가
            다시 조용히 죽는다. 화면상 아무 변화가 없으므로 눈으로는 못 잡는다. */
    input:not([type="checkbox"]):not([type="radio"]),
    select:not([multiple]):not([size]),
    textarea:not([disabled]) {
        font-size: 16px;
    }

    /* 탭 하이라이트·더블탭 확대 지연 제거. 선례: css/global.css, css/sentence.css */
    * { -webkit-tap-highlight-color: transparent; }
    button, [onclick], [role="button"], label { touch-action: manipulation; }

    /* ★ 소프트 키보드가 고정 모달의 푸터를 가리는 문제.
       가로 iPad 에서 키보드가 ~270px 을 먹지만 100vh·height:100% 는 줄지 않아,
       배포/인쇄 버튼이 키보드 아래로 들어가 닿지 않는다. 오버레이도 셸도
       스크롤되지 않으므로 복구 수단이 없다.
       중앙 정렬을 위쪽 정렬로 바꾸고 **오버레이 자체를 스크롤러로** 만들면
       브라우저의 scroll-into-view 가 동작해 visualViewport 배선 없이 해결된다.
       클래스 선택자를 공용 파일에 두는 예외 — 8개 파일의 기존 마크업을 건드리지
       않고 닿을 방법이 이것뿐이고, coarse 한정이라 PC 는 이 규칙을 보지 않는다. */
    .modal-overlay {
        align-items: flex-start;
        overflow-y: auto;
        padding-block: 16px;
    }
    .modal-box {
        /* 위쪽 정렬로 바뀌었으니 높이 캡을 풀어 오버레이가 스크롤을 맡는다 */
        max-height: none;
    }

    /* 내부 스크롤러 끝에서 제스처가 최상위로 전파되면 셸 전체가 고무줄처럼 튄다.
       선례: css/report-shell.css 가 같은 짝을 쓴다.
       ★ 휴대폰에서 패널을 한 줄로 쌓고 문서가 스크롤하게 바꿀 때(height:auto·max-height:none), 이 목록의
         상자는 **overflow 도 visible 로** 빼야 한다. contain 은 스크롤할 내용이 없는 스크롤 상자에도 걸려
         그 안에서 시작한 세로 스와이프가 페이지로 넘어가지 않는다(2026-10-14 매직 리포트·대시보드·
         Writing·Speaking 피드백·Grammar 세트 목록, 실측 0px). */
    .preview-content-scroll, .sets-grid, .pm-body, .pm-side,
    .card-body, .fb-list, .fb-list-panel, .fb-detail, .fb-detail-panel,
    .student-list, .sp-host, .nav-panel, .content-area, .preview-scroll,
    /* ★ Voca·Sentence 의 **실제** 스크롤러가 빠져 있었다. .nav-panel 은 낮은 박스에서만
       스크롤러가 되고, 평상시 스크롤을 맡는 것은 아래 세 개다. 이 목록에 없으면
       제스처가 스크롤 불가능한 조상으로 전파되고 iOS 관성 스크롤도 안 걸린다. */
    .chapter-list, .word-grid, .sentence-list {
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
    }
}

/* ══ 스티키 hover 억제 ════════════════════════════════════════════════════
 * iOS·안드로이드는 탭한 요소에 :hover 를 적용하고 **다음 탭까지 유지한다.**
 * 저장소에 hover/pointer 기능 쿼리가 0건이라 대비가 전혀 없었다.
 *
 * 왜 `@media (hover: hover)` 로 기존 규칙을 감싸지 않는가:
 *   그건 PC 규칙을 조건문 안으로 **옮기는** 것이라, 기능 쿼리를 모르는
 *   브라우저에서 hover 스타일이 통째로 사라진다. 실질 위험은 거의 없지만
 *   "PC 에 이론적 위험도 지지 않는다"가 이 작업의 요구사항이다. 그래서
 *   값을 **되돌리는** 형태로 쓴다 — coarse 한정이라 PC 는 이 블록을 못 본다.
 *
 * 특이도 주의:
 *   ① 선택 상태를 이기면 안 된다. 이 파일이 인라인 뒤에 오므로 동률이면
 *      hover 가 .selected/.active 를 이겨 **무엇을 골랐는지 사라진다.**
 *      그래서 :not(.selected)/:not(.active) 로 대상에서 뺀다.
 *   ② 런타임 주입 <style>(teacher-students.js·grading-queue.js)은 head 에
 *      마지막으로 붙어 이 파일보다 나중이다. 동률로는 못 이기므로 부모를
 *      한 단계 더 써서 특이도를 올린다(!important 를 쓰지 않는 이유).
 * ═════════════════════════════════════════════════════════════════════════ */
@media (hover: none) {

    /* Voca — 선택과 hover 가 같은 선언이었다(둘 다 border-color:--t-purple).
       체크 원(.wc-check-ui)이 상태를 이미 구분해 주므로 hover 만 지운다. */
    .word-card:hover:not(.selected) { border-color: var(--t-border); }

    /* 과제 관리 — 행 잔상 + 정렬 가능 표시가 hover 뿐이었다(아래 ↕ 상시 표시로 보완) */
    .data-table thead th:hover      { color: var(--t-sub); }
    .data-table tbody tr:hover td   { background: transparent; }

    /* 매직 리포트 관리 표 */
    .manage-table tr:hover td       { background: transparent; }

    /* Grammar — 카드가 2px 떠 있는 채로 굳는다 */
    .set-card:hover { transform: none; box-shadow: var(--t-shadow-card); }
    /* hover 로만 드러나던 칩 삭제 X. 터치에서는 .6 으로 고정돼 비활성처럼 보였다 */
    .chip-remove { opacity: 1; }

    /* Voca 와 같은 모양인데 지난번에 빠진 형제들 —
       .chapter-item 은 **다중 선택**이라 더 나쁘다. 탭했다 만 챕터가 보라 테두리를
       유지하면 "지금 무엇을 보낼 건가"가 두 개로 읽힌다. */
    .chapter-item:hover:not(.active)    { border-color: var(--t-border); }
    .sentence-card:hover:not(.selected) { border-color: var(--t-border); }

    /* .sub-item 은 두 파일이 같은 이름을 다르게 쓴다 — 되돌릴 값도 다르다.
         speaking: 기본 border 가 transparent, hover 는 background 를 바꾼다
         writing : 기본 border 가 --t-border, hover 는 **border-color** 를 바꾼다
       그래서 하나의 리셋 값으로는 둘 중 하나가 반드시 틀린다(transparent 로
       통일하면 writing 의 테두리가 사라진다). 부모로 갈라서 각각 제 값으로
       되돌린다 — writing 은 .fb-list-panel, speaking 은 .fb-list 안에 있다. */
    .fb-list-panel .sub-item:hover:not(.active) { border-color: var(--t-border); }
    .fb-list .sub-item:hover:not(.active)       { background: transparent; }

    /* .set-card 와 같은 들뜸인데 z-index:10 까지 굳어 이웃 카드를 덮는다 */
    .q-card:hover { transform: none; box-shadow: var(--t-shadow-card); z-index: auto; }

    /* 교사 메뉴(dashboard) — 탭한 메뉴에 hover 배경이 남아 두 메뉴가 골라진 것처럼 보인다.
       선택 표시는 .active 가 따로 하므로 뺀다. */
    .t-nav-item:hover:not(.active)  { background: transparent; }
    .t-logout .t-nav-item:hover,
    .t-logout .t-manual:hover       { background: transparent; }

    /* 런타임 주입 스타일보다 나중이라 부모를 한 단계 더 쓴다 */
    .sp-body .sp-row:hover  { background: transparent; }
    .gq-list .gq-row:hover  { background: #fff; border-color: #ECECE6; }
}

/* ══ 터치 타겟 ════════════════════════════════════════════════════════════
 * 손가락 기준 44×44 를 목표로 한다. 전부 coarse 한정이라 PC 치수는 그대로다.
 *
 * 두 패턴을 쓰고, 고르는 기준이 있다:
 *   (A) ::after{inset:-8px} 로 히트 영역만 넓힌다 — 겉보기 크기를 지켜야 하는
 *       고립된 아이콘 버튼용. **부모가 overflow:hidden 이면 잘리고**, 인접
 *       컨트롤과 16px 이내면 확장 영역이 겹쳐 나중 요소가 탭을 가로챈다.
 *       그래서 .fs-stepper(overflow:hidden)와 나란한 버튼 쌍에는 못 쓴다.
 *   (B) min-height/min-width 로 실제로 키운다 — 행·라벨·붙어 있는 묶음용.
 *
 * 체크박스는 이미 <label> 래퍼가 히트 영역이므로 라벨만 키운다. 15px 박스를
 * 건드리면 PC 겉보기가 바뀐다.
 * ═════════════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) {

    /* 1) 학생 선택기 행 — 6개 모듈의 배포 흐름마다 닿는, 앱에서 가장 많이
          눌리는 컨트롤이다. 33px → 44px. (B) */
    .sp-body .sp-row { min-height: 44px; }

    /* 2) 모듈 탭·서브내비 — 35px 내외. (B)
       .fb-tab(speaking 38.5px)·.wv2-tab(writing 36px)이 빠져 있었다.
       .m-tab 은 마크업이 없는 죽은 선택자라 뺐다(writing.html 의 탭은 .sub-btn). */
    .g-tab, .sub-btn, .tab-btn, .main-tabs .tab, .fb-tab, .wv2-tab {
        min-height: 44px;
    }

    /* 3) 아이콘 버튼(수정·삭제) — 원래 30×30 에 간격 8px.
          오탐하면 문항이 즉시 삭제된다(deleteBankItem 에 확인 절차가 없다).
          확인창을 붙이는 대신 **오탐 자체를 줄이는** 쪽을 택했다 — 이 목록은
          세트를 다듬는 동안 연속으로 지우는 것이 정상 작업이라, 확인창은
          PC 대량 편집에 마찰만 준다. 권장 44 까지 올린다. (B) */
    .btn-icon { min-width: 44px; min-height: 44px; }
    .q-bank-header { gap: 12px; }

    /* 4) 행 안에 늘어선 작은 버튼들.
          magic 관리 탭은 행마다 5개(보기·수정·재전송·인쇄·삭제)라 44 로 키우면
          행 높이가 크게 뛴다. 36 으로 타협한다 — 행 자체가 이미 높아 실질
          히트 영역은 그보다 크다. management 의 .btn-sm 도 같은 이름이라
          함께 커진다(삭제는 confirm 이 이미 막아 준다). */
    .btn-sm { min-height: 36px; }
    .preset-btn { min-height: 40px; }

    /* 5) 고립된 파괴적·정밀 버튼은 권장치까지 올린다. */
    .imp-row .rm  { min-width: 44px; min-height: 44px; }
    .wv2-del      { min-height: 44px; }

    /* 6) 모달 닫기 — 헤더 모서리에 고립돼 있어 (A)가 안전하다 */
    .modal-close-btn, .close-btn { position: relative; }
    .modal-close-btn::after, .close-btn::after {
        content: ''; position: absolute; inset: -10px;
    }

    /* 7) 폰트 크기 스테퍼 — 부모 .fs-stepper 가 overflow:hidden 이라 (A) 불가. (B) */
    .fs-stepper button { min-width: 44px; min-height: 40px; }
    .fs-stepper span, .fs-stepper #fs-indicator { min-width: 40px; }

    /* 8) 체크박스 라벨 — 박스가 아니라 라벨을 키운다 */
    .type-checkbox-item, .pm-chk, .pm-check, .pm-answer, .toggle-label {
        min-height: 44px;
    }
}

/* ══ 좁은 폭·낮은 화면 (휴대폰) ══════════════════════════════════════════
 * 2026-10-02 휴대폰 개선. 셸(dashboard)이 휴대폰 세로에서 레일을 없애 모듈 iframe 이
 * 기기 폭 전체(360~430px)가 된 뒤에도 남는 문제만 고친다. 조건은 **iframe 상자** 기준이다
 * (여기는 모듈 안이다 — 기기 판단은 셸이 한다):
 *   좁음 = screen and (max-width: 559px)                             휴대폰 세로
 *   낮음 = screen and (max-height: 500px) and (orientation: landscape) 휴대폰 가로
 * ★ 갈래마다 screen. 인쇄 박스 680×1009 에서는 둘 다 거짓이다(559 < 680, 가로가 아님).
 * ★ 이 파일은 home·management·magic·issues·center 도 싣는다. 같은 클래스가 다른 뜻으로 있을 수
 *   있어 모듈 전용 부모(#assign-modal — 5개 모듈에만 있다)나 모듈에만 있는 클래스(.header-sub)로 좁힌다.
 * ═════════════════════════════════════════════════════════════════════════ */
@media screen and (max-width: 559px) {

    /* 전송 창(5개 모듈 공통 #assign-modal). 390px 기기에서 창 안쪽이 310px 남짓이라
       제목 칸이 마감일(170px)에 밀려 120px 로 줄고, 버튼 셋이 한 줄에 끼어
       [학습활동 미리보기]가 3줄로 꺾였다(실측). */
    #assign-modal { padding-inline: 10px; }
    #assign-modal .modal-box { padding: 18px 16px; }
    /* 제목 / 마감일을 두 줄로. 마감일 칸 폭은 마크업 인라인(width:170px)이라 min-width 로 넓힌다
       (!important 없이 인라인 width 를 이기는 방법). */
    #assign-modal .field-row { flex-direction: column; gap: 10px; }
    #assign-modal .field-row > * { min-width: 100%; }
    /* [취소][학습활동 미리보기] / [전송하기] 두 줄. 순서는 그대로 두어 주 버튼이 엄지 쪽(아래)에 온다.
       ※ 학습 단계 4칸(.option-grid)은 2×2 그대로 둔다(사용자 결정, 2026-10-02 assign-modal-compact) —
         대신 창 안쪽 여백을 24 → 16px 로 줄여 칸 폭을 넓혔다. */
    #assign-modal .modal-actions { flex-wrap: wrap; gap: 8px; }
    #assign-modal .modal-actions > button { margin-right: 0; }
    #assign-modal .modal-actions .btn-close   { flex: 0 0 auto; }   /* 글자 폭만 — 남는 폭은 미리보기가 쓴다 */
    #assign-modal .modal-actions .btn-preview { flex: 1 1 0; }
    #assign-modal .modal-actions .btn-confirm { flex: 1 0 100%; }
}

@media screen and (max-width: 559px),
       screen and (max-height: 500px) and (orientation: landscape) {
    /* 모듈 머리의 설명 문구(5개 모듈에만 있다) — 좁거나 낮으면 모듈 이름만 남긴다 */
    .page-header .header-sub { display: none; }
}
