:root {
    /* Entry Education brand palette. Every colour in this project resolves to
       one of these; nothing below should hardcode a hex except #fff. */

    /* Neutral (brand Black ramp) */
    --ink: #18181B;
    --text: #27272A;
    --muted: #71717A;
    --line: #E4E4E7;
    --neutral: #FAFAFA;
    --surface: #FFFFFF;

    /* Orange: brand + primary action.
       --accent is fills, and page headings where the brand tone matters most.
       --accent-dark is orange text on white above body size.
       --accent-deep is orange text at <=14px, or any orange text on --tint. */
    --accent: #ff7200;
    --accent-dark: #CC5A00;
    --accent-deep: #A34600;
    --tint: #ffe7da;
    --soft: #fcf2ee;
    --paper: #fcf2ee;

    /* Green: verified / competent / done.
       --success is a mark colour only; use --success-text for type. */
    --success: #00A676;
    --success-text: #164B35;
    --success-border: #B8F3DC;
    --success-bg: #E9FFF6;

    /* Red: error / failure / recording */
    --danger: #D64545;
    --danger-text: #5C1F1F;
    --danger-border: #FFB4A8;
    --danger-bg: #FFE8E3;

    --shadow: 0 10px 34px rgba(24, 24, 27, 0.08);
}

* {
    box-sizing: border-box;
}

body {
    min-height: 100vh;
    margin: 0;
    background: var(--paper);
    color: var(--text);
    font-family: Arial, Helvetica, sans-serif;
    letter-spacing: 0;
}

.app-shell {
    width: min(1160px, calc(100% - 32px));
    margin: 0 auto;
    padding: 10px 0 28px;
}

.brand-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 18px;
    margin-bottom: 8px;
}

.header-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}

.brand-lockup {
    display: flex;
    align-items: center;
}

.brand-logo {
    display: block;
    width: 126px;
    height: auto;
    object-fit: contain;
}

.brand-subtitle {
    border-left: 1px solid var(--line);
    color: var(--muted);
    font-size: 13px;
    line-height: 1.2;
    padding-left: 14px;
}

.support-chip {
    border: 1px solid var(--line);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.75);
    color: var(--text);
    font-size: 13px;
    padding: 7px 11px;
}

.support-link {
    color: var(--accent-deep);
    text-decoration: none;
}

.support-link:hover {
    background: var(--soft);
    border-color: var(--tint);
}

.hero {
    display: grid;
    grid-template-columns: minmax(360px, 1fr) minmax(260px, 560px);
    gap: 20px;
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 8px;
    box-shadow: var(--shadow);
    padding: 16px 20px;
}

.eyebrow {
    color: var(--accent-deep);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    margin: 0 0 8px;
    text-transform: uppercase;
}

h1,
h2,
p {
    margin-top: 0;
}

h1 {
    max-width: 720px;
    color: var(--accent);
    font-size: clamp(24px, 3vw, 34px);
    font-weight: 700;
    line-height: 1.08;
    margin-bottom: 8px;
}

h2 {
    color: var(--ink);
    font-size: 18px;
    font-weight: 700;
    margin-bottom: 0;
}

.hero-copy,
.section-copy {
    color: var(--muted);
    line-height: 1.55;
}

.section-copy {
    margin-bottom: 10px;
}

.hero-copy {
    max-width: 640px;
    font-size: 15px;
    margin-bottom: 0;
}

.status-card {
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    justify-self: end;
    max-width: 100%;
    min-width: 0;
    min-height: 42px;
    border: 1px solid var(--success-border);
    border-radius: 22px;
    background: var(--success-bg);
    padding: 9px 14px;
    white-space: normal;
}

.status-dot {
    width: 10px;
    height: 10px;
    border-radius: 999px;
    background: var(--success);
    box-shadow: 0 0 0 4px rgba(0, 166, 118, 0.13);
}

.status-card.listening .status-dot {
    animation: listeningPulse 1.4s ease-in-out infinite;
}

@keyframes listeningPulse {
    0% {
        box-shadow: 0 0 0 3px rgba(0, 166, 118, 0.18);
        transform: scale(1);
    }

    50% {
        box-shadow: 0 0 0 8px rgba(0, 166, 118, 0.08);
        transform: scale(1.08);
    }

    100% {
        box-shadow: 0 0 0 3px rgba(0, 166, 118, 0.18);
        transform: scale(1);
    }
}

.status-label {
    color: var(--success-text);
    font-size: 12px;
    font-weight: 600;
}

#status {
    color: var(--success-text);
    font-size: 14px;
    font-weight: 700;
    line-height: 1.2;
    overflow-wrap: anywhere;
}

.workflow-layout {
    display: grid;
    grid-template-columns: 176px minmax(0, 1fr);
    gap: 18px;
    align-items: stretch;
    margin-top: 12px;
}

.progress-strip {
    position: sticky;
    top: 14px;
    display: grid;
    gap: 8px;
    align-self: start;
}

.progress-step {
    display: flex;
    align-items: center;
    gap: 9px;
    min-height: 46px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: linear-gradient(180deg, var(--surface) 0%, var(--soft) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.95),
        inset 0 -1px 0 rgba(24, 24, 27, 0.10),
        0 6px 16px rgba(24, 24, 27, 0.06);
    padding: 9px 10px;
    opacity: 0.68;
}

.progress-step.active,
.progress-step.done {
    opacity: 1;
}

.progress-step span {
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border-radius: 999px;
    background: linear-gradient(180deg, var(--soft) 0%, var(--line) 100%);
    color: var(--ink);
    font-size: 12px;
    font-weight: 700;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.95),
        inset 0 -1px 0 rgba(24, 24, 27, 0.14);
}

.progress-step.active {
    border-color: var(--tint);
    background: linear-gradient(180deg, var(--soft) 0%, var(--tint) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.96),
        inset 0 -1px 0 rgba(255, 114, 0, 0.24),
        0 10px 24px rgba(255, 114, 0, 0.12);
}

.progress-step.active span {
    background: linear-gradient(180deg, var(--accent) 0%, var(--accent-dark) 100%);
    color: #fff;
}

.progress-step.done span {
    background: linear-gradient(180deg, var(--success) 0%, var(--success-text) 100%);
    color: #fff;
}

.progress-step.done {
    border-color: var(--success-border);
    background: linear-gradient(180deg, var(--surface) 0%, var(--success-bg) 100%);
}

.progress-step strong {
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
}

.content-grid {
    display: grid;
    grid-template-columns: minmax(330px, 0.9fr) minmax(440px, 1.1fr);
    gap: 14px;
    align-items: start;
}

.content-grid.view-id,
.content-grid.focus-call {
    grid-template-columns: minmax(0, 820px);
    justify-content: start;
}

.content-grid.focus-call .call-panel {
    border-color: var(--tint);
    box-shadow: 0 16px 46px rgba(24, 24, 27, 0.12);
}

.right-stack {
    display: grid;
    gap: 14px;
}

.panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 8px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.9),
        0 12px 32px rgba(24, 24, 27, 0.08);
    padding: 18px 20px;
}

.call-panel {
    min-height: 320px;
}

.section-heading {
    margin-bottom: 8px;
}

.call-times {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: -2px 0 14px;
}

.call-times div {
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--soft);
    padding: 10px 12px;
}

.call-times span {
    display: block;
    color: var(--muted);
    font-size: 12px;
    margin-bottom: 4px;
}

.call-times strong {
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.35;
}

.question-progress {
    border: 1px solid var(--success-border);
    border-radius: 8px;
    background: var(--surface);
    margin: -2px 0 14px;
    padding: 10px 12px;
}

.progress-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 8px;
}

.progress-meta span,
.progress-meta strong {
    color: var(--success-text);
    font-size: 13px;
    font-weight: 700;
}

.progress-track {
    height: 8px;
    overflow: hidden;
    border-radius: 999px;
    background: var(--line);
}

.progress-fill {
    width: 0;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, var(--success) 0%, var(--accent) 100%);
    transition: width 420ms ease;
}

.milestone-message {
    color: var(--success-text);
    margin-top: 8px;
}

.milestone-pop {
    animation: milestonePop 520ms ease;
}

@keyframes milestonePop {
    0% {
        opacity: 0.55;
        transform: translateY(4px);
    }

    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

label {
    display: block;
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    margin: 10px 0 6px;
}

.required-mark {
    color: var(--accent-deep);
    font-size: 15px;
    font-weight: 700;
    margin-left: 3px;
    line-height: 1;
}

/* Who this call is for, read-only. Replaced the three typed fields (name, Student ID,
   enrolment email) once sign-in started holding the aXcelerate record on the session:
   there is nothing left to type, but the ID document is matched against this name, so
   hiding it would leave a failed name match unexplainable. */
.signed-in-details {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--tint);
    padding: 12px 14px;
    margin-bottom: 18px;
}

.signed-in-label {
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    margin: 0 0 6px;
}

.signed-in-identity {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 10px;
    font-size: 15px;
    margin: 0;
}

.signed-in-id {
    color: var(--muted);
    font-size: 12px;
}

/* break-all, not break-word: a long address must not widen the panel on a phone. */
.signed-in-email {
    color: var(--muted);
    font-size: 12px;
    line-height: 1.4;
    margin: 4px 0 0;
    word-break: break-all;
}

input,
textarea {
    width: 100%;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 14px;
    line-height: 1.45;
    padding: 8px 10px;
}

input {
    min-height: 38px;
}

textarea {
    resize: vertical;
}

input[type="file"] {
    padding: 8px;
}

input:focus,
textarea:focus {
    outline: 3px solid rgba(255, 114, 0, 0.18);
    border-color: var(--accent);
}

/* input.input-error was removed with the typed ID fields. It marked whichever of name /
   Student ID / enrolment email aXcelerate reported as not matching, and nothing sets it now
   that those three come from the signed-in session. */

.camera-box {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 12px;
    align-items: start;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--soft);
    margin-top: 12px;
    padding: 9px;
}

#camera-preview {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    min-height: 0;
    max-height: none;
    border-radius: 6px;
    background: var(--ink);
    object-fit: cover;
}

.camera-box .actions {
    align-content: start;
    display: grid;
    grid-template-columns: 1fr;
    gap: 8px;
    margin-top: 4px;
}

.camera-box .actions button {
    width: 100%;
}

.camera-box .microcopy {
    align-self: start;
    grid-column: 1;
    margin-top: -4px;
    text-align: left;
    white-space: nowrap;
}

.microcopy {
    color: var(--muted);
    font-size: 12px;
    line-height: 1.4;
    margin: 9px 0 0;
}

.verification-progress {
    border-left: 3px solid var(--accent);
    background: var(--soft);
    border-radius: 6px;
    color: var(--text);
    margin-top: 8px;
    padding: 8px 10px;
}

/* No orange box when there's no status text (only shows during/after verify). */
.verification-progress:empty {
    display: none;
}

.listening-hint {
    border-left: 3px solid var(--success);
    background: var(--success-bg);
    border-radius: 6px;
    color: var(--success-text);
    margin-top: 10px;
    padding: 9px 10px;
}

.message {
    min-height: 112px;
    display: flex;
    align-items: center;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--soft);
    color: var(--text);
    font-size: 16px;
    font-weight: 400;
    line-height: 1.45;
    padding: 18px;
    transition: opacity 160ms ease, transform 160ms ease;
}

.message.question-exit {
    opacity: 0;
    transform: translateY(6px);
}

.message.question-enter {
    animation: questionEnter 260ms ease;
}

@keyframes questionEnter {
    0% {
        opacity: 0;
        transform: translateY(6px);
    }

    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

.completion-state {
    display: grid;
    justify-items: center;
    gap: 6px;
    border: 1px solid var(--success-border);
    border-radius: 8px;
    background: var(--success-bg);
    color: var(--success-text);
    margin-top: 12px;
    padding: 14px;
    text-align: center;
}

.completion-check {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 999px;
    background: var(--success);
    color: #fff;
    font-size: 20px;
    font-weight: 700;
}

.completion-state strong {
    color: var(--success-text);
    font-size: 15px;
}

.completion-state p {
    color: var(--success-text);
    font-size: 13px;
    line-height: 1.4;
    margin: 0;
}

.completion-pop .completion-check {
    animation: completionPop 520ms ease;
}

@keyframes completionPop {
    0% {
        transform: scale(0.8);
    }

    70% {
        transform: scale(1.08);
    }

    100% {
        transform: scale(1);
    }
}

.answer {
    min-height: 36px;
    color: var(--success-text);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.45;
    margin-top: 12px;
}

.answer-controls {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    margin-top: 10px;
}

.answer-review {
    border: 1px solid var(--tint);
    border-radius: 8px;
    background: var(--soft);
    margin-top: 12px;
    padding: 12px;
}

.answer-review blockquote {
    border-left: 3px solid var(--accent);
    color: var(--ink);
    font-size: 14px;
    line-height: 1.45;
    margin: 8px 0 12px;
    padding-left: 10px;
}

.icon-button {
    display: inline-grid;
    place-items: center;
    width: 38px;
    height: 38px;
    min-height: 38px;
    border-radius: 999px;
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
    padding: 0;
}

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

.icon-button.primary:hover:not(:disabled) {
    background: var(--accent-dark);
}

.icon-button.secondary {
    background: var(--soft);
    border-color: var(--tint);
    color: var(--accent-dark);
}

.icon-button.secondary:hover:not(:disabled) {
    background: var(--tint);
}

.icon-button.danger-soft {
    border-color: var(--danger-border);
    color: var(--danger-text);
}

.icon-button:disabled {
    background: var(--neutral);
    border-color: var(--line);
    color: var(--muted);
}

.consent-box {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--soft);
    margin-top: 12px;
    padding: 14px;
}

.consent-box p {
    color: var(--text);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.45;
    margin-bottom: 0;
}

.actions {
    display: flex;
    flex-wrap: wrap;
    gap: 9px;
    margin-top: 16px;
}

.actions.compact {
    margin-top: 9px;
}

.actions.actions-end {
    justify-content: flex-end;
}

.landing-actions {
    margin-top: 18px;
}

.primary-link,
.secondary-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 38px;
    border-radius: 6px;
    font: inherit;
    font-size: 14px;
    font-weight: 700;
    padding: 8px 12px;
    text-decoration: none;
}

.primary-link {
    background: var(--accent);
    border: 1px solid var(--accent);
    color: #fff;
}

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

.secondary-link {
    background: var(--surface);
    border: 1px solid var(--line);
    color: var(--text);
}

.secondary-link:hover {
    background: var(--soft);
}

button {
    min-height: 38px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: var(--accent);
    color: #fff;
    cursor: pointer;
    font: inherit;
    font-size: 14px;
    font-weight: 700;
    padding: 8px 12px;
}

button:hover:not(:disabled) {
    background: var(--accent-dark);
}

button.secondary {
    background: var(--surface);
    border-color: var(--line);
    color: var(--text);
}

button.secondary:hover:not(:disabled) {
    background: var(--soft);
}

button:disabled {
    background: var(--line);
    color: var(--muted);
    cursor: not-allowed;
}

/* Buttons that look like links have to opt out of the fill above. `button:hover:not(:disabled)`
   is specificity (0,2,1), which beats a plain `.thing:hover` at (0,2,0) — so a text button
   whose base sets `background: none` still fills solid orange the moment you hover it, and
   any dark-orange text on it disappears. The extra `:not(:disabled)` here matches that
   specificity and wins on source order. */
.login-link:hover:not(:disabled),
.toast-close:hover:not(:disabled),
.review-hero .link-button:hover:not(:disabled) {
    background: none;
}

.toast-close:hover:not(:disabled) {
    background: var(--neutral);
}

.admin-shell {
    width: min(1280px, calc(100% - 32px));
}

.admin-hero {
    margin-bottom: 14px;
}

.admin-workspace {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
    align-items: start;
}

.admin-workspace.has-report {
    /* Report is now an overlay drawer, so it no longer splits the workspace grid. */
    grid-template-columns: minmax(0, 1fr);
}

.admin-panel {
    padding: 0;
    overflow: hidden;
}

.admin-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 0;
    padding: 18px 20px 14px;
}

.admin-tabs {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 4px;
    border-bottom: 1px solid var(--line);
    background: var(--surface);
    padding: 6px 20px 0;
}

/* Inactive tabs carry their own fill and outline: transparent ones read as static
   headings next to the filled active tab, so the strip looked like one control and
   three labels. */
.admin-tab {
    min-height: 38px;
    border: 1px solid var(--line);
    border-bottom: 0;
    border-radius: 10px 10px 0 0;
    background: var(--neutral);
    color: var(--text);
    font-size: 13px;
    font-weight: 700;
    padding: 10px 18px;
    transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
}

.admin-tab:hover:not(:disabled):not(.active) {
    background: var(--soft);
    color: var(--accent-deep);
    border-color: var(--accent);
}

.admin-tab:focus-visible {
    outline: 3px solid rgba(255, 114, 0, 0.28);
    outline-offset: -3px;
}

/* The active tab sits a pixel over the strip's rule so it joins the panel below it
   rather than floating above the line with the others. */
.admin-tab.active,
.admin-tab.active:hover:not(:disabled) {
    background: var(--tint);
    color: var(--accent-deep);
    border-color: var(--accent);
    margin-bottom: -1px;
    padding-bottom: 11px;
}

.admin-tab-panel {
    min-width: 0;
}

.question-bank-editor {
    width: calc(100% - 40px);
    min-height: 520px;
    margin: 0 20px 18px;
    font-family: Consolas, "Courier New", monospace;
    font-size: 12px;
    line-height: 1.45;
    resize: vertical;
}

.question-bank-controls {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
}

.question-bank-form {
    display: grid;
    gap: 12px;
    padding: 0 20px 16px;
}

.system-health-panel {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    padding: 12px;
}

/* ===== Question bank ===== */
.qbank-toolbar {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 0 20px 10px;
}

.qbank-toolbar button {
    min-height: auto;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    padding: 6px 11px;
}

.qbank-toolbar button:hover:not(:disabled) {
    background: var(--soft);
}

.qbank-version {
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    overflow: hidden;
}

.qbank-version-head {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: auto;
    border: 0;
    border-radius: 0;
    background: var(--soft);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    padding: 12px 16px;
}

.qbank-version-head:hover:not(:disabled) {
    background: var(--soft);
}

.qbank-chevron {
    flex-shrink: 0;
    width: 0;
    height: 0;
    border-left: 5px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    color: var(--muted);
    transition: transform 0.15s ease;
}

.qbank-version[data-open="true"] > .qbank-version-head .qbank-chevron {
    transform: rotate(90deg);
}

.qbank-version-num {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    background: var(--tint);
    color: var(--accent-deep);
    font-size: 14px;
    font-weight: 700;
}

.qbank-version-title {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.qbank-version-title strong {
    display: block;
    color: var(--ink);
    font-size: 15px;
    font-weight: 700;
}

.qbank-version-key {
    display: block;
    margin-top: 1px;
    font-family: Consolas, "Courier New", monospace;
    font-size: 12px;
    color: var(--muted);
    word-break: break-all;
}

.qbank-count-pill {
    margin-left: auto;
    flex-shrink: 0;
    border: 1px solid var(--tint);
    border-radius: 999px;
    background: var(--soft);
    color: var(--accent-deep);
    padding: 4px 12px;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}

.qbank-version-body {
    display: none;
}

.qbank-version[data-open="true"] > .qbank-version-body {
    display: block;
    padding: 16px;
    border-top: 1px solid var(--line);
    background: var(--soft);
}

/* Two-column grid of always-open question cards. */
.qbank-cards {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px 28px;
}

.qbank-question {
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.qbank-question-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

.qbank-q-num {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background: var(--accent);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
}

.qbank-q-title {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}

.qbank-question-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.qbank-field {
    min-width: 0;
}

.qbank-field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

.qbank-field-label {
    display: block;
    margin-bottom: 4px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text);
}

.qbank-label-hint {
    font-weight: 400;
    font-size: 11px;
    color: var(--muted);
}

.qbank-input {
    width: 100%;
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 8px 10px;
    font: inherit;
    font-size: 14px;
    color: var(--text);
    background: var(--surface);
}

textarea.qbank-input {
    resize: vertical;
}

.qbank-input:focus {
    border-color: var(--accent);
    outline: none;
    box-shadow: 0 0 0 3px rgba(255, 114, 0, 0.12);
}

.qbank-branch-group {
    display: grid;
    gap: 14px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px dashed var(--line);
}

.qbank-branch-heading {
    margin: 0;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent-deep);
}

.qbank-branch {
    display: grid;
    gap: 10px;
    border-left: 2px solid var(--line);
    padding-left: 12px;
}

.qbank-branch-label {
    margin: 0;
    font-size: 12px;
    font-weight: 700;
    color: var(--text);
}

.qbank-advanced {
    margin: 0 20px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    overflow: hidden;
}

.qbank-advanced summary {
    cursor: pointer;
    padding: 10px 14px;
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
    list-style: none;
    user-select: none;
}

.qbank-advanced summary::-webkit-details-marker {
    display: none;
}

.qbank-advanced[open] summary {
    border-bottom: 1px solid var(--line);
}

.qbank-advanced .question-bank-editor {
    width: calc(100% - 24px);
    margin: 12px;
}

.qbank-advanced .microcopy {
    margin: 0 12px 12px;
}

.inline-toolbar {
    padding: 0;
}

.warning-line {
    border-left: 3px solid var(--accent);
    color: var(--text);
    font-size: 13px;
    line-height: 1.45;
    margin: 0 0 8px;
    padding-left: 10px;
}

.admin-controls {
    display: grid;
    gap: 14px;
    padding: 14px 20px 16px;
}

.admin-summary {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}

.summary-card {
    position: relative;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--soft);
    padding: 12px 14px 12px 16px;
    overflow: hidden;
    transition: box-shadow 140ms ease, border-color 140ms ease;
}

.summary-card::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: var(--line);
}

.summary-card:hover {
    border-color: var(--line);
    box-shadow: 0 6px 16px rgba(24, 24, 27, 0.06);
}

.summary-card span {
    display: block;
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.summary-card strong {
    color: var(--text);
    display: block;
    font-size: 22px;
    font-weight: 700;
    margin-top: 4px;
}

.summary-card.summary-total strong {
    color: var(--ink);
}

.summary-card.summary-pending::before {
    background: var(--muted);
}

.summary-card.summary-pending strong {
    color: var(--text);
}

.summary-card.summary-approved::before {
    background: var(--success);
}

.summary-card.summary-approved strong {
    color: var(--success-text);
}

.summary-card.summary-needs-review::before {
    background: var(--accent);
}

.summary-card.summary-needs-review strong {
    color: var(--accent-dark);
}

.admin-filters {
    display: grid;
    grid-template-columns: minmax(260px, 1fr) 220px;
    gap: 10px;
    align-items: center;
}

.admin-filters input,
.admin-filters select {
    min-height: 40px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    padding: 9px 11px;
}

.admin-filters input[type="search"] {
    padding-left: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2371717A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 12px center;
}

.admin-filters select {
    -webkit-appearance: none;
    appearance: none;
    padding-right: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717A' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
}

.admin-filters select:focus {
    outline: 3px solid rgba(255, 114, 0, 0.18);
    border-color: var(--accent);
}

.table-wrap {
    overflow-x: auto;
    border-top: 1px solid var(--line);
}

.assessment-table {
    width: 100%;
    border-collapse: collapse;
    min-width: 1280px;
    table-layout: fixed;
}

.assessment-table th,
.assessment-table td {
    border-bottom: 1px solid var(--line);
    color: var(--text);
    font-size: 13px;
    line-height: 1.4;
    padding: 14px 16px;
    text-align: left;
    vertical-align: top;
}

.assessment-table th {
    background: linear-gradient(180deg, var(--surface), var(--soft));
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    white-space: nowrap;
}

.assessment-table tbody tr {
    transition: background 120ms ease;
}

.assessment-table tbody tr:hover {
    background: var(--soft);
}

.assessment-table tbody tr.selected-row {
    background: var(--tint);
    box-shadow: inset 4px 0 0 var(--accent);
}

.assessment-table tbody tr:last-child td {
    border-bottom: 0;
}

.assessment-table th:nth-child(1),
.assessment-table td:nth-child(1) {
    width: 14%;
}

.assessment-table th:nth-child(2),
.assessment-table td:nth-child(2) {
    width: 16%;
}

.assessment-table th:nth-child(3),
.assessment-table td:nth-child(3) {
    width: 15%;
}

.assessment-table th:nth-child(4),
.assessment-table td:nth-child(4) {
    width: 10%;
}

.assessment-table th:nth-child(5),
.assessment-table td:nth-child(5) {
    width: 10%;
}

.assessment-table th:nth-child(6),
.assessment-table td:nth-child(6) {
    width: 10%;
}

.assessment-table th:nth-child(7),
.assessment-table td:nth-child(7) {
    width: 12%;
}

.assessment-table th:nth-child(8),
.assessment-table td:nth-child(8) {
    width: 13%;
}

.log-controls .admin-summary {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.log-table {
    min-width: 1120px;
}

.log-table th:nth-child(1),
.log-table td:nth-child(1) {
    width: 15%;
}

.log-table th:nth-child(2),
.log-table td:nth-child(2) {
    width: 20%;
}

.log-table th:nth-child(3),
.log-table td:nth-child(3) {
    width: 16%;
}

.log-table th:nth-child(4),
.log-table td:nth-child(4) {
    width: 34%;
}

.log-table th:nth-child(5),
.log-table td:nth-child(5) {
    width: 15%;
}

.log-details {
    color: var(--text);
    display: block;
    max-height: 76px;
    overflow: auto;
    overflow-wrap: anywhere;
}

.evidence-link {
    display: inline-flex;
    align-items: center;
    width: fit-content;
    border: 1px solid var(--success-border);
    border-radius: 999px;
    background: var(--success-bg);
    color: var(--success-text);
    font-size: 12px;
    font-weight: 700;
    margin-top: 6px;
    padding: 4px 8px;
    text-decoration: none;
}

.evidence-link:hover {
    background: var(--success-border);
}

.log-event-pill {
    border-color: var(--line);
    background: var(--neutral);
    color: var(--text);
}

.session-id {
    font-family: Arial, Helvetica, sans-serif;
    overflow-wrap: anywhere;
}

.table-primary,
.table-secondary {
    display: block;
}

.table-primary {
    color: var(--ink);
    font-size: 13px;
    font-weight: 700;
}

.student-cell .table-primary {
    font-size: 14px;
}

.table-secondary {
    color: var(--muted);
    font-size: 12px;
    margin-top: 3px;
    overflow-wrap: anywhere;
}

/* Outcome cell: score and push status share the one small line under the pill. Green reads
   as done, red as still owed a push. The palette's -text variants are used rather than the
   brighter marks because this sits at 12px on white. */
.ax-note {
    font-weight: 700;
}

.ax-note.is-synced {
    color: var(--success-text);
}

.ax-note.is-unsynced {
    color: var(--danger-text);
}

.table-email {
    word-break: break-word;
    overflow-wrap: anywhere;
}

.table-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--soft);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.25;
    padding: 5px 10px;
    white-space: normal;
    overflow-wrap: anywhere;
}

.table-pill::before {
    content: "";
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: currentColor;
    opacity: 0.7;
}

/* Pill colours are keyed off slug(value), so renaming a status silently unstyles its pill
   — which is what happened to Completed / Review now / Rejected when the Outcome column
   moved off "Competent"/"Needs review", and to Token when code_verified got its own label.
   The column has since gone back to "Needs review", so this rule follows that slug again.
   Green = settled, amber = a person still has to act, red = refused, grey = nothing yet.

   Colour is never the only signal: every pill carries its own words. */
.verification-verified,
.verification-manually-verified,
.verification-automatically-verified,
.verification-code-verified,
.outcome-completed {
    border-color: var(--success-border);
    background: var(--success-bg);
    color: var(--success-text);
}

.verification-needs-review,
.verification-needs-manual-review,
.outcome-needs-review {
    border-color: var(--tint);
    background: var(--soft);
    color: var(--accent-deep);
}

.outcome-rejected {
    border-color: var(--danger-border);
    background: var(--danger-bg);
    color: var(--danger-text);
}

/* Skipped is grey, not green: it bypassed the identity checks rather than passing them. */
.verification-not-recorded,
.verification-skipped,
.outcome-in-progress {
    border-color: var(--line);
    background: var(--soft);
    color: var(--muted);
}

/* .review-* / .sync-* pill colours and .status-stack lived here for the table's Review
   column. That column is gone — its status only restated Outcome, and the sync state and
   evidence summary are in the drawer — so nothing emits these class names any more. */

.empty-state {
    color: var(--muted);
    padding: 32px 20px !important;
    text-align: center !important;
}

.pagination-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    border-top: 1px solid var(--line);
    background: var(--soft);
    padding: 12px 20px;
}

.pagination-bar span {
    color: var(--muted);
    font-size: 13px;
}

.pagination-controls,
.pagination-pages {
    display: flex;
    align-items: center;
    gap: 6px;
}

.pagination-controls button {
    min-height: 32px;
    font-size: 12px;
    padding: 6px 9px;
}

.pagination-pages .active-page {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    box-shadow: 0 3px 10px rgba(204, 90, 0, 0.22);
}

.table-actions {
    display: grid;
    grid-template-columns: 1fr;
    gap: 6px;
    min-width: 0;
}

.table-actions button {
    width: 100%;
    min-height: 34px;
    border-radius: 8px;
    font-size: 12px;
    padding: 7px 10px;
    white-space: nowrap;
    transition: background 140ms ease, border-color 140ms ease,
        color 140ms ease, box-shadow 140ms ease;
}

.table-actions .action-report {
    box-shadow: 0 4px 12px rgba(204, 90, 0, 0.18);
}

.table-actions .action-approve {
    color: var(--success-text);
    border-color: var(--success-border);
}

.table-actions .action-approve:hover:not(:disabled) {
    background: var(--success-bg);
    border-color: var(--success);
}

.table-actions .action-review {
    color: var(--accent-deep);
    border-color: var(--tint);
}

.table-actions .action-review:hover:not(:disabled) {
    background: var(--soft);
    border-color: var(--accent);
}

.table-actions .action-sync {
    color: var(--success-text);
    border-color: var(--success-border);
}

.table-actions .action-sync:hover:not(:disabled) {
    background: var(--success-bg);
    border-color: var(--success);
}

.table-actions button:focus-visible,
.pagination-controls button:focus-visible {
    outline: 3px solid rgba(255, 114, 0, 0.28);
    outline-offset: 1px;
}

/* A near-full centered overlay, not the 440px right-hand slide-in it used to be. An
   assessment carries nine sections including a multi-question transcript; at 440px the
   action buttons wrapped, and the Save button sat ~1500px of scroll away from the
   answers it was judging. Width alone would not fix that — see .drawer-grid.

   Still animated on `transform`: hideReport() closes on transitionend filtered to
   propertyName === 'transform', so switching to an opacity-only fade would leave it
   relying on the fallback timer. */
.report-panel {
    position: fixed;
    top: 50%;
    left: 50%;
    z-index: 1200;
    display: flex;
    flex-direction: column;
    width: min(1440px, 95vw);
    height: min(920px, 92vh);
    height: min(920px, 92dvh);
    max-height: none;
    margin: 0;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 16px;
    box-shadow: 0 24px 70px rgba(24, 24, 27, 0.28);
    background: var(--surface);
    transform: translate(-50%, -50%) scale(0.97);
    opacity: 0;
    transition: transform 280ms cubic-bezier(0.22, 0.61, 0.36, 1), opacity 200ms ease;
    will-change: transform, opacity;
}

.report-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    flex: 0 0 auto;
    border-bottom: 1px solid var(--line);
    padding: 18px 18px 14px;
}

.report-meta {
    color: var(--muted);
    font-size: 12px;
    line-height: 1.45;
    margin: 6px 0 0;
    overflow-wrap: anywhere;
}

.review-drawer-body {
    flex: 1 1 auto;
    min-height: 0;
    /* The two columns scroll themselves, so this must not scroll as well — nested
       scrollbars on the same axis make the outer one swallow the inner one's wheel
       events at its scroll boundary. */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    padding: 14px 18px 18px;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

/* Left rail is the decision surface, right pane is the material being consulted. The
   point of the split: the Save button stays on screen while the transcript scrolls, so
   an assessor is never scrolling back up to the control they just formed an opinion
   with. min-height: 0 on both is what lets the children actually scroll inside a grid. */
.drawer-grid {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    grid-template-columns: minmax(320px, 400px) minmax(0, 1fr);
    gap: 20px;
}

.drawer-rail,
.drawer-pane {
    min-height: 0;
    min-width: 0;
    overflow: auto;
    overscroll-behavior: contain;
}

.drawer-rail {
    padding-right: 16px;
    border-right: 1px solid var(--line);
}

/* Reuses .admin-tabs / .admin-tab from the page-level tab strip, so these read as the
   same control rather than a second tab language. Sticky because the pane scrolls. */
.drawer-pane .admin-tabs {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--surface);
    margin-bottom: 4px;
}

/* The tabbed sections drop the top rule and heading the stacked layout needed; the tab
   itself is now the heading. */
.drawer-pane .drawer-section {
    border-top: 0;
    padding-top: 4px;
}

.drawer-pane .drawer-section > h3 {
    display: none;
}

/* Report drawer: right-side slide-in overlay. Open and close are animated via .is-open. */
.report-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: rgba(24, 24, 27, 0.42);
    opacity: 0;
    pointer-events: none;
    transition: opacity 280ms ease;
    will-change: opacity;
}

@supports ((-webkit-backdrop-filter: blur(6px)) or (backdrop-filter: blur(6px))) {
    .report-backdrop {
        background: rgba(24, 24, 27, 0.28);
        -webkit-backdrop-filter: blur(6px) saturate(1.05);
        backdrop-filter: blur(6px) saturate(1.05);
    }
}

.report-backdrop.is-open {
    opacity: 1;
    pointer-events: auto;
}

.report-panel.is-open {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
}

.report-close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: var(--accent-dark);
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    transition: background 140ms ease, color 140ms ease;
}

.report-close:hover:not(:disabled) {
    background: var(--soft);
    color: var(--accent-deep);
}

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

body.report-open {
    overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
    .report-panel,
    .report-backdrop {
        transition: none;
    }
}

.review-hero {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: 14px;
}

/* White surface, not the orange tint: every container in the drawer is now the same
   neutral card, so orange is left to mean "action" (the Save button) and "brand" (the
   accents) rather than also meaning "panel".

   Two very soft shadow layers rather than one heavy one: the tight one lifts the edge off
   the panel, the wide one grounds it. Kept under 6% opacity — enough to read as a card,
   not enough to look like a popup sitting on the drawer. */
.review-hero > div {
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    box-shadow: 0 1px 2px rgba(24, 24, 27, 0.04), 0 4px 12px rgba(24, 24, 27, 0.05);
    padding: 12px 12px 14px;
}

.review-kicker,
.review-hero span {
    display: block;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.35;
}

/* A text action inside a hero tile — a full button would dominate a 12px status line. */
.review-hero .link-button {
    display: inline-block;
    border: 0;
    background: none;
    padding: 0;
    margin-top: 6px;
    color: var(--accent-deep);
    font: inherit;
    font-size: 11px;
    font-weight: 700;
    text-decoration: underline;
    cursor: pointer;
}

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

.review-hero strong {
    display: block;
    color: var(--ink);
    font-size: 18px;
    margin: 3px 0;
}

/* Sits above the log entries: the pack IS the log plus everything around it, so the
   download belongs with what it contains rather than in a row of decision buttons. */
.audit-pack {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    margin-bottom: 14px;
    padding: 12px 14px;
    max-width: 78ch;
}

.audit-pack strong {
    display: block;
    color: var(--ink);
    font-size: 13px;
}

.audit-pack span {
    display: block;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.45;
    margin-top: 2px;
}

.audit-pack button {
    flex: 0 0 auto;
}

/* Same neutral card and same lift as the hero tiles. */
.drawer-section.review-form {
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    box-shadow: 0 1px 2px rgba(24, 24, 27, 0.04), 0 4px 12px rgba(24, 24, 27, 0.05);
    margin: 4px 0 14px;
    padding: 16px 16px 18px;
}

/* The inputs were white on the old peach card, so the card itself supplied their edge.
   On a white card they need their own or the textarea dissolves into it. Deliberately not
   `background:` shorthand and deliberately not applied to select — the select paints its
   chevron with background-image, which the shorthand would wipe out, and it already
   carries its own border and white background-color. */
.review-form input[type="text"],
.review-form textarea {
    background-color: var(--surface);
    border: 1px solid var(--line);
}

.review-form input[type="text"]:focus,
.review-form textarea:focus {
    border-color: var(--accent);
    outline: none;
}

.review-form h3 {
    margin: 0 0 6px;
}

.review-form label:not(.checkbox-line) {
    display: block;
    color: var(--text);
    font-size: 13px;
    font-weight: 700;
    margin: 14px 0 6px;
}

.review-form select {
    width: 100%;
    min-height: 40px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background-color: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 14px;
    padding: 9px 34px 9px 11px;
    -webkit-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717A' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
}

.review-form select:focus {
    outline: 3px solid rgba(255, 114, 0, 0.18);
    border-color: var(--accent);
}

.review-form input[type="text"],
.review-form textarea {
    border-radius: 8px;
}

.review-form .actions.compact {
    display: block;
    margin-top: 18px;
}

.review-form .actions.compact button {
    width: 100%;
    min-height: 42px;
}

.checkbox-line {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
}

/* Why the record is in this state, when the system put it there rather than a person.
   Read-only context above the form: it explains the routing without becoming the
   assessor's own stated reason the moment they hit Save. */
.auto-note {
    border: 1px dashed var(--line);
    border-radius: 8px;
    background: var(--neutral);
    margin: 0 0 4px;
    padding: 9px 11px;
    color: var(--text);
    font-size: 12px;
    line-height: 1.5;
}

.review-form input.is-invalid,
.review-form select.is-invalid {
    border-color: var(--danger);
}

/* --- save feedback ------------------------------------------------------- */

.save-state {
    display: flex;
    align-items: baseline;
    gap: 6px;
    font-size: 11.5px;
    line-height: 1.45;
    margin: 10px 0 0;
}

.save-state::before {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    transform: translateY(-1px);
}

.save-state.is-synced {
    color: var(--success-text);
}

.save-state.is-synced::before {
    background: var(--success);
}

/* Not an error — "saved here but not in aXcelerate yet" is a real, recoverable state, and
   the Retry action in the Review tile is how it gets resolved. */
.save-state.is-unsynced {
    color: var(--accent-deep);
}

.save-state.is-unsynced::before {
    background: var(--accent);
}

button.is-busy {
    position: relative;
    padding-left: 34px;
    cursor: progress;
}

button.is-busy::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 14px;
    width: 13px;
    height: 13px;
    margin-top: -7px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: button-spin 620ms linear infinite;
}

@keyframes button-spin {
    to { transform: rotate(360deg); }
}

/* --- toasts -------------------------------------------------------------- */

/* Above the drawer's 1200, or a save confirmation would appear behind the thing that
   triggered it. */
.toast-stack {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 1300;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: min(400px, calc(100vw - 36px));
    pointer-events: none;
}

.toast {
    position: relative;
    border: 1px solid var(--line);
    border-left: 4px solid var(--muted);
    border-radius: 8px;
    background: var(--surface);
    box-shadow: 0 8px 26px rgba(24, 24, 27, 0.16);
    padding: 12px 38px 12px 14px;
    color: var(--text);
    font-size: 13px;
    line-height: 1.5;
    pointer-events: auto;
    animation: toast-in 180ms ease-out;
}

.toast-success { border-left-color: var(--success); }
.toast-warning { border-left-color: var(--accent); }
.toast-error   { border-left-color: var(--danger); }
.toast-info    { border-left-color: var(--muted); }

.toast-close {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 24px;
    height: 24px;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--muted);
    font-size: 17px;
    line-height: 1;
    cursor: pointer;
}

.toast-close:hover {
    background: var(--neutral);
    color: var(--ink);
}

@keyframes toast-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .toast { animation: none; }
    button.is-busy::before { animation-duration: 2s; }
}

.review-form .checkbox-line {
    margin-top: 16px;
    font-size: 13px;
}

.checkbox-line input[type="checkbox"] {
    -webkit-appearance: none;
    appearance: none;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    min-height: 0;
    margin: 0;
    border: 1px solid var(--line);
    border-radius: 5px;
    background: var(--surface);
    cursor: pointer;
}

.checkbox-line input[type="checkbox"]:checked {
    border-color: var(--accent);
    background-color: var(--accent);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
}

.checkbox-line input[type="checkbox"]:focus-visible {
    outline: 2px solid rgba(255, 114, 0, 0.45);
    outline-offset: 2px;
}

.drawer-section {
    border-top: 1px solid var(--line);
    padding: 13px 0;
}

.drawer-section:first-child {
    border-top: 0;
}

.drawer-section h3 {
    color: var(--ink);
    font-size: 14px;
    margin: 0 0 10px;
}

.detail-list {
    display: grid;
    gap: 7px;
    margin: 0;
}

.detail-list div {
    display: grid;
    grid-template-columns: 128px minmax(0, 1fr);
    gap: 8px;
}

.detail-list dt {
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
    line-height: 1.5;
}

.detail-list dd {
    color: var(--ink);
    font-size: 13px;
    line-height: 1.5;
    margin: 0;
    overflow-wrap: anywhere;
}

.evidence-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.evidence-card {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    margin: 0;
    overflow: hidden;
}

.evidence-card img {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: var(--ink);
    object-fit: cover;
}

.evidence-video {
    margin-bottom: 12px;
}

/* Call video and ID photos side by side above the answers, in the same tab. auto-fit so
   a record with only a video (or only photos) gets the full width instead of leaving a
   dead column. */
.review-evidence {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 12px;
    align-items: start;
    margin-bottom: 14px;
}

.review-evidence > * {
    margin-bottom: 0;
}

/* Shorter than the 420px standalone cap: the transcript underneath has to start near
   the top of the pane, or merging the tabs just buries the answers instead. */
.review-evidence .evidence-card-video video {
    max-height: 260px;
}

.evidence-card-video video {
    display: block;
    width: 100%;
    max-height: 420px;
    background: var(--ink);
}

.evidence-card figcaption {
    display: grid;
    gap: 2px;
    padding: 8px;
}

.evidence-card strong {
    color: var(--ink);
    font-size: 12px;
}

.evidence-card span {
    color: var(--muted);
    font-size: 11px;
}

/* Video caption is a row: title + meta on the left, download button on the right.
   MUST stay after `.evidence-card figcaption` above: that rule has the same
   specificity, so on equal footing the later one wins and the button would stack. */
.evidence-card-video figcaption {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
}

.evidence-meta {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.evidence-download {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    gap: 6px;
    border-radius: 8px;
    padding: 8px 14px;
    background: var(--text);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    text-decoration: none;
    transition: background 0.15s ease, transform 0.15s ease;
}

.evidence-download svg {
    width: 14px;
    height: 14px;
}

.evidence-download:hover {
    background: var(--ink);
}

.evidence-download:active {
    transform: translateY(1px);
}

.transcript-item,
.rubric-item,
.log-item {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    margin-bottom: 10px;
    padding: 14px 16px;
}

/* Prose caps out at ~78 characters. The drawer is now up to 1440px wide, and text set
   across the whole of that is genuinely hard to read — the eye loses the line on the
   return sweep. This is the single biggest readability win in here. */
.transcript-answer,
.transcript-note,
.rubric-item p,
.log-body p {
    max-width: 78ch;
}

/* --- transcript ---------------------------------------------------------- */

.transcript-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
}

.transcript-item h4 {
    display: flex;
    align-items: baseline;
    gap: 9px;
    color: var(--ink);
    font-size: 14px;
    line-height: 1.4;
    margin: 0;
}

/* The number leaves the heading text so a wrapped question stays aligned instead of
   hanging under its own "1.". */
.transcript-num {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 6px;
    background: var(--soft);
    color: var(--accent-deep);
    font-size: 11px;
    font-weight: 700;
}

.verdict-pill {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 3px 10px;
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
}

.verdict-pill em {
    font-size: 11px;
    font-style: normal;
    font-weight: 600;
}

.verdict-pill.is-competent {
    border-color: var(--success-border);
    background: var(--success-bg);
    color: var(--success-text);
}

.verdict-pill.is-review {
    border-color: var(--tint);
    background: var(--soft);
    color: var(--accent-deep);
}

.verdict-pill.is-unscored {
    background: var(--neutral);
    color: var(--muted);
}

/* The student's own words are the thing being judged, so they get the emphasis the
   verdict used to take: quoted, indented, a size up from the surrounding labels. */
.transcript-answer {
    border-left: 3px solid var(--tint);
    margin: 11px 0 0;
    padding: 2px 0 2px 12px;
    color: var(--ink);
    font-size: 14px;
    line-height: 1.55;
}

.transcript-note {
    color: var(--text);
    font-size: 13px;
    line-height: 1.55;
    margin: 11px 0 0;
}

/* Uppercase micro-label so "Assessor note" reads as a field name, not as the first two
   words of the note itself. */
.field-label {
    display: block;
    color: var(--muted);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-bottom: 3px;
}

/* --- rubric -------------------------------------------------------------- */

.rubric-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 7px;
}

.rubric-id {
    border-radius: 5px;
    background: var(--neutral);
    padding: 2px 7px;
    color: var(--ink);
    font-family: Consolas, "Courier New", monospace;
    font-size: 12px;
}

.rubric-type {
    color: var(--muted);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.rubric-item p {
    color: var(--text);
    font-size: 13px;
    line-height: 1.55;
    margin: 0;
}

/* --- audit log ----------------------------------------------------------- */

.log-item {
    display: grid;
    grid-template-columns: 150px minmax(0, 1fr);
    gap: 14px;
}

/* Tabular figures so every timestamp occupies the same width and the column reads as a
   timeline rather than ragged text. */
.log-time {
    color: var(--muted);
    font-family: Consolas, "Courier New", monospace;
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
    line-height: 1.5;
}

.log-body strong {
    display: block;
    color: var(--ink);
    font-size: 13px;
}

.log-body p {
    color: var(--text);
    font-size: 12.5px;
    line-height: 1.55;
    margin: 4px 0 0;
    overflow-wrap: anywhere;
}

/* --- key/value lists (Student and Call, Access) -------------------------- */

.detail-list div + div {
    border-top: 1px dashed var(--line);
    padding-top: 7px;
}

/* No max-height: a 360px cap gave this its own inner scrollbar, so the report stopped
   dead two thirds down the tab with dead space under it while the pane still had room.
   Letting it grow to its content means the pane scrolls it, exactly like every other
   tab — one scrollbar, full height. */
/* --- plain-English report ------------------------------------------------ */

/* Was one <pre>: a peach wall of ~40 undifferentiated lines you had to read top to
   bottom to find anything in. Now the report's own blank lines become cards and its
   "Label: value" lines become rows, which is what the Access and Audit log tabs already
   look like. The text is untouched — this is the copy that went to aXcelerate. */
.report-title {
    color: var(--ink);
    font-size: 15px;
    margin: 2px 0 12px;
}

.report-block {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    margin-bottom: 10px;
    padding: 14px 16px;
    max-width: 78ch;
}

.report-block h5 {
    color: var(--ink);
    font-size: 13.5px;
    line-height: 1.45;
    margin: 0 0 9px;
}

.report-row {
    display: grid;
    grid-template-columns: 210px minmax(0, 1fr);
    gap: 12px;
    padding: 5px 0;
}

.report-row + .report-row {
    border-top: 1px dashed var(--line);
}

.report-key {
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
    line-height: 1.5;
}

.report-value {
    color: var(--ink);
    font-size: 13px;
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.report-line {
    color: var(--text);
    font-size: 13px;
    line-height: 1.6;
    margin: 0 0 6px;
}

.report-line:last-child {
    margin-bottom: 0;
}

.hidden {
    display: none !important;
}

.landing-page {
    background:
        radial-gradient(circle at top left, rgba(255, 114, 0, 0.08), transparent 28%),
        radial-gradient(circle at top right, rgba(0, 166, 118, 0.07), transparent 26%),
        var(--paper);
}

.landing-shell {
    padding-top: 18px;
    padding-bottom: 34px;
}

/* The two-column .landing-hero / .landing-grid / .landing-summary-card / .feature-list
   layout was removed with the side-by-side landing page. Keeping it would leave two
   competing layouts in this file with nothing saying which one is live. */

/* One card holding the hero and the steps/video, then the FAQ card below it. Previously
   only the FAQ had a panel, so everything above it floated loose on the tinted page with
   no edges - which is why the video read as a beige rectangle rather than a media slot,
   and why the page felt structureless. */
.landing-panel {
    margin-top: 26px;
    padding: 42px 44px 44px;
    border-radius: 18px;
    box-shadow: 0 18px 50px rgba(24, 24, 27, 0.07);
}

/* Centred hero, then the video, then the detail. The previous version put the hero copy,
   a five-item checklist and a three-item meta strip side by side, so a student read ~120
   words before reaching a decision. One claim, one action, then show it. */
.landing-hero-centred {
    max-width: 620px;
    margin: 0 auto;
    text-align: center;
}

.landing-hero-centred h1 {
    margin: 6px 0 12px;
}

.landing-hero-centred .hero-copy {
    color: var(--muted);
    font-size: 15.5px;
    line-height: 1.65;
    margin: 0 auto 26px;
    max-width: 52ch;      /* the measure is what keeps a centred paragraph readable */
}

.landing-hero-centred .landing-actions {
    justify-content: center;
}

.hero-requirements {
    color: var(--muted);
    font-size: 13px;
    margin: 20px 0 0;
}

/* Steps left, video right. Full width, the 16:9 video was the largest thing on the page
   by a distance and pulled attention off the action; at roughly half width it sits beside
   the steps as a companion instead of dominating. Video second in the source so the
   steps come first for a screen reader and when this collapses on a narrow screen. */
.landing-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: 30px;
    align-items: start;
    /* Hairline divider rather than a second card: the hero and the detail are one
       thought, and stacking two panels here would fragment a short page. */
    border-top: 1px solid var(--line);
    margin-top: 38px;
    padding-top: 36px;
}

/* aspect-ratio rather than a fixed height, so a real <video> or embed dropped in here
   fills it correctly at every width with no further CSS. */
.video-band {
    margin: 0;
}

/* Inside a white card now, so it needs its own edge: a heavy drop shadow made sense when
   it floated on the tinted page, but on white it just looked smudged. A real border reads
   as a media slot rather than a coloured rectangle. */
.video-frame {
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 14px;
    box-shadow: 0 6px 18px rgba(24, 24, 27, 0.06);
}

.video-frame > .video-placeholder,
.video-frame > video,
.video-frame > iframe {
    display: grid;
    place-content: center;
    width: 100%;
    aspect-ratio: 16 / 9;
    /* The frame owns the edge now, so the placeholder drops its own border, radius and
       the min-height/margin it needed as a standalone card. */
    min-height: 0;
    margin: 0;
    border: 0;
    border-radius: 0;
}

/* Stacked, not three across: in a half-width column three would be ~150px each and the
   text would wrap to four lines apiece. */
.steps-section {
    margin: 0;
}

.steps-row {
    counter-reset: step;
    display: grid;
    gap: 22px;
    list-style: none;
    margin: 20px 0 0;
    padding: 0;
}

.steps-row li {
    position: relative;
    padding-left: 42px;
}

/* Same treatment as the active step in the screening stepper (.progress-step.active span)
   so a student sees one numbering language across both pages. */
.steps-row li::before {
    counter-increment: step;
    content: counter(step);
    position: absolute;
    left: 0;
    top: 0;
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    border-radius: 999px;
    background: linear-gradient(180deg, var(--accent) 0%, var(--accent-dark) 100%);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
}

.steps-row strong {
    display: block;
    color: var(--ink);
    font-size: 15px;
    margin: 4px 0 4px;
}

.steps-row span {
    display: block;
    color: var(--muted);
    font-size: 13.5px;
    line-height: 1.55;
}

.video-placeholder {
    display: grid;
    place-items: center;
    align-content: center;
    /* Trimmed from 220px: it is a placeholder, and at the old height an empty box was
       the largest thing on the page. Sized so the two cards read as a pair instead. */
    min-height: 168px;
    border: 1px dashed var(--line);
    border-radius: 8px;
    background:
        linear-gradient(135deg, rgba(255, 114, 0, 0.04), rgba(0, 166, 118, 0.04)),
        var(--soft);
    margin-top: 14px;
    padding: 22px;
    text-align: center;
}

.video-placeholder span {
    color: var(--accent-deep);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.video-placeholder p {
    color: var(--muted);
    line-height: 1.6;
    margin: 10px 0 0;
    max-width: 360px;
}

/* --- FAQ dialog ---------------------------------------------------------- */

.faq-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: rgba(24, 24, 27, 0.34);
}

@supports ((-webkit-backdrop-filter: blur(4px)) or (backdrop-filter: blur(4px))) {
    .faq-backdrop {
        background: rgba(24, 24, 27, 0.22);
        -webkit-backdrop-filter: blur(4px);
        backdrop-filter: blur(4px);
    }
}

.faq-modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1200;
    display: flex;
    flex-direction: column;
    width: min(620px, calc(100vw - 32px));
    max-height: min(720px, calc(100vh - 48px));
    max-height: min(720px, calc(100dvh - 48px));
    border: 1px solid var(--line);
    border-radius: 18px;
    background: var(--surface);
    box-shadow: 0 24px 70px rgba(24, 24, 27, 0.28);
}

.faq-modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex: 0 0 auto;
    border-bottom: 1px solid var(--line);
    padding: 22px 26px 18px;
}

.faq-modal-head h2 {
    margin: 0;
    font-size: 19px;
}

.faq-close {
    flex: 0 0 auto;
    min-height: 0;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 9px;
    background: none;
    padding: 0;
    color: var(--muted);
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
}

.faq-close:hover:not(:disabled) {
    background: var(--soft);
    color: var(--ink);
}

.faq-modal .faq-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    margin: 0;
    padding: 4px 26px 20px;
}

/* Stops the page behind scrolling while the dialog is open. */
body.modal-open {
    overflow: hidden;
}

.faq-list {
    margin-top: 16px;
}

/* Hairline rows, not seven filled boxes. Boxed accordions put a heavy border and a
   background behind every question, so a list of seven reads as a wall; the same
   hairline used inside .landing-panel keeps it quiet and consistent. */
.faq-list details {
    border: 0;
    border-top: 1px solid var(--line);
    border-radius: 0;
    background: none;
    padding: 0;
}

.faq-list details:first-child {
    border-top: 0;
}

.faq-list summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 18px;
    list-style: none;          /* hides the default triangle in Firefox */
    padding: 16px 0;
    cursor: pointer;
    color: var(--ink);
    font-size: 14.5px;
    font-weight: 700;
}

.faq-list summary::-webkit-details-marker {
    display: none;             /* ...and in Safari */
}

.faq-list summary:hover {
    color: var(--accent-dark);
}

/* A rotating chevron, so open/closed is legible without relying on the answer appearing. */
.faq-list summary::after {
    content: "";
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    margin-right: 4px;
    border-right: 2px solid var(--accent);
    border-bottom: 2px solid var(--accent);
    transform: translateY(-2px) rotate(45deg);
    transition: transform 160ms ease;
}

.faq-list details[open] summary::after {
    transform: translateY(2px) rotate(-135deg);
}

.faq-list details p {
    color: var(--muted);
    font-size: 14px;
    line-height: 1.65;
    margin: 0 0 18px;
    max-width: 76ch;
}

@media (prefers-reduced-motion: reduce) {
    .faq-list summary::after {
        transition: none;
    }
}

pre {
    min-height: 140px;
    max-height: 280px;
    overflow: auto;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--soft);
    color: var(--text);
    font-family: Arial, Helvetica, sans-serif;
    font-size: 14px;
    line-height: 1.55;
    margin: 0;
    padding: 16px;
    white-space: pre-wrap;
}

@media (max-width: 860px) {
    .app-shell {
        width: min(100% - 24px, 1100px);
        padding-top: 16px;
    }

    .brand-bar {
        align-items: flex-start;
        flex-direction: column;
        gap: 12px;
    }

    .header-actions {
        justify-content: flex-start;
    }

    .brand-lockup {
        align-items: flex-start;
        flex-direction: column;
        gap: 8px;
    }

    .brand-logo {
        width: 150px;
    }

    .hero,
    .workflow-layout,
    .content-grid {
        grid-template-columns: 1fr;
    }

    .workflow-layout {
        gap: 10px;
    }

    .progress-strip {
        position: static;
        grid-template-columns: 1fr;
    }

    .camera-box {
        grid-template-columns: 1fr;
    }

    .camera-box .microcopy {
        grid-column: auto;
    }

    .hero {
        padding: 20px;
    }

    .landing-split {
        grid-template-columns: 1fr;
        gap: 26px;
        margin-top: 26px;
        padding-top: 26px;
    }

    .landing-panel {
        padding: 26px 20px;
        border-radius: 14px;
    }

    .faq-modal-head {
        padding: 18px 18px 14px;
    }

    .faq-modal .faq-list {
        padding: 4px 18px 16px;
    }

    h1 {
        font-size: 27px;
    }

    .status-card {
        justify-self: start;
    }

    .call-panel {
        min-height: auto;
    }

    .message {
        min-height: 104px;
        font-size: 16px;
    }

    .call-times {
        grid-template-columns: 1fr;
    }

    .admin-toolbar {
        align-items: flex-start;
        flex-direction: column;
    }

    .admin-summary {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .admin-filters {
        grid-template-columns: 1fr;
    }

    .pagination-bar {
        align-items: flex-start;
        flex-direction: column;
    }

    .pagination-controls {
        flex-wrap: wrap;
    }

    .report-panel {
        width: 100vw;
        height: 100vh;
        height: 100dvh;
        border: 0;
        border-radius: 0;
    }

    /* One column on a narrow screen: the rail's border and its own scroll would split
       an already-short viewport in two. The body takes the scroll back over, and the
       tabs keep working — they are the only thing making this length bearable here. */
    .drawer-grid {
        grid-template-columns: 1fr;
        gap: 0;
    }

    .review-drawer-body {
        overflow: auto;
    }

    .drawer-rail,
    .drawer-pane {
        overflow: visible;
        padding-right: 0;
        border-right: 0;
    }

    .review-hero,
    .qbank-cards,
    .qbank-field-row,
    .evidence-grid,
    .log-item,
    .report-row,
    .question-bank-controls {
        grid-template-columns: 1fr;
    }

    /* Button under the description rather than beside it. */
    .audit-pack {
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
    }

    .report-row {
        gap: 2px;
    }

    /* The verdict pill can't sit beside the question in this width without squeezing it
       to two words per line, so it drops below. */
    .transcript-head {
        flex-wrap: wrap;
        gap: 8px;
    }

    .log-item {
        gap: 5px;
    }

    .question-bank-editor {
        width: calc(100% - 24px);
        margin-inline: 12px;
    }
}

/* Who is signed in, and the way out. Sits in the header of both pages a signed-in
   student can reach, because an 8-hour session that survives closing the browser needs
   a visible exit - especially on a shared or campus machine. */
.session-bar {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    padding: 5px 6px 5px 13px;
    font-size: 12.5px;
}

.session-who {
    color: var(--ink);
    font-weight: 700;
    max-width: 14ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.session-signout {
    min-height: 0;             /* the global button rule sets 38px, which bloats the pill */
    border: 0;
    border-radius: 999px;
    background: var(--soft);
    padding: 5px 12px;
    color: var(--accent-deep);
    font: inherit;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}

/* Two classes deep on purpose. `button:hover:not(:disabled)` is specificity (0,2,1) and
   beat a plain `.session-signout:hover` at (0,2,0), so the global filled the pill with
   solid --accent-dark while this rule set dark-orange text on top of it: an orange blob
   with invisible text. (0,3,0) wins. */
.session-bar .session-signout:hover {
    background: var(--tint);
    color: var(--accent-dark);
}

/* --- student sign-in ----------------------------------------------------- */

/* The brand tint carries the page and the card floats on it, rather than a white form on
   white. Orange stays what it already means everywhere else: the action. */
.login-page {
    background:
        radial-gradient(circle at 12% 0%, rgba(255, 114, 0, 0.16), transparent 42%),
        radial-gradient(circle at 88% 8%, rgba(0, 166, 118, 0.10), transparent 38%),
        var(--paper);
}

.login-shell {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    min-height: 100vh;
    min-height: 100dvh;
    padding: 32px 20px;
}

.login-card {
    position: relative;
    width: min(440px, 100%);
    border-radius: 18px;
    padding: 34px 32px 30px;
    box-shadow: 0 20px 60px rgba(24, 24, 27, 0.10);
    overflow: hidden;
}

/* A brand rule across the top of the card: one deliberate mark instead of an orange
   wash that would fight the Save-style buttons for attention. */
.login-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 4px;
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-dark) 55%, var(--success) 100%);
}

.login-logo {
    display: block;
    height: 34px;
    width: auto;
    margin-bottom: 22px;
}

.login-step h1 {
    color: var(--ink);
    font-size: 22px;
    line-height: 1.3;
    margin: 2px 0 10px;
}

.login-lede {
    color: var(--muted);
    font-size: 14px;
    line-height: 1.6;
    margin: 0 0 22px;
}

.login-lede strong {
    color: var(--ink);
}

.login-step label {
    display: block;
    color: var(--text);
    font-size: 13px;
    font-weight: 700;
    margin-bottom: 6px;
}

#student-id {
    width: 100%;
    min-height: 46px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    padding: 11px 13px;
    color: var(--ink);
    font: inherit;
    font-size: 16px;               /* 16px stops iOS Safari zooming the page on focus */
    letter-spacing: 0.02em;
}

#student-id:focus {
    border-color: var(--accent);
    outline: 2px solid var(--tint);
    outline-offset: 1px;
}

.login-hint {
    color: var(--muted);
    font-size: 12px;
    line-height: 1.5;
    margin: 7px 0 22px;
}

.login-submit {
    width: 100%;
    min-height: 46px;
    font-size: 15px;
}

/* --- the six code boxes --- */

.otp-inputs {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 8px;
    margin: 4px 0 22px;
}

.otp-box {
    width: 100%;
    aspect-ratio: 3 / 4;
    min-height: 52px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    padding: 0;
    color: var(--ink);
    font: inherit;
    font-size: 22px;
    font-weight: 700;
    text-align: center;
    caret-color: var(--accent);
}

.otp-box:focus {
    border-color: var(--accent);
    background: var(--soft);
    outline: 2px solid var(--tint);
    outline-offset: 1px;
}

.login-footer-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 10px;
    margin-top: 16px;
}

.login-link {
    border: 0;
    background: none;
    padding: 0;
    color: var(--accent-deep);
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    text-decoration: underline;
    cursor: pointer;
}

/* Same leak the :hover note above describes, on the disabled state: `button:disabled` fills
   `var(--line)`, and this rule used to override only the colour. A text button with
   `padding: 0` then drew that grey hugging the words, so "Resend code in 59s" spent its whole
   cooldown looking like a cramped pill. Muted text with no underline is the disabled signal;
   it needs no fill. */
.login-link:disabled {
    background: none;
    color: var(--muted);
    text-decoration: none;
    cursor: default;
}

.login-link:hover:not(:disabled) {
    color: var(--accent-dark);
}

/* Errors here are usually recoverable (wrong digit, expired code), so this is an
   attention colour rather than an alarm. */
.login-error {
    border: 1px solid var(--tint);
    border-left: 4px solid var(--accent);
    border-radius: 8px;
    background: var(--soft);
    margin: 18px 0 0;
    padding: 11px 13px;
    color: var(--accent-deep);
    font-size: 13px;
    line-height: 1.55;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

@media (max-width: 420px) {
    .login-card { padding: 26px 20px 24px; }
    .otp-inputs { gap: 6px; }
    .otp-box { min-height: 46px; font-size: 19px; }
}

/* Support authentication code: student "verify with code" shortcut + admin display */
.auth-code-footer {
    margin-top: 10px;
    text-align: right;
}

.auth-code-toggle {
    min-height: 0;
    padding: 0;
    border: none;
    border-radius: 0;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 0.8rem;
    font-weight: 400;
    text-decoration: underline;
    cursor: pointer;
}

/* Match the global button:hover:not(:disabled) specificity (0,2,1) so the toggle
   never gets the orange button fill on hover — just a link-style colour change. */
.auth-code-toggle:hover:not(:disabled) {
    background: none;
    color: var(--accent-deep);
}

.auth-code-block {
    margin-top: 10px;
}

.auth-code-actions {
    display: flex;
    gap: 8px;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
}

.auth-code-actions #auth-code {
    flex: 0 0 auto;
    width: 150px;
    max-width: 100%;
    text-transform: uppercase;
}

.auth-code-actions #redeem-code-btn {
    flex: 0 0 auto;
    white-space: nowrap;
}

.support-code-panel {
    border-left: 4px solid var(--accent);
    background: linear-gradient(180deg, var(--soft), var(--surface));
}

/* Support role: only the authentication-code panel is available. */
body.role-support #records-panel,
body.role-support #report-backdrop,
body.role-support #report-viewer {
    display: none !important;
}

.support-code-buttons {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

/* Align the intro copy and the code box with the toolbar header (the admin panel
   has padding:0 and the toolbar supplies its own 20px), so nothing sits flush to
   the panel edge. */
.support-code-panel > .microcopy {
    margin: 2px 20px 0;
}

.support-code-display {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin: 12px 20px 18px;
    padding: 14px 18px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--surface);
}

#support-code {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 2.1rem;
    letter-spacing: 0.3em;
    color: var(--accent-dark);
    line-height: 1.1;
}

/* Push the expiry to the far right, code + Copy stay grouped on the left. */
#support-code-ttl {
    margin: 0 0 0 auto;
    color: var(--muted);
}

.support-code-copy {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 0;
    border: 1px solid transparent;
    border-radius: 8px;
    background: none;
    padding: 5px 9px;
    color: var(--muted);
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.support-code-copy:hover:not(:disabled) {
    background: var(--soft);
    border-color: var(--line);
    color: var(--text);
}

.support-code-copy svg {
    width: 15px;
    height: 15px;
}

.support-code-copy.is-copied,
.support-code-copy.is-copied:hover:not(:disabled) {
    color: var(--success-text);
    background: none;
    border-color: transparent;
}

/* Verification failure dialog (native <dialog>) */
.verify-fail-dialog {
    border: none;
    border-radius: 14px;
    padding: 24px;
    max-width: 420px;
    color: var(--text);
    box-shadow: var(--shadow);
}

.verify-fail-dialog::backdrop {
    background: rgba(24, 24, 27, 0.45);
}

.verify-fail-title {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 8px;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--accent-dark);
}

.verify-fail-title svg {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
}

.verify-fail-message {
    margin: 0 0 18px;
    font-size: 0.95rem;
    font-weight: 400;
    line-height: 1.5;
    color: var(--text);
}

/* A span, not a second <p>: the hours live inside the message paragraph already. */
.verify-fail-hours {
    display: block;
    margin-top: 10px;
}

.verify-fail-hours strong {
    color: var(--ink);
    font-weight: 700;
}

.verify-fail-actions {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    flex-wrap: wrap;
}
