:root,
:root[data-theme="dark"] {
    color-scheme: dark;
    --bg-primary: #0d1117;
    --bg-secondary: #161b22;
    --bg-tertiary: #21262d;
    --bg-card: #1c2128;
    --border: #30363d;
    --text-primary: #e6edf3;
    --text-secondary: #8b949e;
    --text-muted: #6e7681;
    --accent: #58a6ff;
    --accent-hover: #79c0ff;
    --success: #3fb950;
    --warning: #d29922;
    --error: #f85149;
    --radius: 8px;
    --shadow: 0 2px 8px rgba(0,0,0,0.3);
}

:root[data-theme="light"] {
    color-scheme: light;
    --bg-primary: #f6f8fa;
    --bg-secondary: #ffffff;
    --bg-tertiary: #f0f3f6;
    --bg-card: #ffffff;
    --border: #d0d7de;
    --text-primary: #24292f;
    --text-secondary: #57606a;
    --text-muted: #6e7781;
    --accent: #0969da;
    --accent-hover: #0550ae;
    --success: #1a7f37;
    --warning: #9a6700;
    --error: #cf222e;
    --shadow: 0 2px 8px rgba(140,149,159,0.2);
}

@media (prefers-color-scheme: light) {
    :root:not([data-theme]),
    :root[data-theme="adaptive"] {
        color-scheme: light;
        --bg-primary: #f6f8fa;
        --bg-secondary: #ffffff;
        --bg-tertiary: #f0f3f6;
        --bg-card: #ffffff;
        --border: #d0d7de;
        --text-primary: #24292f;
        --text-secondary: #57606a;
        --text-muted: #6e7781;
        --accent: #0969da;
        --accent-hover: #0550ae;
        --success: #1a7f37;
        --warning: #9a6700;
        --error: #cf222e;
        --shadow: 0 2px 8px rgba(140,149,159,0.2);
    }
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: var(--bg-primary);
    color: var(--text-primary);
    line-height: 1.6;
}

.hidden { display: none !important; }

/* Auth Page */
.auth-container {
    max-width: 400px;
    margin: 100px auto;
    padding: 2rem;
    background: var(--bg-secondary);
    border-radius: var(--radius);
    border: 1px solid var(--border);
}

.auth-header {
    text-align: center;
    margin-bottom: 2rem;
}

.auth-header h1 {
    font-size: 2rem;
    margin-bottom: 0.5rem;
}

.auth-header p {
    color: var(--text-secondary);
}

.auth-tabs {
    display: flex;
    gap: 0;
    margin-bottom: 1.5rem;
    border-bottom: 1px solid var(--border);
}

.tab {
    flex: 1;
    padding: 0.75rem;
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 1rem;
    border-bottom: 2px solid transparent;
    transition: all 0.2s;
}

.tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.form-group label {
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.form-group input,
.form-group select,
.form-group textarea {
    padding: 0.75rem;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-primary);
    font-size: 1rem;
    transition: border-color 0.2s;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: var(--accent);
}

.theme-toggle {
    width: 2.25rem;
    height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-primary);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    transition: all 0.2s;
}

.theme-toggle:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.theme-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Language switcher — same pill as the theme toggle, sitting next to it in
   the sidebar and in the public navbar. It shows the active language (EN /
   简 / 繁) and cycles on click, exactly as the theme control does. The label
   is text rather than a glyph, so it needs a slightly smaller, wider type. */
.lang-toggle {
    min-width: 2.25rem;
    height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.5rem;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-primary);
    cursor: pointer;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1;
    transition: all 0.2s;
}

.lang-toggle:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.lang-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Chinese needs no italics and reads better a touch larger in dense UI. */
:root[data-lang^="zh"] body {
    font-size: 1.02rem;
}

/* Account button — same round shape as the theme toggle but logs the
   user out on click, so it picks up the danger palette on hover. */
.user-icon {
    width: 2.25rem;
    height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-primary);
    cursor: pointer;
    font-size: 1.05rem;
    line-height: 1;
    transition: all 0.2s;
}

#user-display:hover {
    background: var(--error);
    color: #fff;
    border-color: var(--error);
}

/* Buttons */
.btn {
    padding: 0.75rem 1.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-tertiary);
    color: var(--text-primary);
    cursor: pointer;
    font-size: 0.875rem;
    transition: all 0.2s;
}

.btn:hover {
    background: var(--bg-secondary);
}

.btn-primary {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
}

.btn-primary:hover {
    background: var(--accent-hover);
}

.btn-sm {
    padding: 0.5rem 1rem;
    font-size: 0.8rem;
}

.btn-success {
    background: var(--success);
    color: #fff;
    border-color: var(--success);
}

.btn-warning {
    background: var(--warning);
    color: #fff;
    border-color: var(--warning);
}

.btn-danger {
    background: var(--error);
    color: #fff;
    border-color: var(--error);
}

.text-success {
    color: var(--success);
    font-weight: 500;
}

.text-error {
    color: var(--error);
    font-weight: 500;
}

.link-button {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    color: var(--accent);
    cursor: pointer;
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.link-button:hover {
    color: var(--accent-hover);
}

.link-button:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Navbar */
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.25rem 1.5rem;
    height: 48px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 10;
}

.nav-brand {
    font-size: 1.05rem;
    font-weight: bold;
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nav-user {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex: 0 0 auto;
}

/* Layout */
.container {
    display: flex;
    min-height: 100vh;
}

.container:has(.grade-fs-page:not(.hidden)) {
    height: 100vh;
    min-height: 0;
}

.sidebar {
    width: 220px;
    background: var(--bg-secondary);
    border-right: 1px solid var(--border);
    padding: 1rem 0 0.5rem;
    display: flex;
    flex-direction: column;
    transition: width 0.2s ease;
    /* Pin to the viewport so the bottom toggle stays reachable on long pages. */
    position: sticky;
    top: 0;
    align-self: flex-start;
    height: 100vh;
}

.sidebar.collapsed {
    width: 56px;
}

.nav-menu {
    list-style: none;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.sidebar-bottom {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    padding: 0.5rem;
    border-top: 1px solid var(--border);
}

.grading-layout-controls {
    display: none;
    grid-template-columns: 1fr;
    gap: 0.3rem;
}

body.show-grading-layout-controls .grading-layout-controls {
    display: grid;
}

.submission-feedback {
    margin: 0.5rem 0;
}

.submission-feedback ul {
    margin: 0.35rem 0 0 1.25rem;
    padding: 0;
}

.submission-feedback li {
    margin: 0.25rem 0;
}

.sidebar-tool {
    width: 100%;
    min-height: 2rem;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.35rem 0.45rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-card);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.78rem;
    text-align: left;
}

.sidebar-tool:hover,
.sidebar-tool.active {
    border-color: var(--accent);
    color: var(--text-primary);
    background: var(--bg-tertiary);
}

.sidebar-tool-icon {
    flex: 0 0 1.1rem;
    text-align: center;
}

.sidebar-session-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
}

.nav-item {
    padding: 0.75rem 1.5rem;
    cursor: pointer;
    color: var(--text-secondary);
    transition: all 0.2s;
    font-size: 0.95rem;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    white-space: nowrap;
    overflow: hidden;
}

.nav-icon {
    flex: 0 0 auto;
    width: 1.25rem;
    text-align: center;
}

.nav-label {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar.collapsed .nav-item {
    padding: 0.75rem 0.5rem;
    justify-content: center;
}

.sidebar.collapsed .nav-label {
    display: none;
}

.sidebar.collapsed .sidebar-tool {
    justify-content: center;
    padding: 0.35rem 0.25rem;
}

.sidebar.collapsed .sidebar-tool-label {
    display: none;
}

.sidebar.collapsed .sidebar-session-controls {
    flex-direction: column;
}

.nav-item:hover {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.nav-item.active {
    background: var(--bg-tertiary);
    color: var(--accent);
    border-left: 3px solid var(--accent);
}

.nav-group {
    list-style: none;
}

.nav-submenu {
    list-style: none;
    margin: 0;
    padding: 0;
}

.nav-subitem {
    padding: 0.4rem 1rem 0.4rem 2.6rem;
    cursor: pointer;
    color: var(--text-secondary);
    font-size: 0.85rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: background 0.15s ease, color 0.15s ease;
}

.nav-subitem:hover {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.nav-subitem.active {
    background: var(--bg-tertiary);
    color: var(--accent);
}

.sidebar.collapsed .nav-submenu {
    display: block;
    padding: 0.2rem 0 0.45rem;
}

.sidebar.collapsed .nav-subitem {
    padding: 0.35rem 0;
    text-align: center;
    font-size: 0.72rem;
    font-weight: 650;
    letter-spacing: 0;
}

.sidebar.collapsed .nav-subitem.active {
    border-left: 3px solid var(--accent);
}

.sidebar-toggle {
    flex: 0 0 auto;
    width: 100%;
    margin: 0;
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.9rem;
    transition: background 0.15s ease, color 0.15s ease;
}

.sidebar-toggle:hover {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.content {
    flex: 1;
    min-width: 0;
    padding: 2rem;
    overflow-y: auto;
}

/* When the full-screen grading page is active, drop content padding and
   suppress its outer scroll so the source/PDF panes own the scroll. */
.content:has(> .grade-fs-page:not(.hidden)) {
    padding: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Stats Grid */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
    margin-bottom: 2rem;
}

.stat-card {
    background: var(--bg-card);
    padding: 1.5rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    text-align: center;
}

.stat-value {
    font-size: 2rem;
    font-weight: bold;
    color: var(--accent);
}

.stat-label {
    color: var(--text-secondary);
    font-size: 0.875rem;
}

/* Instructor activity analytics */
.activity-page-header { align-items: flex-end; }
.activity-actions { display: flex; align-items: center; gap: 0.65rem; flex-wrap: wrap; }
.activity-actions label { color: var(--text-secondary); font-size: 0.875rem; }
.activity-actions select {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-card);
    color: var(--text-primary);
    padding: 0.55rem 0.75rem;
}
.activity-stats { margin-top: 0.5rem; }
.activity-panel {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.25rem;
    margin-bottom: 1rem;
    min-width: 0;
}
.activity-panel h3 { margin: 0 0 1rem; }
.activity-rankings { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
.activity-chart-scroll { overflow-x: auto; padding: 0.25rem 0 0; }
.activity-chart {
    display: grid;
    grid-template-columns: repeat(var(--activity-days), minmax(8px, 1fr));
    gap: 4px;
    min-width: max(100%, calc(var(--activity-days) * 12px));
    height: 205px;
    border-bottom: 1px solid var(--border);
}
.activity-day { min-width: 0; display: grid; grid-template-rows: 175px 28px; align-items: end; }
.activity-bar-track { height: 165px; display: flex; align-items: flex-end; }
.activity-bar {
    display: block;
    width: 100%;
    min-height: 1px;
    border-radius: 3px 3px 0 0;
    background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 58%, transparent));
}
.activity-day-label {
    color: var(--text-muted);
    font-size: 0.65rem;
    line-height: 1.1;
    white-space: nowrap;
    overflow: visible;
}
.activity-target { max-width: 32rem; overflow-wrap: anywhere; }
.activity-empty-cell { color: var(--text-muted); text-align: center; }
.activity-inactive { color: var(--text-muted); }
.activity-student-link {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--accent);
    font: inherit;
    text-align: left;
    text-decoration: underline;
    text-underline-offset: 0.15em;
    cursor: pointer;
}
.activity-footnote { color: var(--text-muted); font-size: 0.82rem; margin: 0.75rem 0 0; }

@media (max-width: 800px) {
    .activity-page-header { align-items: flex-start; }
    .activity-rankings { grid-template-columns: 1fr; }
}

/* Card Grid */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
}

.card {
    background: var(--bg-card);
    padding: 1.5rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    transition: border-color 0.2s;
}

.card:hover {
    border-color: var(--accent);
}

.card h3 {
    margin-bottom: 0.5rem;
    color: var(--text-primary);
}

.card-score {
    display: inline-block;
    margin-left: 0.5rem;
    padding: 0.1rem 0.5rem;
    border-radius: 12px;
    background: rgba(63,185,80,0.2);
    color: var(--success);
    font-size: 0.85rem;
    font-weight: 600;
    vertical-align: middle;
}

.card-score-muted {
    background: rgba(125,133,144,0.2);
    color: var(--text-muted);
}

#assignments-calendar {
    margin-bottom: 1.5rem;
    padding: 1rem;
    background: var(--bg-secondary, rgba(255,255,255,0.03));
    border: 1px solid var(--border);
    border-radius: 10px;
}

.cal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.cal-nav {
    display: flex;
    gap: 0.25rem;
}

.cal-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-primary);
}

.cal-legend {
    display: flex;
    gap: 0.35rem;
    flex-wrap: wrap;
}

.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    background: var(--border);
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}

.cal-dow {
    background: rgba(125,133,144,0.15);
    text-align: center;
    padding: 0.4rem 0;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.cal-cell {
    background: var(--bg-card);
    min-height: 88px;
    padding: 0.35rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.cal-cell-blank {
    background: rgba(125,133,144,0.05);
}

.cal-cell-today {
    box-shadow: inset 0 0 0 2px var(--accent);
}

.cal-day {
    font-size: 0.8rem;
    color: var(--text-muted);
    font-weight: 600;
}

.cal-events {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.cal-event {
    display: inline-block;
    padding: 0.1rem 0.4rem;
    border-radius: 4px;
    font-size: 0.7rem;
    font-weight: 500;
    line-height: 1.3;
    text-align: left;
    border: none;
    cursor: pointer;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cal-event-release { background: rgba(63,185,80,0.25); color: var(--success); }
.cal-event-due { background: rgba(88,166,255,0.25); color: var(--accent); }
.cal-event-late { background: rgba(210,153,34,0.25); color: var(--warning); }
.cal-event-grade { background: rgba(187,128,255,0.25); color: #c08bff; }
/* GECC1132CH term schedule: a class meeting or service activity, and a Friday
   with nothing on — the second is deliberately quiet, it is there to answer a
   question rather than to draw the eye. */
.cal-event-class { background: rgba(224,138,102,0.22); color: #e08a66; border-left: 3px solid #e08a66;
                   text-decoration: none; }
.cal-event-off { background: var(--bg-secondary); color: var(--text-muted); font-weight: 400; }

.submission-group {
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 1rem;
    overflow: hidden;
}

.submission-group-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: nowrap;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    background: rgba(125,133,144,0.1);
    border-bottom: 1px solid var(--border);
}

.submission-group-header h4 {
    margin: 0;
    color: var(--text-primary);
    flex: 1 1 auto;
    min-width: 0;
}

.batch-progress {
    height: 8px;
    background: rgba(125,133,144,0.2);
    border-radius: 4px;
    overflow: hidden;
    margin: 0.5rem 0;
}

.batch-progress-bar {
    height: 100%;
    background: var(--accent);
    transition: width 0.2s ease;
}

.submission-group-note {
    padding: 0.4rem 0.9rem;
    color: var(--text-muted);
    font-size: 0.8rem;
    border-bottom: 1px solid var(--border);
}

.submission-group-rows .submission-item {
    border: none;
    border-radius: 0;
    border-bottom: 1px solid var(--border);
}

.submission-group-rows .submission-item:last-child {
    border-bottom: none;
}

/* The student's own submission record, on the assignment card. It is the
   answer to "did my upload go through?", so it sits under the assignment it
   belongs to rather than on a page of its own. */
.submission-record {
    margin-top: 0.9rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
}

.submission-record h4 {
    margin: 0;
    padding: 0.5rem 0.9rem;
    font-size: 0.85rem;
    color: var(--text-muted);
    background: rgba(125,133,144,0.1);
    border-bottom: 1px solid var(--border);
}

.submission-record-empty {
    margin: 0.9rem 0 0;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* Submission accepted. On a phone the old version was a plain heading in a
   modal and read like more form — this is meant to be unmistakable at a
   glance, before anything is scrolled. */
.submission-ok {
    text-align: center;
    padding: 0.5rem 0 0;
}

.submission-ok h3 {
    margin: 0.6rem 0 0.4rem;
    font-size: 1.5rem;
    color: var(--success);
}

.submission-ok h3::before {
    content: "✓";
    display: block;
    width: 3.2rem;
    height: 3.2rem;
    line-height: 3.2rem;
    margin: 0 auto 0.6rem;
    border-radius: 50%;
    font-size: 1.9rem;
    color: #fff;
    background: var(--success);
}

.submission-ok > p:first-of-type {
    font-size: 1.05rem;
    color: var(--text-primary);
}

.submission-ok p { margin: 0.35rem 0; }
.submission-ok .form-help { margin-top: 0.8rem; }

.submission-ok-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 1.2rem;
}

@media (max-width: 560px) {
    .submission-ok-actions { flex-direction: column; }
    .submission-ok-actions .btn { width: 100%; padding: 0.75rem 1rem; }
}

.cal-target-flash {
    animation: cal-flash 1.5s ease-out;
}

@keyframes cal-flash {
    0%, 100% { box-shadow: none; }
    20% { box-shadow: 0 0 0 3px var(--accent); }
}

.card p {
    color: var(--text-secondary);
    font-size: 0.875rem;
    margin-bottom: 1rem;
}

.card-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.assignment-meta {
    justify-content: flex-start;
    align-items: center;
}

.deadline-lines {
    display: inline-grid;
    grid-template-columns: max-content 1fr;
    column-gap: 0.35rem;
    row-gap: 0;
    line-height: 1.15;
}

.deadline-lines span {
    display: contents;
}

.deadline-lines strong {
    color: var(--text-secondary);
    font-weight: 600;
}

.problem-link {
    text-decoration: none;
    color: var(--text-primary);
}

.problem-link:hover {
    color: var(--accent);
}

.instructor-notes {
    margin: 0.5rem 0;
    padding: 0.5rem 0.75rem;
    border: 1px dashed var(--border, #c8c8c8);
    border-radius: 6px;
    background: var(--surface-muted, rgba(0, 0, 0, 0.03));
    font-size: 0.85rem;
}

.instructor-notes > summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--text-secondary);
}

.instructor-notes ul {
    margin: 0.5rem 0 0;
    padding-left: 1.25rem;
}

.instructor-notes li + li {
    margin-top: 0.25rem;
}

.badge {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 500;
}

.badge-success { background: rgba(63,185,80,0.2); color: var(--success); }
.badge-warning { background: rgba(210,153,34,0.2); color: var(--warning); }
.badge-error { background: rgba(248,81,73,0.2); color: var(--error); }
.badge-info { background: rgba(88,166,255,0.2); color: var(--accent); }

.badge-button {
    border: none;
    cursor: pointer;
    font-family: inherit;
}
.badge-button:hover {
    filter: brightness(1.15);
    text-decoration: line-through;
}

.page-title-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.homework-filter-switch {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    min-width: 5.8rem;
    padding: 0.28rem 0.65rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.2s, color 0.2s, background 0.2s;
}

.homework-filter-switch:hover,
.homework-filter-switch[data-mode="current"] {
    border-color: var(--accent);
    color: var(--accent);
}

.homework-filter-switch[data-mode="all"] {
    color: var(--text-secondary);
}

/* Page Header */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.5rem;
}

.submissions-page-header {
    gap: 1rem;
}

.assignment-submissions-toolbar {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 0.75rem;
}

.page-subtitle {
    margin-top: 0.25rem;
    color: var(--text-muted);
}

.filter-select {
    padding: 0.5rem 1rem;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-primary);
}

/* Table */
.table-container {
    overflow-x: auto;
}

.assignment-submissions-table table {
    min-width: 980px;
}

.assignment-subquestions-panel {
    margin: 0.75rem 0 1rem;
}

.assignment-subquestions-table table {
    min-width: 1100px;
}

.assignment-subquestions-table th,
.assignment-subquestions-table td {
    white-space: nowrap;
}

.subquestion-max {
    display: block;
    color: var(--text-muted);
    font-size: 0.75rem;
    line-height: 1.2;
}

.table-actions {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
}

table {
    width: 100%;
    border-collapse: collapse;
    background: var(--bg-card);
    border-radius: var(--radius);
    overflow: hidden;
}

th, td {
    padding: 0.75rem 1rem;
    text-align: left;
    border-bottom: 1px solid var(--border);
}

th {
    background: var(--bg-tertiary);
    font-weight: 600;
    color: var(--text-secondary);
    font-size: 0.875rem;
}

tr:hover {
    background: var(--bg-tertiary);
}

/* Modal */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0,0,0,0.7);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.modal {
    background: var(--bg-secondary);
    border-radius: var(--radius);
    border: 1px solid var(--border);
    width: 90%;
    max-width: 600px;
    max-height: 80vh;
    overflow-y: auto;
}

.modal.modal-wide {
    max-width: 1200px;
}

/* Full-viewport modal — for side-by-side document comparison, where a
   centred dialog wastes most of the screen. */
.modal.modal-fullscreen {
    width: 100vw;
    max-width: 100vw;
    height: 100vh;
    max-height: 100vh;
    border-radius: 0;
    border: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.modal.modal-fullscreen .modal-body {
    flex: 1;
    min-height: 0;
    overflow: auto;
    /* The dialog's roomy padding is wasted space once it fills the screen. */
    padding: 0.75rem 1rem 1rem;
    display: flex;
}

.modal.modal-fullscreen .modal-body > * {
    flex: 1;
    min-height: 0;
}

.modal.modal-fullscreen .pdf-review {
    height: 100%;
}

.modal.modal-fullscreen .pdf-review-frame,
.modal.modal-fullscreen .pdf-review-markdown,
.modal.modal-fullscreen .pdf-review-rendered {
    height: auto;
    min-height: 0;
    max-height: none;
    flex: 1;
}

/* Grading preview view switch: student's upload vs typeset transcription. */
.grade-fs-pdf-views {
    display: inline-flex;
    gap: 0.25rem;
}

.grade-fs-pdf-views .btn.is-active {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
}

/* PDF → Markdown transcription review: the rendered PDF on the left, the
   Markdown that will actually be graded on the right. */
.pdf-review {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    align-items: stretch;
}

.pdf-review-pane {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.pdf-review-pane h4 {
    margin: 0 0 0.5rem;
}

.pdf-review-frame {
    width: 100%;
    height: 60vh;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-secondary);
}

.pdf-review-tabs {
    display: flex;
    gap: 0.25rem;
    margin-bottom: 0.5rem;
}

.pdf-review-tab {
    padding: 0.35rem 0.75rem;
    background: none;
    border: 1px solid transparent;
    border-bottom: 2px solid transparent;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.85rem;
}

.pdf-review-tab.is-active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

/* Rendered transcription — the pandoc-typeset PDF the student compares
   against their own upload. */
.pdf-review-rendered {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 44vh;
}

.pdf-review-rendered .pdf-review-frame {
    flex: 1;
    min-height: 44vh;
}

#pdf-review-render-note:empty {
    display: none;
}

#pdf-review-render-note {
    white-space: pre-line;
}

/* The compiler's own error excerpt in the compile-failure dialog. */
.compile-error-detail {
    margin: .5rem 0 1rem;
    padding: .75rem 1rem;
    background: var(--bg-tertiary, rgba(127, 127, 127, .12));
    border-left: 3px solid var(--error);
    border-radius: 6px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .85rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.pdf-review-markdown {
    width: 100%;
    flex: 1;
    min-height: 44vh;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
    line-height: 1.45;
    padding: 0.75rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    resize: vertical;
}

.pdf-review-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.75rem;
}

@media (max-width: 900px) {
    .pdf-review {
        grid-template-columns: 1fr;
    }

    .pdf-review-frame {
        height: 45vh;
    }
}

.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 1.5rem;
    border-bottom: 1px solid var(--border);
}

.modal-close {
    background: none;
    border: none;
    color: var(--text-secondary);
    font-size: 1.5rem;
    cursor: pointer;
}

.modal-body {
    padding: 1.5rem;
}

/* Student answers are server-watermarked images drawn onto a canvas. These
   UI restrictions deter casual saving; they cannot prevent screenshots. */
.solution-viewer {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
}

.solution-viewer-note {
    margin: 0;
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.solution-viewer-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.solution-viewer-zoom {
    display: inline-flex;
    gap: 0.5rem;
}

.solution-page-scroll {
    flex: 1;
    min-height: 0;
    overflow: auto;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

#solution-canvas {
    display: block;
    width: 100%;
    height: auto;
    background: white;
    pointer-events: none;
}

@media print {
    body.solution-viewer-open {
        display: none !important;
    }
}

.submit-method-tabs,
.signature-mode-tabs {
    display: inline-flex;
    gap: 0.25rem;
    padding: 0.25rem;
    margin-bottom: 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-tertiary);
}

.submit-method-tab,
.signature-mode-tab {
    border: 0;
    border-radius: calc(var(--radius) - 2px);
    padding: 0.55rem 0.85rem;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.875rem;
}

.submit-method-tab.is-active,
.signature-mode-tab.is-active {
    background: var(--bg-secondary);
    color: var(--text-primary);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.generated-declaration-panel {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* The declaration wording, above the signature pad. Deliberately *not* an
   inner scroll box: nothing a student signs should be hidden behind a
   scrollbar they may never touch. The whole text is laid out, and scrolling
   the dialog down to the signature pad takes them past all of it. */
.declaration-reading {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-tertiary);
    padding: .9rem 1.1rem;
    font-size: .88rem;
    line-height: 1.6;
    color: var(--text-secondary);
}

.declaration-reading h4 {
    margin: 0 0 .6rem;
    font-size: .92rem;
    color: var(--text-primary);
}

.declaration-reading p {
    margin: 0 0 .7rem;
}

.declaration-reading p:last-child {
    margin-bottom: 0;
}

.declaration-generated-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

.declaration-generated-grid input[readonly] {
    color: var(--text-secondary);
}

.signature-panel {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.signature-stage {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.signature-stage-tools {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Only worth saying on a portrait handset: landscape roughly doubles the
   usable width of the pad. */
.signature-rotate-hint {
    display: none;
    margin: 0;
    color: var(--text-secondary);
    font-size: 0.8125rem;
}

@media (max-width: 900px) and (orientation: portrait) {
    .signature-rotate-hint {
        display: block;
    }
}

/* Not the Fullscreen API: iOS Safari refuses it on non-video elements. */
.signature-stage.is-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 2000;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.75rem;
    padding-top: max(0.75rem, env(safe-area-inset-top));
    padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
    background: var(--bg-secondary);
}

body.signature-fullscreen-open {
    overflow: hidden;
}

.signature-canvas-wrap {
    width: 100%;
    aspect-ratio: 18 / 5;
    min-height: 150px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-primary);
    overflow: hidden;
}

/* Fullscreen means fullscreen: the pad takes every row the hint and the button
   row leave it. The 2:1 cap is the one concession — the PDF signature box is
   about 3.8:1, and strokes map into it by proportion, so a near-square pad
   would land in the form noticeably squashed. */
.signature-stage.is-fullscreen .signature-canvas-wrap {
    flex: 1 1 auto;
    aspect-ratio: auto;
    min-height: 0;
    max-height: calc((100vw - 1.5rem) / 2);
}

.signature-canvas-wrap canvas {
    width: 100%;
    height: 100%;
    display: block;
    touch-action: none;
    cursor: crosshair;
}

.signature-legal,
.legal-confirmation {
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.legal-confirmation {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
}

.typed-signature-preview {
    min-height: 4.5rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-primary);
    font-family: "Brush Script MT", "Segoe Script", "Snell Roundhand", cursive;
    font-style: normal;
    font-weight: 400;
    font-size: 2rem;
    line-height: 1.35;
    color: var(--text-primary);
}

@media (max-width: 700px) {
    .declaration-generated-grid {
        grid-template-columns: 1fr;
    }

    .submit-method-tabs,
    .signature-mode-tabs {
        width: 100%;
    }

    .submit-method-tab,
    .signature-mode-tab {
        flex: 1;
    }
}

.grade-context {
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
}

.grade-context p {
    margin: 0.25rem 0;
}

/* Full-screen grading page */
.page-content.grade-fs-page {
    margin: 0;
    padding: 0;
    height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--bg-primary);
}

.grade-fs-header {
    flex: 0 0 auto;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border);
    background: var(--bg-secondary);
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.grade-fs-splitter {
    display: none;
    background: var(--border);
    z-index: 3;
}

.grade-fs-splitter:hover {
    background: var(--accent);
}

.is-resizing-grade {
    cursor: col-resize;
    user-select: none;
}

.grade-fs-header-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.grade-fs-meta {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.grade-fs-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-left: auto;
}

.grade-fs-score-inline {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--text-secondary);
    font-size: 0.8rem;
    white-space: nowrap;
}

.grade-fs-score-inline input[type="number"] {
    width: 4.5rem;
    padding: 0.4rem 0.5rem;
}

.grade-fs-meta strong {
    color: var(--text-primary);
}

.grade-fs-meta-line {
    line-height: 1.3;
}

.grade-fs-meta-sub {
    color: var(--text-muted);
    font-size: 0.8rem;
}

.grade-fs-form {
    display: flex;
    align-items: flex-end;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.grade-fs-field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
    width: 100%;
}

.grade-fs-field-grow {
    flex: 1 1 320px;
    min-width: 168px;
}

.grade-fs-field-label {
    font-weight: 500;
}

.grade-fs-field input[type="number"] {
    width: 90px;
}

.grade-fs-field textarea {
    width: 100%;
    min-height: 38px;
    resize: vertical;
    max-width: 100%;
}

.grade-fs-subquestions {
    flex: 1 1 100%;
    min-width: 196px;
    width: 100%;
}

.grade-fs-subquestion-editor {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.45rem;
    align-items: start;
}

.grade-fs-subquestion-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(86px, 1fr));
    gap: 0.35rem;
    align-items: end;
}

.grade-fs-subquestion-field {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem 0.35rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: 0.76rem;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.grade-fs-subquestion-field.is-active {
    border-color: var(--accent);
    background: rgba(37, 99, 235, 0.12);
    color: var(--text-primary);
}

.grade-fs-subquestion-field span {
    white-space: nowrap;
}

.grade-fs-subquestion-field input[type="number"] {
    width: 2.8rem;
    padding: 0.25rem;
}

.grade-fs-subquestion-feedback {
    display: block;
    width: 100%;
    min-width: 0;
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.grade-fs-subquestion-feedback textarea {
    width: 100%;
    min-height: 42px;
    resize: vertical;
    max-width: 100%;
}

.grade-fs-out-of {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-left: 0.25rem;
}

.grade-fs-body {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    min-height: 0;
    overflow: hidden;
}

.grade-layout-single .grade-fs-body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "source pdf";
}

.grade-layout-single .grade-fs-preview-splitter {
    display: none;
}

.page-content.grade-fs-page.grade-layout-split,
.page-content.grade-fs-page.grade-layout-pdf-right {
    display: grid;
    grid-template-columns: minmax(0, var(--grade-main-split, 50%)) 6px minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    grid-template-areas:
        "controls main-split previews";
    overflow: hidden;
}

.page-content.grade-fs-page.grade-layout-split.grade-layout-mirror {
    grid-template-columns: minmax(0, 1fr) 6px minmax(0, var(--grade-main-split, 50%));
    grid-template-areas:
        "previews main-split controls";
}

.page-content.grade-fs-page.grade-layout-pdf-right {
    grid-template-rows: minmax(7rem, var(--grade-preview-split, 50%)) 6px minmax(7rem, 1fr);
    grid-template-areas:
        "controls main-split pdf"
        "preview-split main-split pdf"
        "source main-split pdf";
}

.page-content.grade-fs-page.grade-layout-pdf-right.grade-layout-mirror {
    grid-template-columns: minmax(0, 1fr) 6px minmax(0, var(--grade-main-split, 50%));
    grid-template-areas:
        "pdf main-split controls"
        "pdf main-split preview-split"
        "pdf main-split source";
}

.grade-layout-split .grade-fs-header,
.grade-layout-pdf-right .grade-fs-header {
    grid-area: controls;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    border-bottom: none;
    border-right: 1px solid var(--border);
}

.grade-layout-split.grade-layout-mirror .grade-fs-header,
.grade-layout-pdf-right.grade-layout-mirror .grade-fs-header {
    border-right: none;
    border-left: 1px solid var(--border);
}

.grade-layout-split .grade-fs-form,
.grade-layout-pdf-right .grade-fs-form {
    flex: 1 1 auto;
    align-items: stretch;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

.grade-layout-split .grade-fs-actions,
.grade-layout-pdf-right .grade-fs-actions {
    flex: 0 0 100%;
    flex-wrap: nowrap;
    gap: 0.35rem;
    margin-left: 0;
    white-space: nowrap;
}

.grade-layout-split .grade-fs-header-row,
.grade-layout-pdf-right .grade-fs-header-row {
    flex: 0 0 auto;
    flex-wrap: wrap;
}

.grade-layout-split .grade-fs-meta,
.grade-layout-pdf-right .grade-fs-meta {
    flex: 1 1 auto;
    min-width: 4rem;
}

.grade-layout-split .grade-fs-actions .btn,
.grade-layout-pdf-right .grade-fs-actions .btn {
    padding-inline: 0.55rem;
}

.grade-layout-split .grade-fs-score-inline,
.grade-layout-pdf-right .grade-fs-score-inline {
    gap: 0.2rem;
}

.grade-layout-split .grade-fs-score-inline input[type="number"],
.grade-layout-pdf-right .grade-fs-score-inline input[type="number"] {
    width: 3.4rem;
    padding-inline: 0.35rem;
}

.grade-layout-split .grade-fs-body {
    grid-area: previews;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(7rem, var(--grade-preview-split, 50%)) 6px minmax(7rem, 1fr);
    grid-template-areas:
        "source"
        "preview-split"
        "pdf";
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

.grade-layout-pdf-right .grade-fs-body {
    display: contents;
}

.grade-layout-split .grade-fs-subquestions,
.grade-layout-pdf-right .grade-fs-subquestions {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

.grade-layout-split .grade-fs-subquestion-editor,
.grade-layout-pdf-right .grade-fs-subquestion-editor {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.grade-layout-split .grade-fs-subquestion-grid,
.grade-layout-pdf-right .grade-fs-subquestion-grid {
    flex: 0 0 auto;
    width: 100%;
    min-width: 0;
    grid-template-columns: repeat(auto-fit, minmax(min(6rem, 100%), 1fr));
}

.grade-layout-split .grade-fs-subquestion-feedback,
.grade-layout-pdf-right .grade-fs-subquestion-feedback,
.grade-layout-split .grade-fs-field-grow,
.grade-layout-pdf-right .grade-fs-field-grow {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.grade-layout-split .grade-fs-field,
.grade-layout-pdf-right .grade-fs-field {
    min-height: 0;
}

.grade-layout-split .grade-fs-field textarea,
.grade-layout-pdf-right .grade-fs-field textarea,
.grade-layout-split .grade-fs-subquestion-feedback textarea,
.grade-layout-pdf-right .grade-fs-subquestion-feedback textarea {
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
    max-height: 100%;
    overflow: hidden;
}

.grade-layout-single .grade-fs-source-pane {
    grid-area: source;
}

.grade-layout-single .grade-fs-pdf-pane {
    grid-area: pdf;
}

.grade-layout-single.grade-layout-mirror .grade-fs-body {
    grid-template-areas: "pdf source";
}

.grade-layout-split .grade-fs-source-pane,
.grade-layout-pdf-right .grade-fs-source-pane {
    grid-area: source;
}

.grade-layout-split .grade-fs-preview-splitter,
.grade-layout-pdf-right .grade-fs-preview-splitter {
    grid-area: preview-split;
}

.grade-layout-split .grade-fs-pdf-pane,
.grade-layout-pdf-right .grade-fs-pdf-pane {
    grid-area: pdf;
}

.grade-layout-split .grade-fs-main-splitter,
.grade-layout-pdf-right .grade-fs-main-splitter {
    display: block;
    grid-area: main-split;
    cursor: col-resize;
}

.grade-layout-split .grade-fs-preview-splitter,
.grade-layout-pdf-right .grade-fs-preview-splitter {
    display: block;
    cursor: row-resize;
}

.grade-layout-split .grade-fs-source-pane,
.grade-layout-pdf-right .grade-fs-source-pane,
.grade-layout-split .grade-fs-pdf-pane,
.grade-layout-pdf-right .grade-fs-pdf-pane {
    border-right: none;
}

.grade-layout-split .grade-fs-source-pane,
.grade-layout-pdf-right .grade-fs-source-pane {
    border-bottom: none;
}

.grade-fs-pane {
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--border);
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    background: var(--bg-card);
}

.grade-fs-pane:last-child {
    border-right: none;
}

.grade-layout-single .grade-fs-source-pane {
    border-right: 1px solid var(--border);
}

.grade-layout-single.grade-layout-mirror .grade-fs-source-pane {
    border-right: none;
}

.grade-layout-single.grade-layout-mirror .grade-fs-pdf-pane {
    border-right: 1px solid var(--border);
}

.grade-fs-pane-head {
    flex: 0 0 auto;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border);
    background: var(--bg-tertiary);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.grade-fs-pane-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    background: var(--bg-card);
}

.grade-fs-source {
    margin: 0;
    padding: 0.75rem 1rem;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--text-primary);
}

.grade-fs-source.is-empty {
    color: var(--text-muted);
    font-family: inherit;
    font-size: 0.9rem;
}

iframe.grade-fs-pane-body {
    border: 0;
    width: 100%;
    height: 100%;
}

@media (max-width: 900px) {
    .grade-layout-split .grade-fs-header,
    .grade-layout-pdf-right .grade-fs-header,
    .grade-layout-split .grade-fs-body {
        resize: none;
    }
    .grade-layout-single .grade-fs-body {
        grid-template-columns: 1fr;
        grid-auto-rows: minmax(0, 1fr);
    }
    .grade-layout-single .grade-fs-pane {
        border-right: none;
        border-bottom: 1px solid var(--border);
    }
    .grade-layout-single .grade-fs-pane:last-child {
        border-bottom: none;
    }
}

/* Toast */
.toast-container {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.toast {
    padding: 1rem 1.5rem;
    border-radius: var(--radius);
    color: #fff;
    animation: slideIn 0.3s ease;
    min-width: 300px;
}

.toast-success { background: var(--success); }
.toast-error { background: var(--error); }
.toast-info { background: var(--accent); }

@keyframes slideIn {
    from { transform: translateX(100%); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

/* Submission Item */
.submission-item {
    background: var(--bg-card);
    padding: 1rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    margin-bottom: 1rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.submission-info h4 {
    margin-bottom: 0.25rem;
}

.submission-info p {
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.submission-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.checkbox-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.75rem 0 1rem;
    color: var(--text-primary);
}

.ai-feedback-box {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem;
    line-height: 1.5;
    white-space: normal;
}

.ai-rubric-scores ul {
    margin-left: 1.25rem;
}

/* Recent Section */
.recent-section {
    margin-top: 2rem;
}

.recent-section h3 {
    margin-bottom: 1rem;
    color: var(--text-secondary);
}

/* Course Materials */
.course-info {
    background: var(--bg-card);
    padding: 1.25rem 1.5rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    margin-bottom: 1.5rem;
}

.course-info p {
    color: var(--text-secondary);
    font-size: 0.9rem;
    margin-bottom: 0.25rem;
}

.materials-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
}

/* Rich materials view used by courses that ship a hand-authored block of
 * HTML (see COURSE_MATERIALS_HTML_BY_CODE in app.js). Visual identity ports
 * the original STOTCC/index.html look — section-as-card, accent-colored
 * heading rules, pill tags, schedule table — onto the SPA's theme tokens so
 * dark/light mode keep working. Spans the full grid width. */
.materials-rich {
    grid-column: 1 / -1;
    line-height: 1.6;
    color: var(--text-primary);
}

/* Header banner sits flush across the top of the materials grid. Uses the
 * accent gradient already used elsewhere in the app for visual cohesion. */
.materials-rich-header {
    margin: 0 0 1rem;
    padding: 1.5rem 1.25rem 1.25rem;
    border-radius: var(--radius);
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%);
    color: #fff;
}
.materials-rich-header h2 { margin: 0 0 .35rem; font-size: 1.6rem; line-height: 1.25; color: #fff; }
.materials-rich-header p { margin: .2rem 0; color: rgba(255, 255, 255, 0.92); }
.materials-rich-header .tag { background: rgba(255, 255, 255, 0.18); color: #fff; }

/* Each <section> renders as its own card so the long page reads like a
 * stack of boxes rather than a wall of text. The h3 gets an accent-coloured
 * left bar matching the original index.html design. */
.materials-rich section {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem 1.15rem 1.15rem;
    margin: 0 0 1rem;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}
.materials-rich section h3 {
    margin: 0 0 .75rem;
    font-size: 1.15rem;
    line-height: 1.3;
    border-left: 4px solid var(--accent);
    padding-left: .55rem;
    color: var(--text-primary);
}
.materials-rich section p { margin: .35rem 0; }
.materials-rich section ul,
.materials-rich section ol { padding-left: 1.25rem; margin: .5rem 0; }
.materials-rich section li { margin: .15rem 0; }

.materials-rich .tag {
    display: inline-block;
    padding: .2rem .55rem;
    margin: .15rem .35rem .15rem 0;
    border-radius: 999px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .3px;
}
.materials-rich .materials-tags { margin-top: .6rem; }

.materials-rich .dl-list { list-style: none; padding-left: 0; }
.materials-rich .dl-list li { margin: .35rem 0; }
.materials-rich .dl-list a {
    color: var(--accent);
    font-weight: 600;
    text-decoration: none;
}
.materials-rich .dl-list a:hover { text-decoration: underline; }

.materials-rich .materials-note {
    margin-top: .6rem;
    color: var(--text-muted);
    font-size: .85rem;
}
.materials-rich .materials-alert {
    margin: .75rem 0 0;
    padding: .55rem .75rem;
    background: rgba(238, 178, 64, 0.12);
    border: 1px solid rgba(238, 178, 64, 0.45);
    border-radius: 6px;
    font-size: .9rem;
    color: var(--text-primary);
}

.materials-rich .materials-schedule {
    width: 100%;
    border-collapse: collapse;
    font-size: .92rem;
    margin-top: .5rem;
}
.materials-rich .materials-schedule th,
.materials-rich .materials-schedule td {
    border: 1px solid var(--border);
    padding: .4rem .55rem;
    text-align: left;
    vertical-align: top;
}
.materials-rich .materials-schedule th {
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-weight: 600;
}

.materials-rich-footer {
    margin: 1rem 0 0;
    padding-top: .75rem;
    color: var(--text-muted);
    font-size: .8rem;
    text-align: center;
}

@media (max-width: 700px) {
    .materials-rich-header h2 { font-size: 1.3rem; }
    .materials-rich .materials-schedule { font-size: .82rem; }
}

.materials-homework-section {
    grid-column: 1 / -1;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-left: 4px solid var(--accent);
    border-radius: var(--radius);
    padding: 1.1rem 1.25rem;
    margin-bottom: 0.5rem;
}

.section-heading-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.section-heading-row h3 {
    margin: 0;
    color: var(--text-primary);
    font-size: 1.2rem;
}

.materials-homework-detail {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1rem;
    width: 100%;
}

.materials-homework-copy {
    flex: 1 1 auto;
    min-width: 0;
}

.materials-homework-copy p {
    color: var(--text-secondary);
    margin-bottom: 0.75rem;
}

.material-card {
    background: var(--bg-card);
    padding: 1.25rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    transition: border-color 0.2s;
}

.material-card:hover {
    border-color: var(--accent);
}

.material-card h3 {
    margin-bottom: 0.5rem;
    color: var(--text-primary);
    font-size: 0.95rem;
    border-bottom: 1px solid var(--border);
    padding-bottom: 0.5rem;
}

.material-card p {
    color: var(--text-muted);
    font-size: 0.8rem;
    margin-top: 0.5rem;
}

/* Grey indicates availability to instructors before student release. */
.material-card-unreleased {
    background: var(--bg-tertiary);
    border-color: var(--border);
}

.material-card-unreleased:hover {
    border-color: var(--text-muted);
}

.material-card-unreleased h3,
.material-card-unreleased p {
    color: var(--text-secondary);
}

.material-card-unreleased .material-release-status {
    margin: 0 0 0.75rem;
    font-style: normal;
    font-weight: 600;
}

.material-card-unreleased .link-list a {
    background: #626975;
    color: #fff;
}

.link-list {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.link-list li {
    margin: 0;
}

.link-list a {
    display: inline-block;
    padding: 0.4rem 0.8rem;
    border-radius: var(--radius);
    color: #fff;
    text-decoration: none;
    font-size: 0.8rem;
    transition: opacity 0.2s;
}

.link-list a:hover {
    opacity: 0.85;
}

.slides-link {
    background: var(--accent);
}

.notes-link {
    background: var(--success);
}

/* Homework Instructions */
.hw-instructions {
    background: var(--bg-card);
    padding: 1rem 1.25rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    margin-bottom: 1rem;
    font-size: 0.875rem;
    color: var(--text-secondary);
    grid-column: 1 / -1;
}

/* Responsive */
@media (max-width: 768px) {
    .container {
        flex-direction: column;
    }

    /* Stack the sidebar on top at full width regardless of any persisted
       collapsed state from desktop. */
    .sidebar,
    .sidebar.collapsed {
        width: 100%;
        border-right: none;
        border-bottom: 1px solid var(--border);
        position: static;
        top: auto;
        height: auto;
        align-self: stretch;
    }

    /* Re-show labels even if .collapsed lingers from a prior desktop
       session, but keep the homework sub-list hidden — the sidebar is
       a horizontal top bar at this width and the sublist would wrap
       awkwardly. */
    .sidebar.collapsed .nav-label {
        display: inline;
    }
    .sidebar.collapsed .sidebar-tool-label {
        display: inline;
    }
    .sidebar.collapsed .nav-item {
        padding: 0.75rem 1rem;
        justify-content: flex-start;
    }
    .sidebar.collapsed .nav-submenu,
    .nav-submenu {
        display: none;
    }

    .sidebar-toggle {
        display: none;
    }

    .sidebar-bottom {
        flex-direction: row;
        align-items: center;
        overflow-x: auto;
    }

    body.show-grading-layout-controls .grading-layout-controls {
        display: flex;
        flex: 1 1 auto;
    }

    .sidebar-session-controls,
    .sidebar.collapsed .sidebar-session-controls {
        flex-direction: row;
        flex: 0 0 auto;
    }

    .nav-menu {
        display: flex;
        overflow-x: auto;
    }

    .nav-item {
        white-space: nowrap;
        padding: 0.75rem 1rem;
    }

    .nav-item.active {
        border-left: none;
        border-bottom: 3px solid var(--accent);
    }

    .materials-homework-detail {
        align-items: flex-start;
        flex-direction: column;
    }

    .card-grid {
        grid-template-columns: 1fr;
    }
}

/* Shared course workspace: identical chapter geometry across account roles. */
.course-page {width:100%;max-width:1120px;margin-inline:auto;--course-accent:var(--accent)}
.sidebar {flex-shrink:0}
.course-page>h2 {font-size:clamp(1.4rem,2.5vw,2rem);letter-spacing:-.025em;line-height:1.25;margin-bottom:1.25rem}
.course-page .course-info {background:linear-gradient(135deg,var(--bg-card),var(--bg-secondary));border-radius:16px;padding:1.25rem 1.5rem}
.course-page .materials-grid {grid-template-columns:repeat(3,minmax(0,1fr));gap:1.1rem;align-items:stretch}
.materials-grid>.form-help {grid-column:1/-1;margin:0}
.course-page .material-card {min-width:0;border-radius:16px;padding:1.3rem;display:flex;flex-direction:column;box-shadow:0 4px 20px #00000005;transition:border-color .2s,box-shadow .2s}
.course-page .material-card:hover {box-shadow:0 8px 24px #0000000b}
.course-page .chapter-title {position:relative;min-height:3.4rem;line-height:1.4;font-size:1rem;letter-spacing:-.015em;padding:0 1rem .85rem 0;margin-bottom:1rem}
.chapter-title-link {color:inherit;text-decoration:none;display:block}
.chapter-title-link:hover {color:var(--accent)}
.chapter-title-arrow {position:absolute;right:0;top:0;color:var(--text-muted);font-size:.9rem}
.chapter-title-link:focus-visible,.public-nav-item:focus-visible,.nav-page-button:focus-visible {outline:2px solid var(--accent);outline-offset:5px;border-radius:4px}
.course-page .link-list {gap:.5rem}
.course-page .link-list a {white-space:normal;overflow-wrap:anywhere;border-radius:8px;line-height:1.5;padding:.45rem .7rem}
.course-page .material-card>p:last-child {margin-top:1rem;line-height:1.6}
.course-page .material-card>p:last-child em {font-style:normal}
.public-course-shell {min-height:calc(100vh - 48px)}
.public-sidebar {top:48px;height:calc(100vh - 48px)}
.public-nav-item,.nav-page-button {width:100%;border:0;background:none;color:var(--text-secondary);font:inherit;text-align:left;cursor:pointer;display:flex;align-items:center;gap:.65rem}
.public-nav-item {padding:.85rem 1.5rem;border-left:3px solid transparent}
.public-nav-item:hover {background:var(--bg-tertiary);color:var(--text-primary)}
.public-nav-item.active {background:var(--bg-tertiary);border-left-color:var(--accent);color:var(--accent);font-weight:600}
@media(max-width:1150px) {.course-page .materials-grid {grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:768px) {
 .course-page .materials-grid {grid-template-columns:repeat(2,minmax(0,1fr))}
 .public-sidebar {top:auto;height:auto}.public-sidebar .nav-menu {padding:0 .5rem;gap:.2rem}
 .public-nav-item {white-space:nowrap;padding:.8rem 1rem;border-left:0;border-bottom:3px solid transparent}
 .public-nav-item.active {border-left:0;border-bottom-color:var(--accent)}
 .content:has(>.course-page:not(.hidden)) {padding:1.25rem}
}
@media(max-width:560px) {.course-page .materials-grid {grid-template-columns:minmax(0,1fr)}.course-page .chapter-title {min-height:0}.course-page .course-info {padding:1rem}.course-page .material-card {padding:1.15rem}}

.calendar-page-heading {margin-bottom:1.5rem}.calendar-page-heading h2 {font-size:2rem;letter-spacing:-.035em;margin:.25rem 0 .5rem}
.course-eyebrow {font-size:.7rem;color:var(--accent);letter-spacing:.13em;font-weight:700}
.calendar-collections {display:flex;flex-wrap:wrap;gap:.75rem;margin-top:1.25rem}.calendar-collections a {border:1px solid var(--border);background:var(--bg-card);border-radius:10px;padding:.65rem .9rem;font-size:.85rem;text-decoration:none;color:var(--accent)}
.course-page .cal-grid {border-radius:0 0 16px 16px;overflow:hidden}.course-page .cal-header {border-radius:16px 16px 0 0;padding:1rem;background:var(--bg-card);border:1px solid var(--border);margin-bottom:0}
.course-page .cal-cell {min-width:0;min-height:112px;background:var(--bg-card)}.cal-event-video {background:#176e8c20;color:var(--accent);border-left:3px solid #2188a6;text-decoration:none}
.course-page .cal-event {max-width:100%;overflow-wrap:anywhere;white-space:normal;text-align:left;line-height:1.35}
.course-page .cal-day {font-size:.85rem;font-weight:600}.course-page .cal-cell-today {box-shadow:inset 0 0 0 2px var(--accent)}
@media(max-width:560px){.course-page .cal-cell {min-height:80px;padding:4px}.course-page .cal-event {padding:3px;font-size:.62rem}.course-page .cal-header {gap:.7rem;flex-wrap:wrap}.course-page .cal-legend {flex-wrap:wrap}.course-page .cal-dow {font-size:.7rem}}

.cal-agenda {display:none}
@media(max-width:560px){
 .course-page .cal-grid {display:none}.cal-agenda {display:block;padding:.25rem 0}
 .cal-agenda-day {display:grid;grid-template-columns:42px minmax(0,1fr);gap:12px;padding:16px 4px;border-bottom:1px solid var(--border)}
 .cal-agenda-date {display:flex;flex-direction:column;text-align:center}.cal-agenda-date strong {font-size:1.35rem;line-height:1.2}.cal-agenda-date span {font-size:.7rem;color:var(--text-muted)}
 .cal-agenda .cal-event {font-size:.8rem;padding:8px 10px;margin-bottom:6px;width:100%}
 #main-app .sidebar,#main-app .sidebar.collapsed {width:100%;min-width:0;flex-basis:auto}.nav-menu {max-width:100%}
}

/* ------------------------------------------------------------------------
 * Course-website port (GECC1132CH). The Materials view loads one HTML
 * fragment per language generated from the static course site
 * (scripts/build_ccstot_materials.py). These rules map the site's classes
 * (hero, section nav, section cards, facts, timeline, panels, tables,
 * resource cards, QR) onto the SPA's theme tokens so the page reads
 * correctly in dark, light and adaptive themes.
 * --------------------------------------------------------------------- */
/* Instructor-only strip above the course site: this course's teaching decks
   (instructorPresenterBarHTML in app.js, instructor_files on the server). */
.site-instructor-bar {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .75rem;
    margin: 0 0 .75rem;
    padding: .7rem .9rem;
    border: 1px dashed var(--border);
    border-radius: 10px;
    background: var(--bg-card);
}
.site-instructor-bar h3 {
    margin: 0;
    font-size: .85rem;
    font-weight: 700;
    color: var(--text-muted);
    letter-spacing: .02em;
}
.site-instructor-bar h3 span { font-weight: 400; }
.site-instructor-bar a {
    display: inline-flex;
    flex-direction: column;
    gap: .1rem;
    padding: .35rem .8rem;
    border: 1px solid var(--accent);
    border-radius: 8px;
    color: var(--accent);
    text-decoration: none;
}
.site-instructor-bar a:hover { background: var(--accent); color: #fff; }
/* The class-slides strip is the same bar for a wider audience — every
   signed-in member of the course, not only the instructor — so it is drawn
   solid rather than dashed. */
.site-class-bar { border-style: solid; }
.site-instructor-bar a strong { font-size: .9rem; }
.site-instructor-bar a span { font-size: .75rem; opacity: .85; }

.materials-site {
    grid-column: 1 / -1;
    color: var(--text-primary);
    line-height: 1.6;
    font-size: .97rem;
    --site-warm: #e08a66;
    --site-warm-bg: rgba(224, 138, 102, 0.14);
    --site-warm-line: rgba(224, 138, 102, 0.55);
}
:root[data-theme="light"] .materials-site { --site-warm: #b85c3a; --site-warm-bg: rgba(184, 92, 58, 0.10); --site-warm-line: rgba(184, 92, 58, 0.45); }
@media (prefers-color-scheme: light) {
    :root:not([data-theme]) .materials-site,
    :root[data-theme="adaptive"] .materials-site { --site-warm: #b85c3a; --site-warm-bg: rgba(184, 92, 58, 0.10); --site-warm-line: rgba(184, 92, 58, 0.45); }
}
.materials-site a { color: var(--accent); }
.materials-site [id] { scroll-margin-top: 1rem; }
.materials-site .skip-link { display: none; }

/* Hero */
.materials-site .site-hero {
    margin: 0 0 1rem;
    padding: 1.5rem 1.4rem 1.4rem;
    border-radius: var(--radius);
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%);
    color: #fff;
}
.materials-site .site-hero .eyebrow { margin: 0 0 .4rem; font-size: .74rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; opacity: .85; }
.materials-site .hero-title { margin: 0 0 .5rem; font-size: 1.8rem; font-weight: 800; line-height: 1.2; color: #fff; }
.materials-site .hero-title .course-code { display: block; font-size: .82rem; font-weight: 700; letter-spacing: .1em; opacity: .85; margin-bottom: .2rem; }
.materials-site .hero-lede { max-width: 62ch; margin: 0; color: rgba(255, 255, 255, 0.92); }
.materials-site .hero-meta { list-style: none; display: flex; flex-wrap: wrap; gap: .4rem; margin: 1rem 0 0; padding: 0; }
.materials-site .hero-meta li { padding: .25rem .7rem; border-radius: 999px; background: rgba(255, 255, 255, 0.16); font-size: .82rem; font-weight: 600; }
.materials-site .hero-actions { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1rem; }
.materials-site .button {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 2.4rem; padding: .4rem 1rem; border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.45); color: #fff; font-weight: 700; text-decoration: none;
}
.materials-site .button.primary, .materials-site .button:hover { background: #fff; border-color: #fff; color: var(--accent-hover); }

/* Section navigation */
.materials-site .section-nav { margin: 0 0 1rem; }
.materials-site .nav-shell { display: flex; flex-wrap: wrap; gap: .4rem; }
.materials-site .nav-shell a {
    padding: .3rem .75rem; border-radius: 999px; background: var(--bg-tertiary);
    color: var(--text-secondary); font-size: .8rem; font-weight: 600; text-decoration: none;
}
.materials-site .nav-shell a:hover { color: var(--accent); }

/* Section cards */
.materials-site .section-shell {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.15rem 1.25rem 1.25rem;
    margin: 0 0 1rem;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}
.materials-site .section-shell > h2, .materials-site .section-shell h2 { margin: 0 0 .6rem; font-size: 1.35rem; line-height: 1.3; color: var(--text-primary); }
.materials-site h3 { margin: 0 0 .5rem; font-size: 1.05rem; line-height: 1.3; color: var(--text-primary); }
.materials-site .section-kicker { margin: 0 0 .3rem; color: var(--site-warm); font-size: .72rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }
.materials-site .section-intro { margin: 0 0 .9rem; color: var(--text-secondary); }
.materials-site p { margin: .35rem 0; }
.materials-site ul, .materials-site ol { margin: .4rem 0; padding-left: 1.2rem; }
.materials-site .clean-list { margin: 0; padding-left: 1.1rem; }
.materials-site .clean-list li + li { margin-top: .3rem; }
.materials-site .spaced { margin-top: 1rem; }

.materials-site .notice {
    display: grid; grid-template-columns: auto 1fr; gap: .7rem; align-items: start;
    border: 1px solid rgba(210, 153, 34, 0.5); border-radius: var(--radius);
    background: rgba(210, 153, 34, 0.12); padding: .8rem .9rem;
}
.materials-site .notice-mark { display: grid; width: 1.6rem; height: 1.6rem; place-items: center; border-radius: 50%; background: var(--warning); color: #fff; font-weight: 900; }
.materials-site .notice p { margin: 0; }

.materials-site .facts-grid, .materials-site .assessment-grid, .materials-site .resource-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: .8rem;
}
.materials-site .fact, .materials-site .assessment-card, .materials-site .resource-card {
    border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-secondary); padding: .9rem 1rem;
}
.materials-site .fact-label, .materials-site .assessment-weight {
    display: block; margin-bottom: .3rem; color: var(--site-warm); font-size: .72rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
}
.materials-site .assessment-weight { font-size: 1.2rem; }
.materials-site .fact strong { font-size: 1rem; }
.materials-site .assessment-card p, .materials-site .resource-card p { margin: 0; color: var(--text-secondary); }
.materials-site .resource-card p + p { margin-top: .5rem; }
.materials-site .resource-card { overflow-wrap: anywhere; }
.materials-site .resource-card a { font-weight: 700; }
.materials-site .resource-card-qr .qr-image {
    display: block; width: 100%; max-width: 200px; height: auto; margin: .7rem auto 0;
    border: 1px solid var(--border); border-radius: var(--radius); background: #fff;
}

.materials-site .two-column { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(260px, 0.9fr); gap: 1rem; align-items: start; }
.materials-site .panel { border-radius: 12px; background: var(--bg-tertiary); padding: 1rem 1.1rem; }
.materials-site .panel.clay { background: var(--site-warm-bg); }
.materials-site .course-description { margin-top: 1rem; }

/* Timeline */
.materials-site .schedule-list { position: relative; margin: 1.25rem 0 0; padding: 0; list-style: none; }
.materials-site .schedule-list::before { position: absolute; top: 1rem; bottom: 1rem; left: calc(6.5rem + 1rem - 1px); width: 2px; background: var(--border); content: ""; }
.materials-site .schedule-item { display: grid; grid-template-columns: 6.5rem 2rem minmax(0, 1fr); align-items: start; }
.materials-site .date-block { padding-top: .45rem; text-align: right; }
.materials-site .date-block strong { display: block; color: var(--accent); font-size: 1rem; }
.materials-site .date-block span { color: var(--text-muted); font-size: .8rem; }
.materials-site .timeline-dot {
    position: relative; z-index: 1; display: block; width: .9rem; height: .9rem; margin: .7rem auto 0;
    border: 3px solid var(--bg-card); border-radius: 50%; background: var(--site-warm); box-shadow: 0 0 0 2px var(--site-warm);
}
.materials-site .schedule-card { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-secondary); padding: .9rem 1rem; margin: 0 0 .9rem; }
.materials-site .schedule-card h3 { margin: 0 0 .3rem; font-size: 1.02rem; }
.materials-site .schedule-meta { margin: 0; color: var(--text-secondary); font-size: .86rem; }
.materials-site .schedule-meta span + span::before { content: " · "; }
.materials-site .status { display: inline-block; margin-top: .55rem; border-radius: 999px; background: rgba(63, 185, 80, 0.16); color: var(--success); padding: .15rem .6rem; font-size: .72rem; font-weight: 800; }
.materials-site .status.no-class { background: var(--bg-tertiary); color: var(--text-muted); }

.materials-site .assessment-alert {
    margin-top: .9rem; border-left: 4px solid var(--site-warm); border-radius: 6px;
    background: var(--site-warm-bg); padding: .6rem .8rem; font-weight: 600;
}

/* Tables and details */
.materials-site .table-scroll { overflow-x: auto; margin-top: 1rem; }
.materials-site table { width: 100%; border-collapse: collapse; font-size: .88rem; }
.materials-site caption { text-align: left; font-weight: 700; padding-bottom: .5rem; color: var(--text-primary); }
.materials-site th, .materials-site td { border: 1px solid var(--border); padding: .5rem .6rem; text-align: left; vertical-align: top; }
.materials-site thead { background: var(--bg-tertiary); }
.materials-site tbody th { color: var(--text-primary); font-weight: 600; }
.materials-site .table-scroll th:first-child { min-width: 6.5rem; }
.materials-site .rubric-details { margin-top: 1rem; border: 1px solid var(--border); border-radius: var(--radius); padding: .8rem 1rem; }
.materials-site .rubric-details summary { cursor: pointer; font-weight: 700; color: var(--accent); }
.materials-site .rubric-details table { min-width: 760px; }

.materials-site .site-footer { margin: .5rem 0 0; color: var(--text-muted); font-size: .8rem; text-align: center; }
.materials-site .site-footer p { margin: .1rem 0; }

@media (max-width: 800px) {
    .materials-site .two-column { grid-template-columns: 1fr; }
    .materials-site .hero-title { font-size: 1.45rem; }
    .materials-site .schedule-list::before { left: .4rem; }
    .materials-site .schedule-item { grid-template-columns: 1rem minmax(0, 1fr); column-gap: .9rem; margin-bottom: .6rem; }
    .materials-site .date-block { grid-column: 2; margin-bottom: .3rem; padding: 0; text-align: left; }
    .materials-site .date-block strong { display: inline; margin-right: .4rem; }
    .materials-site .timeline-dot { grid-column: 1; grid-row: 1 / span 2; width: .8rem; height: .8rem; margin-top: .35rem; }
    .materials-site .schedule-card { grid-column: 2; }
}

/* --- Course groups (student-formed) --------------------------------------
   The Groups page: one card per group with its optional photo, its member
   roster, and the join/leave controls. Sized so four or five cards fit a
   laptop screen without scrolling — the whole point is seeing at a glance
   where the class has landed. */

.group-create-form {
    display: flex;
    align-items: flex-end;
    gap: .6rem;
    flex-wrap: wrap;
    margin-bottom: 1.2rem;
    padding: .9rem 1rem;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.group-create-form label {
    color: var(--text-secondary);
    font-size: .85rem;
}

.group-create-form input {
    flex: 1 1 14rem;
    min-width: 0;
}

/* The 🎲 that swaps in another suggested name: square and compact, so Create
   stays the obvious button to press. */
.group-name-shuffle {
    flex: 0 0 auto;
    padding-left: .6rem;
    padding-right: .6rem;
    line-height: 1.1;
}

.group-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 1rem;
}

.group-card {
    display: flex;
    gap: 1rem;
    padding: 1rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.group-card-mine {
    border-color: var(--accent);
}

.group-photo {
    flex: 0 0 auto;
    width: 84px;
    height: 84px;
    border-radius: var(--radius);
    object-fit: cover;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
}

.group-photo-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2rem;
    color: var(--text-muted);
}

.group-card-body {
    flex: 1 1 auto;
    min-width: 0;
}

.group-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .5rem;
}

.group-card-head h3 {
    margin: 0;
    font-size: 1.05rem;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.group-members {
    list-style: none;
    margin: 0 0 .5rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .15rem;
}

.group-member {
    display: flex;
    align-items: baseline;
    gap: .4rem;
    font-size: .9rem;
    color: var(--text-primary);
}

.group-member small {
    color: var(--text-muted);
    font-size: .78rem;
}

.group-member.is-me span {
    font-weight: 600;
    color: var(--accent);
}

.group-member-empty {
    color: var(--text-muted);
    font-style: italic;
}

.group-member-remove {
    margin-left: auto;
    padding: 0 .35rem;
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
}

.group-member-remove:hover {
    color: var(--error);
}

.group-card-actions {
    display: flex;
    gap: .4rem;
    flex-wrap: wrap;
    margin-top: .6rem;
}

/* Heads the submit dialog on group homework: which group the upload lands
   in, or why it cannot be accepted yet. */
.group-submit-notice {
    margin-bottom: 1rem;
    padding: .75rem .9rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-tertiary);
}

.group-submit-notice p {
    margin: .3rem 0 0;
    color: var(--text-secondary);
    font-size: .88rem;
}

.group-submit-notice-warning {
    border-color: var(--warning);
}

.group-submit-notice-warning .btn {
    margin-top: .6rem;
}

/* "🤝 Cleaners A • submitted by …" under a group submission in My
   Submissions, so a teammate's upload is not mistaken for a stranger's. */
.submission-group-attribution {
    margin: .2rem 0 0;
    color: var(--text-secondary);
    font-size: .85rem;
}

/* Language and theme controls on the login card, mirroring the pair in the
   sidebar and the public navbar. */
.auth-controls {
    display: flex;
    justify-content: flex-end;
    gap: .45rem;
    margin-bottom: .25rem;
}

/* Attendance
   The live code is meant to be read from across a room, so it is set large
   and monospaced with wide tracking; the rest reuses the app's stat-card and
   table styles rather than inventing a second visual language. */
.attendance-live {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: 1.5rem;
}

.attendance-live-code {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.attendance-code-label {
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.attendance-code-value {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: clamp(2.5rem, 8vw, 4.5rem);
    font-weight: 700;
    letter-spacing: 0.18em;
    color: var(--accent);
    line-height: 1.1;
}

.attendance-headcount {
    margin: 0;
}

.attendance-code-input {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 2rem;
    letter-spacing: 0.25em;
    text-transform: uppercase;
    text-align: center;
    width: 100%;
    max-width: 16rem;
    padding: 0.5rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.card .attendance-done {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--success);
    margin: 0;
}

.attendance-checkin-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.65rem;
}

.attendance-scanner {
    margin-top: 1rem;
    max-width: 34rem;
}

.attendance-scanner video {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    background: #111;
    border-radius: var(--radius);
}

/* A session still taking check-ins, in the session list. */
.attendance-open-badge {
    display: inline-block;
    padding: 0.05rem 0.45rem;
    border-radius: 999px;
    font-size: 0.75rem;
    background: var(--accent);
    color: #fff;
}

/* Flags a student well below the class's attendance, so the rows worth
   looking at stand out without reading every line. It is a prompt to check,
   not a judgement. */
.attendance-low td {
    /* Tinted from the theme's own warning colour so the row reads as a gentle
       flag in both light and dark, rather than a fixed amber that glares on
       one of them. */
    background: color-mix(in srgb, var(--warning) 16%, transparent);
}

.attendance-checkin .signature-canvas-wrap {
    margin-top: 0.75rem;
}

.error-text {
    color: var(--error);
}

/* The live panel puts the code and the QR side by side: two ways to reach the
   same check-in, for students who would rather type and students who would
   rather scan. They wrap on a narrow screen. */
.attendance-live-main {
    display: flex;
    gap: 1.5rem;
    align-items: flex-start;
    flex-wrap: wrap;
    justify-content: space-between;
}

.attendance-qr {
    margin: 0;
    text-align: center;
}

.attendance-qr img {
    width: 180px;
    height: 180px;
    display: block;
    /* The QR must stay high-contrast in dark mode: a scanner reads the image,
       not the theme, so it keeps its own white quiet zone. */
    background: #fff;
    padding: 8px;
    border-radius: 8px;
    image-rendering: pixelated;
}

.attendance-qr figcaption {
    margin-top: 0.35rem;
}

.card .attendance-verified {
    color: var(--success);
    font-weight: 600;
    margin: 0 0 0.25rem;
}

.attendance-roster-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.attendance-demo-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-secondary);
    font-size: 0.875rem;
    cursor: pointer;
}

/* The demo-account switch, now on the Roster. The attendance register keeps a
   plain note in the same slot saying where the switch went. */
.roster-head {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.25rem;
    align-items: center;
    justify-content: flex-end;
    margin-bottom: 0.6rem;
}

.table-sort-button {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
    white-space: nowrap;
}

.table-sort-button:hover {
    color: var(--accent);
}

.table-sort-button:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
}

.demo-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-secondary);
    font-size: 0.875rem;
    cursor: pointer;
}

.attendance-demo-note {
    color: var(--text-muted);
    font-size: 0.875rem;
}

/* Signature review: one card per captured sample, all the same size so the
   eye can compare them. The ink follows the text colour so it stays visible
   in both themes. */
.signature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 0.9rem;
    margin-top: 0.9rem;
}

.signature-sample {
    margin: 0;
    padding: 0.6rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-secondary);
}

.signature-render {
    display: block;
    width: 100%;
    height: auto;
    background: var(--bg-primary);
    border-radius: 6px;
    fill: none;
    stroke: var(--text-primary);
    stroke-width: 0.9;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.signature-render circle {
    fill: var(--text-primary);
    stroke: none;
}

.signature-typed {
    margin: 0;
    min-height: 3.2rem;
    display: flex;
    align-items: center;
    font-family: 'BrushScript', cursive;
    font-size: 1.4rem;
    color: var(--text-primary);
}

.signature-sample figcaption {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.45rem;
    color: var(--text-secondary);
    font-size: 0.78rem;
}

.signature-review-who {
    margin: 0;
    font-size: 1.05rem;
    color: var(--text-primary);
}

.signature-review-who small {
    color: var(--text-muted);
    font-weight: 400;
}

/* Attendance sub-views: register, kiosk, projector. */
.attendance-subnav {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

/* The register is one column per meeting, so it can outgrow the page; the
   container already scrolls, and the marks stay narrow to delay that. */
.attendance-register .attendance-date-col {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
}

.attendance-register .attendance-present,
.attendance-register .attendance-absent {
    text-align: center;
    width: 3.2rem;
}

.attendance-register .attendance-present { color: var(--success); font-weight: 700; }
/* Absence is a quiet dot rather than a cross: the register is a record, not
   an accusation, and a wall of red reads as one. */
.attendance-register .attendance-absent { color: var(--text-muted); }

.kiosk-candidates {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-bottom: 0.6rem;
}

.kiosk-confirm {
    margin-top: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    align-items: flex-start;
}

.kiosk-username-input {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 1.25rem;
    letter-spacing: 0.08em;
    padding: 0.4rem 0.6rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

/* Projector board */
.attendance-board {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.25rem;
}

.attendance-board.is-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 3000;
    border-radius: 0;
    overflow: auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1.5rem;
}

.attendance-board-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1rem;
}

/* The stand-alone board window. Its own small bar holds the full-screen
   button, which has to be a click inside that window for the browser to
   allow fullscreen; the bar disappears once fullscreen is on, so the
   projector shows only the board. */
body.board-window {
    margin: 0;
    padding: 0.6rem;
    background: var(--bg-primary);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

body.board-window .board-window-bar {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    flex: 0 0 auto;
}

body.board-window .board-window-hint {
    color: var(--text-muted);
    font-size: 0.85rem;
}

body.board-window .attendance-board.is-fullscreen {
    position: static;
    inset: auto;
    flex: 1 1 auto;
    z-index: auto;
}

/* Once the board is on the projector, the button and the "drag this window"
   hint have done their job and would only be clutter on the wall; Escape still
   leaves fullscreen.
   Two traps here, both of which bit: the fullscreen element is the popup's
   <html> (requestFullscreen is called on documentElement), so
   `body:fullscreen` never matches; and `:fullscreen .board-window-bar` alone
   loses on specificity to the `body.board-window .board-window-bar` rule above
   that sets display:flex. Naming html and body explicitly wins outright
   instead of depending on rule order. */
html:fullscreen body.board-window .board-window-bar {
    display: none;
}

/* Real fullscreen (the projector case): the element *is* the screen, so the
   fixed positioning the overlay uses is unnecessary, and a fullscreen root
   with a transparent background paints black on some platforms. Fill it with
   the board's own background and give the content room to breathe on a large
   display. */
.attendance-board:fullscreen {
    position: static;
    width: 100%;
    height: 100%;
    padding: 3vh 4vw;
    background: var(--bg-card);
}

.attendance-board-code {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2rem;
    flex-wrap: wrap;
}

/* Sized to be read from the back row, not from a laptop. */
.attendance-code-huge {
    font-size: clamp(3.5rem, 14vw, 10rem);
}

.attendance-qr-huge {
    width: clamp(140px, 22vw, 320px);
    height: auto;
    background: #fff;
    padding: 10px;
    border-radius: 10px;
    image-rendering: pixelated;
}

.board-progress-bar {
    height: 12px;
    border-radius: 999px;
    background: var(--bg-tertiary);
    overflow: hidden;
}

.board-progress-bar span {
    display: block;
    height: 100%;
    background: var(--success);
    transition: width 0.6s ease;
}

.board-progress-label {
    margin: 0.35rem 0 0;
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.board-podium {
    list-style: none;
    margin: 1.25rem 0;
    padding: 0;
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    justify-content: center;
}

.board-podium li {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--bg-tertiary);
    border-radius: 999px;
    padding: 0.4rem 1rem;
    font-size: clamp(1rem, 2.5vw, 1.6rem);
}

.board-podium .podium-1 { font-weight: 700; }
.podium-medal { font-size: 1.3em; }

.board-latest p {
    margin: 0.25rem 0;
    font-size: clamp(0.95rem, 2vw, 1.3rem);
}

.board-waiting {
    color: var(--text-secondary);
    margin-top: 0.75rem;
}

.attendance-board-idle {
    color: var(--text-secondary);
    text-align: center;
    margin: 1.5rem 0;
}

/* Keep grading navigation together beside the return button. */
.grade-student-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}
.grade-student-controls .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    min-height: 2rem;
}
.grade-student-controls span {
    white-space: nowrap;
}

.ai-rubric-editor { width: 100%; min-height: 45vh; font-family: monospace; line-height: 1.5; tab-size: 2; resize: vertical; }
