/* ============================================================================
   한경국립대학교 포털 — 레이아웃 & 컴포넌트

   반응형 규칙은 세 구간이다.
     ~767px    스마트폰   : 하단 5탭 네비, 본문 전체 폭
     768~1199  태블릿     : 왼쪽 아이콘 레일, 본문 가운데 정렬
     1200px~   데스크톱   : 왼쪽 사이드바(라벨 포함) + 넓은 화면에선 2단 구성

   입력 장치 대응은 <html data-pointer="touch|mouse"> 로 갈린다 (theme.css 참고).
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    overscroll-behavior-y: none;   /* 당겨서 새로고침 막기 — 앱처럼 보이게 */
}

body {
    font-family: var(--font);
    font-size: var(--font-base);
    line-height: 1.55;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
img { max-width: 100%; display: block; }

/* 인라인 SVG 는 크기를 안 주면 부모 폭을 다 먹는다. 기본값을 여기서 한 번 정하고
   버튼·네비 등에서만 따로 키운다. */
svg { width: 20px; height: 20px; flex: none; }
.chev { width: 18px; height: 18px; }

/* 포커스는 키보드 사용자에게만 — 마우스/터치 클릭에는 링이 안 뜬다 */
:focus { outline: none; }
:focus-visible {
    outline: 3px solid var(--hknu-blue-400);
    outline-offset: 2px;
    border-radius: 4px;
}

/* 모션 최소화 설정 존중 */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ── 부팅 화면 (Blazor 로딩 전) ─────────────────────────────────────────── */
.boot {
    position: fixed; inset: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 14px;
    background: linear-gradient(160deg, var(--hknu-navy), var(--hknu-blue));
    color: #fff;
}
/* 진한 파란 그라디언트 위라 흰색 단색 로고를 쓴다 (원래 색은 묻힌다) */
.boot-mark {
    width: 76px; height: 76px;
    object-fit: contain;
}
.boot-title { font-size: 17px; font-weight: 700; }
.boot-bar { width: 148px; height: 3px; border-radius: 3px; background: rgba(255,255,255,.25); overflow: hidden; }
.boot-bar span { display: block; width: 40%; height: 100%; background: #fff; border-radius: 3px; animation: bootslide 1.1s var(--ease) infinite; }
@keyframes bootslide { 0% { transform: translateX(-100%); } 100% { transform: translateX(350%); } }
.boot-note { font-size: 12.5px; opacity: .75; }

#blazor-error-ui {
    display: none;
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 2000;
    padding: 12px 16px;
    background: #ffefc2; color: #4a3a00;
    box-shadow: 0 -2px 12px rgba(0,0,0,.2);
}
#blazor-error-ui .dismiss { position: absolute; right: 12px; top: 10px; cursor: pointer; }
#blazor-error-ui .reload { text-decoration: underline; font-weight: 700; }

/* ============================================================================
   앱 셸
   ========================================================================= */
/* 사이드 네비는 position:fixed 라 흐름에서 빠진다.
   그래서 그리드 칸을 잡아주는 대신 셸에 왼쪽 여백을 줘서 자리를 비운다.
   (그리드로 하면 fixed 요소가 grid item 이 되지 못해 본문이 1번 칸으로 밀려 들어간다.) */
.shell {
    min-height: 100dvh;
    background: var(--bg);
}

.shell-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 100dvh;
}

/* 본문 — 상하 고정 바만큼 자리를 비워 둔다 */
.page {
    flex: 1;
    width: 100%;
    max-width: var(--content-max);
    margin: 0 auto;
    padding: calc(var(--topbar-h) + var(--safe-top) + 8px) 0
             calc(var(--bottomnav-h) + var(--safe-bottom) + 16px);
}

/* 좌우 스와이프 페이지(공지·학사)는 자기가 패딩을 관리한다 */
.page.is-flush { padding-left: 0; padding-right: 0; }

/* 안쪽이 따로 스크롤되는 화면(AI 대화)은 페이지 자체 높이를 화면에 고정한다.
   그래야 대화 목록이 늘어나는 대신 그 안에서 스크롤된다. */
.page.is-fixed { height: 100dvh; overflow: hidden; }

.page-pad { padding-inline: 16px; }

/* ── 상단바 ────────────────────────────────────────────────────────────── */
.topbar {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 60;
    height: calc(var(--topbar-h) + var(--safe-top));
    padding-top: var(--safe-top);
    display: flex; align-items: center; gap: 4px;
    padding-inline: 8px 6px;
    background: color-mix(in srgb, var(--surface) 86%, transparent);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid var(--line);
}

/* 이름 영역 (누르면 프로필 시트) */
.topbar-id {
    display: flex; align-items: center; gap: 9px;
    padding: 6px 10px 6px 6px;
    margin-right: auto;
    min-width: 0;
    border: 0; background: none;
    border-radius: var(--r-pill);
    cursor: pointer;
    transition: background var(--dur) var(--ease);
}
.topbar-id:active { background: var(--surface-sunken); }

.avatar {
    flex: none;
    width: 34px; height: 34px;
    border-radius: 12px;
    display: grid; place-items: center;
    font-weight: 800; font-size: 14px;
    color: #fff;
    background: linear-gradient(140deg, var(--hknu-blue), var(--hknu-navy));
    letter-spacing: -.5px;
}
/* 사진을 넣으면 배경 그라디언트는 가려지고 사진이 칸을 꽉 채운다 */
.avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.avatar.sm { width: 28px; height: 28px; border-radius: 10px; font-size: 12px; }
.avatar.lg { width: 56px; height: 56px; border-radius: 18px; font-size: 21px; }
.avatar.xl { width: 76px; height: 76px; border-radius: 24px; font-size: 28px; }
.avatar.prof   { background: linear-gradient(140deg, var(--hknu-teal), #045f5a); }
.avatar.staff  { background: linear-gradient(140deg, #b06a12, #6d3f05); }
.avatar.admin  { background: linear-gradient(140deg, #6b46c1, #3b2377); }

.topbar-name { min-width: 0; text-align: left; }
.topbar-name b { display: block; font-size: 15.5px; font-weight: 700; line-height: 1.2; }
.topbar-name small {
    display: block; font-size: 11px; color: var(--text-2);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 아이콘 버튼 */
.iconbtn {
    position: relative;
    flex: none;
    width: var(--tap); height: var(--tap);
    min-width: 40px; min-height: 40px;
    display: grid; place-items: center;
    border: 0; background: none;
    border-radius: 50%;
    cursor: pointer;
    color: var(--text);
    transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.iconbtn svg { width: 21px; height: 21px; }
.iconbtn:active { transform: scale(.92); }

/* hover 는 마우스일 때만 — 터치에서 hover 가 남는 문제를 피한다 */
@media (hover: hover) and (pointer: fine) {
    .iconbtn:hover { background: var(--surface-sunken); }
}

/* 아이콘 오른쪽 위 모서리에 살짝 걸치게. 더 안쪽으로 오면 아이콘을 덮어버린다. */
.badge-dot {
    position: absolute; top: 3px; right: 2px;
    min-width: 15px; height: 15px; padding: 0 4px;
    border-radius: var(--r-pill);
    background: var(--hknu-red); color: #fff;
    font-size: 9.5px; font-weight: 700; line-height: 15px;
    text-align: center;
    border: 2px solid var(--surface);
    box-sizing: content-box;
}
.badge-dot.dot { min-width: 8px; width: 8px; height: 8px; padding: 0; }

/* ── 하단 탭 네비 (모바일) ──────────────────────────────────────────────── */
.bottomnav {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    z-index: 60;
    height: calc(var(--bottomnav-h) + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-top: 1px solid var(--line);
    box-shadow: var(--sh-up);
}

.navitem {
    position: relative;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px;
    border: 0; background: none;
    color: var(--text-3);
    cursor: pointer;
    font-size: 10.5px; font-weight: 600;
    transition: color var(--dur) var(--ease);
    -webkit-tap-highlight-color: transparent;
}
.navitem svg { width: 23px; height: 23px; }
.navitem.active { color: var(--hknu-blue); }
.navitem.active svg { stroke-width: 2.4; }
.navitem:active { transform: scale(.94); }

.navitem .badge-dot { top: 4px; right: calc(50% - 20px); border-color: var(--surface); }

/* ── 사이드 네비 (태블릿·데스크톱) ─────────────────────────────────────── */
.sidenav { display: none; }

/* ============================================================================
   공통 컴포넌트
   ========================================================================= */

.card {
    background: var(--surface);
    border-radius: var(--r-lg);
    box-shadow: var(--sh-1);
    overflow: hidden;
}
.card + .card { margin-top: var(--gap); }

.card-head {
    display: flex; align-items: center; gap: 8px;
    padding: 14px 16px 8px;
}
.card-head h2 { font-size: 15px; font-weight: 700; }
.card-head .more {
    margin-left: auto; font-size: 12.5px; color: var(--text-2);
    display: inline-flex; align-items: center; gap: 2px;
    background: none; border: 0; cursor: pointer; padding: 4px;
}

.section-title {
    padding: 20px 16px 8px;
    font-size: 13px; font-weight: 700; color: var(--text-2);
    letter-spacing: -.2px;
}

/* 목록 행 */
.row {
    display: flex; align-items: center; gap: 12px;
    width: 100%;
    padding: var(--row-py) 16px;
    min-height: var(--tap);
    border: 0; background: none; text-align: left;
    cursor: pointer;
    transition: background var(--dur) var(--ease);
}
.row + .row { border-top: 1px solid var(--line); }
.row:active { background: var(--surface-sunken); }
@media (hover: hover) and (pointer: fine) {
    .row:hover { background: var(--surface-2); }
}
.row-main { flex: 1; min-width: 0; }
.row-title {
    font-size: 14.5px; font-weight: 600;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}
.row-sub {
    font-size: 12px; color: var(--text-2);
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
    margin-top: 2px;
}
.row-sub .sep { color: var(--line-strong); }
.row-aside { flex: none; font-size: 11.5px; color: var(--text-3); text-align: right; }
.chev { flex: none; color: var(--text-3); }

/* 칩(pill) 탭 — 참고 이미지의 상단 필터와 같은 형태 */
.chips {
    display: flex; gap: 8px;
    padding: 10px 16px;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
}
.chips::-webkit-scrollbar { display: none; }

.chip {
    flex: none;
    scroll-snap-align: center;
    display: inline-flex; align-items: center; justify-content: center; gap: 5px;
    padding: 8px 16px;
    min-height: 38px;
    border-radius: var(--r-pill);
    border: 1px solid var(--line-strong);
    background: var(--surface);
    color: var(--text-2);
    font-size: 13.5px; font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: all var(--dur) var(--ease);
}
.chip.active {
    background: var(--hknu-blue);
    border-color: var(--hknu-blue);
    color: #fff;
}
.chip:active { transform: scale(.96); }
@media (hover: hover) and (pointer: fine) {
    .chip:not(.active):hover { border-color: var(--hknu-blue-400); color: var(--hknu-blue); }
}
.chip.sm { padding: 5px 12px; min-height: 30px; font-size: 12.5px; }
/* 못 고르는 칩 — 답하는 중이거나, 서비스가 그 주제를 아직 준비하지 못했을 때 */
.chip:disabled { cursor: not-allowed; transform: none; }
.chip:disabled:not(.active) { opacity: .45; }

/* 칩 안에 붙는 안 읽은 건수 */
.chipcount {
    min-width: 17px; height: 17px; padding: 0 5px;
    border-radius: var(--r-pill);
    background: var(--hknu-red); color: #fff;
    font-size: 10px; font-weight: 700; line-height: 17px;
    text-align: center;
}
.chip.active .chipcount { background: rgba(255, 255, 255, .28); }

/* 서브탭 바 — 공지/학사 상단. 아래 인디케이터가 활성 탭을 따라간다 */
.subtabs {
    position: sticky;
    top: calc(var(--topbar-h) + var(--safe-top));
    z-index: 40;
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--line);
}
.subtabs-scroll {
    display: flex;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.subtabs-scroll::-webkit-scrollbar { display: none; }

.subtab {
    position: relative;
    flex: none;
    padding: 13px 16px 12px;
    border: 0; background: none;
    font-size: 14px; font-weight: 600;
    color: var(--text-3);
    cursor: pointer;
    white-space: nowrap;
    transition: color var(--dur) var(--ease);
}
.subtab.active { color: var(--hknu-blue); font-weight: 700; }
.subtab.active::after {
    content: '';
    position: absolute; left: 12px; right: 12px; bottom: 0;
    height: 3px; border-radius: 3px 3px 0 0;
    background: var(--hknu-blue);
}
@media (hover: hover) and (pointer: fine) {
    .subtab:not(.active):hover { color: var(--text); }
}

/* 좌우 스와이프 컨테이너 — CSS scroll-snap 으로 구현했다.
   JS 제스처 라이브러리 없이도 터치에서 자연스럽고, 마우스에선 화살표 버튼을 쓴다. */
.swipe {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    overscroll-behavior-x: contain;

    /* 손가락 가로 스와이프는 js/app.js 의 swipeInit 이 직접 처리한다.
       pan-y 로 브라우저의 가로 팬을 꺼 두어야 우리가 넣는 scrollLeft 와 싸우지 않는다.
       세로 팬은 그대로 브라우저가 가져가므로 페이지 스크롤은 평소처럼 된다.
       (마우스 휠·트랙패드 가로 스크롤은 touch-action 과 무관하게 계속 동작한다.) */
    touch-action: pan-y;
}
.swipe::-webkit-scrollbar { display: none; }
.swipe > .pane {
    flex: none;
    width: 100%;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    min-height: 40vh;
}

/* 스와이프 안내 — 터치일 때만 보인다 */
.swipe-hint {
    display: none;
    text-align: center; font-size: 11.5px; color: var(--text-3);
    padding: 6px 0 0;
}
html[data-pointer="touch"] .swipe-hint { display: block; }

/* 페이지 인디케이터 (점) */
.dots { display: flex; justify-content: center; gap: 6px; padding: 10px 0 2px; }
.dots i {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--line-strong);
    transition: all var(--dur) var(--ease);
}
.dots i.on { width: 18px; border-radius: 3px; background: var(--hknu-blue); }

/* 뱃지 / 태그 */
.tag {
    display: inline-flex; align-items: center; gap: 3px;
    padding: 2px 8px;
    border-radius: var(--r-pill);
    font-size: 11px; font-weight: 700;
    background: var(--surface-sunken); color: var(--text-2);
    white-space: nowrap;
}
.tag.brand  { background: var(--brand-tint); color: var(--hknu-blue); }
.tag.ok     { background: #e3f5ea; color: var(--ok); }
.tag.warn   { background: #fdf1d9; color: var(--warn); }
.tag.danger { background: #fdeaea; color: var(--danger); }
:root[data-theme="dark"] .tag.ok     { background: #12301f; }
:root[data-theme="dark"] .tag.warn   { background: #33280d; }
:root[data-theme="dark"] .tag.danger { background: #33191a; }

/* 버튼 */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    min-height: var(--tap);
    padding: 0 18px;
    border-radius: var(--r-md);
    border: 1px solid transparent;
    background: var(--surface-sunken);
    color: var(--text);
    font-size: 14px; font-weight: 700;
    cursor: pointer;
    transition: all var(--dur) var(--ease);
}
.btn:active { transform: scale(.97); }
.btn.primary { background: var(--hknu-blue); color: #fff; }
.btn.ghost   { background: none; border-color: var(--line-strong); }
.btn.danger  { background: var(--danger); color: #fff; }
.btn.block   { width: 100%; }
.btn:disabled { opacity: .45; cursor: default; transform: none; }
@media (hover: hover) and (pointer: fine) {
    .btn.primary:hover { background: var(--hknu-blue-600); }
    .btn.ghost:hover { background: var(--surface-2); }
}

/* 버튼 세 개를 한 줄에 — 기본 .btn 여백으로는 좁은 폰에서 넘친다 */
.actionrow { display: flex; gap: 8px; }
.actionrow .btn {
    flex: 1 1 0; min-width: 0;
    padding: 0 8px;
    font-size: 13px;
    white-space: nowrap;
}
.actionrow .btn svg { width: 17px; height: 17px; }

/* 입력 */
.field {
    display: flex; align-items: center; gap: 8px;
    padding: 0 14px;
    min-height: var(--tap);
    background: var(--surface-sunken);
    border: 1px solid transparent;
    border-radius: var(--r-md);
}
.field:focus-within { border-color: var(--hknu-blue-400); background: var(--surface); }
.field input, .field textarea {
    flex: 1; min-width: 0;
    border: 0; background: none; outline: none;
    font: inherit; color: var(--text);
    padding: 10px 0;
    resize: none;
}
.field input::placeholder, .field textarea::placeholder { color: var(--text-3); }
.field svg { flex: none; color: var(--text-3); width: 18px; height: 18px; }

/* 바로가기 편집 — 분류 머리줄, 아이콘 고르기 */
.grouphead {
    display: flex; align-items: center; gap: 4px;
    padding-block: 14px 6px;
}
.grouphead b { font-size: 13px; font-weight: 700; color: var(--text-2); }

/* 행 안에 여러 개 들어가는 작은 아이콘 버튼 */
.iconbtn.sm { width: 32px; height: 32px; min-width: 32px; min-height: 32px; }
.iconbtn.sm svg { width: 17px; height: 17px; }
.iconbtn:disabled { opacity: .25; cursor: default; }
.iconbtn:disabled:active { transform: none; }

.emojipick {
    width: 40px; height: 40px;
    display: grid; place-items: center;
    font-size: 19px;
    border-radius: var(--r-md);
    border: 2px solid transparent;
    background: var(--surface-sunken);
    cursor: pointer;
    transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.emojipick.on { border-color: var(--hknu-blue); background: var(--brand-tint); }
.emojipick:active { transform: scale(.92); }

.linkicon-preview {
    flex: none;
    width: 46px; height: 46px; border-radius: 15px;
    display: grid; place-items: center;
    font-size: 22px;
    background: var(--surface-sunken);
}

/* 토글 스위치 */
.switch {
    position: relative; flex: none;
    width: 48px; height: 28px;
    border-radius: var(--r-pill);
    background: var(--line-strong);
    border: 0; cursor: pointer; padding: 0;
    transition: background var(--dur) var(--ease);
}
.switch::after {
    content: '';
    position: absolute; top: 3px; left: 3px;
    width: 22px; height: 22px; border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0,0,0,.25);
    transition: transform var(--dur) var(--ease);
}
.switch.on { background: var(--hknu-blue); }
.switch.on::after { transform: translateX(20px); }

/* 빈 상태 */
.empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px;
    padding: 56px 24px;
    color: var(--text-3);
    text-align: center;
}
.empty .ico { font-size: 34px; opacity: .55; }
.empty b { font-size: 14.5px; color: var(--text-2); font-weight: 600; }
.empty p { font-size: 12.5px; }

/* 스켈레톤 */
.sk {
    background: linear-gradient(90deg, var(--surface-sunken) 25%, var(--surface-2) 37%, var(--surface-sunken) 63%);
    background-size: 400% 100%;
    animation: skshine 1.3s ease infinite;
    border-radius: var(--r-sm);
}
@keyframes skshine { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ============================================================================
   시트 (바텀시트 / 모달)
   ========================================================================= */
.sheet-scrim {
    position: fixed; inset: 0; z-index: 100;
    background: rgba(10, 20, 40, .45);
    backdrop-filter: blur(2px);
    animation: fadein var(--dur) var(--ease);
}
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }

.sheet {
    position: fixed; z-index: 101;
    left: 0; right: 0; bottom: 0;
    max-height: 88dvh;
    display: flex; flex-direction: column;
    background: var(--surface);
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    box-shadow: var(--sh-3);
    padding-bottom: var(--safe-bottom);
    animation: sheetup 280ms var(--ease);
}
@keyframes sheetup { from { transform: translateY(100%); } to { transform: translateY(0); } }

.sheet-grab {
    flex: none;
    width: 40px; height: 4px; border-radius: 4px;
    background: var(--line-strong);
    margin: 10px auto 4px;
}
.sheet-head {
    flex: none;
    display: flex; align-items: center; gap: 8px;
    padding: 8px 16px 12px;
    border-bottom: 1px solid var(--line);
}
.sheet-head h2 { font-size: 16.5px; font-weight: 700; flex: 1; }
.sheet-body { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
/* 채팅방은 시트가 스크롤하는 게 아니라 대화 목록이 스크롤한다 */
.sheet-body:has(> .chatroom) { overflow: hidden; display: flex; }
.sheet-foot {
    flex: none;
    display: flex; gap: 8px;
    padding: 12px 16px;
    border-top: 1px solid var(--line);
    background: var(--surface);
}

/* 전체화면 시트 (채팅방, 공지 상세, 바코드) */
.sheet.full {
    top: 0; border-radius: 0; max-height: none;
    padding-top: var(--safe-top);
    animation: slidein 260ms var(--ease);
}
@keyframes slidein { from { transform: translateX(100%); } to { transform: translateX(0); } }
.sheet.full .sheet-grab { display: none; }

/* 토스트 */
.toast {
    position: fixed;
    left: 50%; transform: translateX(-50%);
    bottom: calc(var(--bottomnav-h) + var(--safe-bottom) + 16px);
    z-index: 200;
    max-width: min(90vw, 420px);
    padding: 12px 18px;
    border-radius: var(--r-pill);
    background: rgba(20, 26, 36, .94);
    color: #fff;
    font-size: 13.5px; font-weight: 500;
    box-shadow: var(--sh-3);
    animation: toastin 240ms var(--ease);
    text-align: center;
}
@keyframes toastin { from { opacity: 0; transform: translate(-50%, 12px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* ============================================================================
   태블릿 (768px~)  — 왼쪽 아이콘 레일
   ========================================================================= */
@media (min-width: 768px) {
    .bottomnav { display: none; }

    .shell { padding-left: var(--rail-w); }

    .sidenav {
        display: flex; flex-direction: column;
        position: fixed; top: 0; bottom: 0; left: 0;
        width: var(--rail-w);
        z-index: 70;
        padding: 12px 8px calc(12px + var(--safe-bottom));
        background: var(--surface);
        border-right: 1px solid var(--line);
    }

    .sidenav-brand {
        display: flex; flex-direction: column; align-items: center; gap: 6px;
        padding: 8px 0 16px;
        margin-bottom: 4px;
        border-bottom: 1px solid var(--line);
    }
    /* 파비콘·앱 아이콘과 같은 심볼마크. 배경이 투명이라 어느 테마에도 얹힌다. */
    .sidenav-mark {
        width: 40px; height: 40px;
        flex: none;
        object-fit: contain;
    }

    /* 로고의 왼쪽 절반이 딥네이비라 어두운 바탕에서는 묻힌다.
       색을 바꾸지 않고 밝기만 올려 형태가 보이게 한다. */
    :root[data-theme="dark"] .sidenav-mark { filter: brightness(1.5) saturate(1.05); }

    @media (prefers-color-scheme: dark) {
        :root:not([data-theme="light"]):not([data-theme="dark"]) .sidenav-mark {
            filter: brightness(1.5) saturate(1.05);
        }
    }
    .sidenav-wordmark { display: none; }

    .sidenav .navitem {
        flex-direction: column;
        height: 62px;
        border-radius: var(--r-md);
        margin-top: 4px;
        font-size: 11px;
    }
    .sidenav .navitem.active { background: var(--brand-tint); }
    .sidenav .navitem .badge-dot { top: 8px; right: calc(50% - 20px); border-color: var(--surface); }
    @media (hover: hover) and (pointer: fine) {
        .sidenav .navitem:not(.active):hover { background: var(--surface-2); color: var(--text); }
    }

    .sidenav-foot { margin-top: auto; }

    .topbar { left: var(--rail-w); }
    .page { padding-top: calc(var(--topbar-h) + var(--safe-top) + 12px); padding-bottom: 32px; }
    .subtabs { top: calc(var(--topbar-h) + var(--safe-top)); }
    .toast { bottom: 28px; left: calc(50% + var(--rail-w) / 2); }

    /* 시트는 큰 화면에서 가운데 모달로 뜬다 */
    .sheet {
        left: 50%; right: auto; bottom: auto;
        top: 50%;
        transform: translate(-50%, -50%);
        width: min(560px, 92vw);
        max-height: 84dvh;
        border-radius: var(--r-xl);
        animation: popin 220ms var(--ease);
    }
    @keyframes popin {
        from { opacity: 0; transform: translate(-50%, -46%) scale(.97); }
        to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    }
    .sheet .sheet-grab { display: none; }
    .sheet.full {
        top: 50%; width: min(680px, 94vw); height: min(860px, 88dvh);
        border-radius: var(--r-xl);
        padding-top: 0;
        animation: popin 220ms var(--ease);
    }
}

/* ============================================================================
   데스크톱 (1200px~) — 라벨 있는 사이드바 + 넓은 본문
   ========================================================================= */
@media (min-width: 1200px) {
    :root { --content-max: 860px; }

    .shell { padding-left: var(--sidebar-w); }

    .sidenav {
        width: var(--sidebar-w);
        padding: 16px 12px;
    }
    .sidenav-brand { flex-direction: row; align-items: center; gap: 10px; padding: 6px 8px 16px; }
    .sidenav-wordmark { display: block; line-height: 1.15; }
    .sidenav-wordmark b { display: block; font-size: 14.5px; font-weight: 800; }
    .sidenav-wordmark small { font-size: 11px; color: var(--text-2); }

    .sidenav .navitem {
        flex-direction: row;
        justify-content: flex-start;
        gap: 12px;
        height: 46px;
        padding: 0 14px;
        font-size: 14px;
    }
    .sidenav .navitem .badge-dot { position: static; margin-left: auto; border: 0; }

    .topbar { left: var(--sidebar-w); }
    .toast { left: calc(50% + var(--sidebar-w) / 2); }

    /* 데스크톱 홈은 2단. DOM 순서(신분증 → 캘린더 → 요약 → 공지 → 링크)는 그대로 두고
       grid 배치만 바꾼다 — 캘린더가 왼쪽 큰 칸을 세로로 다 쓰고, 나머지가 오른쪽에 쌓인다. */
    .home-grid {
        display: grid;
        grid-template-columns: minmax(0, 1.35fr) minmax(320px, .9fr);
        gap: 16px;
        align-items: start;
        padding-inline: 16px;
    }
    .home-grid > * { min-width: 0; margin: 0; padding: 0; }

    /* 행은 지정하지 않는다 — 자동 배치라 신분증이 숨겨지면 바로가기가 알아서 위로 올라온다. */
    .home-cal    { grid-column: 1; grid-row: 1 / span 2; }
    .home-idcard { grid-column: 2; }
    .home-links  { grid-column: 2; }

    /* 바코드는 리더기에 대는 용도라 손에 드는 기기에서만 쓸모가 있다.
       데스크톱에서는 숨긴다. (아래에서 터치 기기는 예외로 되살린다) */
    .home-idcard { display: none; }

    /* 2단이 되면 각 조각이 스스로 갖고 있던 좌우 여백은 필요 없다 */
    .home-grid .idcard,
    .home-grid .card { margin-inline: 0; }
}

/* 큰 화면이라도 손가락을 쓰는 기기(가로로 놓은 태블릿 등)에서는 신분증을 그대로 둔다.
   폭이 아니라 "이 기기를 들고 다니느냐"가 기준이기 때문이다.
   data-pointer 는 실제 입력에 따라 js/app.js 가 바꾼다. */
html[data-pointer="touch"] .home-idcard { display: block; }

/* 아주 넓은 화면 — 본문을 더 넓게 쓰되 줄 길이는 제한 */
@media (min-width: 1600px) {
    :root { --content-max: 1120px; }
}

/* ============================================================================
   화면별 스타일
   ========================================================================= */

/* ── 홈 ──────────────────────────────────────────────────────────────── */
/* 1200px 미만에서는 한 줄로 쌓인다. 조각 사이 간격만 준다. */
.home-cal, .home-links { margin-top: 14px; }
.home-cal { padding-inline: 16px; }
.home-links > .card { margin-inline: 16px; }

/* ── 홈: 모바일 신분증 카드 ─────────────────────────────────────────────── */
.idcard {
    position: relative;
    margin: 0 16px;
    padding: 16px 18px 14px;
    border-radius: var(--r-lg);
    background: linear-gradient(135deg, var(--hknu-navy) 0%, var(--hknu-blue) 55%, var(--hknu-blue-400) 100%);
    color: #fff;
    box-shadow: var(--sh-2);
    cursor: pointer;
    overflow: hidden;
    user-select: none;
    touch-action: pan-x;          /* 아래로 미는 제스처를 우리가 처리한다 */
}
.idcard::before {
    content: '';
    position: absolute; right: -40px; top: -60px;
    width: 190px; height: 190px; border-radius: 50%;
    background: rgba(255,255,255,.07);
}
.idcard-top { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; position: relative; }
.idcard-top .who { flex: 1; min-width: 0; }
.idcard-top .who b { display: block; font-size: 16px; font-weight: 800; }
.idcard-top .who small {
    display: block;
    font-size: 11.5px; opacity: .8;
    /* 좁은 칸(데스크톱 오른쪽 열)에서 학번+학부가 두 줄로 접히지 않게 */
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.idcard-kind {
    padding: 3px 10px; border-radius: var(--r-pill);
    background: rgba(255,255,255,.18);
    font-size: 11px; font-weight: 700;
}

.barcode {
    background: #fff;
    border-radius: var(--r-md);
    padding: 10px 12px 6px;
    position: relative;
}
.barcode-bars { display: flex; align-items: flex-end; gap: 1px; height: 46px; }
.barcode-bars i { display: block; background: #101318; height: 100%; }
.barcode-num {
    text-align: center;
    font-family: ui-monospace, 'SFMono-Regular', Consolas, monospace;
    font-size: 11px; letter-spacing: 2px; color: #333;
    padding-top: 4px;
}
.idcard-hint {
    display: flex; align-items: center; justify-content: center; gap: 5px;
    font-size: 11px; opacity: .75; padding-top: 9px;
}

/* 전체화면 신분증 */
.idfull {
    position: fixed; inset: 0; z-index: 300;
    background: linear-gradient(160deg, var(--hknu-navy), var(--hknu-blue));
    color: #fff;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 20px;
    padding: calc(24px + var(--safe-top)) 24px calc(24px + var(--safe-bottom));
    animation: fadein 200ms var(--ease);
}
.idfull-close {
    position: absolute; top: calc(14px + var(--safe-top)); right: 14px;
    width: 42px; height: 42px; border-radius: 50%;
    background: rgba(255,255,255,.15); color: #fff; border: 0;
    display: grid; place-items: center; cursor: pointer;
}
.idfull-barcode {
    background: #fff; border-radius: var(--r-lg);
    padding: 28px 26px 18px;
    width: min(460px, 88vw);
    box-shadow: 0 20px 60px rgba(0,0,0,.35);
}
.idfull-barcode .barcode-bars { height: min(150px, 22vh); }
.idfull-barcode .barcode-num { font-size: 14px; padding-top: 12px; }
/* 전체화면 신분증의 사진. 어두운 배경 위라 흰 테두리로 카드에서 띄운다. */
.avatar.idfull-photo {
    width: min(112px, 26vw); height: min(112px, 26vw);
    border-radius: 28px;
    font-size: min(42px, 10vw);
    border: 3px solid rgba(255, 255, 255, .85);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .3);
}

.idfull-who { text-align: center; }
.idfull-who b { display: block; font-size: 24px; font-weight: 800; }
.idfull-who span { font-size: 13.5px; opacity: .85; }
.idfull-note { font-size: 12px; opacity: .7; text-align: center; max-width: 320px; }

/* ── 캘린더 ────────────────────────────────────────────────────────────── */
.cal-head {
    display: flex; align-items: center; gap: 6px;
    padding: 12px 16px 8px;
}
.cal-title { font-size: 17px; font-weight: 800; letter-spacing: -.3px; }
.cal-head .spacer { flex: 1; }

.cal-viewswitch {
    display: flex; gap: 2px; padding: 3px;
    background: var(--surface-sunken);
    border-radius: var(--r-pill);
}
.cal-viewswitch button {
    border: 0; background: none; cursor: pointer;
    padding: 5px 11px; border-radius: var(--r-pill);
    font-size: 12.5px; font-weight: 700; color: var(--text-2);
    transition: all var(--dur) var(--ease);
}
.cal-viewswitch button.on { background: var(--surface); color: var(--hknu-blue); box-shadow: var(--sh-1); }

.cal-dow {
    display: grid; grid-template-columns: repeat(7, 1fr);
    padding: 4px 8px 6px;
    font-size: 11.5px; font-weight: 700; color: var(--text-3);
    text-align: center;
}
.cal-dow .sun { color: var(--hknu-red); }
.cal-dow .sat { color: var(--hknu-blue); }

.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    padding: 0 8px 8px;
}
.cal-cell {
    position: relative;
    aspect-ratio: 1 / 1;
    min-height: 42px;
    display: flex; flex-direction: column; align-items: center;
    padding-top: 5px; gap: 3px;
    border: 0; background: none; cursor: pointer;
    border-radius: var(--r-sm);
    font-size: 13px; font-weight: 600; color: var(--text);
    transition: background var(--dur) var(--ease);
}
.cal-cell.out { color: var(--text-3); opacity: .45; }
.cal-cell.sun { color: var(--hknu-red); }
.cal-cell.sat { color: var(--hknu-blue); }
.cal-cell.today .num {
    background: var(--hknu-blue); color: #fff;
    border-radius: 50%; width: 25px; height: 25px;
    display: grid; place-items: center;
}
.cal-cell.sel { background: var(--brand-tint); }
.cal-cell.sel.today { background: var(--brand-tint-strong); }
@media (hover: hover) and (pointer: fine) {
    .cal-cell:hover { background: var(--surface-sunken); }
}
.cal-cell .num { line-height: 25px; height: 25px; }
.cal-dots { display: flex; gap: 2px; }
.cal-dots i { width: 4px; height: 4px; border-radius: 50%; }

/* 주간 / 일간 타임그리드 — 헤더 한 줄 + 본문(시각 눈금 열 + 날짜 열들) */
.tg { padding: 0 8px 10px; }

.tg-headrow { display: flex; border-bottom: 1px solid var(--line); }
.tg-headrow .tg-gutter { flex: none; width: 40px; }
.tg-dayhead {
    flex: 1 1 0; min-width: 0;
    text-align: center; padding: 4px 0 7px;
    font-size: 11px; font-weight: 600; color: var(--text-3);
}
.tg-dayhead b { display: block; font-size: 15px; font-weight: 700; color: var(--text); }
.tg-dayhead.today { color: var(--hknu-blue); }
.tg-dayhead.today b {
    color: #fff; background: var(--hknu-blue);
    width: 24px; height: 24px; line-height: 24px; border-radius: 50%;
    margin: 1px auto 0;
}

.tg-body { display: flex; }
.tg-body > .tg-gutter { flex: none; width: 40px; }

/* 눈금 칸과 슬롯의 높이가 정확히 같아야 이벤트 위치가 맞는다 (SlotPx = 46) */
.tg-hour {
    height: 46px;
    position: relative;
}
.tg-hour span {
    position: absolute; top: -7px; right: 6px;
    font-size: 10px; color: var(--text-3);
    background: var(--surface); padding-left: 2px;
}

.tg-col {
    position: relative;
    flex: 1 1 0; min-width: 0;
    border-left: 1px solid var(--line);
}
.tg-slot { height: 46px; border-top: 1px solid var(--line); }
.tg-slot:first-child { border-top: 0; }

.tg-ev {
    position: absolute; left: 2px; right: 2px;
    border-radius: 6px;
    padding: 4px 6px;
    font-size: 10.5px; font-weight: 600;
    color: #fff;
    overflow: hidden;
    cursor: pointer;
    line-height: 1.25;
}
.tg-ev small { display: block; opacity: .85; font-weight: 500; font-size: 9.5px; }
.tg-ev.k-lecture  { background: var(--k-lecture); }
.tg-ev.k-academic { background: var(--k-academic); }
.tg-ev.k-exam     { background: var(--k-exam); }
.tg-ev.k-personal { background: var(--k-personal); }
.tg-ev.k-holiday  { background: var(--k-holiday); color: #4a3800; }

/* 선택한 날의 일정 목록 */
.daylist { padding: 4px 16px 10px; border-top: 1px solid var(--line); }
.daylist-head {
    display: flex; align-items: baseline; gap: 8px;
    padding: 10px 0 6px;
}
.daylist-head b { font-size: 14px; font-weight: 700; }
.daylist-head span { font-size: 12px; color: var(--text-3); }

.ev {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 9px 0;
}
.ev + .ev { border-top: 1px dashed var(--line); }
/* 내가 만든 일정만 눌러서 고칠 수 있다 */
.ev.editable { cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
    .ev.editable:hover { background: var(--surface-2); }
}

/* 일정 종류 고르기 칩 앞의 색 점 */
.kinddot { width: 8px; height: 8px; border-radius: 3px; display: inline-block; }
.kinddot.k-lecture  { background: var(--k-lecture); }
.kinddot.k-academic { background: var(--k-academic); }
.kinddot.k-exam     { background: var(--k-exam); }
.kinddot.k-personal { background: var(--k-personal); }
.kinddot.k-holiday  { background: var(--k-holiday); }
.ev-bar { flex: none; width: 3px; align-self: stretch; border-radius: 3px; min-height: 32px; }
.ev-bar.k-lecture  { background: var(--k-lecture); }
.ev-bar.k-academic { background: var(--k-academic); }
.ev-bar.k-exam     { background: var(--k-exam); }
.ev-bar.k-personal { background: var(--k-personal); }
.ev-bar.k-holiday  { background: var(--k-holiday); }
.ev-body { flex: 1; min-width: 0; }
.ev-body b { display: block; font-size: 14px; font-weight: 600; }
.ev-body small { font-size: 11.5px; color: var(--text-2); }

.legend { display: flex; flex-wrap: wrap; gap: 10px; padding: 8px 16px 14px; }
.legend span { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--text-2); }
.legend i { width: 8px; height: 8px; border-radius: 3px; }

/* ── 링크 그리드 ────────────────────────────────────────────────────────── */
.linkgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
    gap: 4px;
    padding: 6px 10px 14px;
}
.linktile {
    display: flex; flex-direction: column; align-items: center; gap: 6px;
    padding: 12px 4px 10px;
    border: 0; background: none; cursor: pointer;
    border-radius: var(--r-md);
    transition: background var(--dur) var(--ease);
}
.linktile .ico {
    width: 46px; height: 46px; border-radius: 15px;
    display: grid; place-items: center;
    font-size: 22px;
    background: var(--surface-sunken);
    position: relative;
}
.linktile .ico .sso {
    position: absolute; right: -3px; bottom: -3px;
    width: 17px; height: 17px; border-radius: 50%;
    background: var(--hknu-teal); color: #fff;
    font-size: 9px; display: grid; place-items: center;
    border: 2px solid var(--surface);
}
.linktile span {
    font-size: 11px; font-weight: 600; color: var(--text-2);
    text-align: center; line-height: 1.25;
    word-break: keep-all;
}
.linktile:active { transform: scale(.94); }
@media (hover: hover) and (pointer: fine) {
    .linktile:hover { background: var(--surface-2); }
    .linktile:hover .ico { background: var(--brand-tint); }
}

/* ── 채팅 ──────────────────────────────────────────────────────────────── */
.chatroom { display: flex; flex-direction: column; flex: 1; min-height: 0; width: 100%; }
.chatlog {
    flex: 1; min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 14px 14px 8px;
    background: var(--surface-2);
    display: flex; flex-direction: column; gap: 10px;
}
/* 메시지가 몇 개 없어도 아래쪽에 붙어 있게 (카카오톡과 같은 느낌).
   justify-content:flex-end 는 넘칠 때 위쪽이 잘리므로 이 방법을 쓴다. */
.chatlog > *:first-child { margin-top: auto; }
.msg { display: flex; gap: 8px; align-items: flex-end; max-width: 84%; }
.msg.me { align-self: flex-end; flex-direction: row-reverse; }
.msg-bubble {
    padding: 9px 13px;
    border-radius: 16px 16px 16px 4px;
    background: var(--surface);
    box-shadow: var(--sh-1);
    font-size: 14px;
    word-break: break-word;
    white-space: pre-wrap;
}
.msg.me .msg-bubble {
    background: var(--hknu-blue); color: #fff;
    border-radius: 16px 16px 4px 16px;
}
.msg-meta { font-size: 10px; color: var(--text-3); flex: none; padding-bottom: 2px; }
.msg-who { font-size: 11.5px; color: var(--text-2); margin-bottom: 3px; font-weight: 600; }
.msg-col { min-width: 0; }
.msg-sys {
    align-self: center;
    font-size: 11.5px; color: var(--text-2);
    background: var(--surface-sunken);
    padding: 5px 14px; border-radius: var(--r-pill);
}
.chat-daysep {
    align-self: center;
    font-size: 11px; color: var(--text-3);
    padding: 2px 12px;
}

.chatbar {
    flex: none;
    display: flex; gap: 8px; align-items: flex-end;
    padding: 10px 12px calc(10px + var(--safe-bottom));
    background: var(--surface);
    border-top: 1px solid var(--line);
}
.chatbar .field { flex: 1; align-items: flex-end; }
.chatbar textarea { max-height: 110px; }
.chatbar .send {
    flex: none;
    width: 40px; height: 40px; border-radius: 50%;
    background: var(--hknu-blue); color: #fff;
    border: 0; cursor: pointer; display: grid; place-items: center;
}
.chatbar .send:disabled { background: var(--line-strong); cursor: default; }

/* 채팅방 목록 행 */
.roomrow .thumb { position: relative; flex: none; }
.roomrow .unread {
    flex: none;
    min-width: 20px; height: 20px; padding: 0 6px;
    border-radius: var(--r-pill);
    background: var(--hknu-red); color: #fff;
    font-size: 11px; font-weight: 700; line-height: 20px; text-align: center;
}

/* ── AI ───────────────────────────────────────────────────────────────── */
.ai-wrap { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.ai-log {
    flex: 1; min-height: 0; overflow-y: auto;
    padding: 12px 16px 8px;
    display: flex; flex-direction: column; gap: 14px;
}
.ai-turn { display: flex; gap: 10px; }
.ai-turn.user { flex-direction: row-reverse; }
.ai-face {
    flex: none; width: 30px; height: 30px; border-radius: 10px;
    display: grid; place-items: center; font-size: 15px;
    background: var(--brand-tint);
}
.ai-turn.user .ai-face { background: var(--surface-sunken); }
.ai-text {
    max-width: 82%;
    padding: 11px 14px;
    border-radius: 14px 14px 14px 4px;
    background: var(--surface);
    box-shadow: var(--sh-1);
    font-size: 14.2px; line-height: 1.62;
}
.ai-turn.user .ai-text {
    background: var(--hknu-blue); color: #fff;
    border-radius: 14px 14px 4px 14px;
}
.ai-sources {
    margin-top: 9px; padding-top: 8px;
    border-top: 1px dashed var(--line);
    display: flex; flex-direction: column; gap: 4px;
}
.ai-sources b { font-size: 10.5px; color: var(--text-3); font-weight: 700; }
.ai-sources span { font-size: 11.5px; color: var(--text-2); }

.ai-typing { display: flex; gap: 4px; padding: 4px 2px; }
.ai-typing i {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--text-3);
    animation: blink 1.2s infinite;
}
.ai-typing i:nth-child(2) { animation-delay: .2s; }
.ai-typing i:nth-child(3) { animation-delay: .4s; }
@keyframes blink { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }

.ai-suggest {
    display: flex; gap: 8px;
    padding: 6px 16px 10px;
    overflow-x: auto; scrollbar-width: none;
}
.ai-suggest::-webkit-scrollbar { display: none; }
.ai-suggest button {
    flex: none;
    padding: 8px 14px;
    border-radius: var(--r-pill);
    border: 1px solid var(--line-strong);
    background: var(--surface);
    font-size: 12.5px; color: var(--text-2);
    cursor: pointer; white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
    .ai-suggest button:hover { border-color: var(--hknu-blue-400); color: var(--hknu-blue); }
}

/* ── 검색 / 사이트맵 ────────────────────────────────────────────────────── */
.searchgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 8px;
    padding: 4px 16px 16px;
}
.searchtile {
    display: flex; align-items: center; gap: 10px;
    padding: 12px;
    border-radius: var(--r-md);
    background: var(--surface);
    border: 1px solid var(--line);
    cursor: pointer; text-align: left;
    transition: all var(--dur) var(--ease);
}
.searchtile .ico { font-size: 19px; flex: none; }
.searchtile b { display: block; font-size: 13.5px; font-weight: 600; }
.searchtile small { font-size: 11px; color: var(--text-3); }
@media (hover: hover) and (pointer: fine) {
    .searchtile:hover { border-color: var(--hknu-blue-400); background: var(--brand-tint); }
}

/* ── 진행 막대 ─────────────────────────────────────────────────────────── */
.meter {
    height: 7px; border-radius: 7px;
    background: var(--surface-sunken);
    overflow: hidden;
}
.meter i { display: block; height: 100%; border-radius: 7px; background: var(--hknu-blue); }
.meter i.warn { background: var(--warn); }
.meter i.danger { background: var(--danger); }
.meter i.ok { background: var(--ok); }

/* ── 표 ───────────────────────────────────────────────────────────────── */
.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.data {
    width: 100%; border-collapse: collapse;
    font-size: 13px;
    min-width: 460px;
}
table.data th, table.data td {
    padding: 10px 12px;
    text-align: left;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}
table.data th {
    font-size: 11.5px; font-weight: 700; color: var(--text-2);
    background: var(--surface-2);
    position: sticky; top: 0;
}
table.data td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ── 통계 타일 ─────────────────────────────────────────────────────────── */
.stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: 1px;
    background: var(--line);
    border-radius: var(--r-md);
    overflow: hidden;
    margin: 0 16px;
}
.stat { background: var(--surface); padding: 14px 10px; text-align: center; }
.stat b { display: block; font-size: 20px; font-weight: 800; letter-spacing: -.5px; }
.stat small { font-size: 11px; color: var(--text-2); }

/* 유틸 */
.mt8 { margin-top: 8px; } .mt12 { margin-top: 12px; } .mt16 { margin-top: 16px; }
.px16 { padding-inline: 16px; }
.muted { color: var(--text-2); }
.tiny { font-size: 11.5px; }
.center { text-align: center; }
.grow { flex: 1; }
.rowflex { display: flex; align-items: center; gap: 8px; }
.wrapflex { display: flex; flex-wrap: wrap; gap: 8px; }
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── 식단조회 ──────────────────────────────────────────────────────
   날짜 띠는 다섯 칸(월~금)을 균등 분할한다. 캘린더의 7칸과 달리
   주말이 없으므로 grid 로 고정해 폭이 흔들리지 않게 했다. */
.mealdays {
    display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px;
    padding-top: 10px;
}
.mealday {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 8px 0 9px; border: 1px solid var(--line);
    border-radius: var(--r-md); background: var(--surface);
    color: var(--text-2); cursor: pointer;
    transition: all var(--dur) var(--ease);
}
.mealday small { font-size: 11.5px; font-weight: 700; }
.mealday b { font-size: 16px; font-weight: 800; color: var(--text); }
.mealday.today { border-color: var(--hknu-blue); }
.mealday.on {
    background: var(--hknu-blue); border-color: var(--hknu-blue);
    color: #fff; box-shadow: var(--sh-1);
}
.mealday.on b { color: #fff; }

/* 반찬은 칩처럼 죽 늘어놓는다 — 줄 수가 날마다 달라 목록보다 이 편이 눕는다 */
.mealdishes {
    display: flex; flex-wrap: wrap; gap: 6px;
    padding: 2px 16px 14px;
}
.mealdishes span {
    padding: 5px 10px; border-radius: var(--r-pill);
    background: var(--surface-sunken);
    font-size: 13px; font-weight: 600; color: var(--text);
}
/* 첫 번째가 그날의 주 메뉴다. 눈이 먼저 가게 색을 준다. */
.mealdishes span:first-child {
    background: var(--brand-tint); color: var(--hknu-blue); font-weight: 700;
}

/* ── 규정 Q&A 근거 조문 ────────────────────────────────────────────
   답 밑에 접어 둔다. 가장 좋은 모델도 틀릴 때가 있어서, 학생이 조문을
   직접 보고 거를 수 있어야 한다. 그래서 펼치면 본문과 원문 PDF 가 나온다. */
.ai-sources {
    margin-top: 10px;
    border-top: 1px solid var(--line);
    padding-top: 8px;
}
.ai-sources > summary {
    cursor: pointer; list-style: none;
    font-size: 12px; font-weight: 700; color: var(--hknu-blue);
    padding: 2px 0;
}
.ai-sources > summary::-webkit-details-marker { display: none; }
.ai-sources > summary::before { content: "▸ "; }
.ai-sources[open] > summary::before { content: "▾ "; }

.ai-source { padding: 8px 0; border-bottom: 1px solid var(--line); }
.ai-source:last-child { border-bottom: 0; }
.ai-source-head {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    font-size: 12.5px;
}
.ai-source p {
    margin: 5px 0 6px;
    font-size: 12.5px; line-height: 1.65; color: var(--text-2);
    white-space: pre-wrap;
}
.ai-source a {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 11.5px; font-weight: 600; color: var(--hknu-blue);
}

/* 서비스에 못 닿았거나 속도 제한에 걸린 답 */
.ai-text.is-error { color: var(--danger); }

/* ══ 첫 화면 (/) ═══════════════════════════════════════════════════════
   들어가는 길을 둘로 나눈다 — 실제로 쓰는 챗봇과, 포털 화면 구성 미리보기.
   챗봇 쪽을 진하게 칠한 것은 그쪽이 실물이라서다. */
.start {
    min-height: 100dvh;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 32px 20px calc(32px + env(safe-area-inset-bottom));
    background: var(--surface-2);
}
.start-head { text-align: center; margin-bottom: 28px; }
.start-head img { display: block; margin: 0 auto 12px; }
.start-head h1 { font-size: 24px; font-weight: 900; color: var(--text); margin: 0; }
.start-head p { margin: 6px 0 0; font-size: 15px; color: var(--text-2); }

.start-cards {
    width: 100%; max-width: 760px;
    display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
}
@media (max-width: 640px) {
    .start-cards { grid-template-columns: 1fr; }
}

.start-card {
    display: flex; flex-direction: column; gap: 6px;
    padding: 26px 24px 22px;
    border-radius: var(--r-xl);
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: var(--sh-1);
    color: var(--text); text-decoration: none;
    transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.start-card:active { transform: scale(.98); }
@media (hover: hover) and (pointer: fine) {
    .start-card:hover { transform: translateY(-2px); box-shadow: var(--sh-2); }
}
.start-ico { font-size: 34px; line-height: 1; margin-bottom: 8px; }
.start-card b { font-size: 21px; font-weight: 900; }
.start-sub { font-size: 14px; font-weight: 700; color: var(--hknu-blue); }
.start-desc { font-size: 14.5px; line-height: 1.6; color: var(--text-2); margin-top: 4px; flex: 1; }
.start-go { margin-top: 14px; font-size: 15px; font-weight: 800; color: var(--hknu-blue); }

.start-card.is-ai {
    background: linear-gradient(150deg, var(--hknu-blue), var(--hknu-navy));
    border-color: transparent; color: #fff;
}
.start-card.is-ai .start-sub,
.start-card.is-ai .start-go { color: #fff; }
.start-card.is-ai .start-desc { color: rgba(255,255,255,.86); }

.start-foot {
    max-width: 760px; margin: 22px 0 0;
    font-size: 13px; color: var(--text-3); text-align: center; line-height: 1.6;
}

/* ══ 챗봇 전체화면 (/chat) ═════════════════════════════════════════════
   포털 셸 없이 대화만. 글씨를 포털 AI 탭(14.2px)보다 크게 — 학생이 폰으로
   규정을 읽는 화면이라 읽기 편한 쪽을 택했다. 여기 규칙은 전부 .chatfull 아래로
   묶어서 포털의 AI 탭에는 닿지 않는다. */
.chatfull {
    height: 100dvh;
    display: flex; flex-direction: column;
    max-width: 880px; margin: 0 auto;
    background: var(--surface-2);
}

.chatfull-head {
    flex: none;
    display: flex; align-items: center; gap: 8px;
    padding: calc(10px + env(safe-area-inset-top)) 10px 10px;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}
.chatfull-head h1 {
    flex: 1; margin: 0; text-align: center;
    font-size: 19px; font-weight: 900; color: var(--text);
}
.chatfull-back, .chatfull-reset {
    flex: none; display: inline-flex; align-items: center; gap: 2px;
    min-height: 44px; padding: 0 10px;
    border: 0; background: none; cursor: pointer;
    border-radius: var(--r-md);
    font-size: 16px; font-weight: 700; color: var(--text-2);
}
/* 제목이 가운데 오도록 오른쪽 버튼 폭을 왼쪽과 맞춘다 */
.chatfull-reset { min-width: 92px; justify-content: flex-end; }
@media (hover: hover) and (pointer: fine) {
    .chatfull-back:hover, .chatfull-reset:hover { background: var(--surface-2); }
}

/* 주제 — [규정 문답] [학교 안내]. 제목 바로 아래, 가운데. 아래 안내와 한 덩어리로 보이게 같은 바탕. */
.chatfull-topics {
    flex: none;
    display: flex; justify-content: center; gap: 8px;
    padding: 10px 14px 2px;
    background: var(--surface);
}
.chatfull-topics .chip { font-size: 15.5px; min-height: 42px; padding: 8px 20px; }

/* 맨 위 안내 — 주제 바로 아래, 작게. 대화 중에도 늘 보인다. */
.chatfull-info {
    flex: none;
    padding: 8px 16px 10px;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}
.chatfull-info p {
    margin: 0; font-size: 12.5px; line-height: 1.6; color: var(--text-2);
}
.chatfull-info p + p { margin-top: 4px; }
/* 돈이 드는 버튼의 이름만 붉게 — 챗봇 전체화면과 포털 AI 탭의 맨 위 안내가 같이 쓴다 */
.cloud-name { color: var(--hknu-red); font-weight: 800; }
/* 포털 AI 탭 — 학습·취업·인성 상담이 아직 예시 답변이라는 안내. 같은 붉은색으로 */
.demo-note { margin: 0; padding-top: 2px; color: var(--hknu-red); font-weight: 700; }

.chatfull-log {
    flex: 1; min-height: 0; overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 16px 14px 8px;
    display: flex; flex-direction: column; gap: 14px;
}
.chatfull-log > *:first-child { margin-top: auto; }

/* 글씨 크게 */
.chatfull .ai-text { font-size: 18px; line-height: 1.7; max-width: 88%; padding: 14px 18px; }
.chatfull .ai-face { font-size: 26px; }
.chatfull .ai-sources > summary { font-size: 15.5px; padding: 4px 0; }
.chatfull .ai-source-head { font-size: 15.5px; }
.chatfull .ai-source p { font-size: 16px; line-height: 1.75; }
.chatfull .ai-source a { font-size: 15px; }
.chatfull .ai-text .tiny { font-size: 14px; }
.chatfull .ai-text .btn.sm { font-size: 15.5px; min-height: 42px; padding: 0 16px; }

/* 한 줄 가로 스크롤이었는데 PC 에서 마지막 칩이 잘려 보이고 넘길 방법도 마땅치 않았다.
   줄을 바꿔 전부 보이게 한다. 칩 하나가 폰 폭보다 길면 그 안에서도 줄을 바꾼다. */
.chatfull-suggest {
    flex: none; display: flex; flex-wrap: wrap; gap: 8px;
    padding: 6px 14px 10px;
}
.chatfull-suggest button {
    max-width: 100%; padding: 9px 14px;
    border-radius: var(--r-pill);
    border: 1px solid var(--line-strong);
    background: var(--surface);
    font-size: 14.5px; color: var(--text-2); text-align: left;
    cursor: pointer; white-space: nowrap;
}
/* 폭이 모자라는 화면(폰)에서는 칩 안에서도 줄을 바꿔 잘리지 않게 */
@media (max-width: 720px) {
    .chatfull-suggest button { white-space: normal; }
}

.chatfull-bar {
    flex: none; display: flex; align-items: flex-end; gap: 8px;
    padding: 10px 14px calc(12px + env(safe-area-inset-bottom));
    background: var(--surface);
    border-top: 1px solid var(--line);
}
.chatfull-bar .field { flex: 1; }
.chatfull-bar textarea { font-size: 18px; line-height: 1.5; }
.chatfull-bar .send { width: 52px; height: 52px; }

/* 사이드바 로고가 첫 화면으로 가는 링크가 되면서 <a> 로 바뀌었다.
   링크 색·밑줄이 붙지 않게 예전 모양 그대로 둔다. */
a.sidenav-brand { color: inherit; text-decoration: none; }
a.sidenav-brand:focus-visible { outline: 2px solid var(--hknu-blue); outline-offset: 2px; border-radius: var(--r-md); }

/* 폰 상단바의 첫 화면 버튼. 사이드바가 보이는 768px 이상에서는 로고가 대신한다. */
.topbar-start {
    flex: none; display: grid; place-items: center;
    width: var(--tap, 40px); height: var(--tap, 40px);
    margin-right: 2px; border-radius: var(--r-md);
}
.topbar-start img { display: block; width: 28px; height: 28px; }
.topbar-start:active { transform: scale(.94); }
@media (min-width: 768px) { .topbar-start { display: none; } }

/* [더 자세한 답 보기] 앞의 안내. 돈이 드는 버튼이라 누르기 전에 눈에 띄게 붉은 계열로. */
.cloud-note {
    margin-top: 12px;
    padding: 10px 12px;
    border-left: 3px solid var(--hknu-red);
    border-radius: var(--r-sm);
    background: color-mix(in srgb, var(--hknu-red) 9%, transparent);
    color: var(--hknu-red);
    font-size: 12.5px; font-weight: 600; line-height: 1.6;
}
.cloud-btn { border-color: color-mix(in srgb, var(--hknu-red) 45%, transparent); }
.chatfull .cloud-note { font-size: 15px; }

/* 답 아래 버튼 줄 — [복사] [더 자세한 답 보기] */
.ai-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.ai-actions .btn.sm { min-height: 34px; }

/* ── [더 자세한 답 보기] 앞 숫자 4자리 잠금 창 ─────────────────────────── */
.pin-scrim {
    position: fixed; inset: 0; z-index: 900;
    background: rgba(0,0,0,.42);
}
.pin-dialog {
    position: fixed; z-index: 901;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(320px, calc(100vw - 40px));
    padding: 22px 20px 18px;
    border-radius: var(--r-xl);
    background: var(--surface);
    box-shadow: var(--sh-3);
    text-align: center;
}
.pin-dialog > b { display: block; font-size: 17px; font-weight: 800; color: var(--text); }
.pin-dialog > p { margin: 8px 0 14px; font-size: 14px; color: var(--text-2); }
.pin-input {
    width: 100%; box-sizing: border-box;
    padding: 12px 0;
    border: 1.5px solid var(--line-strong); border-radius: var(--r-md);
    background: var(--surface-2); color: var(--text);
    font-size: 26px; font-weight: 800; letter-spacing: .6em; text-indent: .6em;
    text-align: center;
}
.pin-input:focus { outline: none; border-color: var(--hknu-blue); }
.pin-input.is-wrong { border-color: var(--hknu-red); animation: pin-shake .3s; }
@keyframes pin-shake {
    20%, 60% { transform: translateX(-6px); }
    40%, 80% { transform: translateX(6px); }
}
.pin-dialog .pin-error { margin: 8px 0 0; font-size: 13px; font-weight: 700; color: var(--hknu-red); }
.pin-actions { display: flex; gap: 8px; margin-top: 16px; }
.pin-actions .btn { flex: 1; }
