@import url('https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400;500;600;700;800&display=swap'); :root { --font-sans: 'Be Vietnam Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; --bg-app: #f5f7fa; --bg-card: #ffffff; --bg-sidebar: #ffffff; --bg-subtle: #f0f3f7; --border-color: #e4e9f0; --border-light: #eef1f6; --accent: #bb2126; --accent-dark: #9e1c22; --accent-light: #fde8e9; --accent-hover: #a01d22; --accent-glow: rgba(187, 33, 38, 0.12); --text-primary: #1a2332; --text-secondary: #5a6a7e; --text-muted: #8b99a8; --success: #0d9f6e; --success-light: #e6f7f1; --success-glow: rgba(13, 159, 110, 0.1); --warning: #e6a817; --danger: #d63031; --danger-light: #fdeaea; --shadow-sm: 0 1px 3px rgba(26, 35, 50, 0.05); --shadow-md: 0 4px 16px rgba(26, 35, 50, 0.07); --shadow-lg: 0 8px 32px rgba(26, 35, 50, 0.09); --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; --transition: all 0.2s ease; } * { box-sizing: border-box; margin: 0; padding: 0; } html { height: 100%; overflow: hidden; } body { font-family: var(--font-sans); background-color: var(--bg-app); color: var(--text-primary); height: 100%; overflow: hidden; -webkit-font-smoothing: antialiased; } ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: var(--bg-subtle); } ::-webkit-scrollbar-thumb { background: #c5cdd8; border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { background: var(--accent); } #root { height: 100vh; max-height: 100vh; overflow: hidden; display: flex; } /* ── Sidebar ── */ .sidebar { width: 272px; background-color: var(--bg-sidebar); border-right: 1px solid var(--border-color); display: flex; flex-direction: column; padding: 1.25rem 1.25rem; position: fixed; height: 100vh; max-height: 100vh; overflow: hidden; z-index: 10; box-shadow: var(--shadow-sm); } .sidebar > nav { flex: 1; min-height: 0; overflow-y: auto; margin: 0 -0.25rem; padding: 0 0.25rem; } .brand { display: flex; align-items: center; gap: 0.85rem; margin-bottom: 1.25rem; padding: 0 0.5rem; flex-shrink: 0; } .brand-logo-img { width: 42px; height: 42px; border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } .brand-logo { width: 42px; height: 42px; background: var(--accent); border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 0.85rem; color: white; letter-spacing: -0.5px; flex-shrink: 0; } .brand-text { display: flex; flex-direction: column; gap: 0.1rem; } .brand-name { font-size: 1.05rem; font-weight: 800; color: var(--text-primary); letter-spacing: -0.3px; line-height: 1.2; } .brand-sub { font-size: 0.72rem; font-weight: 500; color: var(--accent); letter-spacing: 0.02em; } .nav-links { list-style: none; display: flex; flex-direction: column; gap: 0.25rem; } .nav-header { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; color: var(--text-muted); letter-spacing: 0.08em; margin: 1.25rem 0.75rem 0.35rem; } .nav-item { width: 100%; } .nav-btn { width: 100%; padding: 0.7rem 0.85rem; background: transparent; border: none; border-radius: var(--radius-sm); color: var(--text-secondary); font-size: 0.9rem; font-weight: 500; font-family: var(--font-sans); cursor: pointer; display: flex; align-items: center; gap: 0.7rem; text-align: left; transition: var(--transition); position: relative; } .nav-btn:hover { background-color: var(--bg-subtle); color: var(--text-primary); } .nav-btn.active { background-color: var(--accent-light); color: var(--accent); font-weight: 600; } .nav-btn.active::before { content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 3px; height: 60%; background: var(--accent); border-radius: 0 3px 3px 0; } .nav-icon { display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; flex-shrink: 0; } .nav-icon svg { width: 18px; height: 18px; } .sidebar-footer { margin-top: auto; border-top: 1px solid var(--border-light); padding-top: 1rem; display: flex; flex-direction: column; gap: 0.5rem; flex-shrink: 0; } .sidebar-user-btn { width: 100%; text-align: left; border: 1px solid transparent; border-radius: var(--radius-sm); background: none; padding: 0.5rem 0.6rem; cursor: pointer; display: flex; flex-direction: column; gap: 0.15rem; transition: background 0.15s, border-color 0.15s; } .sidebar-user-btn:hover { background: var(--bg-subtle); } .sidebar-user-btn.active { background: var(--accent-light); border-color: var(--accent); } .sidebar-user-btn.active .sidebar-user-name, .sidebar-user-btn.active .sidebar-user-email { color: var(--accent); } .sidebar-user-name { font-size: 0.82rem; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .sidebar-user-email { font-size: 0.72rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .token-badge { background-color: var(--bg-subtle); border: 1px solid var(--border-color); border-radius: var(--radius-sm); padding: 0.5rem 0.75rem; font-size: 0.75rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 0.4rem; } .token-badge::before { content: ''; width: 6px; height: 6px; background: var(--success); border-radius: 50%; flex-shrink: 0; } /* ── Main Content ── */ .main-content { margin-left: 272px; flex: 1; height: 100vh; max-height: 100vh; min-width: 0; padding: 1rem 1.5rem; display: flex; flex-direction: column; overflow: hidden; } .page-viewport { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; } /* ── Tab pages (fill viewport, scroll inside) ── */ .tab-page { height: 100%; display: flex; flex-direction: column; min-height: 0; overflow: hidden; gap: 0.75rem; } .tab-page-toolbar { flex-shrink: 0; display: flex; flex-direction: column; gap: 0.75rem; } .tab-page-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; } .tab-page-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 1rem; padding-right: 0.15rem; } .tab-page-footer { flex-shrink: 0; } .table-fill { flex: 1; min-height: 0; overflow: auto; } .table-fill .data-table thead { position: sticky; top: 0; z-index: 2; } .page-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; } .page-title h1 { font-size: 1.65rem; font-weight: 800; letter-spacing: -0.4px; margin-bottom: 0.3rem; color: var(--text-primary); } .page-title p { color: var(--text-secondary); font-size: 0.9rem; line-height: 1.5; } /* ── Stats Cards ── */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.25rem; } .stat-card { background-color: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 1.35rem 1.5rem; display: flex; align-items: center; justify-content: space-between; transition: var(--transition); box-shadow: var(--shadow-sm); } .stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: #d0d8e4; } .stat-label { font-size: 0.8rem; color: var(--text-muted); margin-bottom: 0.4rem; font-weight: 500; } .stat-value { font-size: 2rem; font-weight: 800; color: var(--text-primary); letter-spacing: -0.5px; } .stat-icon { width: 48px; height: 48px; border-radius: var(--radius-md); background-color: var(--accent-light); display: flex; align-items: center; justify-content: center; font-size: 1.35rem; flex-shrink: 0; } .stat-icon.success { background-color: var(--success-light); } /* ── Content Cards ── */ .content-card { background-color: var(--bg-card); border: 1px solid var(--border-color); padding: 1.75rem; border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); } .content-card h2 { font-size: 1.05rem; font-weight: 700; color: var(--text-primary); margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.5rem; } .content-card p { color: var(--text-secondary); font-size: 0.9rem; line-height: 1.65; margin-bottom: 1.25rem; } .content-grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 1.25rem; } /* ── Control Bar ── */ .control-bar { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; justify-content: space-between; background-color: var(--bg-card); border: 1px solid var(--border-color); padding: 1rem 1.25rem; border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); } .search-input-wrapper { position: relative; flex: 1; max-width: 300px; } .search-input { width: 100%; background-color: var(--bg-subtle); border: 1px solid var(--border-color); padding: 0.65rem 1rem 0.65rem 2.35rem; border-radius: var(--radius-sm); color: var(--text-primary); font-family: var(--font-sans); font-size: 0.875rem; transition: var(--transition); } .search-input:focus { outline: none; border-color: var(--accent); background-color: #fff; box-shadow: 0 0 0 3px var(--accent-glow); } .search-icon { position: absolute; left: 0.8rem; top: 50%; transform: translateY(-50%); color: var(--text-muted); font-size: 0.9rem; pointer-events: none; } .filters-wrapper { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; } .select-filter { background-color: var(--bg-subtle); border: 1px solid var(--border-color); padding: 0.65rem 1rem; border-radius: var(--radius-sm); color: var(--text-primary); font-family: var(--font-sans); font-size: 0.875rem; cursor: pointer; outline: none; transition: var(--transition); } .select-filter:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); } /* ── Buttons ── */ .btn { padding: 0.65rem 1.15rem; border: none; border-radius: var(--radius-sm); font-family: var(--font-sans); font-weight: 600; font-size: 0.875rem; cursor: pointer; display: inline-flex; align-items: center; gap: 0.45rem; transition: var(--transition); white-space: nowrap; } .btn-primary { background: var(--accent); color: white; box-shadow: 0 2px 8px var(--accent-glow); } .btn-primary:hover:not(:disabled) { background: var(--accent-hover); box-shadow: 0 4px 14px rgba(187, 33, 38, 0.25); transform: translateY(-1px); } .btn-secondary { background-color: #ffffff; border: 1px solid var(--border-color); color: var(--text-primary); } .btn-secondary:hover:not(:disabled) { background-color: var(--bg-subtle); border-color: #c5cdd8; } .btn:disabled { opacity: 0.55; cursor: not-allowed; } /* ── Sync Banner ── */ .sync-progress-banner { background: #fff; border: 1px solid var(--border-color); border-left: 4px solid var(--accent); padding: 1.15rem 1.35rem; border-radius: var(--radius-md); display: flex; flex-direction: column; gap: 0.65rem; box-shadow: var(--shadow-sm); } .sync-header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem; } .sync-title { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; font-size: 0.9rem; color: var(--text-primary); } .sync-spinner { width: 16px; height: 16px; border: 2px solid var(--border-color); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; flex-shrink: 0; } .sync-bar-container { height: 6px; background-color: var(--bg-subtle); border-radius: 99px; overflow: hidden; } .sync-bar { height: 100%; background: var(--accent); border-radius: 99px; transition: width 0.3s ease; } .sync-meta { display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--text-muted); } @keyframes spin { to { transform: rotate(360deg); } } /* ── Tables ── */ .table-wrapper { background-color: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm); } .data-table { width: 100%; border-collapse: collapse; text-align: left; } .data-table th { background-color: var(--bg-subtle); color: var(--text-muted); font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.9rem 1.25rem; border-bottom: 1px solid var(--border-color); } .data-table td { padding: 0.9rem 1.25rem; border-bottom: 1px solid var(--border-light); color: var(--text-primary); font-size: 0.875rem; } .data-table tbody tr { transition: var(--transition); } .data-table tbody tr:hover { background-color: #fafbfc; } .data-table tbody tr:last-child td { border-bottom: none; } /* ── Toggle Switch ── */ .switch-container { display: inline-flex; align-items: center; gap: 0.5rem; } .switch { position: relative; display: inline-block; width: 44px; height: 24px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #d0d8e4; transition: 0.2s; border-radius: 34px; } .slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 3px; bottom: 3px; background-color: white; transition: 0.2s; border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,0.15); } input:checked + .slider { background-color: var(--success); } input:checked + .slider:before { transform: translateX(20px); } /* ── Badges ── */ .badge { display: inline-flex; align-items: center; padding: 0.2rem 0.6rem; border-radius: 6px; font-size: 0.75rem; font-weight: 600; } .badge-success { background-color: var(--success-light); color: var(--success); border: 1px solid rgba(13, 159, 110, 0.2); } .badge-muted { background-color: var(--bg-subtle); color: var(--text-secondary); border: 1px solid var(--border-color); } .badge-info { background-color: var(--accent-light); color: var(--accent); border: 1px solid rgba(187, 33, 38, 0.2); } .badge-warning { background-color: #fff8e6; color: #b45309; border: 1px solid rgba(180, 83, 9, 0.25); } .courses-tag-list { display: flex; flex-wrap: wrap; gap: 0.3rem; max-width: 320px; } .course-tag { background-color: var(--bg-subtle); border: 1px solid var(--border-color); padding: 0.15rem 0.45rem; border-radius: 4px; font-size: 0.75rem; color: var(--text-secondary); } /* ── Pagination ── */ .pagination-row { display: flex; align-items: center; justify-content: space-between; margin-top: 1rem; font-size: 0.85rem; color: var(--text-muted); } .pagination-btn-group { display: flex; gap: 0.4rem; } .pagination-btn { background-color: var(--bg-card); border: 1px solid var(--border-color); color: var(--text-primary); width: 34px; height: 34px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--transition); font-size: 0.85rem; } .pagination-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); background-color: var(--accent-light); } .pagination-btn:disabled { opacity: 0.35; cursor: not-allowed; } /* ── Empty / Loading States ── */ .empty-state { padding: 3.5rem 2rem; text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.75rem; color: var(--text-secondary); } .empty-state-icon { font-size: 2.5rem; opacity: 0.5; } .empty-state h2 { font-size: 1rem; font-weight: 700; color: var(--text-primary); } .empty-state p { font-size: 0.875rem; color: var(--text-muted); max-width: 360px; } .loading-screen { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; min-height: 0; gap: 1rem; background: var(--bg-app); color: var(--text-primary); } /* ── Modals ── */ .modal-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(26, 35, 50, 0.45); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 1.5rem; } .modal-container { background-color: #ffffff; border: 1px solid var(--border-color); width: 100%; max-width: 800px; max-height: 85vh; border-radius: var(--radius-lg); display: flex; flex-direction: column; box-shadow: var(--shadow-lg); animation: modalScaleUp 0.25s ease; overflow: hidden; } @keyframes modalScaleUp { from { transform: scale(0.97); opacity: 0; } to { transform: scale(1); opacity: 1; } } .modal-header { padding: 1.25rem 1.75rem; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; gap: 1rem; } .modal-title { font-size: 1.1rem; font-weight: 700; color: var(--text-primary); } .modal-close-btn { background: var(--bg-subtle); border: 1px solid var(--border-color); border-radius: var(--radius-sm); width: 32px; height: 32px; font-size: 1rem; color: var(--text-secondary); cursor: pointer; transition: var(--transition); display: flex; align-items: center; justify-content: center; } .modal-close-btn:hover { background: var(--accent-light); color: var(--accent); border-color: rgba(187, 33, 38, 0.3); } .modal-body { padding: 1.75rem; overflow-y: auto; flex: 1; } .modal-footer { padding: 1rem 1.75rem; border-top: 1px solid var(--border-color); display: flex; justify-content: flex-end; gap: 0.75rem; } .detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; background-color: var(--bg-subtle); border: 1px solid var(--border-color); padding: 1.15rem; border-radius: var(--radius-md); } .detail-item-label { font-size: 0.72rem; color: var(--text-muted); text-transform: uppercase; font-weight: 600; letter-spacing: 0.04em; } .detail-item-value { font-size: 0.95rem; font-weight: 600; color: var(--text-primary); margin-top: 0.2rem; } /* ── Live Proctor Modal ── */ .proctor-container { max-width: min(98vw, 1280px); width: min(98vw, 1280px); max-height: 96vh; display: flex; flex-direction: column; overflow: hidden; } .proctor-content { padding: 1rem 1.25rem 1.25rem; overflow-y: auto; flex: 1; min-height: 0; } .proctor-panel { border: 1px solid var(--border-color); border-radius: var(--radius-md); overflow: hidden; background: var(--bg-subtle); } .panel-title { padding: 0.65rem 1rem; font-size: 0.8rem; font-weight: 700; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.04em; background: #fff; border-bottom: 1px solid var(--border-color); } .panel-title-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.5rem 0.65rem; background: #fff; border-bottom: 1px solid var(--border-color); flex-wrap: wrap; } .panel-title-text { font-size: 0.78rem; font-weight: 700; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap; } .panel-toolbar { display: flex; align-items: center; gap: 0.25rem; flex-wrap: wrap; } .proctor-tool-btn { min-width: 28px; height: 28px; padding: 0 0.4rem; border: 1px solid var(--border-color); border-radius: 6px; background: var(--bg-subtle); color: var(--text-primary); font-size: 0.82rem; font-weight: 700; cursor: pointer; font-family: var(--font-sans); line-height: 1; transition: var(--transition); } .proctor-tool-btn:hover { border-color: var(--accent); color: var(--accent); background: #fff; } .proctor-tool-btn-wide { padding: 0 0.55rem; font-size: 0.72rem; font-weight: 600; min-width: auto; } .proctor-zoom-label { font-size: 0.72rem; font-weight: 700; color: var(--text-muted); min-width: 2.5rem; text-align: center; font-family: monospace; } .proctor-stream-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; } .proctor-stream-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; } .proctor-action-btn { padding: 0.4rem 0.75rem !important; font-size: 0.78rem !important; } .proctor-action-btn.active { border-color: var(--accent); color: var(--accent); background: #fff5f5; } .proctor-zoom-viewport { width: 100%; height: 100%; min-height: inherit; overflow: auto; display: flex; align-items: center; justify-content: center; background: #1a2332; } .proctor-zoom-viewport .live-frame { transform-origin: center center; transition: transform 0.15s ease; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; } .proctor-zoom-viewport--webcam { min-height: 180px; } .screen-panel--fullscreen { background: #000; } .screen-panel--fullscreen .screen-body { min-height: 100vh; height: 100vh; } .screen-panel--fullscreen .proctor-zoom-viewport { min-height: calc(100vh - 44px); } .screen-panel--fullscreen .panel-title-row { background: #111; border-color: #333; color: #eee; } .screen-panel--fullscreen .panel-title-text { color: #ccc; } .screen-panel--fullscreen .proctor-tool-btn { background: #222; border-color: #444; color: #eee; } .panel-body { min-height: 280px; display: flex; flex-direction: column; align-items: stretch; justify-content: center; background: #1a2332; position: relative; padding: 0; overflow: hidden; } .screen-body { min-height: min(58vh, 620px); cursor: zoom-in; } .screen-panel--fullscreen .screen-body { cursor: default; } .webcam-body { min-height: 200px; } .proctor-grid-focus { display: grid; grid-template-columns: 1fr minmax(240px, 300px); gap: 1rem; align-items: start; } .proctor-grid-focus .screen-body { min-height: min(62vh, 680px); } .proctor-grid-focus.proctor-grid--no-webcam { grid-template-columns: 1fr; } .proctor-grid-focus.proctor-grid--no-webcam .screen-body { min-height: min(68vh, 720px); } .proctor-grid-default { display: grid; grid-template-columns: 1fr 280px; gap: 1.25rem; } @media (max-width: 900px) { .proctor-grid-focus, .proctor-grid-default { grid-template-columns: 1fr; } .proctor-grid-focus .screen-body { min-height: min(50vh, 480px); } } .proctor-actions { display: flex; align-items: center; gap: 0.75rem; } .status-pill { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0.75rem; border-radius: 99px; font-size: 0.8rem; font-weight: 600; } .status-pill.connecting { background: #fff8e6; color: #b8860b; border: 1px solid rgba(230, 168, 23, 0.3); } .status-pill.connected { background: var(--success-light); color: var(--success); border: 1px solid rgba(13, 159, 110, 0.25); } .status-pill.disconnected { background: var(--danger-light); color: var(--danger); border: 1px solid rgba(214, 48, 49, 0.25); } .live-frame { width: 100%; height: 100%; object-fit: contain; display: block; } .no-stream-placeholder { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; color: #8b99a8; padding: 2rem; text-align: center; } .no-stream-placeholder p { font-size: 0.85rem; } .placeholder-icon { font-size: 2rem; opacity: 0.4; } .alert-error { background: var(--danger-light); color: var(--danger); padding: 0.75rem 1rem; border-radius: var(--radius-sm); font-size: 0.875rem; border: 1px solid rgba(214, 48, 49, 0.2); } .proctor-stream-wrap { display: flex; flex-direction: column; gap: 0.65rem; } .proctor-stream-status { display: flex; justify-content: flex-end; } .proctor-stream-error { margin: 0; padding: 0.5rem 0.75rem; font-size: 0.82rem; } .proctor-grid-compact .screen-body { min-height: min(50vh, 480px); } .student-detail-overlay { z-index: 1050; } .student-detail-modal { max-width: 960px; width: min(96vw, 960px); max-height: 92vh; display: flex; flex-direction: column; overflow: hidden; } .student-detail-modal--proctor { max-width: min(98vw, 1280px); width: min(98vw, 1280px); max-height: 96vh; } .student-detail-modal--proctor .student-detail-body { flex: 1; min-height: 0; overflow: hidden; } .student-detail-modal--proctor .student-detail-info { flex-shrink: 0; } .student-detail-modal--proctor .student-detail-proctor { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; } .student-detail-modal--proctor .proctor-stream-wrap { flex: 1; min-height: 0; overflow: hidden; } .student-detail-modal--proctor .proctor-grid-focus { flex: 1; min-height: 0; } .student-detail-modal--proctor .screen-panel { display: flex; flex-direction: column; min-height: 0; } .student-detail-modal--proctor .screen-body { flex: 1; min-height: min(62vh, 680px); } .student-detail-header { display: flex; align-items: center; gap: 0.85rem; } .student-detail-body { display: flex; flex-direction: column; gap: 1rem; padding: 1rem 1.25rem 1.25rem; overflow-y: auto; min-height: 0; } .student-detail-info { display: flex; flex-direction: column; gap: 0.85rem; } .student-detail-meta { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.65rem; } .student-meta-item { background: var(--bg-subtle); border: 1px solid var(--border-light); border-radius: 8px; padding: 0.55rem 0.7rem; display: flex; flex-direction: column; gap: 0.2rem; } .student-meta-label { font-size: 0.68rem; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; } .student-meta-value { font-size: 0.88rem; font-weight: 600; color: var(--text-primary); } .student-meta-value.online { color: var(--success); } .student-detail-proctor { border-top: 1px solid var(--border-color); padding-top: 1rem; } /* ── Workspace (ClassWorkspace) ── */ .workspace-layout { display: flex; flex-direction: column; gap: 0.75rem; color: var(--text-primary); height: 100%; min-height: 0; overflow: hidden; width: 100%; } .workspace-header { background: #fff; border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 1rem 1.35rem; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; box-shadow: var(--shadow-sm); flex-shrink: 0; } .class-badge-container { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.4rem; flex-wrap: wrap; } .workspace-grid { display: grid; grid-template-columns: minmax(280px, 360px) 1fr; gap: 1rem; flex: 1; min-height: 0; overflow: hidden; } .workspace-main { display: flex; flex: 1; min-height: 0; overflow: hidden; position: relative; } .workspace-content-panel { flex: 1; min-width: 0; } .workspace-config-toggle.active { border-color: var(--accent); color: var(--accent); background: var(--accent-light, #fff5f5); } .workspace-drawer-backdrop { position: absolute; inset: 0; background: rgba(15, 23, 42, 0.35); z-index: 20; } .workspace-config-drawer { position: absolute; top: 0; left: 0; bottom: 0; width: min(460px, calc(100vw - 1.5rem)); z-index: 30; background: #fff; border-right: 1px solid var(--border-color); box-shadow: var(--shadow-lg); display: flex; flex-direction: column; transform: translateX(-105%); transition: transform 0.28s ease; pointer-events: none; overflow: hidden; } .workspace-config-drawer.open { transform: translateX(0); pointer-events: auto; } .workspace-drawer-header { display: flex; align-items: center; justify-content: space-between; padding: 0.85rem 1rem; border-bottom: 1px solid var(--border-color); flex-shrink: 0; } .workspace-drawer-close { padding: 0.25rem 0.55rem !important; font-size: 1.1rem !important; line-height: 1; } .workspace-drawer-tabs { display: flex; gap: 0.35rem; padding: 0.65rem 1rem 0; flex-shrink: 0; } .workspace-drawer-tab { flex: 1; padding: 0.45rem 0.75rem; border: 1px solid var(--border-color); border-radius: 8px 8px 0 0; background: var(--bg-subtle); color: var(--text-secondary); font-weight: 600; font-size: 0.82rem; cursor: pointer; font-family: var(--font-sans); } .workspace-drawer-tab.active { background: #fff; color: var(--accent); border-bottom-color: #fff; } .workspace-drawer-body { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 0 1rem 1rem; } .config-card-flat { border: none; box-shadow: none; padding: 0.75rem 0 0; gap: 0.75rem; min-width: 0; overflow: hidden; } .config-card-desc { font-size: 0.8rem; color: var(--text-secondary); margin: 0; } .config-suggestions { display: flex; flex-direction: column; gap: 0.45rem; } .config-suggestions-label { font-size: 0.75rem; color: var(--text-muted); font-weight: 600; } .config-suggestions-list { display: flex; flex-wrap: wrap; gap: 6px; } @media (max-width: 1100px) { .workspace-grid { grid-template-columns: 1fr; overflow-y: auto; } } .left-panel { display: flex; flex-direction: column; gap: 1rem; min-height: 0; overflow-y: auto; padding-right: 0.15rem; } .right-panel { display: flex; flex-direction: column; gap: 0.75rem; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 1.15rem; box-shadow: var(--shadow-sm); min-height: 0; overflow: hidden; } .workspace-panel-toolbar { flex-shrink: 0; } .workspace-panel-body { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding-right: 0.15rem; } .config-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 1.5rem; display: flex; flex-direction: column; gap: 1rem; box-shadow: var(--shadow-sm); } .card-header-title { font-size: 0.95rem; font-weight: 700; color: var(--text-primary); display: flex; align-items: center; gap: 0.5rem; } .app-textarea { width: 100%; min-height: 80px; background: var(--bg-subtle); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); padding: 0.75rem; font-family: 'Consolas', 'Courier New', monospace; font-size: 0.85rem; resize: vertical; transition: var(--transition); } .app-textarea:focus { outline: none; border-color: var(--accent); background: #fff; box-shadow: 0 0 0 3px var(--accent-glow); } .schedule-table { width: 100%; display: flex; flex-direction: column; gap: 0.5rem; } .schedule-row-item { display: grid; grid-template-columns: 80px 1fr 1fr; align-items: center; gap: 0.65rem; background: var(--bg-subtle); padding: 0.45rem 0.65rem; border-radius: var(--radius-sm); border: 1px solid var(--border-light); } .day-label { font-size: 0.8rem; font-weight: 600; color: var(--text-secondary); } .time-input { background: #fff; border: 1px solid var(--border-color); border-radius: 6px; color: var(--text-primary); padding: 0.4rem 0.55rem; font-size: 0.82rem; font-family: var(--font-sans); text-align: center; outline: none; transition: var(--transition); } .time-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); } /* Schedule editor — multi-shift per day */ .schedule-editor { display: flex; flex-direction: column; gap: 0.75rem; width: 100%; min-width: 0; overflow: hidden; } .schedule-editor .schedule-input, .schedule-editor .time-input { width: 100%; max-width: 100%; box-sizing: border-box; min-width: 0; } .schedule-editor .schedule-input { background: #fff; border: 1px solid var(--border-color); border-radius: 6px; color: var(--text-primary); padding: 0.5rem 0.65rem; font-size: 0.85rem; font-family: var(--font-sans); outline: none; transition: var(--transition); } .schedule-editor .schedule-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); } .schedule-editor-toolbar { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; } .schedule-editor-toolbar .btn { font-size: 0.78rem; padding: 0.45rem 0.7rem; } .schedule-hint { font-size: 0.78rem; color: var(--text-muted); } .schedule-hint-warn { color: #b45309; background: #fffbeb; border: 1px solid #fde68a; padding: 0.45rem 0.6rem; border-radius: 6px; margin: 0; } .schedule-hint-error { color: var(--danger); background: #fef2f2; border: 1px solid #fecaca; padding: 0.45rem 0.6rem; border-radius: 6px; margin: 0; } .schedule-day-tabs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.35rem; } .schedule-day-tab { padding: 0.4rem 0.35rem; border: 1px solid var(--border-color); border-radius: 6px; background: var(--bg-subtle); color: var(--text-secondary); font-size: 0.72rem; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 0.25rem; min-width: 0; } .schedule-day-tab.active { background: #fff; border-color: var(--accent); color: var(--accent); } .schedule-day-count { background: var(--accent); color: #fff; font-size: 0.62rem; padding: 0.05rem 0.3rem; border-radius: 999px; min-width: 0.9rem; text-align: center; line-height: 1.2; } .schedule-day-panel { background: var(--bg-subtle); border: 1px solid var(--border-light); border-radius: var(--radius-sm); padding: 0.75rem; min-width: 0; overflow: hidden; } .schedule-day-header { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; margin-bottom: 0.65rem; } .schedule-day-header .btn { flex-shrink: 0; white-space: nowrap; } .schedule-shift-card { background: #fff; border: 1px solid var(--border-color); border-radius: 8px; padding: 0.75rem; margin-bottom: 0.55rem; display: flex; flex-direction: column; gap: 0.55rem; min-width: 0; } .schedule-shift-card:last-child { margin-bottom: 0; } .schedule-shift-card.inactive { opacity: 0.6; } .schedule-shift-head { display: flex; align-items: flex-end; gap: 0.5rem; min-width: 0; } .schedule-field-ca { flex: 1; min-width: 0; } .schedule-time-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; min-width: 0; } .schedule-field { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.72rem; color: var(--text-muted); font-weight: 600; min-width: 0; } .schedule-active-toggle { display: flex; align-items: center; gap: 0.3rem; font-size: 0.75rem; color: var(--text-secondary); white-space: nowrap; flex-shrink: 0; padding-bottom: 0.45rem; } .schedule-remove-btn { padding: 0.35rem 0.55rem !important; font-size: 1rem !important; line-height: 1; flex-shrink: 0; margin-bottom: 0.1rem; } /* Attendance panel */ .attendance-panel, .session-logs-panel { display: flex; flex-direction: column; gap: 0.75rem; flex: 1; min-height: 0; overflow: hidden; } .workspace-panel-fill { display: flex; flex-direction: column; overflow: hidden; } .attendance-table-scroll { flex: 1; min-height: 0; overflow: auto; } .attendance-table-scroll .data-table thead { position: sticky; top: 0; z-index: 2; background: #fff; } .attendance-panel { height: 100%; } .attendance-toolbar { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: flex-end; } .attendance-field { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); } .attendance-shift-info { display: flex; flex-wrap: wrap; gap: 0.75rem; font-size: 0.82rem; color: var(--text-secondary); padding: 0.5rem 0.75rem; background: var(--bg-subtle); border-radius: var(--radius-sm); border: 1px solid var(--border-light); } .attendance-field--grow { flex: 1; min-width: 180px; } .attendance-search { width: 100%; } .attendance-qldt-banner { display: flex; flex-direction: column; gap: 0.15rem; padding: 0.65rem 0.85rem; border-radius: var(--radius-sm); border: 1px solid var(--border-color); background: var(--bg-subtle); font-size: 0.8rem; color: var(--text-secondary); } .attendance-qldt-banner strong { font-size: 0.85rem; color: var(--text-primary); } .attendance-qldt-banner--synced { border-color: rgba(46, 125, 50, 0.45); background: rgba(46, 125, 50, 0.08); } .attendance-qldt-banner--synced strong { color: #2e7d32; } .attendance-qldt-banner--stale { border-color: rgba(239, 108, 0, 0.5); background: rgba(239, 108, 0, 0.08); } .attendance-qldt-banner--stale strong { color: #ef6c00; } .attendance-status-summary { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; } .attendance-summary-chip { display: inline-flex; align-items: center; gap: 0.35rem; border: 1px solid transparent; border-radius: 999px; padding: 0.25rem 0.55rem; font-size: 0.72rem; font-weight: 700; cursor: default; background: transparent; } .attendance-summary-chip-label { opacity: 0.9; } .attendance-summary-chip-count { min-width: 1.1rem; text-align: center; padding: 0.05rem 0.3rem; border-radius: 999px; background: rgba(0, 0, 0, 0.12); } .attendance-summary-total { margin-left: auto; font-size: 0.75rem; color: var(--text-muted); font-weight: 600; } /* Thanh thao tác hàng loạt */ .attendance-bulk-actions { display: flex; align-items: center; gap: 1rem; padding: 0.75rem 1.25rem; background: var(--bg-card, #ffffff); border: 1px solid var(--border-color, #dee2e6); border-radius: 8px; margin-bottom: 1rem; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); animation: attendanceSlideDown 0.2s ease-out; } .attendance-bulk-title { font-weight: 600; font-size: 0.9rem; color: var(--text-color, #212529); } .attendance-bulk-btns { display: flex; gap: 0.5rem; flex-wrap: wrap; } .attendance-bulk-btn-close { margin-left: auto; } @keyframes attendanceSlideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } /* Trạng thái điểm danh — màu theo status 0..4 */ .attendance-status--0, .attendance-summary-chip.attendance-status--0 { --att-fg: #b71c1c; --att-bg: rgba(183, 28, 28, 0.12); --att-border: rgba(183, 28, 28, 0.45); } .attendance-status--1, .attendance-summary-chip.attendance-status--1 { --att-fg: #1565c0; --att-bg: rgba(21, 101, 192, 0.12); --att-border: rgba(21, 101, 192, 0.4); } .attendance-status--2, .attendance-summary-chip.attendance-status--2 { --att-fg: #e65100; --att-bg: rgba(230, 81, 0, 0.12); --att-border: rgba(230, 81, 0, 0.45); } .attendance-status--3, .attendance-summary-chip.attendance-status--3 { --att-fg: #f9a825; --att-bg: rgba(249, 168, 37, 0.15); --att-border: rgba(249, 168, 37, 0.5); } .attendance-status--4, .attendance-summary-chip.attendance-status--4 { --att-fg: #2e7d32; --att-bg: rgba(46, 125, 50, 0.12); --att-border: rgba(46, 125, 50, 0.45); } .attendance-summary-chip.attendance-status--0, .attendance-summary-chip.attendance-status--1, .attendance-summary-chip.attendance-status--2, .attendance-summary-chip.attendance-status--3, .attendance-summary-chip.attendance-status--4 { color: var(--att-fg); background: var(--att-bg); border-color: var(--att-border); } .attendance-table tbody tr.attendance-status--0, .attendance-table tbody tr.attendance-status--1, .attendance-table tbody tr.attendance-status--2, .attendance-table tbody tr.attendance-status--3, .attendance-table tbody tr.attendance-status--4 { background: var(--att-bg); } .attendance-table tbody tr:hover { filter: brightness(0.97); } .attendance-student-name { font-weight: 700; font-size: 0.88rem; } .attendance-student-meta { display: flex; flex-wrap: wrap; gap: 0.35rem 0.6rem; margin-top: 0.2rem; font-size: 0.72rem; color: var(--text-muted); } .attendance-student-meta code { font-size: 0.72rem; color: var(--text-secondary); } .attendance-online-mins { font-family: monospace; font-weight: 800; font-size: 1rem; } .attendance-online-unit { display: block; font-size: 0.68rem; color: var(--text-muted); } .attendance-status-cell { display: flex; flex-direction: column; gap: 0.35rem; align-items: flex-start; } .attendance-status-badge { display: inline-block; padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.72rem; font-weight: 700; color: var(--att-fg); background: var(--att-bg); border: 1px solid var(--att-border); } .attendance-status-select { width: 100%; max-width: 200px; padding: 0.35rem 0.5rem; border-radius: var(--radius-sm); font-size: 0.78rem; font-weight: 600; border: 1px solid var(--att-border); background: var(--att-bg); color: var(--att-fg); cursor: pointer; } .attendance-notes { display: flex; flex-wrap: wrap; gap: 0.35rem; } .attendance-qldt-tag { font-size: 0.68rem; font-weight: 700; padding: 0.15rem 0.4rem; border-radius: 4px; border: 1px solid var(--border-color); } .attendance-qldt-tag--ok { color: #2e7d32; background: rgba(46, 125, 50, 0.1); border-color: rgba(46, 125, 50, 0.35); } .attendance-qldt-tag--pending { color: var(--text-muted); background: var(--bg-subtle); } .attendance-lock-tag { font-size: 0.68rem; font-weight: 700; padding: 0.15rem 0.4rem; border-radius: 4px; color: #1565c0; background: rgba(21, 101, 192, 0.1); border: 1px solid rgba(21, 101, 192, 0.3); } .tab-btn-group { display: flex; background: var(--bg-subtle); padding: 0.3rem; border-radius: var(--radius-sm); border: 1px solid var(--border-color); width: fit-content; } .tab-sub-btn { padding: 0.45rem 1rem; background: transparent; border: none; color: var(--text-secondary); font-weight: 600; font-size: 0.85rem; font-family: var(--font-sans); cursor: pointer; border-radius: 6px; transition: var(--transition); } .tab-sub-btn.active { background: #fff; color: var(--accent); box-shadow: var(--shadow-sm); } .student-status-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.85rem; } .student-status-card { background: #fff; border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 1rem; display: flex; align-items: center; gap: 0.75rem; transition: var(--transition); } .student-status-card.online { border-color: rgba(13, 159, 110, 0.3); background: linear-gradient(135deg, #fff, var(--success-light)); } .student-status-card:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); } .student-status-card-clickable { cursor: pointer; } .student-status-card-clickable:hover { border-color: var(--accent); box-shadow: 0 4px 14px rgba(187, 33, 38, 0.12); } .student-status-card-clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .pulse-dot-online { width: 7px; height: 7px; background: var(--success); border-radius: 50%; animation: pulse-online 1.8s infinite ease-in-out; } @keyframes pulse-online { 0% { box-shadow: 0 0 0 0 rgba(13, 159, 110, 0.5); } 70% { box-shadow: 0 0 0 6px rgba(13, 159, 110, 0); } 100% { box-shadow: 0 0 0 0 rgba(13, 159, 110, 0); } } .status-badge-offline { width: 7px; height: 7px; background: var(--text-muted); border-radius: 50%; } .student-workspace-avatar { width: 48px; height: 48px; border-radius: 50%; background: var(--bg-subtle); border: 2px solid var(--border-color); color: var(--text-secondary); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 1rem; flex-shrink: 0; overflow: hidden; position: relative; } .student-avatar-img { width: 100%; height: 100%; object-fit: cover; display: block; } .student-workspace-avatar.has-image { background: #fff; border-color: var(--border-color); } .student-status-card.online .student-workspace-avatar.has-image { border-color: var(--success); box-shadow: 0 0 0 2px rgba(13, 159, 110, 0.2); } .student-status-card.online .student-workspace-avatar:not(.has-image) { background: var(--accent); color: white; border-color: var(--accent); } .app-suggestion-badge { font-size: 0.72rem; padding: 0.2rem 0.5rem; background: var(--bg-subtle); border: 1px solid var(--border-color); border-radius: 6px; color: var(--text-secondary); cursor: pointer; transition: var(--transition); } .app-suggestion-badge:hover { background: var(--accent); color: white; border-color: var(--accent); } .discovered-apps-pool { margin-top: 0.75rem; padding: 0.75rem; border: 1px solid #f0c674; border-radius: 8px; background: #fffbf0; } .discovered-apps-pool-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.35rem; } .discovered-apps-refresh { padding: 0.2rem 0.55rem !important; font-size: 0.72rem !important; min-height: auto !important; } .discovered-apps-hint { margin: 0 0 0.5rem; font-size: 0.72rem; line-height: 1.4; color: var(--text-muted); } .discovered-apps-empty { font-size: 0.78rem; color: var(--text-secondary); padding: 0.55rem 0.65rem; background: rgba(255, 255, 255, 0.65); border: 1px dashed #e0c878; border-radius: 6px; line-height: 1.45; } .discovered-apps-error { border-color: #e8a0a0; background: #fff5f5; color: #a33; } .app-suggestion-badge--discovered { border-color: #f0c674; background: #fffbf0; } .app-suggestion-badge--discovered em { font-style: normal; opacity: 0.75; font-size: 0.65rem; } .app-pool-open-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-top: 0.85rem; padding: 0.75rem; border: 1px solid #f0c674; border-radius: 8px; background: #fffbf0; } .app-pool-open-btn { flex-shrink: 0; white-space: nowrap; } .app-pool-overlay { z-index: 1200; } .app-pool-modal { max-width: 920px; width: 100%; } .app-pool-modal-sub { margin: 0.35rem 0 0; font-size: 0.8rem; color: var(--text-muted); } .app-pool-toolbar { display: flex; gap: 0.65rem; padding: 0 1.25rem 1rem; border-bottom: 1px solid var(--border-color); } .app-pool-search { flex: 1; padding: 0.55rem 0.75rem; border: 1px solid var(--border-color); border-radius: 8px; font-size: 0.9rem; outline: none; } .app-pool-search:focus { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(187, 33, 38, 0.12); } .app-pool-body { flex: 1; overflow: auto; padding: 0 1.25rem; min-height: 280px; max-height: min(58vh, 520px); } .app-pool-table { font-size: 0.82rem; } .app-pool-table th { position: sticky; top: 0; background: #fff; z-index: 1; } .app-pool-kw { font-weight: 700; color: var(--accent); background: #fff5f5; padding: 0.1rem 0.35rem; border-radius: 4px; } .app-pool-muted { color: var(--text-muted); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .app-pool-title { max-width: 220px; } .app-pool-hit { font-weight: 700; font-family: monospace; color: #b8860b; } .app-pool-add-btn { padding: 0.25rem 0.55rem !important; font-size: 0.75rem !important; min-height: auto !important; } .app-pool-added-tag { font-size: 0.72rem; color: var(--success); font-weight: 600; } .app-pool-row--added { opacity: 0.72; } .app-pool-status { padding: 2rem 1rem; text-align: center; color: var(--text-muted); font-size: 0.9rem; } .app-pool-footer { padding: 0.65rem 1.25rem; border-top: 1px solid var(--border-color); font-size: 0.75rem; color: var(--text-muted); background: var(--bg-subtle); } .workspace-class-title { font-size: 1.5rem; font-weight: 800; color: var(--text-primary); letter-spacing: -0.4px; } .workspace-stat-value { font-size: 1.25rem; font-weight: 800; color: var(--text-primary); } .status-panel { display: flex; align-items: center; gap: 1rem; background: var(--bg-subtle); padding: 0.6rem 1.15rem; border-radius: var(--radius-md); border: 1px solid var(--border-color); } .divider { width: 100%; height: 1px; background: var(--border-color); } /* ── Navigation history bar ── */ .nav-history-bar { display: flex; flex-direction: column; gap: 0.65rem; flex-shrink: 0; } .breadcrumb-row { display: flex; align-items: center; flex-wrap: wrap; gap: 0.35rem; font-size: 0.85rem; } .breadcrumb-back { display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.35rem 0.65rem; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-secondary); font-family: var(--font-sans); font-size: 0.82rem; font-weight: 600; cursor: pointer; transition: var(--transition); } .breadcrumb-back:hover { background: var(--accent-light); color: var(--accent); border-color: rgba(187, 33, 38, 0.25); } .breadcrumb-sep { color: var(--text-muted); user-select: none; } .breadcrumb-link { background: none; border: none; padding: 0; color: var(--text-secondary); font-family: var(--font-sans); font-size: 0.85rem; font-weight: 500; cursor: pointer; transition: var(--transition); } .breadcrumb-link:hover { color: var(--accent); text-decoration: underline; } .breadcrumb-current { color: var(--text-primary); font-weight: 700; max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .history-pills-row { display: flex; align-items: center; gap: 0.65rem; flex-wrap: wrap; } .history-pills-label { font-size: 0.72rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; flex-shrink: 0; } .history-pills { display: flex; flex-wrap: wrap; gap: 0.4rem; } .history-pill { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0.65rem; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 99px; font-family: var(--font-sans); font-size: 0.78rem; color: var(--text-secondary); cursor: pointer; transition: var(--transition); max-width: 200px; } .history-pill:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-light); } .history-pill.active { background: var(--accent); border-color: var(--accent); color: white; } .history-pill-index { font-size: 0.65rem; font-weight: 800; opacity: 0.75; flex-shrink: 0; } .history-pill-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .workspace-embedded { padding: 0; min-height: 0; height: 100%; max-width: none; gap: 0.75rem; } .page-container { padding: 1.5rem 2rem; max-width: 1100px; } .page-header { margin-bottom: 1.25rem; } .page-title { margin: 0; font-size: 1.5rem; font-weight: 800; color: var(--text-primary); } .page-subtitle { margin: 0.35rem 0 0; font-size: 0.88rem; color: var(--text-muted); line-height: 1.45; } .network-grid { display: grid; grid-template-columns: 1.2fr 0.8fr; gap: 1.25rem; align-items: start; } .network-actions { display: flex; gap: 0.65rem; margin-top: 1rem; flex-wrap: wrap; } .network-manual-form { display: grid; grid-template-columns: 1fr 1fr auto; gap: 0.55rem; margin-bottom: 0.85rem; align-items: start; } .network-manual-form .app-pool-search { width: 100%; min-width: 0; } .network-manual-error { grid-column: 1 / -1; margin: 0; font-size: 0.82rem; color: var(--danger, #c0392b); } .network-manual-hint { grid-column: 1 / -1; margin: 0 0 0.15rem; font-size: 0.8rem; color: var(--text-muted); } @media (max-width: 720px) { .network-manual-form { grid-template-columns: 1fr; } } .network-info-list { margin: 0; padding-left: 1.1rem; font-size: 0.85rem; line-height: 1.55; color: var(--text-secondary); } .network-info-list li + li { margin-top: 0.45rem; } @media (max-width: 900px) { .network-grid { grid-template-columns: 1fr; } } /* ── Learning tab: search, cards, timetable ── */ .learning-stats-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-bottom: 1rem; } .learning-stat { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 0.85rem 1rem; display: flex; flex-direction: column; gap: 0.2rem; } .learning-stat--accent { border-color: rgba(198, 40, 40, 0.35); background: rgba(198, 40, 40, 0.06); } .learning-stat-value { font-size: 1.45rem; font-weight: 800; color: var(--text-primary); line-height: 1.1; } .learning-stat-label { font-size: 0.78rem; color: var(--text-muted); } .learning-toolbar-card { margin-bottom: 1rem; padding: 1rem !important; } .learning-toolbar { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; } .learning-search { flex: 1; min-width: 220px; } .learning-view-toggle { display: inline-flex; border: 1px solid var(--border-color); border-radius: var(--radius-sm); overflow: hidden; flex-shrink: 0; } .learning-view-btn { border: none; background: transparent; color: var(--text-secondary); padding: 0.5rem 0.9rem; font-size: 0.82rem; font-weight: 600; cursor: pointer; transition: background 0.15s, color 0.15s; } .learning-view-btn--active { background: var(--primary-color); color: #fff; } .learning-day-filters { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.85rem; } .learning-day-chip { border: 1px solid var(--border-color); background: var(--bg-subtle); color: var(--text-secondary); border-radius: 999px; padding: 0.28rem 0.65rem; font-size: 0.75rem; font-weight: 600; cursor: pointer; } .learning-day-chip--active { border-color: var(--primary-color); background: rgba(198, 40, 40, 0.12); color: var(--primary-color); } .learning-empty { text-align: center; padding: 2.5rem 1rem; color: var(--text-muted); } .learning-empty-icon { font-size: 2.2rem; display: block; margin-bottom: 0.5rem; } .learning-class-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; } .learning-class-card { border: 1px solid var(--border-color); border-radius: var(--radius-md); background: var(--bg-subtle); padding: 1rem; display: flex; flex-direction: column; gap: 0.75rem; transition: border-color 0.15s, box-shadow 0.15s; } .learning-class-card:hover { border-color: rgba(198, 40, 40, 0.35); box-shadow: 0 4px 18px rgba(0, 0, 0, 0.12); } .learning-class-card--today { border-color: rgba(198, 40, 40, 0.45); background: linear-gradient(145deg, rgba(198, 40, 40, 0.07), var(--bg-subtle)); } .learning-class-card-head { display: flex; justify-content: space-between; gap: 0.75rem; align-items: flex-start; } .learning-class-code { font-weight: 800; font-size: 0.95rem; color: var(--primary-color); } .learning-class-name { margin: 0.2rem 0 0; font-size: 0.88rem; font-weight: 600; line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .learning-class-meta { margin: 0.25rem 0 0; font-size: 0.75rem; color: var(--text-muted); } .learning-class-badges { display: flex; flex-direction: column; gap: 0.3rem; align-items: flex-end; flex-shrink: 0; } .learning-badge { font-size: 0.68rem; font-weight: 700; padding: 0.2rem 0.45rem; border-radius: 4px; background: var(--bg-card); border: 1px solid var(--border-color); color: var(--text-secondary); white-space: nowrap; } .learning-badge--today { background: rgba(198, 40, 40, 0.15); border-color: rgba(198, 40, 40, 0.4); color: #ff8a80; } .learning-class-schedule { display: flex; flex-direction: column; gap: 0.45rem; max-height: 140px; overflow-y: auto; } .learning-schedule-day { display: flex; gap: 0.5rem; align-items: flex-start; } .learning-schedule-day-label { font-size: 0.72rem; font-weight: 700; color: var(--text-muted); min-width: 3.2rem; flex-shrink: 0; padding-top: 0.15rem; } .learning-schedule-shifts { display: flex; flex-wrap: wrap; gap: 0.3rem; } .learning-class-no-sched { margin: 0; font-size: 0.8rem; color: var(--text-muted); } .learning-class-apps { margin: 0; font-size: 0.72rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .learning-class-apps code { font-size: 0.7rem; } .learning-class-actions { display: flex; gap: 0.45rem; flex-wrap: wrap; margin-top: auto; padding-top: 0.35rem; border-top: 1px solid var(--border-color); } .learning-btn-danger { color: #ff8a80 !important; border-color: rgba(198, 40, 40, 0.25) !important; } .learning-add-list { list-style: none; padding: 0; margin: 0; } .learning-add-item { padding: 0.65rem 0; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; } /* Timetable (TKB) */ .learning-tkb-wrap { margin: -0.25rem 0 0; } .learning-tkb-scroll { overflow-x: auto; padding-bottom: 0.5rem; } .learning-tkb { width: 100%; min-width: 720px; border-collapse: separate; border-spacing: 0; table-layout: fixed; } .learning-tkb-corner { width: 64px; background: var(--bg-subtle); border: 1px solid var(--border-color); border-radius: var(--radius-sm) 0 0 0; padding: 0.6rem; font-size: 0.75rem; color: var(--text-muted); } .learning-tkb-dayhead { background: var(--bg-subtle); border: 1px solid var(--border-color); border-left: none; padding: 0.55rem 0.4rem; text-align: center; font-size: 0.78rem; font-weight: 700; color: var(--text-secondary); } .learning-tkb-dayhead span { display: block; } .learning-tkb-dayhead em { display: block; font-style: normal; font-size: 0.65rem; font-weight: 700; color: var(--primary-color); margin-top: 0.15rem; } .learning-tkb-dayhead--today { background: rgba(198, 40, 40, 0.1); color: var(--primary-color); } .learning-tkb-period { background: var(--bg-subtle); border: 1px solid var(--border-color); border-top: none; padding: 0.5rem; text-align: center; vertical-align: top; } .learning-tkb-period-num { font-size: 0.75rem; font-weight: 700; color: var(--text-muted); } .learning-tkb-cell { border: 1px solid var(--border-color); border-left: none; border-top: none; padding: 0.35rem; vertical-align: top; min-height: 72px; background: var(--bg-card); } .learning-tkb-cell--today { background: rgba(198, 40, 40, 0.04); } .learning-tkb-cell--filled { background: rgba(255, 255, 255, 0.02); } .learning-tkb-empty { display: block; text-align: center; color: var(--text-muted); font-size: 0.8rem; padding: 1rem 0; opacity: 0.4; } .learning-tkb-blocks { display: flex; flex-direction: column; gap: 0.3rem; } .learning-tkb-block { display: flex; flex-direction: column; align-items: flex-start; gap: 0.1rem; width: 100%; text-align: left; border: none; border-left: 3px solid var(--tkb-accent, var(--primary-color)); border-radius: 4px; background: rgba(255, 255, 255, 0.04); padding: 0.35rem 0.45rem; cursor: pointer; transition: transform 0.12s, background 0.12s; } .learning-tkb-block:hover { background: rgba(255, 255, 255, 0.08); transform: translateY(-1px); } .learning-tkb-block-code { font-size: 0.72rem; font-weight: 800; color: var(--tkb-accent, var(--primary-color)); } .learning-tkb-block-course { font-size: 0.68rem; color: var(--text-primary); line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .learning-tkb-block--inactive { opacity: 0.55; border-left-style: dashed; } .learning-tkb-block-time { font-size: 0.62rem; color: var(--text-muted); font-family: monospace; } @media (max-width: 900px) { .learning-stats-row { grid-template-columns: repeat(2, 1fr); } .learning-toolbar { flex-direction: column; align-items: stretch; } .learning-view-toggle { width: 100%; } .learning-view-btn { flex: 1; } } /* ── Login ── */ .auth-shell { width: 100%; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1.5rem; background: var(--bg-app); } .login-screen { width: 100%; max-width: 440px; margin: 0 auto; } .login-card { width: 100%; max-width: 420px; padding: 1.75rem; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); } .login-brand { display: flex; gap: 0.85rem; align-items: center; margin-bottom: 1.25rem; } .login-brand-title { font-weight: 800; font-size: 1.1rem; } .login-brand-sub { font-size: 0.75rem; color: var(--text-muted); } .login-heading { margin: 0 0 0.35rem; font-size: 1.35rem; } .login-hint { margin: 0 0 1rem; font-size: 0.85rem; color: var(--text-muted); } .login-form { display: flex; flex-direction: column; gap: 0.75rem; } .login-field { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.8rem; color: var(--text-muted); } .login-field input { padding: 0.55rem 0.65rem; border-radius: 8px; border: 1px solid var(--border-color); background: var(--bg-elevated); color: var(--text-primary); } .login-submit { width: 100%; margin-top: 0.25rem; } .login-error { color: #ef4444; font-size: 0.82rem; } .login-success { color: #22c55e; font-size: 0.82rem; } .login-links { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1rem; } .link-btn { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 0.82rem; padding: 0; } .domain-list { list-style: none; margin: 0; padding: 0; } .domain-item { display: flex; justify-content: space-between; align-items: center; padding: 0.5rem 0; border-bottom: 1px solid var(--border-color); } .domain-empty { color: var(--text-muted); font-size: 0.85rem; padding: 0.5rem 0; } /* ── Chat messenger dock ── */ .chat-dock { position: fixed; right: 20px; bottom: 20px; z-index: 10000; font-family: var(--font-sans); } .chat-toast { position: absolute; right: 0; bottom: 72px; width: 280px; padding: 0.7rem 0.85rem; border-radius: 10px; background: #1e293b; color: #fff; box-shadow: 0 8px 28px rgba(0, 0, 0, 0.25); display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.82rem; animation: chat-toast-in 0.25s ease; } .chat-toast strong { font-size: 0.78rem; color: #93c5fd; } @keyframes chat-toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .chat-fab { position: relative; width: 56px; height: 56px; border-radius: 50%; border: none; background: var(--accent); color: #fff; font-size: 1.4rem; cursor: pointer; box-shadow: 0 8px 28px rgba(0, 0, 0, 0.22); } .chat-fab-badge { position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: #ef4444; color: #fff; font-size: 0.65rem; font-weight: 700; line-height: 18px; } .chat-messenger { width: min(720px, calc(100vw - 40px)); height: min(520px, calc(100vh - 100px)); background: #fff; border: 1px solid var(--border-color); border-radius: 14px; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.2); display: flex; flex-direction: column; overflow: hidden; } .chat-messenger-head { display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border-color); background: #fff; flex-shrink: 0; } .chat-messenger-body { display: flex; flex: 1; min-height: 0; background: #fff; } .chat-sidebar { width: 260px; flex-shrink: 0; border-right: 1px solid var(--border-color); display: flex; flex-direction: column; min-height: 0; background: #f8fafc; } .chat-sidebar-search { padding: 0.6rem; border-bottom: 1px solid var(--border-color); background: #fff; } .chat-sidebar-search input { width: 100%; padding: 0.5rem 0.65rem; border-radius: 8px; border: 1px solid var(--border-color); font-size: 0.82rem; } .chat-picker-list, .chat-conv-list { list-style: none; margin: 0; padding: 0; overflow-y: auto; } .chat-picker-list { max-height: 160px; border-bottom: 1px solid var(--border-color); background: #fff; } .chat-conv-list { flex: 1; } .chat-picker-list button, .chat-conv-list button { width: 100%; text-align: left; border: none; background: transparent; padding: 0.65rem 0.75rem; cursor: pointer; border-bottom: 1px solid var(--border-light); color: var(--text-primary); } .chat-conv-list button:hover, .chat-picker-list button:hover { background: #eef2f7; } .chat-conv-list button.active { background: var(--accent-light); border-left: 3px solid var(--accent); } .chat-conv-row { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; } .chat-conv-name { font-size: 0.84rem; font-weight: 600; display: block; } .chat-conv-preview { display: block; font-size: 0.75rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 0.15rem; } .chat-conv-meta { font-size: 0.68rem; color: var(--text-muted); } .chat-conv-unread { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--accent); color: #fff; font-size: 0.62rem; font-weight: 700; line-height: 18px; text-align: center; } .chat-empty-hint { padding: 1rem 0.75rem; font-size: 0.78rem; color: var(--text-muted); text-align: center; } .chat-thread { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; background: #fff; } .chat-thread-empty { flex: 1; display: flex; align-items: center; justify-content: center; padding: 1.5rem; color: var(--text-muted); font-size: 0.85rem; text-align: center; } .chat-thread-head { padding: 0.65rem 1rem; border-bottom: 1px solid var(--border-color); background: #fff; flex-shrink: 0; } .chat-sub { font-size: 0.72rem; color: var(--text-muted); } .chat-head-actions { display: flex; gap: 0.25rem; } .chat-icon-btn { background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 1rem; width: 30px; height: 30px; border-radius: 6px; } .chat-icon-btn:hover { background: var(--bg-subtle); } .chat-messages { flex: 1; overflow-y: auto; padding: 0.75rem 1rem; display: flex; flex-direction: column; gap: 0.5rem; background: #f5f7fa; } .chat-bubble { max-width: 78%; display: flex; flex-direction: column; gap: 0.15rem; } .chat-bubble--staff { align-self: flex-start; } .chat-bubble--student { align-self: flex-end; } .chat-bubble-body { padding: 0.5rem 0.7rem; border-radius: 14px; font-size: 0.84rem; line-height: 1.4; word-break: break-word; } .chat-bubble--staff .chat-bubble-body { background: #fff; border: 1px solid var(--border-color); } .chat-bubble--student .chat-bubble-body { background: var(--accent); color: #fff; } .chat-bubble-time { font-size: 0.62rem; color: var(--text-muted); padding: 0 0.25rem; } .chat-compose { display: flex; gap: 0.5rem; padding: 0.65rem 0.85rem; border-top: 1px solid var(--border-color); background: #fff; flex-shrink: 0; } .chat-compose input { flex: 1; padding: 0.55rem 0.7rem; border-radius: 8px; border: 1px solid var(--border-color); font-size: 0.84rem; } /* ── Exam workspace ── */ .exam-workspace { flex: 1; min-height: 0; height: 100%; } .exam-workspace-header { flex-shrink: 0; } .exam-workspace-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; } .exam-workspace-alert { flex-shrink: 0; margin: 0; } .exam-workspace-scroll { flex: 1; min-height: 0; padding-bottom: 1rem; } .exam-section-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; } .exam-section-grid--bottom { margin-top: 0; } @media (max-width: 960px) { .exam-section-grid { grid-template-columns: 1fr; } } .exam-section { padding: 1.15rem 1.25rem; display: flex; flex-direction: column; gap: 0.85rem; min-width: 0; } .exam-section-head { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; } .exam-section-title { margin: 0; font-size: 1rem; font-weight: 700; color: var(--text-primary); } .exam-section-toolbar { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; } .exam-section-toolbar .search-input { min-width: 140px; width: auto; } .exam-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; } @media (max-width: 640px) { .exam-form-grid { grid-template-columns: 1fr; } } .exam-section-students { min-height: 280px; } .exam-students-panel { padding: 0; overflow: hidden; } .exam-students-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; padding: 1.15rem 1.25rem 0.85rem; border-bottom: 1px solid var(--border-light); background: #fff; flex-shrink: 0; } .exam-online-stat { margin: 0.35rem 0 0; font-size: 0.8rem; color: var(--text-muted); font-weight: 600; } .exam-online-count { color: var(--success); font-size: 1rem; font-weight: 800; } .exam-online-sep { margin: 0 0.2rem; color: var(--text-muted); } .exam-students-toolbar { display: flex; align-items: center; gap: 0.65rem; flex-wrap: wrap; } .exam-students-search { min-width: 200px; } .exam-students-search .search-input { width: 100%; min-width: 180px; } .exam-students-body { padding: 1rem 1.25rem 1.15rem; max-height: min(52vh, 520px); overflow-y: auto; overflow-x: hidden; } .exam-student-grid { padding-right: 0.15rem; } .exam-student-card { align-items: flex-start; position: relative; } .exam-student-card-main { display: flex; flex-direction: column; flex: 1; min-width: 0; overflow: hidden; } .exam-student-card-name { font-size: 0.875rem; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .exam-student-card-code { font-size: 0.78rem; color: var(--accent); font-family: monospace; font-weight: 600; } .exam-student-card-status { display: flex; align-items: center; gap: 0.35rem; margin-top: 0.4rem; } .exam-student-online-label { font-size: 0.75rem; font-weight: 700; color: var(--success); } .exam-student-offline-label { font-size: 0.75rem; font-weight: 700; color: var(--text-muted); } .exam-student-card-tags { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.5rem; } .exam-student-tag { font-size: 0.7rem; font-weight: 600; padding: 0.15rem 0.45rem; border-radius: 999px; background: var(--bg-subtle); border: 1px solid var(--border-light); color: var(--text-secondary); max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .exam-student-tag--muted { color: var(--text-muted); } .exam-student-tag--ok { background: var(--success-light); color: var(--success); border-color: rgba(13, 159, 110, 0.25); } .exam-student-tag--sent { background: var(--accent-light); color: var(--accent); border-color: rgba(187, 33, 38, 0.2); } .exam-student-card-actions { display: flex; flex-direction: column; gap: 0.25rem; flex-shrink: 0; } .exam-student-chat-btn { font-size: 1rem !important; line-height: 1; } .exam-students-table-scroll { max-height: min(46vh, 460px); overflow: auto; border: 1px solid var(--border-light); border-radius: var(--radius-md); } .exam-students-table-scroll .data-table thead { position: sticky; top: 0; z-index: 2; background: #fff; box-shadow: 0 1px 0 var(--border-light); } .exam-students-table-scroll .data-table th { background: #fff; } .exam-submissions-scroll .data-table thead { position: sticky; top: 0; z-index: 2; background: #fff; } .exam-student-row-clickable { cursor: pointer; } .exam-student-row-clickable:hover td { background: var(--bg-subtle); } .exam-row-status { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.78rem; font-weight: 700; } .exam-row-status.online { color: var(--success); } .exam-row-status.offline { color: var(--text-muted); } .exam-student-row-actions { white-space: nowrap; } .exam-table-wrap { flex: 1; min-height: 0; max-height: 320px; overflow: auto; border: 1px solid var(--border-light); border-radius: var(--radius-md); } .exam-table-wrap--short { max-height: 240px; } .exam-table-empty { text-align: center; color: var(--text-muted); padding: 2rem 1rem !important; } .exam-cell-muted { font-size: 0.78rem; color: var(--text-muted); } .exam-empty-state { text-align: center; padding: 1.5rem 1rem; color: var(--text-muted); background: var(--bg-subtle); border-radius: var(--radius-md); border: 1px dashed var(--border-color); } .exam-empty-state span { font-size: 1.75rem; display: block; margin-bottom: 0.35rem; } .exam-empty-state--compact { padding: 1rem; } .exam-paper-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.65rem; } .exam-paper-item { border: 1px solid var(--border-light); border-radius: var(--radius-md); padding: 0.75rem 0.85rem; background: var(--bg-subtle); } .exam-paper-item-head { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; } .exam-paper-meta { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.25rem; } .exam-paper-add-res { margin-top: 0.5rem; cursor: pointer; } .exam-papers-view-modal { width: min(560px, 94vw); max-height: 85vh; display: flex; flex-direction: column; } .exam-papers-view-body { padding: 0 1.25rem 1.25rem; overflow-y: auto; display: flex; flex-direction: column; gap: 0.75rem; } .exam-paper-view-card { border: 1px solid var(--border-light); border-radius: var(--radius-md); padding: 0.85rem 1rem; background: var(--bg-subtle); } .exam-paper-view-head { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; flex-wrap: wrap; } .exam-paper-view-resources { margin: 0.65rem 0 0; padding-left: 1.1rem; font-size: 0.88rem; color: var(--text-secondary); } .exam-paper-view-resources li { margin-bottom: 0.35rem; } .exam-paper-view-actions { margin-left: 0.5rem; display: inline-flex; gap: 0.5rem; } .exam-pdf-viewer-overlay { z-index: 2000; } .exam-pdf-viewer-modal { width: min(960px, 96vw); height: min(90vh, 900px); display: flex; flex-direction: column; background: var(--bg-card); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-lg); } .exam-pdf-viewer-header { flex-shrink: 0; padding: 0.85rem 1rem; border-bottom: 1px solid var(--border-light); } .exam-pdf-viewer-scroll { flex: 1; overflow-y: auto; overflow-x: hidden; background: #525659; padding: 1rem 0; min-height: 0; } .exam-pdf-viewer-status { text-align: center; color: #fff; padding: 2rem 1rem; margin: 0; } .exam-pdf-page-wrap { display: flex; justify-content: center; margin-bottom: 12px; padding: 0 12px; } .exam-pdf-page { display: block; max-width: 100%; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35); background: #fff; } .exam-pdf-viewer-frame { flex: 1; width: 100%; border: none; background: #525659; } .exam-inline-resource-modal { height: min(85vh, 800px); } .exam-inline-resource-body { flex: 1; overflow: auto; display: flex; align-items: center; justify-content: center; background: var(--bg-subtle); min-height: 0; } .exam-inline-resource-image { max-width: 100%; max-height: 100%; object-fit: contain; } .exam-send-row { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; } .exam-send-row .search-input { width: auto; min-width: 180px; } .exam-student-overlay { padding: 1.5rem; } .exam-student-modal { max-width: min(920px, 96vw); width: 100%; max-height: min(88vh, 760px); display: flex; flex-direction: column; } .exam-student-modal-header { flex-shrink: 0; } .exam-student-modal-desc { margin: 0.35rem 0 0; color: var(--text-muted); font-size: 0.88rem; } .exam-student-modal-body { padding: 0 1.5rem 1.5rem; display: flex; flex-direction: column; gap: 0.85rem; flex: 1; min-height: 0; overflow: hidden; } .exam-student-modal-search .search-input { width: 100%; padding: 0.7rem 2.5rem 0.7rem 0.85rem; font-size: 0.95rem; } .exam-student-hits { flex: 1; min-height: 280px; max-height: min(62vh, 560px); overflow-y: auto; display: flex; flex-direction: column; gap: 0.65rem; padding-right: 0.2rem; } .exam-student-hits-empty { text-align: center; padding: 2.5rem 1rem; color: var(--text-muted); } .exam-student-hits-empty span { font-size: 2rem; display: block; margin-bottom: 0.5rem; } .exam-student-hit { display: grid; grid-template-columns: auto auto 1fr auto; align-items: center; gap: 0.85rem; padding: 0.85rem 1rem; border: 1px solid var(--border-light); border-radius: var(--radius-md); background: #fff; transition: var(--transition); } .exam-student-hit--added { opacity: 0.85; } .exam-student-hit--selected { border-color: var(--accent); background-color: var(--accent-light, #fff5f5); } .exam-student-hit:hover { border-color: var(--accent); box-shadow: 0 2px 10px rgba(187, 33, 38, 0.08); } .exam-student-hit-avatar { width: 42px; height: 42px; border-radius: 50%; background: linear-gradient(135deg, #fff5f5 0%, #fee2e2 100%); color: var(--accent); font-weight: 700; font-size: 0.82rem; display: flex; align-items: center; justify-content: center; flex-shrink: 0; border: 1px solid rgba(187, 33, 38, 0.12); } .exam-student-hit-info { min-width: 0; } .exam-student-hit-info strong { display: block; font-size: 0.95rem; margin-bottom: 0.2rem; } .exam-student-hit-meta { font-size: 0.8rem; color: var(--text-muted); line-height: 1.45; word-break: break-word; } .exam-student-hit-meta code { font-size: 0.78rem; color: var(--accent); font-weight: 700; } @media (max-width: 640px) { .exam-student-hit { grid-template-columns: 1fr; text-align: left; } .exam-student-hit .btn { width: 100%; justify-content: center; } } .exam-submissions-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border-light); background: #fafafa; } .exam-submissions-toolbar-hint { font-size: 0.78rem; color: var(--text-muted); flex: 1; min-width: 200px; } .exam-git-settings { margin-top: 0.5rem; padding-top: 0.75rem; border-top: 1px dashed var(--border-light); } .exam-git-oauth-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.65rem; margin-bottom: 0.65rem; } .exam-git-connected { font-size: 0.85rem; color: var(--text-secondary); } .exam-git-connected strong { color: var(--text-primary); } .exam-git-status-line { margin: 0 0 0.65rem; font-size: 0.85rem; color: var(--text-secondary); } .exam-git-not-connected { color: var(--danger); } .github-repos-panel { margin-top: 0.75rem; } .github-repos-toolbar { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.75rem; } .github-repos-table-wrap { max-height: 360px; overflow: auto; } .github-repo-link { color: var(--accent); font-weight: 500; word-break: break-all; } .section-subtitle { font-size: 0.95rem; font-weight: 600; margin: 0; } .exam-git-branch-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: 0.45rem; } .exam-git-branch-label { font-size: 0.8rem; color: var(--text-secondary); margin: 0; } .exam-git-branch-input { width: 120px; padding: 0.4rem 0.55rem; font-size: 0.85rem; } .exam-git-hint { margin: 0.5rem 0 0; font-size: 0.75rem; color: var(--text-muted); line-height: 1.45; } .exam-git-hint code { font-size: 0.72rem; } .exam-git-last { margin: 0.45rem 0 0; font-size: 0.78rem; word-break: break-all; } .exam-git-last a { color: var(--accent); } /* ── Mobile sidebar drawer ── */ .mobile-menu-btn { display: none; position: fixed; top: 0.75rem; left: 0.75rem; z-index: 30; width: 42px; height: 42px; border-radius: var(--radius-sm); border: 1px solid var(--border-color); background: var(--bg-card); color: var(--text-primary); box-shadow: var(--shadow-sm); align-items: center; justify-content: center; cursor: pointer; } .mobile-menu-btn svg { width: 22px; height: 22px; } .sidebar-backdrop { display: none; position: fixed; inset: 0; z-index: 19; background: rgba(15, 23, 42, 0.45); border: none; cursor: pointer; } .nav-sub { list-style: none; margin: 0 0 0.35rem 0; padding: 0 0 0 2.15rem; } .nav-sub .nav-btn { font-size: 0.82rem; padding: 0.45rem 0.65rem; min-height: auto; } .nav-sub .nav-btn::before { display: none; } .nav-sub .nav-btn.active { background: var(--accent-light); color: var(--accent); font-weight: 600; } @media (max-width: 900px) { .mobile-menu-btn { display: inline-flex; } .sidebar-backdrop { display: block; } .sidebar { transform: translateX(-110%); transition: transform 0.28s ease; z-index: 25; box-shadow: var(--shadow-md); } .sidebar.sidebar--open { transform: translateX(0); } .main-content { margin-left: 0; padding: 3.75rem 0.85rem 1rem; } } /* ── System management ── */ .system-page { overflow-y: auto; padding-bottom: 1.5rem; } .system-subnav { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.65rem; margin-bottom: 1.25rem; } .system-subnav-btn { display: flex; align-items: flex-start; gap: 0.65rem; text-align: left; padding: 0.85rem 1rem; border-radius: var(--radius-md); border: 1px solid var(--border-color); background: var(--bg-card); cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s, background 0.15s; } .system-subnav-btn:hover { border-color: rgba(198, 40, 40, 0.35); } .system-subnav-btn.active { border-color: var(--accent); background: var(--accent-light); box-shadow: 0 0 0 1px rgba(198, 40, 40, 0.12); } .system-subnav-icon { width: 36px; height: 36px; border-radius: var(--radius-sm); background: var(--bg-subtle); display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: var(--accent); } .system-subnav-btn.active .system-subnav-icon { background: rgba(198, 40, 40, 0.12); } .system-subnav-icon svg { width: 18px; height: 18px; } .system-subnav-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; } .system-subnav-text strong { font-size: 0.88rem; color: var(--text-primary); } .system-subnav-text small { font-size: 0.72rem; color: var(--text-muted); } .system-panel { min-height: 200px; } .system-section { display: flex; flex-direction: column; gap: 1rem; } .system-section--grid { display: grid; grid-template-columns: 1fr 280px; gap: 1rem; align-items: start; } .system-block { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 1.15rem 1.25rem; box-shadow: var(--shadow-sm); } .system-block--info { background: var(--bg-subtle); } .system-block-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; } .system-block-title { margin: 0 0 0.35rem; font-size: 1.05rem; font-weight: 700; } .system-block-desc { margin: 0; font-size: 0.84rem; color: var(--text-muted); line-height: 1.5; max-width: 52rem; } .system-stat-pill { flex-shrink: 0; padding: 0.25rem 0.65rem; border-radius: 99px; font-size: 0.75rem; font-weight: 700; background: var(--bg-subtle); border: 1px solid var(--border-color); color: var(--text-muted); } .system-inline-form { display: flex; gap: 0.5rem; margin-bottom: 1rem; } .system-inline-form input { flex: 1; min-width: 0; } .system-inline-form--stack { flex-direction: column; } .system-empty { padding: 1.25rem; text-align: center; color: var(--text-muted); font-size: 0.88rem; border: 1px dashed var(--border-color); border-radius: var(--radius-sm); background: var(--bg-subtle); } .system-empty--muted { background: transparent; } .system-domain-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.45rem; } .system-domain-item { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.65rem 0.85rem; border: 1px solid var(--border-color); border-radius: var(--radius-sm); background: var(--bg-subtle); } .system-domain-label { font-weight: 600; font-family: ui-monospace, monospace; font-size: 0.88rem; } .system-info-title { margin: 0 0 0.65rem; font-size: 0.92rem; font-weight: 700; } .system-form-card { background: var(--bg-subtle); border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 1rem 1.15rem; margin-bottom: 1rem; } .system-form-title { margin: 0 0 0.85rem; font-size: 0.95rem; font-weight: 700; } .system-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; } .system-form-full { grid-column: 1 / -1; } .system-form-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-top: 0.85rem; flex-wrap: wrap; } .system-form-actions-right { display: flex; gap: 0.5rem; } .system-table-wrap { overflow-x: auto; margin-bottom: 0.75rem; } .template-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.75rem; } .template-card { border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 0.9rem 1rem; background: var(--bg-subtle); display: flex; flex-direction: column; gap: 0.45rem; } .template-card-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; } .template-card-head h3 { margin: 0; font-size: 0.95rem; } .template-card-badge { font-size: 0.7rem; font-weight: 700; padding: 0.15rem 0.45rem; border-radius: 99px; background: var(--bg-card); border: 1px solid var(--border-color); color: var(--text-muted); } .template-card-desc { margin: 0; font-size: 0.8rem; color: var(--text-muted); } .template-card-kw { display: block; font-size: 0.72rem; line-height: 1.45; padding: 0.45rem 0.55rem; border-radius: var(--radius-sm); background: var(--bg-card); border: 1px solid var(--border-light); word-break: break-word; max-height: 4.5rem; overflow: hidden; } .template-card-actions { display: flex; gap: 0.35rem; margin-top: 0.25rem; } .template-picker-list { display: flex; flex-direction: column; gap: 0.65rem; } .template-picker-card { border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 0.85rem 1rem; background: var(--bg-subtle); } .template-picker-card-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.35rem; } .template-picker-count { font-size: 0.72rem; color: var(--text-muted); font-weight: 600; } .template-picker-desc { margin: 0 0 0.35rem; font-size: 0.8rem; color: var(--text-muted); } .template-picker-kw { display: block; font-size: 0.72rem; margin-bottom: 0.65rem; word-break: break-word; } .template-picker-apply { width: 100%; justify-content: center; } .app-pool-open-actions { display: flex; flex-wrap: wrap; gap: 0.45rem; justify-content: flex-end; } /* ── Exams list cards ── */ .exams-page { overflow-y: auto; padding-bottom: 1.5rem; } .exams-stats-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; margin-bottom: 1rem; } .exams-toolbar { margin-bottom: 1rem; } .exams-search { max-width: 420px; } .exams-create-card { margin-bottom: 1rem; } .exams-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 0.85rem; } .exam-list-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: 0.75rem; box-shadow: var(--shadow-sm); transition: border-color 0.15s, box-shadow 0.15s; } .exam-list-card:hover { border-color: rgba(198, 40, 40, 0.3); box-shadow: var(--shadow-md); } .exam-list-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.65rem; } .exam-list-card-head h3 { margin: 0; font-size: 1rem; line-height: 1.35; } .exam-list-card-meta { display: flex; flex-direction: column; gap: 0.45rem; font-size: 0.8rem; color: var(--text-secondary); } .exam-list-card-meta > div { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; } .exam-list-card-label { font-weight: 700; color: var(--text-muted); margin-right: 0.25rem; } .exam-list-card-sep { color: var(--text-muted); } .exam-list-card-open { width: 100%; justify-content: center; } @media (max-width: 900px) { .system-subnav { grid-template-columns: 1fr; } .system-section--grid { grid-template-columns: 1fr; } .system-form-grid { grid-template-columns: 1fr; } .exams-stats-row { grid-template-columns: 1fr; } }