/* ============================================================
   교실 화면 (ROADMAP 「자」 만들기 ③ — 운영 사이트 exam/class.html 을 앱으로 옮긴 것)

   ## 옛 판에서 그대로 가져온 것

   모양·크기·색은 **거의 손대지 않았다.** 이 화면은 2026-06 부터 네 번의 시험을
   교실 스마트칠판에서 견뎌 낸 배치이고, 1920 실측으로 칸 폭을 맞춘 자리가 여럿
   있다 (아래 `.vacant-label` 주석). 옮기면서 예쁘게 고칠 자리가 아니다.

   ## 🔴 칠판은 **4K(UHD 3840×2160) · 16:9** 다 — 그래도 1920 에서 재는 것이 맞다

   진님 확인 (2026-09-20). 그런데 **1920 으로 검증해도 된다.** 아래 `html` 의
   `font-size: 1.1vw` 가 글자 기준(`1rem`)을 **화면 폭에 묶어** 두기 때문이다 —
   폭이 두 배면 글자도 칸도 두 배가 되어 **비율이 같으면 똑같이 그려진다.**
   칸 폭도 전부 `%` · `fr` 이라 같이 늘어난다. 「1920 실측」은 그래서
   **「16:9 에서 실측」이라는 뜻**이다. 폭 숫자가 아니라 **비율**이 조건이다.

   ⚠️ **안 커지는 것 둘.**
     1. `px` 로 굳은 값 — `padding: 5px`(`.stat-cell input` · `.info-box td`) ·
        `padding: 8px 5px`(`.info-title`) · `margin-right: 6px`(`.vacant-label`) ·
        `padding: 10px`(`.info-content`) · 테두리 · `border-radius`.
        4K 에서는 **상대적으로 절반**이 되어 글자가 칸 벽에 조금 더 붙는다.
        보기 문제일 뿐 깨지지 않는다. **새로 더하는 여백은 `rem` 으로 적는다.**
     2. **세로.** `1.1vw` 는 **폭만** 본다. 전체화면이 아니어서 세로만 짧아지면
        (작업표시줄 · 주소줄) 내용이 그 높이보다 커진다 — `overflow: hidden` 이
        말없이 자른다. 교2 의 전체화면 단추가 중요한 이유가 이것이다.

   ## 늘어난 것 하나 — **띠(`#banner`) 가 넷을 겸한다**

   옛 판에는 `#stale-banner` 하나에 「화면이 오래됐습니다」와 「본부 요청 새로고침」
   둘이 들어 있었다. 여기에 둘이 더 붙는다 ([D68] ⑧):

     · 저장이 연달아 실패한다   → 옛 판은 `catch (e) {}` 로 **아무 말도 안 했다**
     · 시험 기간이 아니라 거절됐다 → [D66] 완화 ③. 말없이 안 되는 것이 가장 나쁘다

   띠를 넷으로 나누지 않은 이유는 옛 판의 이유와 같다 — **교실 화면에 띠가 여럿
   겹치면 정작 급한 것을 가린다.** 색으로 가른다.
   ============================================================ */

html { font-size: 1.1vw; }
* { box-sizing: border-box; }
body {
    margin: 0; padding: 1.5rem; background-color: #f4f7f6;
    font-family: 'Malgun Gothic', sans-serif;
    height: 100vh; display: flex; flex-direction: column;
    overflow: hidden; position: relative;
}

.top-bar {
    display: flex; justify-content: space-between; align-items: center;
    background-color: white; padding: 0.8rem 1.5rem; margin-bottom: 1rem;
    border-radius: 12px; box-shadow: 0 4px 10px rgba(0,0,0,0.05);
}
.class-tag {
    background-color: #1a237e; color: white; padding: 0.6rem 1.5rem;
    border-radius: 50px; font-size: 1.8rem; font-weight: bold;
    box-shadow: 0 2px 5px rgba(0,0,0,0.2); white-space: nowrap;
    cursor: pointer; text-decoration: none;
}
.class-tag:hover { background-color: #283593; }
.main-title { flex: 1; text-align: center; font-size: 2.4rem; font-weight: 800; color: #1a237e; outline: none; margin: 0 1rem; }
.fullscreen-btn { padding: 0.6rem 1.2rem; background-color: #f5f5f5; color: #1a237e; border: 1px solid #1a237e; border-radius: 8px; font-size: 1.1rem; font-weight: bold; cursor: pointer; white-space: nowrap; }

/* 맨 위 띠의 홈 · 로그인/로그아웃 (`partials/topbar-buttons.blade.php`).

   ⚠️ **크기를 여기서 되돌린다.** 그 파일의 기본 크기는 14px 로 굳어 있는데, 이
      화면은 `html { font-size: 1.1vw }` 라 칠판 크기에 맞춰 전부 커진다. 그대로
      두면 옆의 「전체화면」(1.1rem ≒ 23px @1920)만 크고 이 둘만 깨알같이 작다.
      **크기를 정하는 자리가 이 화면에서는 여기다** — 위 `.fullscreen-btn` 과 같이 본다. */
.top-bar .app-topbar__btn { padding: 0.6rem 1.2rem; font-size: 1.1rem; border-radius: 8px; }
.top-bar .app-topbar__logout { margin-left: 0.6rem; }

.container { flex: 1; display: grid; grid-template-columns: 5fr 5fr; gap: 1.5rem; min-height: 0; overflow: hidden; }
.card { background: white; border-radius: 15px; box-shadow: 0 8px 20px rgba(0,0,0,0.08); display: flex; flex-direction: column; overflow: hidden; border: 1px solid #e0e6ed; }

table { width: 100%; height: 100%; border-collapse: collapse; table-layout: fixed; }
th, td { border: 1px solid #edf2f7; text-align: center; padding: 0.5rem; outline: none; }
th { background-color: #3949ab; color: white; font-size: 1.8rem; height: 10%; }

/* 시험 날 4칸 모드 (기본) */
th:nth-child(1) { width: 12%; }
th:nth-child(2) { width: 25%; }
th:nth-child(3) { width: 15%; }
th:nth-child(4) { width: 40%; }

/* 평소 날 2칸 모드 */
#exam-schedule.mode-default th:nth-child(1) { width: 20%; }
#exam-schedule.mode-default th:nth-child(2) { width: 80%; }

td { font-size: 2.1rem; font-weight: 800; word-break: keep-all; overflow: hidden; height: 1px; line-height: 1.2; vertical-align: middle; }
.current-period { background-color: #fff9c4 !important; }

/* [D119] 비상용 빈 시간표 — 본부가 아직 안 적은 과목 칸. 빈칸이면 표가 깨진 것처럼 보여 흐린 「—」. */
td.subject-empty { color: #c5cbd6; font-weight: 600; }

/* 로그인한 부관리자 이상이 연 화면에서는 과목 칸이 입력 칸이다. 칸을 통째로 채워 누르는 자리를 넓게. */
td.subject-cell { padding: 0; }
.subject-input {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    border: 0;
    background: #f5f7ff;
    font: inherit;
    color: inherit;
    text-align: center;
    padding: 0.5rem;
}
.subject-input::placeholder { color: #b0b8c4; font-weight: 600; font-size: 0.7em; }
.subject-input:focus { outline: 3px solid #5c6bc0; outline-offset: -3px; background: #fff; }
.current-period .subject-input { background: transparent; }

.right-layout { display: flex; flex-direction: column; gap: 1.5rem; min-height: 0; overflow: hidden; }
.clock-container { flex: 6; background: #ffffff; display: flex; flex-direction: column; align-items: center; justify-content: center; border: 2px solid #000; position: relative; min-height: 0; overflow: hidden; }
.digital-clock { font-size: min(9vw, 15vh); font-family: 'Courier New', monospace; font-weight: 900; letter-spacing: -2px; }

/* 본부 호출 종류 고르기 (2026-09-03). 버튼을 셋으로 늘리는 대신 팝업으로 띄운다 —
   시계 카드 아래가 좁고, 버튼이 늘면 잘못 누를 일도 는다. */
.call-pop-bg { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 9000; align-items: center; justify-content: center; }
.call-pop-bg.show { display: flex; }
.call-pop { background: #fff; border-radius: 14px; padding: 22px 24px; min-width: 320px; text-align: center; box-shadow: 0 10px 30px rgba(0,0,0,0.35); }
.call-pop h3 { margin: 0 0 14px; font-size: 1.3rem; }

/* 버튼을 셋 다 빨강으로 두면 눈이 아프고, 무엇이 무엇인지 색으로 가려지지 않는다.
   종류별 색을 **연한 바탕 + 왼쪽 굵은 띠 + 진한 글씨**로 쓴다. */
.call-pop .opt {
    display: flex; align-items: center; gap: 12px; width: 100%; margin: 10px 0;
    padding: 0.95rem 1rem; font-size: 1.15rem; font-weight: bold;
    border: 2px solid currentColor; border-left-width: 10px; border-radius: 10px;
    background: #fff; cursor: pointer; text-align: left; transition: background 0.15s;
}
.call-pop .opt:hover { background: #f3f4f6; }
.call-pop .opt:focus-visible { outline: 3px solid #111; outline-offset: 2px; }
.call-pop .cancel { display: block; width: 100%; margin-top: 14px; padding: 0.7rem; font-size: 1rem; border: none; border-radius: 10px; background: #eceff1; color: #37474f; cursor: pointer; }

/* ↻ 새로고침 · 전체화면 (진님 요청 2026-09-10). 머리줄에서 시계 카드 안으로 내려왔다.

   ⚠️ **`.call-btn` 과 같은 카드 안에서 자리를 나눠 쓴다** — 호출은 오른쪽 아래,
      이 둘은 오른쪽 위다. 겹치지 않게 둘 다 `position: absolute` 로 모서리에 건다.
      시계(`.digital-clock`)는 카드 가운데에 `justify-content: center` 로 서 있으므로
      이 둘이 자리를 차지해도 시계가 안 밀린다. */
.clock-tools { position: absolute; top: 10px; right: 10px; display: flex; align-items: center; gap: 0.5rem; z-index: 1; }

/* 머리줄에 있을 때 옆 단추와 띄우려고 붙여 둔 것이다. 이제 `gap` 이 그 일을 한다. */
.clock-tools .reload-link { margin-right: 0; }

/* ⛶ **새로고침 뒤 전체화면으로 돌아가기** (ROADMAP 2-A 교2 · 진님이 이 모양을 골랐다).

   🔴 **흐름 밖에 떠 있다 (`position: fixed`).** 이 화면은 `body` 가 세로 flex 라
      줄을 하나 더 두면 1920 으로 맞춰 둔 표 높이가 그만큼 눌린다 (띠 `#banner` 가
      실제로 그렇게 눌러 준다 — 그것은 사고를 알리는 값이라 받아들인 것이다).
      전체화면 복귀는 **사고가 아니라 편의**라 표를 줄일 값이 없다.

   ⚠️ **띠(`#banner`) 를 다섯째로 늘리지 않았다.** 띠는 **순위로 하나만** 보이는데
      (`class.js` 의 `BANNERS`), 「연결이 끊겼습니다」(50)가 떠 있는 동안 전체화면
      단추가 순위에 밀려 사라지면 **돌아갈 길이 없어진다.** 자리가 달라야 한다.

   ⚠️ 띠 전체가 아래 응시현황 위를 가로로 덮으므로 `pointer-events: none` 이다 —
      단추 둘만 `auto` 로 되살린다. 그러지 않으면 **결시 칸을 눌러도 안 먹는다.**

   `z-index` 는 호출 팝업(`.call-pop-bg`, 9000)보다 낮다. 호출 고르기가 떠 있으면
   그쪽이 위다 — 시험 중에 급한 쪽은 호출이다. */
#fs-return {
    display: none; position: fixed; left: 0; right: 0; bottom: 1.8rem; z-index: 50;
    align-items: center; justify-content: center; pointer-events: none;
}
#fs-return.show { display: flex; }
#fs-return button { pointer-events: auto; font-family: inherit; cursor: pointer; }

/* 큰 단추와 ✕ 를 **한 덩어리**로 묶는다 — ✕ 를 모서리에 겹치려면 기준이 필요하다. */
.fs-return-group { position: relative; }

.fs-return-btn {
    padding: 1rem 2.6rem; background-color: #1a237e; color: #fff;
    border: none; border-radius: 14px; font-size: 1.9rem; font-weight: 800;
    box-shadow: 0 6px 18px rgba(0,0,0,0.3);
}

/* 브라우저가 전체화면을 거절했다 (교12). **말없이 안 되는 것이 가장 나쁘다** —
   단추가 그 자리에서 이유를 말하고, 그대로 다시 누를 수 있게 남는다.

   ⚠️ **폭을 묶는다.** 글이 길어 평소보다 넓어지는데, 1920 실측으로 그대로 두면
      응시현황의 **결번 칸까지 덮어** 그 칸을 누를 수 없게 된다 (2026-09-19 미리보기에서
      쟀다). 넘치면 두 줄로 내려가고 단추는 **위로** 자란다 — 위쪽은 전달사항이라
      적는 칸이 없다. */
.fs-return-btn.failed {
    background-color: #ef6c00; font-size: 1.5rem;
    max-width: 26rem; white-space: normal; line-height: 1.3;
}

/* 닫기. 🔴 **큰 단추의 오른쪽 위 모서리에 겹쳐 둔다** (진님 2026-09-19).

   처음에는 화면 오른쪽 끝에 따로 뒀다 — *"너무 구석에 숨어 있다"* 였다. 칠판은
   터치라 **툴팁이 안 뜨므로** 닫는 단추라는 것이 모양만으로 읽혀야 한다. 둥근 ✕ 가
   단추 모서리에 걸쳐 있는 모양은 「이것을 누르면 닫힌다」로 바로 읽힌다.

   ⚠️ 칠판에서 손가락으로 누르는 것이라 **작게 만들지 않는다** — 2.8rem ≒ 59px @1920. */
.fs-return-close {
    position: absolute; top: -0.9rem; right: -0.9rem;
    width: 2.8rem; height: 2.8rem; padding: 0; border-radius: 50%;
    background-color: #fff; color: #1a237e; border: 3px solid #1a237e;
    font-size: 1.4rem; font-weight: 800; line-height: 1;
    box-shadow: 0 3px 8px rgba(0,0,0,0.3);
}

/* 거절일 때는 단추가 주황이므로 ✕ 도 그 색을 따라간다 — 남색 테두리만 남으면
   어느 단추에 붙은 것인지 읽히지 않는다. */
.fs-return-btn.failed + .fs-return-close { color: #ef6c00; border-color: #ef6c00; }

.call-btn { position: absolute; bottom: 10px; right: 10px; padding: 0.6rem 1.2rem; background-color: #d32f2f; color: white; border: none; border-radius: 8px; font-size: 1.1rem; font-weight: bold; cursor: pointer; }

/* 🔔 **호출이 어떻게 됐나** — 시계 바로 아래 한 줄 (ROADMAP 2-A 공2 · 공3).
   진님이 2026-09-21 에 그림 셋(시계 아래 한 줄 · 호출 단추가 상태로 · 떠 있는 칸)
   중 이것을 골랐다.

   🔴 **`min-height` 로 자리를 늘 잡아 둔다.** 이 카드는 세로 `flex` 에
      `justify-content: center` 라, 줄이 생겼다 없어지면 **그 큰 시계가 위아래로
      움직인다.** 호출을 누른 순간 화면이 들썩이면 칠판에서는 고장으로 보인다.

   ⚠️ **`rem` 으로 적는다.** 이 화면은 `html { font-size: 1.1vw }` 라 4K 에서도
      비율이 같아야 한다 — `px` 로 굳히면 4K 에서 여백만 절반이 된다 (머리주석 ①).

   ⚠️ 비어 있을 때도 자리를 차지하므로 `:empty` 로 숨기지 않는다. 숨기는 순간
      위 `min-height` 를 둔 이유가 통째로 없어진다. */
.call-state {
    min-height: 2.4rem;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.6rem; font-weight: 800; white-space: nowrap;
    padding: 0 0.6rem;
}

/* 호출이 나갔고 **아직 답이 없다.** 호출 단추와 같은 빨강이다 — 누른 그 단추가
   지금 무엇을 하고 있는지가 한눈에 이어져야 한다. */
.call-state.calling { color: #d32f2f; }

/* 🔴 **본부가 봤다.** 빨강에서 초록으로 바뀌는 것이 이 줄의 전부다 —
   교실 뒤에서는 글자보다 **색이 먼저** 읽힌다. */
.call-state.confirmed { color: #2e7d32; }

/* 💬 본부가 보낸 말. 확인(초록)과 같은 계열이되 한 칸 진하다 — 「봤다」보다
   「이렇게 합니다」가 더 알맹이 있는 소식이라 눈이 한 번 더 가야 한다. */
.call-state.replied { color: #1b5e20; }

.view-toggle-buttons { position: absolute; bottom: 10px; left: 10px; display: none; gap: 8px; }
.view-toggle-buttons.show { display: flex; }
.view-btn { padding: 0.55rem 1.1rem; background-color: #1a237e; color: white; border: none; border-radius: 8px; font-size: 1rem; font-weight: bold; cursor: pointer; }
.view-btn.active-view { background-color: #ffd600; color: #000; }

#proctor-schedule th:nth-child(1) { width: 10%; }
#proctor-schedule th:nth-child(2) { width: 26%; }
#proctor-schedule th:nth-child(3) { width: 32%; }
#proctor-schedule th:nth-child(4) { width: 32%; }
#proctor-schedule td { font-size: 1.7rem; }

.bottom-grid { flex: 4; display: grid; grid-template-columns: 3fr 2fr 2fr 3fr; gap: 1rem; min-height: 0; overflow: hidden; }
.info-box { background: white; border-radius: 12px; border: 1px solid #e0e6ed; display: flex; flex-direction: column; overflow: hidden; height: 100%; }
.info-title { background: #5c6bc0; color: white; padding: 8px 5px; font-size: 1.1rem; text-align: center; font-weight: bold; white-space: nowrap; }
/* [ROADMAP 2-A 교10] 응시현황 제목 옆의 저장 상태. 제목 줄 **안**에 작게 둔다 —
   줄을 하나 더 두면 1920 칠판에서 맞춘 표 높이가 달라진다. 비어 있으면 자리도 안 차지한다. */
.save-state { font-size: 0.75rem; font-weight: normal; margin-left: 6px; padding: 1px 6px; border-radius: 8px; }
.save-state:empty { display: none; }
.save-state.saving { opacity: 0.8; }
.save-state.saved { background: rgba(255, 255, 255, 0.2); }
.save-state.failed, .save-state.rejected { background: #ffeb3b; color: #b71c1c; font-weight: bold; }
.info-box table td { font-size: 1.1rem !important; padding: 5px !important; height: auto !important; line-height: 1.2 !important; border: 1px solid #eee !important; }

/* [D81] — 재적·결시는 `<input>` 이다. 칸을 통째로 채워서 **누르는 자리가
   예전과 같게** 보이도록 한다. 스마트 칠판은 손가락으로 짚으므로 칸이 작아지면
   그만큼 눌리지 않는다. */
.info-box table td.stat-cell { padding: 0 !important; }
.stat-cell input {
    width: 100%;
    box-sizing: border-box;
    border: 0;
    background: transparent;
    font: inherit;
    color: inherit;
    text-align: center;
    padding: 5px;
}
.stat-cell input:focus { outline: 2px solid #5c6bc0; outline-offset: -2px; }

/* ── [교4] 빈 칸에 「눌러서 입력」 ──────────────────────
   칠판은 손가락으로 짚는 화면인데, 빈 칸은 적는 자리인지 그냥 빈 자리인지
   구별이 안 됐다. 값이 들어오면 저절로 사라진다.

   ⚠️ `contenteditable` 에는 `placeholder` 가 없어 `::before` 로 그린다.
      `:empty` 를 안 쓰고 **JS 가 `is-empty` 를 붙인다** — 글을 지우면
      브라우저가 `<br>` 하나를 남겨 `:empty` 가 거짓이 된다. 그러면
      비어 보이는 칸에 안내문이 안 돌아온다. */
/* 🔴 **크기는 1920 실측으로 정했다** (2026-09-20). 칸마다 폭이 다르다:

     | 칸 | 쓸 수 있는 폭 | 안내문 |
     |---|---|---|
     | 재적 (`input`) | **82px** | `눌러서` — 세 글자뿐이다 |
     | 결번 (`#stat-vacant`) | 줄 167px 중 약 121px | `눌러서 입력` |
     | 명단·특이사항 | 148px / 233px | `눌러서 입력` |

   재적만 글자가 짧은 것은 **칸이 그만큼 좋아서**다. `눌러서 입력` 을
   억지로 넣으려면 글자가 13px 까지 줄어 **칠판 뒤에서 안 보인다.**

   ⚠️ 크기는 `em`·`rem` 이다 — 칠판은 4K 이라 `px` 로 적으면 절반으로 보인다.
   ⚠️ `white-space: nowrap` 을 빼지 말 것. `.info-content` 의 `word-break: break-all` 이
      안내문을 **단어 가운데서** 잘라 `눌러서 입 / 력` 이 된다 (실측했다). */
.stat-cell input::placeholder { color: #b0b8c4; opacity: 1; font-size: 0.8em; }
[data-placeholder].is-empty::before {
    content: attr(data-placeholder);
    color: #b0b8c4;
    font-weight: normal;
    white-space: nowrap;
}
/* 결번은 「결번」 글자와 한 줄을 나눠 쓴다. 크면 줄이 둘로 늘고,
   그러면 응시현황 표가 세로로 자라 1920 실측 배치가 밀린다 (실제로 겪었다). */
#stat-vacant.is-empty::before { font-size: 0.8em; }
/* 명단·특이사항은 글자가 2.5rem 이라 안내문까지 그 크기면 고함처럼 보인다. */
.info-content.is-empty::before { font-size: 1.1rem; }

/* ── [교4] 아직 아무도 안 만진 결시 `0` 은 회색이다 ────────────
   🔴 결시 칸은 **비는 법이 없다** ([D81] — 빈칸은 `0` 이다). 그래서
   「눌러서 입력」은 여기 뜨질 않는다. 대신 **아직 아무도 안 적은 `0`**
   과 **확인해서 `0`** 을 색으로 가른다. 가르는 값은 새 것이 아니다 —
   서버의 `checked_at` 은 이미 있고 본부 카드가 그것 하나로 「아직 확인
   안 함」 배지를 가른다 (`ExamDashboard`). 폴링에 실어 오기만 했다. */
.stat-cell input.unchecked { color: #b0b8c4; }

/* ── [교5] 적을 수 없는 기간엔 칸을 잠가 보인다 ───────────────
   `can_write` 는 첫 폴링부터 오고 있었는데 **화면이 아무도 안 읽었다.**
   평상시에 칠판에서 값을 치면 다 치고 저장할 때서야 409 로 거절됐다.

   ⚠️ **줄을 더 두지 않는다.** 자물쇠는 제목 줄 **안**에 들어간다 —
      상자 아래에 안내줄을 붙이면 1920 실측으로 맞춘 표 높이가 달라진다.
      이유는 눌렀을 때 토스트가 말해 준다. */
.lock-mark { display: none; font-size: 0.9em; }
.info-box.locked .lock-mark { display: inline; }
.info-box.locked table td,
.info-box.locked .info-content { background: #f2f3f5; color: #9aa0a6; }
.info-box.locked .stat-cell input { color: #9aa0a6; }
.info-box.locked #stat-present { background: #f2f3f5 !important; }
.info-box.locked .vacant-row td { color: #9aa0a6; background: #f2f3f5; }
/* 잠긴 칸은 눌려도 아무 일도 안 나므로, 손가락에게 「여기 아니다」를 보인다. */
/* 🔴 잠긴 칸에는 「눌러서 입력」을 안 보인다 — 누를 수 없는 칸이 누르라고
   말하면 그것이 고장처럼 보인다. 1920 미리보기에서 눈으로 잡았다 (2026-09-20). */
.info-box.locked [data-placeholder].is-empty::before { content: ""; }
.info-box.locked .stat-cell input::placeholder { color: transparent; }

.info-box.locked table td.stat-cell,
.info-box.locked .info-content,
.info-box.locked .vacant-row td { cursor: not-allowed; }

/* ── [교7] 결시 수와 명단이 어긋난다 ─────────────────────
   띠는 순위로 하나만 보이므로([교7] 랭크 5) 급한 말이 뜨면 이것은 숨는다 —
   진님이 고른 「급한 것이 뜨면 주황은 숨는다」는 이 구조 그대로다.
   칸 표시는 띠과 따로 간다 — 띠이 숨어도 **어느 칸이 어긋나는지**는 남아야 한다. */
.stat-cell input.mismatch {
    background: #fff8e1; color: #e65100;
    box-shadow: inset 0 0 0 2px #ef6c00;
}

/* 결번 줄은 다른 셋과 성격이 다르다 — 오늘 값이 아니라 학년 내내 고정이고
   초기화가 안 지운다. 색으로 그것을 표시한다 (특이사항 초록과도, 결시 빨강과도 구별). */
.info-box .vacant-row td { color: #00695c; background: #f1f8f6; }

/* 칸을 둘로 안 나누고 한 칸을 통째로 쓴다 (colspan). 1920 실측에서 응시현황 상자가
   **170px** 뿐이라, 재적/결시처럼 반씩 나누면 값 칸이 83px 이 되어 `2.7.14.` 가
   두 줄로 접혔다. 통으로 쓰면 같은 값이 한 줄에 들어간다. */
.info-box .vacant-label { font-size: 0.85em; opacity: 0.8; margin-right: 6px; }

/* 비어 있어도 누를 자리가 남아야 한다 — 스마트 칠판은 손가락으로 짚는다. */
#stat-vacant { display: inline-block; min-width: 4em; border-bottom: 1px dashed #80cbc4; }

.info-content { flex: 1; display: flex; padding: 10px; font-size: 2.5rem; font-weight: 800; line-height: 1.3; text-align: center !important; justify-content: center; align-items: center; word-break: break-all; white-space: pre-wrap; overflow: hidden; }
#absent-list { color: #d32f2f; font-size: 1.5rem; }
#notice-content { white-space: pre-wrap; word-break: keep-all; overflow-wrap: break-word; }

/* ── 띠 ──────────────────────────────────────────────────────
   body 가 세로 flex 라서, 이 띠를 첫 칸으로 넣으면 아래 화면을 **가리지 않고**
   밀어낸다. 시험 중에 결시 인원을 치고 있는 칸을 덮어 버리면 더 나쁘다.
   평소에는 `hidden` 이라 자리를 아예 안 먹는다. */
#banner {
    display: none; align-items: center; justify-content: center;
    background: #d32f2f; color: #fff; font-size: 1.6rem; font-weight: 800;
    padding: 0.7rem 1rem; margin-bottom: 1rem; border-radius: 12px;
    box-shadow: 0 4px 10px rgba(0,0,0,0.15); flex: none;
}
#banner.show { display: flex; }

/* 저장이 안 되고 있다 — 빨강보다 한 칸 약한 주황. 「화면이 오래됐다」(빨강)와
   급한 정도가 다르다: 저쪽은 사람이 새로고침하면 끝이고, 이쪽은 서버가 돌아올
   때까지 화면이 할 수 있는 것이 없다. */
#banner.warn { background: #ef6c00; }

/* 시험 기간이 아니라 거절됐다 — 고장이 아니라 **규칙**이라 회색이다. */
#banner.info { background: #455a64; }

/* 띠 안의 새로고침 단추 (2026-09-04. 진님 요청).
   **스마트 칠판은 전체화면으로 두므로 F5 를 누르기가 번거롭다** — 키보드가 손에
   없을 수도 있다. 경고를 띄우면서 고치는 방법을 안 주면, 보는 사람은 경고를
   읽고도 할 수 있는 것이 없다.
   ⚠️ <button onclick> 이 아니라 **<a href="">** 다. 자바스크립트가 죽은 화면에서도
      브라우저가 알아서 이동한다 — 얼어붙은 화면을 되살릴 유일한 길이다. */
#banner a {
    margin-left: 1rem; padding: 0.35rem 1.1rem; background: #fff; color: #d32f2f;
    border-radius: 8px; text-decoration: none; font-size: 1.3rem; font-weight: 800;
    white-space: nowrap;
}
/* 🔴 [교7] 닫기 ✕ — 진님 요청 (2026-09-20).
   명단을 세는 것은 **짐작**이다. 사람이 `7. 김민준 10. 이서연` 처럼 쉼표 없이
   적으면 1명으로 셀다 — 그러면 **맞게 적었는데 경고가 안 사라진다.**
   칠판은 하루 종일 띄워 두는 화면이라 그것은 사고다. 손으로 닫을 수 있게 한다.

   ⚠️ 닫기가 붙는 띠는 `mismatch` 뿐이다 — 급한 띠(저장 실패·새로고침·기간 아님)을
      닫게 하면 그것이야말로 못 보고 지나가는 일이 된다. */
#banner-close {
    display: none; margin-left: 1rem; padding: 0.25rem 0.7rem;
    background: rgba(255,255,255,0.25); color: #fff;
    border: 2px solid #fff; border-radius: 8px;
    font-size: 1.2rem; font-weight: 800; line-height: 1; cursor: pointer;
}
#banner.can-close #banner-close { display: block; }

#banner.warn a { color: #ef6c00; }
#banner.info a { color: #455a64; }

/* 머리줄에 늘 있는 새로고침 (2026-09-04). 전체화면 단추 왼쪽.
   **평소에 쓰라고 둔 것이 아니다** — 화면 안의 값은 3초마다 저절로 갱신된다.
   이것이 있어야 하는 자리는 하나다: **화면이 얼어붙었을 때.** 그때는 시계가 멈추고
   본부의 ↻ 도 안 먹는다(그 화면의 자바스크립트가 죽었으므로 명령을 못 받는다).
   그래서 이것도 <a href=""> 다 — 자바스크립트 없이 브라우저만으로 돈다. */
.reload-link {
    padding: 0.6rem 0.9rem; background-color: #f5f5f5; color: #1a237e;
    border: 1px solid #1a237e; border-radius: 8px; font-size: 1.1rem; font-weight: bold;
    text-decoration: none; margin-right: 0.5rem; white-space: nowrap;
}

/* ── 저절로 사라지는 안내 (토스트) ─────────────────────────────────────
   🔴 [ROADMAP 2-A 공1] `alert()` 을 없앤 자리. `alert` 은 창을 닫을 때까지 **시계가
      멈추고 폴링이 안 돈다** — 칠판은 아무도 안 닫으면 종 칠 때까지 그대로였다.

   ⚠️ 흐름 밖에 떠 있다 (`position: fixed`). 띠(`#banner`)처럼 흐름 안에 두면 1920 으로
      맞춘 표 높이가 눌리고, 띠는 순위로 하나만 보여서 「연결이 끊겼습니다」에 밀린다
      (교2 의 `#fs-return` 과 같은 이유). 위 가운데다 — 아래 가운데는 교2 의 큰 단추 자리.
   ⚠️ `pointer-events` 를 살려 둔다 — 누르면 바로 사라진다. 폭을 묶어 두어 시계·응시현황을
      가로로 덮지 않는다. `z-index` 는 호출 팝업(9000)보다 낮다 — 급한 쪽은 호출이다.
   🔴 **긴 말은 줄을 바꾼다 — 자르지 않는다** (2026-09-23, [D114]). 예전에는 `nowrap` +
      말줄임표라 긴 문장을 더하는 날 **조용히 잘렸다.** 줄바꿈만 켜면 안 된다 — `left: 50%`
      라 줄어드는 폭의 한계가 **화면 절반**이 되어 짧은 말까지 괜히 두 줄이 된다.
      그래서 `width: max-content` 로 글 길이만큼 잡고 `max-width` 에서만 접는다. */
#toast {
    display: none; position: fixed; top: 1.2rem; left: 50%; transform: translateX(-50%);
    z-index: 60; width: max-content; max-width: 70vw; padding: 0.8rem 1.6rem; border-radius: 12px;
    background: #2e7d32; color: #fff; font-size: 1.5rem; font-weight: 800; line-height: 1.35;
    box-shadow: 0 6px 18px rgba(0,0,0,0.3); cursor: pointer; text-align: center;
    overflow-wrap: anywhere; word-break: keep-all;
    animation: toast-in .2s ease-out;
}
#toast.show { display: block; }
#toast.error { background: #ef6c00; }

@keyframes toast-in {
    from { opacity: 0; transform: translate(-50%, -8px); }
    to { opacity: 1; transform: translate(-50%, 0); }
}

/* 호출 팝업 안의 안내 한 줄 — 종류를 못 읽었을 때만 (`class.js` `openCallPicker`). */
.call-pop .note { margin: 0 0 6px; color: #546e7a; font-size: 1rem; font-weight: bold; }
