/* ============================================================
   영동고 시간표 알리미 — 셸 테마 (정본 nav-b-rail.html 이식)
   출처: mockups/design-samples/nav-b-rail.html <style> 9–503행
   프레임 밖 요소(.stage, .panel, .p- 접두 클래스, .frame 크기·그림자)는 제외.
   [주의] 주석 안에 별표+슬래시 시퀀스 금지 — 주석이 조기 종료되어
   다음 규칙(:root 토큰!)이 통째로 무효화된다(0.1.3 실사고).
   ============================================================ */
/* Pretendard Variable 내장(0.1.23) — 미설치 PC에서 한글이 맑은 고딕으로 폴백되어
   글자가 뭉개지던 문제. local() 우선: 설치본이 있으면 파일 로드 생략. OFL(fonts/ 참고). */
@font-face{
  font-family:'Pretendard Variable';
  font-weight:45 920;
  font-style:normal;
  font-display:swap;
  src:local('Pretendard Variable'), url('fonts/PretendardVariable.woff2?v=9599f12fd42fc0bc') format('woff2-variations');
}
:root{
  --ink-1: rgba(16,18,20,.92);
  --ink-2: rgba(16,18,20,.62);
  --ink-3: rgba(16,18,20,.45);
  --hair:  rgba(16,18,20,.09);
  --hair-2: rgba(16,18,20,.055);
  --hair-strong: rgba(16,18,20,.16);   /* 2h: 점심 경계 직후 행·강조 헤어라인(목업 --hair-2) */
  --sc-cols: 7;   /* 2h: .sc-grid 기본 열 수 — school.js 가 인라인 style 로 그날 최대 교시 수로 재정의 */
  /* 보이는 뷰포트 높이 — 기본은 창 전체다. app.js 가 visualViewport 를 읽어 **키보드가 올라온
     만큼** 줄여 준다(iOS Safari 처럼 레이아웃 뷰포트가 안 주는 브라우저 폴백). `.lc-smoke` 가 읽는다. */
  --vvh: 100%;
  /* iPhone 메모 시트는 키보드 뒤 offsetTop만 커져도 위치를 따라야 한다. 기본 0px라 Android
     resizes-content와 visualViewport 미지원 브라우저에서는 값 기반 보정이 자동으로 없다. */
  --vvt: 0px;
  /* 앱바 역스케일 계수 = **웹뷰 배율의 역수**(B0 · 2026-09-09). `js/zoom.js` 의 `apply()` 가
     `1 / 배율`을 문서 루트 인라인 스타일로 흘리고, `.appbar{zoom:var(--zinv,1)}` 과
     `overrides.css` 의 `.notif-panel{top:calc(52px * var(--zinv,1))}` 이 그것을 읽는다.
     ★ 기본값 1 이 **계약**이다 — 1 이면 그 둘은 항등이라 화면이 한 픽셀도 안 바뀐다.
       모바일 웹(`/m`)은 `wireZoom` 이 `available()` 로 갈라 아무것도 안 걸므로 **영원히 1** 이다.
       위 `--vvh`·`--vvt` 와 같은 「값이 안 흘러도 화면이 옳다」 선례를 그대로 따른다. */
  --zinv: 1;
  /* ---- 배경 레이어 (Mica 블루그레이 2톤) ---- */
  --bg-page:#e8eaed;
  --bg-frame:#E7EDF4;
  --surface:#ffffff;
  --tick-bg:rgba(231,237,244,.9);
  /* ---- 변동 4색·악센트 ---- */
  --red-now:#d93025;
  --c-sub:#0f7b0f;
  --c-rep:#9d5d00;
  --c-canc:#c42b1c;
  --c-swap:#0067b8;
  --a-swap:#0078d4;
  --t-sub-a: rgba(15,123,15,.16);
  --t-sub-b: rgba(15,123,15,.05);
  --t-sub: rgba(15,123,15,.12);
  --t-rep:   rgba(157,93,0,.11);
  --t-swap:  rgba(0,120,212,.10);
  --t-chg-swap: rgba(0,120,212,.14);   /* 교체 카드 틴트 전용(2026-09-22) — --t-swap 은 레일·초점·칩 공용 */
  --t-canc:  rgba(196,43,28,.06);
  --today-tint: rgba(0,120,212,.055);
  --pnum-idle:#DEE6EF;
  --ease-enter: cubic-bezier(.1,.9,.2,1);
  /* ---- 대체수업일(0.1.23) — 변동 4색·앰버(교체 태그)와 독립된 보라(요일 층위 신호) ---- */
  --c-day:#6b46a2;
  --t-day:rgba(107,70,162,.12);
  /* ---- 「내 수업」 표식(U11 시안 C) — 「오늘의 전체 시간표」의 현재/검색 링(--a-swap)과
     색상환상 겹치지 않는 여섯째 색. 플랜 고정값(W6 조사 u11-investigation.md §5). ---- */
  --a-mine:#0d7a72;
  --t-mine:rgba(13,122,114,.12);
  /* 오늘 탭 「출석 마감」 칩(2026-09-22 C1) — 「내 수업」 표식(--a-mine)과 같은 청록을 쓰되
     바탕·테두리 알파는 칩 전용으로 둔다(브리프 값 그대로). 초록은 이 앱에서 「보강」이다. */
  --seal-tint:rgba(13,122,114,.10);
  --seal-line:rgba(13,122,114,.28);
  --seal-count-num:#b02418;
  /* login.js 인라인 스타일이 참조(0.1.26) — 취소 빨강(--c-canc)과 동일 계열 */
  --danger:#c42b1c;
  --surface-ours:#E4EBF4;   /* 2e 우리 반 열 카드 — 중립 표면(신호색 아님) */
  /* 진행률 칩(기간·백분율) 잉크(0.1.58) — 바탕은 둘 다 --pnum-idle(#DEE6EF)이고, 그 위에
     **--ink-1** 로 쓴다(12.54:1). 옛 판 둘이 차례로 안 읽혔다: --ink-3 은 2.89:1(사용자 신고
     2026-09-02), 뒤이은 슬레이트 채움도 실기기에서 여전히 흐리다는 신고를 받았다(같은 날).
     바탕을 안 건드리므로 신호색(초록 보강·앰버 교체·파랑 현재·빨강 취소·보라 대체수업일)과는
     애초에 무관하다 — 진행률이 변동으로 오독되면 안 된다는 규칙은 그대로다. */
  --prog-ink:var(--ink-1);
  /* 「우리 반」 색(2026-09-30 사용자 · 시안 A 슬레이트) — 우리 반 열의 교시 번호와 우리 반 고사
     카드(.ex-ours)가 같이 쓴다. 값은 감독 색 후보 여덟(mockups/exam-card-결정요약.md §1-①)의
     4 슬레이트: 청록 감독 카드와 색상환으로 갈리고 이 열의 회청색 표면·칩과 한 계열이다.
     --surface-ours 위 5.85:1(AA). ★ 옛 --ours-num(슬레이트 42%)은 1.9:1 이었다 — 「어긋난 교시만」
     드문드문 나오던 신호였을 때의 값이라, 번호가 늘 나오게 되자(같은 날) 읽히지 않았다. */
  --c-ours:#425a7a;
  --ours-num:var(--c-ours);
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%}
/* body: 정본 flex-center(53–55행) 제거 — 창=프레임이므로 중앙정렬 불필요.
   프레임 배경(미세 노이즈, 정본 .frame 62–64행)을 body 로 이식. */
body{ background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.04'/%3E%3C/svg%3E") repeat,
    var(--bg-frame);
  font-family:'Pretendard Variable', Pretendard, 'Segoe UI Variable', system-ui, sans-serif;
  font-variant-numeric:tabular-nums; color:var(--ink-1); -webkit-font-smoothing:antialiased;
  /* dvh: 모바일 URL 바가 보이는 동안 100vh 는 화면보다 커서 하단이 잘리는데,
     overflow:hidden 이라 끌어올 수도 없다. 데스크톱에선 vh 와 같은 값이다. */
  height:100vh; height:100dvh; overflow:hidden; display:flex; flex-direction:column; }

/* ============================================================
   상단 앱바 — 브랜드 · 연결상태 · 🔔배지 (정본 그대로)
   ============================================================ */
.appbar{
  flex:none; height:48px; display:flex; align-items:center; gap:10px;
  padding:0 0 0 14px;                 /* 우측 0 — 윈도 컨트롤이 모서리에 붙는다(0.1.14 타이틀바) */
  /* ★★ 앱바만 웹뷰 배율에서 뺀다(B0 · 2026-09-09 · 사용자 확정).
     앱바는 `decorations:false` 라 **HTML 로 그린 타이틀바**인데, Ctrl+휠 확대가 그것까지 키워
     본문 자리를 먹었다(사용자가 매일 겪던 것은 이것 하나다). `--zinv` = 1/배율이므로 앱바가
     문서 좌표계에서 차지하는 높이는 48 * (1/z) 이고, 웹뷰가 그것을 z 배로 그리니
     **화면에서는 늘 48px** 이다. 위 `height:48px` 이 그 나눗셈의 피제수다 — 지우지 마라.
     ★ 왜 `transform:scale` 이 아니라 `zoom` 인가:
       ① `transform` 은 이미 그린 래스터를 늘려 **글자가 흐려진다.** `zoom` 은 레이아웃을 다시
          잡아 글자를 그 크기로 **새로 그린다.**
       ② `transform` 은 스태킹 컨텍스트와 **fixed 자손의 컨테이닝 블록**을 만든다.
          `zoom` 에는 그 함정이 없다.
       ★ 히트테스트는 **결정 근거가 아니었다** — `elementFromPoint` 로 z=1·1.5·2 에서 재니
         세 후보(zoom · transform · width 해킹) 모두 정상이었고 창버튼 우측 틈도 셋 다 0 이었다.
         근거는 위 ①②뿐이다.
     ★ `width` 해킹도 `transform-origin` 도 넣지 마라 — 셋 다 없이 폭이 창 전체를 채우는 것을
       z=1·1.25·2 에서 실측했다. `zoom` 은 그리기가 아니라 **레이아웃**을 다시 잡기 때문이다.
     ★ `calc()` 를 `zoom` 안에 쓰지 않는다(옛 WebView2 지원 편차) — 역수는 JS 가 계산해 넘긴다. */
  zoom: var(--zinv,1);
  border-bottom:1px solid var(--hair);
  background:rgba(255,255,255,.42);
  user-select:none; -webkit-user-select:none;
}
.appbar .brand{
  display:flex; align-items:center; gap:8px;
  font-size:14px; font-weight:600; letter-spacing:-.01em; color:var(--ink-1);
  white-space:nowrap;  /* 375px 실측: 알약이 길면 「영동고 시간표 알리 / 미」로 접혔다(2026-09-16) */
}
.appbar .brand svg{pointer-events:none}   /* 드래그 판정은 data-tauri-drag-region 보유 요소로 */
/* 윈도 컨트롤(최소화·최대화·닫기) — decorations:false 대체 */
.wincontrols{display:flex; align-self:stretch; flex:none}
/* 웹(비Tauri)에서 app.js 가 [hidden] 을 붙인다. UA 의 [hidden]{display:none} 은
   작성자 오리진의 display:flex 를 절대 못 이기므로(특이도가 아니라 캐스케이드
   오리진 우선순위) 여기서 직접 눌러야 한다. 이게 없으면 375px 앱바의 34%를
   눌러도 아무 일도 안 나는 최소화·최대화·닫기 버튼이 차지한다. */
.wincontrols[hidden]{display:none}
/* ★ 2026-09-23 W1 — 모바일 웹에서 알림 종의 배지가 화면 오른쪽으로 2px 삐져나가 문서가
   넓어지던 결함(실측: 요청 375 → documentElement.scrollWidth 377). `.iconbtn .badge` 는
   `right:-3px` 인데 웹(비Tauri)에서는 `.wincontrols[hidden]` 로 창 단추가 사라져 종이 앱바
   오른쪽 끝에 붙기 때문이다(데스크톱 앱은 종 뒤에 창 단추가 있어 안 넘친다 — 실측 520·930).
   ★ 왜 기본 `.appbar` 규칙의 `padding:0 0 0 14px` 를 고치지 않고 규칙을 하나 더 두나:
     그 값은 0.1.14 타이틀바 계약이고 B0 시험이 그대로 잠근다. 여기서는 **오른쪽만** 3px 늘리고
     `.wincontrols` 에 **같은 값의 음수 마진**을 주어 데스크톱의 flex 흐름을 정확히 상쇄한다 —
     spacer 가 3px 줄고 창 단추가 3px 오른쪽으로 당겨져 conn·종·창단추의 위치가 배포 전과
     한 픽셀도 다르지 않다. 모바일 웹은 창 단추가 없어 종이 3px 안쪽으로 들어오고, 배지
     오른쪽이 clientWidth-1 이 되어 문서가 안 넓어진다. 두 값은 반드시 «짝»이다 — 한쪽만
     바뀌면 데스크톱이 밀리거나 넘침이 되살아난다(theme-css.test.mjs W1 ⓑ 잠금). */
.appbar{padding-right:3px}
.wincontrols{margin-right:-3px}
.winbtn{
  width:42px; border:0; background:transparent; color:var(--ink-2);
  display:inline-flex; align-items:center; justify-content:center;
  transition:background-color 120ms ease, color 120ms ease;
}
.winbtn:hover{background:rgba(16,18,20,.07); color:var(--ink-1)}
.winbtn:active{background:rgba(16,18,20,.12)}
.winbtn.win-close:hover{background:#c42b1c; color:#fff}
.winbtn.win-close:active{background:#b02418; color:#fff}
.winbtn:focus-visible{outline:2px solid var(--a-swap); outline-offset:-2px}
.appbar .brand .logo{
  width:22px; height:22px; border-radius:6px; flex:none;
  background:linear-gradient(140deg, var(--a-swap), #2b90e6);
  display:flex; align-items:center; justify-content:center; color:#fff;
  box-shadow:0 1px 2px rgba(0,120,212,.35);
}
.appbar .spacer{flex:1}

/* 연결 상태 pill (클릭 시 상태 순환 — 데모) */
.conn{
  display:inline-flex; align-items:center; gap:6px; cursor:pointer; user-select:none;
  font-size:12px; font-weight:500; color:var(--ink-2);
  padding:4px 9px 4px 8px; border-radius:999px;
  background:rgba(15,123,15,.10);
  transition:background-color 150ms ease, color 150ms ease;
  position:relative;   /* ::after 터치 영역의 기준(2026-09-16 「다시 연결」) */
  white-space:nowrap;  /* 375px 실측: 옛 오프라인 문구가 두 줄로 접혔다 — 알약은 한 줄이다 */
}
/* 누르면 뭔가 되는 상태(offline·expired · app.js renderConn 이 붙인다) — 색·글자는 그대로 두고 얇은
   테두리 하나로 «버튼»임을 말한다. 일반 교사가 알약을 누르라는 표지가 없으면 알 수 없다(2026-09-16). */
.conn.action{box-shadow:inset 0 0 0 1px rgba(16,18,20,.28)}
/* 알약을 탭하면 다시 연결한다(app.js wireConnTap). 알약은 글자 높이(≈24px)라 손가락 표적으로 작다 —
   겉모습은 그대로 두고 **세로만** 10px 씩 넓혀 44px 표적을 만든다. 가로는 넓히지 않는다: 오른쪽 🔔 버튼의
   가장자리를 훔친다. */
.conn::after{content:""; position:absolute; inset:-10px 0}
.conn i{width:6px; height:6px; border-radius:50%; background:var(--c-sub); flex:none}
.conn.retry{background:rgba(157,93,0,.12); color:#7a4a00}
.conn.retry i{background:var(--c-rep)}
.conn.offline{background:rgba(16,18,20,.06); color:var(--ink-3)}
.conn.offline i{background:var(--ink-3)}
.conn:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}

/* 🔔 아이콘 버튼 + 배지 */
.iconbtn{
  position:relative; flex:none; width:34px; height:34px; border-radius:8px;
  border:1px solid transparent; background:transparent; color:var(--ink-2);
  display:inline-flex; align-items:center; justify-content:center; cursor:pointer;
  transition:background-color 150ms ease, border-color 150ms ease;
}
.iconbtn:hover{background:rgba(16,18,20,.05); border-color:var(--hair)}
.iconbtn:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}
.iconbtn .badge{
  position:absolute; top:-3px; right:-3px; min-width:16px; height:16px; padding:0 4px;
  border-radius:999px; background:var(--c-canc); color:#fff;
  font-size:10px; font-weight:700; line-height:16px; text-align:center;
  border:2px solid var(--bg-frame);
}

/* 배율 배지 — **배율이 100% 가 아닐 때만** zoom.js 가 연결 상태 pill 앞에 만든다.
   100% 면 이 요소는 DOM 에 **없다**(숨김이 아니라 부재) — 절대다수 상태의 앱바는
   이 변경 전과 마크업이 같다. 그래서 여기엔 부재 상태를 위한 규칙이 아예 없다.
   ★ 색은 중립(--ink-2·--hair·--surface)만 쓴다. 변동 3색(보강 초록·교체 파랑·취소 빨강)을
     빌리면 「무슨 변동이 났나」로 오독된다 — 배율은 변동이 아니라 보기 설정이다.
   ★ 초점 링은 --a-swap 으로 .iconbtn·.conn 과 같다(앱바 안에서 초점 언어가 갈리면 안 된다).
   ★ tabular-nums: 100↔125↔67 을 오갈 때 숫자 폭이 흔들려 옆의 pill 이 밀리지 않게. */
.zoombadge{
  flex:none; display:inline-flex; align-items:center; cursor:pointer;
  font-size:11.5px; font-weight:600; line-height:1; font-variant-numeric:tabular-nums;
  padding:5px 9px; border-radius:999px;
  border:1px solid var(--hair); background:var(--surface); color:var(--ink-2);
  transition:background-color 150ms ease, color 150ms ease;
}
.zoombadge:hover{background:rgba(16,18,20,.05); color:var(--ink-1)}
.zoombadge:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}

/* ============================================================
   좌측 「아이콘 레일」 — 폭 52px, 라벨 없음
   ------------------------------------------------------------
   · .rail-gutter : flex 흐름에서 52px 만 예약 → 콘텐츠 폭 최대
   · .rail        : 그 위를 덮는 절대배치 오버레이. hover/focus 시
                    186px 로 부드럽게 확장돼 라벨 노출(콘텐츠 안 밀림)
   ============================================================ */
.body{flex:1; min-height:0; display:flex; position:relative}

/* 흐름에서 예약하는 52px 거터(레일 자리) */
.rail-gutter{flex:none; width:52px}

/* 오버레이 레일 */
/* z-index 20 — 콘텐츠 층(1~7) 위, 스모크·모달(30·40·60·70) 아래.
   0.1.42 까지 6 이었는데 `.wk-grid .hd.corner`(교시, sticky z-index 6)와 **동점**이라
   DOM 순서(rail 이 main 보다 앞)로 코너가 이겨서, 레일을 펼치면 '교시' 칩이 메뉴 위로
   떠 보였다(공강 찾기·오늘의 전체 시간표 — corner 를 그리는 두 탭). `.sc-c .tip`(7)도
   같은 이유로 새어 나온다. 레일은 콘텐츠 위를 덮는 오버레이이므로 콘텐츠 층 전체보다
   위여야 한다 — 개별 셀렉터를 낮추는 대신 레일을 층 밖으로 올려 근본을 막는다. */
.rail{
  position:absolute; left:0; top:0; bottom:0; z-index:20;
  width:52px; overflow:hidden;
  display:flex; flex-direction:column; padding:6px 0;
  background:var(--bg-frame);
  border-right:1px solid var(--hair);
  transition:width 220ms var(--ease-enter), background-color 220ms ease, box-shadow 220ms ease;
}
/* 확장 트리거가 :hover/:focus-within 뿐이라, 터치 기기에서는 sticky-hover 나 버튼
   포커스로 열린 뒤 **닫을 수단이 없다**(폭을 만지는 JS 가 전무). 375px 화면의 절반을
   메뉴가 덮은 채 고착한다. 그래서 포인터가 있는 기기로 한정한다 — 모바일은 52px
   아이콘 레일 그대로 쓴다. */
@media (hover: hover) and (pointer: fine){
  .rail:hover, .rail:focus-within{
    width:186px;
    background:var(--surface);
    box-shadow:3px 0 18px rgba(16,18,20,.14);
  }
  /* 라벨 드러내기 — 폭 확장과 한 세트라 같은 가드 안에 둔다(따로 두면 터치에서
     52px 레일 안에 라벨만 켜져 잘린 글자가 보인다). */
  .rail:hover .rail-label, .rail:focus-within .rail-label{opacity:1; transform:none}
}

/* 레일 머리(「메뉴」)는 2026-09-23 사용자 결정으로 삭제 — 첫 항목이 맨 위에 온다. */

/* 항목(=버튼) */
.railitem{
  position:relative; display:flex; align-items:center;
  height:44px; width:100%; flex:none;
  border:0; background:transparent; cursor:pointer;
  color:var(--ink-2); font-family:inherit; padding:0; text-align:left;
  border-radius:0;
  transition:background-color 140ms ease, color 140ms ease;
}
/* 아이콘 존 — 52px 고정 폭에 중앙정렬(축소·확장 모두 정지) */
.nav-ic{
  flex:none; width:52px; height:44px;
  display:flex; align-items:center; justify-content:center; color:inherit;
}
.nav-ic svg{width:20px; height:20px; display:block}

/* 라벨 — 축소 시 클립+투명, 확장 시 슬라이드+페이드 */
.rail-label{
  flex:1; min-width:0; white-space:nowrap; padding-right:16px;
  font-size:13px; font-weight:500; letter-spacing:-.01em; color:var(--ink-2);
  opacity:0; transform:translateX(-5px);
  transition:opacity 150ms ease, transform 200ms var(--ease-enter);
}
.railitem:hover{background:rgba(16,18,20,.05); color:var(--ink-1)}
.railitem:hover .rail-label{color:var(--ink-1)}
.railitem:focus-visible{outline:2px solid var(--a-swap); outline-offset:-2px; border-radius:6px}

/* 활성 = 파란 채움 + 좌측 악센트 레일 + 악센트 아이콘 */
.railitem.active{background:var(--t-swap); color:var(--ink-1)}
.railitem.active .nav-ic{color:var(--a-swap)}
.railitem.active .rail-label{color:var(--ink-1); font-weight:600}
.railitem.active::before{
  content:''; position:absolute; left:0; top:50%; transform:translateY(-50%);
  width:3px; height:24px; border-radius:0 2px 2px 0; background:var(--a-swap);
}

/* ============================================================
   메인 콘텐츠 열 (헤더 + 타임라인) — 정본 그대로
   ============================================================ */
.main{flex:1; min-width:0; display:flex; flex-direction:column}

.app-header{flex:none; padding:11px 14px 9px; border-bottom:1px solid var(--hair)}
.head-row{display:flex; align-items:baseline; gap:8px}
/* ★★★ R-7 ⓐ(웨이브 4 A) — 이 규칙은 5화면 공유다: timeline·week·free·hist·school.
   min-width:0 은 flex 아이템의 기본 min-width:auto 를 푸는 「동작 변경」이고, 전역 적용은
   컨트롤러 결정(2026-08-27, 안 ㉠ — 넘침보다 말줄임이 나은 실패 모드)이다. 좁히지 마라. */
.head-row .teacher{font-size:16px; font-weight:600; letter-spacing:-.01em;
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* ★★★ 삭제 금지 — hist.js(「최근 2주」/「학기 전체」)·school.js(#scClock)가 함께 쓴다.
   오늘 탭이 .hd-date 로 옮겨 갔다고 지우면 두 탭이 조용히 폰트·색을 잃는다(단위 시험은 전부 초록). */
.head-row .date{font-size:14px; font-weight:600; color:var(--ink-1)}
/* 마지막 자리(오늘=시계 #hdClock · 비오늘=칩 #tdToday)를 **고정 폭 트랙**에 담는다.
   실측(Chromium 1208 · Pretendard Variable 14px/600/tabular-nums · 520px 창, 2026-08-28):
   시계 'HH:MM:SS' = 62.61px(00:00:00·23:59:59·11:11:11 전부 같다 — tabular-nums) ·
   「오늘로」 칩 = 53.13px → 비오늘 화면에서 날짜·◀▶ 가 **9.48px** 오른쪽으로 밀렸다(실기기 피드백 1).
   W = ceil(62.61) + 2 = 65px.
   ★ 고정할 것은 **마지막 트랙**이지 컨테이너가 아니다 — 컨테이너 폭만 고정하고 오른쪽으로
     붙이면(justify-content:flex-end) 마지막 자리의 폭 차이가 그대로 남아 nav 가 여전히 움직인다.
   ★ 칩·시계는 트랙 안에서 오른쪽 정렬(justify-items:end)이라 **오늘 화면 픽셀은 그대로**다. */
/* ★★ 세로 정렬은 center 다 — baseline 이 아니다(2026-09-01 실기기 피드백 · 하네스 실측).
   ⓐ 첫 트랙 아이템 .hd-nav 는 flex 컨테이너고, **flex 컨테이너의 baseline 은 첫 flex 아이템**
     에서 온다. 그 첫 아이템이 글자가 없는 **아이콘 전용 버튼 #tdPrev** 라, baseline 이 글자
     baseline 이 아니라 **SVG 의 아래 margin 모서리**(y=80)로 합성된다 — .hd-date 의 진짜 글자
     baseline 은 y≈77.2 다. 즉 시계는 **가짜 baseline** 에 맞춰지고 있었다.
   ⓑ 실측(Chromium · harness/app.html · 실 theme.css): baseline 이면 .hd-date 상단 63.6px 대
     .clock 상단 66.4px 로 시계가 **2.8px** 처지고(둘 다 높이 16.8px), 비오늘 화면의 「오늘로」
     칩(.hd-today)은 nav 행(59~85) 밖으로 **2.2px** 삐져나온다.
   ⓒ 정본 목업 mockups/memo-r2.html:348 도 center 를 의도했으나, 셀렉터 `.head-row.nav`
     가 목업 마크업에서 **매치 0건**(nav 클래스는 .app-header 에 붙었다)이라 죽어 있었다 —
     그래서 목업 자신이 같은 2.8px 어긋남을 렌더했고, 승인 스크린샷이 그 결함을 안고 있었다.
   ⓓ .hd-date 는 이미 26px .hd-nav(align-items:center) 안에서 세로 중앙이고 .clock 도 같은
     16.8px 상자라, center 가 곧 **정확한 baseline 일치**다. 헤더 전 요소 좌표 전수 대조에서
     움직이는 것은 .clock 하나뿐(−2.8px)이다. baseline 으로 되돌리지 마라(A-T23 이 잠근다). */
.hd-when{margin-left:auto; display:inline-grid; grid-auto-flow:column;
  grid-template-columns:auto 65px; align-items:center; justify-items:end; gap:7px}
.hd-when .clock{font-size:14px; font-weight:600; color:var(--ink-1); font-variant-numeric:tabular-nums; letter-spacing:.01em}

/* 오늘 탭 헤더 날짜 이동(웨이브 4 A · 정본 mockups/memo-r2.html:347·349~356).
   ⚠ 목업 :348 의 「nav 클래스가 붙은 head-row 안의 hd-when」 **셀렉터**는 이식하지 않는다 —
   목업에서 한 번도 매치되지 않는 죽은 셀렉터고, 되살리면 간격이 7→8px 로 승인 스크린샷과
   달라진다(A-T12 가 정적으로 부재를 잠근다).
   ※ 다만 그 죽은 규칙이 담고 있던 **정렬 값 align-items:center 는 옳았다** — 2026-09-01 에
     값만 위 .hd-when 에 따로 채택했다(근거는 그 주석 ⓐ~ⓓ). 셀렉터는 지금도 이식하지 않는다. */
.hd-nav{display:inline-flex; align-items:center; gap:1px}
.hd-arw{flex:none; width:26px; height:26px; border-radius:7px; border:1px solid transparent; background:transparent;
  color:var(--ink-2); display:inline-flex; align-items:center; justify-content:center; font-family:inherit}
.hd-arw:hover{background:rgba(16,18,20,.05)}
.hd-arw[disabled]{color:var(--ink-3); opacity:.35}
/* W19 R2 — .hd-date 가 span 에서 button 으로 바뀌어도(달력 팝오버 트리거) 옛 span 과 같아
   보이게 브라우저 기본 버튼 모양을 지운다(테두리·배경·여백·글꼴족). 값 자체(글꼴·크기·색·
   자간)는 옛 span 규칙 그대로 — hover·focus-visible 링만 .wk-range(989~990행) 관용구를 쓴다. */
.hd-date{font-size:14px; font-weight:600; color:var(--ink-1); padding:0 3px; white-space:nowrap;
  letter-spacing:-.005em; border:0; margin:0; background:transparent; font-family:inherit; cursor:pointer}
.hd-date:hover{background:rgba(16,18,20,.05); border-radius:6px}
.hd-date:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px; border-radius:6px}
.hd-today{flex:none; font-size:12px; font-weight:600; font-family:inherit; color:var(--a-swap);
  background:rgba(0,120,212,.10); border:0; border-radius:99px; padding:4px 11px; white-space:nowrap}
.head-sub{display:flex; align-items:center; gap:9px; margin-top:7px; flex-wrap:wrap}
.delta-count{font-size:12.5px; font-weight:600; color:var(--ink-1)}
/* 고사 조회 실패 한 줄(§8-5) — .delta-count 와 같은 크기, 색만 --ink-2 로 조용하게(경고지 알림이 아니다) */
.exam-warn{font-size:12.5px; font-weight:600; color:var(--ink-2)}

/* ---------- 타임라인 스크롤 영역 ---------- */
.tl-scroll{flex:1; overflow-y:auto; overflow-x:hidden; scrollbar-width:thin; scrollbar-color:rgba(16,18,20,.22) transparent}
/* Q167 C(2026-10-16) — 축 맨 위에서도 선 위 라벨(약 47px + 간격 7px)을 자르지 않는다.
   클리핑 경계만 48px 올리고 같은 패딩으로 상쇄해 축·카드 좌표는 그대로 둔다.
   오늘의 나우라인이 있는 스크롤에만 적용한다. 라벨 그림자도 들어갈 여유를 포함한다. */
.tl-scroll-now{margin-top:-48px; padding-top:48px}
/* 스크롤이 조금이라도 있으면 확장부 전체를 잘라 선·라벨이 헤더를 넘지 않게 한다.
   클리핑만 바꾸므로 스크롤 위치·축·카드 좌표는 움직이지 않는다. */
.tl-scroll-now.tl-scroll-clipped{clip-path:inset(48px 0 0 0)}
/* 확장한 스크롤 여백이 날짜 버튼을 가로채거나 스크롤한 카드를 머리 뒤로 비치지 않게 한다.
   머리는 열 머리 알약(z 2)보다 위, 나우라인(z 4)보다 아래라 버튼과 라벨이 모두 살아 있다. */
.tl-header{position:relative; z-index:3; background:var(--bg-frame)}
.tl-scroll::-webkit-scrollbar{width:8px}
.tl-scroll::-webkit-scrollbar-track{background:transparent}
.tl-scroll::-webkit-scrollbar-thumb{background:rgba(16,18,20,.18); border-radius:4px; border:2px solid transparent; background-clip:padding-box}
.tl-scroll::-webkit-scrollbar-thumb:hover{background:rgba(16,18,20,.3)}

/* 절단 타임라인 08:10–17:30 = 560분 × 1.4px = 784px */
.tl{position:relative; height:784px; margin:12px 0 28px}

/* 괘선 + 거터 시각 */
.rule{position:absolute; left:44px; right:0; height:0; border-top:1px solid var(--hair); pointer-events:none}
.tick{
  position:absolute; left:-40px; width:36px; top:0; transform:translateY(-50%);
  text-align:right; font-size:12px; color:var(--ink-2); font-weight:600;
  letter-spacing:.01em; background:var(--tick-bg); border-radius:2px; padding:1px 0;
}

/* ---------- 교시 밴드 ---------- */
/* 카드 마감(0.1.40) — 모서리 3px·그림자 0 이 '촌하다'의 실제 원인이었다.
   좌표(left/right)는 건드리지 않는다: 담임 2열(.tl-col-l/-r)·나우라인·괘선·눈금이
   같은 좌표계를 공유해 함께 옮겨야 하고, 얻는 것은 여백 8px 뿐이다. */
/* ★ container:band — **카드 자신**이 폭 기준이다. 아래 「카드 폭 축소」 블록이 이 이름을 잰다.
   조상(.tl·.tl-col)을 재면 겹침 수업을 놓친다: timeline.js 가 레인 분할 밴드에 인라인
   `left:X%;width:Y%` 를 붙여 **카드 폭 ≠ 조상 폭**이 되기 때문이다(3레인이면 조상의 1/3).
   inline-size containment 는 여기서 안전하다 — .band 의 폭은 언제나 좌표(left/right 또는
   인라인 width)로 정해지고 내용에 의존하지 않으며, 자식은 .b-inner 하나뿐이다.
   ★★ 패딩이 .band 에 있으면 축소에 넣을 수 없다 — 컨테이너는 **자기 자신을 스타일할 수
   없다**(@container 안의 규칙은 그 컨테이너의 자손에만 적용된다). 그래서 .b-inner 로 한 층
   내렸다. .band 는 display:flex + box-sizing:border-box 이고 .b-inner 는 flex:1 이라
   결과 좌표는 픽셀 동일하다(실렌더 전수 대조로 확인). */
.band{
  position:absolute; left:48px; right:12px;
  border-radius:14px;
  background:var(--surface);
  box-shadow:0 2px 6px rgba(16,18,20,.07), 0 8px 20px rgba(16,18,20,.05);
  outline:none;
  display:flex; align-items:center;
  container:band / inline-size;
}
.band::before{
  content:''; position:absolute; inset:0; border-radius:inherit;
  background:rgba(16,18,20,.05); opacity:0; pointer-events:none;
  transition:opacity 150ms ease;
}
.band:hover::before{opacity:1}
.band:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}
.band.flash::after{
  content:''; position:absolute; inset:0; border-radius:inherit;
  background:rgba(0,120,212,.20); pointer-events:none;
  animation:flashFade 1.1s ease-out forwards;
}
@keyframes flashFade{from{opacity:1}to{opacity:0}}

/* 붙은 교시(쉬는 시간 0분 — 모의고사·단축 일과) 구분선.
   ★★ 왜 간격이 아니라 선인가: 이 화면에서 **간격은 「쉬는 시간」을 뜻하는 언어**다
     (밴드 top·height 가 순수 시각 환산이라 쉬는 시간 10분이 14px 로 저절로 나온다).
     쉬는 시간이 0인 자리에 여백을 넣으면 **없는 쉬는 시간이 있다고 말하게 된다** —
     0.1.55 에서 실기기 사용자가 그대로 신고했다. 사이는 붙인 채 두고 선만 진하게 긋는다.
   ★★ 왜 전용 자식 요소인가 — 넷을 실측으로 배제했다. 되살리지 마라:
     · `::after`  = 바로 위 `.band.flash::after` 가 쓴다. 같은 특이도라 소스 순서로 갈리고
       플래시가 `forwards` 라 **한 번 반짝인 뒤 선이 영영 사라진다.**
     · `::before` = 바로 위 `.band::before` 가 호버 오버레이로 쓴다.
     · `background-image` = 아래 `.st-sub`(사선 줄무늬)·`.st-rep`·`.st-swap` 이 쓴다 —
       보강·교체 카드가 **틴트를 잃거나 선을 잃는다.**
     · `box-shadow` = `.st-canc`·`.band.gone`·`.band.hb` 가 쓴다.
   ★ `position:absolute` 는 필수다 — `.band` 는 display:flex 이고 자식이 `.b-inner` 하나뿐이라
     흐름에 들어가면 조판이 깨진다. DOM 에서 `.b-inner` **뒤**라 호버 오버레이(::before)보다
     늦게 칠해진다 = 호버해도 선이 살아 있다.
   ★ 좌우 14px 의 근거는 **`border-radius` 와 같은 값**이라는 것이다 — 반경은 카드 폭과
     무관하게 14px 로 고정이므로, 이 여백이면 선이 둥근 모서리를 넘지 않는다.
     넓은 카드에서는 `.b-inner` 의 가로 패딩(14px)과도 우연히 같아 글자와 맞아떨어지지만,
     **카드 폭 340px 아래에서는 패딩이 10px 로 줄어 선이 글자보다 4px 안쪽**이다(실측:
     카드 807.6px → 둘 다 14 / 카드 297.6px → 글자 10·선 14). 실사용 폭(창 930·폰)에는
     안 나타나므로 그대로 둔다. 맞추려면 `@container band (max-width: 340px)` 와 터치
     되돌림 블록 **양쪽에 짝으로** 넣어야 한다 — 한쪽만 넣으면 폰에서 어긋난다. */
.band.abut .b-edge{
  position:absolute; left:14px; right:14px; bottom:0; height:1px;
  background:var(--hair-strong); pointer-events:none;
}

/* 카드 안쪽 패딩은 여기 산다(옛 자리 = .band). 위 .band 주석 ★★ 참조 — 컨테이너는 자기
   자신을 못 고치므로, 폭에 따라 줄일 값은 반드시 컨테이너 **안쪽** 요소에 있어야 한다. */
.b-inner{position:relative; flex:1; min-width:0; display:flex; align-items:center; gap:9px;
  padding:10px 14px; transition:opacity 200ms ease}

.pnum{
  flex:none; width:32px; height:32px;
  display:flex; align-items:center; justify-content:center;
  font-size:14.5px; font-weight:700; color:var(--ink-2); background:var(--bg-frame);
  font-variant-numeric:tabular-nums;
  border-radius:50%;
  transition:background-color 200ms ease, color 200ms ease, box-shadow 200ms ease;
}
.b-body{flex:1; min-width:0}
.b-line1{display:flex; align-items:baseline; gap:6px; min-width:0}
/* 넘침 차단(0.1.40) — 이 줄은 예전부터 우측 블록(태그·나우칩·진행률) 위로 흘러넘쳤다.
   담임 2열 좌측 열은 폭이 절반(기본 창 520px 에서 약 198px)이라 특히 심했고, 과목명을
   키우면서 더 나빠졌다. 말줄임으로 끊어 우측 블록을 침범하지 않게 한다. */
.b-subj{font-size:14.5px; font-weight:600; letter-spacing:-.01em; color:var(--ink-1);
  white-space:nowrap; min-width:0; overflow:hidden; text-overflow:ellipsis}
/* 카드가 좁으면 과목명을 본문 크기(14.5px)로 되돌려 잘림을 줄인다 — 규칙 자체는 아래
   「카드 폭 축소」 @container 블록에 있다. 2열이라서가 아니라 **카드가 좁아서** 줄인다. */
/* 0.1.44: 나우칩 폐지 — 2열에서만 숨기던 것을 아예 없앴다. 나우라인 라벨이 같은 내용을
   과목명·초 단위까지 담아 보여주는데, 그 라벨이 밴드 우측 상단을 덮어 1열에서는 칩과
   실제로 겹쳤다(실측). 마크업·updateNow 분기도 함께 제거. */
/* 학급=보조(작은 회색) · 과목=주체(크고 진하게). 한 덩어리로 읽히던 것을 가른다(0.1.40) */
/* 학급 라벨은 **고정 자리**를 차지한다 — 자연 폭이면 '2-3'(3자)과 '2-11'(4자)이
   뒤따르는 과목명을 서로 다른 x 로 밀어, 목록을 세로로 훑을 때 과목이 들쭉날쭉했다.
   min-width 라 더 긴 라벨이 와도 잘리지 않고 그 줄만 밀린다(폭 고정이 아니다). */
.b-cls{display:inline-block; min-width:4ch; text-align:left;
  font-size:12.5px; font-weight:600; color:var(--ink-3); letter-spacing:.01em; margin-right:7px}
.b-sj{font-size:16.5px; font-weight:600; color:var(--ink-1); letter-spacing:-.02em}
.b-line1 .arrow{align-self:center; flex:none; color:inherit}
.b-line2{margin-top:2px; font-size:13.5px; color:var(--ink-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
s{ text-decoration-thickness:1px; text-decoration-color:currentColor }

.b-side{flex:none; display:flex; flex-direction:column; align-items:flex-end; gap:2px}
.b-tag{flex:none; font-size:12.5px; font-weight:600; letter-spacing:-.005em}
/* 변동 태그 알약(2026-09-22) — **변동 태그 전용 클래스 .b-chg 에만** 건다. `.b-tag` 는 다른 표지
   (예: 옛 `.b-tag.b-sealed`)도 쓰는 자리라, 흰 글자를 `.b-tag` 전체에 걸면 바탕이 없는 그 표지가
   흰 카드 위에서 사라진다(병합 시험으로 발견). */
.b-tag.b-chg{font-size:12px; color:#fff; line-height:16px; padding:1px 7px; border-radius:999px}

/* 오늘 탭 「출석 마감」 칩(2026-09-22 C1 사용자 결정) — 마감한 수업의 **과목명 바로 옆**에 붙는다.
   ★ 오른쪽 칸(.b-side)이 아니라 .b-line1 의 과목 strong **뒤 형제**다: 과목명이 길면
     strong 만 말줄임되고(overflow:hidden) 칩은 flex:none 으로 온전히 남는다 — 가장 긴
     「동아시아 역사 기행A」에서도 칩이 사라지지 않는다(G2 시안 5). 그래서 `.b-subj` 안에
     넣지 않는다(넣으면 말줄임에 함께 잘린다).
   ★ 청록 = 「내 수업」(--a-mine)과 같은 색. 초록은 이 앱에서 「보강」이라 마감에 쓰면 오독된다.
   ★ 실제 글자 노드다(::after 금지) — 화면 읽기·시험이 본다. */
/* ★ 2026-09-23 사용자 지적 — 칩이 과목명 **아래로** 내려앉아 보였다. `.b-line1` 이
     `align-items:baseline` 이라, 테두리·여백이 있는 칩의 «글자 밑줄»을 14.5px 과목명의
     밑줄에 맞추면 칩 상자 전체가 그만큼 처진다. 같은 줄의 `.arrow` 가 이미 쓰는 처방
     (`align-self:center`)으로 **칩만** 세로 가운데에 세운다 — 줄 전체의 baseline 규칙은
     학급·과목·구간 이름이 공유하므로 건드리지 않는다. */
.b-seal{align-self:center; flex:none; font-size:10.5px; font-weight:700; letter-spacing:-.01em; white-space:nowrap;
  color:var(--a-mine); background:var(--seal-tint); border:1px solid var(--seal-line);
  border-radius:999px; padding:0 6px; line-height:16px}
.b-seal-count{align-self:center; flex:none; font-size:10.5px; font-weight:600;
  white-space:nowrap; color:var(--ink-1); line-height:16px}
.b-seal-num{color:var(--seal-count-num)}

/* 현재 교시(수업) */
.band.current::before{opacity:1}
.band.current{box-shadow:0 4px 10px rgba(0,120,212,.14), 0 14px 34px rgba(0,120,212,.12),
  0 0 0 1px rgba(0,120,212,.22)}
.band.current .b-subj,
.band.current .b-sj{font-weight:750}
.band.current .b-line2{color:var(--ink-1)}
.band.current .pnum{background:var(--a-swap); color:#fff}
.band.canc-now .pnum, .band.idle-now .pnum{background:var(--pnum-idle); color:var(--ink-2)}
.band.is-next .pnum{box-shadow:inset 0 0 0 1.5px var(--a-swap); color:var(--c-swap)}
/* .55 는 일과 종료 후(전 교시가 past) 화면 전체를 죽인다 — 카드감은 남기고 내용만 물린다 */
.band.past .b-inner{opacity:.7}

/* --- 변동: 보강=초록, 교체(맞교환 포함)=파랑, 취소·공강=빨강 (2026-07-14 용어 체계) --- */
/* ★ 가독성 보강(2026-09-22 사용자 요청 「변동 색이 옅다」 → 시안 비교 뒤 「A안」 확정):
     ① 변동 카드 = 신호색 1px 테두리. 취소·gone 카드가 **원래 쓰던 문법**(inset 1px)을 보강·교체로
        넓힌 것이다 — 새 장식을 들이지 않는다.
        ⛔ 왼쪽 4px 색 띠는 한 번 넣었다가 뺐다(사용자: 「너무 AI스럽다」) — 둥근 모서리(14px)를
          따라 휘어 괄호처럼 보인다. 되살리지 마라.
        ⛔ 교시 번호 원을 신호색으로 칠하는 안(B)은 기각 — 그 원은 이미 「지금(파랑 채움)」·
          「다음(파랑 테)」을 말하는 자리라 옅은 파랑 원이 「다음 수업」으로 읽힌다.
        `:not(.current)` — 현재 교시는 자기 파랑 링·그림자(.band.current)가 이긴다(같은 box-shadow).
        `:not(.hb)` — 「우리 반」 열은 자기 테두리 규칙(.band.hb …)을 따로 가진다.
     ② 태그 = 색 알약(흰 글자). 높이 18px(줄 16 + 상하 1) — 옛 글자 태그(12.5px × 1.45 ≈ 18.1)
        안쪽이라 우측 스택 예산(theme-css.test 「태그 밴드 우측 스택」)을 한 픽셀도 안 늘린다.
     ③ 교체 틴트 .10 → .14(--t-chg-swap). --t-swap 은 레일·초점·칩이 함께 쓰므로 안 건드린다. */
.st-sub{background-image:repeating-linear-gradient(135deg, var(--t-sub-a) 0 5px, var(--t-sub-b) 5px 11px)}
.st-sub .b-chg{background:var(--c-sub)}
.st-rep{background-image:linear-gradient(var(--t-chg-swap), var(--t-chg-swap))}
.st-rep .b-chg{background:var(--c-swap)}
.st-rep .arrow{color:var(--c-swap)}
.st-sub .arrow{color:var(--c-sub)}
.b-line2 .arrow{margin:0 3px}
.band.st-sub:not(.current):not(.hb){box-shadow:inset 0 0 0 1px rgba(15,123,15,.5)}
.band.st-rep:not(.current):not(.hb),
.band.st-swap:not(.current):not(.hb){box-shadow:inset 0 0 0 1px rgba(0,103,184,.45)}
.st-canc{background:transparent; box-shadow:inset 0 0 0 1px rgba(196,43,28,.5)}
.st-canc .b-chg{background:var(--c-canc)}
.st-canc .b-subj{color:var(--ink-3); font-weight:500}
.st-canc .b-line2{color:var(--ink-3)}
.st-canc.canc-now{box-shadow:inset 0 0 0 1px rgba(196,43,28,.75)}
.st-swap{background-image:linear-gradient(var(--t-chg-swap), var(--t-chg-swap))}
.st-swap .b-chg{background:var(--c-swap)}
.st-swap .arrow{color:var(--c-swap)}
/* gone — 내 수업이 나간 교시(취소) 또는 소멸(공강): 빨강 통일, 배경 없애고 취소선·흐림 */
/* gone 배경: 투명이 아니라 트랙 동색 불투명 — 평상시 시각 동일, A안 겹침(1·2학년 점심 밴드
   위에 얹히는 3학년 취소 카드)에서 밑의 점심 라벨 텍스트 비침만 차단(2c-1b 시각 스모크 발견)
   ★ 위 `.band.st-swap:not(.current):not(.hb)`(0,4,0)가 `.band.gone`(0,2,0)을 파랑 테두리로
     이기므로, gone 은 같은 모양의 선택자로 빨강을 되찾는다. */
.band.gone,
.band.gone.st-swap:not(.current):not(.hb),
.band.gone.st-rep:not(.current):not(.hb),
.band.gone.st-sub:not(.current):not(.hb){background-image:none; background:var(--bg-frame);
  box-shadow:inset 0 0 0 1px rgba(196,43,28,.5)}
.band.gone .b-chg{background:var(--c-canc)}
.band.gone .b-subj,
.band.gone .b-cls,
.band.gone .b-sj{color:var(--ink-3); font-weight:500}
.band.gone .b-line2{color:var(--ink-3)}
/* 옮겨 간 gone(교환·이동 — 짝 있음) = 교체. 취소선·흐림(이 시간엔 내 수업이 없다)은 그대로 두고
   신호색만 파랑으로 바꾼다. (0,3,0) 이상이라 .st-canc.canc-now(0,2,0)의 빨강 테두리도 이긴다. */
.band.gone.moved,
.band.gone.moved.st-swap:not(.current):not(.hb),
.band.gone.moved.st-rep:not(.current):not(.hb),
.band.gone.moved.st-canc{box-shadow:inset 0 0 0 1px rgba(0,103,184,.45)}
.band.gone.moved .b-chg{background:var(--c-swap)}
.band.gone.moved .b-line2 .b-moved{color:var(--c-swap); font-weight:650}
.st-free{background:transparent; box-shadow:none}
.st-free .b-subj{color:var(--ink-2); font-weight:400}
.st-free .pnum{font-weight:400; background:transparent}

/* 2c-1b: 기준과 다른 일과표 블록의 캡션 — 색 축 미사용(회색 텍스트 전용, 기존 토큰 --ink-3) */

/* 진행률(0.1.39) — 밴드 우측(.b-side)의 비어 있던 공간에 항상 표시. 세로 공간을 쓰지 않아
   다음 밴드와 겹치지 않고, 나우칩·태그 '아래'라 나우라인 라벨(우측 상단)과도 안 부딪힌다.
   퍼센트 칩은 **중립색만** 쓴다 — 파랑/초록/앰버/빨강은 보강·교체·취소 신호에 예약돼 있어
   진행률이 그 색을 빌리면 변동으로 오독된다(--pnum-idle 은 교시 원형의 중립 회청색). */
/* 0.1.44: 분수(윗줄) / 퍼센트(아랫줄) 두 줄. 한 줄로 두면 담임 2열에서 .b-side 가
   37→79px 로 불어 본문이 93→52px 로 뭉개진다(그래서 분수를 통째로 숨기고 있었다).
   세로로 쌓으면 폭이 38px 로 유지돼 본문을 한 픽셀도 뺏지 않는다 — 실측. */
.b-prog{display:flex; flex-direction:column; align-items:flex-end; gap:1px;
  white-space:nowrap; margin-top:2px; line-height:1.1; font-variant-numeric:tabular-nums}
/* 후속 ④(2026-09-02): 분수 **위**에 기간 칩 — 그 차시가 속한 구간 이름(승인된 셋) 또는
   「학기 전체」. 색은 중립만 쓴다 — 파랑/초록/앰버/빨강은 보강·교체·취소 신호에 예약돼
   있다(퍼센트 칩과 같은 이유).
   ★★ 판이 두 번 바뀌었다(둘 다 **실기기에서 안 읽힌다**는 사용자 신고, 2026-09-02).
     ① --pnum-idle 바탕 + --ink-3 → 대비 2.89:1. 10px 글자 기준 4.5:1 미달이었다.
     ② 슬레이트 채움 + 흰 글자(목업 B안) → 계산상 7.51:1 인데도 폰에서 여전히 흐리다는 신고.
     ③ **확정: 바탕은 그대로 두고 잉크만 --ink-1 로**(12.54:1) + 굵기 700. 백분율 칩도 같이
        --ink-2 → --ink-1 로 올렸다 — 한쪽만 올리면 그 차이가 위계가 아니라 사고로 보인다.
     교훈: 「신호색을 안 쓴다」와 「읽힌다」는 다른 요구다. 앞의 것만 잠가 두었더니 뒤의 것이
     비어 있었고, **전 스위트가 초록인 채로** 칩이 보이지 않았다. 이제 대비도 함께 잰다
     (theme-css.test.mjs 「AY: 기간 칩은 읽혀야 한다」 — 토큰을 풀어 실제 비를 계산한다).
     ★ 계산한 대비가 기준을 넘겨도 실기기가 아니라고 하면 실기기가 옳다 — ②가 그 사례다.
   ★★ 폭이 이 변경의 진짜 위험이다. .b-side 는 flex:none 이라 **내용이 폭을 정하고**, 늘어난
     만큼 본문(.b-body)을 그대로 뺏는다 — 0.1.44 가 분수·퍼센트를 한 줄로 뒀다가 .b-side 37→79px,
     본문 93→52px 로 뭉갠 그 자리다. 그래서 셋을 함께 건다:
     ⓐ 10px·좌우 4px — 실측(Pretendard·700)으로 승인된 셋이 전부 52.8px + 좌우 4px = 60.8px.
        옛 이름 「중간고사~기말고사」는 81.8px 로 여유가 2.1px 뿐이었다 — 이름을 셋으로 정리하며
        (2026-09-02) 여유가 23.2px 이 됐다. 이름이 길어지면 이 값을 **다시 재라**.
     ⓑ max-width:84px + 말줄임 — 앞으로 더 긴 이름이 오더라도 폭이 그 이상 못 자란다.
     ⓒ **좁은 카드(@container band ≤340px)에서는 칩을 숨긴다** — 담임 2열(창 520px 에서 카드
        194.8px)에서 .b-side 를 38.8px 그대로 두어 본문 92px 을 **한 픽셀도** 안 뺏는다.
        전체 문구는 title 에 남고, 폰(터치)에서는 아래 되돌림 블록이 다시 보인다 —
        `.pg-u`(차시)와 **같은 폭 전략**이고 같은 근거다(터치엔 hover 가 없다). */
/* ★★★ 2026-09-22 C1(사용자 결정) — 구간 이름을 **알약에서 배경 없는 작은 회색 글자**로 낮춘다.
   마감 칩(.b-seal)이 과목명 옆으로 가면서, 구간 이름은 「주인공이 아니라 보조 라벨」이 됐다.
   바탕·패딩·둥근 모서리를 **없애고**(background:none) 11px·500·--ink-3 로 둔다. 퍼센트(94%)는
   그대로 남는다. max-width·말줄임·nowrap 은 폭 상한 잠금이라 그대로 유지한다(이름이 길어져도
   .b-body 를 더 못 뺏는다). 대비는 4.5:1 미만이지만 이건 의도된 2차 라벨이다 — 옛 4.5 잠금은
   「칩」이던 시절의 계약이고 이 결정으로 재정의됐다(theme-css.test.mjs 「AY」 절 참조). */
.b-prog .pg-seg{max-width:84px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  background:none; border-radius:0; padding:0; color:var(--ink-3);
  font-size:11px; font-weight:500; letter-spacing:-.01em}
/* 분수 + 백분율 묶음. 기본은 **세로 둘**(= 0.1.44 조판 그대로 · 간격도 1px 로 같다).
   ★★ 태그가 있는 밴드에서만 pg-fold 가 이것을 **가로 한 줄**로 접는다 — 세로 예산 때문이다:
     밴드는 50분 = 70px 고정, .b-inner 상하 패딩 20px → 내용 예산 **50px**. 태그 밴드의 우측
     스택은 배포 전에 이미 태그18 + 간격2 + 진행률30 = 50px(여유 0.8px, 실측)이라 칩 한 줄을
     더할 자리가 없다. 접으면 태그18 + 2 + 칩12 + 1 + 한줄16 = 49px → .b-inner 65.9px ≤ 70px
     (여유 4.1px — 배포 전 0.8px 보다 오히려 넉넉하다). 실측: 하네스 Chrome · 930×860 · 담임 2열.
   ★ 판정은 JS(timeline.js)가 태그 유무로 한다 — `:has()` 를 쓰면 구형 iOS 에서 조용히 안 걸린다. */
.b-prog .pg-r{display:flex; flex-direction:column; align-items:flex-end; gap:1px}
.b-prog.pg-fold .pg-r{flex-direction:row; align-items:center; gap:4px}
.b-prog .pg-f{display:inline-flex; align-items:baseline; gap:3px}
.b-prog .pg-n{font-size:13px; font-weight:700; color:var(--ink-1)}
.b-prog .pg-t{font-size:12px; color:var(--ink-3)}
/* 카드가 좁으면(담임 2열·창 520px 에서 194.8px) '차시' 두 글자가 .b-side 폭을 넓혀 본문을
   밀어낸다 — 단위만 숨겨 폭을 되돌린다. 규칙은 아래 「카드 폭 축소」 @container 블록에 있다.
   ★ 전체 문구는 title 속성에 남지만 그건 **마우스에서만** 보이는 보완책이다 — 터치엔 hover 가
   없다. 폰에서 이 축소를 되돌리는(=차시를 계속 보여주는) 이유 중 하나가 그것이다(위 ⓓ). */
.b-prog .pg-p{padding:1px 6px; border-radius:9px;
  background:var(--pnum-idle); color:var(--prog-ink); font-size:11.5px; font-weight:600}
/* 좁은 카드에서는 교시배지+학급+과목+태그+진행률이 한 줄을 두고 경쟁한다 — 배지를 줄이고
   여백을 좁힌다. 0.1.44: 진행률 분수를 접던 규칙은 폐지(위 .b-prog 가 두 줄이라 폭을 안 먹는다).
   규칙은 아래 「카드 폭 축소」 @container 블록에 있다. */
/* 지난 교시 흐림은 별도 규칙이 필요 없다 — .b-prog 가 .b-side 안, 즉 .b-inner 안이라
   기존 `.band.past .b-inner{opacity:.55}` 가 그대로 덮는다(옛 '밴드 아래' 카드일 때만
   형제라서 별도 규칙이 필요했다). */

/* 2e: 담임 2열 분할 — 열 컨테이너가 밴드 좌우 오프셋(48/12px)을 대신 진다.
   내부 밴드·점심은 left/right 0 리셋(레인 % 는 열 안에서 그대로 성립).
   스팬 밴드는 .tl 직접 자식이라 기본 오프셋 유지 = 전폭. */
/* 2f-2 B안: 열 머리 아이콘 필 칩 — 1교시 바로 위 하단 정렬(첫 눈금 56px, 칩 27px → top 25px).
   그라데이션·아이콘 원판·소프트 섀도. 색조 = 열 카드 색 계열(범례 역할, 신호색 무사용). */
.tl-col-chip{position:absolute; top:25px; left:0; z-index:2; height:27px;
  display:flex; align-items:center; gap:7px; padding:0 12px 0 5px;
  font-size:12px; font-weight:700; letter-spacing:.01em; color:var(--ink-2);
  background:linear-gradient(180deg,#ffffff,#f3f6fa);
  border-radius:99px; box-shadow:0 1px 3px rgba(16,18,20,.10); pointer-events:none}
.tl-col-chip .chip-dot{flex:none; width:19px; height:19px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:rgba(0,120,212,.10); color:var(--a-swap)}
.tl-col-r .tl-col-chip{background:linear-gradient(180deg,#EBF1F8,#DEE7F2);
  box-shadow:0 1px 3px rgba(52,84,120,.14); color:rgba(52,84,120,.78)}
.tl-col-r .tl-col-chip .chip-dot{background:rgba(52,84,120,.12); color:rgba(52,84,120,.78)}
.tl-col{position:absolute; top:0; bottom:0}
/* 0.1.44: 두 열 폭을 같게. 이전엔 가운데를 '창의 절반'(50%)으로 잡아서
   좌열 = 50% - 52 / 우열 = 50% - 16 로 **우열이 36px 넓었다**(왼쪽은 시각 눈금
   48px 을 비우는데 오른쪽은 12px 만 비우므로). 가운데를 콘텐츠(48~우측 12)의
   절반 = 50% + 18 로 잡으면 두 폭이 50% - 34 로 같아지고 간격 8px 도 그대로다. */
.tl-col-l{left:48px; right:calc(50% - 14px)}
.tl-col-r{left:calc(50% + 22px); right:12px}
.tl2 .tl-col .band, .tl2 .tl-col .lunch{left:0; right:0}

/* ============================================================
   카드 폭 축소 — 재는 것은 조상이 아니라 **카드 자신**이다
   ------------------------------------------------------------
   ⓐ 왜 이렇게 됐나. 과목명·교시 배지·안쪽 패딩·'차시' 단위 넷은 원래 담임(.tl2)이라는
      **역할**에 걸려 있었다. 그래서 담임 칸을 194.8 → 634.8px(비담임 카드의 1.6배)로
      넓혀도 과목명은 14.5px 에 못 박혔고, 반대로 비담임이 창을 좁혀도 16.5px 그대로였다.
      조건을 폭으로 옮겨야 「같은 폭 = 같은 크기」가 성립한다.
   ⓑ 그 다음 판은 **조상**(.tl / .tl-col)을 쟀는데, 그것도 틀렸다. timeline.js 가 겹치는
      수업의 밴드에 인라인 `left:X%;width:Y%` 를 붙이기 때문이다(레인 분할) — 3레인이면
      카드는 조상의 1/3 이라 **카드 폭 ≠ 조상 폭**이다. 조상만 보면 창 930 담임의 3레인
      카드(133.5px)에 16.5px/32px 이 그대로 들어간다. 학년별 시각 차로 실제로 난다.
      **카드 자신**(container:band)을 재면 1열·2열 칸·전폭 스팬·레인 분할이 전부 한 기준으로
      판정되고, 조상 관계에 따른 60px 보정도 필요 없어져 **임계값이 340 하나**로 준다.
   ⓒ B = 340 의 근거(전부 실측):
        · 과목명이 잘리기 시작하는 카드 폭 ≈ 220px → B 는 그보다 120px 위라 **잘리기 전에** 준다.
        · 비담임 창 520 의 카드 폭 397.6px → B 위 → 지금 모습이 그대로 보존된다(회귀 금지).
        · 담임 창 930 의 칸 폭 400.0px → B 위 → 큰 글씨(16.5px)가 켜진다.
        · 담임 창 520 의 칸 폭 194.8px → B 아래 → 현행대로 줄어든다.
   ⓓ **폰은 예외다 — 큰 글씨를 지킨다**(사용자 결정). 축소는 좁은 **데스크톱 2열**을 위한
      보상이지 폰을 위한 게 아니다. 폰에서는 글씨가 큰 편이 낫고 넘침은 말줄임이 받는다.
      게다가 '차시'를 숨기는 보완책이 `title` 툴팁인데 **터치엔 hover 가 없어** 성립하지 않는다.
      실측: 폰 폭 320~430 에서 담임 2열 한 칸은 126~181px(줄어야 한다), 1열·스팬 카드는
      260~370px(안 줄어야 한다). **220px** 이 그 사이를 정확히 가르고, 마침 ⓒ 의 '잘리기
      시작하는 폭'과 같다.
   ★ 안전한 기본값. 두 미디어 쿼리로 갈라 놓으면 어느 쪽에도 안 맞는 기기(스타일러스 등)가
     축소를 **통째로 잃는다**. 그래서 340 축소를 **무조건 깔고**, 터치에서만 220~340 구간을
     기본값으로 **되돌린다**. 미지의 기기는 저절로 340 쪽에 남는다.
   ★★ 되돌림 블록은 축소 블록보다 **뒤**에 와야 한다 — 둘 다 `.band …`(같은 특이도)라
     소스 순서가 판정한다.
   ★★ `.band.hb .b-subj{font-size:13.5px}`(우리 반 열)는 여기 없다 — 그건 폭 보상이 아니라
     의도된 위계(내 수업 = 주체 / 우리 반 = 보조)다. 폭이 넓어져도 그대로 둔다.
   ★★★ `.band.l3 .b-inner`(0,3,0)가 축소·되돌림의 `.band .b-inner`(0,2,0)를 **둘 다 이긴다**
     — 그래서 3줄 밴드 상하 6px 은 어느 경우에도 짝 규칙 없이 유지된다. 옛
     `.tl2 .tl-col .band.l3` 는 이중 기준이 사라져 삭제했다.
   ============================================================ */
@container band (max-width: 340px){
  .band .b-sj{font-size:14.5px}
  .band .b-inner{padding:8px 10px}
  .band .pnum{width:26px; height:26px; font-size:13px}
  .band .b-prog .pg-u{display:none}
  .band .b-prog .pg-seg{display:none}
  .band .b-prog.pg-fold .pg-r{flex-direction:column; align-items:flex-end; gap:1px}
  /* Positive counts get an adjacent status row below the lesson identity.
     Reserve progress/period space and fit identity/status/detail/memo in 70px. */
  .band.has-seal-count .b-inner,
  .band.has-seal-count.l3 .b-inner{padding-top:3px; padding-bottom:3px}
  .band.has-seal-count .b-line1{display:grid; grid-template-columns:max-content max-content 1fr;
    column-gap:5px; row-gap:0; align-items:center; line-height:16px}
  .band.has-seal-count .b-subj{grid-column:1 / -1; width:100%; line-height:16px}
  .band.has-seal-count .b-seal{width:15px; height:15px; padding:0; border-radius:50%; border:0;
    background:var(--a-mine); display:inline-grid; place-items:center; font-size:0; line-height:0}
  .band.has-seal-count .b-seal::before{content:"✓"; font-size:10px; font-weight:900; color:#fff; line-height:1}
  .band.has-seal-count .b-line2,
  .band.has-seal-count .b-memo{font-size:11px; line-height:13px; margin-top:1px}
}
/* C1(2026-09-22)·사용자 결정(2026-09-23): 「출석 마감」 칩이 안 들어가는 아주 좁은 카드
   (폰 담임 2열 ≈135px).
   실측(하네스 Chrome): 카드 200px(앱 520 담임) 본문 97px → 과목 39 + 칩 52 = 91px 로 들어간다
   (칩 오른쪽 -9px = 안 겹침). 카드 135px(폰 390 담임 2열) 본문 32px → 과목이 **이미 0px 로
   완전히 잘린다**(기존 동작). 여기에 글자 칩(52px)을 두면 .b-side(진도) 위로 17px 넘쳐 겹친다.
   → **교시 배지는 남긴다.** 감추면 공강 줄의 교시 번호와 현재 교시 파란 원까지 사라져
     이 앱의 뼈대(교시 강조)가 그 폭에서 통째로 없어진다(사용자가 시안 비교로 반려).
     대신 **칩을 글자 없는 청록 ✓ 동그라미(15px)로 줄여** 자리를 만든다 — 칩 52px → 15px.
   ★ 글자는 DOM 에 그대로 둔다(`font-size:0`) — 화면 읽기는 「출석 마감」을 그대로 읽는다.
   ★ 터치 되돌림 블록(min-width:220px)은 .b-seal 을 안 건드리므로 충돌하지 않는다. */
@container band (max-width: 170px){
  .band .b-seal{width:15px; height:15px; padding:0; border-radius:50%; border:0;
    background:var(--a-mine); display:inline-grid; place-items:center; font-size:0; line-height:0}
  .band .b-seal::before{content:"✓"; font-size:10px; font-weight:900; color:#fff; line-height:1}
}
/* F6(R1 리뷰 · 2026-09-23 사용자 결정 · 시안 `f6B-seal-badge.css`) — 흔한 안드로이드 폭
   360~412 에서 「출석 마감」+「우리 반」 칩이 붙은 **전폭 스팬 카드**(카드 폭 ≤300px)는
   두 칩이 한 줄로 고정된 만큼 반·과목 칸이 360 에서 0px 로 사라진다(칸 안 일반 카드는
   폭 263~278px 이라 같은 줄이지만 `.tl2 >` 가 아니라 안 걸린다).
   → 좁은 **스팬** 카드에서만 마감 칩을 기존 ✓ 배지(15px 청록 동그라미)로 줄인다.
   ★ 선언은 170 분기와 **글자 그대로 같게** 둔다 — 한쪽만 바뀌면 두 배지가 달라진다.
   ★ `.tl2 > .band` 인 이유: 전폭 스팬 카드는 `#tl.tl2` 의 **직계** `.band` 다(칸 안 카드는
     `.tl-col` 안이라 이 선택자에 안 걸린다). 값 300 은 360·375·390 폰의 스팬 카드 폭
     (248·263·278)을 덮고 430(318)·461 이상은 건드리지 않는다.
   ★ 자리: 170 «뒤»·터치 되돌림 «앞»(코디 승인 2026-09-23) — A-T24 ⑶ 의 조건 목록 순서. */
@container band (max-width: 300px){
  .tl2 > .band .b-seal{width:15px; height:15px; padding:0; border-radius:50%; border:0;
    background:var(--a-mine); display:inline-grid; place-items:center; font-size:0; line-height:0}
  .tl2 > .band .b-seal::before{content:"✓"; font-size:10px; font-weight:900; color:#fff; line-height:1}

}
/* 폰(터치)에서만 220~340 구간을 기본값으로 되돌린다 — 위 ⓓ·★ 참조.
   220 미만(담임 2열 한 칸 = 폰에서 126~181px)에서는 되돌리지 않으므로 축소가 그대로 산다.
   ★ 범위 문법(`width > 220px`)이 아니라 `min-width` 를 쓴다 — 컨테이너 쿼리 자체는
     iOS Safari 16.0 부터지만 **범위 문법은 16.4 부터**라, 16.0~16.3 에서는 이 블록이
     통째로 무시돼 폰 예외(사용자 결정)가 조용히 사라진다. 실폭이 220 에 정확히 걸리는
     카드는 없으므로(126~181 / 260~370) 두 표기의 거동 차이도 없다. */
@media (hover: none) and (pointer: coarse){
  @container band (min-width: 220px){
    .band .b-sj{font-size:16.5px}
    .band .b-inner{padding:10px 14px}
    .band .pnum{width:32px; height:32px; font-size:14.5px}
    .band .b-prog .pg-u{display:inline}
    .band .b-prog .pg-seg{display:block}
    .band .b-prog.pg-fold .pg-r{flex-direction:row; align-items:center; gap:4px}
  }
}
.band.hb{background:var(--surface-ours); box-shadow:inset 0 0 0 1px rgba(52,84,120,.10)}
/* 확정 ⑤: 원형 배지 = 내 수업 열 전용. hb 숫자는 슬레이트(--ours-num) 고정 — ★ 2026-09-30 사용자 지시로
   숫자는 **모든 교시에** 나온다(옛 확정 ⑤ 는 「시각이 어긋난 교시만」이었다 · timeline.js hrBandsHtml).
   0.1.44: 원판을 **모든 hb 밴드**에서 지운다. 이전엔 .current 의 파랑 원만 지웠는데,
   기본 .pnum{background:var(--bg-frame)} 이 남아 우리 반 칸(--surface-ours)에 26px 회청색
   원판이 상시 깔렸다(#E7EDF4 vs #E4EBF4 — 3단위 차라 평소엔 흐릿하고 hover 오버레이가
   카드를 어둡게 하면 드러난다). 우리 반 열의 pnum 은 대개 빈 슬롯(정렬용)이라 원판이
   그려질 이유가 없다. 이 규칙이 .band.current/.canc-now/.idle-now 의 배경보다 뒤에 와야
   이긴다(같은 특이도 — 순서로 결정). */
.band.hb .pnum{background:transparent; color:var(--ours-num)}
.band.hb.current:not(:hover)::before{opacity:0}
.band.hb.current .b-line2{color:var(--ink-2)}
.band.hb .b-subj{font-size:13.5px}
.band.hb.st-free{background:var(--surface-ours)}
/* 우리 반 열 변동 틴트(2026-09-09) — 「우리 반 열은 결과만」이던 결정을 뒤집었다(담임에게
   알림은 가는데 시간표엔 표시가 없었다). 색은 내 수업 밴드와 **같은 토큰**을 쓴다.
   ★ 위 `.band.hb{background:…}` 가 단축이라 `.st-sub`/`.st-swap` 의 background-image 를
     none 으로 되돌린다 — (0,2,0) 이라 더 세고 뒤에 온다. 그래서 여기서 되살려야 한다.
     이 두 줄을 지우면 클래스는 붙는데 화면에는 아무 변화가 없다(조용한 소실). */
/* 교체 원과목은 물러난다 — 같은 잉크면 1px 취소선이 안 보여 `<s>체육</s> 자율` 이
   「체육 자율」이라는 한 과목명으로 읽힌다(하네스 실측 2026-09-09). */
.band.hb.st-swap .b-subj s, .band.hb.st-sub .b-subj s{color:var(--ink-3); font-weight:500}
/* 취소 밴드는 원과목이 유일한 정보다 — 흐려지면 안 된다. 주간 격자와 같은 빨강. */
.band.hb.st-canc .b-subj s{color:var(--c-canc); opacity:.8}
.band.hb.st-sub{background-image:repeating-linear-gradient(135deg, var(--t-sub-a) 0 5px, var(--t-sub-b) 5px 11px)}
.band.hb.st-swap{background-image:linear-gradient(var(--t-swap), var(--t-swap))}
/* 취소·이동 밴드 — `.band.hb{box-shadow:…}` 가 (0,2,0) 이라 `.st-canc` 의 빨강 테두리를
   이긴다(위 background 와 같은 함정). 여기서 되살리지 않으면 취소가 보통 밴드로 보인다. */
.band.hb.st-canc{box-shadow:inset 0 0 0 1px rgba(196,43,28,.5)}
.band.hb.st-canc .b-line2{color:var(--c-canc)}
/* 둘째 줄 분류어 낱말(교체·보강·취소) — 색만으로 뜻을 나르지 않기 위해 낱말을 넣었고,
   색은 주간 격자(`.wg-c.swap .s2 b`)와 같은 토큰으로 맞춘다. */
.band.hb.st-swap .b-line2 b{color:var(--c-swap); font-weight:650}
.band.hb.st-sub .b-line2 b{color:var(--c-sub); font-weight:650}

/* 점심 밴드 — **카드가 아니다.**
   흰 카드에 12px 모서리를 두니 수업 카드와 같은 옷이 됐고, 타임라인은 시간 축이라
   11:10~12:00 과 그 다음 교시 사이가 0px 이다. 두 카드가 한 덩어리로 붙어 보였다.
   규칙을 세운다 — **카드가 있으면 수업, 없으면 수업이 없는 시간.** 이미 공강이 그렇게
   그려지고 있어 자연히 맞물린다. 색으로 가르지 않는 이유는 이 앱에서 색이 변동의
   언어이기 때문이다(보강 초록·교체 파랑·취소 빨강·대체수업일 보라). */
.lunch{
  position:absolute; left:48px; right:12px;
  display:flex; align-items:center; justify-content:center; gap:10px; padding:0 11px;
  font-size:12.5px; color:var(--ink-2);
}
.lunch strong{font-weight:600; color:var(--ink-2); letter-spacing:.02em}
.lunch-content{width:100%; min-width:0; display:flex; flex-direction:column}
.lunch-title{display:flex; align-items:center; justify-content:center; gap:10px}
.lunch-menu{color:var(--ink-3); font-weight:400; line-height:17.5px; text-align:center;
  white-space:normal; word-break:keep-all; overflow-wrap:anywhere}
.lunch-covered{visibility:hidden}

/* ---------- red now line ---------- */
.nowline{
  position:absolute; left:34px; right:12px; top:0; height:0;
  pointer-events:none; z-index:4;
  transition:transform 300ms var(--ease-enter);
}
.nl-line{position:absolute; left:7px; right:0; top:-0.75px; height:1.5px; background:var(--red-now)}
.nl-dot{position:absolute; left:0; top:-4px; width:8px; height:8px; border-radius:50%; background:var(--red-now)}
/* Q173 B(2026-10-16) — 첫 카드 전에는 아래, 실제 충돌 뒤에는 그날 내내 위. */
.nl-label{
  --nl-below-gap:8px;
  position:absolute; right:0; bottom:7px; max-width:212px;
  background:var(--red-now); color:#fff; border-radius:4px;
  padding:5px 10px 6px; text-align:right;
  box-shadow:0 2px 6px rgba(217,48,37,.28);
  transition:transform 300ms var(--ease-enter);
}
.nl-label.below{top:var(--nl-below-gap); bottom:auto}
.nl-ctx{display:block; font-size:12px; line-height:1.35; color:rgba(255,255,255,.88); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.nl-cd{display:block; font-size:14px; line-height:1.4; font-weight:600; letter-spacing:.01em; white-space:nowrap}

/* ============================================================
   학급 시간표 — 헤어라인 행 (탈카드, 구 학급 탭 목업 이식)
   ------------------------------------------------------------
   .pnum 은 오늘(타임라인) 탭에서 이미 원형 배지로 쓰이므로(위 `.pnum{…border-radius:50%}` 규칙),
   여기선 .period .pnum 으로 스코프해 컨테이너 레이아웃만 재정의하고
   숫자/시각은 .pnum .n · .pnum .t 로 별도 스타일한다(충돌 방지).
   ============================================================ */
.page-h{display:flex; align-items:baseline; gap:8px; padding:11px 14px; border-bottom:1px solid var(--hair)}
.page-h h1{font-size:16px; font-weight:700; letter-spacing:-.01em}
.page-h .sub{font-size:13px; color:var(--ink-2)}

.toolbar{display:flex; align-items:center; gap:8px; padding:10px 14px; flex-wrap:wrap; font-size:13.5px; color:var(--ink-2)}
.toolbar select{
  font-family:inherit; font-size:14px; font-weight:600; color:var(--ink-1);
  background:#fff; cursor:pointer;
  border:1px solid var(--hair); border-radius:7px; padding:6px 10px;
}
.toolbar select:focus-visible{outline:none; border-color:var(--c-swap); box-shadow:0 0 0 3px var(--t-swap)}

.period-list{display:flex; flex-direction:column; overflow-y:auto}
.period{display:flex; align-items:center; gap:12px; padding:11px 14px; border-bottom:1px solid var(--hair)}
.period:last-child{border-bottom:0}
.period .pnum{flex:none; width:44px; display:flex; flex-direction:column; align-items:center; gap:2px}
.pnum .n{font-size:19px; font-weight:600}
.pnum .t{font-size:11px; color:var(--ink-2)}
.pbody{flex:1; min-width:0}
.subj{font-size:14.5px; font-weight:600}
.meta{color:var(--ink-2); font-size:13px}
.chip{
  display:inline-flex; align-items:center;
  font-size:11.5px; font-weight:600; padding:2px 7px; border-radius:4px;
  background:var(--t-swap); color:var(--c-swap);
}
/* ★ 2026-09-23 W1(담임 폰 「한 칸 보기」 아크) — 전폭 스팬 카드의 「우리 반」 칩이 세로로
   꺾이던 결함. `.b-line1` 은 flex 라 `.chip` 이 flex 항목이 되는데, `min-width:0`·말줄임으로
   과목명(.b-subj)이 먼저 줄어드는 동안에도 칩은 폭을 잃어 3줄(375·390 높이 46px)·
   2줄(430·460·461 높이 32px)로 접혔다. 520 이상에서는 18px 한 줄이었다(실측).
   같은 줄의 선례 `.chip.ex-role` 과 같은 처방을 줄 안 칩 전체에 건다.
   ★ 폭이 아니라 «줄 안 칩» 자체의 계약이라 460 블록 «밖»(전 폭)에 둔다 — 마감 칩이 붙은
     전폭 스팬 카드는 461 이상에서도 같은 줄을 쓴다. */
.b-line1 .chip{flex:none; white-space:nowrap}

/* ---------- 준비 중 자리표시(다른 탭 클릭 시) ---------- */
.placeholder{
  flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center; padding:24px; gap:6px; color:var(--ink-3);
}
.placeholder .ph-ic{
  width:52px; height:52px; border-radius:14px; margin-bottom:6px;
  background:var(--surface); box-shadow:0 1px 3px rgba(16,18,20,.08);
  display:flex; align-items:center; justify-content:center; color:var(--a-swap);
}
.placeholder h2{font-size:16px; font-weight:600; color:var(--ink-1); letter-spacing:-.01em}
.placeholder p{font-size:13px; color:var(--ink-2); line-height:1.5}

/* ============================================================
   변동 알림 다이얼로그 — 전면 다크 (정본 공통 블록 그대로)
   ============================================================ */
.alert-smoke{
  position:absolute; inset:0; z-index:30;
  background:rgba(0,0,0,.44);
  display:flex; align-items:center; justify-content:center;
  padding:24px;
  opacity:0; visibility:hidden;
  transition:opacity 160ms ease, visibility 0s linear 160ms;
}
.alert-smoke.open{opacity:1; visibility:visible; transition:opacity 160ms ease}
.alert-dlg{
  width:100%; max-width:372px; max-height:560px;
  background:#221E19; color:#FAF8F4;
  border-radius:10px;
  box-shadow:0 32px 64px rgba(0,0,0,.38), 0 2px 21px rgba(0,0,0,.22);
  display:flex; flex-direction:column; overflow:hidden;
  opacity:0; transform:scale(.94);
  transition:opacity 180ms ease, transform 220ms cubic-bezier(.1,.9,.2,1);
}
.alert-smoke.open .alert-dlg{opacity:1; transform:scale(1)}
.ad-body{padding:22px 24px 14px; overflow-y:auto; scrollbar-width:thin; scrollbar-color:rgba(250,248,244,.3) transparent}
.ad-body::-webkit-scrollbar{width:8px}
.ad-body::-webkit-scrollbar-thumb{background:rgba(250,248,244,.25); border-radius:4px}
.ad-title{font-size:20px; line-height:1.3; font-weight:700; letter-spacing:-.01em}
.ad-caption{font-size:13px; color:rgba(250,248,244,.55); margin-top:3px}
.ad-list{list-style:none; margin-top:10px}
.ad-item{display:flex; align-items:flex-start; gap:12px; padding:12px 0; border-top:1px solid rgba(250,248,244,.12)}
.ad-item:first-child{border-top:0}
/* 분류어 배지 — 머리 **끝**에 붙는 인라인 조각(2026-09-09). 옛 좌측 열 배치
   (flex:none; min-width:46px)는 은퇴했다: 사용자가 확정한 어순이 「… 1교시 교체」라
   분류어가 머리 끝에 와야 한다. 색은 변동 3색 언어 그대로 — 넷째 색을 만들지 않는다. */
.ad-kind{
  display:inline-block; margin-left:6px; vertical-align:1px;
  font-size:12px; font-weight:700; letter-spacing:.01em;
  padding:1px 7px 2px; border-radius:4px;
}
.ad-kind.k-sub{color:#6CCB5F; background:rgba(108,203,95,.16)}
.ad-kind.k-canc{color:#FF8A80; background:rgba(255,138,128,.16)}
.ad-kind.k-swap{color:#6CB8FF; background:rgba(108,184,255,.16)}
.ad-text{flex:1; min-width:0}
/* word-break:keep-all — 한글은 기본값에서 음절 아무 데서나 끊긴다(실측: `체육2(오승 / 환)`).
   어절을 지키면 「과목(교사)」가 한 덩어리로 남고 ` → ` 의 공백에서만 줄이 넘어간다.
   ★ overflow-wrap:anywhere 는 짝이다 — keep-all 만 두면 줄보다 넓은 한 덩어리가 상자를
     넘쳐 .alert-dlg 의 overflow:hidden 에 잘린다(실측 33.9px). anywhere 는 달리 방법이
     없을 때만 끊으므로 어절 보호를 무르지 않는다. */
.ad-t1{display:block; font-size:15px; font-weight:600; letter-spacing:-.01em; line-height:1.4; word-break:keep-all; overflow-wrap:anywhere}
.ad-t2{display:block; font-size:13px; line-height:1.45; color:rgba(250,248,244,.62); margin-top:2px; word-break:keep-all; overflow-wrap:anywhere}
.ad-footer{
  flex:none; padding:14px 24px;
  border-top:1px solid rgba(250,248,244,.12);
  background:rgba(250,248,244,.04);
  display:flex; justify-content:flex-end; gap:8px;
}
.ad-ok{
  font-family:inherit; font-size:15px; font-weight:600; letter-spacing:-.01em;
  padding:7px 26px; border:0; border-radius:6px; cursor:pointer;
  background:#FAF8F4; color:#221E19;
  transition:background-color 150ms ease;
}
.ad-ok:hover{background:#EFEAE2}
.ad-ok:active{background:#E3DDD2}
.ad-ok:focus-visible{outline:2px solid #6CB8FF; outline-offset:2px}
.ad-ok.ghost{background:transparent; color:rgba(250,248,244,.7); box-shadow:inset 0 0 0 1px rgba(250,248,244,.25)}

/* ============================================================
   로그인 / 교사선택 모달 — 밝은 Mica 표면 (정본 그대로)
   ============================================================ */
.sheet-smoke{
  position:absolute; inset:0; z-index:40;
  background:rgba(0,0,0,.44);
  display:flex; align-items:center; justify-content:center; padding:24px;
  opacity:0; visibility:hidden;
  transition:opacity 160ms ease, visibility 0s linear 160ms;
}
.sheet-smoke.open{opacity:1; visibility:visible; transition:opacity 160ms ease}
.sheet{
  width:100%; max-width:344px;
  background:var(--surface); color:var(--ink-1);
  border-radius:10px;
  box-shadow:0 28px 56px rgba(16,18,20,.30), 0 2px 12px rgba(16,18,20,.16);
  overflow:hidden;
  opacity:0; transform:scale(.95) translateY(6px);
  transition:opacity 170ms ease, transform 210ms cubic-bezier(.1,.9,.2,1);
}
.sheet-smoke.open .sheet{opacity:1; transform:none}
.sheet-body{padding:22px 22px 6px}
.sheet-app{font-size:12px; font-weight:600; letter-spacing:.01em; color:var(--a-swap)}
.sheet-title{font-size:19px; font-weight:700; letter-spacing:-.01em; margin-top:3px}
.sheet-desc{font-size:13px; line-height:1.5; color:var(--ink-2); margin-top:6px}
.field{margin-top:14px}
.field label{display:block; font-size:12px; font-weight:600; color:var(--ink-2); margin-bottom:5px}
.field input, .field select{
  width:100%; font-family:inherit; font-size:14px; color:var(--ink-1);
  padding:9px 11px; border:1px solid rgba(16,18,20,.18); border-radius:6px;
  background:#fff; letter-spacing:-.01em;
  transition:border-color 150ms ease, box-shadow 150ms ease;
}
.field input:focus, .field select:focus{
  outline:none; border-color:var(--a-swap); box-shadow:0 0 0 3px rgba(0,120,212,.14);
}
.sheet-err{font-size:12.5px; color:var(--c-canc); min-height:16px; margin-top:8px; white-space:pre-line}
.sheet-foot{
  display:flex; justify-content:flex-end; gap:8px;
  padding:12px 22px 18px;
}
.sbtn{
  font-family:inherit; font-size:14px; font-weight:600; letter-spacing:-.01em;
  padding:8px 16px; border-radius:6px; cursor:pointer; border:1px solid transparent;
  transition:background-color 150ms ease, border-color 150ms ease;
}
.sbtn.ghost{background:transparent; border-color:rgba(16,18,20,.16); color:var(--ink-2)}
.sbtn.ghost:hover{background:rgba(16,18,20,.05)}
.sbtn.primary{background:var(--a-swap); color:#fff}
.sbtn.primary:hover{background:#0069be}
.sbtn.primary:active{background:#005ba6}
.sbtn:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}

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

/* ============================================================
   주간 시간표 (D2) — 스코프: .wk-grid 하위 또는 wk- 접두
   목업 정본 screen-week.html 이식. 교시 라벨은 번호만(열 32px).
   ============================================================ */
.wk-nav{display:inline-flex; align-items:center; gap:2px; margin-left:auto}
.wk-btn{
  flex:none; min-width:24px; height:24px; border-radius:6px; padding:0 4px;
  border:1px solid transparent; background:transparent; color:var(--ink-2);
  display:inline-flex; align-items:center; justify-content:center; cursor:pointer;
  font-family:inherit;
  transition:background-color 150ms ease, border-color 150ms ease;
}
.wk-btn:hover{background:rgba(16,18,20,.05); border-color:var(--hair)}
.wk-btn:focus-visible{outline:2px solid var(--a-swap); outline-offset:1px}
.wk-btn.wk-cur{font-size:12px; font-weight:600; color:var(--a-swap); padding:0 8px}
.wk-fail{
  flex:none; display:flex; align-items:center; gap:10px; padding:6px 14px;
  font-size:12.5px; color:#7a4a00; background:rgba(157,93,0,.10);
  border-bottom:1px solid var(--hair);
}
.wk-fail button{
  font-family:inherit; font-size:12px; font-weight:600; cursor:pointer;
  padding:2px 10px; border-radius:5px; border:1px solid rgba(157,93,0,.35);
  background:transparent; color:#7a4a00;
}
.wk-retry{
  font-family:inherit; font-size:13.5px; font-weight:600; cursor:pointer; margin-top:10px;
  padding:6px 18px; border-radius:6px; border:1px solid rgba(16,18,20,.14);
  background:#fdfdfc; color:var(--ink-1);
}
.wk-retry:hover{background:#f4f5f4}
.wk-scroll{flex:1; overflow:auto; scrollbar-width:thin; scrollbar-color:rgba(16,18,20,.22) transparent}
.wk-scroll::-webkit-scrollbar{width:8px; height:8px}
.wk-scroll::-webkit-scrollbar-thumb{background:rgba(16,18,20,.18); border-radius:4px; border:2px solid transparent; background-clip:padding-box}
.wk-grid{
  display:grid;
  grid-template-columns:32px repeat(5, minmax(62px, 1fr));
  min-width:344px; position:relative;
}
.wk-grid > *{border-right:1px solid var(--hair-2); border-bottom:1px solid var(--hair-2)}
.wk-grid > *:nth-child(6n+1){border-left:1px solid var(--hair-2)}
.wk-grid .hd{
  position:sticky; top:0; z-index:4; background:var(--bg-frame);
  padding:7px 4px 6px; text-align:center; border-bottom:1px solid var(--hair);
}
.wk-grid .hd .dow{font-size:13px; font-weight:700; letter-spacing:.01em; color:var(--ink-1)}
/* 0.1.24: 요일 줄 = 3열 그리드(1fr|요일|1fr) — 오늘 pill 이 요일을 왼쪽으로 밀던 문제.
   요일(.dw)은 정확히 중앙 고정, pill 은 오른쪽 트랙(밀림·겹침 불가). corner(교시)는 제외 */
.wk-grid .hd:not(.corner) .dow{display:grid; grid-template-columns:minmax(0,1fr) max-content minmax(0,1fr); align-items:center}
.wk-grid .hd .dow .dw{grid-column:2}
.wk-grid .hd .dow .wk-pill{grid-column:3; justify-self:start; white-space:nowrap}
.wk-grid .hd .dt{display:block; font-size:11px; color:var(--ink-3); margin-top:1px}
.wk-grid .hd.corner{left:0; z-index:6}
.wk-grid .hd.corner .dow{font-size:11px; color:var(--ink-3)}
/* 0.1.25: is-today 를 이웃 헤더 위로 — 오늘 pill 이 셀을 살짝 넘칠 때 뒤 요일의 불투명
   sticky 배경이 pill 을 덮어 잘려 보이던 문제(corner 는 6으로 유지해 좌측 고정 우선) */
.wk-grid .hd.is-today{background:linear-gradient(var(--today-tint), var(--today-tint)), var(--bg-frame); z-index:5}
.wk-grid .hd.is-today .dow{color:var(--a-swap)}
.wk-pill{
  display:inline-block; margin-left:4px; vertical-align:middle;
  font-size:9.5px; font-weight:700; letter-spacing:.02em; color:#fff;
  background:var(--a-swap); border-radius:999px; padding:1px 5px 2px;
}
.wk-grid .pl{
  position:sticky; left:0; z-index:3; background:var(--bg-frame);
  display:flex; align-items:center; justify-content:center; padding:6px 0;
}
.wk-grid .pl .pn{font-size:15px; font-weight:600; color:var(--ink-2); line-height:1}
.wk-grid .cell{
  position:relative; min-height:56px;
  display:flex; flex-direction:column; justify-content:center; gap:2px;
  align-items:center; text-align:center;   /* 0.1.24: 셀 내용 가운데 정렬(사용자 피드백) */
  padding:6px 7px 6px 9px;
  transition:padding-bottom 150ms ease;    /* 배지 출현/소멸 시 행 높이 점프 완충 */
}
.wk-grid .cell.c-off{background:rgba(16,18,20,.028)}

/* 주간 탭 2단 구조(2d) — 교과·학급 섹션 헤딩 + 학급 섹션 압축 마커 */
.wk-sec{font-size:14px;font-weight:700;color:var(--ink-2);margin:18px 2px 8px}
.wk-sec-h{display:flex;align-items:center;gap:10px;margin:18px 2px 8px}
.wk-sec-h .wk-sec{margin:0}

/* ============================================================
   2h 주간 시간표(.wg-) — B1 소프트 시트
   정본 mockups/school-week-2h-final.html (세로선 없음·행 헤어라인만·오늘 열 흰 밴드
   승격·4교시 뒤 여백·변동 글자색+취소선·나우 요소 없음·셀 가운데 정렬[2i-2]). 전 규칙 .wg- 스코프.
   free 탭은 기존 .wk-grid 문법 그대로(공유 금지).
   ============================================================ */
.wg-search{position:relative; z-index:10; gap:8px; flex-wrap:nowrap; padding:7px 11px;
  border:1px solid var(--hair-strong); border-radius:9px; background:var(--surface);
  box-shadow:inset 0 1px 2px rgba(16,18,20,.04)}
.wg-search svg{color:var(--a-swap); flex:none}
.wg-search input{flex:1; min-width:0; border:0; background:transparent; font:inherit;
  font-size:12px; color:var(--ink-1)}
.wg-search input:focus{outline:none}
.wg-search input::placeholder{color:var(--ink-2)}
.wg-search .free-sugg{left:0; right:0; min-width:0}
.wg-count{margin-top:6px}
.wg-count .delta-count{font-size:11px; font-weight:600; color:var(--ink-2)}
.wg-range{font-size:12.5px; font-weight:650; color:var(--ink-1); letter-spacing:.01em; padding:0 2px}
.wk-btn.wk-range{padding:0}
.wk-btn.wk-range:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}
/* U10(D13·D14) 자체 달력 팝오버 — mountDatepick(datepick.js)가 트리거 아래 fixed 로 붙인다.
   관리자 웹 dsDate(다른 트리·다른 시각 정본, 공통부 §5-6)를 베끼지 않고 앱 자체 토큰만 쓴다. */
.dp-wrap{z-index:25}   /* 레일(z 20) 위 — 팝오버는 트리거가 레일 옆이어도 안 가려야 한다 */
.dp-pop{width:236px; background:var(--surface); border:1px solid var(--hair);
  border-radius:10px; box-shadow:0 10px 28px rgba(16,18,20,.18); padding:10px; font-size:12.5px}
.dp-head{display:flex; align-items:center; justify-content:space-between; margin-bottom:6px}
.dp-nav{border:0; background:none; cursor:pointer; font-size:15px; line-height:1;
  color:var(--ink-2); padding:5px 9px; border-radius:6px}
.dp-nav:hover{background:var(--today-tint)}
.dp-nav:focus-visible{outline:2px solid var(--a-swap); outline-offset:1px}
.dp-ym{font-weight:700; color:var(--ink-1); font-size:12.5px}
.dp-dow{display:grid; grid-template-columns:repeat(7,1fr); text-align:center; font-size:10.5px;
  color:var(--ink-3); font-weight:600; margin-bottom:2px}
.dp-grid{display:grid; gap:1px}
.dp-row{display:grid; grid-template-columns:repeat(7,1fr)}
.dp-day{border:0; background:none; cursor:pointer; font:inherit; font-size:12px;
  color:var(--ink-1); padding:6px 0; border-radius:6px; text-align:center}
.dp-day:hover{background:var(--today-tint)}
.dp-day:focus-visible{outline:2px solid var(--a-swap); outline-offset:-1px}
.dp-day.out{color:var(--ink-3)}
/* 토요일 파랑 · 일요일 빨강(2026-09-22 사용자 요청 · 한국 달력 관례). 앞뒤 달 패딩 칸은 색을
   지키고 흐리게만 — 회색으로 덮으면 열의 색 리듬이 끊긴다. 오늘·선택·범위 밖은 아래 규칙이 이긴다. */
.dp-day.sun{color:var(--c-canc)}
.dp-day.sat{color:var(--c-swap)}
.dp-day.hol{color:var(--c-canc)}          /* 휴일(학사일정 이름 있는 쉬는 날) — 토요일 휴일도 빨강 */
.dp-day.out.sun,.dp-day.out.sat,.dp-day.out.hol{opacity:.5}
.dp-dow .sun{color:var(--c-canc)}
.dp-dow .sat{color:var(--c-swap)}
.dp-day.today{font-weight:700; color:var(--a-swap)}
.dp-day.cur{background:var(--a-swap); color:#fff; font-weight:700}
.dp-day.dis{color:var(--ink-3); opacity:.4; cursor:not-allowed}
.dp-foot{display:flex; justify-content:space-between; margin-top:8px; padding-top:8px;
  border-top:1px solid var(--hair)}
.dp-today,.dp-close{border:0; background:none; cursor:pointer; font-size:11.5px;
  font-weight:600; color:var(--a-swap); padding:4px 8px; border-radius:6px}
.dp-today:hover,.dp-close:hover{background:var(--today-tint)}
.wg-sec{display:flex; align-items:center; gap:7px; margin:14px 14px 5px; font-size:11px;
  font-weight:700; color:var(--ink-3); letter-spacing:.04em}
.wg-sec .chip{font-size:10px; font-weight:600; color:var(--ink-2); background:var(--surface);
  border-radius:99px; padding:2px 8px; box-shadow:0 1px 1.5px rgba(16,18,20,.07); letter-spacing:0}
.wg-back{margin-left:auto; border:0; cursor:pointer; font-size:10.5px; font-weight:600;
  color:var(--a-swap); background:var(--surface); border-radius:99px; padding:3px 9px;
  box-shadow:0 1px 1.5px rgba(16,18,20,.08)}
.wg-grid{display:grid; grid-template-columns:30px repeat(5,minmax(0,1fr));
  font-size:11.5px; padding:0 14px 8px}
.wg-h{padding:6px 0 7px; text-align:center; font-size:12.5px; font-weight:700; color:var(--ink-1)}
.wg-h small{display:block; font-size:10px; font-weight:500; color:var(--ink-3); margin-top:1px}
.wg-h.td{color:var(--a-swap); background:rgba(255,255,255,.55); border-radius:9px 9px 0 0}
.wg-h.td small{color:rgba(0,120,212,.75)}
.wg-h.vd{color:var(--c-day)}
.wg-h.vd small{color:var(--c-day); opacity:.75}
.wg-pn{display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:600;
  color:var(--ink-3); border-top:1px solid var(--hair)}
.wg-c{position:relative; min-height:44px; min-width:0; padding:5px 4px 4px; text-align:center;
  border-top:1px solid var(--hair)}
.wg-c.off{background:rgba(16,18,20,.028)}
.wg-c.td{background:rgba(255,255,255,.55)}
.wg-c.td.last{border-radius:0 0 9px 9px}
.wg-c .s1{font-size:12.5px; font-weight:650; letter-spacing:-.01em; line-height:1.15; color:var(--ink-1)}
.wg-c .s2{font-size:10.5px; color:var(--ink-2); margin-top:1px}
.wg-c .s1 s{color:var(--ink-3); font-weight:500; text-decoration-thickness:1px}
.wg-c.sub .s1{color:var(--c-sub)}
.wg-c.sub .s2 b{color:var(--c-sub); font-weight:650}
.wg-c.swap .s1{color:var(--a-swap)}
.wg-c.swap .s2 b{color:var(--a-swap); font-weight:650}
.wg-c.canc .s1{color:var(--c-canc)}
.wg-c.canc .s1 s{color:var(--c-canc); opacity:.8}
.wg-c.canc .s2 b{color:var(--c-canc); font-weight:650}
/* 내 수업 표식 — 시안 A1(사용자 택일 2026-10-01): 배경 tint + 내 이름 글자(`.me-nm` · 아래 .sc-c 블록의
   공통 규칙). 옛 시안 C(U11 · 09-15)의 왼쪽 테두리·「내」 배지는 걷었다(「촌스럽고 AI스럽다」 지적).
   이 격자에는 변동 tint 가 없어(.wg-c.sub/.swap 는 글자색만 바꾼다) 배경 우선순위 충돌이 없다.
   `.wg-c.td`(오늘 열) 보다 뒤라 오늘 열에서도 tint 가 이긴다. */
.wg-c.me{background:var(--t-mine)}
.wg-more{position:absolute; right:5px; bottom:4px; font-size:10px; font-weight:700; color:var(--ink-3)}
/* 0.1.43: 점심 구분(.wg-gap 12px 빈 행 + 5교시 .al 강화 헤어라인) 폐지 — 주간 격자는
   교시 순서만 보는 표라 점심 경계가 정보를 주지 않고, 빈 행이 4교시에 붙어 보였다. */

/* ============================================================
   변동 히스토리 (D3) — 스코프: hist- 접두 또는 .hist-scroll 하위
   목업 정본 screen-history.html 이식. 종류 틴트는 앱 기존 토큰 사용.
   ============================================================ */
.hist-seg{display:inline-flex; gap:2px; margin-top:10px; padding:2px; border-radius:8px; background:rgba(16,18,20,.05)}
.hist-seg button{
  font-family:inherit; font-size:12.5px; font-weight:600; letter-spacing:-.01em;
  color:var(--ink-2); border:0; background:transparent; border-radius:6px;
  padding:4px 12px; cursor:pointer; transition:background-color 140ms ease, color 140ms ease;
}
.hist-seg button.on{background:var(--surface); color:var(--ink-1); box-shadow:0 1px 2px rgba(16,18,20,.12)}
.hist-seg button:focus-visible{outline:2px solid var(--a-swap); outline-offset:1px}
.hist-filters{display:flex; align-items:center; gap:6px; margin-top:10px; flex-wrap:wrap}
.hist-chip{
  display:inline-flex; align-items:center; gap:5px;
  font-family:inherit; font-size:12.5px; font-weight:600; letter-spacing:-.01em;
  color:var(--ink-2); cursor:pointer;
  padding:5px 10px 5px 9px; border-radius:999px;
  border:1px solid var(--hair); background:var(--surface);
  transition:background-color 140ms ease, border-color 140ms ease, color 140ms ease;
}
.hist-chip .cn{
  font-size:11px; font-weight:700; line-height:1; padding:1px 5px; border-radius:999px;
  background:rgba(16,18,20,.06); color:var(--ink-3);
}
.hist-chip:hover{border-color:rgba(16,18,20,.18); color:var(--ink-1)}
.hist-chip:focus-visible{outline:2px solid var(--a-swap); outline-offset:1px}
.hist-chip[data-f="all"].on{background:var(--a-swap); border-color:var(--a-swap); color:#fff}
.hist-chip[data-f="all"].on .cn{background:rgba(255,255,255,.22); color:#fff}
.hist-chip[data-f="sub"].on{background:var(--t-sub); border-color:rgba(15,123,15,.4); color:var(--c-sub)}
.hist-chip[data-f="rep"].on{background:var(--t-swap); border-color:rgba(0,103,184,.4); color:var(--c-swap)}
.hist-chip[data-f="canc"].on{background:var(--t-canc); border-color:rgba(196,43,28,.4); color:var(--c-canc)}
.hist-chip[data-f="sub"].on .cn{background:rgba(15,123,15,.85); color:#fff}
.hist-chip[data-f="rep"].on .cn{background:rgba(0,103,184,.85); color:#fff}
.hist-chip[data-f="canc"].on .cn{background:rgba(196,43,28,.85); color:#fff}
.hist-scroll{flex:1; min-height:0; overflow-y:auto; overflow-x:hidden; padding:0 0 16px; scrollbar-width:thin; scrollbar-color:rgba(16,18,20,.22) transparent}
.hist-scroll::-webkit-scrollbar{width:8px}
.hist-scroll::-webkit-scrollbar-track{background:transparent}
.hist-scroll::-webkit-scrollbar-thumb{background:rgba(16,18,20,.18); border-radius:4px; border:2px solid transparent; background-clip:padding-box}
.hist-scroll .ghead{
  position:sticky; top:0; z-index:2;
  display:flex; align-items:baseline; gap:8px;
  padding:13px 14px 6px 15px;
  background:linear-gradient(var(--bg-frame) 78%, rgba(231,237,244,0));
}
.hist-scroll .gdate{font-size:12.5px; font-weight:700; letter-spacing:-.01em; color:var(--ink-1)}
.hist-scroll .today-dot{
  display:inline-block; width:6px; height:6px; border-radius:50%;
  background:var(--red-now); margin-right:5px; vertical-align:1px;
}
.hist-scroll .gsub{font-size:12px; color:var(--ink-3)}
.hist-scroll .gcount{margin-left:auto; font-size:11.5px; font-weight:600; color:var(--ink-3)}
.hist-scroll .hrow{
  position:relative;
  display:flex; align-items:flex-start; gap:11px;
  padding:11px 12px 11px 15px;
  border-bottom:1px solid var(--hair);
}
.hist-scroll .hrow::before{content:''; position:absolute; left:0; top:0; bottom:0; width:3px; opacity:.9}
.hist-scroll .hrow.k-sub::before{background:var(--c-sub)}
.hist-scroll .hrow.k-rep::before{background:var(--c-swap)}
.hist-scroll .hrow.k-swap::before{background:var(--c-swap)}
.hist-scroll .hrow.k-canc::before{background:var(--c-canc)}
.hist-scroll .hper{flex:none; width:38px; padding-top:1px; display:flex; flex-direction:column; align-items:center; gap:1px}
.hist-scroll .hper .num{font-size:19px; font-weight:600; line-height:1; color:var(--ink-1); font-variant-numeric:tabular-nums}
.hist-scroll .hper .lab{font-size:10px; font-weight:500; color:var(--ink-3)}
.hist-scroll .hbody{flex:1; min-width:0}
.hist-scroll .hline1{display:flex; align-items:center; gap:7px; min-width:0}
.hist-scroll .kind-chip{
  flex:none; display:inline-flex; align-items:center; gap:4px;
  font-size:11.5px; font-weight:700; letter-spacing:.01em;
  padding:2px 8px 2px 6px; border-radius:5px;
}
.hist-scroll .kind-chip svg{width:12px; height:12px; display:block}
.hist-scroll .k-sub .kind-chip{color:var(--c-sub); background:var(--t-sub)}
.hist-scroll .k-rep .kind-chip{color:var(--c-swap); background:var(--t-swap)}
.hist-scroll .k-swap .kind-chip{color:var(--c-swap); background:var(--t-swap)}
.hist-scroll .k-canc .kind-chip{color:var(--c-canc); background:var(--t-canc)}
.hist-scroll .hsubj{font-size:14.5px; font-weight:600; letter-spacing:-.01em; color:var(--ink-1); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.hist-scroll .k-canc .hsubj{color:var(--ink-3)}
.hist-scroll .k-canc .hsubj s{text-decoration-thickness:1px; text-decoration-color:rgba(196,43,28,.7)}
.hist-scroll .hchange{display:flex; align-items:center; gap:6px; margin-top:5px; font-size:13px; color:var(--ink-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.hist-scroll .hchange .seg{display:inline-flex; align-items:center; gap:5px}
.hist-scroll .hchange .p-old{color:var(--ink-3)}
.hist-scroll .hchange .p-new{color:var(--ink-1); font-weight:600}
.hist-scroll .hchange .mv{flex:none; display:flex; color:var(--ink-3)}
.hist-scroll .k-swap .hchange .mv{color:var(--c-swap)}
.hist-scroll .k-rep .hchange .mv{color:var(--c-swap)}
.hist-scroll .k-sub .hchange .mv{color:var(--c-sub)}
.hist-scroll .hchange .tail{color:var(--ink-2)}
.hist-scroll .hmeta{margin-top:4px; font-size:12.5px; color:var(--ink-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.hist-scroll .hrecv{
  flex:none; align-self:flex-start; text-align:right; padding-top:2px;
  display:flex; flex-direction:column; align-items:flex-end; gap:1px;
}
.hist-scroll .hrecv .rt{font-size:13px; font-weight:600; color:var(--ink-2); font-variant-numeric:tabular-nums; letter-spacing:.01em; white-space:nowrap}
.hist-scroll .hrecv .rl{font-size:10px; color:var(--ink-3)}
.hist-empty{padding:40px 20px; text-align:center; color:var(--ink-3); font-size:13px; line-height:1.6}
.hist-more{
  display:block; margin:14px auto 6px; font-family:inherit; cursor:pointer;
  font-size:13px; font-weight:600; color:var(--a-swap);
  padding:7px 18px; border-radius:6px; border:1px solid rgba(0,120,212,.3); background:transparent;
}
.hist-more:hover{background:rgba(0,120,212,.06)}
.hist-endnote{padding:14px; text-align:center; font-size:12px; color:var(--ink-3)}

/* ============================================================
   전 교사 시간표 + 공통 공강 찾기 (D4) — 스코프: all- 및 free- 접두.
   주간 그리드 셀 문법(.wk-grid .cell .c-off .c-free .col-today)은 D2 재사용.
   ============================================================ */
.all-wknav{display:inline-flex; align-items:center; gap:4px; font-size:12px;
  margin-left:auto}
.all-wknav button{border:1px solid var(--hair); background:var(--surface);
  border-radius:6px; padding:3px 8px; cursor:pointer; font:inherit;
  font-size:11.5px; color:var(--ink-2)}
/* 공통 공강 찾기 */
/* z-index 10 — 콘텐츠 층(1~7) 위, 레일(20)·모달 아래. 레일과 **같은 사고**를 겪었다
   (위 .rail 주석 참조): 제안 목록이 5 였는데 `.wk-grid .hd.corner`(교시)가 6, `.hd.is-today`
   (오늘 열)가 5(동점)라, '연구부' 로 검색해 목록을 펼치면 그 둘만 목록 위로 뚫고 올라왔다
   (2026-08-26 사용자 보고). 개별 셀렉터를 낮추면 다음에 또 생긴다 — **피커에 쌓임 맥락을
   만들어 목록을 통째로 층 밖으로 올린다.** 안쪽 .free-sugg 의 z-index 는 이 맥락 안에서만
   의미를 갖는다. 주간 탭 검색바(.wg-search)도 같은 목록을 쓰므로 함께 올린다. */
.free-picker{position:relative; z-index:10; padding:10px 14px 0}
.free-picker input{width:100%; box-sizing:border-box; padding:7px 10px;
  border:1px solid var(--hair); border-radius:6px; font:inherit; font-size:12.5px;
  background:var(--surface); color:var(--ink-1)}
.free-picker input::placeholder{color:var(--ink-3)}
.free-sugg{display:none; position:absolute; left:14px; right:14px; top:100%; z-index:5;
  background:var(--surface); border:1px solid var(--hair); border-radius:8px;
  box-shadow:0 6px 18px rgba(16,18,20,.12); overflow:hidden}
.free-sugg.on{display:block}
.free-sugg button{display:flex; justify-content:space-between; gap:10px; width:100%;
  border:0; background:none; padding:8px 12px; cursor:pointer; font:inherit;
  font-size:12.5px; text-align:left; color:var(--ink-1)}
.free-sugg button:hover{background:var(--today-tint)}
.free-sugg button.act{background:var(--today-tint)}
.free-sugg .sd{color:var(--ink-3); font-size:11.5px}
.free-chips{display:flex; flex-wrap:wrap; gap:6px; padding:10px 14px}
/* 칩은 무채색 — 초록·파랑은 그리드 범례(가능·1명) 전용이라 칩에 쓰면 오독(0.1.17 사용자 피드백) */
.free-chip{display:inline-flex; align-items:center; gap:5px; font-size:12px;
  font-weight:600; padding:3px 6px 3px 9px; border-radius:999px;
  background:var(--surface); color:var(--ink-1); border:1px solid var(--hair)}
.free-chip.me{font-weight:700}
.free-chip .x{border:0; background:none; cursor:pointer; color:inherit;
  font-size:11px; padding:0 3px}
/* 0.1.22 피드백: 이름 위주 그리드라 기본 경계선(--hair-2, 5.5%)이 안 보임 — 뚜렷한 선(14%,
   입력창 테두리와 동급) */
.free-grid > *{border-right:1px solid rgba(16,18,20,.14); border-bottom:1px solid rgba(16,18,20,.14)}
.free-grid > *:nth-child(6n+1){border-left:1px solid rgba(16,18,20,.14)}
.free-detail{padding:10px 14px; border-top:1px solid var(--hair);
  font-size:12.5px; color:var(--ink-1); line-height:1.5}
.free-detail .free-hint{color:var(--ink-3)}
/* ── 3안-A(2026-10-15 사용자 채택) — 요일 열 × 실제 시각 축. 접두 ft-.
   교시 칸(.fcell · 학년별 갈린 행)을 걷어 냈다: 학년마다 5~10분 어긋난 교시를 칸으로 가르면
   같은 시각 다른 학년 수업을 못 봐 틀린 초록이 났다. 이제 세로 = 분 비례(1.3px/분, free.js SC),
   «바쁜 선택 교사 집합이 같은 동안» = 한 블록. 색은 토큰만 — 장식(왼쪽 색 띠·그림자·그라데이션·배지) 없음. */
.ft-legend{display:flex; align-items:center; gap:6px; padding:0 14px 6px; font-size:11.5px; color:var(--ink-3)}
.ft-sw{flex:none; width:10px; height:10px; box-sizing:border-box; background:var(--t-sub);
  border:1px solid rgba(15,123,15,.30)}
/* 6열 주에서 nth-child(6n+1) 왼쪽 선이 어긋나므로 열 머리·눈금 칸(.ft-first)에만 왼쪽 선 */
.wk-grid.ft-grid > *{border-left:0}
.wk-grid.ft-grid > .ft-first{border-left:1px solid rgba(16,18,20,.14)}
.ft-gut{position:sticky; left:0; z-index:3; background:var(--bg-frame)}
.ft-tk{position:absolute; right:4px; font-size:10px; color:var(--ink-3); transform:translateY(-50%);
  font-variant-numeric:tabular-nums; white-space:nowrap; line-height:1}
.ft-col{position:relative}
.ft-hl{position:absolute; left:0; right:0; height:0; border-top:1px dashed rgba(16,18,20,.10); pointer-events:none}
.ft-off{position:absolute; left:0; right:0; background:rgba(16,18,20,.028)}
/* 20분 미만 빈 틈 — 옅게 · 누를 수 없음 · 글자 없음(마우스 글상자만 받는다) */
.ft-gap{position:absolute; left:0; right:0; background:var(--t-sub-b)}
.ft-acad{display:block; margin-top:2px; text-align:center; font-size:10.5px; line-height:1.25;
  font-weight:600; color:var(--ink-3); pointer-events:none}
.ft-list{list-style:none; margin:0; padding:0}
.ft-list > li{display:contents}
.ft-blk{position:absolute; left:0; right:0; margin:0; border:0; border-top:1px solid rgba(16,18,20,.14);
  border-bottom:1px solid rgba(16,18,20,.14); box-sizing:border-box; padding:0 2px; overflow:hidden;
  display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
  font:inherit; font-size:11px; line-height:1.25; cursor:pointer}
.ft-blk .ln{display:block; white-space:nowrap}
/* 작은 줄(시각·길이)은 줄 높이 1.15 — 20분 블록(26px · 안쪽 24px)에 「10:00」「~10:20」 두 줄(23px)이
   들어가야 폰 폭(열 52~60px)에서도 시작·끝 시각이 남는다(측정 10-15: 1.25 면 25px 로 1px 모자라 글자 없음). */
.ft-blk .ln.sm{font-size:10px; font-weight:500; line-height:1.15}
.ft-blk.ft-free{background:var(--t-sub); color:var(--c-sub); font-weight:600}
.ft-blk.ft-busy{background:rgba(16,18,20,.05); color:var(--ink-1)}
.ft-blk .me{color:var(--a-mine)}
.ft-blk.sel, .ft-blk:focus-visible{outline:2px solid var(--a-swap); outline-offset:-2px}
/* 마우스 글상자(Q147 B) — 기본은 숨김. 보이게 하는 규칙은 아래 hover 미디어 블록 «안에만» 둔다(L6):
   휴대폰 탭이 만드는 호환 mouseover 로 .on 이 붙어도 마우스 없는 기기에선 안 보인다.
   z 8 = 격자 머리(sticky 4~6) 위 · 검색 목록(.free-picker 10)과 레일(20) 아래(레일 층 잠금). */
.ft-tip{display:none; position:fixed; z-index:8; pointer-events:none; max-width:240px; padding:5px 8px;
  border:1px solid var(--hair-strong); border-radius:6px; background:var(--surface); color:var(--ink-1);
  font-size:11.5px; line-height:1.45; white-space:pre-line; font-variant-numeric:tabular-nums}
@media (hover: hover) and (pointer: fine){
  .ft-tip.on{display:block}
}

/* ============================================================
   수업 요일 표시(0.1.23) — 평상시 '(수) 수업' 조용히 상시 노출,
   대체수업일(다른 요일 시간표)은 보라 pill 로 강조. 그리드 헤더는 .wk-swap 미니 마크.
   ============================================================ */
.lesson-dow{margin-left:auto; font-size:12px; font-weight:600; color:var(--ink-2)}
.lesson-dow.swap{color:var(--c-day); background:var(--t-day);
  border-radius:999px; padding:2px 9px; font-weight:700}
.page-h .sub .lesson-dow{margin-left:7px}
.wk-grid .hd .wk-swap{margin-left:3px; font-size:10px; font-weight:700; color:var(--c-day)}

/* ── 설정 탭(D5 0.1.26) — 섹션 카드·행·토글 스위치 (목업 screen-notifset 이식) ── */
.set-scroll{flex:1; overflow-y:auto; overflow-x:hidden; padding:14px 16px 24px;
  scrollbar-width:thin; scrollbar-color:rgba(16,18,20,.22) transparent}
.set-head{display:flex; align-items:baseline; gap:9px; margin:2px 2px 4px}
.set-h1{font-size:19px; font-weight:700; letter-spacing:-.02em; color:var(--ink-1)}
.set-section{margin-top:16px}
.set-section-h{font-size:11.5px; font-weight:600; letter-spacing:.04em; color:var(--ink-3); margin:0 4px 7px}
.set-card{background:var(--surface); border-radius:12px; border:1px solid var(--hair);
  box-shadow:0 1px 2px rgba(16,18,20,.04); overflow:hidden}
.set-row{display:flex; align-items:center; gap:12px; padding:13px 15px}
.set-row.rowsep{border-top:1px solid var(--hair)}
.set-txt{flex:1; min-width:0}
.set-title{font-size:14.5px; font-weight:600; letter-spacing:-.01em; color:var(--ink-1);
  display:flex; align-items:center; gap:7px}
.set-desc{font-size:12.5px; line-height:1.45; color:var(--ink-2); margin-top:3px}
.set-val{flex:none; font-size:13.5px; font-weight:500; color:var(--ink-2)}
.set-cardnote{font-size:11.5px; line-height:1.5; color:var(--ink-3); margin:7px 6px 0}
.acct-badge{flex:none; font-size:10.5px; font-weight:600; color:var(--c-swap);
  background:var(--t-swap); padding:1px 7px; border-radius:999px}
.set-flash{font-size:12px; color:var(--ink-2); margin-right:2px}
.switch{position:relative; flex:none; width:44px; height:25px; border-radius:999px;
  border:1px solid rgba(16,18,20,.16); background:rgba(16,18,20,.11); cursor:pointer; padding:0;
  font-family:inherit; transition:background-color 180ms ease, border-color 180ms ease}
.switch .knob{position:absolute; top:2px; left:2px; width:19px; height:19px; border-radius:50%;
  background:#fff; box-shadow:0 1px 2px rgba(16,18,20,.32); transition:transform 180ms var(--ease-enter)}
.switch[aria-checked="true"]{background:var(--a-swap); border-color:var(--a-swap)}
.switch[aria-checked="true"] .knob{transform:translateX(19px)}
.switch:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}

/* ── 공용 버튼·로그인 모달(0.1.26) — D1 리스타일 때 소실된 .modal-bg/.alert-pop 복원 ── */
.btn{font-family:inherit; font-size:13.5px; font-weight:600; letter-spacing:-.01em;
  color:var(--ink-1); background:var(--surface); border:1px solid rgba(16,18,20,.18);
  border-radius:6px; padding:7px 14px; cursor:pointer;
  transition:background-color 150ms ease, border-color 150ms ease}
.btn:hover{background:rgba(16,18,20,.04)}
.btn:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}
.btn:disabled{opacity:.5; cursor:default}
.btn.primary{color:#fff; background:var(--a-swap); border-color:var(--a-swap)}
.btn.primary:hover{background:var(--c-swap)}
/* ★ 0.1.59 — 로그인 모달도 키보드 보정을 받는다(스펙 §9-8·§9-9 · 축 A42).
   선언 순서가 계약이다: `inset:0` 이 `top:var(--vvt)` **앞**이어야 한다 — 단축 속성이
   뒤에 오면 top 을 0 으로 되돌려 보정이 **조용히** 죽는다(.lc-smoke 와 같은 자리). */
.modal-bg{position:fixed; inset:0; z-index:70; background:rgba(0,0,0,.44);
  display:flex; align-items:center; justify-content:center; padding:24px;
  top:var(--vvt, 0px); height:var(--vvh)}
/* ★ 0.1.59 — safe-area 는 **기존 규칙에 선언을 더한다**(새 규칙으로 더하면 C-T15 ⓐ-1 의
   「정확히 1회 정의」가 2회로 빨개진다 · 축 A43). padding:18px 20px **뒤**여야 단축이 되돌리지 않는다. */
.alert-pop{width:100%; max-width:360px; background:var(--surface); border-radius:12px;
  border:1px solid var(--hair); box-shadow:0 24px 48px rgba(16,18,20,.22); padding:18px 20px;
  padding-bottom:max(18px, env(safe-area-inset-bottom))}
.ap-app{font-size:11.5px; font-weight:600; letter-spacing:.04em; color:var(--ink-3)}
.ap-t{font-size:18px; font-weight:700; letter-spacing:-.02em; color:var(--ink-1); margin-top:2px}
.ap-t .nw{white-space:nowrap}
.ap-m{font-size:13.5px; color:var(--ink-2); line-height:1.5; margin-top:8px}
.ap-m label{display:block; margin-top:10px; font-size:12.5px; font-weight:600; color:var(--ink-2)}
.ap-m input{display:block; width:100%; margin-top:4px; padding:8px 10px; font:inherit;
  font-size:14px; color:var(--ink-1); background:#fff;
  border:1px solid rgba(16,18,20,.18); border-radius:6px}
.ap-m input:focus{outline:none; border-color:var(--a-swap); box-shadow:0 0 0 3px rgba(0,120,212,.14)}
.ap-foot{display:flex; justify-content:flex-end; gap:8px; margin-top:14px}

/* 로그인 저장 체크박스 행(0.1.27) — .ap-m label 블록 규칙을 인라인 행으로 재정의 */
.ap-remember{display:flex; gap:16px; margin-top:12px}

/* ── 명렬 미리보기(2026-10-12 명렬수강기간) — 업로드 전 학생별 수강 기간 확인 ──────
   소비자: roster-preview.js(HTML) · app.js(배선). `.alert-pop` 문법을 잇되 목록이 길어
   자체 스크롤을 진다. 색은 기존 토큰만 쓴다(추가/복귀/제외 = 파랑/청록/빨강 = 기존 신호색). */
.rp-pop{width:100%; max-width:420px; max-height:min(86vh, 720px); display:flex;
  flex-direction:column; background:var(--surface); border-radius:12px; border:1px solid var(--hair);
  box-shadow:0 24px 48px rgba(16,18,20,.22); padding:18px 20px;
  padding-bottom:max(18px, env(safe-area-inset-bottom))}
.rp-lead{font-size:13px; color:var(--ink-2); margin-top:6px}
/* 계열 맥락 한 줄(2026-10-12 F2) — 동아리는 `이름 동아리`, 교과는 `학급 과목[분반]`. */
.rp-ctx{font-size:12.5px; font-weight:650; color:var(--ink-1); margin-top:6px}
.rp-sum{font-size:12.5px; font-weight:650; color:var(--ink-1); margin-top:8px;
  font-variant-numeric:tabular-nums}
.rp-banner{margin-top:8px; padding:8px 10px; border-radius:8px; font-size:12.5px;
  color:var(--danger); background:var(--t-canc)}
.rp-list{margin-top:10px; overflow-y:auto; min-height:0; flex:1; display:flex;
  flex-direction:column; gap:6px}
.rp-row{border:1px solid var(--hair); border-radius:10px; padding:8px 10px; background:var(--surface)}
.rp-who{display:flex; align-items:baseline; gap:6px; flex-wrap:wrap}
.rp-kind{flex:none; display:inline-block; padding:1px 6px; border-radius:999px;
  font-size:11px; font-weight:700}
.rp-kind.added{color:var(--a-swap); background:var(--t-swap)}
.rp-kind.returned{color:var(--a-mine); background:var(--t-mine)}
.rp-kind.removed{color:var(--danger); background:var(--t-canc)}
.rp-id{font-size:12px; color:var(--ink-2); font-variant-numeric:tabular-nums}
.rp-name{font-size:13px; font-weight:650; color:var(--ink-1); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; min-width:0}
.rp-prior{flex-basis:100%; font-size:11.5px; color:var(--ink-3)}
.rp-ctl{display:flex; align-items:center; gap:6px; margin-top:6px; flex-wrap:wrap}
.rp-reason{font:inherit; font-size:13px; color:var(--ink-1); background:var(--surface);
  border:1px solid var(--hair-strong); border-radius:6px; padding:6px 8px; max-width:100%}
.rp-date{font:inherit; font-size:13px; color:var(--ink-1); background:var(--surface);
  border:1px solid var(--hair-strong); border-radius:6px; padding:5px 8px}
.rp-when{font-size:12px; color:var(--ink-3)}
.rp-err{font-size:11.5px; color:var(--danger); min-height:14px; margin-top:2px}
.rp-pop .ap-foot{flex:none}
.ap-remember label{display:flex; align-items:center; gap:6px; margin-top:0;
  font-size:12.5px; font-weight:500; color:var(--ink-2); cursor:pointer}
.ap-remember input{display:inline-block; width:14px; height:14px; margin:0;
  accent-color:var(--a-swap); cursor:pointer}

/* 설정 탭 보조(0.1.27) — 저작권 표기 */
.set-copy{font-size:11px; color:var(--ink-3); text-align:center; margin:22px 4px 6px}

/* ── 학급 탭 마커 행(2c-2c) — 빈 교시 설명: 원수업 취소선, 이동=파랑, 취소=빨강 ── */
.period.mk .subj{color:var(--ink-3); font-weight:500}
.period.mk .subj s{text-decoration-thickness:1px}
.period.mk .mk-lab.mv{color:var(--c-swap); font-weight:600}
.period.mk .mk-lab.cx{color:var(--c-canc); font-weight:600}

/* ============================================================
   2h 오늘의 전체 시간표(.sc-) — 격자 대시보드
   정본 mockups/school-grid-2h-final.html (셀 가운데 정렬·현재=흰 카드+파랑 링[2i-2]·
   틴트 2종+글자 변동색·hover 다크 툴팁·지난 교시 흐림·범례). 전 규칙 .sc- 스코프.
   ============================================================ */
/* 0.1.43: 검색창이 제목 행에서 자기 행(.wg-search, 주간 탭과 같은 부품)으로 내려갔다.
   150px 고정 폭 검색창이 제목 행을 밀어 기본 창 520 에서 네 항목이 동시에 줄바꿈되던 문제.
   `.sc-search` 전용 규칙 일습(고정 폭·margin-left:auto·우측 정렬 서제스트)은 함께 폐지 —
   전폭 바에서는 `.wg-search` 규칙이 그대로 맞는다. */
.sc-head .date{margin-left:auto}
#scBody{flex:1; min-height:0; display:flex; flex-direction:column}
.sc-scroll{flex:1; overflow-y:auto; scrollbar-width:thin; scrollbar-color:rgba(16,18,20,.22) transparent}
.sc-grid{display:grid; grid-template-columns:40px repeat(var(--sc-cols,7),minmax(0,1fr));
  font-size:11px; padding:0 10px 4px}
.sc-h{position:sticky; top:0; z-index:4; background:var(--bg-frame);
  padding:5px 0 4px; text-align:center; font-size:11px; font-weight:700; color:var(--ink-2)}
.sc-gh{grid-column:1 / -1; display:flex; align-items:baseline; gap:8px;
  padding:8px 2px 3px; font-size:10.5px; font-weight:700; color:var(--ink-3); letter-spacing:.03em}
.sc-gh em{font-style:normal; font-weight:500; color:var(--ink-3); letter-spacing:0}
.sc-gh em.live{color:var(--a-swap); font-weight:600}
.sc-cl{display:flex; align-items:center; padding:0 6px; font-size:11px; font-weight:600;
  color:var(--ink-2); border-top:1px solid var(--hair)}
.sc-c{position:relative; min-height:33px; min-width:0; padding:2px;
  display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
  border-top:1px solid var(--hair)}
.sc-c .sj{font-size:11px; font-weight:650; letter-spacing:-.01em; line-height:1.1; color:var(--ink-1)}
.sc-c .tc{font-size:9.5px; color:var(--ink-2); line-height:1.15}
.sc-c.past .sj,.sc-c.past .tc{opacity:.45}
.sc-c.sub{background:var(--t-sub)}
.sc-c.sub .sj{color:var(--c-sub)}
.sc-c.swap{background:var(--t-rep)}
.sc-c.swap .sj{color:var(--c-rep)}
.sc-c.cur{background:var(--surface); border-radius:6px; border-top-color:transparent; z-index:1;
  box-shadow:0 1px 4px rgba(16,18,20,.16), inset 0 0 0 1.5px var(--a-swap)}
.sc-c.cur .sj{font-weight:750}
.sc-c.cur.sub{background:var(--t-sub)}
.sc-c.cur.swap{background:var(--t-rep)}
/* 내 수업 표식 — 시안 A1(사용자 택일 2026-10-01). 두 채널 = 배경 tint(`.me`) + 내 이름 글자(`.me-nm`).
   옛 시안 C(U11 D15 · 09-15)의 왼쪽 테두리·「내」 배지는 걷었다(「촌스럽고 AI스럽다」 지적).
   색은 신규 청록(--a-mine)이라 「현재 셀」·「검색 일치」(둘 다 --a-swap 링)와 겹치지 않고, 링은
   `.me` 가 box-shadow 를 더는 안 건드려 그대로 산다(옛 결합 규칙 셋이 필요 없어졌다). */
.sc-c.me{background:var(--t-mine)}
/* 변동 tint 와 겹칠 때는 **변동색이 배경을 이긴다** — 그래도 내 이름 색은 남아 둘 다 읽힌다.
   3클래스 결합이라 특이도로 위 줄을 이긴다(선언 순서 무관). */
.sc-c.me.sub{background:var(--t-sub)}
.sc-c.me.swap{background:var(--t-rep)}
/* 내 이름 글자 — 세 격자 공통(전체 시간표 `.tc` · 고사 감독표 `.nm`·아래 줄 · 학급 주간 `.s2`).
   렌더러가 교사 번호로 가려 감싼다(school.js `nameHtml` · week.js). 자기 색을 스스로 선언하므로
   부모의 글자색(.tc 의 --ink-2, .nm 의 --ink-1)을 이긴다 — 지난 교시·검색은 아래에서 따로 덮는다. */
.sc-c .me-nm,.exb-c .me-nm,.wg-c .me-nm{color:var(--a-mine); font-weight:750}
/* 검색 하이라이트 — 변동색·현재 셀보다 뒤(결합 시 링·글자 파랑이 이긴다, 스펙 §3-2) */
.sc-c.hit{box-shadow:inset 0 0 0 1.5px var(--a-swap); border-radius:5px}
.sc-c.cur.hit{box-shadow:0 1px 4px rgba(16,18,20,.16), inset 0 0 0 1.5px var(--a-swap)}
.sc-c.hit .sj,.sc-c.hit .tc{color:var(--a-swap); opacity:1}
/* 검색이 내 이름 색도 이긴다(스펙 §3-2 「결합 시 링·글자 파랑이 이긴다」) — `.me-nm` 은 자기 색을
   선언해 부모 `.tc` 의 파랑을 상속받지 못하므로 여기서 직접 덮는다. */
.sc-c.hit .me-nm{color:var(--a-swap)}
/* ★ 2026-09-09(B6) — `.sc-more`(「+N」 배지) 규칙을 **지웠다.** 확정 D5(2026-09-08 합반명렬)로
   `school.js` 가 그 클래스를 더는 내보내지 않아(병기 표시로 대체) 소비자가 0 이 됐다 —
   이 저장소는 死 CSS 를 금지한다. 되살아나는지는 두 자리가 잰다: 렌더러 쪽은
   `tests/school.test.mjs` 의 `assert.doesNotMatch(html, /sc-more/)`, CSS 쪽은
   `tests/theme-css.test.mjs` 의 「B6 死 CSS 잠금」이다. */
.sc-c .tip{display:none; position:absolute; left:50%; bottom:calc(100% + 6px); transform:translateX(-50%);
  z-index:7; background:rgba(33,30,25,.96); color:#fff; font-size:10.5px; line-height:1.4;
  padding:5px 9px; border-radius:7px; white-space:nowrap; pointer-events:none}
.sc-c:hover .tip{display:block}
.sc-legend{display:flex; flex-wrap:wrap; gap:12px; align-items:center; padding:8px 12px 10px;
  font-size:10.5px; color:var(--ink-2)}
.sc-legend i{display:inline-block; width:10px; height:10px; border-radius:3px; margin-right:4px;
  vertical-align:-1px}
.sc-legend .lg-cur{background:var(--surface); box-shadow:inset 0 0 0 1.5px var(--a-swap)}
.sc-legend .lg-sub{background:var(--t-sub)}
.sc-legend .lg-swap{background:var(--t-rep)}
.sc-legend .lg-mine{background:var(--t-mine)}

/* ============================================================
   웨이브 4 ① 수업별 메모 — 오늘 탭 셀 한 줄 + 「차시 노트」 모달/시트
   정본 목업 mockups/memo-r2.html 에서 **화이트리스트만** 이식했다(그 밖의 한 줄도 옮기지 않는다).
   목업이 theme.css 와 겹치게 정의하는 bare 셀렉터 46건(.band .b-body … .st-free)은 목업이
   앱 화면을 그리려고 이 파일을 복사해 둔 **배경**이라 병합 대상이 아니다.
   ★ 색은 중립 잉크 한 축만 — 보강 초록·교체 앰버(--c-rep)·취소 빨강(--c-canc)·
     대체수업일 보라(--c-day)·나우 빨강(--red-now)을 재사용하지 않는다. 강조는 --a-swap 뿐이다.
   ★ 카드의 최상위 클래스는 `.lc-card`다 — hist.js 의 히스토리 필터 칩 개수 배지가
     이미 class="cn" 을 쓰므로, 범용 이름을 쓰면 width:100%·display:flex·
     flex-direction:column·overflow:hidden·box-shadow 가 그 배지에 붙어 깨진다.
   ============================================================ */

/* ── 오늘 탭 셀 한 줄(안 A) — 변동 사유가 이미 2줄째면 메모는 3줄째 ── */
.b-memo{display:flex; align-items:center; gap:5px; margin-top:2px; min-width:0;
  font-size:12.5px; line-height:1.25; color:var(--ink-2)}
.b-memo .mic{flex:none; color:var(--ink-3)}
.b-memo .mtx{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* ★ 패딩이 .band → .b-inner 로 내려갔으므로(「카드 폭 축소」 블록 참조) 이 규칙도 한 층
   내려간다. 특이도 0,3,0 이라 축소(`.band .b-inner`)·되돌림(같은 0,2,0) **둘 다 이긴다** —
   3줄 밴드 상하 6px 은 어느 폭·어느 기기에서도 유지된다. 예전엔 `.tl2 .tl-col .band`(0,3,0)가
   `.band.l3`(0,2,0)를 이겨 2열에서만 8px 로 좁아졌고 실렌더 스모크가 그걸 잡았는데(정적
   시험은 「규칙이 있다」만 보고 「이긴다」를 못 본다), 기준이 카드 하나로 통일되면서 그
   2열 전용 짝 규칙(`.tl2 .tl-col .band.l3`)은 필요가 없어져 삭제했다.
   3줄 밴드에만 붙고 2e 픽셀 결정(비-l3 밴드 8px)은 한 글자도 안 건드린다. */
.band.l3 .b-inner{padding-top:6px;padding-bottom:6px}
.band.gone .b-memo{color:var(--ink-3)}
.band.gone .b-memo .mic{color:var(--ink-3)}


/* ── 「차시 카드」 3층 — 앱 창을 덮는 카드와 모바일 시트 ── */
/* iPhone에서 메모 입력 뒤 iOS Safari가 레이아웃 뷰포트는 그대로 두고 visualViewport만
   offsetTop 만큼 스크롤해 시트가 위로 밀렸다. app.js가 관측값을 --vvt로 싣고, Android
   resizes-content의 0px는 자동으로 보정을 없앤다. 변수가 없는 브라우저도 0px 폴백으로 현재 위치다. */
/* ★★ 0.1.63 「PDF로 저장」 — 종이를 **화면에서만** 감춘다.
     `PrintToPdf` 는 «문서»를 찍으므로 종이가 DOM 에 있어야 한다. 그런데 미리보기를 띄우지
     않기로 했으므로 화면에서는 안 보여야 한다 — 화면 매체에서만 감추고, 인쇄 매체에서는
     아래 인쇄 블록이 도로 보이게 한다(그 블록의 `.pv-off` 규칙).
     ★ 이 주석에 인쇄 매체 «규칙 이름»을 적지 마라 — 정적 검사가 그 이름에서 파일을
       자르는 자가 있어(`outsideMedia`) 아래 규칙들이 통째로 안 보이게 된다. 실제로 밟았다. */
/* 알림 창의 «보조 줄» — 파일 경로처럼 긴 문자열(0.1.64). 제목보다 작고 연하게, 경로는
   중간에서 접힌다. 굵은 본문으로 그대로 흘리면 창이 제목만큼 커지고 성의 없어 보인다. */
.ap-sub{margin-top:6px; font-size:12px; line-height:1.55; font-weight:400; color:var(--ink-2);
  background:var(--pnum-idle); border-radius:8px; padding:8px 10px; text-align:left;
  word-break:break-all; max-height:5.6em; overflow:auto}
.lc-smoke.pv-off{display:none}
.lc-smoke{position:fixed; inset:0; top:var(--vvt, 0px); z-index:25; background:rgba(0,0,0,.44);
  display:flex; align-items:center; justify-content:center; padding:14px; height:var(--vvh)}
/* ★ 0.1.59 — safe-area 는 **카드에** 건다(스펙 §9-8 · 축 A43 자리 단언). `.lc-f`(카드 발)는
   renderLessonList·loadingCard 만 그리고 카드 뷰·출석 뷰에는 아예 없다. 폰에서 카드는
   바텀시트라(아래 460px 블록) 발이 없으면 `.s-grid` 의 마지막 학생 줄과 「더 보기」·[다시] 가
   홈 인디케이터에 깔린다 — 그게 이 아크의 주 화면이다.
   ★ 새 규칙이 아니라 **이 규칙에 선언을 더한다**(C-T15 ⓐ-1 은 정확히 1회 정의를 요구한다). */
.lc-card{width:100%; max-width:900px; height:auto; max-height:calc(100% - 28px); background:var(--surface); color:var(--ink-1);
  border-radius:0; overflow:hidden; display:flex; flex-direction:column; position:relative;
  box-shadow:0 28px 56px rgba(16,18,20,.30),0 2px 12px rgba(16,18,20,.16);
  padding-bottom:env(safe-area-inset-bottom);
  /* 청람·코랄 기록지의 색은 차시 카드 안에서만 바뀐다. */
  --lc-main:#155E75; --lc-strong:#0B5067; --lc-att:#087DA0; --lc-att-hover:#006687;
  --lc-memo:#C75334; --lc-mast:#E8F4F6; --lc-select:#E8F3F6; --lc-rule:#B5D1D9;
  --a-swap:var(--lc-main)}
.lc-smoke.lc-app .lc-card[data-editing]{container:lesson-card / inline-size}
.lc-smoke.lc-phone{align-items:flex-end; padding:0}
.lc-smoke.lc-phone .lc-card{max-width:600px; height:auto; max-height:calc(100% - 30px);
  border-radius:16px 16px 0 0; box-shadow:0 -10px 34px rgba(16,18,20,.26);
  padding-left:0; padding-right:0}
.lc-smoke.lc-phone .lc-card .lc-grab{display:block; position:absolute; top:8px; left:calc(50% - 19px); margin:0; z-index:4}
.lc-card .lc-body{flex:0 1 auto; min-height:0; display:flex; flex-direction:column; overflow:auto; overscroll-behavior:contain}
.lc-card .at-bar{flex:none; z-index:3; min-height:28px; background:var(--lc-mast); padding:3px 36px}
.lc-card .at-save.pill{background:transparent; border-radius:0}
.lc-card .lc-fact{display:grid; grid-template-columns:minmax(0,1fr) 70px; gap:0; padding:0; border:0}
.lc-card .lc-fb{display:contents}
.lc-card .lc-f1{grid-column:1; grid-row:1; padding:8px 0 20px 36px; background:var(--lc-mast); position:relative;
  display:grid; grid-template-columns:max-content minmax(0,1fr); gap:3px 8px}
.lc-card .lc-f1 .lc-cls{grid-row:1; grid-column:1; margin:0; color:var(--lc-main); font-size:12px; font-weight:800}
.lc-card .lc-f1 .lc-sj{grid-row:2; grid-column:1 / -1; font-size:31px; font-weight:800; line-height:1.2; color:var(--lc-strong)}
.lc-card .lc-grp{grid-row:1; grid-column:2; justify-self:start}
.lc-card .lc-f1 > .sep{display:none}
.lc-card .lc-f1 .lc-when{grid-row:3; grid-column:1 / -1; font-size:12px}
.lc-card .lc-f1 .lc-timing{position:absolute; left:36px; right:0; bottom:0; min-width:0; font-size:12px;
  line-height:16px; color:var(--ink-2); font-weight:400; font-variant-numeric:tabular-nums;
  white-space:normal; word-break:keep-all; overflow:visible; text-overflow:clip}
.lc-card .lc-x{grid-column:2; grid-row:1; width:44px; height:44px; border-radius:0;
  margin:0 26px 0 0; align-self:start; background:var(--lc-mast)}
.lc-card .lc-fact{background:var(--lc-mast)}
.lc-card .s-f2{grid-column:1 / -1; margin:0; padding:20px 36px 0; background:var(--surface);
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:20px; font-variant-numeric:tabular-nums}
.lc-card .s-f2 .lc-seg,.lc-card .s-f2 .lc-ord{display:block; min-width:0; white-space:normal;
  overflow:visible; overflow-wrap:anywhere; word-break:keep-all; text-overflow:clip;
  border-bottom:1px solid var(--lc-rule); padding-bottom:12px; color:var(--lc-strong)}
.lc-card .s-f2 > .sep{display:none}
.lc-card .lc-f2{grid-column:1 / -1; margin:0; padding:12px 36px 0; background:var(--surface)}
.lc-card .lc-work{flex:none; display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:28px; padding:22px 36px 26px}
.lc-card .lc-work section{min-width:0}
.lc-card .lc-work h3{font-size:12px; font-weight:800; color:var(--lc-main); margin:0 0 10px}
.lc-card .s-enter{width:100%; min-height:52px; margin:0; padding:12px 32px 12px 15px;
  justify-content:flex-start; text-align:left; flex-wrap:wrap; gap:5px; border:0; border-radius:4px;
  background:var(--lc-att); color:#fff}
.lc-card .s-enter:hover{background:var(--lc-att-hover)}
.lc-card .s-enter .t,.lc-card .s-enter .s,.lc-card .s-enter .sep,.lc-card .s-enter .rc{color:#fff}
.lc-card .s-enter .t{font-size:15px; font-weight:800}
.lc-card .lc-write{width:100%; min-height:52px; padding:4px 0 8px; display:flex; align-items:flex-end;
  justify-content:space-between; gap:12px; background:transparent; border:0;
  border-bottom:2px solid var(--lc-memo); border-radius:0; text-align:left; font:inherit; cursor:pointer}
.lc-card .lc-preview{min-width:0; font-size:12px; line-height:1.4; color:var(--ink-3); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.lc-card .lc-write-label{flex:none; display:inline-flex; align-items:center; gap:5px; font-size:13px; font-weight:800; color:var(--lc-memo)}
.lc-card .lc-write:focus-visible{outline:2px solid var(--lc-memo); outline-offset:3px}
.lc-card .lc-listhead{flex:none; margin:0 36px; padding:0 0 8px; display:flex; justify-content:space-between;
  border-bottom:1px solid var(--lc-main); font-size:12px; color:var(--lc-strong)}
.lc-card .lc-listhead > span{font-size:11px; color:var(--ink-3)}
.lc-card .lc-columns{flex:none; display:grid; grid-template-columns:74px 148px minmax(0,1fr);
  gap:9px; margin:0 36px; padding:10px; font-size:11px; color:var(--ink-3); border-bottom:1px solid var(--lc-rule)}
.lc-card .lc-list{flex:0 1 auto; min-height:80px; margin:0 36px 24px; overscroll-behavior:contain}
.lc-card[data-editing="true"] .lc-list{flex:0 0 auto; height:auto; min-height:44px; max-height:max(44px, min(340px, calc(var(--vvh, 100dvh) - 140px - env(safe-area-inset-bottom, 0px))))}
/* 보이는 높이가 부족하면 입력/저장 공간을 먼저 남기고 머리는 스크롤한다. */
.lc-card[data-editing="true"] .lc-fact{max-height:max(0px, calc(var(--vvh, 100dvh) - 106px - env(safe-area-inset-bottom, 0px) - min(260px, max(44px, calc(var(--vvh, 100dvh) - 140px - env(safe-area-inset-bottom, 0px)))))); min-height:0; overflow:auto}
.lc-smoke.lc-phone .lc-card[data-editing="true"] .lc-fact{max-height:max(0px, calc(var(--vvh, 100dvh) - 80px - env(safe-area-inset-bottom, 0px) - min(260px, max(44px, calc(var(--vvh, 100dvh) - 140px - env(safe-area-inset-bottom, 0px))))))}
.lc-smoke.lc-phone .lc-card[data-editing="true"] .s-ta{max-height:min(calc(9.3em + 20px), max(44px, calc(var(--vvh, 100dvh) - 140px - env(safe-area-inset-bottom, 0px))))}
/* Same full-window default as 100%, expressed as a length for editing calc().
   The visualViewport inline value still takes precedence while the keyboard is up. */
@supports (height:100dvh){:root{--vvh:100dvh}}
.lc-card .s-f2,.lc-card .lc-f2{flex:none}
.lc-card .lc-row{align-items:center; min-height:44px; padding:8px 10px; gap:9px}
.lc-card .lc-row .rn{width:74px; color:var(--ink-2)}
.lc-card .lc-row .rb{display:grid; grid-template-columns:148px minmax(0,1fr); gap:9px; align-items:center}
.lc-card .lc-row .rt{margin:0}
.lc-card .lc-row .rc{display:none}
.lc-card .lc-row.cur,.lc-card .lc-row.cur:hover{background:var(--lc-select)}
.lc-card .lc-row.cur .rn{color:var(--lc-strong)}
.lc-card .lc-item.open{background:var(--lc-select); box-shadow:none}
.lc-card .lc-chip{color:var(--lc-strong); background:transparent; border-radius:0; padding:0}
.lc-card .lc-fade{display:none}
.lc-card .lc-ta{border-radius:0}
.lc-card .lc-ta:focus{border-color:var(--lc-memo); box-shadow:none}
.lc-card .lc-edit{border-top:1px solid var(--lc-memo); padding-top:10px}
.lc-card .lc-att{color:var(--lc-strong); border-color:var(--lc-rule); background:transparent}
.lc-card .btn.primary:hover{background:var(--lc-att-hover)}
.lc-card .at-hint,.lc-card .at-foot,.lc-card .at-sec{background:transparent}
.lc-card .lc-memo:only-child{grid-column:1 / -1}
/* 앱의 내부 열만 접는다. 표면을 고르는 조건은 lc-app / lc-phone 이다. */
@container lesson-card (max-width: 600px){
  .lc-smoke.lc-app .lc-card .lc-work{grid-template-columns:minmax(0,1fr); gap:18px; padding:18px 24px 22px}
  .lc-smoke.lc-app .lc-card .s-f2{grid-template-columns:minmax(0,1fr); gap:8px; padding:18px 24px 0}
  .lc-smoke.lc-app .lc-card .lc-listhead,.lc-smoke.lc-app .lc-card .lc-columns,.lc-smoke.lc-app .lc-card .lc-list{margin-left:24px; margin-right:24px}
  .lc-smoke.lc-app .lc-card .lc-columns{grid-template-columns:60px 128px minmax(0,1fr)}
  .lc-smoke.lc-app .lc-card .lc-row .rn{width:60px}
  .lc-smoke.lc-app .lc-card .lc-row .rb{grid-template-columns:128px minmax(0,1fr)}
}
.lc-smoke.lc-phone .lc-card .at-bar{padding-left:18px; padding-right:18px}
.lc-smoke.lc-phone .lc-card .lc-f1{padding:6px 0 16px 18px}
.lc-smoke.lc-phone .lc-card .lc-timing{left:18px}
.lc-smoke.lc-phone .lc-card .lc-sj{font-size:23px}
.lc-smoke.lc-phone .lc-card .lc-x{margin-right:12px}
.lc-smoke.lc-phone .lc-card .lc-fact{grid-template-columns:minmax(0,1fr) 56px}
.lc-smoke.lc-phone .lc-card .s-f2{display:flex; flex-direction:column; gap:3px; padding:16px 18px 0; font-size:12px}
.lc-smoke.lc-phone .lc-card .s-f2 .lc-seg,.lc-smoke.lc-phone .lc-card .s-f2 .lc-ord{border:0; padding:0}
.lc-smoke.lc-phone .lc-card .lc-f2{padding-left:18px; padding-right:18px}
.lc-smoke.lc-phone .lc-card .lc-work{grid-template-columns:minmax(0,1fr); gap:16px; padding:18px}
.lc-smoke.lc-phone .lc-card .lc-work h3{margin-bottom:6px}
.lc-smoke.lc-phone .lc-card .lc-write{min-height:44px; align-items:center}
.lc-smoke.lc-phone .lc-card .lc-listhead,.lc-smoke.lc-phone .lc-card .lc-list{margin-left:18px; margin-right:18px}
.lc-smoke.lc-phone .lc-card .lc-columns{display:none}
.lc-smoke.lc-phone .lc-card .lc-row{min-height:56px; padding:8px 6px; align-items:center}
.lc-smoke.lc-phone .lc-card .lc-row .rn{width:54px}
.lc-smoke.lc-phone .lc-card .lc-row .rb{display:flex; flex-direction:column; align-items:stretch; gap:2px}
.lc-smoke.lc-phone .lc-card .lc-row .rt{display:flex}
.lc-smoke.lc-phone .lc-card .lc-edit{display:flex; flex-direction:column}
.lc-smoke.lc-phone .lc-card .lc-ef{order:-1; margin-top:0; margin-bottom:8px; flex-wrap:wrap}
.lc-smoke.lc-phone .lc-card .lc-ta{font-size:16px}
.lc-smoke.lc-phone .lc-card button{min-height:44px; min-width:44px}
.lc-grab{display:none; flex:none; width:38px; height:4px; border-radius:99px; background:rgba(16,18,20,.16); margin:8px auto 2px}

/* 1층: 수업 정보와 이 자리의 변동 */
.lc-fact{flex:none; display:flex; align-items:flex-start; gap:6px; padding:12px 10px 11px 14px; border-bottom:1px solid var(--hair)}
.lc-fb{flex:1; min-width:0}
.lc-f1{font-size:13.5px; line-height:1.55; color:var(--ink-2); letter-spacing:-.01em}
.lc-f1 .lc-cls{font-size:12.5px; font-weight:600; color:var(--ink-3); letter-spacing:.01em; margin-right:6px}
.lc-f1 .lc-sj{font-size:16.5px; font-weight:700; color:var(--ink-1); letter-spacing:-.02em}
.lc-grp{display:inline-flex; align-items:center; font-size:11.5px; font-weight:600; padding:2px 7px; border-radius:4px;
  background:var(--hair); color:var(--ink-3)}
.lc-f1 .sep{color:var(--ink-3); margin:0 5px}
.lc-f1 .lc-when{color:var(--ink-1); font-weight:600; white-space:nowrap}
/* ★ 0.1.59 결정 8(축 A45) — 첫 줄의 시각 조각 규칙을 **지웠다**(이름은 축 A45 가 적어 둔다 —
   여기 다시 적으면 은퇴 게이트의 grep 이 제 주석에 걸린다). 1층 첫 줄에서 시각 조각이 빠졌고
   (`lessonnote.js` 의 `firstFloor`), 규칙만 남기면 소비자 0 인 死 CSS 다(C-T53 축 AF).
   시각은 **오늘 탭 거터**에 그대로 있다 — 그 존재 짝은 `timeline.test.mjs` 의 기존 단언이 진다. */
/* ★ 0.1.59 결정 8(축 A45) — `.lc-f1 .lc-seg`·`.lc-f1 .lc-ord` 두 규칙을 **지웠다.** 이름이 아니라
   **자리**가 바뀐 것이다: 진도 조각 둘이 1층 첫 줄에서 둘째 줄로 내려갔고, 그 새 자리 규칙
   `.s-f2 .lc-seg,.s-f2 .lc-ord` 는 아래 출석 체크 구획에 이미 서 있다. 옛 자리를 남기면
   소비자 0 인 死 CSS 다(C-T53 축 AF). 존재 짝은 `theme-css.test.mjs` 의 C-T44·C-T44b 가
   **새 자리**(`.s-f2 …`)를 그대로 이어받아 진다 — 부재 단언만 남기지 않는다. */
.lc-f2{margin-top:5px; font-size:13px; line-height:1.55; color:var(--ink-2)}
.lc-f2 .ci{vertical-align:-2px; margin-right:3px}
.lc-f2 .ck{font-weight:700}
.lc-f2 .em{color:var(--ink-1); font-weight:600}
.lc-rep .ci,.lc-rep .ck{color:var(--c-swap)}
.lc-sub .ci,.lc-sub .ck{color:var(--c-sub)}
.lc-canc .ci,.lc-canc .ck{color:var(--c-canc)}
.lc-x{flex:none; width:30px; height:30px; border-radius:8px; border:0; background:transparent;
  color:var(--ink-2); display:inline-flex; align-items:center; justify-content:center; font-family:inherit; cursor:pointer}
.lc-x:hover{background:rgba(16,18,20,.05)}

/* 2층: 선택 차시 ±2의 메모 목록 */
.lc-sec{flex:none; display:flex; align-items:center; gap:8px; padding:7px 8px 7px 14px;
  border-bottom:1px solid var(--hair); background:rgba(255,255,255,.55); font-size:12px; color:var(--ink-2)}
.lc-sec b{color:var(--ink-1); font-weight:700}
.lc-sp{flex:1}
.lc-all{font-family:inherit; font-size:12px; font-weight:600; color:var(--a-swap);
  background:transparent; border:0; padding:5px 8px; border-radius:6px; cursor:pointer; white-space:nowrap}
.lc-all:hover{background:rgba(21,94,117,.08)}
.lc-list{flex:0 1 auto; min-height:0; overflow:auto}
.lc-list.all{max-height:296px}
.lc-item{border-top:1px solid var(--hair-2)}
.lc-item:first-child{border-top:0}
.lc-row{position:relative; display:flex; align-items:flex-start; gap:10px; width:100%; padding:8px 10px 9px 14px;
  text-align:left; font-family:inherit; background:transparent; border:0; cursor:pointer}
.lc-row:hover{background:rgba(16,18,20,.035)}
.lc-row .rn{flex:none; width:46px; padding-top:1px; font-size:12.5px; font-weight:700; color:var(--ink-3); letter-spacing:-.01em}
.lc-row .rb{flex:1; min-width:0}
.lc-row .rd{display:block; font-size:12.5px; font-weight:600; color:var(--ink-2); letter-spacing:-.005em}
.lc-row .rt{display:flex; align-items:center; gap:5px; margin-top:2px; min-width:0; font-size:12.5px; line-height:1.35; color:var(--ink-3)}
.lc-row .rt .mtx{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.lc-row .rt .mic{flex:none; color:var(--ink-3)}
.lc-row .rc{flex:none; align-self:center; color:var(--ink-3)}
.lc-row.has .rd,.lc-row.has .rt{color:var(--ink-1)}
.lc-row.has .rn{color:var(--ink-2)}
.lc-row.past{opacity:.66}
.lc-row.cur{background:rgba(21,94,117,.06); opacity:1}
.lc-row.cur::before{content:''; position:absolute; left:0; top:0; bottom:0; width:3px; background:var(--a-swap)}
.lc-row.cur .rn{color:var(--a-swap)}
.lc-row.cur:hover{background:rgba(21,94,117,.09)}
.lc-row.canc .rn{color:var(--ink-3); font-weight:600}
.lc-row.canc .rd .ck{font-weight:700}
.lc-chip{flex:none; margin-left:6px; font-size:10px; font-weight:700; color:#fff; background:var(--a-swap); border-radius:99px; padding:1px 7px; letter-spacing:.01em}
.lc-fade{flex:none; height:16px; background:linear-gradient(rgba(255,255,255,0),rgba(255,255,255,.9)); margin-top:-16px; position:relative; z-index:1; pointer-events:none}

/* 3층: 데스크톱 아코디언 편집 */
.lc-item.open{position:relative; background:rgba(21,94,117,.045); box-shadow:inset 0 0 0 1px rgba(21,94,117,.12)}
.lc-item.open::before{content:''; position:absolute; left:0; top:0; bottom:0; width:3px; background:var(--a-swap); z-index:1}
.lc-item.open > .lc-row{background:transparent}
.lc-item.open > .lc-row .rc{transform:rotate(90deg)}
.lc-edit{padding:0 14px 12px}
/* ★ 0.1.59 확정 3·스펙 §9-13(축 A69) — `.lc-ta` 는 더 이상 **높이 계약을 지지 않는다.**
   옛 고정 높이 선언을 치웠고, 「기본 한 줄 · 최대 6줄 뒤 내부 스크롤」은 정본 목업의
   `.s-ta`(아래 출석 체크 구획)가 **단독으로** 진다 — 실제 입력창은 `class="lc-ta s-ta"` 라
   둘이 한 요소에 걸리므로, 높이를 두 규칙이 나눠 가지면 뒤 규칙이 앞 규칙을 조용히 되돌린다.
   여기 남는 것은 폭·글꼴·색·테두리 등 **표면과 무관한 공통**뿐이다. */
.lc-ta{width:100%; resize:none; display:block; font-family:inherit; font-size:13.5px; line-height:1.55;
  color:var(--ink-1); background:#fff; border:1px solid rgba(16,18,20,.18); border-radius:8px; padding:9px 11px}
.lc-ta::placeholder{color:var(--ink-3)}
.lc-ta:focus{border-color:var(--a-swap); box-shadow:0 0 0 3px rgba(21,94,117,.14); outline:none}
.lc-ef{display:flex; align-items:center; gap:8px; margin-top:8px}
.lc-n{font-size:11.5px; color:var(--ink-3); font-variant-numeric:tabular-nums; white-space:nowrap}
/* ★ 0.1.71 — 수정 시각은 옆의 글자 수 세기와 **같은 층의 정보**다(사용자 지적: 혼자 크고
   진했다). 예전엔 이름 없는 span 이라 카드 본문 크기·색을 물려받았다. `.lc-n` 과 값을
   맞추되 셀렉터는 따로 둔다 — 화이트리스트가 `.lc-n` 의 «정확히 1회 정의»를 잰다. */
.lc-upd{font-size:11.5px; color:var(--ink-3); white-space:nowrap}
/* ★ 0.1.59 확정 15(축 A75) — 편집기 발치의 실패 문면 규칙을 **지웠다**(이름은 축 A75). 저장·삭제 실패 문면은 카드 맨 위
   `.at-bar > .at-save.fail` 로 옮겼다(「보이는 언어는 하나」 · §9-5). 소비자가 0 이 된 규칙을
   남기면 死 CSS 다(C-T53 축 AF). ★ **`.lc-fail` 은 남는다** — 그건 「조회 실패」(카드가 아직
   안 열린 상태)이고 `.at-bar` 가 담을 자리가 없는 다른 갈래다. */
.lc-f{flex:none; display:flex; align-items:center; gap:8px; padding:10px 14px 12px;
  border-top:1px solid var(--hair); background:rgba(255,255,255,.55)}
.lc-sum{flex:none; display:flex; align-items:center; gap:8px; padding:9px 14px;
  border-bottom:1px solid var(--hair); background:rgba(255,255,255,.55); font-size:12px; color:var(--ink-2)}
.lc-sum b{color:var(--ink-1); font-weight:700}
.lc-load{flex:none; margin:0; padding:18px 14px 16px; font-size:13.5px; line-height:1.6; color:var(--ink-2); font-weight:600}
.lc-fail{flex:none; margin:0; padding:18px 14px 16px; font-size:13.5px; line-height:1.6; color:var(--danger); font-weight:600}
.lc-warn{flex:none; display:flex; align-items:center; gap:8px; flex-wrap:wrap; padding:8px 12px 9px;
  border-bottom:1px solid var(--hair-strong); background:rgba(16,18,20,.045); font-size:12.5px; line-height:1.45; color:var(--ink-1)}
.lc-warn .wic{flex:none; color:var(--ink-2)}
.lc-warn .wtx{flex:1; min-width:120px}

/* 공용 버튼은 기존 기본/primary에 이 세 변형과 텍스트 변형만 더한다. */
.btn.sm{font-size:12px; padding:5px 11px}
.btn.quiet{color:var(--ink-2); border-color:var(--hair); background:transparent}
.btn.danger{color:var(--danger); border-color:rgba(196,43,28,.32)}

/* ══ 출석 체크 · 저장 상태 · 카드 재조판 조각(0.1.59) ══════════════════════════
   정본: mockups/attendance-card.html 의 「신설 B(.at-)」·「신설 D(.s- · M2 정본 상태군)」.
   ★ 이식 판정 기준은 **M2 정본 상태군(S-* 18 상태)이 실제로 소비하는가** 다 — 옛 A~F 후보
     상태만 쓰는 규칙(.at-fold·.at-list·.at-row·.at-box·.at-mark·.at-lock·.at-enter·.at-back·
     .at-tabs·.lc-row .at-lockic·.lc-row.at-ord-chip)은 **안 들여온다**(소비자 0 = 死 CSS).
     인쇄 서식(.s-p* 계열)은 T13 이 `.pv-*` 이름으로 가져간다 — 여기 없다.
   ★ 색은 전부 무채도다. 신호 다섯(초록 보강·앰버 교체·파랑 현재·빨강 취소·보라 대체수업일)을
     빌리지 않는다(스펙 §1-6 · 확정 14). 새 토큰을 만들지 않는다. */

/* 저장 상태 줄 — 출석과 메모가 이 표시 **하나**를 나눠 쓴다(스펙 §9-5 · 확정 15).
   평상시에도 30px 짜리 줄이 자리를 지켜 상태가 바뀔 때 조판이 안 흔들린다. */
.at-bar{flex:none; display:flex; align-items:center; justify-content:flex-end; gap:4px;
  min-height:30px; padding:4px 12px 0}
.at-save{flex:none; display:inline-flex; align-items:center; gap:5px; font-size:11.5px; font-weight:700;
  color:var(--ink-1); white-space:nowrap}
.at-save.pill{background:var(--pnum-idle); border-radius:99px; padding:3px 9px}
.at-save.fail{color:var(--danger)}
.at-save .dot{width:7px; height:7px; border-radius:50%; background:var(--ink-3); flex:none}
.at-save.saving .dot{background:var(--ink-2)}
.at-save.saved .dot{background:var(--ink-1)}
.at-save.fail .dot{background:var(--danger)}
.at-retry{font-family:inherit; font-size:11.5px; font-weight:700; color:var(--danger); background:transparent;
  border:0; padding:0 6px; min-height:44px; min-width:44px; display:inline-flex; align-items:center;
  justify-content:center; cursor:pointer; text-decoration:underline}

/* 출석 체크 구획 머리·안내·발 — 명단이 없을 때와 명단 관리 패널이 쓴다(스펙 §9-6·§9-7) */
.at-sec{flex:none; display:flex; align-items:center; gap:8px; padding:6px 8px 6px 14px;
  border-bottom:1px solid var(--hair); background:rgba(255,255,255,.55); font-size:12px; color:var(--ink-2)}
.at-sec b{color:var(--ink-1); font-weight:700; font-size:12.5px}
.at-sec .sp{flex:1}
.at-cnt{flex:none; font-size:11.5px; font-weight:700; color:var(--ink-1); background:var(--pnum-idle);
  border-radius:99px; padding:2px 8px; letter-spacing:.01em}
.at-hint{flex:none; padding:7px 14px 8px; font-size:11.5px; line-height:1.55; color:var(--ink-2);
  background:rgba(255,255,255,.35); border-bottom:1px solid var(--hair-2)}
.at-hint b{color:var(--ink-1); font-weight:700}
.at-foot{flex:none; display:flex; align-items:center; gap:9px; padding:8px 12px 8px 14px;
  border-top:1px solid var(--hair); background:rgba(255,255,255,.55)}
.at-foot .sp{flex:1}
.at-meta{font-size:11.5px; line-height:1.5; color:var(--ink-2); min-width:0}

/* 차시 목록의 마감 배지(스펙 §9-4) — 바탕은 진행률 칩과 같은 **중성 회청**(--pnum-idle) 위
   --ink-1 = 계산 대비 12.5:1. 무채도 (max−min)/255 = 0.0667 로 신호색이 아니다(축 A28). */
/* ★ 0.1.67 — 배지가 사는 자리가 **출석 체크 진입 줄로 옮겨졌다**(차시 목록에서는 뺐다).
   스코프가 `.lc-row` 뿐이라 옮긴 자리에서 «맨 글자»로 나왔다 — 두 자리를 함께 적는다. */
.lc-row .at-badge,.s-enter .at-badge{flex:none; margin-left:6px; font-size:10.5px; font-weight:700;
  color:var(--ink-1); background:var(--pnum-idle); border-radius:99px; padding:1px 7px;
  letter-spacing:.01em}

/* 1층 둘째 줄 — 첫 줄에서 시각을 뺀 자리로 진도 조각 둘이 내려온다(결정 8 · 스펙 §9-12).
   ★ 0.1.59 T9 가 옛 자리의 두 규칙을 지워 이 이동을 닫았다 — 진도 조각의 자리는 이제 여기 하나다. */
.s-f2{margin-top:3px; font-size:12.5px; line-height:1.5; color:var(--ink-2); letter-spacing:-.01em}
.s-f2 .lc-seg,.s-f2 .lc-ord{color:var(--ink-1); font-weight:600; white-space:nowrap}
.s-f2 .sep{color:var(--ink-3); margin:0 5px}

/* 출석 체크 진입 줄 — 「출석 체크 · 20 / 22명 출석 ›」(결정 1 = A-c · 스펙 §9-1) */
/* ★★ 0.1.65 — **버튼으로 보이게** 한다(사용자 지적: 진입인지 시각적으로 안 갈렸다).
   예전에는 배경도 테두리도 없이 아래 헤어라인만 있어 «목록의 한 줄»과 구별되지 않았다.
   이제 카드 안에서 한 칸 들여 앉은 «누를 것»으로 읽힌다 — 테두리·바탕·둥근 모서리. */
/* ★ 0.1.68 — 라벨을 **가운데**로, 글씨를 키웠다(사용자 요청). 꺾쇠는 흐름에서 빼
   절대 위치로 두어야 «가운데»가 꺾쇠 폭만큼 밀리지 않는다. */
.s-enter{position:relative; display:flex; align-items:center; justify-content:center; gap:6px;
  width:calc(100% - 24px); min-height:52px;
  margin:10px 12px; padding:10px 30px; background:var(--surface); border:1px solid var(--hair-strong);
  border-radius:10px; font-family:inherit; text-align:center; cursor:pointer;
  transition:background-color 150ms ease, border-color 150ms ease}
.s-enter .rc{position:absolute; right:12px; top:50%; transform:translateY(-50%)}
.s-enter:hover{background:var(--pnum-idle); border-color:var(--a-swap)}
.s-enter .t{font-size:16px; font-weight:700; color:var(--a-swap)}
.s-enter .sep{color:var(--ink-3)}
.s-enter .s{font-size:12.5px; color:var(--ink-2)}
.s-enter .sp{flex:1}
.s-enter .rc{flex:none; color:var(--ink-3)}

/* 출석 체크 화면 머리 줄(결정 2 = B-c · 스펙 §9-2). 390px 에서 두 줄로 접히는 것을 허용한다. */
.s-head{flex:none; display:flex; align-items:center; gap:7px; flex-wrap:wrap;
  padding:5px 10px 5px 6px; border-bottom:1px solid var(--hair); background:rgba(255,255,255,.55)}
.s-head b{font-size:13px; font-weight:700; color:var(--ink-1)}
.s-head .sp{flex:1}
/* ★★ 0.1.67 — 머리 줄의 버튼들은 **줄어들지도 접히지도 않는다**(사용자 지적: 「명단 ‹」의
   글자가 잘렸다). flex 기본값 `min-width:auto` 로도 버튼은 내용보다 작아질 수 있고,
   `.btn` 은 `white-space` 를 정하지 않아 좁아지면 글자가 접힌다. 둘 다 못 박는다.
   ★★ 0.1.68 — 그런데 «안 줄어드는 것»만으로는 부족하다: 줄이 좁으면 이번엔 **넘쳐서
   잘린다**(카드가 넘친 부분을 자른다). 그래서 줄어들 «자리»를 하나 지정한다 — 인원 칩이다.
   버튼은 누르는 것이라 잘리면 안 되지만, 칩은 정보라서 줄어도 뜻이 남는다. */
.s-head .s-print,.s-head .btn{flex:none; white-space:nowrap}
.s-head .s-cnt{flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.s-back{font-family:inherit; font-size:12px; font-weight:700; color:var(--ink-1); background:transparent;
  border:0; border-radius:7px; padding:0 9px; min-height:44px; min-width:44px;
  display:inline-flex; align-items:center; justify-content:center; cursor:pointer}
.s-back:hover{background:rgba(16,18,20,.05)}
.s-cnt{flex:none; font-size:11.5px; font-weight:700; color:var(--ink-1); background:var(--pnum-idle);
  border-radius:99px; padding:3px 9px; letter-spacing:.01em}
/* 마감됨 배지 — 무채도(--pnum-idle 위 --ink-1 = 12.5:1). 예약색 5종 미사용(축 A28) */
.s-closed{flex:none; display:inline-flex; align-items:center; gap:5px; font-size:11.5px; font-weight:700;
  color:var(--ink-1); background:var(--pnum-idle); border-radius:6px; padding:3px 8px; letter-spacing:.01em}
.s-when{flex:none; font-size:11.5px; color:var(--ink-2); font-variant-numeric:tabular-nums}
.s-print{font-family:inherit; font-size:12px; font-weight:600; color:var(--a-swap); background:transparent;
  border:0; border-radius:6px; padding:5px 8px; cursor:pointer; white-space:nowrap}
.s-print:hover{background:rgba(21,94,117,.08)}
.s-hint{flex:none; padding:7px 14px 8px; font-size:11.5px; line-height:1.55; color:var(--ink-2);
  background:rgba(255,255,255,.35); border-bottom:1px solid var(--hair-2)}
.s-hint b{color:var(--ink-1); font-weight:700}
/* 출석 체크 화면의 차시 이동 줄(0.1.73 · 사용자 확정 ⓑ). 가운데가 **지금 보고 있는 차시**다 —
   이 화면에는 원래 날짜가 어디에도 없었고, 다른 차시로 옮길 수 있게 된 순간 그 부재가
   「누구의 출석을 찍고 있나」를 못 말하는 결함이 된다. 그래서 라벨을 이동 단추와 한 줄에 둔다.
   ★ 끝 차시에서 단추를 감추지 않고 **비활성**으로 남긴다 — 감추면 줄 폭이 흔들려 라벨이 춤춘다. */
.s-nav{flex:none; display:flex; align-items:center; gap:6px; padding:5px 8px;
  border-bottom:1px solid var(--hair-2); background:rgba(255,255,255,.35)}
.s-navw{flex:1 1 auto; min-width:0; text-align:center; font-size:12.5px; font-weight:700;
  color:var(--ink-1); font-variant-numeric:tabular-nums;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.s-mv{flex:none; font-family:inherit; font-size:12px; font-weight:700; color:var(--ink-1);
  background:transparent; border:1px solid var(--hair); border-radius:7px; padding:0 10px;
  min-height:32px; display:inline-flex; align-items:center; justify-content:center;
  cursor:pointer; white-space:nowrap}
.s-mv:hover:not(:disabled){background:rgba(16,18,20,.05)}
.s-mv:disabled{color:var(--ink-3); border-color:var(--hair-2); cursor:default}
/* 펼친 줄 안의 출석 체크 버튼(0.1.73 · 사용자 확정 ⓐ) — `.btn.sm` 위에 nowrap 만 얹는다.
   글자가 접히면 「명단 ‹」 때와 같은 잘림으로 보인다(0.1.67 교훈). */
.lc-att{white-space:nowrap}

/* 3열 격자 — 결과 학생 = 옅은 채움 **그리고** 네모 칸 안 «/»(색+형태 이중 부호화 · 축 A35).
   화면의 «/» 는 인쇄물의 «/» 와 같은 글자다 — 화면과 종이가 한 낱말로 이어진다. */
.s-grid{flex:1 1 auto; min-height:0; overflow:auto; background:var(--surface);
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:6px; padding:9px 12px 12px; align-content:start}
.s-cell{display:flex; align-items:center; gap:6px; min-height:46px; padding:4px 7px;
  border:1px solid var(--hair); border-radius:9px; background:transparent; font-family:inherit;
  text-align:left; cursor:pointer}
.s-cell:hover{background:rgba(16,18,20,.035)}
/* ★ 2026-09-08 합반명렬 태스크 G — `.no` 가 「6-01」·「타교 01」로 길어지면(위 T3) 결과 배지
   (`.s-sl`)가 붙은 칸에서 `.nm`(이름) 자리가 모자란다(코디네이터 실렌더 실측): 930px 창
   3열에서 45px, 380px 창 3열에서 18px — 실명 폭(같은 글꼴) 2자 24.2px·3자 36.3px·4자
   48.4px 에 못 미친다. 기준선(반 표시 없음)에서는 안 잘린다 — 이 아크가 만든 문제다.
   `.s-sl` 을 좁히는 길은 기각됐다(0.1.70 이 「한 글자→두 글자」로 넓힌 자리라 되돌릴 수
   없다). `.s-grid.mixed` 아래에서만 3열 고정을 auto-fill(최소 130px)로 풀고 여백을 줄인다 —
   후보 넷 중 이 조합만 두 창을 다 살린다: 930px 은 **3열 유지**(45→54px, 4자 ✅), 380px 은
   **2열 자동**(18→87px, 4자 ✅). auto-fill 단독은 930px 이 45px 그대로, 여백만 줄이면
   380px 이 30px(3자 ❌), 늘 2열이면 930px 이 칸 215px·8행으로 과하다. 반이 하나뿐인
   절대다수 격자는 `.mixed` 밖이라 바이트 그대로다(불변식 I2). */
.s-grid.mixed{grid-template-columns:repeat(auto-fill,minmax(130px,1fr)); gap:4px}
.s-grid.mixed .s-cell{gap:4px; padding:4px 5px}
/* ★ 2026-09-08 합반명렬 — 안에 드는 것이 **두 글자**(`07`)에서 **넷·다섯 글자**(`6-01`·
   `타교 01`)로 늘 수 있다(합반·공동교육과정, 스펙 §3-2 S6). 고정 20px 이면 글자가 넘치므로
   폭을 내용에 맡기되 최소치를 둔다(빈 칸이 찌그러지지 않게) — `.s-sl`(아래 `min-width:19px`
   규칙)의 0.1.70 선례와 같은 이유다.
   ★ 2026-09-09(B6): 여기 적혀 있던 「1572행」을 **콘텐츠 앵커로 바꿨다.** 그 숫자는 백로그
     작성 시점에 이미 1590 이었고 이 아크 시점엔 1634 였다 — 자기 파일의 줄을 숫자로 가리키는
     주석은 위아래에 한 줄만 들어와도 낡는다. 줄번호로 되돌리지 마라. */
.s-cell .no{flex:none; min-width:20px; font-size:12.5px; font-weight:700; color:var(--ink-3);
  font-variant-numeric:tabular-nums; letter-spacing:-.01em}
.s-cell .nm{flex:1; min-width:0; font-size:14px; font-weight:600; color:var(--ink-1);
  letter-spacing:-.01em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* ★ 0.1.70 — 안에 드는 것이 «한 글자»(/)에서 «두 글자»(결과)로 바뀌었다. 고정 19px 이면
   글자가 넘치므로 폭을 내용에 맡기되 최소치를 둔다(빈 칸이 찌그러지지 않게). */
.s-sl{flex:none; min-width:19px; height:22px; padding:0 5px; border:1px solid var(--ink-1);
  border-radius:3px; display:none; align-items:center; justify-content:center; line-height:1;
  font-size:11.5px; font-weight:700; color:var(--ink-1); white-space:nowrap}
.s-cell.on{background:var(--pnum-idle); border-color:var(--hair-strong)}
.s-cell.on .no{color:var(--ink-1)}
.s-cell.on .s-sl{display:inline-flex}
/* 마감 후 — 색을 빼서 흐리게 하지 않는다(0.1.58 교훈). 조작만 잠근다. */
.s-grid.locked .s-cell{cursor:default; background:rgba(16,18,20,.022)}
.s-grid.locked .s-cell:hover{background:rgba(16,18,20,.022)}
.s-grid.locked .s-cell.on{background:var(--pnum-idle)}

/* 메모 입력창: 기본 한 줄 · 내용만큼 늘어나되 6줄에서 멈춘다(결정 3 · 스펙 §9-13).
   ★ 0.1.59 T9 갱신 — 입력창은 `class="lc-ta s-ta"` 라 둘이 한 요소에 걸린다. **높이 계약은 이
     규칙이 «단독으로» 진다** — T9 이 `.lc-ta` 의 옛 고정 높이 선언을 치웠다. 나눠 가지면
     뒤 규칙이 앞 규칙을 조용히 되돌린다(시험은 초록인데 화면만 어긋나는 형태).
   ★ max-height 의 9.3em = 6줄 × 1.55em, +20px 는 패딩 9+9 와 테두리 1+1 이다. `em` 이라
     coarse(16px)에서도 스스로 6줄이 된다 — JS(`autosizeNoteTa`)의 px 상한은 그 위의 안전망이다. */
.s-ta{height:calc(1.55em + 20px); max-height:calc(9.3em + 20px); min-height:0}
.s-nol{font-size:12px; color:var(--ink-2)}
.s-path{font-variant-numeric:tabular-nums; color:var(--ink-1); font-weight:600}

/* ══ 인쇄 미리보기(0.1.59 T13) — 나이스 「교과시간별출석부」 서식 전사 ═══════════════
   정본: mockups/attendance-card.html 의 `S-print-preview-980`·`S-print-paper-980`(`.s-p*` 15계열).
   이름만 `.pv-*` 로 옮겼다(인쇄 영역 클래스 `.pv-paper` 가 축 A70 의 앵커다 · 플랜 T13).
   ★★ **`.pv-*` 는 `.lc-card` «밖»이다**(스펙 §17-3-6). 카드 밖 전면이고 진입이 윈도우 앱
     전용이라 coarse 표면에 존재하지 않는다 → A41(coarse 44px)·A43(safe-area)·A74(coarse
     블록 하나)의 대상이 **아니고**, `.lc-` 접두를 안 쓰므로 C-T31(카드 색 계약)의 대상도 아니다.
   ★ 표 안 조각(.c1/.c3/.c4/.dc/.dd/.pp/.nm/.mk/.out)은 **전부 `table.pv` 로 스코프**한다 —
     bare 로 두면 다른 화면의 같은 이름과 부딪힌다(C-T30 bare 스윕이 그 사고를 잡는다).
   ★ 색은 무채도다. 신호 다섯을 빌리지 않고 새 토큰도 만들지 않는다. */
.pv-full{flex:1 1 auto; align-self:stretch; min-height:0; display:flex; flex-direction:column;
  background:var(--surface); color:var(--ink-1); border-radius:10px; overflow:hidden;
  box-shadow:0 28px 56px rgba(16,18,20,.30),0 2px 12px rgba(16,18,20,.16)}
.pv-head{flex:none; display:flex; align-items:center; gap:10px; padding:10px 14px;
  border-bottom:1px solid var(--hair); background:rgba(255,255,255,.55)}
.pv-head h3{margin:0; font-size:15px; font-weight:700; letter-spacing:-.02em; color:var(--ink-1)}
.pv-head .sp{flex:1}
.pv-pick{font-family:inherit; font-size:12.5px; font-weight:600; color:var(--ink-1); background:var(--surface);
  border:1px solid var(--hair-strong); border-radius:7px; padding:5px 9px}
.pv-scroll{flex:1; min-height:0; overflow:auto; padding:16px; display:flex; justify-content:center;
  background:#d8dade}
/* 인쇄 영역 — 이 안에 들어가는 것은 `renderAttendanceSheet(monthly)` 의 반환값뿐이다(축 A70) */
.pv-paper{width:100%; max-width:900px; display:flex; flex-direction:column; gap:16px}
.pv-sheet{background:#fff; color:var(--ink-1); box-shadow:0 2px 10px rgba(16,18,20,.14); padding:20px 22px 22px}
.pv-pdate{font-size:10.5px; color:var(--ink-1); text-align:right; font-variant-numeric:tabular-nums}
.pv-t1{margin-top:8px; font-size:17px; font-weight:700; text-align:center; letter-spacing:-.01em}
.pv-t2{margin-top:14px; display:flex; justify-content:space-between; align-items:flex-start;
  gap:12px; font-size:11.5px; line-height:1.75; color:var(--ink-1)}
/* `container-type` — 아래 차시 열 폭이 **이 상자의 실제 폭(100cqw)** 에서 나온다(0.1.95 · 종이 폭을 박지 않는다).
   `--pvn` = 이 쪽의 차시 열 수 — 렌더러가 쪽마다 인라인으로 덮는다(기본 20 = 한 쪽 상한). */
.pv-tblwrap{position:relative; margin-top:8px; overflow-x:auto; container-type:inline-size; --pvn:20;
  -webkit-print-color-adjust:exact; print-color-adjust:exact}
/* ★★ 0.1.64 — `table-layout:fixed` 다. 자동 배치에서는 아래 width 가 «제안»일 뿐이라
     차시 열이 늘면 브라우저가 고정 열부터 깎는다 — 실제로 「일반학과」가 28.5pt 로 눌려
     줄바꿈이 났고(실측) 정작 차시 열은 27pt 를 낭비하고 있었다. 나이스 실물은 반대다:
     고정 열에 넉넉히 주고(학과 78pt) 차시 열을 17pt 로 좁힌다.
     고정 배치에서는 width 가 지켜지고 **남은 폭을 차시 열이 균등하게** 나눠 갖는다 —
     주당 4시간(월 18열)도 A4 세로 한 장에 들어간다. */
/* ★★ 0.1.96(2026-09-30 사용자 「선 굵기·색이 고르지 못하다」 → 「나이스 원본에 맞춰라」 → 「굵기가 너무 굵다」) —
     선은 나이스 원본(`download-99096572666889063.pdf` 벡터 실측)의 **굵기 그대로**다:
       · 안쪽 격자 = **검정 0.602pt** · 바깥 네 변만 = **검정 0.957pt**
       · 머리 칸 배경 **없음**(흰 칸) · 머리 칸과 본문 사이도 안쪽과 같은 가는 선
     ★ 선을 `border` 로 긋지 않는다 — 인쇄 엔진(Chromium · 앱 PDF 저장도 같다)이 테두리 굵기를
       **1px(0.75pt) 단위로 반올림**해 0.6pt·0.96pt 가 둘 다 0.75pt 가 됐고, 그래서 0.1.95 는 1px·2px
       (0.75pt·1.5pt)을 써 원본보다 굵었다(600dpi 바깥 13화소 vs 원본 8).
     ★ 선 = **1px 검정 막대를 변형(transform)으로 줄이거나 키운 것**이다: 안쪽 ×0.8027(= 0.602/0.75) ·
       바깥 ×1.276(= 0.957/0.75). 변형은 반올림되지 않는다 — PDF 실측 안쪽 0.602pt · 바깥 0.957pt 로
       원본과 같고 단색 채움이다(600dpi 먹량 1289 · 원본 1276 · 0.1.95 는 1598).
       ✗ 시도하고 버린 것: SVG 배경(0.75pt 로 반올림) · 그라디언트 배경(0.6pt 는 되지만 PDF 에 «패턴
       채움»으로 들어가 뷰어가 가장자리 흐림 없이 2~3화소로 꽉 채워 오히려 진했다 — 150dpi 먹량 577 vs 386).
     ★★ `print-color-adjust:exact` 가 **필수**다: 막대는 배경색이고 「인쇄」 창 「배경 그래픽」 기본값은
       꺼짐이라, 이 설정이 없으면 선이 **통째로 사라진다**(양성 대조 실측: 배경 끔 + exact 없음 → 선 0).
       상속되는 속성이라 표 하나에 건다. 같은 까닭에 회색 칸(td.out)도 이제 배경 끔 인쇄에서 찍힌다.
     ★ 막대는 각 칸의 **오른쪽(::after)·아래(::before)** 에 있다. 맨 오른쪽 칸·맨 아래 행은 그 막대를
       바깥 굵기로 키우고(`--pvsx`·`--pvsy`), 왼쪽·위 바깥 두 변은 표를 감싼 상자가 긋는다(`.pv-tblwrap`).
     ★ 전에는 rgba(16,18,20,.45) 테두리였다: 조각이 겹치는 교차점 · 머리 칸 배경 위에서 같은 선이 더
       진해졌다(PDF 채움 불투명도 .451 실측). 불투명 검정은 겹쳐도 같은 색이다. */
table.pv{width:100%; table-layout:fixed; border-collapse:separate; border-spacing:0; font-size:11px;
  font-variant-numeric:tabular-nums; -webkit-print-color-adjust:exact; print-color-adjust:exact}
table.pv th,table.pv td{position:relative; border:0; padding:3px 2px; text-align:center; line-height:1.3;
  color:var(--ink-1)}
table.pv th::after,table.pv td::after{content:''; position:absolute; top:0; right:0; bottom:0; width:1px;
  background:#000; transform:scaleX(var(--pvsx, .8027)); transform-origin:right center; pointer-events:none}
table.pv th::before,table.pv td::before{content:''; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:#000; transform:scaleY(var(--pvsy, .8027)); transform-origin:center bottom; pointer-events:none}
table.pv tr > :last-child{--pvsx:1.276}
table.pv tbody tr:last-child > *{--pvsy:1.276}
.pv-tblwrap::before{content:''; position:absolute; left:0; top:0; bottom:0; width:1px; background:#000;
  transform:scaleX(1.276); transform-origin:left center; pointer-events:none; z-index:1}
.pv-tblwrap::after{content:''; position:absolute; left:0; right:0; top:0; height:1px; background:#000;
  transform:scaleY(1.276); transform-origin:center top; pointer-events:none; z-index:1}
table.pv thead th{font-weight:700; vertical-align:middle}
table.pv th.c1{width:30px}
table.pv th.c3{width:64px}
/* ★★ 0.1.95 — 차시 열 폭을 **정수 px** 로 내리고(아래 th.dc) 남는 자투리를 `성 명` 열이 받는다.
     전에는 남은 폭을 차시 열이 똑같이 나눠 36.86px 같은 소수 폭이 됐고, 엔진이 선을 1px 격자에
     맞추며 36px·37px 열이 섞였다 — 인쇄·PDF 에서 세로선이 화소 경계마다 달리 떨어져 굵기·진하기가
     갈렸다(래스터 실측: 600dpi 세로선 3가지 → 정수 폭 1가지). `성 명` 은 76px 아래로 안 준다 —
     `--pvfix` 가 그 76px 을 먼저 떼고 계산한다.
     `--pvfix` = 고정 여섯 열 합 260px(선이 배경 그림이라 테두리 몫이 없다 · 0.1.95 는 +2) — 타교 계열은 `반` 46px 더. */
table.pv th.c4{width:auto}
table.pv{--pvfix:260px}
table.pv.longcls{--pvfix:306px}
table.pv th.dc{width:round(down, calc((100cqw - var(--pvfix)) / var(--pvn)), 1px)}
/* ★★ 2026-09-08 합반명렬(적대 리뷰 C2) — **타교가 든 계열만** `반` 열을 넓힌다.
     공동교육과정 명렬의 `반` 칸은 나이스 원본대로 **과목명 문자열**이다(확정 D3 · '고급 대수').
     기본 30px 에서 실렌더 실측이 `clientWidth 29px / scrollWidth 43px` 였고(2026-09-08),
     위 `white-space:nowrap` 탓에 그 글자가 옆 `번호` 칸을 덮어 **타교생 열 줄의 번호가
     종이에서 안 읽혔다.** 값 76px 은 이 표의 가장 넓은 선례(`th.c4` 성 명)를 그대로 쓴 것이다 —
     실측 43px 에 여유가 있고, 과목명이 한두 글자 길어져도 다시 고칠 일이 없다. 이 계열은
     차시 열이 셋뿐이라(주 3시간) 고정 열을 넓혀도 남은 폭이 넉넉하다.
   ★ 기본 `th.c1{width:30px}` 은 **한 글자도 안 고친다** — 기존 명렬 열세 건의 인쇄물이
     바이트 그대로여야 한다(불변식 I1). 이 규칙은 렌더러가 그 계열에만 붙이는 수식 클래스
     `.longcls` 아래에서만 산다(`attendance-print.js` 의 `needsWideClassCol`).
   ★ `@media print` 에 `th.c1` 재정의가 **없어** 이 폭이 종이에도 그대로 간다
     (2026-09-08 print 에뮬레이션 실렌더로 확인 — 화면과 같은 폭이다). */
table.pv.longcls th.c1:nth-child(4){width:76px}
/* 고정 여섯 열은 줄바꿈하지 않는다 — 「일반학과」가 두 줄로 깨지던 자리다. */
table.pv th:nth-child(-n+6),table.pv td:nth-child(-n+6){white-space:nowrap}
/* 머리글 세 줄(날짜/요일/교시) — 18열에서도 옆 열과 안 겹치게 작고 촘촘하게. */
table.pv th.dc{font-size:8px; font-weight:600; padding:2px 0; line-height:1.25}
/* 세 줄 사이에 가로선 — 날짜/요일/교시가 무엇인지 눈으로 갈린다(사용자 요청 0.1.65).
   위 칸 테두리와 같은 색·굵기라 표의 격자와 한 몸으로 보인다.
   ★★ F5(2026-10-12 · 실제 제품 폰트 실측으로 F4 대체) — 5자 날짜는 19px 칸(`longcls` 20열)에
   **그냥은 안 들어간다**. 실제 폰트(Pretendard Variable · document.fonts check true) 인쇄
   에뮬레이션 실측: `10/12` 가 tabular 숫자로 **23.39px**(기본 계열은 칸 22px → −1.39px),
   F4 자간(−0.06em)에서도 21.00px(칸 19px → −2.00px, 루트 실제 PDF textRight 522.66 >
   cellRight 520.66). 최악은 `10/30` 21.82px 다.
   · 날짜 머리글은 칸마다 홀로 서므로 **tabular 정렬이 필요 없다** → 비례 숫자로 바꾼다
     (`10/12` 20.15px → `10/30` 21.82px).
   · 여기에 자간 −0.12em(=−0.96px) → 최악 `10/30` **17.03px**(칸 19px · 여유 1.97px),
     `10/12` 16.16px(여유 2.84px). 기본 계열은 여유 ~4.2px 로 더 넉넉하다.
   크기(8px)·굵기(600)·세 줄 구성·선 굵기·쪽 나눔(20열)·NEIS 여섯 열은 그대로다.
   ★ F4 의 `.longcls` 전용 자간 규칙은 지웠다 — 그 스코프는 F4 가 **4자 날짜(`10/1`)를
     5자로 착각해** 잰 값(18.27px)에 기초한 오판이었고, 기본 계열도 A4 에서 넘쳤다. */
table.pv th.dc .dd{display:block; white-space:nowrap; padding-bottom:1px;
  font-variant-numeric:normal; letter-spacing:-.12em}
table.pv th.dc .dw{position:relative; display:block; color:var(--ink-2); font-weight:500; padding:1px 0}
table.pv th.dc .dw::before,table.pv th.dc .dw::after{content:''; position:absolute; left:0; right:0; height:1px;
  background:#000; transform:scaleY(.8027); pointer-events:none}
table.pv th.dc .dw::before{top:0; transform-origin:center top}
table.pv th.dc .dw::after{bottom:0; transform-origin:center bottom}
table.pv th.dc .pp{display:block; color:var(--ink-2); padding-top:1px}
table.pv td.nm{text-align:center; font-weight:600; white-space:nowrap}
/* ★★ 0.1.95(사용자 「표의 위아래 높이가 학생마다 다르다」) — 본문 행 높이는 **고정**이다.
     전에는 행 높이가 글자에서 나왔다: «/» 만 12.5px 굵은 글씨라 그 칸의 줄 높이가 커져 «/» 가
     있는 행만 23.25px(종이 · 나머지 19.344px)였고, 19.344px 을 엔진이 1px 격자에 맞추며 19px·20px
     행도 섞였다. 지금은 모든 본문 칸이 같은 높이이고 «/» 는 그 높이 안에서 줄 높이를 묶는다
     (글자 크기는 그대로 12.5px). 화면 22px · 종이 20px(아래 인쇄 블록) — 둘 다 정수 px 라
     선이 행마다 같은 자리에 떨어진다. */
table.pv tbody td{height:22px; padding-top:0; padding-bottom:0}
table.pv td.mk{font-size:12.5px; font-weight:700; line-height:12px}
/* 명단 밖(전입 전·전출 뒤) — 옅은 회색. 이 칸에는 «/» 를 찍지 않는다(렌더러가 진다)
   ★ `background-color` 만 쓴다 — `background:` 줄임말은 위 칸 선 그림(background-image)까지 지운다. */
table.pv td.out{background-color:rgba(16,18,20,.10)}
.pv-foot{margin-top:12px; display:flex; justify-content:space-between; align-items:center;
  font-size:10.5px; color:var(--ink-2)}
.pv-foot span{flex:1}
.pv-foot span:nth-child(2){text-align:center}
.pv-foot span:last-child{text-align:right}

/* ★★ 인쇄 조판 — 인쇄되는 것은 `.pv-paper` 하나이고 그 형제(머리·선택·버튼)는 인쇄 영역
     «밖»이라 애초에 종이에 없다. 여기서 감추는 것은 «화면 크롬의 조판»이지 인쇄 영역의
     내용이 아니다 — 인쇄 영역 안의 무엇을 이 블록에서 감추기 시작하면 확정 13 이 CSS
     한 줄로 뚫린다(축 A70).
   ★ `@page` 는 **A4 세로**다(원본이 세로). 정본 목업 상단 M1 후보 구역의 가로 지정은
     후보 기록의 문서 크롬이지 앱으로 옮기는 규칙이 아니다(스펙 §8-2).
   ★ 쪽 나눔은 종이 사이에서만 일어난다. 쪽 **번호**는 렌더러가 직접 쓴다(CSS 카운터 금지). */
@media print{
  /* ★★ 2026-09-03 사용자 정정 — `margin:0` 이다.
       크로미움은 **쪽 여백 영역에 자기 머리말·꼬리말을 그린다**(왼쪽 위 날짜 · 가운데 문서
       제목 · 왼쪽 아래 원본 주소 `tauri.localhost` · 오른쪽 아래 `1/1`). 실제 출력물에서
       그 넷이 종이에 찍혀 나왔다. 여백을 0 으로 두면 **그릴 자리가 없어 사라진다.**
       그 대신 여백은 종이(`.pv-sheet`)가 자기 패딩으로 만든다 — 값 12mm 는 나이스 실물
       실측에서 왔다(표 왼쪽 x=34.8pt ≒ 12.3mm · 날짜 y=35pt ≒ 12mm). */
  @page{size:A4 portrait; margin:0}
  /* ★★ F-B I-2(Critical) — 인쇄 영역 «밖»은 «감춘다». 전에는 `.pv-full`/`.pv-sheet` 의 흰
       배경이 앱 화면을 «칠했을» 뿐이라 종이는 멀쩡해 보였지만, 앱 셸·시간표·차시 카드가
       레이아웃에 그대로 남아 **PDF 텍스트 층에 실렸다**(실측: 인쇄 PDF 에서 교사 메모 첫
       줄과 다른 학급·다른 교사 이름까지 추출됐다). 칠하지 말고 레이아웃에서 없앤다.
     ★ 몸통 세 자리가 대상이다 — `header.appbar`·`.body`(레일 + main)와, 몸통에 직접 붙는
       겹침 그릇들(`.alert-smoke`·`.modal-bg`). 차시 카드 `.lc-card` 는 메모를 싣는 그릇이라
       인쇄 영역 밖에서 «반드시» 감춘다.
     ★ `.lc-smoke` 는 **감추지 않는다** — 인쇄 미리보기(`.pv-full`)가 그 «안»에 산다.
       감추면 종이까지 사라진다. 겹침용 선언(fixed·검은 막·뷰포트 높이·가운데 정렬)만 풀어
       종이가 문서 흐름에 그대로 흐르게 둔다. */
  header.appbar, .body, .alert-smoke, .modal-bg, .lc-card{display:none !important}
  .lc-smoke{position:static; display:block; height:auto; padding:0; background:none}
  /* ★ 화면에서 감춘 종이(`pv-off`)를 인쇄에서는 도로 보인다. `.lc-smoke.pv-off` 가
       `.lc-smoke` 보다 특정도가 높아 그냥 두면 위 규칙이 져서 «백지»가 나온다. */
  .lc-smoke.pv-off{display:block !important; position:static; height:auto; padding:0}
  .pv-head{display:none !important}
  .pv-scroll{overflow:visible; padding:0; background:#fff}
  .pv-full{box-shadow:none; border-radius:0}
  .pv-paper{max-width:none; gap:0}
  /* 쪽 여백을 «종이»가 만든다(위 @page margin:0 주석 참조).
     ★ 꼬리(쪽번호·학교명)는 나이스 실물에서 **쪽 맨 아래**다(실측 y=789.9 / A4 842pt).
       종이를 쪽 높이만큼 세우고 꼬리를 아래로 밀지 않으면 표 바로 뒤에 떠서 종이가 달라 보인다. */
  .pv-sheet{box-shadow:none; padding:12mm; min-height:100vh; box-sizing:border-box;
            display:flex; flex-direction:column}
  .pv-sheet .pv-foot{margin-top:auto}
  .pv-sheet + .pv-sheet{break-before:page; page-break-before:always}
  table.pv{font-size:9.5px}
  /* 종이 본문 행 = 20px 고정(0.1.95 · 위 `table.pv tbody td` 주석) — 9.5px 글꼴 한 줄(12.35px)이 들어간다 */
  table.pv tbody td{height:20px}
}

@media (max-width: 460px){
  .lc-row{padding:11px 10px 12px 14px; min-height:52px}
  .lc-all{padding:8px 10px}
  /* 2026-09-02 후속 ② · 확정 18 — 전용 편집 화면을 없앴으므로 저장줄을 **인라인 편집기 안에서**
     입력창 위로 올린다. 그 화면이 [저장]을 위에 둔 이유(키보드가 아래를 덮는다)는 화면이 사라져도
     그대로다 — 사용자가 실기기에서 이미 겪은 증상이다.
     ★ .lc-edit 을 flex 컨테이너로 바꾸는 것까지가 계약이다 — order 는 flex/grid 자식에만 듣는다.
       .lc-ef 에 order:-1 만 넣으면 **아무 일도 안 일어나는데 존재 단언은 통과한다**(축 AH).
     ★ margin-top:0 · margin-bottom:8px 도 계약이다 — 기본 규칙의 margin-top:8px 을 그대로
       두면 위로 올라간 저장줄이 아래쪽 여백 없이 입력창에 붙는다.
     ★ 새 블록을 만들지 않고 기존 460px 블록 안에 더한다(C-T33 이 .lc-* @media 블록을 하나로 잠근다). */
  .lc-edit{display:flex; flex-direction:column}
  .lc-ef{order:-1; margin-top:0; margin-bottom:8px}

  /* ── 담임 폰 「한 칸 보기」 (2026-09-23 G1 확정 · W1 CSS 몫) ──────────────────
     담임 2열은 flex 가 아니라 좌표다(.tl-col-l/-r 의 left·right). 460 이하에서만 두 칸을
     «같은 자리»로 겹치고 `#tl` 의 `data-pane`(W2 가 렌더 · 기본 me)으로 한 칸만 보인다.
     알약 둘은 그 위에 남는 탭이다. 이 블록은 좌표·가시성·타깃과 발견성(위치 막대·비운
     알약)만 바꾼다 — 460 초과는
     이 블록 밖이라 한 픽셀도 안 바뀐다(넓은 화면은 data-pane 속성을 그냥 무시한다). */
  /* L1 두 칸을 같은 자리로 — 한 칸의 폭은 콘텐츠 전폭(좌 48 ~ 우 12)이다. */
  .tl2 .tl-col-l, .tl2 .tl-col-r{left:48px; right:12px}
  /* L2 오른쪽 알약은 오른쪽 끝으로 — 같은 자리에 겹치면 두 알약이 왼쪽에서 포개진다. */
  .tl2 .tl-col-r .tl-col-chip{left:auto; right:0}
  /* L3 ★ 안 보는 칸은 «칸 상자째» 숨긴다. 시안의 자식 숨김은 틀렸다: 겹친 위 칸
     (.tl-col-r, DOM 뒤)의 투명한 칸 상자가 히트 테스트에서 터치를 가로채, 보이는
     「내 수업」 카드를 눌러도 차시 노트가 안 열린다. visibility 는 상속되므로 알약만
     되살린다 — 되살린 알약은 다시 눌린다. */
  .tl2:not([data-pane="hr"]) .tl-col-r,
  .tl2[data-pane="hr"] .tl-col-l{visibility:hidden}
  /* L3·L4·L5 알약 되살림 + 누름 + 비운 알약 전이. 기본 `.tl-col-chip` 의 pointer-events:none 은
     블록 «밖»에 그대로 산다 — 460 초과에서는 알약이 눌리지 않는다(과잉 교정 금지).
     ★ top:16px(2026-09-23 W8) — 알약 줄을 25→16px 로 9px 올려(16~43) 그 아래 47~50 에
       위치 막대 자리를 만든다. 기본 `.tl-col-chip` 의 top:25px 은 블록 «밖» 그대로다. */
  .tl2 .tl-col-chip{visibility:visible; pointer-events:auto; cursor:pointer; top:16px;
    transition:background-color .2s, box-shadow .2s}
  /* L4 터치 영역 세로 44px — 알약은 27px 이라 손가락에 작다. 보이지 않는 ::after 로만 넓힌다.
     ★ F8(R1 리뷰 · 2026-09-23) — 합계 45px 는 그대로 두고 **위를 늘리고 아래를 줄인다**.
       예전 top/bottom −9px 는 영역이 y 16~61 이라 첫 교시 카드 윗단(56px) 5px 를 가로챘다.
       W8(2026-09-23)에서 알약이 16~43 으로 올라가 이제 ::after(−14/−4)는 y 2~47 —
       첫 카드(56)와 한 픽셀도 안 겹친다(위쪽은 알약 위 빈 자리). */
  .tl2 .tl-col-chip::after{content:""; position:absolute; left:0; right:0; top:-14px; bottom:-4px}
  /* ① 위치 막대(2026-09-23 W8 발견성) — 알약 줄 아래 얇은 트랙(콘텐츠 폭 전체) + 절반 손잡이.
     지금 보는 쪽에 손잡이가 선다(스크롤 바 문법). 트랙은 좌 48 ~ 우 12(한 칸 폭 그대로)라
     손잡이 폭 `(100% − 60px) / 2` 의 `translateX(100%)` 가 정확히 반대쪽 절반으로 간다.
     ★ y 47~50 — 알약(16~43)과도, 첫 눈금 08:20(56px)과도 안 겹친다(눈금과 6px).
     ★ `pointer-events:none` — 알약의 터치 영역(::after)을 가로채지 않는다.
     ★ `transition:transform .2s` 미끄러짐은 전역 prefers-reduced-motion 블록이 끈다. */
  .tl2::before{content:""; position:absolute; left:48px; right:12px; top:47px; height:3px;
    border-radius:2px; background:rgba(16,18,20,.07); pointer-events:none}
  .tl2::after{content:""; position:absolute; left:48px; width:calc((100% - 60px) / 2); top:47px; height:3px;
    border-radius:2px; background:rgba(16,18,20,.34); pointer-events:none; transition:transform .2s ease-out}
  .tl2[data-pane="hr"]::after{transform:translateX(100%)}
  /* L5(⑥ 2026-09-23 W8 재정의) 안 보는 쪽 알약은 «비운 알약» — 흐리게(opacity .45) 대신
     불투명 그대로 두고 바탕을 비우고 1px 테두리만 남긴다(「꺼진 버튼」으로 읽히지 않게).
     전이도 opacity 가 아니라 background-color·box-shadow 다(흐림이 사라졌다). */
  .tl2:not([data-pane="hr"]) .tl-col-r .tl-col-chip,
  .tl2[data-pane="hr"] .tl-col-l .tl-col-chip{opacity:1; background:transparent;
    box-shadow:inset 0 0 0 1px rgba(16,18,20,.16)}
  .tl2:not([data-pane="hr"]) .tl-col-r .tl-col-chip .chip-dot,
  .tl2[data-pane="hr"] .tl-col-l .tl-col-chip .chip-dot{background:transparent}
  /* L6 새로 보이는 칸의 자식들이 0.2초 미끄러져 들어온다. `data-slide` 와 `data-pane` 이
     «둘 다» 맞을 때만 — `data-pane` 만으로 걸면 동기화 재렌더마다 칸이 미끄러진다.
     `data-slide` 는 W2 가 «전환 순간에만» 붙이고 렌더 결과에는 없다. */
  .tl2[data-pane="hr"][data-slide="from-right"] .tl-col-r > :not(.tl-col-chip){animation:tl-pane-from-right .2s ease-out both}
  .tl2[data-pane="me"][data-slide="from-left"] .tl-col-l > :not(.tl-col-chip){animation:tl-pane-from-left .2s ease-out both}

  /* 공강 찾기 3안-A — 열 머리의 대체 수업 표시 「10/17(금)」 사이엔 줄 나눌 자리가 없어 44~52px 열을
     넘쳐 격자가 가로로 밀렸다(시안 측정 10-15 · 6열 주 375·390) → 좁은 폭에서는 아랫줄로 내린다. */
  .ft-grid .hd .wk-swap{display:block; margin-left:0}
  /* 6열 주(열 44~50px)에서는 「(목) 오늘」이 열을 넘어 이웃 「(금)」을 덮었다(측정 10-15 · 375·390) →
     알약을 요일 아랫줄 가운데로. 5열(52px~)은 넘쳐도 이웃 글자를 안 덮어 그대로 둔다. */
  .ft-grid[data-cols="6"] .hd .dow .wk-pill{grid-column:2; grid-row:2; justify-self:center; margin:1px 0 0}
}

/* L6 미끄러짐 키프레임 — 이동 거리 24px 안팎(과하지 않게) · 투명도 0→1. */
@keyframes tl-pane-from-right{from{transform:translateX(24px); opacity:0} to{transform:translateX(0); opacity:1}}
@keyframes tl-pane-from-left{from{transform:translateX(-24px); opacity:0} to{transform:translateX(0); opacity:1}}
/* L6 움직임 줄이기 설정이면 미끄러지지 않는다. 폭 조건 없는 순수 prefers-reduced-motion
   블록으로 둔다(정규식 도우미가 두 번째 460 블록으로 오인하지 않도록) — 460 밖에는
   애니메이션 자체가 없어 animation:none 은 무해하다. */
@media (prefers-reduced-motion: reduce){
  .tl2[data-pane="hr"][data-slide="from-right"] .tl-col-r > :not(.tl-col-chip),
  .tl2[data-pane="me"][data-slide="from-left"] .tl-col-l > :not(.tl-col-chip){animation:none}
}

/* ★★ 이 블록은 iOS 16px 방지 **와** 카드 44px 타깃 둘을 진다(0.1.59 · 스펙 §9-8 · 축 A74).
   iOS Safari는 계산 font-size가 16px 미만인 텍스트 입력을 포커스할 때 확대한다.
   실측 .lc-ta 13.5px, .free-picker 12.5px, .wg-search 12px, .ap-m 14px를 16px로 덮는다.
   Tauri 데스크톱(마우스) 조판은 유지하고 JS 부팅 실패에도 안전하도록 터치 장치 미디어쿼리만 사용한다.
   ★ 44px 규칙에 **새 @media 블록을 만들지 않는다** — 만들면 같은 조건의 블록이 셋이 되고
     이 블록과 `.lc-ta` 를 나눠 갖는다(변이 M119). 데스크톱은 44px 규칙 «밖»이다(결정 9) —
     `.lc-x` 30px · `.btn.sm` 26px 등 현행 값이 블록 밖에 그대로 산다. */
@media (hover: none) and (pointer: coarse){
  .lc-ta,
  .free-picker input,
  .wg-search input,
  /* ★ 0.1.59 T13 — 인쇄 미리보기의 수업·월 select 둘. **44px·safe-area 축과는 다른 축**이다:
     A41·A43·A74 는 터치 «타깃»이라 `.pv-*` 가 대상이 아니지만(스펙 §17-3-6), 이 블록이 지는
     것은 「16px 미만 입력을 포커스하면 확대된다」는 **글씨 축**이고 그 정적 인벤토리
     (theme-css.test.mjs 「text-input template inventory」)는 템플릿의 select 전량을 훑는다.
     터치 스크린 윈도우 기기에서 앱을 쓰면 이 화면도 coarse 로 잡히므로 죽은 규칙이 아니다. */
  .pv-pick,
  /* 2026-10-12 명렬 미리보기의 사유 select — 템플릿 전량을 훑는 정적 인벤토리(위 주석)가
     이 select 도 잡는다. 날짜 입력(type=date)은 그 인벤토리 밖이지만 같은 축이라 함께 덮는다. */
  .rp-reason,
  .rp-date,
  .ap-m input{font-size:16px}

  /* ★ `.lc-ta{min-height:44px}` 는 넣지 않는다 — 입력창의 높이 계약은 `.s-ta` 가 단독으로 지고
     이 블록의 `.s-ta{height:44px}` 가 coarse 44px 를 준다(둘로 나누면 서로를 되돌린다). */
  .lc-card .lc-x{width:44px; height:44px}
  .lc-card .lc-all{min-height:44px; min-width:44px; display:inline-flex; align-items:center}
  .lc-card .btn.sm{min-height:44px; min-width:44px; display:inline-flex;
    align-items:center; justify-content:center}
  /* ★ 0.1.69 — 「마감」은 글자가 두 자라 44×44 **정사각형**이 되어 옆의 칩·버튼과 어울리지
     않고 혼자 튄다(사용자 지적, 실기기). 세로 44 는 터치 타깃 계약이라 못 줄인다 —
     대신 **가로를 늘려** 알약 모양으로 만든다. 긴 버튼(마감 해제 등)은 이미 더 넓어 무영향. */
  .lc-card .s-head .btn.sm{min-width:76px}
  .lc-card .lc-row{min-height:44px}
  .lc-card .s-back,.lc-card .s-cell,.lc-card .at-retry{min-height:44px; min-width:44px}
  /* 차시 이동 단추도 터치 타깃이다(0.1.73) — 데스크톱은 32px 그대로다. */
  .lc-card .s-mv{min-height:44px; min-width:44px}
  /* 메모 입력창의 한 줄 높이는 coarse 에서 44px 이다(스펙 §9-13 · 정본 목업 data-coarse="1") */
  .s-ta{height:44px}
}
/* 확인창은 coarse 밖에서도 44px 이다(결정 9 셋째 항). `.lc-card` 밖이라 위 블록에 안 걸린다. */
.alert-pop .btn.sm{min-height:44px; min-width:44px; display:inline-flex; align-items:center;
  justify-content:center; padding:5px 16px}

/* ══ 출석 관리 탭(설계 §C · D1~D4 · 앱 전용) — 시안 B(2026-09-22 C1) ══════════════
   정본: 디자인 에이전트 시안 B(`출석관리-시안-보드.html` 「시안 B」 · 추출본 attn-B-520/1000).
   보드 설명: 「차시 목록 + 표 — 두 질문을 나란히. 왼쪽은 차시 목록(마감 작업), 오른쪽은
   월별 표(누가 빠졌나). 좁히면 위아래로 쌓인다.」
   ★ 마감 색은 **청록**(--a-mine · --seal-tint · --seal-line) — 보드의 초록은 이 앱에서
     「보강」이라 마감에 쓰면 오독된다(사용자 결정).
   ★ 앱 창 기본 폭 520px 에서 먼저 맞추고 1000px 에서 두 칸. 표만 가로로 스크롤한다.
   ★ 소비자: client-tauri/src/js/attn.js(renderAttn). 클래스 이름은 그 파일이 낸다. */
.atk-body{flex:1; min-height:0; overflow:auto; padding:0 14px 22px}
.atk-pad{padding:10px 2px 0}
.atk-sub{margin:2px 0 10px; font-size:13px; color:var(--ink-2)}
.atk-ph{padding:22px 4px; text-align:center; color:var(--ink-2); font-size:13px}

/* 월 이동 · 계열 칩 */
.atk-month{display:flex; align-items:center; gap:8px; padding:2px 0 8px}
.atk-month button{font-family:inherit; font-size:12px; font-weight:700; color:var(--ink-1);
  background:var(--surface); border:1px solid var(--hair-strong); border-radius:8px; padding:5px 10px; cursor:pointer}
.atk-month button:hover{background:rgba(16,18,20,.04)}
.atk-month button:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}
.atk-month #atkYm{min-width:62px; text-align:center; font-size:14px; font-weight:700; color:var(--ink-1)}
.atk-series{display:flex; flex-wrap:wrap; gap:6px; align-items:center; padding:2px 0 4px}
.atk-chip{font-family:inherit; font-size:12px; font-weight:700; color:var(--ink-2); background:var(--surface);
  border:1px solid var(--hair-strong); border-radius:999px; padding:6px 11px; cursor:pointer}
.atk-chip:hover{background:rgba(16,18,20,.04)}
.atk-chip:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}
.atk-chip.on{color:#fff; background:var(--a-swap); border-color:var(--a-swap)}
.atk-chipsep{width:1px; height:16px; background:var(--hair-strong); margin:0 2px}
.atk-chiplab{font-size:11.5px; font-weight:650; color:var(--ink-3); letter-spacing:.02em}

/* 두 칸 — 좁으면(앱 520) 위아래로 쌓이고, 넓으면(≥760) 나란히. 표만 가로 스크롤. */
.atk-panes{display:flex; flex-direction:column; gap:10px; margin-top:8px}
.atk-card{display:flex; flex-direction:column; background:var(--surface);
  border:1px solid var(--hair); border-radius:12px; overflow:hidden}
.atk-cardhd{display:flex; align-items:center; gap:8px; padding:10px 12px; border-bottom:1px solid var(--hair)}
.atk-cardhd h2{font-size:14px; font-weight:660; letter-spacing:-.01em; color:var(--ink-1)}
.atk-count{margin-left:auto; font-size:12px; color:var(--ink-2); font-variant-numeric:tabular-nums}
.atk-count b{color:var(--ink-1); font-weight:660}
@media (min-width: 760px){
  .atk-panes{flex-direction:row}
  .atk-pane-l{flex:0 0 288px}
  .atk-pane-r{flex:1; min-width:0}
}

/* 왼쪽 — 교시별 마감 현황(마감 안 한 차시만 선택 상자 · 줄을 누르면 체크 화면) */
.atk-list{display:flex; flex-direction:column}
.atk-srow{display:flex; align-items:center; gap:9px; min-height:36px; padding:0 10px 0 11px;
  border-bottom:1px solid var(--hair-2); font-size:13px}
.atk-srow:last-child{border-bottom:none}
.atk-srow.today{background:var(--today-tint)}
.atk-srow input[type="checkbox"]{flex:none; width:16px; height:16px; margin:0; accent-color:var(--a-swap); cursor:pointer}
.atk-srow .cbhole{flex:none; width:16px; height:16px}
.atk-open{display:flex; align-items:center; gap:9px; padding:0; font-family:inherit; font-size:13px;
  color:var(--ink-1); background:none; border:0; cursor:pointer}
.atk-open .dt{font-weight:620; letter-spacing:-.01em; font-variant-numeric:tabular-nums}
.atk-open .dt .wd{font-weight:500; color:var(--ink-3); font-size:11.5px}
.atk-open .pd{color:var(--ink-2); font-variant-numeric:tabular-nums; font-size:12.5px}
.atk-open:focus-visible, .atk-chev:focus-visible{outline:2px solid var(--a-swap); outline-offset:2px}
.atk-today{display:inline-flex; align-items:center; margin-left:6px; padding:0 6px; border-radius:999px;
  background:rgba(16,18,20,.07); color:var(--ink-2); font-size:10.5px; font-weight:650}
.atk-srow .gap{flex:1}
.atk-miss{font-size:12px; color:var(--ink-2); font-variant-numeric:tabular-nums}
.atk-tag{display:inline-flex; align-items:center; height:18px; padding:0 7px; border-radius:999px;
  font-size:11px; font-weight:680; letter-spacing:-.01em}
.atk-tag.done{background:var(--seal-tint); color:var(--a-mine)}
.atk-tag.canc{background:transparent; color:var(--ink-3)}
.atk-chev{display:flex; color:var(--ink-3); cursor:pointer}
.atk-srow.canc .atk-open .dt, .atk-srow.canc .atk-open .pd{color:var(--ink-3); text-decoration:line-through}

/* 일괄 막대 — 「고른 차시 N개」 + 「고른 차시 마감」(U1 확인창 한 줄은 그대로) */
.atk-bulkbar{display:flex; align-items:center; gap:8px; padding:8px 11px;
  border-top:1px solid var(--hair); background:rgba(16,18,20,.02)}
.atk-bulkbar .t{margin-right:auto; font-size:12.5px; color:var(--ink-2)}
.atk-bulkbar .t b{color:var(--ink-1); font-weight:660; font-variant-numeric:tabular-nums}

/* 오른쪽 — 월별 출석 현황 표(표만 가로 스크롤 · 이름 열 고정 · 머리 행 고정)
   ★ 되먹임4 W3 머리 행 고정 — `overflow-x:auto` 는 세로도 스크롤 그릇으로 만든다. 그래서 그 안의
     `position:sticky; top:0` 은 바깥 세로 스크롤(`.atk-body`)에 붙지 않는다. 표 그릇이 **스스로**
     세로 스크롤하도록 높이 상한을 준다 — 상한 = 창 높이에서 앱 머리·카드 머리를 뺀 값이라,
     바깥을 내려 표 카드가 위에 닿으면 표 그릇 전체가 한 화면에 든다(넓은 폭·좁은 폭 같은 규칙).
     낮은 창에서도 몇 줄은 보이게 하한 260px. 스크롤 유지는 `ATK_SCROLLERS`(attn.js)가 이 그릇을 잰다. */
.atk-grid-scroll{overflow-x:auto; overflow-y:auto; flex:1; min-height:0; max-height:max(260px, calc(100vh - 150px))}
.atk-grid{border-collapse:separate; border-spacing:0; width:100%; font-size:12.5px; font-variant-numeric:tabular-nums}
.atk-grid th, .atk-grid td{padding:0; text-align:center; white-space:nowrap}
.atk-grid .stick{position:sticky; left:0; z-index:2; background:var(--surface); text-align:left; border-right:1px solid var(--hair)}
.atk-grid thead th{position:sticky; top:0; z-index:3; background:var(--surface); border-bottom:1px solid var(--hair)}
.atk-grid thead th.stick{z-index:4}
.atk-grid th.stu, .atk-grid td.stu{width:92px; min-width:92px; padding:0 8px}
/* ★ 2026-09-23 사용자 결정 — 칸(92px)이 내용보다 넓어 글자가 왼쪽 벽에 붙어 보였다.
   `text-align:center` 로 통째 가운데 정렬하면 이름 길이(2~4자)가 제각각이라 **앞 번호가
   세로로 안 맞아** 22줄을 훑기 어려워진다. 그래서 「번호+이름」을 인라인 덩어리로 묶고
   그 덩어리만 가운데에 놓는다 — 번호끼리는 계속 맞는다(`.no` 는 고정 폭). */
.atk-grid td.stu{text-align:center; font-size:12.5px}
/* ★ 2026-10-12 명렬수강기간(코디 확정 8) — 신원 칸: 실제 학번 전체(다섯 자리) · 타교는 `타교`
   표지 + 원문 라벨. **고정 열은 넓히지 않는다**(92px 유지 — 출석 칸이 가려지면 안 된다).
   번호는 줄이지 않고, 이름만 말줄임(전체값은 title)이라 긴 이름이 번호·출석 칸을 밀지 않는다. */
.atk-grid td.stu .who{display:inline-flex; align-items:baseline; gap:3px; max-width:100%;
  text-align:left; white-space:nowrap}
.atk-grid td.stu .no{flex:none; display:inline-block; min-width:18px; color:var(--ink-3);
  font-size:11px; font-variant-numeric:tabular-nums}
.atk-grid td.stu .no.out{color:var(--ink-2); font-weight:650}
.atk-grid td.stu .nm{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.atk-grid th.sess{width:58px; min-width:58px; padding:5px 3px}
.atk-grid th .inner{display:flex; flex-direction:column; align-items:center; gap:1px; padding:5px 2px;
  border:1px solid transparent; border-radius:4px}
.atk-grid th.done .inner{background:var(--seal-tint); border-color:var(--seal-line)}
.atk-grid th.today .inner{background:var(--today-tint); border-color:var(--hair-strong)}
.atk-grid .sd{font-size:12px; font-weight:670; font-variant-numeric:tabular-nums; line-height:1.1}
.atk-grid .sw{font-weight:500; color:var(--ink-3); font-size:10.5px}
.atk-grid .sp{font-size:10.5px; color:var(--ink-2); font-variant-numeric:tabular-nums; line-height:1.2}
.atk-grid .mini{display:inline-flex; align-items:center; height:15px; margin-top:2px; padding:0 5px;
  border-radius:999px; background:var(--seal-tint); color:var(--a-mine); font-size:10px; font-weight:700}
.atk-grid .minihole{height:15px; margin-top:2px}
.atk-grid thead th.stu{text-align:left; font-size:11.5px; font-weight:650; color:var(--ink-2);
  vertical-align:bottom; padding-bottom:9px}
.atk-grid tbody td{height:27px; border-bottom:1px solid var(--hair-2)}
.atk-grid tbody tr:last-child td{border-bottom:none}
.atk-grid td.col-today{background:var(--today-tint)}
/* 명단 밖(전입 전·전출 뒤) 칸 — 종이(`table.pv td.out`)와 같은 판정·같은 회색. 오늘 열보다 뒤에 둔다
   (명단 밖이면 오늘이라도 회색이다). 이 칸에는 「/」가 없다(attn.js monthlyStats). */
.atk-grid td.out{background:rgba(16,18,20,.10)}
/* 포커스 셀(되먹임4 W3) — 올린 칸의 행·열에 옅은 **회색** 십자 + 이름 칸·날짜 머리 칸 강조.
   오늘 열(파랑 `--today-tint`)·마감(청록)과 헷갈리지 않게 무채색만 쓴다. 바탕을 갈지 않고
   inset 그림자로 **겹쳐** 칠해 아래 틴트(오늘·명단 밖·마감 머리)가 그대로 비친다. 테두리는 1px 하나. */
/* ★ 2026-09-30 Q17 B(사용자 결정 「포커스 십자를 더 옅게 — 행·열 음영은 아주 약하게, 제목 칸 강조만 또렷하게」
     → 명단 밖 회색 `.10` 과 덜 헷갈린다) — 행·열 음영 .04 → .018(명단 밖의 1/5 아래). 올린 칸은 음영이 아니라
     **테두리**(--ink-2 1px)로 알아본다. 이름 칸·날짜 머리는 바탕을 짙게 하지 않고 테두리(--ink-2)·굵기·글자색으로
     또렷하게 한다(바탕을 짙게 하면 그것이 곧 명단 밖 회색과 헷갈린다). 새 장식·색 띠 없음 — 기존 1px 테두리 문법. */
.atk-grid tr.fx-r td, .atk-grid td.fx-c{box-shadow:inset 0 0 0 999px rgba(16,18,20,.018)}
.atk-grid tr.fx-r td.fx-x{box-shadow:inset 0 0 0 1px var(--ink-2), inset 0 0 0 999px rgba(16,18,20,.018)}
.atk-grid tr.fx-r td.stu.fx{box-shadow:inset 0 0 0 1px var(--ink-2), inset 0 0 0 999px rgba(16,18,20,.018); color:var(--ink-1); font-weight:760}
.atk-grid tr.fx-r td.stu.fx .no{color:var(--ink-1); font-weight:700}
.atk-grid thead th.sess.fx{box-shadow:inset 0 0 0 999px rgba(16,18,20,.018)}
.atk-grid thead th.sess.fx .inner{border-color:var(--ink-2); box-shadow:inset 0 0 0 1px var(--ink-2)}
.atk-grid thead th.sess.fx .sd, .atk-grid thead th.sess.fx .sp{color:var(--ink-1); font-weight:760}
.atk-grid .slash{font-size:14px; font-weight:600; color:var(--ink-1); line-height:1}
.atk-grid th.cnt, .atk-grid td.cnt{width:42px; min-width:42px; border-left:1px solid var(--hair);
  color:var(--ink-2); font-size:11.5px; font-variant-numeric:tabular-nums}
.atk-grid thead th.cnt{font-size:11px; font-weight:650; color:var(--ink-3); vertical-align:bottom; padding-bottom:9px}

.atk-err{margin:6px 0; padding:9px 11px; font-size:12px; font-weight:600; color:var(--c-canc);
  background:var(--t-canc); border:1px solid rgba(196,43,28,.24); border-radius:8px}
.atk-tools{display:flex; flex-wrap:wrap; gap:6px; margin-top:14px; padding-top:12px; border-top:1px solid var(--hair-2)}
.atk-tools .btn{flex:none; display:inline-flex; align-items:center; gap:6px}

/* ============================================================
   시험 감독 카드 — 예령 띠 + 적응 조판 (2026-09-05, T4b)
   정본: mockups/exam-card-결정요약.md §3 CSS 블록. 스펙 §8-3 확정 문단 · §8-9(색·모서리) ·
   §8-9′(레인 거터) · §18 J9. 사용자 확정(2026-09-05 13:40): 색 = 1 청록 · 모서리 = 직각 0px.
   ------------------------------------------------------------
   시험 감독 색 토큰(신설 3) — 여덟 후보 값은 결정요약 §1-① 표. --exam-r·--exam-edge 는
   모서리 결정의 한 축(둥근/직각)을 함께 돌리는 짝이다(§1-⑤ 3번 — 반경과 여백은 반드시 같이 움직인다).
   ============================================================ */
:root{
  --c-exam:#0a6b70;
  --t-exam:rgba(10,107,112,.10);
  --exam-pre:rgba(10,107,112,.22);
  --exam-r:0px;      /* ⑤ 확정: 직각. 감독 카드 외 다른 카드는 .band 의 14px 을 그대로 쓴다 */
  --exam-edge:0px;   /* .abut 구분선 좌우 여백 — 반경과 짝(0이면 여백도 0) */
  /* 아래 둘은 timeline.js/school.js 가 인라인 style 로 실값을 얹는 자리다(순수 시각 환산·
     열 개수) — 여기 기본값은 §7-4 ③(「토큰을 정의해 통과시킨다」)을 지키기 위함이다. */
  --pre:0px;
  --exb-cols:1;
}

/* ---- 감독 카드 ---- */
.band.st-exam{
  background-image:linear-gradient(var(--t-exam),var(--t-exam));
  padding-top:var(--pre,0px);          /* 예령 띠 높이만큼 본문 중심을 내린다 */
  border-radius:var(--exam-r,0px);
}
/* 예령 띠 — 전용 자식 요소다(스펙 §8-9). ::before/::after/background-image/box-shadow 는
   .band 에서 이미 임자가 있다: 호버 오버레이·flash·틴트 3종·취소 테두리·hb. */
.exam-pre{
  position:absolute; left:0; right:0; top:0; height:var(--pre,0px);
  border-radius:var(--exam-r,0px) var(--exam-r,0px) 0 0;   /* 본체와 반드시 같은 값 — 삐져나옴 방지 */
  background:var(--exam-pre);
  display:flex; align-items:center; justify-content:center; overflow:hidden; pointer-events:none;
}
.exam-pre span{font-size:9.5px; font-weight:700; letter-spacing:.02em; color:var(--c-exam); line-height:1}
.band.st-exam .pnum{background:var(--t-exam); color:var(--c-exam)}
/* ★ 이 규칙이 없으면 위 줄(같은 특이도 0,2,0 · 소스 뒤)이 `.band.current .pnum` 을 이겨
   현재 교시 파랑 신호가 조용히 사라진다. theme.css `.band.hb .pnum` 이 같은 함정을 남긴 자리다. */
.band.st-exam.current .pnum{background:var(--a-swap); color:#fff}
.band.st-exam .b-cls{color:var(--c-exam); font-weight:700}
.band.st-exam .b-tag{color:var(--c-exam)}
/* flex:none 없으면 390px 좁은 카드에서 「1감 / 독」으로 쪼개진다(실렌더 확인) */
.chip.ex-role{background:var(--t-exam); color:var(--c-exam); font-weight:700; flex:none; white-space:nowrap}
/* §1-⑤ 3번 — 직각에서는 근거(반경과 같은 값)가 사라져 여백도 같은 축(--exam-edge)에 태운다.
   6/25·7/1 실데이터에는 감독 카드가 .abut 에 걸리는 자리가 없다(교대시간 5분 — 결정요약 §4⑤). */
.band.st-exam.abut .b-edge{left:var(--exam-edge,0px); right:var(--exam-edge,0px)}

/* 4행 = 자리 줄. ★ H2(2026-09-06) 뒤 이 줄은 **`place != null` 일 때만 존재한다** —
   08:00 전·당일표 미게시·내 자리 없음 셋은 `timeline.js` 가 요소를 아예 안 낸다. */
.b-place{margin-top:2px; font-size:13px; line-height:1.35; color:var(--ink-1);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
/* ★★ 아래 흐림 규칙 둘(`.b-place.dim` · `.b-line2 .pd`)은 **쓰는 데가 0인 규칙**이다 —
   H2(2026-09-06)로 흐림을 쓰던 갈래 셋이 통째로 사라졌다(결정요약 §6-1). 살아 있는 갈래로
   오독하지 마라: `examPlaceLine` 은 `dim` 을 반환하지 않고 렌더는 `dim`·`pd` 를 안 붙인다.
   남겨 둔 이유는 A26(2행 접기에서 자리가 절대 안 잘린다)이 `.pd` 의 `flex:none` 을 잠그고
   있어서다 — 지우려면 그 단언을 함께 옮겨야 한다(판정 H1F-1 Q3: 남기고 주석).
   ★ 값 자체는 2026-09-05 확정(흐림 = --ink-2. 스펙 초안의 --ink-3 은 틴트 위 2.61:1 AA 미달). */
.b-place.dim{color:var(--ink-2)}
.b-place .ex-pr{color:var(--c-exam); font-weight:700}
/* 2행 접기에서 3행+4행을 한 줄로 이을 때 */
.b-line2 .pd{color:var(--ink-2)}          /* ← 쓰는 데 0(위 주석) */
.b-line2 .pn{color:var(--ink-1); font-weight:600}
/* 줄1 의 `{p}교시 ` 조각(H1 · 2026-09-06) — 마크업은 늘 나오고 **기본은 숨긴다**.
   좁은 카드(≤220px)에서만 되살린다(아래 F1 블록) — 거기서는 교시 원형 배지를 감추므로
   되살리지 않으면 교시 표시가 화면에서 통째로 사라진다(결정요약 §6-3 안 「나」).
   ★ 이 규칙을 `display:inline` 으로 바꾸거나 블록 밖에 짝을 두면 930px 에서 교시 글자가
     되살아나 H1 되먹임이 통째로 뒤집힌다(theme-css 음성 짝이 잠근다). */
.cls-p{display:none}

/* 퇴실불가 배지 — 3행 끝. 신호색 재사용 금지라 고사색 채움이다.
   ★ 축소(.tight) 대상에서 빼라 — 9.5px 로 줄이면 30분 카드에서 안 읽힌다(실렌더 확인).
     「교대시간 5분 안에 학생을 내보내지 말라」는 운영 경고라 작아지면 안 된다. */
.ex-noexit{display:inline-flex; align-items:center; margin-left:6px; font-size:10.5px; font-weight:700;
  color:#fff; background:var(--c-exam); border-radius:4px; padding:1px 6px; letter-spacing:.01em}

/* 머리 고사 알약 — 대체수업일 pill(.lesson-dow.swap)과 같은 자리 규칙·같은 모양, 색만 고사색 */
.exam-pill{font-size:12px; font-weight:700; color:var(--c-exam); background:var(--t-exam);
  border-radius:999px; padding:2px 9px; letter-spacing:-.01em}

/* ---- 짧은 카드 축소(적응 조판 ㉲의 둘째 규칙) ---- */
.band.st-exam.tight .b-inner{padding:4px 12px; gap:7px}
.band.st-exam.tight .pnum{width:24px; height:24px; font-size:12.5px}
.band.st-exam.tight .b-sj{font-size:14px}
.band.st-exam.tight .b-cls{font-size:11.5px; margin-right:5px}
.band.st-exam.tight .b-line2{font-size:11.5px; margin-top:1px}
.band.st-exam.tight .b-place{font-size:11.5px; margin-top:1px}
.band.st-exam.tight .chip.ex-role{font-size:10.5px; padding:1px 6px}

/* ---- 「우리 반」 고사 카드(2026-09-30 사용자 · 시안 A 슬레이트) ----
   감독 카드와 **같은 마크업·같은 조판**이고 색 토큰 셋만 바꿔 끼운다(timeline.js examBandHtml opts.ours).
   이 파일의 고사 카드 규칙이 전부 var(--c-exam)·var(--t-exam)·var(--exam-pre) 를 읽으므로 이 한 줄이
   예령 띠·교시 원·퇴실불가 배지·좁은 카드 규칙까지 한꺼번에 다시 칠한다 — 규칙을 복제하면 한쪽만
   고치는 사고가 난다. 「지금 교시」 파랑(--a-swap)은 토큰이 달라 그대로 파랑이다(왼쪽 열과 같은 신호). */
.band.st-exam.ex-ours{--c-exam:var(--c-ours); --t-exam:rgba(66,90,122,.10); --exam-pre:rgba(66,90,122,.22)}
/* 학년 글자가 없다(열 머리 「우리 반 1-2」가 학급을 말한다) — 빈 .b-cls 가 4ch+7px 자리를 먹어
   과목이 들여 써지지 않게 한다. ★ 위 `.tight .b-cls{margin-right:5px}`(같은 특이도)보다 **뒤**여야
   이긴다. 좁은 카드에서는 .cls-p(「1교시 」)가 되살아나므로 그때만 간격을 돌려준다(아래 @container). */
.band.st-exam.ex-ours .b-cls{min-width:0; margin-right:0}

/* ---- F2(T11 발견 · 판정 J-T4e-2) — 2행 접기에서 «자리·짝»은 절대 잘리지 않는다 ----
   한 줄 텍스트(`시각 · 자리`)였을 때는 넘치면 **뒤부터** 사라져 390px 1열에서
   「3-8 교실 · 2감독 박관우 선생님」의 뒷사람 이름이 통째로 증발했다(스크린샷-T11/S09 실측).
   시각·구분점·자리를 각각 span 으로 갈라 flex 로 놓는다 — 줄어드는 것은 **시각뿐**이고
   자리·짝은 flex:none 이라 자기 폭을 지킨다. 문면은 한 글자도 안 바뀐다(조판만 바뀐다).
   ★ `.b-sep{white-space:pre}` 는 장식이 아니다 — flex 항목이 되면 앞뒤 공백이 지워져
     「(30분)·3-8」로 붙는다. ` · ` 를 있는 그대로 지키는 유일한 길이다. */
.band.st-exam.tight .b-line2{display:flex; align-items:baseline}
/* ★ `flex:0 1 auto` 다(`1 1 auto` 가 아니다 — 실렌더 확인). 늘어나게 두면 930px 에서 시각이
   남는 폭을 다 먹어 자리·짝이 **오른쪽 끝으로 밀려난다**(넓은 화면 렌더가 바뀐다).
   줄어들기만 하면 좁을 때는 말줄임되고 넓을 때는 배포 전과 같은 자리에 그대로 붙는다. */
.band.st-exam.tight .b-line2 .b-t{flex:0 1 auto; min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.band.st-exam.tight .b-line2 .b-sep{flex:none; white-space:pre}
.band.st-exam.tight .b-line2 .pn,
.band.st-exam.tight .b-line2 .pd{flex:none; white-space:nowrap}

/* ---- F1(T11 발견 · 판정 T4e-1) — 좁은 카드(폰 담임 2열 한 칸)에서의 고사 카드 조판 ----
   증상: 390px 담임 2열에서 1행이 「1교시」만 남고 **학년과 과목이 말줄임 없이 잘렸다**
   (스크린샷-T11/S08). `.b-cls` 가 인라인 블록이라 `.b-subj` 의 말줄임이 그 자리에 안 찍힌다.
   실측(Chrome emulate 390x844x2, 담임 2열 · 1교시 50분 카드):
     카드 135.2×84px · 본문 세로 예산 **58px**(84 − 예령 띠 14 − .b-inner 상하 12) ·
     1행 가용 가로 **80.2px**(115.2 − pnum 26 − gap 9) 인데
     `.b-cls`(「1교시 · 1학년」 69.7~76) + gap 6 + 역할 칩(41.4~66) = **117~142px** 이 필요하다.
   → 폭이 모자란다. **교시 원형 배지(26 + gap 9 = 35px)를 감추면** 115.2px 이 되어
     [1교시 · 1학년][역할 칩]이 한 줄에 서고 과목이 둘째 줄로 내려간다.
     배지가 지던 「N교시」는 **문면이 이미 진다**(중복이라 잃는 뜻이 없다).
   ★ 배지를 감추면 `.band.st-exam.current .pnum` 의 파랑 원(= 지금 이 교시)이 함께 사라진다.
     그래서 같은 신호를 `.b-cls` 글자색으로 **승계**한다 — 보상 없이 감추면 신호만 조용히 죽는다.
   ★ 네 줄(교시·학년 / 과목 / 시각 / 자리)을 58px 에 넣으려면 11~13px 이어야 한다.
     그래도 **시각 줄 하나는 말줄임이 남는다**(판정 T4e-1 수용) — 예령은 띠에 크게 있고
     시작·종료 시각은 타임라인 눈금이 진다. 자리(교실·짝)·과목·학년은 전문으로 보인다.
   ★ 경계 220px 은 이 파일이 이미 쓰는 「담임 2열 한 칸(폰) = 126~181px」 경계다
     (위 「카드 폭 축소」 ⓓ). 930px 담임 2열은 카드 260~370px 이라 **이 블록에 안 걸린다** —
     넓은 화면 렌더는 한 픽셀도 안 바뀐다. */
@container band (max-width: 220px){
  /* 변동 태그 알약(2026-09-22) — 폰 폭 담임 2열(카드 ≈ 130px)에서 좌우 여백 7px 이 본문을
     44.5 → 31.4px 로 뺏었다(하네스 390px 실측). 여백·글꼴을 줄여 39.4px 로 되돌린다. */
  .band .b-tag.b-chg{padding:1px 4px; font-size:11px; letter-spacing:-.02em}
  .band.st-exam .pnum,
  .band.hb.l3 .pnum{display:none}
  .band.st-exam .b-subj{white-space:normal; overflow:visible; text-overflow:clip}
  .band.st-exam .b-cls{font-size:11.5px}
  .band.st-exam .b-sj{font-size:13px}
  .band.st-exam.current .b-cls{color:var(--a-swap)}
  .band.st-exam .chip.ex-role{font-size:10px; padding:0 5px}
  .band.st-exam .b-line2,
  .band.st-exam .b-place{font-size:11px}
  .band.hb.l3 .b-subj,
  .band.hb.l3 .b-line2{white-space:normal; overflow:visible; text-overflow:clip}

  /* ---- H1·H4(2026-09-06 · 목업 3라운드 「나」+「N3」 · 결정요약 §6-3·§6-4) ----
     ★ 되먹임 1 이 줄1 에서 교시 글자를 빼면 **좁은 카드에는 교시 표시가 아무 데도 없다**
       (위에서 배지를 감췄다). 조각을 여기서만 되살린다 — 실측 본문 77.0 / 가용 70.0px 로
       배포 전(88.0px)보다 11px 낫다(안 「가」 배지 복원은 94.0px 로 24px 넘쳤다).
     ★★ 되먹임 4 가 자리 줄에 「교실」·「선생님」 다섯 글자를 더해 106 → **144px** 가 됐는데
       이 폭이 자리 줄에 내주는 가로는 **106px** 이다 — 배포 전엔 106/106 으로 딱 전문이었다.
       새 문면이 처음으로 뒷사람 이름을 잘라 먹는다(S23b 실측). N3 로 푼다:
         ⑴ 자리 줄 **두 줄 허용** — `word-break:keep-all` 이 짝이다. 없으면 한국어가 낱말
            한가운데서 감긴다(실렌더 「1감독 임지 / 후 선생님」 — M3).
         ⑵ 시각 줄을 **여기서만** 감춘다. 예령은 띠가, 시작·종료는 왼쪽 눈금이 이미 말한다
            (판정 T4e-1 이 「좁은 카드에서 시각 줄 하나는 말줄임이 남는다」를 수용한 근거와 같다).
       세로는 N1(한 줄 그대로)과 **똑같다**.
     ★ `.tight` 는 `.b-t`·`.b-sep` 만 감춘다 — `.b-line2` 를 통째로 감추면 **자리까지 사라진다**
       (2행 접기에서는 시각과 자리가 그 한 줄에 함께 산다). `.pn` 을 감추는 것도 같은 사고다. */
  .band.st-exam .cls-p{display:inline}
  /* 우리 반 고사 카드 — 되살아난 「1교시」와 과목 사이 간격(학년 글자가 없어 .b-cls 가 이 조각뿐이다) */
  .band.st-exam.ex-ours .b-cls{margin-right:5px}
  .band.st-exam .b-place{white-space:normal; overflow:visible; text-overflow:clip; word-break:keep-all}
  .band.st-exam.tight .b-line2 .pn{white-space:normal; word-break:keep-all}
  .band.st-exam:not(.tight) .b-line2{display:none}
  .band.st-exam.tight .b-line2 .b-t,
  .band.st-exam.tight .b-line2 .b-sep{display:none}
}

/* ---- 오늘의 전체 시간표 · 감독표 모드 격자(§8-7 · J9 — 이름은 이 파일이 정한다. T5 는
   이 이름으로 마크업만 낸다) ---- */
/* ★ 열 폭에 상한을 둔다 — 6/25 1학년은 고사가 1교시뿐이라 minmax(0,1fr) 이면 한 열이
   화면 전폭(약 820px)을 먹고 이름 두 개가 가운데 떠 버린다(실렌더 확인). */
.exb{display:grid; grid-template-columns:46px repeat(var(--exb-cols,1),minmax(120px,240px));
  justify-content:start; font-size:11px; padding:0 10px 2px}
.exb-h{position:sticky; top:0; z-index:4; background:var(--bg-frame); padding:5px 6px 4px;
  text-align:center; font-size:11px; font-weight:700; color:var(--ink-2)}
.exb-h.cur{color:var(--a-swap)}
.exb-h .sj{color:var(--c-exam)}
.exb-cl{display:flex; align-items:center; padding:0 6px; font-size:11px; font-weight:600;
  color:var(--ink-2); border-top:1px solid var(--hair)}
.exb-cl.xk{font-weight:700; color:var(--c-exam); white-space:nowrap}
.exb-c{position:relative; min-height:36px; min-width:0; padding:3px 4px; display:flex; flex-direction:column;
  align-items:center; justify-content:center; text-align:center; gap:1px; border-top:1px solid var(--hair)}
.exb-c .rl{font-size:9.5px; font-weight:700; color:var(--c-exam)}
.exb-c .nm{font-size:11.5px; font-weight:650; color:var(--ink-1); letter-spacing:-.01em}
.exb-c .ln{display:flex; align-items:baseline; gap:4px}
.exb-c.pre{color:var(--ink-3); font-size:11px; font-weight:600}
/* 내 수업(내 감독) 표식 — 시안 A1(2026-10-01): 배경(--t-exam · A18 잠금) + 내 이름 글자(`.me-nm`).
   옛 시안 C 의 왼쪽 테두리·「내」 배지와 둥근 모서리(5px)를 걷었다 — 둥근 칸에 색 줄을 붙인 모양이
   지적 대상이었고, 격자 칸이라 각진 tint 가 표 문법이다(「지금」 칸은 아래 .exb-c.cur 의 흰 카드가 이긴다). */
.exb-c.me{background:var(--t-exam); border-top-color:transparent}
.exb-c.cur{background:var(--surface); border-radius:6px; border-top-color:transparent;
  box-shadow:0 1px 4px rgba(16,18,20,.16), inset 0 0 0 1.5px var(--a-swap)}
.exb-c.xn{min-height:26px; font-size:11px; font-weight:600; color:var(--ink-1)}
/* 08:00 전엔 소비처 0(floors/others 빈 배열) · 08:00 뒤 격자 행에서만 */
.exb-c.xn .pt{color:var(--ink-3); font-weight:600}
/* 지난 교시 흐림(I2 · 스펙 §8-7 「같은 규칙」 = **규칙이 같다**는 뜻이고 기전은 색 축이다 ·
   판정 F2-1). 감독표에서는 `opacity` 를 **쓰지 않는다** — 이유가 둘이고 둘 다 실화면에서 났다:
   ★ `.exb-h` 는 `position:sticky` 인 열 머리다. 요소에 `opacity` 를 걸면 **배경까지** 반투명해져
     붙어 있는 머리 뒤로 스크롤하는 행 글자가 그대로 비친다(리뷰 R2 I-R2-1 · 930×620 실브라우저).
   ★ 부모 `opacity` 는 자식의 `opacity:1` 로 되돌릴 수 없다 — 검색 강조(`.hit`)의 파랑 링·글자까지
     45% 로 바랬다(M-R2-1). 색 축은 자식이 자기 색으로 그냥 이긴다.
   그래서 셀·머리 **둘 다 색**으로 흐리고, 자기 색을 스스로 선언한 자식(`.rl`·`.nm`·`.pt`·`.sj`)을
   **전수** 로 덮는다. 셀의 날 텍스트(「08:00 공개」·배정없음 `—`·아래줄 이름 join)는 span 이 없어
   자식 셀렉터로 못 닿으므로, 셀 자신의 `color` 가 그것들을 진다(`school.js` 무수정). */
.exb-c.past,
.exb-h.past{color:var(--ink-3)}
.exb-c.past .rl,
.exb-c.past .nm,
.exb-c.past .me-nm,
.exb-c.past .pt,
.exb-h.past .sj{color:var(--ink-3)}

/* 검색 하이라이트 — 변동색·현재 셀보다 뒤(결합 시 링·글자 파랑이 이긴다, 스펙 §3-2).
   ★ `.past` **뒤**여야 한다(M-R2-1) — `.exb-c.past .nm` 과 특이도가 같은 0,3,0 이라
     소스 순서가 이긴다. 앞으로 옮기면 지난 열의 강조 이름이 회색으로 돌아간다. */
.exb-c.hit{box-shadow:inset 0 0 0 1.5px var(--a-swap); border-radius:5px}
.exb-c.cur.hit{box-shadow:0 1px 4px rgba(16,18,20,.16), inset 0 0 0 1.5px var(--a-swap)}
.exb-c.hit .nm,
.exb-c.hit .me-nm{color:var(--a-swap)}
/* 고사 구획 제목의 좌우 여백(M2) — 제목이 `.sc-grid` **밖**으로 나가면서 격자의 `0 10px` 을
   잃어 왼쪽 2px 에 홀로 섰다(수업 학년 제목은 10+2=12px). 같은 x 로 되돌린다.
   ★ 자식 결합자여야 한다 — 수업 격자 제목은 `.sc-grid` 안이라 이 규칙에 안 걸린다.
   ★ 12px 은 지어낸 값이 아니라 `.sc-grid{padding:0 10px 4px}` + `.sc-gh{padding:8px 2px 3px}`
     의 합이다(그 둘이 바뀌면 정적 시험이 빨개진다). */
.sc-scroll > .sc-gh{padding-left:12px; padding-right:12px}
