
/* 이 앱은 라이트 전용이다 — 선언하지 않으면 브라우저(특히 안드로이드 크롬 '강제 다크')가
   제멋대로 색을 뒤집는다. head 의 meta 와 한 쌍이다(둘 다 있어야 확실히 걸린다). */
html{ color-scheme:only light; }
:root{
  --primary:#3B82F6; --primary-dark:#2563EB; --primary-light:#EAF1FE;
  --dark:#1E2233; --navy:#312E81;
  --gray-50:#F8FAFC; --gray-100:#F1F3F9; --gray-200:#E6E9F2; --gray-300:#CBD2E0;
  /* gray-400 은 .muted(문서 전체 557곳)·th·캡션 등 '본문 보조 텍스트'의 기본색이다.
     예전 #97A0B5 는 흰 배경 2.62:1, 페이지 배경(#F4F5FA) 2.41:1 로 AA(4.5:1)에 한참 못 미쳐
     학생 목록의 학교/학년처럼 실제로 입력된 값이 빈 칸처럼 보였다.
     #646C82 → 흰 5.24 / gray-50 5.01 / 페이지 4.81 / gray-100 4.72 (네 배경 모두 통과).
     이 두 토큰은 배경·테두리로 쓰인 곳이 없어(전수 확인) 글자만 진해진다.
     400 만 내리면 500(4.91)보다 진해져 램프가 뒤집히므로 500 도 같이 내렸다. */
  --gray-400:#646C82; --gray-500:#565E75; --gray-600:#4A5168; --gray-700:#333A4D;
  --green:#047857; --green-light:#DCFCE7; --orange:#B45309; --orange-light:#FEF3C7;
  --red:#C81E4A; --red-light:#FFE4E6; --sky:#0369A1; --sky-light:#E0F2FE;
  --purple:#7C3AED; --purple-light:#EDE9FE; --teal:#0F766E; --teal-light:#CCFBF1;
  --border:#ECEEF5;
  --shadow:0 1px 2px rgba(30,34,51,.04),0 4px 12px rgba(30,34,51,.05);
  --shadow-lg:0 18px 48px rgba(30,34,51,.16);
  --radius:16px; --radius-sm:11px; --radius-lg:22px;
  /* ===== 간격·라운드 토큰(4pt 그리드) =====
     padding 이 9·11·13·14·18px 처럼 그리드를 벗어난 값이 많아 화면 전체가 미묘하게
     어긋나 보였다. 새로 쓰는 곳은 이 값만 쓴다. 라운드는 컨트롤·카드·필 3단계. */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:20px; --s6:24px; --s7:32px;
  /* ===== 의미색의 '글자용' 값 =====
     --red/--green/--orange 는 배경·테두리·차트에도 쓰여 값을 못 올린다. 글자로 쓸 때만
     이 변형을 쓴다 — 각자의 연한 배경(--red-light 등) 위에서도 4.5:1 을 넘는 값이다. */
  /* 본 토큰이 이미 4.5:1 을 넘으므로 별칭은 참조만 한다(값이 두 군데로 갈라지지 않게) */
  --red-text:var(--red); --green-text:var(--green); --orange-text:var(--orange);
  --r-ctl:10px; --r-card:16px; --r-pill:999px;
  /* ===== 타입 스케일 =====
     선언의 60%가 13px 이하라 섹션 제목과 본문이 1px 차이였다. 단계 간 3px 이상 벌린다.
     모바일에서는 아래 미디어쿼리가 본문을 15px 로 올린다. */
  --t-display:26px; --t-title:19px; --t-section:16px;
  --t-body:14px; --t-sub:12.5px; --t-caption:12px;
}
*{margin:0;padding:0;box-sizing:border-box}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{
  font-family:"Pretendard Variable",Pretendard,-apple-system,BlinkMacSystemFont,"Apple SD Gothic Neo","Malgun Gothic",sans-serif;
  background:#F4F5FA; color:var(--dark); font-size:14px; line-height:1.5;
  -webkit-font-smoothing:antialiased; touch-action:manipulation;
  word-break:keep-all; overflow-wrap:break-word;  /* 한국어 단어 중간 줄바꿈 방지(백분위·선택 등) */
}
button{font-family:inherit;cursor:pointer;border:none;background:none}
select,input,textarea{font-family:inherit}
.app{display:flex;min-height:100vh}

/* ===== 사이드바 ===== */
.sidebar{
  width:236px;background:#fff;border-right:1px solid var(--border);
  display:flex;flex-direction:column;position:fixed;top:0;left:0;bottom:0;z-index:50;
}
.sidebar-head{padding:18px 16px;border-bottom:1px solid var(--gray-100)}
.logo{font-size:13px;font-weight:800;color:var(--primary-dark);letter-spacing:-.3px;margin-bottom:12px;display:flex;align-items:center;gap:7px}
.logo .dot{width:24px;height:24px;border-radius:9px;background:#2563EB linear-gradient(135deg,#1D4ED8,#2563EB);color:#fff;display:flex;align-items:center;justify-content:center;font-size:13px}
/* ===== 브랜드 심볼(앱티마이저) + 워드마크 ===== */
.brand-mark{width:30px;height:30px;display:block;flex:none}
.app.admin .brand-mark{--bm-d:#C7D2FE;--bm-v:#A78BFA}
/* 좌상단 'Apticare' 워드마크 — 파란 글씨 대신 브랜드 색(바이올렛→딥블루) 그라디언트, 더 크게 */
.logo{gap:9px;min-width:0}
/* 학원 로고 이미지 — 브랜드 심볼과 같은 자리·같은 크기 */
.aca-logo-img{width:30px;height:30px;flex:none;object-fit:contain;border-radius:7px;display:block}
/* 워드마크에 학원 이름이 들어가므로 긴 이름은 줄여서 한 줄로 */
.logo span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.logo span{font-size:19px;font-weight:800;letter-spacing:-.6px;line-height:1;
  background:linear-gradient(120deg,#6439FF 0%,#050C9C 100%);
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:#6439FF}
.app.admin .logo span{background:linear-gradient(120deg,#C4B5FD 0%,#A78BFA 100%);
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
/* ===== 홈 환영 헤더 ===== */
.home-hero{position:relative;overflow:hidden;border-radius:var(--radius-lg);padding:22px 26px;margin-bottom:18px;color:#fff;
  background:linear-gradient(120deg,#6439FF 0%,#4F46E5 48%,#3B82F6 100%);box-shadow:0 16px 38px -18px rgba(79,70,229,.6)}
.home-hero::after{content:"";position:absolute;right:-40px;top:-40px;width:200px;height:200px;border-radius:50%;background:rgba(255,255,255,.10)}
.home-hero h2{font-size:21px;font-weight:800;letter-spacing:-.6px;position:relative;z-index:1}
.home-hero .sub{font-size:12.5px;opacity:.92;margin-top:6px;position:relative;z-index:1;line-height:1.6}
.home-hero .when{position:absolute;top:22px;right:26px;font-size:12px;opacity:.9;font-weight:700;z-index:1}
.home-hero .hero-chips{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px;position:relative;z-index:1}
.home-hero .hero-chips .hc{background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.24);border-radius:20px;padding:5px 13px;font-size:12px;font-weight:700}
.home-hero .hero-chips .hc b{font-weight:800}
/* ===== 홈 anada — 데이터/분석 블루 + 아이소메트릭 일러스트 ===== */
.ha-hero{position:relative;overflow:visible;z-index:3;display:flex;align-items:center;gap:40px;min-height:300px;
  background:linear-gradient(120deg,#EAF1FF 0%,#F3F8FF 52%,#EEF3FF 100%);
  border:1px solid #DCE7FB;border-radius:22px;padding:46px 56px;margin-bottom:18px;
  box-shadow:0 1px 2px rgba(47,107,255,.05),0 16px 40px -24px rgba(47,107,255,.5)}
/* 워터마크/일러스트 블리드 클립(히어로 자체는 overflow:visible 이라 검색 드롭다운이 안 잘림) */
.ha-hero-clip{position:absolute;inset:0;overflow:hidden;border-radius:22px;z-index:0;pointer-events:none}
.ha-hero-l{flex:1;position:relative;z-index:2}
.ha-hero-search{margin-top:18px;max-width:460px;position:relative;z-index:5}
.ha-hs-q{font-size:13.5px;font-weight:800;color:#13224A;margin-bottom:8px}
.ha-eye{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;letter-spacing:.03em;color:#1D4ED8;
  background:#fff;border:1px solid #D6E3FB;padding:5px 12px;border-radius:20px;box-shadow:0 2px 7px rgba(47,107,255,.18)}
.ha-hero h1{font-size:30px;font-weight:800;letter-spacing:-.6px;color:#13224A;margin-top:14px}
.ha-hero .hsub{font-size:14.5px;color:#5A6B8C;margin-top:10px;line-height:1.65;max-width:720px}
.ha-illu{width:330px;height:auto;flex:none;position:relative;z-index:1;filter:drop-shadow(0 14px 24px rgba(19,34,74,.16))}
@media(max-width:900px){.ha-illu{display:none}}
/* 히어로 배경 브랜드 심볼 워터마크(은은하게) */
.ha-wm{position:absolute;left:-46px;top:50%;transform:translateY(-50%);width:340px;height:340px;z-index:0;opacity:.05;pointer-events:none;--bm-d:#2F6BFF;--bm-v:#5B8DEF}
.ha-wm .brand-mark{width:100%;height:100%;display:block}
.ha-kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:18px}
.ha-kpi{position:relative;background:#fff;border:1px solid #E7ECF5;border-radius:18px;padding:18px;cursor:pointer;
  box-shadow:0 1px 2px rgba(19,34,74,.04),0 12px 28px -22px rgba(19,34,74,.34);transition:transform .16s,box-shadow .16s}
@media (hover:hover){
  .ha-kpi:hover{transform:translateY(-3px);box-shadow:0 18px 36px -18px rgba(47,107,255,.4)}
}
.ha-kpi .tile{width:46px;height:46px;border-radius:14px;display:flex;align-items:center;justify-content:center;background:var(--at);color:var(--ac)}
/* 홈 카드 보조 텍스트가 #76819A·#9AA3B8·#A6AFC2 하드코딩 회색이었다. 흰 카드 위 2.20~3.91:1 로
   AA 미달인데 내용은 KPI 부제·일정 시각·공지 날짜처럼 실제 데이터다. 회색 토큰으로 통일한다. */
.ha-kpi .lab{font-size:12px;color:var(--gray-500);font-weight:600;margin-top:14px}
.ha-kpi .num{font-size:27px;font-weight:800;color:#13224A;letter-spacing:-.5px;line-height:1.1;margin-top:2px;font-variant-numeric:tabular-nums}
.ha-kpi .num small{font-size:14px;color:var(--gray-400);font-weight:700;margin-left:1px}
.ha-kpi .sub{font-size:12.5px;color:var(--gray-400);margin-top:5px}
@media(max-width:1080px){.ha-kpis{grid-template-columns:repeat(2,1fr)}}
.ha-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
@media(max-width:900px){.ha-grid{grid-template-columns:1fr}}
/* 전체화면 대시보드: 시간표(넓게) + 오늘 일정 + 공지 3열, 화면 폭을 가득 채움 */
.ha-dash{display:grid;grid-template-columns:1.7fr 1fr 1fr;gap:16px;align-items:start;margin-bottom:16px}
.ha-dash>.ha-card{display:flex;flex-direction:column;min-height:240px}
.ha-dash .ha-empty{margin:auto 0}
@media(max-width:1240px){.ha-dash{grid-template-columns:1fr 1fr}.ha-dash .ha-tt{grid-column:1/-1}}
@media(max-width:760px){.ha-dash{grid-template-columns:1fr}.ha-dash .ha-tt{grid-column:auto}}
.ha-card{background:#fff;border:1px solid #E7ECF5;border-radius:18px;padding:18px 20px;box-shadow:0 1px 2px rgba(19,34,74,.04),0 10px 26px -22px rgba(19,34,74,.3)}
.ha-ch{display:flex;align-items:center;justify-content:space-between;margin-bottom:13px}
.ha-ch .t{display:flex;align-items:center;gap:9px;font-size:15px;font-weight:800;color:#13224A}
.ha-ch .t .i{width:30px;height:30px;border-radius:10px;display:flex;align-items:center;justify-content:center;background:var(--ci,#E8F0FF);color:var(--cic,#2F6BFF)}
.ha-ch .lnk{font-size:12px;font-weight:700;color:#2F6BFF;cursor:pointer}
@media (hover:hover){
  .ha-ch .lnk:hover{text-decoration:underline}
}
.ha-ag{display:flex;align-items:center;gap:12px;padding:11px 0;border-bottom:1px solid #EEF1F7;cursor:pointer}
.ha-ag:last-child{border-bottom:none}
.ha-ag .tp{font-size:12.5px;font-weight:700;color:#1D4ED8;background:#E8F0FF;border-radius:9px;padding:5px 9px;white-space:nowrap}
.ha-ag .nm{font-size:13px;font-weight:600;color:#2C3756}
.ha-ag .mt{font-size:12.5px;color:var(--gray-400);margin-top:1px}
.ha-nrow{display:flex;align-items:center;gap:8px;padding:10px 0;border-bottom:1px solid #EEF1F7;cursor:pointer}
.ha-nrow:last-child{border-bottom:none}
.ha-nrow .tt{flex:1;font-size:13px;font-weight:600;color:#2C3756;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ha-nrow .dt{font-size:12.5px;color:var(--gray-400);white-space:nowrap}
.ha-empty{text-align:center;padding:24px 8px;color:var(--gray-400);font-size:13px}
.ha-empty .lnk{color:#2F6BFF;cursor:pointer;font-weight:600}
.ha-badge-new{background:#2F6BFF!important;color:#fff!important}
/* 홈 대시보드 v2 (인사문구 없이 학원명·날짜 / 지표 5칸 / 시간표+상담 / 하단 4칸) */
.ha2{width:100%}
.ha2-top{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap;margin-bottom:16px}
.ha2-title{font:800 20px Pretendard;color:#161D34;display:flex;align-items:center;gap:8px}
.ha2-title .micon{color:#2F6BFF}
/* ha2 카드도 같은 문제 — #8A93A6(3.09:1)·#9AA3B5(2.54:1) 하드코딩. 토큰으로 통일. */
.ha2-sub{font:600 14px Pretendard;color:var(--gray-400)}
.ha2-date{font:600 13px Pretendard;color:var(--gray-400);margin-top:4px}
/* 홈에만 검색창이 2개였다 — 헤더(#topSearch)와 본문(#haSearch)이 같은 _renderSearch 를 불러
   결과까지 똑같았다. 헤더 검색은 앱 셸에 있어 모든 화면에서 쓰지만 760px 이하에서 숨는다
   (.top-search). 그래서 데스크톱은 헤더 하나만 두고, 헤더가 숨는 폭에서만 본문 검색을 살린다.
   → 어느 폭에서도 화면에 뜬 검색창은 1개다. */
.ha2-search{position:relative;flex:1 1 240px;max-width:380px;display:none}
@media(max-width:760px){.ha2-search{display:block;max-width:none}}
.ha2-search input{width:100%;height:40px;border:1px solid var(--border);border-radius:12px;padding:0 14px 0 38px;font-size:13px;background:#fff}
.ha2-search-ic{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--gray-400);pointer-events:none}
.ha2-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:14px;margin-bottom:16px}
/* align-items 가 center 였을 때, 같은 줄이라도 '부가 설명(.ha2-subl)이 있는 카드'와 없는
   카드의 숫자·라벨이 서로 다른 높이에 섰다(그리드가 높이를 맞춰 늘려 놓은 만큼 어긋난다).
   폰·데스크톱 모두 같은 결함이라 여기서 한 번에 위 정렬로 맞춘다. */
/* 부제(.ha2-subl)는 아이콘 옆 좁은 칸이 아니라 카드 폭 전체를 쓰는 아래 행에 둔다.
   1212px 에서 5열(카드 177px)이면 아이콘 옆 텍스트 칸이 94px 뿐이어서 '0% · 수납대상 4명'(100px)
   ·'오늘 1건 · 지난 예약 6건'(130px)이 2줄로 접혀 행이 116px 로 커졌다. 전체 폭이면 143px 라
   두 문구가 모두 한 줄에 들어가고(실측) 문구를 줄이지 않아도 된다. align-items:start 는
   flex-start 와 같은 뜻 — 부제 유무로 숫자·라벨이 서로 다른 높이에 서던 문제는 그대로 막힌다. */
.ha2-stat{display:grid;grid-template-columns:38px 1fr;column-gap:11px;align-items:start;background:#fff;border:1px solid var(--border);border-radius:14px;padding:14px 16px;cursor:pointer;transition:box-shadow .15s,transform .1s}
@media (hover:hover){
  .ha2-stat:hover{box-shadow:0 6px 18px rgba(16,24,54,.09);transform:translateY(-1px)}
}
.ha2-ic{width:38px;height:38px;flex:none;border-radius:11px;display:flex;align-items:center;justify-content:center}
.ha2-num{font:800 22px Pretendard;line-height:1}
.ha2-num small{font-size:12px;font-weight:700;margin-left:2px}
.ha2-lab{font:600 12.5px Pretendard;color:#5C6582;margin-top:5px}
.ha2-subl{grid-column:1/-1;font:500 12.5px Pretendard;color:var(--gray-400);margin-top:5px}
/* 가운데 줄도 아래 줄과 같은 4칸 그리드에 정렬: 시간표=3칸 span, 오늘 상담=4번째 칸(폭·좌측선이 하단 4번째 카드와 일치). align-items:stretch로 두 카드 높이도 동일. */
.ha2-mid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:16px;align-items:stretch}
.ha2-mid>.ha2-card:first-child{grid-column:span 3}
.ha2-bottom{display:grid;grid-template-columns:repeat(auto-fit,minmax(212px,1fr));gap:14px}
.ha2-card{background:#fff;border:1px solid var(--border);border-radius:16px;padding:16px 18px;min-width:0}
.ha2-ch{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:12px}
.ha2-ch .t{font:700 14px Pretendard;color:#161D34;display:flex;align-items:center;gap:7px}
.ha2-ch .t .muted{font-weight:400;font-size:12.5px;color:var(--gray-400)}
.ha2-ch .lnk{font:600 12px Pretendard;color:#2F6BFF;cursor:pointer;white-space:nowrap}
@media (hover:hover){
  .ha2-ch .lnk:hover{text-decoration:underline}
}
.ha2-crow{display:flex;gap:10px;align-items:flex-start;padding:9px 0;border-top:1px solid var(--gray-100);cursor:pointer}
.ha2-crow:first-of-type{border-top:none}
.ha2-crow .tp{font:700 12px Pretendard;color:#2F6BFF;white-space:nowrap;padding-top:1px}
.ha2-crow .nm{font:600 13px Pretendard;color:#161D34}
.ha2-crow .mt{font:400 12.5px Pretendard;color:var(--gray-400);margin-top:2px}
.ha2-lrow,.ha2-srow{display:flex;gap:8px;align-items:center;padding:7px 0;border-top:1px solid var(--gray-100);cursor:pointer;font-size:12.5px}
.ha2-lrow:first-of-type,.ha2-srow:first-of-type{border-top:none}
.ha2-lrow .dot{width:7px;height:7px;border-radius:50%;flex:none}
.ha2-lrow .tt{flex:1;min-width:0;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ha2-lrow .dt,.ha2-srow .dt{color:var(--gray-400);font-size:12.5px;white-space:nowrap;flex:none}
.ha2-srow .av{width:24px;height:24px;flex:none;border-radius:50%;background:#E8F0FF;color:#2F6BFF;display:flex;align-items:center;justify-content:center;font:700 12.5px Pretendard}
.ha2-srow .nm{font-weight:600;color:#161D34;flex:none}
.ha2-srow .cl{flex:1;min-width:0;color:var(--gray-400);font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 홈 '지금 수업 출결' 체크리스트 */
.hn-list{max-height:236px;overflow-y:auto;margin:0 -2px}
.hn-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 2px;border-top:1px solid var(--gray-100)}
.hn-row:first-child{border-top:none}
.hn-nm{font:600 13px Pretendard;color:#161D34;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hn-btns{display:flex;gap:4px;flex:none}
.hn-att{width:30px;height:28px;border:1px solid var(--border);background:#fff;border-radius:8px;font:700 12px Pretendard;color:var(--gray-500);cursor:pointer;transition:background .1s,color .1s,border-color .1s}
.hn-att.on{background:var(--c);border-color:var(--c);color:#fff}
@media(max-width:900px){.ha2-mid{grid-template-columns:1fr}.ha2-mid>.ha2-card:first-child{grid-column:auto}}
/* 가로 전체에서 안 깨지게 최대폭 제한(중앙 정렬) */
.ha-wrap{width:100%}
/* 홈 통합 검색(학생·기능) */
.ha-search{position:relative;max-width:540px;margin:0}
.ha-search-ic{position:absolute;left:18px;top:50%;transform:translateY(-50%);font-size:16px;pointer-events:none;opacity:.7}
.ha-search>input{width:100%;border:1.5px solid #DCE7FB;background:#fff;border-radius:999px;padding:15px 20px 15px 46px;font-size:15px;outline:none;box-shadow:0 2px 10px -4px rgba(19,34,74,.12)}
.ha-search>input:focus{border-color:#2F6BFF;box-shadow:0 0 0 4px rgba(47,107,255,.16)}
.ha-search-res{display:none;position:absolute;left:0;right:0;top:48px;z-index:50;background:#fff;border:1px solid #E3EAF5;border-radius:14px;box-shadow:0 18px 44px -18px rgba(19,34,74,.5);padding:6px;max-height:360px;overflow:auto}
.ha-sr-sec{font-size:12px;font-weight:800;color:var(--gray-500);letter-spacing:.04em;padding:9px 9px 4px}
/* 결과 한 줄은 한 줄로 — 긴 검색어·긴 학생명이 여러 줄로 늘어나 드롭다운이 아래 카드를 덮었다 */
.ha-sr-item{display:flex;align-items:center;gap:10px;padding:8px 9px;border-radius:10px;cursor:pointer}
.ha-sr-item > *:not(.ic){min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (hover:hover){
  .ha-sr-item:hover{background:#F1F5FF}
}
/* 키보드(↑↓)로 고른 항목 — hover 와 구분되게 조금 더 진하게. 예전엔 ↑↓ 가 아예 안 먹어
   마우스 없이는 검색 결과를 고를 수 없었다(#6). */
.ha-sr-item.active{background:#E2EBFF;box-shadow:inset 0 0 0 1px #B9CCFF}
.ha-sr-item .ic{width:28px;height:28px;border-radius:8px;background:#EAF1FF;color:#2F6BFF;display:flex;align-items:center;justify-content:center;font-size:12.5px;font-weight:800;flex:none}
.ha-sr-item .ic.fn{background:#EEF2F7;color:#5A6B8C}
.ha-sr-item .ic.fn svg{width:15px;height:15px}
.ha-sr-item .t{font-size:13px;font-weight:600;color:#2C3756}
.ha-sr-item .m{font-size:12.5px;color:var(--gray-400);margin-top:1px}
.ha-sr-empty{padding:16px 10px;color:var(--gray-400);font-size:12.5px;text-align:center}
/* 인사 영역 컴팩트 스탯 칩(큰 카드 대체) */
.ha-stats{display:flex;flex-wrap:wrap;gap:9px;margin-top:16px}
.ha-stat{display:inline-flex;align-items:center;gap:8px;background:rgba(255,255,255,.72);border:1px solid #DCE7FB;border-radius:13px;padding:8px 14px;cursor:pointer;transition:.15s}
@media (hover:hover){
  .ha-stat:hover{background:#fff;transform:translateY(-1px);box-shadow:0 8px 16px -9px rgba(47,107,255,.45)}
}
.ha-stat .dot{width:9px;height:9px;border-radius:50%;background:var(--sc);flex:none}
.ha-stat .v{font-size:18.5px;font-weight:800;color:#13224A;letter-spacing:-.3px;font-variant-numeric:tabular-nums}
.ha-stat .v small{font-size:12.5px;font-weight:700;color:var(--gray-400);margin-left:1px}
.ha-stat .l{font-size:12px;color:#5A6B8C;font-weight:600}
@media(max-width:560px){.ha-stat{flex:1 1 44%}}
/* ===== 로그인 화면 ===== */
.login-bg{position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;overflow:hidden;
  background:radial-gradient(120% 120% at 12% 8%, #EEF0FF 0%, #F4F5FA 46%, #E7ECFF 100%)}
.login-bg .blob{position:absolute;border-radius:50%;filter:blur(64px);opacity:.45;pointer-events:none}
.login-bg .blob.v{width:430px;height:430px;left:-130px;top:-120px;background:radial-gradient(circle,#6439FF,transparent 70%)}
.login-bg .blob.b{width:500px;height:500px;right:-170px;bottom:-170px;background:radial-gradient(circle,#050C9C,transparent 70%)}
.login-card{position:relative;width:382px;max-width:92vw;background:#fff;border-radius:24px;padding:34px 32px 28px;
  box-shadow:0 30px 70px -28px rgba(20,16,60,.45),0 2px 8px rgba(20,16,60,.05);border:1px solid rgba(255,255,255,.8)}
.login-brand{display:flex;flex-direction:column;align-items:center;gap:13px;margin-bottom:22px}
.login-brand .bm-wrap{width:64px;height:64px;border-radius:19px;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(140deg,#F1ECFF,#E7ECFF);box-shadow:inset 0 0 0 1px rgba(100,57,255,.14),0 10px 22px -10px rgba(100,57,255,.4)}
.login-brand .bm-wrap .brand-mark{width:42px;height:42px}
.login-title{font-size:25px;font-weight:800;letter-spacing:-.6px;color:#1E2233;line-height:1}
.login-title b{background:linear-gradient(120deg,#6439FF,#312E81);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
.login-sub{font-size:12.5px;color:var(--gray-500);margin-top:6px;text-align:center}
.login-card .field{margin-bottom:13px}
.login-card .field label{display:block;font-size:12px;font-weight:700;color:var(--gray-600);margin-bottom:5px}
.login-btn{background:linear-gradient(120deg,#6439FF,#4F46E5)!important;box-shadow:0 12px 26px -8px rgba(100,57,255,.6)!important;border:none}
@media (hover:hover){
  .login-btn:hover{filter:brightness(1.05)}
}
.login-demo{margin-top:18px;border-top:1px dashed var(--gray-200);padding-top:15px}
.login-demo .dlabel{font-size:12px;color:var(--gray-400);font-weight:700;margin-bottom:9px;text-align:center}
.login-demo .drow{display:flex;gap:7px}
.login-demo .dchip{flex:1;border:1px solid var(--gray-200);border-radius:12px;padding:9px 6px;text-align:center;transition:.14s;background:#fff;cursor:pointer}
@media (hover:hover){
  .login-demo .dchip:hover{border-color:#6439FF;background:#F6F3FF;transform:translateY(-1px)}
}
.login-demo .dchip .r{font-size:12px;font-weight:800;color:#312E81}
.login-demo .dchip .e{font-size:12px;color:var(--gray-400);margin-top:2px;letter-spacing:-.2px}
/* 로그인 화면은 앱 위(z-index 9999)를 덮는다. 그래서 로그인 전에 연 모달(비밀번호 찾기)·
   안내창·토스트가 전부 로그인 카드 뒤에 깔려 "눌러도 아무 일이 없다"가 됐다(실제로는
   떠 있었고, 로그인해서 이 배경이 사라져야 비로소 보였다). 로그인 중일 때만 위로 올린다. */
body.at-login .modal-overlay{z-index:10000}
body.at-login .modal-overlay.ui-dlg{z-index:10001}
body.at-login .toast{z-index:10002;pointer-events:none}
/* ===== 도우미 챗봇(오른쪽 아래) ===== */
/* 앱의 다른 화면과 같은 언어로 — 보라 그라데이션(#6439FF)은 이 앱 어디에도 없다.
   카드는 흰 배경 + var(--border) 테두리 + 14px 라운드 + var(--shadow) 이고 강조는 --primary 하나다.
   챗봇만 다른 브랜드처럼 보이던 것을 그 규칙에 맞춘다(색·라운드·테두리·그림자 전부 토큰 사용). */
#botFab{position:fixed;right:20px;bottom:20px;z-index:150;width:52px;height:52px;border-radius:16px;border:0;cursor:pointer;
  background:var(--primary);color:#fff;box-shadow:0 8px 22px -8px rgba(59,130,246,.55);
  display:flex;align-items:center;justify-content:center;transition:transform .14s,box-shadow .14s,background .14s}
@media (hover:hover){
  #botFab:hover{transform:translateY(-1px);background:var(--primary-dark);box-shadow:0 12px 26px -8px rgba(37,99,235,.6)}
}
#botFab svg{width:24px;height:24px}
#botFab .dot{position:absolute;top:-2px;right:-2px;width:10px;height:10px;border-radius:50%;background:var(--green,#16A34A);border:2px solid #fff}
#botPanel{position:fixed;right:20px;bottom:84px;z-index:151;width:368px;max-width:calc(100vw - 32px);height:min(560px,calc(100vh - 130px));
  background:#fff;border:1px solid var(--border);border-radius:16px;overflow:hidden;display:none;flex-direction:column;
  box-shadow:0 18px 44px -14px rgba(30,34,51,.22),0 2px 8px rgba(30,34,51,.06)}
#botPanel.show{display:flex}
/* 머리글은 색면이 아니라 앱의 카드 머리처럼 — 흰 바탕 + 아래 경계선. 강조는 아이콘 하나로 준다. */
.bot-head{display:flex;align-items:center;gap:10px;padding:14px 15px;border-bottom:1px solid var(--border);background:#fff;color:var(--dark)}
.bot-head .ic{flex:none;width:32px;height:32px;border-radius:10px;background:var(--primary-light);color:var(--primary-dark);
  display:flex;align-items:center;justify-content:center}
.bot-head .ic svg{width:17px;height:17px}
.bot-head .t{font-size:14px;font-weight:700;letter-spacing:-.2px}
.bot-head .s{font-size:12.5px;color:var(--gray-500);margin-top:1px}
.bot-head button{margin-left:auto;background:transparent;border:0;color:var(--gray-400);width:30px;height:30px;border-radius:9px;
  cursor:pointer;font-size:17px;line-height:1;transition:.12s}
@media (hover:hover){
  .bot-head button:hover{background:var(--gray-100);color:var(--gray-700)}
}
.bot-body{flex:1;overflow-y:auto;padding:14px;background:var(--gray-50);display:flex;flex-direction:column;gap:9px}
.bot-msg{max-width:88%;font-size:13.2px;line-height:1.68;padding:10px 13px;border-radius:14px;white-space:pre-wrap;word-break:break-word}
.bot-msg.me{align-self:flex-end;background:var(--primary);color:#fff;border-bottom-right-radius:5px}
.bot-msg.ai{align-self:flex-start;background:#fff;color:var(--gray-700);border:1px solid var(--border);border-bottom-left-radius:5px}
/* 이동 버튼·추천 질문은 앱의 .chip 과 같은 모양으로 통일한다 */
.bot-acts{display:flex;flex-wrap:wrap;gap:6px;align-self:flex-start;max-width:92%}
.bot-acts button{background:var(--primary-light);border:1px solid var(--primary);color:var(--primary-dark);font-size:12.2px;font-weight:600;
  padding:7px 12px;border-radius:999px;cursor:pointer;font-family:inherit;transition:.12s}
@media (hover:hover){
  .bot-acts button:hover{background:#DCE8FD}
}
.bot-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 14px 12px;background:var(--gray-50)}
.bot-chips button{background:#fff;border:1px solid var(--gray-200);color:var(--gray-500);font-size:12px;font-weight:500;
  padding:6px 11px;border-radius:999px;cursor:pointer;font-family:inherit;transition:.12s}
@media (hover:hover){
  .bot-chips button:hover{border-color:var(--gray-300);color:var(--gray-700)}
}
.bot-foot{display:flex;gap:8px;padding:11px 12px;border-top:1px solid var(--border);background:#fff}
.bot-foot input{flex:1;min-width:0;border:1px solid var(--gray-200);border-radius:11px;padding:10px 13px;font-size:13.4px;font-family:inherit;background:#fff;color:var(--dark)}
.bot-foot input:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 3px rgba(59,130,246,.14)}
.bot-foot button{background:var(--primary);border:0;color:#fff;border-radius:11px;padding:0 15px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit;transition:.12s}
@media (hover:hover){
  .bot-foot button:hover:not(:disabled){background:var(--primary-dark)}
}
.bot-foot button:disabled{opacity:.45;cursor:default}
.bot-typing{display:flex;gap:4px;align-self:flex-start;background:#fff;border:1px solid var(--border);padding:12px 14px;border-radius:14px}
.bot-typing i{width:6px;height:6px;border-radius:50%;background:var(--gray-300);animation:botBlink 1.2s infinite}
.bot-typing i:nth-child(2){animation-delay:.18s}.bot-typing i:nth-child(3){animation-delay:.36s}
@keyframes botBlink{0%,60%,100%{opacity:.3}30%{opacity:1}}
/* 학생 상세의 '변경사항 저장' 고정 바가 같은 자리(오른쪽 아래)에 있다 — 챗봇이 그 위를
   덮으면 저장 버튼을 못 누른다. 그 바가 있는 화면에서는 챗봇을 위로 올린다. */
body.has-savebar #botFab{bottom:86px}
body.has-savebar #botPanel{bottom:152px;height:min(560px,calc(100vh - 196px))}
/* 모바일: 화면을 덮는 시트로 — 좁은 폭에서 카드가 잘리지 않게 */
@media(max-width:560px){
  #botFab{right:14px;bottom:14px;width:52px;height:52px}
  #botPanel{right:8px;left:8px;bottom:74px;width:auto;max-width:none;height:min(70vh,520px)}
  body.has-savebar #botFab{bottom:82px}
  body.has-savebar #botPanel{bottom:142px;height:min(62vh,470px)}
}
/* 로그인·안내 오버레이 위에는 챗봇을 띄우지 않는다 */
body.at-login #botFab,body.at-login #botPanel{display:none}
/* 관리자 테이블 폴리시(줄바꿈 방지) */
.adm-pill{white-space:nowrap}
.adm-tag,.adm-tag-admin{white-space:nowrap}
.adm-table .adm-cell-main{white-space:nowrap}
.academy-switch{
  display:flex;align-items:center;justify-content:space-between;
  padding:10px 12px;background:var(--primary-light);border-radius:12px;cursor:pointer;transition:.15s;
}
@media (hover:hover){
  .academy-switch:hover{background:#E4E6FD}
}
.academy-switch .name{font-weight:700;color:var(--primary-dark);font-size:13px}
.academy-switch .sub{font-size:12.5px;color:var(--gray-400);margin-top:2px}
.academy-switch .arrow{color:var(--primary-dark);font-size:12px}
.nav-section{padding:12px 16px 5px;font-size:12px;font-weight:700;color:var(--gray-400);letter-spacing:.5px;display:flex;align-items:center;justify-content:space-between;cursor:pointer;user-select:none;border-radius:8px;margin:0 6px;transition:.12s}
@media (hover:hover){
  .nav-section:hover{color:var(--gray-600);background:var(--gray-50)}
}
/* 접기 캐럿 — opacity:.7 이 겹쳐 실효 대비가 1.90:1 이었고, 토큰을 올린 뒤에도 2.89:1 로
   여전히 미달이라 투명도를 뺐다. 그래도 12px 삼각형이 섹션 이름과 같은 색(gray-400)이어서
   '눌러서 접는 컨트롤'로 읽히지 않았다 → 이름보다 한 단계 크고 진하게 한다.
   흰 사이드바 7.79:1, 다크(관리자) 9.7:1 로 3:1 요건을 넘긴다. */
.nav-caret{font-size:15px;line-height:1;color:var(--gray-600);transition:.18s}
.app.admin .nav-caret{color:rgba(255,255,255,.75)}
.nav-group{overflow:hidden}
.nav{flex:1;overflow-y:auto;padding-bottom:20px}
/* 사이드바 메뉴는 본문과 별개로 자기만 스크롤한다. 화면이 짧으면 마지막 그룹('설정')이
   그냥 아래에 잠기는데, 알려 주는 것이 얇고 연한 스크롤바뿐이라 '메뉴가 여기까지'로 읽혔다.
   위/아래 그늘로 '더 있다'를 알린다. 가림막(local)은 내용과 함께 움직이고 그늘(scroll)은
   보이는 상자에 붙어 있어, 넘칠 때·그 방향의 끝이 아닐 때만 그늘이 드러난다.
   스크롤 이벤트나 scrollIntoView 를 쓰지 않으므로 사용자의 스크롤을 되돌리지 않는다. */
.sidebar{--side-bg:#fff;--side-bg0:rgba(255,255,255,0);--side-sh:rgba(15,27,61,.26);--side-sh0:rgba(15,27,61,0)}
.app.admin .sidebar{--side-bg:#1E1B36;--side-bg0:rgba(30,27,54,0);--side-sh:rgba(0,0,0,.55);--side-sh0:rgba(0,0,0,0)}
.nav{
  background:
    linear-gradient(var(--side-bg) 38%, var(--side-bg0)) top/100% 20px local no-repeat,
    linear-gradient(var(--side-bg0), var(--side-bg) 62%) bottom/100% 26px local no-repeat,
    radial-gradient(farthest-side at 50% 0, var(--side-sh), var(--side-sh0)) top/100% 11px no-repeat,
    radial-gradient(farthest-side at 50% 100%, var(--side-sh), var(--side-sh0)) bottom/100% 11px no-repeat;
  background-color:var(--side-bg);
}
.nav-item{
  display:flex;align-items:center;gap:10px;padding:9px 14px;margin:2px 10px;
  border-radius:11px;color:var(--gray-600);font-size:13px;font-weight:500;cursor:pointer;transition:.12s;
}
@media (hover:hover){
  .nav-item:hover{background:var(--gray-50);color:var(--dark)}
}
.nav-item.active{background:#2563EB linear-gradient(135deg,#1D4ED8,#2563EB);color:#fff;font-weight:600;box-shadow:0 6px 16px rgba(59,130,246,.32)}
.nav-item .ico{width:18px;height:18px;flex-shrink:0;opacity:.85}
.nav-item.active .ico{opacity:1}

/* ===== 메인 ===== */
/* min-width:0 이 없으면 .main 은 flex 항목의 자동 최소 크기(min-content)로 부풀어, 줄어들
   수 없는 표(공지 제목 칸 nowrap+max-width, 성적 표 min-width:720px 등)의 min-content 가
   그대로 페이지 폭이 된다 → 사이드바는 fixed 라 제자리인데 본문만 밀려 '우측이 잘린' 모습이
   되고, .tbl-scroll 은 컨테이너가 함께 넓어져 **내부 스크롤을 아예 안 만든다**(넓은 표만
   가로로 밀리게 하려던 _wrapContentTables 가 무력화된다).
   실측(1212×881): 공지 목록에서 문서 가로 초과 24px·표 내부 스크롤 0 → 적용 후 초과 0px·
   표만 24px 스크롤. 900×881 에서는 초과 336px·'+ 공지 작성' 버튼이 화면 밖 312px 이었다.
   860px 이하에는 이미 같은 선언이 있다(@media(max-width:860px) 의 .main) — 데스크톱에도 둔다. */
.main{flex:1;min-width:0;margin-left:236px;display:flex;flex-direction:column;min-height:100vh}
.topbar{
  height:58px;background:#fff;border-bottom:1px solid var(--border);
  display:flex;align-items:center;justify-content:space-between;padding:0 24px;
  position:sticky;top:0;z-index:40;
}
.topbar .crumb{display:flex;align-items:center;gap:8px}
.topbar .page-title{font-size:18px;font-weight:700;margin:0}   /* h1 기본 여백 제거 */
.topbar .back-btn{display:flex;align-items:center;gap:5px;font-size:13px;color:var(--gray-500);font-weight:600;padding:6px 10px;border-radius:8px}
@media (hover:hover){
  .topbar .back-btn:hover{background:var(--gray-100);color:var(--dark)}
}
.topbar-right{display:flex;align-items:center;gap:8px}
.top-search{position:relative;width:210px}
.top-search .ts-ic{position:absolute;left:12px;top:50%;transform:translateY(-50%);font-size:12.5px;opacity:.6;pointer-events:none}
.top-search>input{width:100%;border:1px solid var(--border);background:var(--gray-50);border-radius:999px;padding:8px 12px 8px 32px;font-size:12.5px;outline:none}
.top-search>input:focus{border-color:var(--primary);background:#fff;box-shadow:0 0 0 3px rgba(47,107,255,.12)}
.top-search .ha-search-res{top:42px;left:auto;right:0;width:320px}
@media(max-width:760px){.top-search{display:none}}
.icon-btn{
  width:38px;height:38px;border-radius:11px;display:flex;align-items:center;justify-content:center;
  color:var(--gray-500);position:relative;transition:.12s;
}
@media (hover:hover){
  .icon-btn:hover{background:var(--gray-100);color:var(--dark)}
}
.badge-dot{position:absolute;top:8px;right:8px;width:7px;height:7px;border-radius:50%;background:var(--red);border:1.5px solid #fff}
.profile{display:flex;align-items:center;gap:8px;padding:5px 10px;border-radius:11px;cursor:pointer;transition:.12s}
@media (hover:hover){
  .profile:hover{background:var(--gray-100)}
}
.avatar{width:30px;height:30px;border-radius:50%;background:var(--primary-dark);color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex:none;overflow:hidden}
/* 사진이 등록된 학생 — 이름 첫 글자 대신 업로드한 사진을 채워 넣는다 */
.avatar.has-photo{background:var(--gray-100)}
.avatar>img{width:100%;height:100%;object-fit:cover;display:block}
.content{flex:1;padding:24px;overflow-y:auto}

/* ===== 공통 컴포넌트 ===== */
.card{background:#fff;border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow)}
.card-pad{padding:20px}
.card-title{font-size:15px;font-weight:700;display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:14px}
.card-title>.micon:first-child,.card-title>i.micon:first-child{margin-right:2px}
/* 마스터 설정 — 위기·주의 기준 문장형 선택 줄 */
.mw-line{font-size:13px;line-height:1.9;display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:2px 0 10px}
@media(max-width:520px){.mw-line{font-size:12.5px;gap:4px}.mw-line .input{width:56px!important;padding:5px 2px!important}}
/* 스크롤 카드: 제목이 스크롤해도 상단 고정 */
.card-sc{padding-top:0}
.card-sc>.card-title{position:sticky;top:0;z-index:3;background:#fff;padding-top:16px;padding-bottom:8px;margin-bottom:8px;box-shadow:0 4px 8px -6px rgba(19,34,74,.14)}
.card-title .link{font-size:12px;color:var(--primary-dark);font-weight:600;cursor:pointer}
@media (hover:hover){
  .card-title .link:hover{text-decoration:underline}
}
.grid{display:grid;gap:16px}
.btn{display:inline-flex;align-items:center;gap:6px;padding:9px 16px;border-radius:11px;font-size:13px;font-weight:600;transition:.14s;white-space:nowrap}
.btn-primary{background:#2563EB linear-gradient(135deg,#1D4ED8,#2563EB);color:#fff;box-shadow:0 6px 16px rgba(59,130,246,.28)}
@media (hover:hover){
  .btn-primary:hover{filter:brightness(1.05);box-shadow:0 8px 20px rgba(59,130,246,.36)}
}
.btn-outline{background:#fff;color:var(--gray-700);border:1px solid var(--gray-200)}
/* 선택된 '지각·연기'용 — 예전엔 btn-outline(흰 배경)이라 고른 티가 안 났다.
   결석·미완만 색이 채워져, 상단 집계는 올라가는데 버튼은 안 눌린 것처럼 보였다. */
.btn-warn{background:var(--orange);color:#fff;border:1px solid var(--orange)}
@media (hover:hover){
  .btn-warn:hover{filter:brightness(.96)}
  .btn-outline:hover{background:var(--gray-50);border-color:var(--gray-300)}
}
.btn-ghost{background:var(--gray-100);color:var(--gray-600)}
@media (hover:hover){
  .btn-ghost:hover{background:var(--gray-200)}
}
.btn-danger{background:var(--red);color:#fff}
@media (hover:hover){
  .btn-danger:hover{filter:brightness(1.05)}
}
.btn-sm{padding:6px 11px;font-size:12px;border-radius:9px}
/* disabled 를 붙여도 색이 그대로여서 눌리는 버튼처럼 보였다 — 잠긴 버튼은 눈에도 잠겨 보이게 */
.btn:disabled,.btn[disabled]{opacity:.45;cursor:not-allowed;box-shadow:none}
@media (hover:hover){
  .btn:disabled:hover,.btn[disabled]:hover{filter:none;box-shadow:none}
}
.btn-block{width:100%;justify-content:center}
.badge{display:inline-flex;align-items:center;padding:4px 10px;border-radius:20px;font-size:12.5px;font-weight:700}
/* 과제 진행 단계명은 학원이 마스터 설정에서 직접 입력하는 값이라 길이 제한이 없다.
   .btn 은 white-space:nowrap 이어서 예전에는 '제출 확인' 표의 처리 버튼 3개가
   입력한 글자 수만큼 그대로 늘어나 표가 카드 밖으로 밀려 나갔고,
   배지는 여러 줄로 쪼개져 행 높이가 제각각이 됐다.
   표시 폭을 한 줄로 제한하고 잘린 글자는 title 속성으로 확인한다
   — 글자 크기·색 대비는 건드리지 않는다. */
.stg-lbl{display:block;max-width:7em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(max-width:520px){.stg-lbl{max-width:5em}}
.badge-green{background:var(--green-light);color:#047857}
.badge-orange{background:var(--orange-light);color:#B45309}
.badge-red{background:var(--red-light);color:#BE123C}
.badge-blue{background:var(--primary-light);color:var(--primary-dark)}
.badge-purple{background:var(--purple-light);color:#6D28D9}
.badge-teal{background:var(--teal-light);color:#0F766E}
.badge-gray{background:var(--gray-100);color:var(--gray-500)}
.badge-new{background:#2563EB linear-gradient(135deg,#1D4ED8,#2563EB);color:#fff;font-size:12px;padding:3px 7px}
/* 위기·주의 배지 — 행이 많은 목록(수강생)에 붙으므로 .badge 보다 작게 잡는다.
   이름 칸은 폰에서 flex-wrap:nowrap 이라, 줄어들면 안 되는 이 칩에 flex:0 0 auto 를 준다
   (대신 이름 쪽이 말줄임으로 접힌다 — 배지가 아래로 떨어져 행 높이가 터지는 것보다 낫다). */
.risk-chip{flex:0 0 auto;padding:2px 7px;font-size:12px;white-space:nowrap;cursor:help}
.risk-chip.rc-crisis{background:var(--red-light);color:#BE123C}
.risk-chip.rc-warn{background:var(--orange-light);color:#B45309}
table{width:100%;border-collapse:collapse}
.tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
th{text-align:left;padding:11px 14px;font-size:12.5px;font-weight:700;color:var(--gray-400);background:var(--gray-50);border-bottom:1px solid var(--border)}
td{padding:12px 14px;font-size:13px;border-bottom:1px solid var(--gray-100)}
td.flex{gap:8px;align-items:center}
tr:last-child td{border-bottom:none}
tr.clickable{cursor:pointer;transition:.1s}
@media (hover:hover){
  tr.clickable:hover td{background:var(--primary-light)}
}
/* ── 표 헤더 클릭 정렬(4차 QA BUG-19) ──
   방향 표시는 헤더의 오른쪽 여백(위 th{padding:11px 14px}) 안에 절대배치한다 — 글자폭을
   전혀 차지하지 않는다. 인라인 글리프로 두면 열이 넓어져 _tablePass 의 '이 표가 넘치는가'
   실측 판정과 _tableScrollHint 가 함께 흔들리고, 좁은 화면에서 헤더가 2줄로 접힌다.
   (측정: 학생관리 표 폭 916→916, 열 폭 192,118,195,190,88,134 붙이기 전후 동일) */
th.thsort{position:relative;cursor:pointer;user-select:none}
@media (hover:hover){
  th.thsort:hover{color:var(--gray-600)}
}
th.thsort:focus{outline:2px solid var(--primary);outline-offset:-2px}
th.thsort::after{content:'↕';position:absolute;right:3px;top:50%;transform:translateY(-50%);font-size:11px;font-weight:700;line-height:1;color:var(--gray-300);opacity:0}
@media (hover:hover){
  th.thsort:hover::after{opacity:1}
}
th.thsort:focus::after{opacity:1}
/* 켜진 방향만 앱의 강조색으로 — 새 색을 만들지 않는다(.tab.active 와 같은 --primary-dark) */
th.thsort.sort-asc::after{content:'▲';color:var(--primary-dark);opacity:1}
th.thsort.sort-desc::after{content:'▼';color:var(--primary-dark);opacity:1}
/* 손가락으로 쓰는 기기(태블릿) — th 는 패딩 11+11 + 줄 19 = 41px 로 44px 에 3px 모자란다.
   _tapPass 는 th 를 대상에 넣지 않는다(표 구조 요소라 가로로 벌리면 행이 무너진다 —
   .badge·.sev 를 _TAP_DENY 로 뺀 것과 같은 이유) → 여기서 세로만 키운다.
   폰(≤560px)은 _tablePass 가 넘치는 표를 카드로 접고 thead 를 감추므로(table.tbl-cards >
   thead{display:none}) 이 규칙이 닿지 않는다 — 폰의 정렬은 필터바 '정렬' select 가 맡는다.
   hover 가 없는 기기에서는 '정렬 가능' 힌트도 늘 보이게 둔다(::after 는 폭을 안 먹는다). */
@media (hover:none){
  th.thsort,.adm-table thead th.thsort{padding-top:14px;padding-bottom:14px}
  th.thsort::after{opacity:.55}
}
/* 폰 전용 정렬 select — 카드 모드(thead 숨김)와 같은 breakpoint 에서만 나온다.
   그 위 폭에서는 헤더를 직접 누르므로 숨긴다(두 컨트롤이 나란히 있으면 중복이다). */
.sort-m{display:none}
@media (max-width:560px){
  .sort-m{display:block;width:100%;height:40px;margin:0 0 8px;font-size:13px}
}
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--border);margin-bottom:16px;flex-wrap:wrap}
.tab{padding:9px 16px;font-size:13px;font-weight:600;color:var(--gray-500);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;white-space:nowrap;flex:none}
@media (hover:hover){
  .tab:hover{color:var(--dark)}
}
.tab.active{color:var(--primary-dark);border-bottom-color:var(--primary)}
.page-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;margin-bottom:16px}
.input{width:100%;padding:10px 13px;border:1px solid var(--gray-200);border-radius:11px;font-size:13px;background:#fff;transition:.14s}
/* 표준 폼(.field) 안의 입력·선택칸만 높이 통일 — 날짜 칸이 옆 칸보다 커 보이던 문제 해결.
   기간/시간 등 컴팩트 입력(.field 밖)은 원래 크기 유지(세로 커짐 방지) */
.field input.input:not([type=checkbox]):not([type=radio]):not([type=file]),.field select.input{height:38px}
/* 파일 선택칸 — 네이티브 컨트롤이 잘려 깨져 보이던 문제: 높이 자동 + 버튼 스타일링 */
input[type=file].input{height:auto;padding:7px 10px;font-size:12.5px;color:var(--gray-500);line-height:1.5;cursor:pointer}
input[type=file].input::file-selector-button{margin-right:10px;padding:6px 13px;border:none;border-radius:8px;background:var(--primary);color:#fff;font-weight:700;font-size:12px;cursor:pointer;transition:.14s}
input[type=file].input::-webkit-file-upload-button{margin-right:10px;padding:6px 13px;border:none;border-radius:8px;background:var(--primary);color:#fff;font-weight:700;font-size:12px;cursor:pointer}
@media (hover:hover){
  input[type=file].input::file-selector-button:hover{filter:brightness(.94)}
}
.input:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 3px rgba(59,130,246,.14)}
select.input{cursor:pointer;appearance:none;-webkit-appearance:none;-moz-appearance:none;padding-right:36px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;background-size:15px}
@media (hover:hover){
  select.input:hover{border-color:var(--gray-300)}
}
.timepick{display:flex;align-items:center;gap:7px}
.timepick .tp-sel{flex:1;min-width:0;padding-right:30px;background-position:right 9px center}
.tp-colon{font-weight:800;color:var(--gray-400)}
.field{margin-bottom:14px}
.field label{display:block;font-size:12px;font-weight:600;color:var(--gray-600);margin-bottom:6px}
/* 필드 라벨의 필수/선택 표기 규칙 — 예전엔 별표, '(선택)', '· 선택' 세 표기가 뒤섞여 같은 뜻인데도
   화면마다 다르게 보였고, 필수가 아닌 칸에도 별표가 붙어 있었다. 새 필드는 아래 셋만 쓴다.
   1) 필수 = 비우거나 미선택으로 두면 저장·실행이 막히는 칸. 라벨 뒤에 span.req 별표 하나만 붙인다.
   2) 선택 = 아무 표시도 붙이지 않는다. 비워도 된다고 알려 줄 필요가 있을 때만
      span.muted 로 '· 선택' 을 덧붙인다. '(선택)' 괄호꼴은 쓰지 않는다.
   3) '전체'·'미지정' 값으로도 그대로 진행되는 필터성 칸은 필수가 아니다 — 별표를 붙이지 않는다.
   CSV 컬럼 안내문·토스트·placeholder 는 라벨이 아니라 설명문이라 이 규칙 대상이 아니다. */
.field .req{color:var(--red-text)}
.field .help{font-size:12.5px;color:var(--gray-400);margin-top:4px}
.row-2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.row-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}
.row-4{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
/* 그리드 칸이 내용(date input 등) 고유폭 아래로도 줄어들게 — 우측 삐져나옴 방지 */
.row-2>*,.row-3>*,.row-4>*{min-width:0}
.row-2 .input,.row-3 .input,.row-4 .input{max-width:100%}

/* 통계 카드 */
.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px}
.stat{background:#fff;border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px;box-shadow:var(--shadow)}
.stat .label{font-size:12px;color:var(--gray-500);display:flex;align-items:center;gap:6px}
.stat .val{font-size:26px;font-weight:800;margin:6px 0 2px;letter-spacing:-.5px}
.stat .delta{font-size:12px;font-weight:600}
.stat .delta.up{color:var(--green-text)} .stat .delta.warn{color:var(--orange-text)} .stat .delta.down{color:var(--red-text)} .stat .delta.muted{color:var(--gray-400)}

/* 액션 카드 (홈) */
.action-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:20px}
.action-card{background:#fff;border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px;box-shadow:var(--shadow);cursor:pointer;transition:.18s;position:relative;overflow:hidden}
@media (hover:hover){
  .action-card:hover{transform:translateY(-3px);box-shadow:0 14px 30px rgba(30,34,51,.1)}
}
.action-card .ac-ico{width:42px;height:42px;border-radius:13px;display:flex;align-items:center;justify-content:center;margin-bottom:11px}
.action-card .ac-label{font-size:12.5px;color:var(--gray-600);font-weight:500}
.action-card .ac-num{font-size:24px;font-weight:800;margin-top:3px}
.action-card .ac-arrow{position:absolute;top:16px;right:16px;color:var(--gray-400);font-size:15px}
@media (hover:hover){
  .action-card:hover .ac-arrow{color:var(--primary-dark)}
}

/* 프로그레스 */
.progress{height:9px;background:var(--gray-200);border-radius:20px;overflow:hidden}
.progress .fill{height:100%;background:linear-gradient(90deg,#1D4ED8,#2563EB);border-radius:20px}

/* ===== 모달 ===== */
.modal-overlay{position:fixed;inset:0;background:rgba(30,34,51,.45);backdrop-filter:blur(2px);z-index:300;display:none;align-items:center;justify-content:center;padding:20px}
/* 예전엔 모달이 100, 챗봇이 150/151 이라 챗봇 버튼이 모달 위로 떠 있었다.
   모달이 열려 있는 동안에는 챗봇을 누를 수도, 탭으로 갈 수도 없어야 한다. */
body:has(.modal-overlay.show) #botFab, body:has(.modal-overlay.show) #botPanel{ pointer-events:none; opacity:.35; }
.modal-overlay.show{display:flex}
/* 안내창은 기존 모달 위에 뜬다(모달 안에서 확인을 묻는 경우).
   200 이면 모달(300) 아래라 주석과 정반대로 동작했다 — 모달 안에서 띄운 확인창이
   그 모달 뒤에 깔려 보이지 않았다. 레이어는 모달 300 < 확인창 400 < 토스트 500 이다. */
.modal-overlay.ui-dlg{z-index:400;background:rgba(30,34,51,.5)}
/* 확인창 버튼은 항상 같은 자리에 — 문구 줄 수·버튼 라벨 길이에 따라 좌표가 흔들리면
   같은 위치를 눌렀는데 취소/확인이 뒤바뀐다(오발송 위험). */
.modal-overlay.ui-dlg .modal-foot{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.modal-overlay.ui-dlg .modal-foot .btn{width:100%;min-width:0;justify-content:center}
.modal-overlay.ui-dlg .modal-foot .btn:only-child{grid-column:1/-1}
.modal-overlay.ui-dlg .modal{animation:none}   /* 등장 애니메이션 중 히트 영역이 움직이지 않게 */
.modal-overlay.ui-dlg .modal-foot{justify-content:flex-end;gap:8px}
/* max-height:90vh 는 오버레이가 실제로 주는 공간(100vh - padding 20px×2)보다 48px 작았다.
   그래서 내용이 조금만 길어도 '14px 만 움직이는' 쓸모없는 스크롤바가 생기고 위가 잘려 보였다.
   오버레이가 비워 둔 만큼을 그대로 쓴다 — 진짜 넘칠 때만 스크롤한다. */
.modal{background:#fff;border-radius:var(--radius-lg);box-shadow:var(--shadow-lg);width:100%;max-width:520px;max-height:calc(100vh - 40px);overflow:hidden;display:flex;flex-direction:column;animation:pop .2s cubic-bezier(.16,1,.3,1)}
.modal.wide{max-width:720px}
.modal.narrow{max-width:410px}
@keyframes pop{from{opacity:0;transform:scale(.96) translateY(10px)}to{opacity:1;transform:none}}
.modal-head{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid var(--gray-100);position:sticky;top:0;background:#fff;z-index:2;border-radius:var(--radius-lg) var(--radius-lg) 0 0}
.modal-head h3{font-size:17px;font-weight:700}
.modal-close{width:34px;height:34px;border-radius:10px;display:flex;align-items:center;justify-content:center;color:var(--gray-400);font-size:20px}
@media (hover:hover){
  .modal-close:hover{background:var(--gray-100);color:var(--dark)}
}
.modal-body{padding:24px;overflow-y:auto;flex:1 1 auto;min-height:0}
/* 자체 스크롤 디자인 — 앱 전역 얇고 깔끔한 스크롤바 */
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:#CBD5E6;border-radius:10px;border:2px solid transparent;background-clip:content-box}
@media (hover:hover){
  ::-webkit-scrollbar-thumb:hover{background:#AEBBD0;border:2px solid transparent;background-clip:content-box}
}
::-webkit-scrollbar-track,::-webkit-scrollbar-corner{background:transparent}
.modal-body,.card-sc,.tip-panel{scrollbar-width:thin;scrollbar-color:#CBD5E6 transparent}
/* 가이드 투어 — 다음 버튼 강조(항상 은은히 깜빡, 잘못 클릭 시 흔들림) */
@keyframes tourPulse{0%{box-shadow:0 0 0 0 rgba(59,91,254,.55)}70%{box-shadow:0 0 0 9px rgba(59,91,254,0)}100%{box-shadow:0 0 0 0 rgba(59,91,254,0)}}
@keyframes tourNudge{0%,100%{transform:scale(1)}30%{transform:scale(1.14)}55%{transform:scale(.96)}80%{transform:scale(1.05)}}
#tourNextBtn{animation:tourPulse 1.25s infinite}
#tourNextBtn.nudge{animation:tourNudge .5s ease}
/* 사용법 안내 — 현재 눌린 메뉴 강조 + 클릭 커서 */
.nav-item.tour-hi-item{position:relative;z-index:1;box-shadow:0 0 0 3px rgba(59,130,246,.75);border-radius:12px;animation:tourClickPulse 1.1s infinite}
@keyframes tourClickPulse{0%{box-shadow:0 0 0 0 rgba(96,165,250,.8)}70%{box-shadow:0 0 0 11px rgba(96,165,250,0)}100%{box-shadow:0 0 0 0 rgba(96,165,250,0)}}
#tourCursor{animation:tourTap 1.05s infinite}
@keyframes tourTap{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
/* 온보딩 투어(실화면 스포트라이트) — 실제 화면 위에 기능 영역만 선명하게 남기고 나머지는 블러+어둡게 */
#rtourRoot{position:fixed;inset:0;z-index:100000;pointer-events:none;display:none}
#rtourRoot.on{display:block}
.rtour-panel{position:fixed;background:rgba(17,24,39,.06);backdrop-filter:blur(2.5px) saturate(108%);-webkit-backdrop-filter:blur(2.5px) saturate(108%);pointer-events:auto}
.rtour-ring{position:fixed;z-index:2;border:2.5px solid #3B5BFE;border-radius:16px;box-shadow:0 0 0 4px rgba(59,91,254,.20),0 14px 40px rgba(59,91,254,.34);pointer-events:none;opacity:0;transition:opacity .16s ease}
.rtour-badge{position:fixed;z-index:3;background:#3B5BFE;color:#fff;font:800 12.5px/1 Pretendard;letter-spacing:-.01em;padding:7px 12px;border-radius:9px;box-shadow:0 6px 16px rgba(59,91,254,.42);white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .16s ease}
.rtour-close{position:fixed;top:14px;right:16px;z-index:20;width:36px;height:36px;border-radius:50%;border:none;background:rgba(17,24,39,.52);color:#fff;font-size:20px;line-height:1;cursor:pointer;pointer-events:auto;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}
@media (hover:hover){
  .rtour-close:hover{background:rgba(17,24,39,.74)}
}
.rtour-tip{position:fixed;z-index:10;width:min(340px,calc(100vw - 28px));background:#fff;border-radius:16px;box-shadow:0 20px 54px rgba(16,24,54,.30);padding:15px 17px 14px;pointer-events:auto}
.rtour-tip-top{display:flex;align-items:center;gap:8px;margin-bottom:7px}
.rtour-tip-ic{font-size:20px;flex:none}
.rtour-tip-title{font:800 15px Pretendard;color:#161D34}
.rtour-tip-step{margin-left:auto;flex:none;font:800 12.5px Pretendard;color:#3B5BFE;background:#EEF3FF;border-radius:999px;padding:3px 9px}
.rtour-tip-desc{font:400 13px/1.62 Pretendard;color:#4A5568}
.rtour-tip-btns{display:flex;align-items:center;gap:7px;margin-top:14px}
@keyframes tutSpin{to{transform:rotate(360deg)}}
/* 첫 로딩 화면 */
#bootLoader{position:fixed;inset:0;z-index:2147483000;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:15px;background:#F7F9FD;transition:opacity .3s ease}
#bootLoader.hide{opacity:0;pointer-events:none}
#bootLoader .bl-logo{font:800 27px Pretendard;letter-spacing:-.02em;
  /* 사이드바 워드마크(.logo span)와 같은 브랜드 그라디언트 — 파란 단색이던 유일한 자리 */
  background:linear-gradient(120deg,#6439FF 0%,#050C9C 100%);
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:#6439FF}
#bootLoader .bl-txt{font:600 13px Pretendard;color:#646C82}
.boot-spin{width:38px;height:38px;border:4px solid #E3EAF7;border-top-color:#2F6BFF;border-radius:50%;animation:tutSpin .85s linear infinite}
.modal-foot{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--gray-100);background:var(--gray-50);border-radius:0 0 var(--radius-lg) var(--radius-lg);position:sticky;bottom:0}

/* 힌트 */
.hint{background:var(--primary-light);border-radius:12px;padding:13px 15px;font-size:12px;color:var(--primary-dark);margin-bottom:14px;line-height:1.6}
.hint-amber{background:var(--orange-light);color:#92400E}
.hint-purple{background:var(--purple-light);color:#6D28D9}

/* 페이지 전환 */
.page{display:none}
.page.active{display:block}

/* 위젯 리스트 항목 */
.list-item{display:flex;align-items:center;gap:12px;padding:11px 0;border-bottom:1px solid var(--gray-100);cursor:pointer}
.list-item:last-child{border-bottom:none}
@media (hover:hover){
  .list-item:hover{background:var(--gray-50);margin:0 -10px;padding:11px 10px;border-radius:11px}
}
.list-item.static{cursor:default}
@media (hover:hover){
  .list-item.static:hover{background:none;margin:0;padding:11px 0}
}
.sched-bar{width:4px;height:36px;border-radius:3px;flex-shrink:0}

/* 토글 */
.toggle{width:40px;height:22px;background:var(--gray-300);border-radius:11px;position:relative;cursor:pointer;transition:.18s;flex-shrink:0}
.toggle.on{background:var(--primary)}
.toggle::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;background:#fff;border-radius:50%;transition:.18s}
.toggle.on::after{left:20px}

/* 토스트 */
/* 토스트는 무엇보다 위에 있어야 한다 — z-index 260 은 모달(300) 아래라, 시트를 열어 놓고
   저장을 누르면 "체험판입니다" 안내가 그 시트 뒤에 깔려 아무 반응도 없는 것처럼 보였다. */
.toast{position:fixed;bottom:28px;left:50%;transform:translateX(-50%) translateY(20px);background:var(--dark);color:#fff;padding:13px 22px;border-radius:14px;font-size:13px;font-weight:500;box-shadow:var(--shadow-lg);z-index:500;opacity:0;transition:.25s;display:flex;align-items:center;gap:9px;pointer-events:none}   /* 보이든 안 보이든 클릭을 가로채지 않는다 */
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.toast .ic{color:var(--green-text);font-size:16px}
/* 체험판 안내 — 성공(초록 ✓)·실패(주황 !)와 성격이 달라 장식을 뺀다.
   테두리 없는 납작한 회색 알약 + 자물쇠 하나. 문구도 한 줄로 짧게. */
.toast.t-demo{background:#2C3244;box-shadow:0 10px 26px -12px rgba(20,26,45,.55);border-radius:12px;font-weight:600}
.toast.t-demo .ic{color:rgba(255,255,255,.55);font-size:14px}

/* 우하단 소형 안내 팝업 — 운영 알림(반 미배정 등). 모바일에서는 표시하지 않는다(요청). */
.minipop{position:fixed;right:20px;bottom:20px;width:290px;max-width:calc(100vw - 40px);background:#fff;
  border:1px solid var(--gray-200);border-radius:12px;box-shadow:0 8px 24px rgba(30,34,51,.12);
  padding:14px 16px;z-index:190;opacity:0;transform:translateY(14px);transition:opacity .2s,transform .2s}
.minipop.show{opacity:1;transform:translateY(0)}
.minipop .mp-x{border:none;background:none;color:var(--gray-400);cursor:pointer;font-size:13px;line-height:1;padding:2px;flex:none}
@media (hover:hover){
  .minipop .mp-x:hover{color:var(--gray-600)}
}
.minipop .mp-snz{display:flex;align-items:center;gap:5px;font-size:12.5px;color:var(--gray-400);cursor:pointer;user-select:none}
@media (hover:hover){
  .minipop .mp-snz:hover{color:var(--gray-600)}
}
.minipop .mp-snz input{width:13px;height:13px;accent-color:var(--primary)}
@media(max-width:860px){.minipop{display:none}}

/* 칩 */
.chip{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:20px;font-size:12px;font-weight:600;background:var(--gray-100);color:var(--gray-600);cursor:pointer;border:1px solid transparent;transition:.12s}
@media (hover:hover){
  .chip:hover{background:var(--gray-200)}
}
.subj-btn{padding:5px 13px;border-radius:99px;border:1px solid var(--gray-200);background:transparent;font-size:12px;font-family:inherit;cursor:pointer;color:var(--gray-500);transition:all .12s;font-weight:600}
@media (hover:hover){
  .subj-btn:hover{border-color:var(--gray-300)}
}
.chip.active{background:var(--primary-light);color:var(--primary-dark);border-color:var(--primary)}
/* 결과가 0건인 필터 칩 — 예전에는 눌러도 목록이 빈 채로 남는 칩이 다른 칩과 색·커서까지
   똑같아서 '필터가 고장났다'로 읽혔다. 0건은 눌리지 않게 하고 색으로도 구분한다.
   opacity 로 흐리게 하면 글자 대비가 4.5:1 아래로 떨어지므로 색을 직접 지정한다. */
.chip:disabled{background:var(--gray-50);color:var(--gray-500);border-color:var(--gray-200);cursor:default}
@media (hover:hover){
  .chip:disabled:hover{background:var(--gray-50)}
}
/* 칩 안 건수 — opacity:.6 으로 흐리게 하던 시절엔 회색 칩 위 대비가 2.8:1 밖에 안 됐다 */
.chip .cnt{font-weight:800;margin-left:1px;font-variant-numeric:tabular-nums}
.ai-rec{font-size:12px;font-weight:800;background:var(--primary-dark);color:#fff;padding:1px 6px;border-radius:9px;margin-left:5px;letter-spacing:.3px}
/* 카드형 리포트 — 모노톤 미니멀(A) */
.rcm-stat3{display:flex;border-top:1px solid var(--gray-100);border-bottom:1px solid var(--gray-100);margin-bottom:2px}
.rcm-stat3 .c{flex:1;text-align:center;padding:13px 4px;border-right:1px solid var(--gray-100)}
.rcm-stat3 .c:last-child{border-right:none}
.rcm-stat3 .n{font-size:18px;font-weight:800}
.rcm-stat3 .l{font-size:12px;color:var(--gray-500);margin-top:3px}
.rcm-sec{padding:13px 0;border-bottom:1px solid var(--gray-100)}
.rcm-sec:last-child{border-bottom:none}
.rcm-sl{font-size:12.5px;font-weight:700;color:var(--gray-400);letter-spacing:.3px;margin-bottom:10px}
.rcm-srow{display:flex;align-items:center;gap:10px;margin-bottom:9px;font-size:12.5px}
.rcm-srow .nm{width:34px;color:var(--gray-700);font-weight:600}
.rcm-srow .sc{width:66px;text-align:right;font-weight:700}
.rcm-obs{font-size:12.5px;line-height:1.9;color:var(--gray-700)}
.rcm-diag{font-size:12px;color:var(--gray-600);line-height:1.75}
.rcm-cmt{font-size:12px;line-height:1.7;color:var(--gray-700);background:var(--primary-light);border-radius:11px;padding:12px 14px;position:relative}
.rcm-cmt .edit{position:absolute;top:10px;right:12px;font-size:12.5px;color:var(--primary-dark);font-weight:700;cursor:pointer}
.rcm-home{font-size:12.5px;color:var(--gray-500);line-height:1.7}
.report-editing{outline:2px dashed var(--primary);outline-offset:7px;border-radius:14px}
.report-editing:focus{outline:2px dashed var(--primary-dark)}
.edit-banner{background:var(--primary-light);color:var(--primary-dark);font-size:12px;font-weight:600;padding:9px 13px;border-radius:10px;margin-bottom:11px}
.chip .x{color:var(--gray-400);font-size:13px;margin-left:1px}
@media (hover:hover){
  .chip .x:hover{color:var(--red-text)}
}
/* 긴 값이 들어와도 칩이 부모 폭을 넘지 않게 한다.
   body 에 word-break:keep-all 이 걸려 있어 한글 태그는 한 단어로 취급되고, flex 항목이
   줄어들지 않아 칩이 모달 밖으로 삐져나갔다 — 그러면 오른쪽 끝의 × 가 화면 밖에 있어
   **지울 방법이 없어진다**(길게 저장된 태그가 영구히 남는다). 텍스트만 말줄임하고 × 는 지킨다.
   전체 이름은 title 속성으로 볼 수 있다. */
.chip{max-width:100%;min-width:0}
.chip>.ctxt{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chip .x{flex:0 0 auto}
.badge{max-width:100%;overflow:hidden;text-overflow:ellipsis}
.checkbox{display:flex;align-items:center;gap:8px;font-size:13px;cursor:pointer;padding:6px 0}
.checkbox input{width:16px;height:16px;accent-color:var(--primary)}

/* 미니 차트 바 */
.barchart{display:flex;align-items:flex-end;gap:10px;height:120px;padding-top:10px}
.barchart .bar-wrap{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;height:100%;justify-content:flex-end}
.barchart .bar{width:100%;max-width:40px;background:var(--gray-200);border-radius:4px 4px 0 0;transition:.2s}
.barchart .bar.hl{background:var(--primary)}
.barchart .bar-label{font-size:12.5px;color:var(--gray-400)}

/* 라인 차트 (성적 추이) */
.linechart{position:relative;height:200px;margin:10px 0}

.section-label{font-size:12.5px;font-weight:700;color:var(--gray-400);letter-spacing:.5px;margin:22px 0 10px}
.muted{color:var(--gray-400)}
.flex{display:flex;align-items:center;gap:8px}
/* 표 셀에 .flex를 쓰면 열 정렬이 깨짐 → 셀은 table-cell 유지하고 내용만 우측 정렬(버튼은 inline) */
td.flex{display:table-cell;white-space:nowrap;text-align:right}
td.flex>.btn{vertical-align:middle}
/* td.flex 는 위에서 display:table-cell 로 되돌려지므로 gap 이 먹지 않는다.
   표 안 '수정 / 삭제' 같은 액션 버튼은 margin 으로 간격을 준다. */
td.flex>.btn+.btn,td>.btn+.btn{margin-left:10px}
.flex-between{display:flex;align-items:center;justify-content:space-between}
.flex-wrap{flex-wrap:wrap}
.mt8{margin-top:8px}.mt12{margin-top:12px}.mt16{margin-top:16px}.mt20{margin-top:20px}
/* mb 쪽에 10·20 이 빠져 있었다 — 마크업은 쓰는데 규칙이 없으니 그 간격이 통째로 0 이 됐다.
   브랜딩 지표 그리드(.grid.mb20)가 그 한 곳이고, 아래 안내 문구가 margin-top:-8px 로
   '20px 을 상쇄한다'는 전제로 쓰여 있어서 결과가 -8px → 문구가 카드 위로 8px 파고들었다.
   mt 는 8·12·16·20 이 다 있는데 mb 만 8·12·16 이었던 것이 원인이다(짝을 맞춘다). */
.mb8{margin-bottom:8px}.mb10{margin-bottom:10px}.mb12{margin-bottom:12px}
.mb16{margin-bottom:16px}.mb20{margin-bottom:20px}

/* 달력 */
.calendar{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:1px;background:var(--border);border:1px solid var(--border);border-radius:14px;overflow:hidden}
.cal-head{background:var(--gray-50);text-align:center;padding:9px 0;font-size:12.5px;font-weight:700;color:var(--gray-500)}
.cal-cell{background:#fff;min-height:84px;min-width:0;padding:6px 7px;font-size:12px;cursor:pointer;transition:.1s}
@media (hover:hover){
  .cal-cell:hover{background:var(--gray-50)}
}
.cal-cell.other{background:var(--gray-50);color:var(--gray-400)}
.cal-cell .day{font-weight:600;margin-bottom:4px}
.cal-cell.cal-sel{background:var(--primary-light,#EEF2FF);box-shadow:inset 0 0 0 2px var(--primary)}
.cal-cell.today .day{background:var(--primary-dark);color:#fff;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center}
.cal-event{font-size:12px;padding:2px 5px;border-radius:4px;margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* 시간표 그리드 */
.timetable{display:grid;grid-template-columns:56px repeat(7,1fr);border:1px solid var(--border);border-radius:14px;overflow:hidden;font-size:12.5px}
.tt-cell{border-right:1px solid var(--gray-100);border-bottom:1px solid var(--gray-100);padding:6px;min-height:46px;position:relative}
.tt-head{background:var(--gray-50);font-weight:700;color:var(--gray-500);text-align:center;padding:9px 0;font-size:12.5px}
.tt-time{background:var(--gray-50);color:var(--gray-400);text-align:center;font-size:12px;display:flex;align-items:center;justify-content:center}
.tt-block{border-radius:5px;padding:5px 6px;font-size:12px;font-weight:600;line-height:1.3;cursor:pointer}
/* 수업이 이미 있는 칸에도 보강·수업을 더 넣을 수 있게 하는 추가 버튼(빈 칸 클릭과 같은 동작).
   평소엔 흐리게 두고 칸에 커서를 올리거나 터치 화면에선 항상 보이게 한다. */
.tt-add{margin-top:4px;border:1px dashed var(--gray-300);background:transparent;color:var(--gray-400);
  border-radius:5px;padding:3px 0;font-size:12px;font-weight:700;cursor:pointer;opacity:.75;transition:.12s}
@media (hover:hover){
  .tt-cell:hover .tt-add{opacity:1;border-color:var(--primary);color:var(--primary-dark)}
  .tt-add:hover{background:var(--primary-light)}
}
.tt-block+.tt-block{margin-top:4px}
.tt-cell{display:flex;flex-direction:column}

/* 강의실 배정 매트릭스 */
.room-grid{display:grid;gap:8px;min-width:520px}
.rg-head{background:var(--gray-50);font-weight:700;color:var(--gray-500);text-align:center;padding:9px 0;font-size:12px;border-radius:8px}
.rg-room{display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13px;background:var(--gray-50);border-radius:8px}
.rg-cell{min-height:64px;border:1px dashed var(--gray-200);border-radius:8px;padding:6px;display:flex;flex-direction:column;gap:5px;justify-content:center}
.rg-block{border-radius:7px;padding:7px 9px;font-size:12.5px;line-height:1.35;cursor:pointer}
.rg-add{border:none;background:transparent;color:var(--gray-400);font-size:12.5px;cursor:pointer;padding:6px;font-weight:600}
@media (hover:hover){
  .rg-add:hover{color:var(--primary-dark)}
}

/* 주간 일정 그리드 */
.weekgrid{display:grid;gap:6px}
.wg-head{background:var(--gray-50);font-weight:700;color:var(--gray-500);text-align:center;padding:8px 0;font-size:12.5px;border-radius:6px}
.wg-time{display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--gray-400);background:var(--gray-50);border-radius:6px}
.wg-cell{min-height:46px;border:1px dashed var(--gray-200);border-radius:6px;padding:4px}
.wg-block{border-radius:6px;padding:6px 7px;font-size:12.5px;font-weight:600;cursor:pointer;height:100%;display:flex;align-items:center}

/* 상담 TIP 패널 (출력·공유 제외) */
.tip-panel{background:#fff;border:1px solid var(--primary);border-radius:var(--radius);box-shadow:var(--shadow);position:sticky;top:74px;overflow:hidden}
.tip-head{background:var(--primary-light);padding:12px 16px;border-bottom:1px dashed var(--primary)}
.tip-panel.cs-panel{max-height:calc(100vh - 92px);display:flex;flex-direction:column}
.cs-panel .tip-head{flex-shrink:0}
.cs-body{overflow-y:auto}
.cs-intro{font-size:12.5px;color:var(--gray-500);line-height:1.6;margin-bottom:10px}
.cs-lab{font-size:12px;font-weight:800;color:var(--primary-dark);letter-spacing:.3px;margin:13px 0 6px}
.cs-line{font-size:12.5px;line-height:1.72;color:var(--gray-700);background:var(--gray-50);border-left:3px solid var(--primary);border-radius:0 8px 8px 0;padding:8px 11px}
.cs-note{font-size:12.5px;color:var(--gray-500);line-height:1.55;margin-top:5px}

/* 맞춤 지도 가이드 (진단형 · 컨설팅 리포트형 A) */
.plan-block{border:1px solid var(--border);border-radius:12px;padding:12px 14px;margin-bottom:10px}
.plan-h{font-size:13px;font-weight:700;display:flex;align-items:center;gap:8px;margin-bottom:7px}
.plan-n{width:20px;height:20px;border-radius:7px;background:var(--primary-dark);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex-shrink:0}
.plan-ul{margin:0;padding-left:18px;font-size:12.5px;line-height:1.8;color:var(--gray-700)}
.gd-ctx{font-size:12px;color:var(--gray-600);line-height:1.6;background:var(--gray-50);border-radius:10px;padding:10px 13px;margin-bottom:6px}
.gd-ctx b{color:var(--gray-700)}
.gd-fc{border-top:2px solid var(--gray-100);padding:14px 0}
.gd-fc:first-of-type{padding-top:6px}
.gd-ft{display:flex;align-items:center;gap:9px;margin-bottom:9px}
.gd-num{font-size:12px;font-weight:800;color:#1E3A5F}
.gd-nm{font-size:14px;font-weight:800}
.gd-ft .gst{margin-left:auto}
.gd-dl{display:grid;grid-template-columns:48px 1fr;gap:0 12px;font-size:12.5px}
.gd-dt{font-size:12px;font-weight:800;color:var(--gray-400);letter-spacing:.5px;padding:8px 0}
.gd-dd{color:var(--gray-700);line-height:1.65;padding:8px 0;border-bottom:1px solid var(--gray-50)}
.gd-dl > .gd-dd:last-child{border-bottom:none}
.gd-dd b{color:var(--dark)}
.gst{font-size:12px;font-weight:800;padding:3px 9px;border-radius:20px;white-space:nowrap;letter-spacing:.2px}
.gst.up{background:var(--green-light);color:#047857}
.gst.keep{background:var(--gray-100);color:var(--gray-600)}
.gst.lag{background:var(--orange-light);color:#B45309}
.gst.down{background:var(--red-light);color:#BE123C}
.gd-foot{font-size:12.5px;color:var(--gray-500);background:var(--gray-50);border-radius:10px;padding:10px 13px;line-height:1.6;margin-top:8px}
.gd-foot b{color:var(--gray-700)}

/* AI 진행 중 오버레이 — 화면 흐림 + 진행 표시 */
#aiOverlay{position:fixed;inset:0;z-index:99990;display:none;align-items:center;justify-content:center;background:rgba(248,250,252,.5);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);animation:aiOvFade .18s ease}
#aiOverlay.show{display:flex}
@keyframes aiOvFade{from{opacity:0}to{opacity:1}}
.ai-ov-card{background:#fff;border-radius:18px;padding:28px 32px;box-shadow:0 14px 44px rgba(30,58,95,.18);text-align:center;max-width:320px;margin:0 20px}
.ai-ov-badge{position:relative;width:58px;height:58px;margin:0 auto 16px}
.ai-ov-ic{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--primary-dark);font-size:24px}
.ai-ov-ic .micon{width:24px;height:24px}
.ai-ov-spin{position:absolute;inset:0;border:3px solid var(--primary-light,#E9E3FB);border-top-color:var(--primary);border-radius:50%;animation:aiSpin .8s linear infinite}
@keyframes aiSpin{to{transform:rotate(360deg)}}
.ai-ov-msg{font-size:15px;font-weight:800;color:var(--dark)}
.ai-ov-sub{font-size:12px;color:var(--gray-500);margin-top:7px;line-height:1.5}
/* 진행 막대·중단 — 예전엔 스피너와 초 세기만 있어 '얼마나 남았는지'가 글로만 있었고,
   최대 3분을 기다리는 동안 빠져나올 방법이 없었다(#45). */
.ai-ov-bar{height:5px;border-radius:999px;background:var(--gray-100);margin-top:12px;overflow:hidden}
.ai-ov-bar>i{display:block;height:100%;width:0;background:var(--primary-dark);border-radius:999px;transition:width .4s linear}
.ai-ov-cancel{margin-top:14px;background:none;border:1px solid var(--gray-200);border-radius:var(--r-ctl);padding:7px 14px;font-size:12.5px;font-weight:600;color:var(--gray-600);cursor:pointer}
@media (hover:hover){
  .ai-ov-cancel:hover{background:var(--gray-50);color:var(--dark)}
}
.ai-ov-note{font-size:12px;color:var(--gray-500);margin-top:8px;line-height:1.5}

/* 알림톡 미리보기 (카카오 스타일) */
.kakao-wrap{background:#9BBBD4;padding:14px;border-radius:14px}
.kakao-card{background:#fff;border-radius:12px;overflow:hidden;max-width:280px;box-shadow:0 1px 3px rgba(0,0,0,.12)}
.kakao-head{background:#FAE100;color:#3A1D1D;font-weight:800;font-size:12px;padding:8px 13px;display:flex;align-items:center;gap:5px}
.kakao-body{padding:13px 15px;font-size:12.5px;line-height:1.75;color:#222}
.kakao-title{font-weight:700;margin-bottom:7px;font-size:13.5px}
.kakao-foot{border-top:1px solid #EEE;padding:9px 15px;font-size:12.5px;color:#888}
.rcp{display:flex;align-items:center;gap:8px;padding:9px 11px;border:1px solid var(--border);border-radius:10px;margin-bottom:7px;font-size:13px;cursor:pointer}
.rcp.on{border-color:var(--primary);background:var(--primary-light)}

/* 과제 드릴다운 */
.asg-cls{transition:transform .12s, box-shadow .12s}
@media (hover:hover){
  .asg-cls:hover{transform:translateY(-2px);box-shadow:var(--shadow-lg)}
}
.subj-group{margin-bottom:22px}
.subj-head{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:800;color:var(--gray-700);margin:0 2px 11px}
.subj-dot{width:9px;height:9px;border-radius:50%;display:inline-block}
.wk-row{display:flex;align-items:center;gap:8px;padding:13px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .12s}
.wk-row:last-child{border-bottom:none}
@media (hover:hover){
  .wk-row:hover{background:var(--gray-50)}
}
.wk-now{background:var(--primary-light)}
@media (hover:hover){
  .wk-now:hover{background:#E5E9FE}
}
.rate-row{display:flex;align-items:center;gap:10px;padding:9px 2px;border-bottom:1px solid var(--gray-100)}
.rate-row:last-child{border-bottom:none}
/* 브랜드 리포트 */
.metric-card{position:relative;border:1.5px solid var(--border);border-radius:14px;padding:14px 15px;cursor:pointer;transition:.12s;background:#fff;
  /* 카드와 '+ 지표 추가' 버튼이 같은 최소 높이를 갖게 한다.
     예전엔 버튼에만 min-height:118px 가 있어, 그 버튼과 같은 행에 놓인 카드가 118px 행에
     들어갔다 — 카드 내용은 137px 이라 '클릭해 수정 · 수동 · ×' 줄이 둥근 테두리 밖으로
     삐져나와 아래 안내 문구와 겹쳤다(행이 카드 내용보다 낮게 잡힌 것이 원인이다).
     min-height 는 바닥만 올리므로 이름이 길어 두 줄이 되는 카드는 그대로 더 커진다. */
  min-height:138px;display:flex;flex-direction:column}
.metric-card.on{border-color:var(--primary);background:var(--primary-light)}
@media (hover:hover){
  .metric-card:hover{box-shadow:var(--shadow)}
}
.metric-ico{width:34px;height:34px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:17px;background:var(--gray-50)}
.metric-card.on .metric-ico{background:#fff}

/* 세로형 시간표 */
.vsched{display:flex;flex-direction:column}
.vsched-row{display:flex;align-items:stretch;gap:12px;padding:11px 6px;border-bottom:1px solid var(--gray-100);cursor:pointer;transition:.12s}
.vsched-row:last-child{border-bottom:none}
@media (hover:hover){
  .vsched-row:hover{background:var(--gray-50)}
}
.vsched-time{width:52px;text-align:right;flex-shrink:0}
.vsched-bar{width:4px;border-radius:4px;flex-shrink:0}
.vsched-body{flex:1}
/* 홈 시간표 — 캘린더형(A안) */
.tlc{display:grid;position:relative}
.tlc-block{border-radius:9px;padding:6px 10px;border-left:3px solid var(--bc,var(--primary));background:var(--bt,var(--primary-light));margin:2px;cursor:pointer;overflow:hidden;display:flex;flex-direction:column;justify-content:center;transition:.12s;z-index:1}
@media (hover:hover){
  .tlc-block:hover{filter:brightness(.97)}
}
.tlc-block b{font-size:12.5px;font-weight:700;color:var(--dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tlc-block span{font-size:12.5px;color:var(--gray-500);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tlc-line{border-top:1px solid var(--gray-100)}
.tlc-time{font-size:12.5px;color:var(--gray-400);font-weight:700;padding-top:3px}

/* 반별 출결 카드 */
.att-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px}
.att-card{background:#fff;border:1px solid var(--gray-200);border-radius:12px;padding:15px;box-shadow:var(--shadow);cursor:pointer;transition:.15s}
@media (hover:hover){
  .att-card:hover{box-shadow:var(--shadow-lg);transform:translateY(-2px)}
}
.att-pill{display:inline-flex;align-items:center;gap:4px;font-size:12.5px;font-weight:700;padding:3px 8px;border-radius:20px}

/* 심각도 배지 */
.sev{font-size:12px;font-weight:700;padding:3px 8px;border-radius:20px;white-space:nowrap}
.sev-1{background:var(--red-light);color:#B91C1C}
.sev-2{background:var(--orange-light);color:#B45309}
.sev-3{background:#FEF9C3;color:#854D0E}

/* AI 리포트 카드 */
.report-card{background:#fff;border:1px solid var(--border);border-radius:20px;overflow:hidden;box-shadow:0 8px 30px rgba(59,130,246,.13);color:var(--dark)}
.rc-head{padding:18px 20px 16px;background:linear-gradient(135deg,#EAF1FE 0%,#EEF2FF 60%,#F5F8FF 100%);border-bottom:1px solid #D6E2FB}
.rc-avatar{width:44px;height:44px;border-radius:13px;background:#2563EB linear-gradient(145deg,#1D4ED8,#2563EB);color:#fff;display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:700;box-shadow:0 4px 12px rgba(59,130,246,.3)}
.rc-body{background:#fff;color:var(--dark);margin:0;border-radius:0;padding:14px 20px 16px}
.rc-section{padding:12px 0;border-bottom:1px solid var(--gray-100)}
.rc-section:last-child{border-bottom:none}
.rc-title{font-size:13px;font-weight:700;margin-bottom:10px}
.rc-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:7px}
.rc-stat{background:linear-gradient(155deg,#1D4ED8,#2563EB);border-radius:13px;padding:11px 6px 10px;text-align:center;box-shadow:0 4px 12px rgba(59,130,246,.18)}
.rc-stat .rc-ico{font-size:13px;opacity:.9;line-height:1}
.rc-num{font-size:19px;font-weight:800;line-height:1.15;margin-top:3px}
.rc-lbl{font-size:12px;color:rgba(255,255,255,.92);margin-top:2px}
.rc-line{font-size:12.5px;line-height:1.6;color:var(--gray-700);padding:3px 0 3px 4px;display:flex;gap:7px}
.rc-no{flex-shrink:0;width:17px;height:17px;border-radius:50%;background:var(--primary-light);color:var(--primary-dark);font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center;margin-top:1px}
.rc-comment{background:var(--primary-light);margin:8px -20px -4px;padding:14px 20px}
.rc-subdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:6px;vertical-align:middle}
.rc-diag{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.diag-item{display:flex;align-items:center;gap:10px;background:var(--gray-50);border:1px solid var(--gray-100);border-radius:12px;padding:9px 12px}
.diag-ico{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:15px;flex-shrink:0}
.diag-lbl{font-size:12px;color:var(--gray-500)}
.diag-val{font-size:14px;font-weight:800;margin-top:1px}
@media(max-width:980px){.report-layout{grid-template-columns:1fr !important}}
.rc-sum{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;align-items:stretch}
.rc-sumtile{background:var(--gray-50);border:1px solid var(--gray-100);border-radius:14px;padding:12px 8px;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center}
.rc-ringlbl{font-size:12.5px;color:var(--gray-500);margin-top:7px;font-weight:600}
.rc-bignum{font-size:25px;font-weight:800;line-height:1}
.rc-bignlbl{font-size:12.5px;color:var(--gray-500);margin-top:5px;font-weight:600}

/* 보고서 형식 */
.report-doc{background:#fff;border:1px solid var(--gray-200);border-radius:8px;max-width:100%;margin:0 auto;box-shadow:var(--shadow);overflow:hidden}
.rd-header{border-bottom:3px double var(--gray-700);padding:26px 34px 18px;text-align:center}
.rd-title{font-size:21px;font-weight:800;letter-spacing:4px;color:var(--dark)}
.rd-sub{font-size:12.5px;color:var(--gray-400);letter-spacing:2px;margin-top:6px}
.rd-meta{padding:14px 34px;background:var(--gray-50);border-bottom:1px solid var(--gray-200);font-size:12px;color:var(--gray-600);display:grid;grid-template-columns:1fr 1fr;gap:5px 20px}
.rd-meta b{color:var(--dark);font-weight:600}
.rd-content{padding:24px 34px 30px}
.rd-section{margin-bottom:24px}
.rd-h2{font-size:14px;font-weight:700;color:var(--dark);padding-bottom:7px;border-bottom:2px solid var(--dark);margin-bottom:12px;display:flex;align-items:center;gap:8px}
.rd-h2 .nn{color:var(--primary-dark)}
.rd-p{font-size:12.5px;line-height:1.85;color:var(--gray-700);margin:6px 0}
.rd-table{width:100%;border-collapse:collapse;font-size:12px;margin:8px 0}
.rd-table th{background:var(--gray-100);border:1px solid var(--gray-300);padding:8px 10px;text-align:center;font-weight:700;color:var(--gray-700)}
.rd-table td{border:1px solid var(--gray-300);padding:8px 10px;text-align:center;color:var(--gray-700)}
.rd-table td.lead{text-align:left;font-weight:600;background:var(--gray-50)}
.rd-footer{border-top:1px solid var(--gray-200);padding:14px 34px;text-align:center;font-size:12px;color:var(--gray-400);letter-spacing:1px}
.rd-tag{font-size:12px;font-weight:700;padding:3px 9px;border-radius:20px;margin-left:auto}
.rd-tag.success{background:var(--green-light);color:#047857}
.rd-tag.warning{background:var(--orange-light);color:#B45309}
.rd-tag.danger{background:var(--red-light);color:#BE123C}
.rd-ai{font-size:12px;line-height:1.8;color:var(--gray-700);background:var(--primary-light);border-left:3px solid var(--primary);border-radius:0 8px 8px 0;padding:9px 13px;margin:8px 0 2px}
.rd-ai b{color:var(--dark)}
.rd-pos{color:#047857;font-weight:600}
.audio-spin{width:44px;height:44px;border:4px solid var(--gray-200);border-top-color:var(--primary);border-radius:50%;margin:0 auto;animation:aspin .9s linear infinite}
@keyframes aspin{to{transform:rotate(360deg)}}
.fmt-toggle{display:inline-flex;background:var(--gray-100);border-radius:9px;padding:3px}
.fmt-toggle button{padding:7px 16px;border-radius:7px;font-size:12px;font-weight:600;color:var(--gray-500);transition:.12s}
.fmt-toggle button.active{background:#fff;color:var(--primary-dark);box-shadow:var(--shadow)}
.role-toggle{display:inline-flex;background:var(--gray-100);border-radius:9px;padding:3px;gap:2px}
.role-toggle button{padding:6px 14px;border-radius:7px;font-size:12px;font-weight:700;color:var(--gray-500);transition:.12s}
.role-toggle button.active{background:#fff;color:var(--primary-dark);box-shadow:var(--shadow)}

/* 학생 상세 헤더 */
.detail-head{display:flex;align-items:center;gap:16px;background:#fff;border:1px solid var(--gray-200);border-radius:var(--radius);padding:20px;box-shadow:var(--shadow);margin-bottom:16px}
.detail-head .big-avatar{width:60px;height:60px;border-radius:16px;font-size:24px}
/* 사진 변경 — 아바타에 마우스를 올리면 카메라 배지가 뜨고, 클릭하면 파일 선택 */
.ava-edit{position:relative;flex:none;cursor:pointer;line-height:0}
.ava-edit .ava-cam{position:absolute;right:-3px;bottom:-3px;width:24px;height:24px;border-radius:50%;background:#fff;border:1px solid var(--gray-200);box-shadow:0 2px 6px rgba(0,0,0,.16);display:flex;align-items:center;justify-content:center;color:var(--gray-600);font-size:12px}
@media (hover:hover){
  .ava-edit:hover .ava-cam{background:var(--primary);border-color:var(--primary);color:#fff}
  .ava-edit:hover .avatar{filter:brightness(.94)}
}

/* 클릭 가능 카드 */
.clickable{cursor:pointer;transition:.12s}
@media (hover:hover){
  .card.clickable:hover{transform:translateY(-2px);box-shadow:0 6px 18px rgba(0,0,0,.08)}
}

/* 강조 행 (이상 징후 등) */
tr.flag td{background:var(--red-light)!important}
@media (hover:hover){
  tr.flag:hover td{background:#FECDD3!important}
}

/* 드롭존 */
.dropzone{border:2px dashed var(--gray-300);border-radius:10px;padding:32px;text-align:center;cursor:pointer;transition:.12s}
@media (hover:hover){
  .dropzone:hover{border-color:var(--primary);background:var(--primary-light)}
}
/* 성적표 업로드 모달 */
.uploadgrid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin:2px 0 4px}
.up-box{border:2px dashed var(--gray-300);border-radius:13px;padding:18px 14px;text-align:center;cursor:pointer;transition:.14s;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:156px;background:var(--gray-50)}
@media (hover:hover){
  .up-box:hover{border-color:var(--primary);background:var(--primary-light)}
}
.up-ico{width:44px;height:44px;border-radius:12px;background:#fff;border:1px solid var(--gray-200);display:flex;align-items:center;justify-content:center;font-size:21px;margin-bottom:11px}
.up-fname{font-size:13px;font-weight:700;color:var(--dark)}
.up-sub{font-size:12.5px;color:var(--gray-500);margin-top:3px;letter-spacing:.3px}
.up-btn{margin-top:12px;font-size:12px;font-weight:700;color:var(--primary-dark);background:#fff;border:1px solid var(--primary);border-radius:8px;padding:6px 15px}
/* 네이티브 '파일 선택' 버튼 → 커스텀 버튼(모든 file input 공통) */
input[type=file]{font-size:12.5px;color:var(--gray-500);max-width:100%}
input[type=file]::file-selector-button{margin-right:12px;padding:8px 15px;border-radius:9px;border:0;cursor:pointer;font-family:Pretendard,sans-serif;font-weight:700;font-size:12.5px;color:#fff;background:var(--primary);transition:.14s}
@media (hover:hover){
  input[type=file]::file-selector-button:hover{background:var(--primary-dark)}
}
input[type=file]::-webkit-file-upload-button{margin-right:12px;padding:8px 15px;border-radius:9px;border:0;cursor:pointer;font-family:Pretendard,sans-serif;font-weight:700;font-size:12.5px;color:#fff;background:var(--primary)}
input.input[type=file]{padding:8px 10px;line-height:1.9}
.up-prev{position:relative;border:1px solid var(--gray-200);border-radius:13px;background:var(--gray-50);display:flex;align-items:center;justify-content:center;min-height:156px;color:var(--gray-400);font-size:12px;overflow:hidden}
.up-badge{position:absolute;top:9px;right:9px;font-size:12px;font-weight:800;background:var(--green);color:#fff;padding:3px 9px;border-radius:20px}
.ai-divider{display:flex;align-items:center;gap:9px;font-size:12.5px;font-weight:700;color:var(--primary-dark);margin:15px 0 11px}
.ai-divider::before,.ai-divider::after{content:"";flex:1;height:1px;background:var(--gray-200)}
.score-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.score-cell label{display:block;font-size:12.5px;font-weight:700;color:var(--gray-600);margin-bottom:6px;text-align:center}
.score-cell input{text-align:center;font-weight:700;font-size:15px;padding:9px 6px}

/* 코멘트박스 */
.callout{background:var(--gray-50);border-left:3px solid var(--primary);padding:12px 14px;font-size:12.5px;line-height:1.7;color:var(--gray-700);border-radius:0 8px 8px 0;margin:8px 0}
.script-line{padding:9px 12px;border-radius:8px;font-size:12.5px;line-height:1.6;margin-bottom:8px}
.script-q{background:var(--sky-light);color:#075985}
.script-a{background:var(--green-light);color:#065F46}

/* ===== 관리자 콘솔 전용 테마 (auto: admin-console-design) ===== */
/* ============================================================
   PLATFORM SUPER-ADMIN CONSOLE — "aurora-indigo" (synthesis)
   Scope: every rule is gated behind .app.admin (shell) or uses
   standalone .adm-* classes, so the blue academy theme is
   completely untouched. Reuses existing CSS variables; violet
   is the single accent on graphite/indigo.
   ============================================================ */

/* ---- admin design tokens (local to the admin scope) ---- */
.app.admin{
  --adm-ink:#1E2233;
  --adm-navy:#312E81;
  --adm-violet:#8B5CF6;
  --adm-violet-soft:#A78BFA;
  --adm-acc-soft:#EDE9FE;
  --adm-grad:linear-gradient(135deg,#6D28D9,#4F46E5);
  --adm-line:#ECEEF5;
  --adm-line-strong:#E0E3EE;
  --adm-num:ui-monospace,"SF Mono","Roboto Mono",Menlo,Consolas,monospace;
}

/* ================= SIDEBAR (dark navy slab + aurora glow) ================= */
.app.admin .sidebar{
  background:
    radial-gradient(120% 80% at 50% -10%, rgba(139,92,246,.30) 0%, rgba(139,92,246,0) 55%),
    linear-gradient(180deg,#262348 0%, #1E1B3A 38%, #161430 100%);
  border-right:1px solid rgba(255,255,255,.06);
  box-shadow:1px 0 0 rgba(0,0,0,.25), 18px 0 48px -36px rgba(20,16,48,.9);
}
.app.admin .sidebar-head{ border-bottom:1px solid rgba(255,255,255,.07); }
/* logo: gradient dot + light wordmark + operator sub-label */
.app.admin .logo{ color:#fff; letter-spacing:-.3px; }
.app.admin .logo .dot{
  background:linear-gradient(135deg,#6D28D9,#4F46E5);
  color:#fff;
  box-shadow:0 6px 18px rgba(99,102,241,.55), inset 0 0 0 1px rgba(255,255,255,.18);
}
.app.admin .adm-brand{display:inline-flex;flex-direction:column;line-height:1.15}
.app.admin .adm-brand .adm-brand-sub{
  font-size:12px;font-weight:800;letter-spacing:.14em;
  color:var(--adm-violet-soft);text-transform:uppercase;margin-top:2px;
}
/* the academy-switch box is an operator badge in admin (no academy to switch) */
.app.admin .academy-switch{
  background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);
  border-radius:12px;cursor:default;
}
.app.admin .academy-switch .arrow{display:none}
.app.admin .academy-switch .name{color:#fff;font-weight:700}
.app.admin .academy-switch .sub{color:var(--adm-violet-soft);font-weight:600}

/* nav section headers + items, light-on-dark */
.app.admin .nav-section{ color:rgba(255,255,255,.42); }
@media (hover:hover){
  .app.admin .nav-section:hover{ color:rgba(255,255,255,.7); background:rgba(255,255,255,.05); }
}
.app.admin .nav-item{ color:rgba(232,233,245,.72); }
@media (hover:hover){
  .app.admin .nav-item:hover{ background:rgba(255,255,255,.06); color:#fff; }
}
.app.admin .nav-item .ico{ opacity:.7; }
.app.admin .nav-item.active{
  background:linear-gradient(135deg,#6D28D9,#4F46E5);
  color:#fff;font-weight:600;position:relative;
  box-shadow:0 10px 24px -6px rgba(124,58,237,.7), inset 0 0 0 1px rgba(255,255,255,.12);
}
.app.admin .nav-item.active::before{
  content:"";position:absolute;left:-2px;top:8px;bottom:8px;width:3px;border-radius:3px;
  background:linear-gradient(180deg,#8B5CF6,#6D28D9);
}
.app.admin .nav-item.active .ico{ opacity:1; }

/* optional status footer pinned under the nav (harmless if absent) */
.app.admin .adm-rail-foot{
  margin:14px 12px;padding:10px 12px;border-radius:12px;
  background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);
  display:flex;align-items:center;gap:8px;
}
.app.admin .adm-rail-foot .dotlive{
  width:7px;height:7px;border-radius:50%;background:#34D399;
  box-shadow:0 0 0 3px rgba(52,211,153,.22);flex:none;
}
.app.admin .adm-rail-foot span{font-size:12.5px;color:rgba(255,255,255,.62);font-weight:600}

/* ================= TOPBAR ================= */
.app.admin .topbar{
  background:rgba(255,255,255,.92);
  backdrop-filter:saturate(140%) blur(8px);
  border-bottom:1px solid var(--adm-line);
}
.app.admin .topbar .page-title{ letter-spacing:-.4px; color:var(--adm-ink); }
.app.admin .avatar{
  background:linear-gradient(135deg,#6D28D9,#4F46E5);
  box-shadow:0 4px 12px rgba(99,102,241,.4);
}
.app.admin .content{ background:#F7F7FC; }

/* operator role pill in #roleToggle gets a darker, premium look (markup unchanged) */
.app.admin #roleToggle .badge.badge-purple{
  background:linear-gradient(135deg,#312E81,#4F46E5);
  color:#fff;border:1px solid rgba(255,255,255,.14);
  box-shadow:0 4px 12px rgba(49,46,129,.35);
  letter-spacing:.01em;border-radius:8px;padding:5px 11px;font-weight:800;
}

/* primary buttons + modal submits read as the console (violet) in admin scope */
.app.admin .btn-primary{
  background:linear-gradient(135deg,#6D28D9,#4F46E5);
  box-shadow:0 8px 18px -6px rgba(99,102,241,.55);
}
@media (hover:hover){
  .app.admin .btn-primary:hover{filter:brightness(1.06);box-shadow:0 10px 22px -6px rgba(99,102,241,.6)}
}

/* ============================================================
   .adm-* COMPONENTS (light surfaces)
   ============================================================ */

/* ---- page heading row ---- */
.adm-head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:18px;flex-wrap:wrap}
.adm-head .adm-h-title{font-size:19px;font-weight:800;letter-spacing:-.5px;color:var(--adm-ink)}
.adm-head .adm-h-sub{font-size:12.5px;color:var(--gray-500);margin-top:3px}
.adm-head .adm-h-sub b{color:var(--adm-ink)}
.adm-head .adm-h-sub b.acc{color:#6D28D9}
.adm-head-actions{display:flex;gap:8px;flex-wrap:wrap}

/* ---- OPERATOR HERO strip (dashboard) ---- */
.adm-hero{
  position:relative;overflow:hidden;border-radius:var(--radius-lg);
  padding:22px 24px;margin-bottom:18px;color:#fff;
  background:
    radial-gradient(130% 130% at 100% -20%, rgba(139,92,246,.55) 0%, rgba(139,92,246,0) 55%),
    radial-gradient(120% 120% at -10% 120%, rgba(56,189,248,.30) 0%, rgba(56,189,248,0) 50%),
    linear-gradient(120deg,#2B2750 0%, #221F44 45%, #181534 100%);
  box-shadow:0 22px 48px -24px rgba(24,21,52,.8), inset 0 0 0 1px rgba(255,255,255,.06);
}
.adm-hero::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(255,255,255,.06),transparent 40%);
}
.adm-hero-top{display:flex;align-items:center;gap:10px;margin-bottom:14px;position:relative;z-index:1}
.adm-hero-badge{
  display:inline-flex;align-items:center;gap:7px;padding:5px 11px;border-radius:20px;
  background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.18);
  font-size:12.5px;font-weight:700;letter-spacing:.04em;color:#fff;
}
.adm-hero-badge .dotlive{width:7px;height:7px;border-radius:50%;background:#34D399;box-shadow:0 0 0 3px rgba(52,211,153,.28)}
.adm-hero-top .adm-hero-when{margin-left:auto;font-size:12.5px;color:rgba(255,255,255,.6);font-weight:600}
.adm-hero-main{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap;position:relative;z-index:1}
.adm-hero-title{font-size:16px;font-weight:800;color:#fff;letter-spacing:-.3px}
.adm-hero-desc{font-size:12px;color:rgba(233,230,255,.78);margin-top:4px;max-width:430px;line-height:1.6}
.adm-hero-cta{display:flex;gap:9px;flex-wrap:wrap}
.adm-hero-cta .hbtn{display:inline-flex;align-items:center;gap:6px;padding:9px 15px;border-radius:11px;font-size:12.5px;font-weight:700;transition:.15s;white-space:nowrap}
.adm-hero-cta .hbtn.solid{background:#fff;color:#4C3BCF;box-shadow:0 6px 16px rgba(0,0,0,.18)}
@media (hover:hover){
  .adm-hero-cta .hbtn.solid:hover{transform:translateY(-1px);box-shadow:0 10px 22px rgba(0,0,0,.24)}
}
.adm-hero-cta .hbtn.ghost{background:rgba(255,255,255,.12);color:#fff;border:1px solid rgba(255,255,255,.30)}
@media (hover:hover){
  .adm-hero-cta .hbtn.ghost:hover{background:rgba(255,255,255,.22)}
}
.adm-hero-stats{
  display:grid;grid-template-columns:repeat(4,1fr);gap:0;margin-top:18px;
  position:relative;z-index:1;
}
.adm-hero-stat{padding:0 18px;border-left:1px solid rgba(255,255,255,.12)}
.adm-hero-stat:first-child{padding-left:0;border-left:none}
.adm-hero-stat .v{font-family:var(--adm-num);font-size:24px;font-weight:800;letter-spacing:-.5px;font-variant-numeric:tabular-nums}
.adm-hero-stat .v small{font-size:12px;font-weight:700;opacity:.7;margin-left:2px}
.adm-hero-stat .l{font-size:12.5px;color:rgba(255,255,255,.62);margin-top:3px;font-weight:600}

/* ---- KPI cards ---- */
.adm-kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:18px}
.adm-kpi{
  background:#fff;border:1px solid var(--adm-line);border-radius:var(--radius);
  padding:16px 18px;box-shadow:var(--shadow);cursor:pointer;position:relative;
  transition:transform .18s cubic-bezier(.16,1,.3,1), box-shadow .18s, border-color .18s;
  overflow:hidden;
}
.adm-kpi::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--accent,#6366F1);opacity:0;transition:opacity .18s;
}
@media (hover:hover){
  .adm-kpi:hover{transform:translateY(-3px);box-shadow:0 16px 34px -16px rgba(30,34,51,.28);border-color:var(--adm-line-strong)}
  .adm-kpi:hover::before{opacity:1}
}
.adm-kpi-top{display:flex;align-items:center;justify-content:space-between}
.adm-kpi-ico{
  width:36px;height:36px;border-radius:11px;display:flex;align-items:center;justify-content:center;
  background:var(--accent-soft,#EEF2FF);color:var(--accent,#6366F1);
}
.adm-kpi-arrow{color:var(--gray-400);font-size:16px;transition:.15s}
@media (hover:hover){
  .adm-kpi:hover .adm-kpi-arrow{color:var(--accent,#6366F1);transform:translateX(2px)}
}
.adm-kpi-label{font-size:12px;color:var(--gray-500);font-weight:600;margin-top:13px}
.adm-kpi-num{
  font-family:var(--adm-num);font-variant-numeric:tabular-nums;
  font-size:27px;font-weight:800;letter-spacing:-.8px;color:var(--adm-ink);margin-top:2px;line-height:1.1;
}
.adm-kpi-num small{font-size:14px;font-weight:700;color:var(--gray-400);margin-left:2px;letter-spacing:0}
.adm-kpi-meta{display:flex;align-items:center;gap:6px;margin-top:6px}
.adm-delta{display:inline-flex;align-items:center;gap:3px;font-size:12.5px;font-weight:700;padding:2px 7px;border-radius:7px}
.adm-delta.up{color:#047857;background:var(--green-light)}
.adm-delta.flat{color:#6D28D9;background:var(--purple-light)}
.adm-delta.warn{color:#B45309;background:var(--orange-light)}
.adm-kpi-sub{font-size:12.5px;color:var(--gray-400)}

/* ---- generic admin panel ---- */
.adm-panel{background:#fff;border:1px solid var(--adm-line);border-radius:var(--radius);box-shadow:var(--shadow)}
.adm-panel-pad{padding:20px}
.adm-panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
.adm-panel-head .t{font-size:14.5px;font-weight:800;color:var(--adm-ink);letter-spacing:-.2px;display:flex;align-items:center;gap:8px}
.adm-panel-head .t .ic{width:26px;height:26px;border-radius:8px;display:flex;align-items:center;justify-content:center;background:#EEF2FF;color:#6366F1}
.adm-panel-head .t .cnt{font-size:12.5px;font-weight:800;color:#6D28D9;background:var(--adm-acc-soft);padding:2px 8px;border-radius:20px}
.adm-panel-head .x{font-size:12.5px;color:var(--gray-400);font-weight:700;cursor:pointer}
@media (hover:hover){
  .adm-panel-head .x:hover{color:#6D28D9}
}

/* ---- quick-action rows (descriptive, two-line) ---- */
.adm-qa{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:13px 14px;border:1px solid var(--gray-200);border-radius:13px;background:#FBFAFF;transition:.15s;margin-bottom:9px}
.adm-qa:last-of-type{margin-bottom:0}
@media (hover:hover){
  .adm-qa:hover{border-color:#C4B5FD;background:#F5F2FF;transform:translateY(-1px)}
}
.adm-qa .qi{width:38px;height:38px;border-radius:11px;flex:none;display:flex;align-items:center;justify-content:center;background:var(--adm-grad);color:#fff;box-shadow:0 6px 14px rgba(99,102,241,.34)}
.adm-qa .qi.alt{background:linear-gradient(135deg,#14B8A6,#0EA5E9);box-shadow:0 6px 14px rgba(14,165,233,.3)}
.adm-qa .qt{font-size:13px;font-weight:700;color:var(--adm-ink)}
.adm-qa .qd{font-size:12.5px;color:var(--gray-400);margin-top:1px}
.adm-qa .qchev{margin-left:auto;color:var(--gray-400);font-size:16px}
@media (hover:hover){
  .adm-qa:hover .qchev{color:var(--adm-violet)}
}

/* ---- recent-signup feed rows ---- */
.adm-feed{display:flex;flex-direction:column}
.adm-feed-row{display:flex;align-items:center;gap:11px;padding:10px 0;border-bottom:1px solid var(--gray-100)}
.adm-feed-row:last-child{border-bottom:none}
.adm-ava{
  width:34px;height:34px;border-radius:11px;flex:none;display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:800;color:#fff;letter-spacing:-.3px;
  background:linear-gradient(135deg,var(--ava-a,#7C3AED),var(--ava-b,#6366F1));
  box-shadow:0 4px 10px -4px rgba(99,102,241,.5);
}
.adm-feed-row .nm{font-size:13px;font-weight:700;color:var(--adm-ink)}
.adm-feed-row .em{font-size:12.5px;color:var(--gray-400);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.adm-feed-row .when{margin-left:auto;font-size:12.5px;color:var(--gray-400);font-family:var(--adm-num);font-variant-numeric:tabular-nums;white-space:nowrap}

/* ---- toolbar (search + segmented + actions) ---- */
.adm-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
.adm-toolbar .spacer{flex:1}
.adm-search{position:relative;display:flex;align-items:center}
.adm-search .ic{position:absolute;left:11px;color:var(--gray-400);display:flex;pointer-events:none}
.adm-search input{
  width:260px;max-width:60vw;padding:9px 13px 9px 32px;border:1px solid var(--gray-200);
  border-radius:11px;font-size:13px;background:#fff;transition:.14s;color:var(--adm-ink);
}
.adm-search input::placeholder{color:var(--gray-400)}
.adm-search input:focus{outline:none;border-color:var(--adm-violet);box-shadow:0 0 0 3px rgba(139,92,246,.16)}
/* segmented role filter with live counts */
.adm-seg{display:inline-flex;background:var(--gray-100);border-radius:11px;padding:3px;gap:2px}
.adm-seg button{
  display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:9px;font-size:12.5px;font-weight:700;color:var(--gray-500);
  transition:.14s;white-space:nowrap;
}
@media (hover:hover){
  .adm-seg button:hover{color:var(--adm-ink)}
}
.adm-seg button.on{background:#fff;color:var(--adm-navy);box-shadow:0 2px 6px rgba(30,34,51,.1)}
.adm-seg button .ct{font-size:12px;font-weight:800;opacity:.7;font-variant-numeric:tabular-nums}

/* ---- admin table ---- */
.adm-table-wrap{background:#fff;border:1px solid var(--adm-line);border-radius:var(--radius);box-shadow:var(--shadow);overflow-x:auto;overflow-y:hidden}
.adm-table{min-width:760px}
.adm-table{width:100%;border-collapse:collapse}
.adm-table thead th{
  text-align:left;padding:11px 16px;font-size:12px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--gray-400);background:#FAFAFE;border-bottom:1px solid var(--adm-line);white-space:nowrap;
}
.adm-table tbody td{padding:13px 16px;font-size:13px;border-bottom:1px solid var(--gray-100);vertical-align:middle}
.adm-table tbody tr:last-child td{border-bottom:none}
.adm-table tbody tr{transition:background .12s}
@media (hover:hover){
  .adm-table tbody tr:hover td{background:#FAF8FF}
}
.adm-table .num{font-family:var(--adm-num);font-variant-numeric:tabular-nums;text-align:center;color:var(--gray-600);font-weight:600}
.adm-table .num.dim{color:var(--gray-400)}
.adm-table .right{text-align:right;white-space:nowrap}

/* primary/secondary cell text */
.adm-cell-main{font-weight:700;color:var(--adm-ink)}
.adm-cell-sub{font-size:12.5px;color:var(--gray-400);margin-top:2px}
.adm-acaname{display:flex;align-items:center;gap:11px}
.adm-acaname .adm-ava{width:32px;height:32px;border-radius:10px;font-size:12px}

/* table footer (scope summary) */
.adm-tfoot{display:flex;align-items:center;justify-content:space-between;padding:11px 16px;border-top:1px solid var(--gray-100);background:#FAFAFE;font-size:12.5px;color:var(--gray-500);font-weight:600}
.adm-tfoot b{color:var(--adm-ink);font-variant-numeric:tabular-nums}
.adm-tfoot b.acc{color:#6D28D9}

/* status pills */
.adm-pill{display:inline-flex;align-items:center;gap:5px;padding:4px 10px;border-radius:20px;font-size:12.5px;font-weight:700}
.adm-pill::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.9}
.adm-pill.live{background:var(--green-light);color:#047857}
.adm-pill.off{background:var(--gray-100);color:var(--gray-500)}
.adm-pill.susp{background:var(--red-light);color:#BE123C}

/* membership tags */
.adm-tag{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:8px;font-size:12.5px;font-weight:700;margin:2px 3px 2px 0}
.adm-tag.dir{background:#EEF2FF;color:#4338CA}
.adm-tag.tea{background:var(--teal-light);color:#0F766E}
.adm-tag .ro{opacity:.6;font-weight:800}
.adm-tag-admin{background:linear-gradient(135deg,#312E81,#4F46E5);color:#fff;padding:3px 9px;border-radius:8px;font-size:12px;font-weight:800;letter-spacing:.02em}

/* enter-academy button (violet outline → fills on hover) */
.adm-enter{
  display:inline-flex;align-items:center;gap:6px;padding:7px 13px;border-radius:10px;
  font-size:12.5px;font-weight:700;color:var(--adm-navy);
  background:#fff;border:1px solid #DDD9F5;transition:.15s;white-space:nowrap;
}
@media (hover:hover){
  .adm-enter:hover{background:linear-gradient(135deg,#6D28D9,#4F46E5);color:#fff;border-color:transparent;box-shadow:0 8px 16px -6px rgba(99,102,241,.5)}
}
.adm-enter svg{width:14px;height:14px}

/* small ghost / outline actions inside tables */
.adm-act{display:inline-flex;align-items:center;gap:4px;padding:6px 11px;border-radius:9px;font-size:12px;font-weight:700;transition:.13s;white-space:nowrap}
.adm-act.ghost{background:var(--gray-100);color:var(--gray-600)}
@media (hover:hover){
  .adm-act.ghost:hover{background:var(--gray-200);color:var(--adm-ink)}
}
.adm-act.warn{background:#fff;border:1px solid var(--red-light);color:#BE123C}
@media (hover:hover){
  .adm-act.warn:hover{background:var(--red-light)}
}
.adm-act.go{background:#fff;border:1px solid var(--gray-200);color:var(--green-text)}
@media (hover:hover){
  .adm-act.go:hover{background:var(--green-light);border-color:transparent;color:#047857}
}

/* empty state */
.adm-empty{text-align:center;padding:34px 16px;color:var(--gray-400)}
.adm-empty .em-ic{width:42px;height:42px;border-radius:13px;background:#F1F0FA;color:var(--adm-violet);display:flex;align-items:center;justify-content:center;margin:0 auto 10px}

/* hint card, indigo-tinted */
.adm-note{
  display:flex;gap:10px;align-items:flex-start;
  background:linear-gradient(180deg,#F5F4FE,#F0EFFB);border:1px solid #E6E3F7;
  border-radius:14px;padding:13px 15px;font-size:12px;color:#433C7A;line-height:1.6;margin-top:16px;
}
.adm-note .ic{flex:none;color:var(--adm-violet);margin-top:1px}
.adm-note b{color:var(--adm-navy)}

/* impersonation banner (ready for exitImpersonation; render at top of impersonated pages) */
.adm-imp-banner{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  background:linear-gradient(150deg,#7C3AED,#9333EA 60%,#6D28D9);color:#fff;
  padding:11px 16px;border-radius:13px;margin-bottom:18px;
  box-shadow:0 10px 28px rgba(124,58,237,.28);
}
.adm-imp-banner .live{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:800;letter-spacing:.4px;text-transform:uppercase}
.adm-imp-banner .live .pulse{width:8px;height:8px;border-radius:50%;background:#fff;animation:admPulse 1.6s infinite}
@keyframes admPulse{0%{box-shadow:0 0 0 0 rgba(255,255,255,.6)}70%{box-shadow:0 0 0 7px rgba(255,255,255,0)}100%{box-shadow:0 0 0 0 rgba(255,255,255,0)}}
.adm-imp-banner .sp{flex:1}

/* responsive: collapse hero + kpi grids */
@media(max-width:1080px){
  .adm-kpis{grid-template-columns:repeat(2,1fr)}
  .adm-hero-stats{grid-template-columns:repeat(2,1fr);gap:14px 0}
  .adm-hero-stat{padding:6px 16px}
  .adm-hero-stat:nth-child(odd){padding-left:0;border-left:none}
}
@media(max-width:680px){
  .adm-kpis{grid-template-columns:1fr}
  .adm-search input{width:100%}
}

/* ============================================================
   관리자 콘솔 심플화 오버라이드 — 장식(글로우·그라디언트·애니메이션) 제거,
   단일 액센트(브랜드 바이올렛 #6439FF)로 플랫하게. 뒤에 와서 우선 적용.
   ============================================================ */
.app.admin{--adm-acc:#6439FF;--adm-acc-d:#5730E0;--adm-acc-soft2:#F1ECFF}
/* 사이드바: 오로라 글로우 제거 → 단색 다크 */
.app.admin .sidebar{background:#1E1B36;box-shadow:none;border-right:1px solid rgba(255,255,255,.07)}
.app.admin .logo .dot{background:var(--adm-acc);box-shadow:none}
.app.admin .nav-item.active{background:var(--adm-acc);box-shadow:none}
.app.admin .nav-item.active::before{display:none}
/* 탑바: 블러 제거, 단색 흰색 */
.app.admin .topbar{background:#fff;backdrop-filter:none}
.app.admin .avatar{background:var(--adm-acc);box-shadow:none}
.app.admin #roleToggle .badge.badge-purple{background:#312E81;box-shadow:none}
.app.admin .btn-primary{background:var(--adm-acc);box-shadow:none}
@media (hover:hover){
  .app.admin .btn-primary:hover{background:var(--adm-acc-d);filter:none;box-shadow:none}
}
.app.admin .content{background:#F8FAFC}
/* 대시보드 히어로 제거 → 헤더 + 지표 카드만 (심플) */
.adm-hero{display:none}
/* KPI 카드: 그림자·호버 리프트·악센트 레일 제거, 색 델타 → 회색 */
.adm-kpi{box-shadow:none;transition:border-color .15s}
.adm-kpi::before{display:none}
@media (hover:hover){
  .adm-kpi:hover{transform:none;box-shadow:none;border-color:#C4B5FD}
}
.adm-kpi-ico{background:var(--adm-acc-soft2);color:var(--adm-acc)}
.adm-delta.up,.adm-delta.flat,.adm-delta.warn{background:var(--gray-100);color:var(--gray-500)}
/* 패널·빠른작업·피드: 플랫 */
.adm-panel{box-shadow:none}
.adm-panel-head .t .ic{background:var(--adm-acc-soft2);color:var(--adm-acc)}
.adm-panel-head .t .cnt{color:var(--adm-acc);background:var(--adm-acc-soft2)}
.adm-qa{background:#fff;transition:border-color .15s,background .15s}
@media (hover:hover){
  .adm-qa:hover{transform:none;background:var(--gray-50);border-color:var(--gray-300)}
}
.adm-qa .qi{background:var(--adm-acc-soft2);color:var(--adm-acc);box-shadow:none}
.adm-qa .qi.alt{background:#E3F3FB;color:#0E7490;box-shadow:none}
@media (hover:hover){
  .adm-qa:hover .qchev{color:var(--gray-500)}
}
/* 아바타: 그라디언트 디스크 → 소프트 단색 */
.adm-ava{background:var(--adm-acc-soft2)!important;color:var(--adm-acc);box-shadow:none}
/* 테이블: 그림자 제거, 호버 중립 */
.adm-table-wrap{box-shadow:none}
@media (hover:hover){
  .adm-table tbody tr:hover td{background:var(--gray-50)}
}
.adm-tag-admin{background:#312E81}
@media (hover:hover){
  .adm-enter:hover{background:var(--adm-acc);box-shadow:none}
}
/* 안내 카드·임퍼소네이션 배너: 그라디언트·펄스 제거 */
.adm-note{background:#F6F6FB;border-color:var(--gray-200);color:var(--gray-600)}
.adm-note b{color:var(--adm-ink)}
.adm-imp-banner{background:var(--adm-acc);box-shadow:none}
.adm-imp-banner .live .pulse{animation:none}

/* ===== 모바일 반응형(대시보드) ===== */
.nav-toggle{display:none;width:38px;height:38px;border-radius:11px;align-items:center;justify-content:center;color:var(--gray-600);cursor:pointer;flex:none}
@media (hover:hover){
  .nav-toggle:hover{background:var(--gray-100);color:var(--dark)}
}
.sidebar-overlay{display:none;position:fixed;inset:0;background:rgba(15,27,61,.42);z-index:49}
#demoBanner{transition:transform .28s ease}
#demoBanner.hide{transform:translateY(140%)}
body.nav-open #demoBanner{transform:translateY(140%)}
/* 데모 배너가 하단을 가리지 않도록 콘텐츠 아래 여백 확보(짧은 화면에서도 맨 아래 보이게) */
body.demo-on .content{padding-bottom:84px}
@media(max-width:680px){body.demo-on .content{padding-bottom:132px}}
@media(max-width:860px){
  .sidebar{transform:translateX(-100%);transition:transform .26s cubic-bezier(.16,1,.3,1);box-shadow:0 0 50px rgba(15,27,61,.28);width:252px;overflow-y:auto}
  body.nav-open .sidebar{transform:none}
  body.nav-open .sidebar-overlay{display:block}
  .main{margin-left:0;min-width:0}
  .nav-toggle{display:flex}
  .topbar{height:54px;padding:0 12px}
  .topbar .page-title{font-size:16px}
  .profile span{display:none}
  .content{padding:18px 20px}
  .home-hero{padding:18px 18px}
  /* 상담운영 우측 카드: 모바일 1열 스택에선 내부 중첩 스크롤 제거(페이지 스크롤로 통일) */
  .counsel-ops .card{max-height:none!important;overflow:visible!important}
  .row-2,.row-3,.row-4,.stat-grid,.action-grid,.rc-stats,.rc-sum,.score-grid,.rc-diag,.uploadgrid{grid-template-columns:1fr 1fr;gap:10px}
  /* 통계 카드 콤팩트 */
  .stat{padding:13px 14px}
  .stat .val{font-size:20px;margin:4px 0 1px}
  .stat .label{font-size:12.5px}
  .ha-kpi{padding:14px}
  .ha-kpi .tile{width:38px;height:38px;border-radius:11px}
  .ha-kpi .lab{margin-top:10px;font-size:12.5px}
  .ha-kpi .num{font-size:22px}
  .content .grid[style]:not([style*="auto-fill"]):not([style*="auto-fit"]){grid-template-columns:1fr!important}
  /* 가로 스크롤은 표/시간표/캘린더 래퍼(.tbl-scroll)에서만 → 제목·버튼·필터·탭은 고정 */
  .content .card .tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
  /* 데이터 표 → 셀 줄바꿈 금지(행 안 깨짐) + 내용이 넓으면 카드 안에서 가로 스크롤 */
  .content .card table:not(.rd-table) th,.content .card table:not(.rd-table) td{white-space:nowrap}
  /* .tbl-scroll 래퍼가 없는 표도 카드 안에서 가로 스크롤(행 안 깨짐·오버플로 방지) */
  .content .card>table:not(.rd-table){display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
  /* 첫 열(이름) 고정 — 가로 스크롤해도 어느 행인지 보이게 */
  .content .card table:not(.rd-table) thead th:first-child,
  .content .card table:not(.rd-table) tbody td:first-child{position:sticky;left:0;background:#fff;box-shadow:1px 0 0 var(--gray-100)}
  /* 홈 히어로(인사) 모바일 컴팩트 — 일러스트 숨김으로 생기던 큰 여백 제거 */
  .ha-hero{padding:22px 18px;min-height:auto;gap:0;border-radius:18px;margin-bottom:14px}
  .ha-hero h1{font-size:21px;margin-top:10px}
  .ha-hero .hsub{font-size:13px;margin-top:8px}
  .ha-hero-search,.ha-hero-l{max-width:none}
  /* 모바일 홈: 원장 요약 칩(전체 재원생·재직 강사·운영 중인 반·상담 필요 학생) 숨김 */
  .ha-stats-dir{display:none}
  /* 버튼 줄 넘침 방지 — 줄바꿈 + 버튼 축소 */
  .flex,.flex-between{flex-wrap:wrap}
  /* 페이지 상단 툴바: 모바일에선 버튼이 한 줄에서 폭을 나눠 채움 */
  .page-actions{justify-content:stretch}
  .page-actions .btn{flex:1 1 0;justify-content:center}
  .btn{padding:8px 12px;font-size:12.5px}
  .btn-sm{padding:5px 9px;font-size:12.5px}
  /* 학생 상세 헤더: 아바타+이름 한 줄, 버튼은 아래 줄로 */
  .detail-head{flex-wrap:wrap;padding:16px}
  .detail-head>div:last-child{flex-direction:row!important;flex-wrap:wrap;width:100%;gap:8px;margin-top:4px}
  .detail-head>div:last-child .btn{flex:1 1 auto;justify-content:center}
  /* 시간표: 카드 안에서 가로 스크롤(폭 필요). 캘린더는 화면 폭에 맞춰 축소(가로 스크롤 없음) */
  .timetable{min-width:560px}
  .calendar{min-width:0}
  /* iOS/모바일 WebKit: 날짜·시간 입력이 width를 무시하고 고유폭으로 렌더돼 흰 박스를 넘던 버그
     → appearance 제거로 컨테이너 폭을 지키게(값 표시·탭 시 피커는 그대로 동작) */
  input[type="date"],input[type="time"]{-webkit-appearance:none;appearance:none;min-width:0;max-width:100%}
  input[type="date"].input,input[type="time"].input{-webkit-appearance:none;appearance:none}
  input[type="date"]::-webkit-date-and-time-value{text-align:left}
  /* 모달: 표 가로 스크롤 + 인라인 2단 그리드 1단 */
  .modal-body .card{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .modal-body table:not(.rd-table) th,.modal-body table:not(.rd-table) td{white-space:nowrap}
  .modal-body>table{display:block;overflow-x:auto}
  .modal-body .grid[style]{grid-template-columns:1fr!important}
  /* 필터 입력/셀렉트 풀폭 */
  .content .flex-wrap>.input{width:100%!important;min-width:0;flex:1 1 100%}
  /* 세그먼트 토글 풀폭 줄바꿈 */
  .fmt-toggle{display:flex;width:100%;flex-wrap:wrap}
  .fmt-toggle button{flex:1 1 auto;padding:7px 8px}
  /* 카드 제목 + 인라인 버튼 줄바꿈 */
  .card-title{flex-wrap:wrap;gap:6px}
  /* 탭: 한 줄 고정(위아래로 안 움직임). 넘치면 가로 스크롤만, 세로 스크롤 차단 */
  .tabs{overflow-x:auto;overflow-y:hidden;flex-wrap:nowrap;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .tabs::-webkit-scrollbar{display:none}
  .tab{padding:9px 11px;font-size:12.5px}
  /* 모달: 위가 잘리지 않게 상단 정렬 + 오버레이 스크롤(키큰 모달도 처음부터 보임) */
  .modal-overlay{padding:10px;align-items:flex-start;overflow-y:auto;-webkit-overflow-scrolling:touch}
  .modal,.modal.wide,.modal.narrow{max-width:100%;max-height:none;margin-bottom:10px}
  .modal-head{padding:16px 18px}.modal-body{padding:18px}.modal-foot{padding:14px 18px}
}
@media(max-width:520px){
  /* 폼 행은 전부 1열(날짜·금액 등 겹침 방지) — 통계 타일 그리드만 2x2 유지 */
  .row-2,.row-3,.action-grid,.rc-diag,.uploadgrid{grid-template-columns:1fr}
  .row-4,.stat-grid,.rc-stats,.rc-sum,.score-grid{grid-template-columns:1fr 1fr}
  .content{padding:16px 18px}
  /* 상담 캘린더 칩: 폰에선 시간 숨기고 이름만(이름이 잘리지 않게) */
  .cal-event .ce-t{display:none}
  .topbar .page-title{font-size:15px}
  /* 리포트 문서 여백/표 셀 축소 */
  .rd-header,.rd-meta,.rd-content,.rd-footer{padding-left:16px!important;padding-right:16px!important}
  .rd-table th,.rd-table td{padding:6px 5px;font-size:12.5px}
  .rd-meta{grid-template-columns:1fr}
  /* 업로드 드롭존 패딩 축소 */
  .dropzone{padding:18px 16px}
  /* 과제 이행률 행: 캡션을 다음 줄로 내려 막대 공간 확보 */
  .rate-row{flex-wrap:wrap;gap:6px 8px}
  .rate-row>.muted{width:auto!important;flex-basis:100%;text-align:left;order:5;font-size:12px}
  /* 캘린더 셀 컴팩트(폰에서 7열이 화면 폭에 맞게) */
  .cal-cell{min-height:58px;padding:2px 3px;font-size:12.5px}
  .cal-head{padding:6px 0;font-size:12px}
  .cal-event{font-size:12px;padding:1px 3px}
  /* 헤더의 버튼/필터 그룹은 한 줄 전체 폭으로(탭/제목 아래 깔끔히) */
  .flex-between>.flex{width:100%}
  /* 브랜드 점수 카드 콤팩트 */
  .metric-card{padding:11px 12px}
  .metric-card input{font-size:16px!important;padding:5px 8px!important}
  .metric-ico{width:30px;height:30px;font-size:15px}
}
/* ===== 아이콘(이모지 대체) — CSS 마스크, currentColor ===== */
.micon{display:inline-block;width:1em;height:1em;vertical-align:-.14em;flex:none;background-color:currentColor;-webkit-mask:var(--i) center/contain no-repeat;mask:var(--i) center/contain no-repeat}
.micon-sparkles{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%203l1.9%205.8a2%202%200%200%200%201.3%201.3L21%2012l-5.8%201.9a2%202%200%200%200-1.3%201.3L12%2021l-1.9-5.8a2%202%200%200%200-1.3-1.3L3%2012l5.8-1.9a2%202%200%200%200%201.3-1.3z'/%3E%3C/svg%3E")}
.micon-bulb{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M9%2018h6M10%2022h4'/%3E%3Cpath%20d='M15.1%2014c.2-1%20.6-1.7%201.4-2.5A4.6%204.6%200%200%200%2018%208%206%206%200%200%200%206%208c0%201%20.2%202.2%201.5%203.5.8.8%201.2%201.5%201.4%202.5'/%3E%3C/svg%3E")}
.micon-file{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M14%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V8z'/%3E%3Cpath%20d='M14%202v6h6M16%2013H8M16%2017H8M10%209H8'/%3E%3C/svg%3E")}
.micon-alert{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M10.3%204%202.4%2018a2%202%200%200%200%201.7%203h15.8a2%202%200%200%200%201.7-3L13.7%204a2%202%200%200%200-3.4%200z'/%3E%3Cpath%20d='M12%209v4M12%2017h.01'/%3E%3C/svg%3E")}
.micon-checkCircle{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M22%2011.1V12a10%2010%200%201%201-5.9-9.1'/%3E%3Cpath%20d='m9%2011%203%203L22%204'/%3E%3C/svg%3E")}
.micon-check{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M20%206%209%2017l-5-5'/%3E%3C/svg%3E")}
.micon-search{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='11'%20cy='11'%20r='8'/%3E%3Cpath%20d='m21%2021-4.3-4.3'/%3E%3C/svg%3E")}
.micon-lock{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='3'%20y='11'%20width='18'%20height='11'%20rx='2'/%3E%3Cpath%20d='M7%2011V7a5%205%200%200%201%2010%200v4'/%3E%3C/svg%3E")}
.micon-pin{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%2017v5'/%3E%3Cpath%20d='M9%2010.8a2%202%200%200%201-1.1%201.8l-1.8.9A2%202%200%200%200%205%2015.2V16a1%201%200%200%200%201%201h12a1%201%200%200%200%201-1v-.8a2%202%200%200%200-1.1-1.7l-1.8-.9A2%202%200%200%201%2015%2010.8V7a1%201%200%200%201%201-1%202%202%200%200%200%200-4H8a2%202%200%200%200%200%204%201%201%200%200%201%201%201z'/%3E%3C/svg%3E")}
.micon-chat{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M7.9%2020A9%209%200%201%200%204%2016.1L2%2022z'/%3E%3C/svg%3E")}
.micon-send{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M22%202%2011%2013M22%202l-7%2020-4-9-9-4z'/%3E%3C/svg%3E")}
.micon-clipboard{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='8'%20y='2'%20width='8'%20height='4'%20rx='1'/%3E%3Cpath%20d='M16%204h2a2%202%200%200%201%202%202v14a2%202%200%200%201-2%202H6a2%202%200%200%201-2-2V6a2%202%200%200%201%202-2h2'/%3E%3Cpath%20d='M9%2012h6M9%2016h6'/%3E%3C/svg%3E")}
.micon-school{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M14%2022v-4a2%202%200%200%200-4%200v4'/%3E%3Cpath%20d='m18%2010%204%202v8a2%202%200%200%201-2%202H4a2%202%200%200%201-2-2v-8l4-2'/%3E%3Cpath%20d='M18%205v17M6%205v17M4%206l8-4%208%204'/%3E%3C/svg%3E")}
.micon-calendar{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='3'%20y='4'%20width='18'%20height='18'%20rx='2'/%3E%3Cpath%20d='M16%202v4M8%202v4M3%2010h18'/%3E%3C/svg%3E")}
.micon-arrowUp{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%2019V5M5%2012l7-7%207%207'/%3E%3C/svg%3E")}
.micon-arrowDown{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%205v14M19%2012l-7%207-7-7'/%3E%3C/svg%3E")}
.micon-folder{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M20%2020a2%202%200%200%200%202-2V8a2%202%200%200%200-2-2h-7.9a2%202%200%200%201-1.7-.9L9.6%203.9A2%202%200%200%200%207.9%203H4a2%202%200%200%200-2%202v13a2%202%200%200%200%202%202z'/%3E%3C/svg%3E")}
.micon-pencil{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%2020h9'/%3E%3Cpath%20d='M16.5%203.5a2.1%202.1%200%200%201%203%203L7%2019l-4%201%201-4z'/%3E%3C/svg%3E")}
.micon-book{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M4%2019.5A2.5%202.5%200%200%201%206.5%2017H20'/%3E%3Cpath%20d='M6.5%202H20v20H6.5A2.5%202.5%200%200%201%204%2019.5v-15A2.5%202.5%200%200%201%206.5%202z'/%3E%3C/svg%3E")}
.micon-bookOpen{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%207v14'/%3E%3Cpath%20d='M3%2018a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1h5a4%204%200%200%201%204%204%204%204%200%200%201%204-4h5a1%201%200%200%201%201%201v13a1%201%200%200%201-1%201h-6a3%203%200%200%200-3%203%203%203%200%200%200-3-3z'/%3E%3C/svg%3E")}
.micon-users{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M16%2021v-2a4%204%200%200%200-4-4H6a4%204%200%200%200-4%204v2'/%3E%3Ccircle%20cx='9'%20cy='7'%20r='4'/%3E%3Cpath%20d='M22%2021v-2a4%204%200%200%200-3-3.9M16%203.1a4%204%200%200%201%200%207.8'/%3E%3C/svg%3E")}
.micon-mic{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%202a3%203%200%200%200-3%203v7a3%203%200%200%200%206%200V5a3%203%200%200%200-3-3z'/%3E%3Cpath%20d='M19%2010v2a7%207%200%200%201-14%200v-2M12%2019v3'/%3E%3C/svg%3E")}
.micon-phone{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='5'%20y='2'%20width='14'%20height='20'%20rx='2'/%3E%3Cpath%20d='M12%2018h.01'/%3E%3C/svg%3E")}
.micon-clip{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m21.4%2011-9.2%209.2a6%206%200%200%201-8.5-8.5l8.6-8.6A4%204%200%201%201%2018%208.8l-8.6%208.6a2%202%200%200%201-2.8-2.9l8.5-8.4'/%3E%3C/svg%3E")}
.micon-camera{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M14.5%204h-5L7%207H4a2%202%200%200%200-2%202v9a2%202%200%200%200%202%202h16a2%202%200%200%200%202-2V9a2%202%200%200%200-2-2h-3z'/%3E%3Ccircle%20cx='12'%20cy='13'%20r='3'/%3E%3C/svg%3E")}
.micon-plus{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%205v14M5%2012h14'/%3E%3C/svg%3E")}
.micon-chart{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M3%203v18h18'/%3E%3Crect%20x='7'%20y='9'%20width='3'%20height='8'%20rx='1'/%3E%3Crect%20x='12'%20y='5'%20width='3'%20height='12'%20rx='1'/%3E%3Crect%20x='17'%20y='12'%20width='3'%20height='5'%20rx='1'/%3E%3C/svg%3E")}
.micon-trendUp{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M22%207%2013.5%2015.5l-5-5L2%2017'/%3E%3Cpath%20d='M16%207h6v6'/%3E%3C/svg%3E")}
.micon-trendDown{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M22%2017%2013.5%208.5l-5%205L2%207'/%3E%3Cpath%20d='M16%2017h6v-6'/%3E%3C/svg%3E")}
.micon-user{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='8'%20r='5'/%3E%3Cpath%20d='M20%2021a8%208%200%200%200-16%200'/%3E%3C/svg%3E")}
.micon-mail{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='2'%20y='4'%20width='20'%20height='16'%20rx='2'/%3E%3Cpath%20d='m22%207-10%205L2%207'/%3E%3C/svg%3E")}
.micon-settings{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='3'/%3E%3Cpath%20d='M19.4%2015a1.7%201.7%200%200%200%20.3%201.8l.1.1a2%202%200%201%201-2.8%202.8l-.1-.1a1.7%201.7%200%200%200-1.8-.3%201.7%201.7%200%200%200-1%201.5V21a2%202%200%200%201-4%200v-.1A1.7%201.7%200%200%200%209%2019.4a1.7%201.7%200%200%200-1.8.3l-.1.1a2%202%200%201%201-2.8-2.8l.1-.1a1.7%201.7%200%200%200%20.3-1.8%201.7%201.7%200%200%200-1.5-1H3a2%202%200%200%201%200-4h.1A1.7%201.7%200%200%200%204.6%209a1.7%201.7%200%200%200-.3-1.8l-.1-.1a2%202%200%201%201%202.8-2.8l.1.1a1.7%201.7%200%200%200%201.8.3H9a1.7%201.7%200%200%200%201-1.5V3a2%202%200%200%201%204%200v.1a1.7%201.7%200%200%200%201%201.5%201.7%201.7%200%200%200%201.8-.3l.1-.1a2%202%200%201%201%202.8%202.8l-.1.1a1.7%201.7%200%200%200-.3%201.8V9a1.7%201.7%200%200%200%201.5%201H21a2%202%200%200%201%200%204h-.1a1.7%201.7%200%200%200-1.5%201z'/%3E%3C/svg%3E")}
.micon-tag{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12.6%202.6A2%202%200%200%200%2011.2%202H4a2%202%200%200%200-2%202v7.2a2%202%200%200%200%20.6%201.4l8.7%208.7a2.4%202.4%200%200%200%203.4%200l6.6-6.6a2.4%202.4%200%200%200%200-3.4z'/%3E%3Ccircle%20cx='7.5'%20cy='7.5'%20r='1.2'/%3E%3C/svg%3E")}
.micon-target{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='10'/%3E%3Ccircle%20cx='12'%20cy='12'%20r='6'/%3E%3Ccircle%20cx='12'%20cy='12'%20r='2'/%3E%3C/svg%3E")}
.micon-save{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M15.2%203a2%202%200%200%201%201.4.6l3.8%203.8a2%202%200%200%201%20.6%201.4V19a2%202%200%200%201-2%202H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2z'/%3E%3Cpath%20d='M17%2021v-7a1%201%200%200%200-1-1H8a1%201%200%200%200-1%201v7M7%203v4a1%201%200%200%200%201%201h7'/%3E%3C/svg%3E")}
.micon-star{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%202l3.1%206.3%206.9%201-5%204.9%201.2%206.8L12%2017.8%205.8%2021l1.2-6.8-5-4.9%206.9-1z'/%3E%3C/svg%3E")}
.micon-flask{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M9%203h6M10%203v6.5L4.5%2019a1%201%200%200%200%20.9%201.5h13.2a1%201%200%200%200%20.9-1.5L14%209.5V3'/%3E%3Cpath%20d='M6.5%2014h11'/%3E%3C/svg%3E")}
.micon-megaphone{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m3%2011%2018-5v12L3%2014v-3z'/%3E%3Cpath%20d='M11.6%2016.8a3%203%200%201%201-5.8-1.6'/%3E%3C/svg%3E")}
.micon-shield{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%2022s8-4%208-10V5l-8-3-8%203v7c0%206%208%2010%208%2010z'/%3E%3C/svg%3E")}
.micon-award{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='8'%20r='6'/%3E%3Cpath%20d='M15.5%2012.5%2017%2022l-5-3-5%203%201.5-9.5'/%3E%3C/svg%3E")}
.micon-cap{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M22%2010%2012%205%202%2010l10%205%2010-5z'/%3E%3Cpath%20d='M6%2012v5c0%201%202%203%206%203s6-2%206-3v-5'/%3E%3C/svg%3E")}
.micon-download{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M12%203v12'/%3E%3Cpath%20d='M7%2010l5%205%205-5'/%3E%3Cpath%20d='M5%2021h14'/%3E%3C/svg%3E")}
.micon-printer{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M6%209V2h12v7'/%3E%3Cpath%20d='M6%2018H4a2%202%200%200%201-2-2v-5a2%202%200%200%201%202-2h16a2%202%200%200%201%202%202v5a2%202%200%200%201-2%202h-2'/%3E%3Crect%20x='6'%20y='14'%20width='12'%20height='8'%20rx='1'/%3E%3C/svg%3E")}
.micon-checkSquare{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='m9%2011%203%203L22%204'/%3E%3Cpath%20d='M21%2012v7a2%202%200%200%201-2%202H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h11'/%3E%3C/svg%3E")}
.micon-square{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='3'%20y='3'%20width='18'%20height='18'%20rx='2'/%3E%3C/svg%3E")}
.micon-logout{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M9%2021H5a2%202%200%200%201-2-2V5a2%202%200%200%201%202-2h4'/%3E%3Cpath%20d='m16%2017%205-5-5-5M21%2012H9'/%3E%3C/svg%3E")}
.micon-coins{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='8'%20cy='8'%20r='6'/%3E%3Cpath%20d='M18.1%2010.4A6%206%200%201%201%2010.3%2018M7%206h1v4M16.7%2013.9l.7.7-2.8%202.8'/%3E%3C/svg%3E")}
.micon-trash{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M3%206h18'/%3E%3Cpath%20d='M19%206l-1%2014a2%202%200%200%201-2%202H8a2%202%200%200%201-2-2L5%206'/%3E%3Cpath%20d='M10%2011v6M14%2011v6'/%3E%3Cpath%20d='M9%206V4a1%201%200%200%201%201-1h4a1%201%200%200%201%201%201v2'/%3E%3C/svg%3E")}
.micon-clock{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'/%3E%3Cpath%20d='M12%207v5l3.5%202'/%3E%3C/svg%3E")}
.micon-flag{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M4%2021V4h9l-1%203h8v9h-8l1-3H4'/%3E%3C/svg%3E")}
.micon-help{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'/%3E%3Cpath%20d='M9.2%209.3a3%203%200%200%201%205.6%201.2c0%202-3%202.2-3%204'/%3E%3Cpath%20d='M12%2017.5h.01'/%3E%3C/svg%3E")}
.micon-refresh{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M20%2011a8%208%200%200%200-13.7-4.3L3%2010'/%3E%3Cpath%20d='M3%205v5h5'/%3E%3Cpath%20d='M4%2013a8%208%200%200%200%2013.7%204.3L21%2014'/%3E%3Cpath%20d='M21%2019v-5h-5'/%3E%3C/svg%3E")}
.micon-sliders{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M4%2021v-7M4%2010V3M12%2021v-9M12%208V3M20%2021v-5M20%2012V3'/%3E%3Cpath%20d='M1%2014h6M9%208h6M17%2016h6'/%3E%3C/svg%3E")}
.micon-x{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M18%206%206%2018M6%206l12%2012'/%3E%3C/svg%3E")}
.micon-bell{--i:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23000'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M6%208a6%206%200%200%201%2012%200c0%207%203%209%203%209H3s3-2%203-9'/%3E%3Cpath%20d='M10.3%2021a1.9%201.9%200%200%200%203.4%200'/%3E%3C/svg%3E")}

/* 성적 입력 범위 오류 — 틀린 칸 자체에 표시(#5) */
#giRows .gi-err{ border-color:var(--red)!important; box-shadow:0 0 0 3px rgba(200,30,74,.14); }
#giRows .gi-err-msg{ font-size:12px; color:var(--red-text); font-weight:600; margin-top:4px; line-height:1.4; }

/* 본문 바로가기 — 포커스될 때만 보인다(#47).
   `#content` 는 <main id="content"> 라 클릭만으로는 포커스가 가지 않는다 → JS 에서 tabindex 를
   붙여 실제로 본문에 포커스를 옮긴다(주소만 바뀌고 포커스는 메뉴에 남는 흔한 실패를 피한다). */
.skip-link{
  position:fixed; top:-60px; left:12px; z-index:2147483100;
  background:var(--primary-dark); color:#fff; font-size:13px; font-weight:700;
  padding:10px 16px; border-radius:0 0 10px 10px; text-decoration:none;
  transition:top .14s ease;
}
.skip-link:focus{ top:0; outline:3px solid #fff; outline-offset:-6px; }

/* ══════════ 모바일 체감(A·B·F) ══════════
   측정 결과: font-size 29종(11px 50회·12px 46회…) · border-radius 20종 ·
   :active 0개 · -webkit-tap-highlight-color 0개 · safe-area 0개 · 100dvh 0개 ·
   @media(hover:hover) 가드 0개(← 지금은 :hover 규칙 88개 전부 가드 안에 있다).
   그래서 (1) 전부 같은 크기로 보여 어디를 볼지 모르겠고
   (2) 눌러도 반응이 없고 (3) 눌렀던 버튼에 hover 색이 남아붙었다. */

/* F-1. 기본 탭 하이라이트 박스 제거 — 누를 때 회색 사각형이 번쩍였다 */
*{ -webkit-tap-highlight-color:transparent; }

/* F-2. hover 는 마우스에서만 — @media (hover:hover) 가드로 처리한다.

   ⚠ 여기 있던 @media (hover:none){ ... background:inherit; border-color:inherit;
   color:inherit; box-shadow:none; transform:none; filter:none } '무력화' 블록은 삭제했다.
   다시 만들지 마라 — 그게 폰에서 나온 증상의 원인이었다:
     · 모바일은 탭하면 :hover 가 걸리고 다른 곳을 탭할 때까지 유지된다(sticky hover).
       그래서 무엇을 눌러도 아래 선언이 발동했다.
     · border-color:inherit → 부모의 border-color 는 대개 초기값 currentColor 라
       부모 글자색(거의 검정)이 테두리로 씌워졌다  = 사용자가 말한 "탭하면 검정 테두리"
     · background:inherit → background 는 단축 속성이라 background-image 가 통째로
       날아간다 → .btn-primary 등의 그라데이션이 사라지고 배경이 부모 것으로 바뀌었다
     · color / opacity:inherit 도 같은 방식으로 글자색·투명도를 오염시켰다
   데스크톱 크롬은 (hover:none) 이 매치되지 않아 이 블록이 아예 켜지지 않는다 —
   창을 375px 로 줄여 전수 측정해도 '이상 없음'이 나오는 이유가 이것이다. 폰에서만 재현된다.

   해법은 '되돌리기'가 아니라 애초에 매치되지 않게 하는 것이다:
   이 스타일시트의 :hover 규칙은 전부 제자리에서 @media (hover:hover){ } 로 감싸 두었다.
   새 :hover 규칙을 추가할 때도 반드시 그 가드 안에 넣어라. */
/* F-3. 터치에는 '눌림'을 준다 — 반응이 없으면 안 눌린 줄 안다 */
@media (hover:none){
  .btn:active, .chip:active, .tab:active, .list-item:active, .att-card:active,
  [role="button"]:active, [data-h-click]:active{
    transform:scale(.975); filter:brightness(.97); transition:transform .06s, filter .06s;
  }
}
/* 마우스에서도 누름 반응은 있는 게 자연스럽다 */
.btn:active{ transform:translateY(1px); }

/* F-3b. 포커스 링을 우리 색으로 정한다.
   이 파일에는 :focus-visible 규칙이 하나도 없었다 — 그래서 포커스가 가면 브라우저 기본
   링(크롬·안드로이드에서 검정에 가까운 두꺼운 테두리)이 그대로 그려졌다.
   _a11yPass 가 data-h-click 붙은 div 에 role=button·tabindex=0 을 주므로 카드·타일·행까지
   전부 그 대상이라, 폰에서 뭘 눌러도 검은 테두리가 남는 것처럼 보였다.
   :focus 가 아니라 :focus-visible 로 건다 — 마우스·터치로 누른 것에는 링을 그리지 않고
   키보드 이동에만 그린다(접근성은 지키고 탭 흔적은 남지 않는다). */
:focus-visible{
  outline:2px solid var(--primary);
  outline-offset:2px;
  border-radius:var(--r-ctl,10px);
}
/* 마우스·터치로 누른 뒤 남는 기본 링은 지운다(위 :focus-visible 이 대신한다).
   .report-editing 은 예외다 — 그 점선은 '지금 편집할 수 있는 칸'이라는 표시라서 포커스와
   무관하게 계속 보여야 한다. 이 규칙과 특이도가 (0,2,0) 로 같은데 선언이 앞서 있어,
   빼 두지 않으면 마우스로 클릭한 순간 편집 표시가 사라진다. */
:focus:not(:focus-visible):not(.report-editing){ outline:none; }

/* F-4. iOS 주소창이 접힐 때 레이아웃이 튀지 않게 */
@supports (height:100dvh){
  .login-bg, .app, .sidebar{ min-height:100dvh; }
}
/* F-5. 시트·사이드바 스크롤이 본문으로 번지지 않게 */
.sidebar, .modal-body, .bot-body{ overscroll-behavior:contain; -webkit-overflow-scrolling:touch; }

@media (max-width:560px){
  /* A. 모바일 본문을 15px 로. 11~12px 본문은 '작아서'가 아니라 '전부 같아서' 안 읽힌다 */
  :root{
    --t-display:28px; --t-title:20px; --t-section:17px;
    --t-body:15px; --t-sub:13px; --t-caption:12px;
  }
  body{ font-size:var(--t-body); }
  .card-title, .section-label{ font-size:var(--t-section); }
  .page-title{ font-size:var(--t-title); }
  /* A-2. 하한 12px — 9·10·10.5px 은 모바일에서 정보가 아니라 노이즈다.
     '값'을 담은 자리를 12px 이상으로 올린다(장식 아이콘은 그대로 둔다). */
  .hint, .help{ font-size:var(--t-sub); line-height:1.65; }
  /* 표·입력은 손가락으로 다룰 크기로 */
  .btn{ min-height:44px; }
  .btn-sm{ min-height:38px; }
  /* 16px 미만 입력에 포커스가 가면 iOS 가 화면을 강제 확대한다(파일 머리의 viewport 주석과
     한 쌍). 실제 계산값은 뒤의 '자동 확대 방지' 블록이 !important 16px 로 이미 못박고 있어
     여기 15px 는 죽은 값이었다 — 그대로 두면 다음 사람이 15px 를 믿고 그 블록을 걷어내는
     사고가 난다. 값을 맞춘다(계산값 변화 없음 · 데스크톱에 닿지 않는 블록). */
  .input, select.input{ min-height:46px; font-size:16px; }
  /* B. 라운드 3단계로 수렴 — 컴포넌트마다 1px 씩 달라 어긋나 보였다 */
  .btn, .input, select.input, .chip{ border-radius:var(--r-ctl); }
  .card, .modal, .hint, .callout{ border-radius:var(--r-card); }
  .badge, .att-pill{ border-radius:var(--r-pill); }
  /* 안전영역 — 아이폰 홈 인디케이터 위에 버튼이 걸쳤다 */
  .content{ padding-bottom:calc(24px + env(safe-area-inset-bottom)); }
  .toast{ bottom:calc(22px + env(safe-area-inset-bottom)); }
}

/* ══════════ 모바일 체감 E(바텀시트) ══════════
   중앙 모달은 폼이 화면보다 높을 때 위아래가 같이 잘린다(학생 추가 폼 1304px vs 화면 844px).
   폰에서는 바닥에 붙는 시트로 바꾼다 — 시작점이 손가락 근처고, 확인 버튼이 항상 화면 안이다.
   showModal 호출 87곳은 그대로 두고 CSS 만 바꾼다. */
@media (max-width:560px){
  .modal-overlay{
    padding:0; align-items:flex-end; justify-content:center;
    overflow:hidden;                 /* 스크롤은 시트 본문이 담당한다 */
  }
  .modal, .modal.narrow, .modal.wide{
    max-width:100%; width:100%;
    max-height:min(90dvh, 90vh);     /* dvh 미지원 브라우저는 vh 로 떨어진다 */
    border-radius:20px 20px 0 0;
    /* transform 으로 밀어 올리지 않는다 — 애니메이션 시계가 멈추면(탭 전환·저사양 기기)
       'from' 상태인 translateY 가 그대로 남아 시트가 화면 밖 102px 에 서고, 그러면 하단의
       확인·취소 버튼을 누를 수 없다. 실제로 그 상태를 재현했다. 위치는 애니메이션과
       무관하게 항상 올바르게 두고, 흐려지는 효과만 준다(멈춰도 그냥 보인다). */
    animation:sheetFade .18s ease-out;
    margin:0;
  }
  /* 손잡이 — 위로 끌어올릴 수 있다는 표시(실제 드래그는 붙이지 않는다: 스크롤과 충돌한다) */
  .modal::before{
    content:''; display:block; flex:none;
    width:38px; height:4px; border-radius:999px; background:var(--gray-200);
    margin:8px auto 0;
  }
  .modal-head{ padding:12px 18px 14px; }
  .modal-body{
    padding:4px 18px 18px;
    overscroll-behavior:contain;     /* 시트 끝에서 뒤 화면이 따라 움직이지 않게 */
  }
  /* 확인·취소는 항상 보여야 한다 — 예전엔 폼이 길면 버튼이 화면 밖으로 나갔다 */
  .modal-foot{
    position:sticky; bottom:0; z-index:2;
    background:#fff; border-top:1px solid var(--gray-100);
    padding:12px 18px calc(12px + env(safe-area-inset-bottom));
    margin:0;
  }
  .ui-dlg{ align-items:center; padding:16px; }        /* 확인창은 짧으니 중앙 유지 */
  .ui-dlg .modal{ border-radius:var(--r-card); max-width:400px; }
  .ui-dlg .modal::before{ display:none; }
}
@keyframes sheetFade{ from{ opacity:.35 } to{ opacity:1 } }

/* ══════════ 모바일 체감 G(풀블리드 리스트) ══════════
   390px 에서 좌우 여백이 72px(18%)을 먹었다 — .content 패딩과 카드 패딩이 양쪽에서 겹친다.
   목록을 담은 카드는 화면 끝까지 쓰고, 카드 안에 또 카드가 있으면 안쪽 껍데기를 지운다.
   `.card-pad`(폼·설명 카드)는 그대로 둔다 — 글이 화면 끝에 붙으면 읽기 어렵다. */
@media (max-width:560px){
  .content{ padding-left:0; padding-right:0; }
  /* 카드 바깥 요소들은 원래 여백을 유지한다(제목·탭·필터·안내) */
  .content > *:not(.card):not(.grid),
  .content > .grid > *:not(.card){ padding-left:16px; padding-right:16px; }
  .content > .card, .content > .grid > .card{
    border-radius:0; border-left:0; border-right:0;
    margin-left:0; margin-right:0;
  }
  /* 목록·표를 담은 카드는 안쪽 패딩도 없애 행이 화면 끝까지 */
  .content > .card > .list-item,
  .content > .card > .tbl-scroll{ margin-left:0; margin-right:0; }
  .card > .card-pad{ padding-left:16px; padding-right:16px; }
  /* 카드 안의 카드 — 테두리가 두 겹 그려져 화면이 좁아 보였다 */
  .card .card{ border:0; box-shadow:none; border-radius:0; }
  .card .card + .card{ border-top:1px solid var(--gray-100); }
  /* 표 셀도 화면 끝까지 쓰되 첫·마지막 열만 여백을 준다 */
  .content > .card table th:first-child, .content > .card table td:first-child{ padding-left:16px; }
  .content > .card table th:last-child,  .content > .card table td:last-child{ padding-right:16px; }
}

/* ══════════ 모바일 체감 C(하단 탭바) ══════════
   폰에서 화면을 옮기려면 햄버거 → 드로어 → 20개 목록에서 찾기, 세 동작이었다.
   자주 쓰는 4개를 바닥에 고정하고 나머지는 '더보기'가 기존 드로어를 연다. */
.tabbar{ display:none; }
@media (max-width:560px){
  .tabbar{
    display:flex; position:fixed; left:0; right:0; bottom:0; z-index:60;
    background:rgba(255,255,255,.96); backdrop-filter:blur(8px);
    border-top:1px solid var(--border);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .tabbar .tb{
    flex:1 1 0; min-width:0;                       /* min-width:0 없으면 라벨이 칸을 밀어낸다 */
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:3px; padding:8px 2px 7px; background:none; border:0;
    color:var(--gray-500); font-size:12px; font-weight:600; cursor:pointer;
    -webkit-tap-highlight-color:transparent;
  }
  .tabbar .tb svg{ width:21px; height:21px; }
  .tabbar .tb span{ max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tabbar .tb.on{ color:var(--primary-dark); }
  .tabbar .tb.on svg{ stroke-width:2.4; }
  .tabbar .tb:active{ transform:scale(.94); transition:transform .06s; }
  /* 탭바에 가려 마지막 항목을 누를 수 없던 문제 — 탭바 높이(58) + 안전영역만큼 비운다 */
  .content{ padding-bottom:calc(58px + 16px + env(safe-area-inset-bottom)); }
  /* 챗봇 버튼·패널은 id 셀렉터다(#botFab) — 예전에 .bot-fab 으로 써서 안전영역·탭바 회피가
     한 번도 적용되지 않았고, 그래서 버튼이 하단 탭바의 '더보기' 를 덮었다. */
  #botFab{ bottom:calc(57px + 12px + env(safe-area-inset-bottom)); }
  #botPanel{ bottom:calc(57px + 70px + env(safe-area-inset-bottom));
             height:min(520px, calc(100dvh - 57px - 150px)); }
  .toast{ bottom:calc(58px + 16px + env(safe-area-inset-bottom)); }
  /* 드로어가 열리면 탭바는 그 아래로 — '더보기'가 켜진 상태에서 탭이 위에 겹치면 어색하다 */
  body.nav-open .tabbar{ z-index:48; }
}
/* 모달·시트가 열려 있으면 탭바를 숨긴다 — 시트 확인 버튼과 탭이 겹쳤다 */
@media (max-width:560px){
  body.sheet-open .tabbar{ display:none; }
}

/* ══════════ 모바일 체감 D(콘텐츠 우선) ══════════
   일정 화면 375px 에서 캘린더가 y≈930px 에서 시작했다. 그 위는 통계 2x2(290px) +
   필터 칩 3줄(100px) + 배너였다. 보러 온 것이 첫 화면에 없다는 뜻이다. */
@media (max-width:560px){
  /* D-1 통계 카드 — 값을 줄이지 않고 배치만 한 줄로. 2x2(290px) → 1줄(약 84px) */
  .stat-grid, .row-4.stat-row, .ha-kpi-grid{
    display:flex; gap:8px; margin-bottom:12px;
    overflow-x:auto; overscroll-behavior-x:contain; -webkit-overflow-scrolling:touch;
    scroll-snap-type:x proximity; padding:0 16px 2px;
    scrollbar-width:none;
  }
  .stat-grid::-webkit-scrollbar, .row-4.stat-row::-webkit-scrollbar{ display:none; }
  .stat-grid > *, .row-4.stat-row > *{
    flex:0 0 auto; min-width:132px; scroll-snap-align:start;
  }
  .stat-grid .stat, .row-4.stat-row .stat{ padding:11px 13px; }
  .stat-grid .stat .val, .row-4.stat-row .stat .val{ font-size:20px; margin:2px 0 0; }
  .stat-grid .stat .label, .row-4.stat-row .stat .label{ font-size:12px; }

  /* D-2 필터 칩 — 줄바꿈 대신 가로 스크롤. 3줄이 1줄이 된다.
     .chip-row 는 렌더 후 _mobilePass() 가 칩만 든 줄에 붙인다(화면별 마크업을 고치지 않는다). */
  .chip-row{
    display:flex!important; flex-wrap:nowrap!important; gap:6px;
    overflow-x:auto; overscroll-behavior-x:contain; -webkit-overflow-scrolling:touch;
    scrollbar-width:none; padding-bottom:2px;
    /* 오른쪽에 더 있다는 신호 — 잘린 게 없으면 눈에 띄지 않는다 */
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 22px),transparent);
            mask-image:linear-gradient(90deg,#000 calc(100% - 22px),transparent);
  }
  .chip-row::-webkit-scrollbar{ display:none; }
  .chip-row > *{ flex:0 0 auto; }
  /* 필터가 걸려 있으면 몇 개인지 알려 준다(칩이 가로로 숨어 안 보일 수 있다) */
  .chip-row-badge{
    display:inline-flex; align-items:center; gap:4px; flex:0 0 auto;
    font-size:12px; font-weight:700; color:var(--primary-dark);
    background:var(--primary-light); border-radius:var(--r-pill); padding:5px 10px;
  }

  /* D-3 긴 안내 배너 — 2줄로 접는다. 짧은 배너는 _mobilePass 가 건드리지 않는다 */
  .hint.clamped > .clamp-txt, .callout.clamped > .clamp-txt{
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  }
  /* '자세히'가 31×14 였다 — 14개 화면에 반복되는 최우선 탭 대상이다.
     배너의 마지막 줄에 혼자 서 있어 옆으로 겹칠 이웃이 없다 → 히트 영역만 늘리는 대신
     실제 크기를 키운다(::after 로 배너 밖까지 늘리면 다음 카드의 버튼을 덮는다).
     inline-flex + min-height 로 글자는 세로 가운데. margin-top:5px 은 padding 에 흡수시켜
     접힌 배너의 순증을 21px 로 묶었다. */
  .clamp-more{
    display:inline-flex; align-items:center; min-height:40px;
    margin-top:0; background:none; border:0; padding:0 16px 0 0;
    font-size:12px; font-weight:700; color:var(--primary-dark); cursor:pointer;
    text-decoration:underline; text-underline-offset:2px;
  }
}

/* ══════════════════════════════════════════════════════════════════
   모바일 2차 정비(연구팀 QA #2·#4~#14)
   측정 기준: 390px / 350px 컨테이너. 아래 규칙은 스타일시트의 맨 끝이므로
   같은 특이도끼리는 여기가 이긴다(앞의 @media 블록을 지우지 않고 덮는다).
   ══════════════════════════════════════════════════════════════════ */

/* ── #4 가로 스크롤이 브라우저 뒤로가기 제스처로 새는 것 차단 ──
   iOS 에서 표를 끝까지 밀면 그 스와이프가 그대로 '뒤로가기'로 이어졌다. */
.tbl-scroll,.timetable-scroll{ overscroll-behavior-x:contain; }

/* ── #7 챗봇 FAB 이 모든 레이어 위에 뜨던 문제 ──
   사이드바 50 · 딤 49 · 모달 100 인데 FAB 만 150 이라 드로어를 열어도 모달을 열어도
   그 위에 떠 있었다(390px 에서는 시트의 등록 버튼을 가렸다). 레이어를 내리고,
   드로어·시트·모달이 열려 있는 동안에는 아예 감춘다. */
#botFab{ z-index:45; }
body.nav-open #botFab, body.nav-open #botPanel,
body.sheet-open #botFab, body.sheet-open #botPanel{ display:none !important; }
body:has(.modal-overlay.show) #botFab, body:has(.modal-overlay.show) #botPanel{ display:none !important; }

/* ── #13 hover 전용 인터랙션 ── (해결됨)
   여기 있던 두 번째 '무력화' 블록 — 스타일시트의 :hover 약 80개를 background /
   border-color / color / opacity:inherit 로 되돌리던 것 — 도 삭제했다.
   이유는 위 F-2 주석과 같다(검정 테두리·그라데이션 소실의 원인).
   :hover 규칙은 전부 @media (hover:hover) 로 감싸 터치에서는 매치되지 않는다.

   ⚠ 아래 (hover:none) 블록은 '무력화'가 아니다 — hover 로만 드러나던 행 액션을
      터치에서 늘 보이게 하는 규칙이라 그대로 둔다(탭으로는 도달할 방법이 없었다). */
@media (hover:none){
  .tt-add{ opacity:1; border-color:var(--gray-300); }
  .action-card .ac-arrow, .adm-kpi-arrow, .adm-qa .qchev{ opacity:1; }
}

@media (max-width:560px){
  /* ── #8 iOS 자동 확대 방지(확대 허용과 한 쌍) ──
     viewport 에서 user-scalable=no 를 걷어내면 입력 글꼴이 16px 미만일 때 포커스 순간
     화면이 멋대로 확대된다. 폰에서만 입력 요소를 16px 로 못 박는다(인라인 12.5·13.4px 포함). */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]),
  select, textarea,
  .input, select.input, textarea.input, .bot-foot input{ font-size:16px !important; }
  .input, select.input{ min-height:46px; }
  /* 표 안의 좁은 입력칸(출결 메모 등)이 16px 로 커져 칸을 밀어내지 않게 */
  td .input, td input, td select{ min-width:0; }
  /* 날짜 입력의 인라인 고정폭(112px·150px)은 13px 글꼴 기준으로 잰 값이다. 위 16px 규칙으로
     ko-KR 표기 '2026. 08. 06.'(~100px) + 크롬 달력 아이콘(~16px)이 콘텐츠 폭을 넘어 연도가
     잘린다. 폰에서만 132px(16px 기준 계산값)로 고치고, 칸이 그보다 좁으면 줄어들 수 있게
     flex-shrink 도 되살린다(인라인 flex:none 이 shrink:0 을 박아 두므로 !important 필요).
     [style*=] 로 좁히는 이유: 나머지 날짜 입력들은 .input 의 width:100% 로 잘 살고 있어
     싸잡아 바꾸면 그쪽이 줄어든다. 학사일정 기간 2칸 + 강의계획서 표의 차시별 기간 칸만
     이 인라인 표기를 쓴다. */
  input[type="date"].input[style*="flex:none"]{
    width:132px !important; min-width:0; flex-shrink:1 !important;
  }

  /* ── #12 터치 타깃 44×44 보장 ──
     _tapPass() 가 실측해서 44px 미만인 컨트롤에만 .tap44 를 붙인다(시각 크기를 지키려고
     ::after 로 늘리면 이미 ::after 를 쓰는 컴포넌트와 충돌해, 크기 자체를 키운다). */
  /* 크기만 준다 — display 는 건드리지 않는다. 버튼·칩은 이미 내용이 세로 가운데로 정렬되고,
     display 를 바꾸면 인라인이던 것이 한 줄을 통째로 차지해 배치가 무너진다. */
  .tap44{ min-width:44px; min-height:44px; }
  /* 문장 속 인라인 링크만 박스로 — 인라인 요소에는 min-height 가 먹지 않는다 */
  .tap44.tap44-ib{ display:inline-flex; align-items:center; justify-content:center; }
  /* 표 셀 안은 세로만 키운다(가로로 벌리면 행이 깨진다) */
  .tap44.tap44-inline{ min-width:0; }
  .btn-sm{ min-height:44px; }
  .modal-close{ width:44px; height:44px; }
  .tabs .tab{ min-height:44px; display:inline-flex; align-items:center; }

  /* ── #14 필터 폭 통일 ──
     같은 줄의 셀렉트가 90~140px 로 제각각이고 기준선도 어긋났다. 폰에서는 2열 격자로
     고정한다(1열로 쌓으면 공지사항처럼 데이터 전에 300px 을 먹는다). */
  .content .flex-wrap > .input, .content .flex-wrap > select.input{
    flex:1 1 calc(50% - 5px) !important; width:auto !important; min-width:0; max-width:none;
  }
  /* 검색 입력(래퍼 div 로 감싼 것)과 정렬 라벨은 한 줄 전체 */
  .content .flex-wrap > div:has(> input.input),
  .content .flex-wrap > label:has(select.input){
    flex:1 1 100% !important; width:100% !important; max-width:none !important;
  }
  .content .flex-wrap > label:has(select.input) select.input{ flex:1 1 auto; width:auto !important; }

  /* ── #14 KPI 3칸이 세로로 다 쌓이던 문제 ──
     홈은 2열 격자인데 출결 통계만 1열 full-width 3장이라 첫 화면을 다 먹었다.
     .stat 만 들어 있는 .row-3 는 _mobilePass 가 .stat-2col 을 붙인다. */
  .row-3.stat-2col{ display:grid !important; grid-template-columns:1fr 1fr !important; gap:10px !important; }
  .row-3.stat-2col > .stat{ padding:12px 13px; }
  .row-3.stat-2col > .stat .val{ font-size:20px !important; }
  .row-3.stat-2col > .stat .label{ font-size:12.5px; }

  /* ── #10 카드 처리가 DOM 깊이에 따라 갈리던 문제 ──
     full-bleed 규칙이 깊이 1~2단(.content > .card, .content > .grid > .card)만 덮어서,
     같은 화면 안에서 OCR·CSV 카드만 좌우 16px+radius 16 으로 남았다.
     깊이와 무관하게 .content 안의 카드는 모두 같은 처리를 받는다. */
  .content .card{ border-radius:0; border-left:0; border-right:0; margin-left:0; margin-right:0; }
  /* 카드만 담은 래퍼의 좌우 여백은 걷어낸다(안 그러면 radius 0 인데 16px 들여쓰기가 된다) */
  .content > *:not(.card):not(.grid):has(> .card),
  .content > .grid > *:not(.card):has(> .card){ padding-left:0; padding-right:0; }

  /* ── #2 성적 입력 과목 행 — 폰에서도 5칸 한 줄(요청) ──
     예전 문제는 '한 줄'이 아니라 그 줄이 감당 못 할 것들을 함께 얹은 것이었다:
     라벨 '등급·선택'이 2줄로 접혀 행 높이가 18/36px 로 갈렸고, 삭제 버튼이 줄 안에서
     44px 를 먹었고, 좌우 패딩 13px 이 좁은 칸의 글자 자리를 잡아먹었다.
     → 캡션(과목 N)과 삭제(×)를 윗줄로 빼고, 라벨의 '·선택'을 감추고, 숫자 칸은
       가운데 정렬 + 좁은 패딩으로 줄인다. 그러면 다섯 칸이 한 줄에 들어간다. */
  #giRows{ counter-reset:girow; }
  #giRows .gi-row{
    display:flex !important; flex-wrap:nowrap !important; gap:5px !important;
    align-items:flex-end !important; position:relative;
    /* 위 44px 은 캡션·삭제 줄의 자리다 — 이만큼 비우지 않으면 44px 짜리 × 가
       맨 오른쪽 '표준' 칸의 라벨 위에 겹쳐 앉는다(실제로 겹쳤다). */
    border-top:1px solid var(--gray-100); padding:46px 0 12px; margin:0 !important;
  }
  #giRows .gi-row:first-child{ border-top:0; }
  #giRows .gi-row::before{
    counter-increment:girow; content:'과목 ' counter(girow);
    position:absolute; left:0; top:14px;
    font-size:12.5px; font-weight:700; color:var(--gray-500);
  }
  #giRows .gi-row > .field{ flex:1 1 0 !important; margin:0 !important; min-width:0; }
  #giRows .gi-row > .field:first-child{ flex:1.7 1 0 !important; }   /* 과목은 글자라 넓게 */
  #giRows .gi-row > .field > label{
    display:block; white-space:nowrap; overflow:hidden;
    min-height:18px; line-height:18px; margin-bottom:5px; font-size:12px;
  }
  /* '·선택' 은 폰에서 숨긴다 — 이게 라벨을 2줄로 접어 행 정렬을 깨뜨렸다 */
  #giRows .gi-row > .field > label .muted{ display:none; }
  #giRows .gi-row > .field .input{ width:100%; padding-left:6px; padding-right:6px; text-align:center; }
  #giRows .gi-row > .field:first-child .input{ text-align:left; padding-left:10px; }
  /* 삭제는 줄 밖(캡션 줄 오른쪽) — 줄 안에 두면 44px 를 먹어 입력칸이 그만큼 좁아진다 */
  #giRows .gi-row > .gi-del{
    position:absolute; right:0; top:0;
    width:44px; height:44px; min-height:44px; padding:0;
    display:flex; align-items:center; justify-content:center;
  }

  /* ── #11 주간시간표: 시간축이 스크롤에 같이 밀려 사라지던 문제 ──
     .timetable 의 overflow:hidden 은 sticky 의 기준을 자기 자신으로 잡아 고정이 먹지
     않는다 → 폰에서는 모서리 클립을 포기하고 바깥 래퍼(.tbl-scroll)를 기준으로 고정한다. */
  .timetable{ overflow:visible; border-radius:0; border-left:0; border-right:0; }
  .timetable > .tt-time,
  .timetable > .tt-head:first-child{
    position:sticky; left:0; z-index:3;
    background:var(--gray-50); box-shadow:1px 0 0 var(--gray-200);
  }
  .timetable > .tt-head{ position:relative; z-index:2; }
  .timetable > .tt-head:first-child{ z-index:4; }

  /* ── #4·#5 넓은 표 → 카드 리스트 ──
     582~758px 짜리 표를 350px 컨테이너에서 가로로 밀게 두면, 고정 열이 '순번'이라
     정작 제목이 흘러가 버린다. _tablePass() 가 '실제로 넘치는' 표에만 .tbl-cards 를
     붙이고, 각 칸에 헤더 이름(data-label)을 심는다. 넘치지 않는 표는 표 그대로 둔다. */
  table.tbl-cards, table.tbl-cards > tbody, table.tbl-cards > tbody > tr,
  table.tbl-cards > tbody > tr > td{ display:block; width:auto; }
  table.tbl-cards > thead{ display:none; }
  /* 가로 16px 은 TABLE 이 준다 — TR 은 padding 을 렌더하지 않기 때문이다(아래 주석 참고).
     카드 모드의 table 은 위에서 display:block 이 되므로 'border-collapse 표에는 padding 이
     안 먹는다'는 제약도 사라진다(375px 실측: td left 0 → 16px).
     트레이드오프: 행(tr)의 탭 영역이 375 → 343px 로 좌우 16px 씩 줄어든다. TR 에 투명
     보더로 주는 대안은 불가능했다 — 크롬은 TR 의 보더도 렌더하지 않는다(실측: 인라인
     !important 20px 보더에도 높이 변화 0). 글자가 화면 끝에 붙는 것보다 가장자리 여백이
     탭에 반응하지 않는 쪽이 낫다. */
  table.tbl-cards{ min-width:0 !important; padding:0 16px; }
  /* ── 카드 행의 여백·구분선은 TR 에 줄 수 없다 ──
     크롬은 TR 박스의 padding·margin·border 를 display:block/flex 로 바꿔도 렌더하지 않는다
     (375px 실측: 인라인 padding-left:16px !important → 계산값 0px, border-bottom 20px → 높이
     변화 0). 그래서 여기 있던 padding:11px 16px 12px 과 border-bottom 이 통째로 죽어,
     이름·NEW 배지·아바타가 뷰포트 왼쪽 끝(0px)에 붙고 행 구분선도 보이지 않은 채 배포돼
     있었다. 가로 16px 은 위 table 패딩으로, 세로 11/12px 과 구분선은 TR 이 display:block
     이라 렌더되는 ::before/::after 로 준다.
     td:first-child/:last-child 에 세로 패딩을 얹는 방법은 쓸 수 없다 — 값이 빈 칸에 붙는
     tc-empty 는 display:none 이면서도 :first-child 자리를 그대로 차지하므로, 그런 행만
     위 여백이 통째로 사라진다. */
  table.tbl-cards > tbody > tr{ background:#fff; }
  table.tbl-cards > tbody > tr::before{ content:''; display:block; height:11px; }
  table.tbl-cards > tbody > tr::after{
    content:''; display:block; height:12px; border-bottom:1px solid var(--gray-100);
  }
  /* 단독 colspan 셀 행(빈 목록 안내)은 자기 padding:24px 0 으로 이미 넉넉하다 — 스페이서를
     더하면 35/36px 이 된다. :only-child 가 중요하다 — 강의계획서 과제 펼침 행은
     <td></td><td colspan> 구조의 '데이터 행'이라 스페이서가 있어야 한다. */
  table.tbl-cards > tbody > tr:has(> td[colspan]:only-child)::before,
  table.tbl-cards > tbody > tr:has(> td[colspan]:only-child)::after{ content:none; }
  table.tbl-cards > tbody > tr:last-child::after{ border-bottom:0; }
  table.tbl-cards > tbody > tr > td{
    display:flex !important; gap:10px; align-items:baseline;
    padding:2px 0 !important; border:0 !important;
    white-space:normal !important; text-align:left !important;
    font-size:14px; min-height:0;
  }
  table.tbl-cards > tbody > tr > td::before{
    content:attr(data-label); flex:0 0 82px; max-width:82px;
    color:var(--gray-400); font-size:13px; font-weight:600; line-height:1.5;
  }
  /* 짧은 값(학년·반·상태 등)은 한 줄씩 차지하지 않고 흐르게 — 학생 카드 233px → 167px.
     _tablePass 가 '값이 짧고 조작 요소가 없는 칸'에만 붙인다. */
  table.tbl-cards > tbody > tr > td.tc-meta{
    display:inline-flex !important; width:auto; margin-right:14px; gap:5px;
  }
  table.tbl-cards > tbody > tr > td.tc-meta::before{ flex:none; max-width:none; }
  table.tbl-cards > tbody > tr > td[data-label=""]::before,
  table.tbl-cards > tbody > tr > td:not([data-label])::before{ content:none; }
  /* 식별 열(제목·이름·반)은 라벨 없이 카드 제목처럼 */
  table.tbl-cards > tbody > tr > td.tc-key{
    font-size:15px; font-weight:700; color:var(--dark);
    padding-bottom:6px !important; align-items:center;
  }
  table.tbl-cards > tbody > tr > td.tc-key::before{ content:none; }
  /* 순번·번호 같은 보조 식별자는 제목 위 작은 캡션으로 */
  table.tbl-cards > tbody > tr > td.tc-seq{
    font-size:12px; color:var(--gray-400); padding:0 0 2px !important;
  }
  table.tbl-cards > tbody > tr > td.tc-seq::before{ content:attr(data-label) ' '; flex:none; max-width:none; }
  /* 값이 비어 있는 칸은 줄만 차지한다 → 접는다 */
  table.tbl-cards > tbody > tr > td.tc-empty{ display:none !important; }
  /* 행 액션(버튼 묶음)은 아래쪽에 한 줄로 */
  table.tbl-cards > tbody > tr > td.tc-act{
    justify-content:flex-start !important; gap:8px; margin-top:8px; flex-wrap:wrap;
  }
  table.tbl-cards > tbody > tr > td.tc-act::before{ content:none; }
  /* 카드 모드에서는 첫 열 고정이 의미가 없다(가로 스크롤 자체가 없어진다) */
  table.tbl-cards > thead th:first-child,
  table.tbl-cards > tbody td:first-child{ position:static !important; box-shadow:none !important; }
  table.tbl-cards > tbody > tr > td:first-child{ padding-left:0 !important; }
  table.tbl-cards > tbody > tr > td:last-child{ padding-right:0 !important; }
  /* 비어 있는 목록의 colspan 안내 행은 그대로 가운데 정렬 */
  table.tbl-cards > tbody > tr > td[colspan]{
    display:block !important; text-align:center !important; padding:24px 0 !important;
  }
  table.tbl-cards > tbody > tr > td[colspan]::before{ content:none; }

  /* 표를 그대로 두는 경우에도 고정 열은 '식별 열'이어야 한다(_tablePass 가 지정) */
  .content .card table:not(.rd-table) thead th.tc-stick,
  .content .card table:not(.rd-table) tbody td.tc-stick{
    position:sticky; left:0; z-index:1; background:#fff;
    box-shadow:1px 0 0 var(--gray-100); min-width:130px;
  }
  .content .card table:not(.rd-table) thead th.tc-stick{ background:var(--gray-50); }
  /* 첫 열을 무조건 고정하던 규칙은 해제 — 순번 열이 고정돼 제목이 흘러갔다 */
  .content .card table:not(.rd-table) thead th:first-child:not(.tc-stick),
  .content .card table:not(.rd-table) tbody td:first-child:not(.tc-stick){
    position:static; box-shadow:none;
  }
  /* ── #5 학생관리 이름 칸이 3줄로 터지던 문제 ──
     첫 열이 75px 로 눌려 아바타·이름·'신규' 배지가 세로로 쌓였고 행 높이가 113/80px 로
     들쭉날쭉했다. 폰에서는 (요청) '신규' 배지를 빼고 사진과 이름만 한 줄로 둔다.
     헤더 이름으로 범위를 잡는다 — 공지의 NEW 배지까지 지우지 않기 위해서다. */
  .content td[data-label="이름"] .badge-new{ display:none; }
  /* 위기·주의는 폰에서도 남긴다 — 목록에서 바로 봐야 하는 정보라 '신규'와 달리 숨기지 않고
     여백만 줄인다(두 글자라 한 줄을 더 만들지 않는다). */
  .content td[data-label="이름"] .risk-chip{ padding:2px 5px; font-size:11.5px; }
  .content td[data-label="이름"] > .flex,
  .content .card table:not(.rd-table) td.tc-stick > .flex{
    flex-wrap:nowrap; min-width:0;
  }
  .content td[data-label="이름"] > .flex > span:not(.badge){
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0;
  }
}

/* ══════════ 모바일 3차 정비 ══════════ */
@media (max-width:860px){
  /* 상단바가 54px 고정이라 '리포트 기록 — (예빈테스트)최연우' 처럼 긴 제목이 줄바꿈되면
     바깥으로 삐져나와 뒤로 버튼·계정 칩과 겹쳤다(측정 top:-7 / bottom:60). */
  .topbar{ height:auto; min-height:54px; align-items:center; }
  .topbar .crumb{ min-width:0; }
  .topbar .page-title{ min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
}
@media (max-width:560px){
  /* ── 챗봇 FAB 이 본문을 가리던 문제 ──
     달력 칸·산식 문구·달력 아이콘 위에 늘 떠 있었다. 스크롤 중에는 접었다가 멈추면 되돌린다
     (JS 가 body.scrolling 을 붙인다). 크기도 줄여 가림 면적을 절반으로. */
  #botFab{ width:46px; height:46px; transition:transform .18s ease, opacity .18s ease; }
  #botFab svg{ width:22px; height:22px; }
  body.scrolling #botFab{ transform:translateY(90px); opacity:0; pointer-events:none; }

  /* ── 카드 밖 칩이 배경과 구분되지 않던 문제 ──
     칩 배경 #F1F3F9 vs 페이지 배경 #F4F5FA + 투명 보더 → 버튼으로 안 보였다. */
  .content .chip:not(.active){ background:#fff; border-color:var(--gray-200); }

  /* ── 가로로 스크롤되는 탭 줄에 '더 있다'는 신호 ──
     학생 상세 8번째 탭(수강 이력)이 화면 밖인데 힌트가 없어 존재를 몰랐다. */
  .tabs{ position:relative;
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 20px),transparent);
            mask-image:linear-gradient(90deg,#000 calc(100% - 20px),transparent); }
  .tabs.no-fade{ -webkit-mask-image:none; mask-image:none; }

  /* ── 출결 체크 표가 350px 안에서 찌그러지던 문제 ──
     특이사항 입력칸이 43px(플레이스홀더 26자), 출석/지각/결석 버튼이 137px 안에서 2줄로
     접혀 결석이 지각 아래로 내려갔다. 학생 1명 = 카드 1장으로 편다. */
  .att-mark-table, .att-mark-table > tbody, .att-mark-table > tbody > tr,
  .att-mark-table > tbody > tr > td{ display:block; width:auto; }
  .att-mark-table > thead{ display:none; }
  /* 순서를 이름 → 출결 버튼 → 특이사항 으로(마크업은 이름 → 특이사항 → 출결) */
  .att-mark-table > tbody > tr{
    display:flex !important; flex-direction:column;
    padding:12px 16px 14px; border-bottom:1px solid var(--gray-100);
  }
  .att-mark-table td.amk-name{ order:1; }
  .att-mark-table td.amk-btns{ order:2; }
  .att-mark-table td.amk-note{ order:3; }
  .att-mark-table > tbody > tr > td{
    padding:0 !important; border:0 !important; white-space:normal !important;
    text-align:left !important; width:auto !important;
  }
  .att-mark-table td.amk-name{ font-size:15px; font-weight:700; margin-bottom:8px; }
  .att-mark-table td.amk-btns > div{ display:grid !important; grid-template-columns:1fr 1fr 1fr;
    gap:6px; justify-content:stretch !important; }
  .att-mark-table td.amk-btns .btn{ width:100%; justify-content:center; min-height:44px; }
  .att-mark-table td.amk-note{ margin-top:8px; }
  .att-mark-table td.amk-note .input{ width:100% !important; min-width:0; }
}

/* ── #6 바텀시트를 열어도 뒤 페이지가 스크롤되던 문제 ──
   body{overflow:hidden} 은 iOS 에서 배경 스크롤을 막지 못한다(딤·헤더·푸터를 잡고 밀면
   그대로 밀린다 — 실측 0→262px). 몸통을 그 자리에 고정하고, 닫을 때 위치를 되돌린다.
   위치 복원은 _scrollLock() 가 담당한다. */
body.scroll-locked{
  position:fixed; left:0; right:0; width:100%;
  top:calc(-1 * var(--lock-y, 0px));
  overflow:hidden;
}

/* ── 데모 배너 하단 여백이 폰 규칙보다 먼저 선언돼 있던 문제 ──
   body.demo-on .content{padding-bottom:132px} 이 @media(max-width:560px) 의
   탭바 여백 계산보다 앞에 있어, 데모 배너가 켜지면 탭바 높이가 빠졌다. */
@media (max-width:560px){
  body.demo-on .content{
    padding-bottom:calc(58px + 74px + env(safe-area-inset-bottom)) !important;
  }
}

/* ── 출결 카드 머리줄 배지 겹침 ──
   '반 이름 + 개강 08/03 + 오늘 수업 없음' 묶음이 한 덩어리로 안 줄어들어, 폰에서 배지끼리
   겹쳐 읽혔다. 왼쪽만 줄바꿈을 허용하고(flex:0 1 — 늘리지는 않는다. 늘리면 학년 배지가
   자리가 남는데도 늘 아랫줄로 밀린다) 오른쪽 학년 배지는 줄이지 않는다. */
.att-card > .flex-between{ align-items:flex-start; gap:8px; }
.att-card > .flex-between > div:first-child{
  flex:0 1 auto; min-width:0; display:flex; flex-wrap:wrap; align-items:center; gap:4px;
  line-height:1.5;
}
.att-card > .flex-between > .badge{ flex:0 0 auto; align-self:flex-start; }

/* ── 주간 시간표 폰 하루 뷰 ──
   7열 그리드에서 요일 한 칸이 72px 이라 '수학 심화반'이 넉 자씩 접히고 시간·강사·강의실이
   여섯 줄로 무너졌다. 하루만 남기면 같은 칸이 300px 가까이 된다.
   요일 바는 인라인 display:none 으로 시작한다 — 프로덕션 인쇄 미리보기는 외부 CSS 가
   빠진 무스타일 문서라, 기본값을 CSS 에 두면 인쇄 창에 버튼 여덟 개가 맨몸으로 찍힌다. */
@media (max-width:560px){
  .tt-daybar{
    display:flex !important; gap:4px; background:var(--gray-100);
    border-radius:10px; padding:3px; margin-bottom:8px;
  }
  .tt-dbtn{
    flex:1 1 0; min-width:0; min-height:44px; border:0; background:none; border-radius:8px;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1px;
    font-size:13px; font-weight:700; color:var(--gray-500); cursor:pointer; padding:0;
  }
  /* 하한 12px — 이 '8개'는 장식이 아니라 그 요일에 수업이 몇 개인지 알려주는 유일한 값이다.
     버튼이 min-height:44px 라 13px+gap+12px 이 그대로 들어가 줄이 늘지 않는다. */
  .tt-dbtn > span{ font-size:12px; font-weight:400; opacity:.7; }
  .tt-dbtn.active{ background:#fff; color:var(--primary-dark); box-shadow:var(--shadow); }
  /* '주 전체'만 폭 34px 이었다(높이는 44px). 375px 기준 daybar 가용폭 약 333px,
     gap 7×4=28 을 빼면 8칸에 305px — 주 버튼을 44px 로 올려도 요일 7칸이
     38.7 → 37.3px 로 1.4px 만 줄어 '월'+'8개'가 그대로 들어간다. */
  .tt-dweek{ flex:0 0 44px; }

  /* 값 없는 [data-day] 에는 걸지 않는다 — 0~6 이 아닌 값이 들어오면 8칸이 2열에 접혀
     시간표가 통째로 무너진다. 값을 명시한 선택자만 쓴다(특이도 0,2,0 > .timetable 0,1,0). */
  .timetable[data-day="0"], .timetable[data-day="1"], .timetable[data-day="2"],
  .timetable[data-day="3"], .timetable[data-day="4"], .timetable[data-day="5"],
  .timetable[data-day="6"]{ grid-template-columns:44px 1fr; min-width:0; }
  .timetable[data-day="0"] > [data-wd]:not([data-wd="0"]),
  .timetable[data-day="1"] > [data-wd]:not([data-wd="1"]),
  .timetable[data-day="2"] > [data-wd]:not([data-wd="2"]),
  .timetable[data-day="3"] > [data-wd]:not([data-wd="3"]),
  .timetable[data-day="4"] > [data-wd]:not([data-wd="4"]),
  .timetable[data-day="5"] > [data-wd]:not([data-wd="5"]),
  .timetable[data-day="6"] > [data-wd]:not([data-wd="6"]){ display:none; }
  /* 그 요일에 수업이 없으면 7열 뷰와 달리 '옆 요일이 비어 보이는' 맥락이 없다.
     빈 칸이 그냥 흰 상자로만 남지 않게 누를 곳을 글자로 보여 준다. */
  .timetable[data-day] .tt-cell:empty::after{
    content:'+ 보강 추가'; display:block; text-align:center;
    color:var(--gray-300); font-size:12px; padding:7px 0;
  }
}

/* ── 일정 캘린더 폰 도트 뷰 ──
   390px 에서 날짜 칸 폭이 49px 이라 '19:00 수학 심화반' 칩이 '19:0…' 로 잘려 아무것도
   읽히지 않았다. 폰에서는 유형색 도트 + 'N건'으로 줄이고, 날짜를 누르면 원래 있던
   그 날 목록(openDaySchedule)이 열린다. cal-dot 표식이 붙은 일정 캘린더에만 적용되고
   같은 _monthGrid 를 쓰는 상담 캘린더는 그대로다. */
.cal-cnt{ display:none; }
@media (max-width:560px){
  /* 상담 캘린더 칩은 41x20 짜리 탭 대상이다(누르면 예약된 상담이 열린다).
     일정 캘린더처럼 도트로 접고 칸 클릭에 넘길 수는 없다 — 상담은 칸 클릭이
     openBookCounsel('새 예약' 폼)이라, 칩을 죽이면 기존 상담을 여는 경로가 통째로
     사라진다. 그래서 칩 자체의 세로만 24px 로 키운다.
     :not(.cal-dot) 이 반드시 있어야 한다 — min-height 는 특이도와 무관하게 아래 도트
     규칙의 height:8px 을 이기므로, 빼면 일정 캘린더 도트가 8x24 막대로 깨진다.
     가로 패딩은 건드리지 않는다(520px 블록의 padding:1px 3px 유지) — 칸 폭 47px 안에서
     칩 폭이 41px 그대로라 넘치지 않는다. box-sizing:border-box 라 4+16+4 = 정확히 24px. */
  .calendar:not(.cal-dot) .cal-event{
    min-height:24px; padding-top:4px; padding-bottom:4px; line-height:16px;
  }
  .calendar.cal-dot .cal-cell{ display:flex; flex-wrap:wrap; align-content:flex-start; gap:3px; }
  .calendar.cal-dot .cal-cell .day{ flex:1 0 100%; margin-bottom:1px; }
  /* .cal-cell.today .day 는 .day 자체를 22px 원으로 만든다 — flex-basis:100% 가 붙으면
     그 원이 칸 전체를 덮는 남색 알약이 된다. 오늘 표시는 칸 테두리로 옮긴다. */
  .calendar.cal-dot .cal-cell.today .day{
    width:auto; height:auto; background:none; color:var(--primary-dark);
    border-radius:0; display:block; justify-content:flex-start;
  }
  .calendar.cal-dot .cal-cell.today{ box-shadow:inset 0 0 0 2px var(--primary); }
  .calendar.cal-dot .cal-event:not(.cal-hol){
    width:8px; height:8px; padding:0; margin:0; border-radius:50%; flex:none;
    font-size:0; overflow:hidden; border-left:0 !important;
    background:currentColor !important;   /* 인라인 배경은 13% 틴트라 도트에선 안 보인다 */
    pointer-events:none;                  /* 8px 도트를 누르는 게 아니라 칸을 누르게 한다 */
  }
  /* 공휴일 칩은 글자를 살린다. 다만 한 줄을 통째로 쓰게 하지 않으면 도트와 폭을 나눠
     '광복절'이 '광…'으로 잘린다. */
  .calendar.cal-dot .cal-hol{
    flex:1 0 100%; min-width:0; font-size:11px; padding:0 2px; border-left:0; pointer-events:none;
  }
  /* 하한 12px — 도트 뷰에서 'N건'은 그 날 일정 수를 읽을 수 있는 유일한 글자다.
     칸 폭 ~45px 에 '12건'이 12px 로 ~34px, 여전히 한 줄에 들어간다.
     (바로 위 공휴일명은 11px 로 남긴다 — nowrap+말줄임이라 12px 로 올리면 '설날'이
     '설…'로 잘려 오히려 읽히는 글자가 줄어든다. 역할이 다르니 1px 차이는 문제없다.) */
  .calendar.cal-dot .cal-cnt{
    display:block; flex:1 0 100%; font-size:12px; color:var(--gray-500); line-height:1.2;
  }
}

/* ── 드로어 닫기 버튼 · 드로어 하단 계정 줄 ──
   _tapPass 는 #content(와 모달 host)만 훑기 때문에 상단바·드로어·탭바는 한 번도 검사되지
   않는다. 이 셸 부분은 정적 CSS 로 잡는다. */
.side-x{ display:none; }
.side-foot{ display:none; }

/* ── 페이지 끝 오른쪽 정렬 저장 버튼이 챗봇 FAB 에 가리던 문제 ──
   #botFab 은 right:20px/bottom:20px 의 56px 원이라, 문서 끝까지 내리면 마지막 줄의
   오른쪽 버튼과 정확히 겹친다(상담일지 저장이 그 사례). 고정 저장바가 있는 화면은
   has-savebar 로 FAB 을 올려 두지만 이 화면들엔 그 바가 없다 → 여백으로 비켜 준다. */
.fab-clear{ margin-bottom:78px; }
/* × 는 드로어가 실제로 밀려 나오는 대역(≤860px) 전체에 둔다 — 태블릿에서도 딤을 누르는
   것 말고 닫는 길이 없었다. 로그아웃 줄은 상단바가 진짜 좁아지는 폰에서만. */
@media (max-width:860px){
  .sidebar-head{ position:relative; }
  .side-x{
    display:flex; align-items:center; justify-content:center;
    position:absolute; top:8px; right:8px; width:44px; height:44px;
    border:0; background:none; border-radius:10px; cursor:pointer;
    font-size:26px; line-height:1; color:var(--gray-400);
  }
  .side-x:active{ background:var(--gray-100); }
  .sidebar-head .logo{ padding-right:44px; }   /* × 와 겹치지 않게 */
}
@media (max-width:560px){
  .side-foot{
    display:flex; gap:8px; flex:none;
    padding:10px 12px calc(10px + env(safe-area-inset-bottom));
    border-top:1px solid var(--gray-100); background:var(--side-bg,#fff);
  }
  /* .btn-ghost 의 회색 배경은 사이드바 테마와 따로 논다 — 테두리만 두고 색을 상속받는다 */
  .side-foot .btn{
    flex:1 1 0; min-height:44px; background:transparent;
    border:1px solid var(--gray-200); color:inherit;
  }
  /* 드로어 메뉴 항목 ~38px → 44px. 섹션 헤더(.nav-section)는 건드리지 않는다 —
     파괴적이지 않은 접기 토글이고, 캐럿 정렬만 흔들린다. */
  .sidebar .nav-item{ min-height:44px; }
}
@media (max-width:860px){
  /* 모든 상세 화면에 그려지는 상단바 '‹ 뒤로'가 33px 이었다. 상단바는 같은 대역에서
     height:auto/min-height:54px 이라 44px 버튼이 들어가도 늘어나지 않는다. */
  .topbar .back-btn{ min-height:44px; }
  .content .back-btn{ min-height:44px; display:inline-flex; align-items:center; padding:0 10px; }
}
@media (max-width:560px){
  /* 칩·태그의 삭제 × 는 8~10px 밖에 안 된다. display 나 margin 을 건드리면 부모가
     inline-flex 냐 inline-block 이냐에 따라 줄 높이가 달라지므로, 투명 확장판만 덧댄다.
     가로는 이웃 칩과의 gap 6px 때문에 44 까지는 못 넓힌다(약 22×44). */
  .chip .x, .tagx{ position:relative; }
  .chip .x::after, .tagx::after{ content:''; position:absolute; inset:-13px -8px; }
  /* 스위치도 같은 방식 — 40×22 라 세로가 특히 모자랐다 */
  .toggle{ position:relative; }
  .toggle::after{ content:''; position:absolute; inset:-11px -2px; }
  /* 문단 속 인라인 링크 — .tap44 를 붙이면 min-width:44px 까지 따라와 hint 문단이
     깨진다. 줄 상자를 키우지 않는 세로 패딩만 준다. */
  /* 3px 로는 실측 21px 밖에 안 나와 손가락에 안 잡혔다(설정 '강의계획서' 등) → 37px.
     문단 속 인라인 링크에서는 세로 padding 이 줄상자를 안 키우고 세로 마진은 무시되므로
     배치가 그대로다. 플렉스 항목으로 쓰인 .link(선택 시트 '전체 해제', 목표/첨부 삭제)는
     세로 마진이 실제로 적용된다 — 패딩 11 에 마진 -8 을 줘 마진박스 21px(기존과 동일)를
     지킨다. -11 로 완전 상쇄하면 마진박스가 15px 로 줄어 첨부 목록(gap 6px)에서 위아래
     행의 삭제 히트영역이 겹친다. 가로 3px 은 같은 값의 음수 마진으로 글자 위치 불변. */
  .link{ padding:11px 3px; margin:-8px -3px; }

  .fab-clear{ margin-bottom:64px; }   /* 폰 FAB 은 46px + bottom 20px */

  /* 홈 KPI — auto-fit 이라 500~560px 에서는 3열이 됐다. 그 폭에서 카드 5개면 4번째가
     둘째 줄에 혼자 서고 5번째가 3칸을 늘려 오히려 더 들쭉날쭉해진다. 폰 구간은 2열로
     못박은 뒤에야 '마지막 홀수 카드 전폭' 규칙이 성립한다. */
  .ha2-stats{ grid-template-columns:1fr 1fr; }
  .ha2-stat:last-child:nth-child(odd){ grid-column:1 / -1; }

  /* 반 상세 — 1,500px 넘는 폼 끝에서 주 동작 '저장'이 오른쪽 구석 60px 짜리였고,
     되돌릴 수 없는 '폐강'이 바로 같은 줄에 있었다. 세로로 세우고 폐강은 아래로 뗀다.
     인라인 style 의 gap·align-items 는 클래스 규칙으로 못 이기므로 !important 로 덮는다. */
  .cd-actions{
    flex-direction:column; align-items:stretch !important; gap:10px !important;
    margin-top:20px; padding-top:16px; border-top:1px solid var(--gray-100);
  }
  .cd-actions > .btn{ width:100%; justify-content:center; }
  .cd-actions > .cd-spacer{ display:none; }
  .cd-actions > .cd-save{ order:1; }
  .cd-actions > .cd-cancel{ order:2; }
  .cd-actions > .cd-close{ order:3; margin-top:6px; font-size:13px; }

  /* 브랜딩 기간 — date 두 칸이 각각 100% 로 잡혀 '~' 만 첫 줄 끝에 홀로 남았다.
     한 줄 3칸 그리드로 못박는다(선택자 클래스 4개 → 1836 블록보다 특이도가 높다). */
  .content .flex-wrap > .br-range{
    display:grid !important; grid-template-columns:1fr auto 1fr;
    align-items:center; gap:8px; width:100% !important;
  }
  .content .flex-wrap > .br-range > .input{ flex:none !important; width:100% !important; min-width:0; }
  .br-range-sep{ text-align:center; }

  /* ── 필터 줄이 화면의 3분의 1을 먹던 문제 ──
     실측: 학생관리 252px(5줄), 성적 통계 314px(6줄). 위 '#14 필터 폭 통일' 규칙이
     셀렉트는 50%, 검색·라벨은 100% 로 못박은 결과다. 표시된 줄만 한 줄 가로 스트립으로 바꾼다.
     ⚠️ 특이도 주의 — 위 규칙들이 (0,3,0)~(0,3,2) 라 `.filterbar > *` (0,2,0) 로는 못 이긴다.
     같은 계열에 클래스를 하나 더 붙여 (0,4,x) 로 올린다.
     ⚠️ 출결 필터는 제외한다 — position:absolute 드롭다운 패널이 overflow 에 잘린다. */
  .content .flex-wrap.filterbar{
    flex-wrap:nowrap !important; overflow-x:auto; overscroll-behavior-x:contain;
    -webkit-overflow-scrolling:touch; scrollbar-width:none; padding-bottom:2px;
  }
  .content .flex-wrap.filterbar::-webkit-scrollbar{ display:none; }
  .content .flex-wrap.filterbar > .input,
  .content .flex-wrap.filterbar > select.input,
  .content .flex-wrap.filterbar > div:has(> input.input),
  .content .flex-wrap.filterbar > label:has(select.input),
  .content .flex-wrap.filterbar > *{
    flex:0 0 auto !important; width:auto !important; max-width:none !important;
  }
  /* 검색칸만은 스트립 안에서도 손가락이 닿을 만큼은 남긴다 */
  .content .flex-wrap.filterbar > .fb-search{ flex:0 0 210px !important; width:210px !important; }
}

/* ══════════ 손가락에 안 잡히던 탭 대상 (375px 실측) ══════════
   '자세히' 31×14 · 지표 ✕ 21×17 · 홈 링크 17px · 홈 목록 행 34px · 수업 블록 34px ·
   완납/미납 배지 27px · 알림톡 칩 32px. 두 갈래로 나눴다:
   (1) 세로로 늘려도 이웃과 겹치지 않는 자리(전폭 목록 행·칩·입력칸·독립 버튼)는
       실제 크기를 키운다.
   (2) 표·배지·머리줄처럼 키우면 줄바꿈/겹침/정렬 붕괴가 생기는 자리는
       'padding + 같은 값의 음수 margin' 이나 ::after 로 히트 영역만 넓힌다.
   여기는 스타일시트의 맨 끝이라 같은 특이도끼리는 이 블록이 이긴다. */
@media (max-width:560px){
  /* 칩 32px — .chip 은 _TAP_SEL 에 있는데도 작게 남는 자리가 있다. _altRenderFilters() 처럼
     컨테이너 innerHTML 만 갈아끼우는 부분 렌더 경로에서는 _tapPass 가 다시 돌지 않기
     때문이다. 렌더 경로와 무관하게 CSS 로 바닥값을 못박는다(값은 tap44 와 동일). */
  .chip{ min-height:44px; }

  /* 홈 카드 머리줄 링크('더보기 ›' 등) — 머리줄(.ha2-ch, display:flex)을 44px 로
     부풀리지 않으려고 히트 영역만 넓힌다. 음수 마진이 padding 을 정확히 상쇄하므로
     플렉스 항목의 마진 박스(=배치에 쓰이는 크기)는 변하지 않는다.
     .ha-empty 안처럼 인라인으로 쓰인 .lnk 에서는 세로 마진이 무시돼 결과가 같다. */
  .lnk{ padding:12px 8px; margin:-12px -8px; }

  /* 홈 '이번 주 일정' 클릭 행 34px — 전폭 목록 행이고 위아래가 1px 경계선뿐이라
     세로로 키워도 겹칠 것이 없다(41px). */
  .ha2-lrow{ padding:11px 0; }

  /* 홈 '오늘 시간표' 수업 블록 — 시간축(.tlc-time)·눈금(.tlc-line)과 같은 그리드에
     얹혀 있어 블록만 키우면 시간 눈금과 어긋나고, 옆 레인이 붙어 있어 히트 영역을
     넓히면 다른 수업을 덮는다. 행 높이 자체를 올린다 — 인라인 값이라 !important 필요.
     격자가 30분 1행이므로 24px = 정시 48px(= 90분 수업 72px - 마진 4px = 68px). */
  .tlc{ grid-auto-rows:24px !important; }

  /* 브랜딩 지표 카드 — 이름 33px·수치 31px 입력칸. 카드 안 전폭이라 세로로만 늘어난다.
     인라인 style 에 height 가 없어 !important 없이 min-height 로 잡힌다. */
  .metric-card input{ min-height:44px; }
  /* 지표 삭제 ✕ 21×17 — 152px auto-fill 격자라 실제로 키우면 카드가 전부 따라 커지고
     같은 줄의 '클릭해 수정' 문구와 세로 정렬이 어긋난다 → 히트 영역만(41×35).
     위쪽을 6px 로 제한한 이유: 바로 위 수치 INPUT 이 그 자체로 탭 대상이라
     겹치면 수치를 누르려다 삭제가 눌린다(확인창이 있긴 하지만 오탭 자체가 성가시다).
     .metric-card 에는 overflow 선언이 없어 ::after 가 잘리지 않는다(전역 .badge 와 다르다). */
  .metric-card button[aria-label="지표 삭제"]{ position:relative; }
  .metric-card button[aria-label="지표 삭제"]::after{
    content:''; position:absolute; inset:-6px -10px -12px -10px;
  }

  /* 클릭 배지(완납/미납 토글 27px, 필터 해제) — .badge 는 전역 overflow:hidden 이라
     ::after 히트영역이 통째로 잘린다(절대배치 자손은 overflow 에 클리핑된다). 대신
     요소 자신의 padding 을 늘리고 같은 값의 음수 마진으로 상쇄한다 — 마진박스 42×27
     불변, 히트박스 48×35, 패딩 영역은 클리핑 대상이 아니다.
     가로 3px 은 임의 값이 아니다 — 필터 해제 배지들이 gap:6px 로 늘어서므로
     3+3=6 이 이웃끼리 겹치지 않는 한계값이다(겹치면 다른 필터가 지워진다). */
  span.badge[data-h-click]{ padding:8px 13px; margin:-4px -3px; }
  /* 배지 모양이지만 실제로는 독립 버튼인 것(강의계획서 '과제 N건 ▾' 29px)은 실제로 키운다.
     .badge 가 inline-flex; align-items:center 라 min-height 만으로 글자가 가운데 유지된다. */
  button.badge{ min-height:40px; }

  /* ── 입력과 버튼이 한 몸인 줄(검색창, 모달의 '추가' 등) ──
     input.input 은 모바일에서 min-height:46px 인데 .btn 은 44px 라, 모서리를 나눠 가진
     결합 컨트롤(왼쪽 입력 radius 10 0 0 10 + 오른쪽 버튼 0 10 10 0)의 이음매가 2px
     어긋나 버튼이 움푹/삐져 보였다. 입력과 같은 줄의 버튼은 46px 로 맞춘다.
     (.fb-search 는 아래 필터 스트립 규칙이 44px 로 다시 맞추므로 제외) */
  .flex:has(> .input):not(.fb-search) > .btn{ min-height:46px; }

  /* ── 필터 스트립(수강생·공지·클래스 등 목록 위 한 줄) ──
     한 줄 수평 나열이라 컨트롤 높이가 제각각이면 바로 티가 난다 — 실측 46(검색·셀렉트)/
     44(칩·버튼)/38(정렬 라벨) 혼재 + 정렬 select(46)가 38px 고정 라벨 밖으로 삐져나왔다.
     칩(44)에 맞춰 전부 44 로 통일한다. 폼(.field) 안의 select 는 입력칸들과 46 으로
     맞아야 하므로 건드리지 않는다 — 필터 줄(.filterbar, .flex.flex-wrap 직계)만.
     드롭다운 글자도 16→14px: 16px 는 iOS 가 텍스트 입력 포커스에서 확대하는 것을 막는
     값인데 select 는 피커가 열릴 뿐이라 위험이 낮고, 옆 버튼(12.5px)·칩(13px)과의
     크기 차가 '폰트가 들쭉날쭉'하게 보이는 주범이었다(2085행 16px !important 를 이기려면
     여기도 !important 가 필요하다). */
  .filterbar .input, .filterbar select.input,
  .content .flex.flex-wrap > select.input{ min-height:44px; }
  .filterbar .fb-search > .btn{ min-height:44px; }
  .filterbar select.input, .filterbar label > select.input,
  .content .flex.flex-wrap > select.input{ font-size:14px !important; }
  /* 인라인 height:38px 을 이기려면 !important 가 필요하다(인라인은 특이도 밖이다) */
  .filterbar label[style*="height:38px"]{ height:auto !important; }

  /* ── 홈(폰) 리듬 정리 ──
     간격이 14(카드 사이)와 16(섹션 사이·화면 좌우 여백)으로 미묘하게 섞여 있었고,
     지표 카드만 라운드 14·패딩 14/16 으로 콘텐츠 카드(16·16/18)와 달랐다.
     16 하나로 통일한다 — 좌우 여백과 같은 값이라 격자가 맞아 떨어진다. */
  .ha2-top{ gap:16px; }
  .ha2-stats, .ha2-mid, .ha2-bottom{ gap:16px; }
  .ha2-stat{ border-radius:16px; padding:16px; }
  /* 홈 검색도 다른 검색줄과 같은 44px(글꼴 16px 는 전역 확대 방지 규칙이 이미 처리) */
  .ha2-search input{ height:44px; }
  /* 카드 제목(14px)이 카드 본문 이름(15px)보다 작아 위계가 뒤집혀 보였다 */
  .ha2-ch .t{ font-size:15px; }

  /* 폰 전용 정렬 select(.sort-m) — 목록 카드 맨 위에 화면 끝까지(375px) 꽉 차게 떠서
     혼자 이질적이었다(둥근 모서리도 화면에 잘림). 카드 내용 여백(16px)에 맞춰 안으로
     들이고, 필터 스트립의 셀렉트와 같은 44px/14px 로 맞춘다.
     width 는 기본 규칙(520px 블록)의 100% 를, font 는 2085행의 16px !important 를,
     min-height 는 .input 의 46px 를 각각 이겨야 해서 !important 가 붙는다. */
  /* select.sort-m 로 쓰는 이유: 확대 방지 블록의 select.input(0,1,1)과 특이도를 맞춰야
     뒤에 선언된 이 규칙이 이긴다(.sort-m 만으로는 0,1,0 이라 진다). */
  select.sort-m{
    width:calc(100% - 32px) !important; margin:12px 16px 6px !important;
    min-height:44px !important; height:44px !important; font-size:14px !important;
  }

  /* ── 타이포 단 정리(폰) ──
     본문 계열이 12 / 12.5 / 13 / 13.5 — 1.5px 안에 네 단계로 쪼개져 있었다(인라인 12.5px
     404곳·13.5px 11곳). 화면마다 같은 성격의 글이 미묘하게 다른 크기라 '폰트가 들쭉날쭉'
     하게 보이는 근본 원인. 마크업 수백 곳을 고치는 대신 반칸짜리 두 값을 격자(12/13/14)로
     올려 세 단으로 만든다 — 12=캡션·날짜, 13=보조, 14=본문.
     [style*=] 는 인라인 선언만 잡는다. 데스크톱은 이 블록 밖이라 그대로다. */
  [style*="font-size:12.5px"]{ font-size:13px !important; }
  [style*="font-size:13.5px"]{ font-size:14px !important; }
  /* 클래스 규칙으로 12.5 를 받는 자리도 같은 단으로 — 폰에서 실제로 보이는 것만.
     버튼은 44px 높이에 12.5px 글자가 얹혀 비어 보였다 → 본문과 같은 14.
     배지·표머리·도움말·콜아웃·홈 목록행은 보조 13. 달력 칸·날짜류는 캡션 12.
     (.adm-* 관리자 콘솔은 폰 사용이 없어 제외 — 건드리는 범위를 좁게 유지) */
  .btn, .tab{ font-size:14px; }
  .btn-sm{ font-size:13px; }
  .badge, th, .callout, .field .help, .section-label,
  .ha2-lrow, .ha2-srow, .ha2-ch .t .muted, .ha2-lab, .bot-foot input{ font-size:13px; }
  .cal-cell, .ha2-lrow .dt, .ha2-srow .dt{ font-size:12px; }
  /* 홈 잔여 12.5 — KPI 부제·시간축 라벨·시간표 블록 안 글자(b/span)·공지 날짜·상담 유형 */
  .ha2-subl, .ha2-srow .cl, .tlc-block b, .tlc-block span, .ha-ag .mt, .ha-ag .tp{ font-size:13px; }
  .tlc-time, .ha-nrow .dt{ font-size:12px; }
}
