/* ============================================================
   ExamPilot AI - Admin Panel + Exam Styles
   Matches welcome.css / auth.css: Linear-inspired dark theme
   ============================================================ */

:root {
  --bg: #08090a;
  --panel: #0f1011;
  --surface: #191a1b;
  --surface-2: #28282c;
  --text-1: #f7f8f8;
  --text-2: #d0d6e0;
  --text-3: #8a8f98;
  --text-4: #62666d;
  --brand: #5e6ad2;
  --accent: #7170ff;
  --accent-hover: #828fff;
  --border-subtle: rgba(255, 255, 255, 0.05);
  --border: rgba(255, 255, 255, 0.08);
  --green: #10b981;
  --amber: #f59e0b;
  --red: #f87171;
  --radius: 8px;
  --font: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Translucent white overlays used across the dark theme. Expressed as
     variables so the white admin theme (body.light below) can flip them
     to dark-on-light equivalents without touching every rule. */
  --overlay-1: rgba(255, 255, 255, 0.015);  /* row hover, question blocks */
  --overlay-2: rgba(255, 255, 255, 0.02);   /* subtle panel fills */
  --overlay-3: rgba(255, 255, 255, 0.03);   /* link/profile hovers */
  --overlay-4: rgba(255, 255, 255, 0.04);   /* sidebar active, btn hovers */
  --overlay-5: rgba(255, 255, 255, 0.05);   /* badges, muted chips */
  --overlay-6: rgba(255, 255, 255, 0.06);   /* question number circles */
  --overlay-8: rgba(255, 255, 255, 0.08);   /* brand mark glow ring */
  --overlay-16: rgba(255, 255, 255, 0.16);  /* input hover borders */
  --overlay-18: rgba(255, 255, 255, 0.18);  /* segmented hover border */
  --dropdown: #17181c;                       /* combobox list bg */
}

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

body {
  font-family: var(--font);
  font-feature-settings: 'cv01', 'ss03';
  background: var(--bg);
  color: var(--text-2);
  -webkit-font-smoothing: antialiased;
  line-height: 1.5;
}

::selection { background: rgba(113, 112, 255, 0.3); color: #fff; }

/* ================= ADMIN LAYOUT ================= */
.admin-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: 240px;
  flex-shrink: 0;
  background: var(--panel);
  border-right: 1px solid var(--border-subtle);
  padding: 24px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 10px 20px;
  text-decoration: none;
  border-bottom: 1px solid var(--border-subtle);
  margin-bottom: 16px;
}

.sidebar-brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 7px;
  background: linear-gradient(135deg, var(--brand), var(--accent));
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 20px rgba(113, 112, 255, 0.3);
}

.sidebar-brand-mark svg { width: 16px; height: 16px; }

/* Phase 4 white-label: org logo inside the sidebar brand slot. Fills the
   30px mark with object-fit cover so any aspect ratio looks intentional. */
.sidebar-brand-logo {
  width: 30px;
  height: 30px;
  border-radius: 7px;
  object-fit: cover;
  display: block;
}

.sidebar-brand-text {
  color: var(--text-1);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.sidebar-brand-text span { color: var(--accent); }

/* Tenant strip (Phase 4): org identity under the sidebar brand.
   Always visible: org admins see their org; founder sees Platform
   or the acting org. Pairs with the temporary "Viewing as" banner. */
.tenant-strip {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: -8px 0 14px;
  padding: 9px 12px;
  background: var(--overlay-4);
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
}
.tenant-label {
  font-family: var(--mono);
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-4);
}
.tenant-name {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-1);
}
.tenant-logo {
  width: 20px;
  height: 20px;
  border-radius: 5px;
  object-fit: contain;
  flex-shrink: 0;
  background: var(--overlay-8);
}
.tenant-logo-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 600;
  color: #fff;
  background: linear-gradient(135deg, #5e6ad2, #a78bfa);
}
.tenant-name-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Org badge - phone-only org identity in the page header (Phase 4).
   Hidden by default; shown inside the ≤640px block below. */
.org-badge { display: none; }

.sidebar-label {
  font-family: var(--mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-4);
  padding: 12px 10px 6px;
}

.sidebar-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 6px;
  color: var(--text-3);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 450;
  transition: all 0.12s ease;
}

.sidebar-link svg { width: 16px; height: 16px; flex-shrink: 0; opacity: 0.8; }
/* Long "Platform Console" label on desktop; short "Console" at ≤640px */
.sidebar-link .nav-label-short { display: none; }

.sidebar-link:hover { background: var(--overlay-3); color: var(--text-1); }

.sidebar-link.active {
  background: rgba(113, 112, 255, 0.1);
  color: var(--accent-hover);
}

.sidebar-footer {
  margin-top: auto;
  padding: 12px 10px 0;
  border-top: 1px solid var(--border-subtle);
}

/* Admin profile chip in sidebar */
.admin-profile {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: default;
  transition: background 0.12s ease;
}

.admin-profile:hover { background: var(--overlay-3); }

.admin-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, #5e6ad2, #a78bfa);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  flex-shrink: 0;
  letter-spacing: 0.02em;
  box-shadow: 0 0 0 2px rgba(113, 112, 255, 0.25);
}

.admin-profile-meta {
  flex: 1;
  min-width: 0;
  line-height: 1.3;
}

.admin-profile-meta strong {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.admin-profile-meta span {
  display: block;
  font-size: 11px;
  color: var(--text-4);
}

.admin-profile-more {
  color: var(--text-4);
  display: flex;
  align-items: center;
  padding: 4px;
  border-radius: 5px;
  border: none;
  background: none;
  cursor: pointer;
}

.admin-profile-more:hover { color: var(--text-1); background: var(--overlay-5); }

.admin-profile-more svg { width: 15px; height: 15px; }

/* ================= MAIN CONTENT ================= */
.main {
  flex: 1;
  min-width: 0;   /* flex item must be allowed to shrink below table
                     min-content, or wide tables overflow the viewport */
  padding: 32px 40px 60px;
  max-width: 1200px;
}

.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 28px;
  flex-wrap: wrap;
}

.page-head h1 {
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text-1);
}

.page-head p {
  font-size: 13px;
  color: var(--text-4);
  margin-top: 4px;
}

.page-actions { display: flex; gap: 10px; align-items: center; }

/* ================= STAT CARDS ================= */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 28px;
}

.stat-card {
  background: var(--panel);
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  padding: 20px;
}

.stat-card-label {
  font-size: 12px;
  color: var(--text-4);
  margin-bottom: 8px;
}

.stat-card-value {
  font-size: 30px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text-1);
  font-feature-settings: 'tnum';
}

.stat-card-value .unit { font-size: 14px; color: var(--text-4); margin-left: 4px; }

.stat-card-delta {
  font-size: 12px;
  margin-top: 6px;
}

.stat-card-delta.up { color: var(--green); }
.stat-card-delta.down { color: var(--red); }

/* ================= PANELS & TABLES ================= */
.panel {
  background: var(--panel);
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  margin-bottom: 20px;
  min-width: 0;  /* allow shrink below content width (wide tables) */
}

/* Soft-padded variant for panels without .panel-body wrapper */
.panel-soft { padding: 20px; }

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border-subtle);
}

.panel-head h2 {
  font-size: 15px;
  font-weight: 500;
  color: var(--text-1);
  letter-spacing: -0.01em;
}

.panel-body { padding: 20px; }

table.tbl {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  /* Real table layout on desktop: width:100% spreads the columns across
     the panel. The block+scroll mode below ONLY applies at ≤1024px
     (see media query) - as a base rule it squeezed every column to
     content width and left the right half of the panel empty. */
}

.tbl th {
  text-align: left;
  font-size: 11px;
  font-family: var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-4);
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
}

.tbl td {
  padding: 13px 16px;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-2);
  vertical-align: middle;
}

.tbl tr:last-child td { border-bottom: none; }

.tbl tr:hover td { background: var(--overlay-1); }

.tbl .cell-strong { color: var(--text-1); font-weight: 500; }
.tbl .cell-mono { font-family: var(--mono); font-size: 12.5px; color: var(--text-3); }

/* ================= BADGES ================= */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 500;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

.badge-dot { width: 6px; height: 6px; border-radius: 50%; }

.badge-green { background: rgba(16, 185, 129, 0.1); color: #34d399; }
.badge-green .badge-dot { background: var(--green); }
.badge-amber { background: rgba(245, 158, 11, 0.1); color: #fbbf24; }
.badge-amber .badge-dot { background: var(--amber); }
.badge-red { background: rgba(248, 113, 113, 0.1); color: #f87171; }
.badge-red .badge-dot { background: var(--red); }
.badge-gray { background: var(--overlay-5); color: var(--text-3); }
.badge-gray .badge-dot { background: var(--text-4); }

/* Semantic aliases used by exams.js / candidates.js */
.badge-success { background: rgba(16, 185, 129, 0.1); color: #34d399; }
.badge-muted   { background: var(--overlay-5); color: var(--text-3); }
.badge-warn    { background: rgba(245, 158, 11, 0.1); color: #fbbf24; }
.badge-danger  { background: rgba(248, 113, 113, 0.1); color: #f87171; }
.badge-brand { background: rgba(113, 112, 255, 0.12); color: var(--accent-hover); }

/* ================= BUTTONS ================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font);
  font-size: 13.5px;
  font-weight: 500;
  padding: 9px 16px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.15s ease;
  text-decoration: none;
  border: none;
  font-feature-settings: 'cv01', 'ss03';
}

.btn svg { width: 15px; height: 15px; }

.btn-primary {
  background: var(--brand);
  color: #fff;
  box-shadow: 0 0 0 1px var(--overlay-5) inset, 0 4px 16px rgba(94, 106, 210, 0.2);
}

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

.btn-ghost {
  background: transparent;
  color: var(--text-2);
  border: 1px solid rgb(36, 40, 44);
}

.btn-ghost:hover { background: var(--overlay-4); color: var(--text-1); }

.btn-sm { padding: 6px 12px; font-size: 12.5px; }
.btn-sm svg { width: 13px; height: 13px; }

.btn-danger { background: rgba(248, 113, 113, 0.1); color: #fca5a5; border: 1px solid rgba(248, 113, 113, 0.25); }
.btn-danger:hover { background: rgba(248, 113, 113, 0.18); }

/* ================= FORMS ================= */
/* minmax(0,1fr): a plain 1fr track sizes to the widest item's min-content,
   which can exceed the container on phones (inputs were forced to 410px,
   clipping the modal footer). 0 allows the track to shrink to the actual
   container width (Kishan Aug 29). */
.form-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; }
.form-grid .full { grid-column: 1 / -1; }

.field { display: flex; flex-direction: column; gap: 6px; }
/* The hidden attribute MUST win over .field's display:flex - otherwise a
   hidden field (e.g. superadmin-only bank size) renders for everyone.
   Author CSS beats the browser's UA [hidden] rule, so this explicit rule
   restores the attribute's authority (Kishan Aug 28 2026). */
.field[hidden] { display: none; }

.field label {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-2);
}

.field input, .field select, .field textarea {
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-1);
  background: var(--overlay-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(113, 112, 255, 0.15);
}

.field select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8f98' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 14px;
  cursor: pointer;
}

.field .hint { font-size: 11.5px; color: var(--text-4); }

/* ================= INDUSTRY COMBOBOX (searchable select) ================= */
.combobox { position: relative; }
.combobox input[type="text"] { width: 100%; padding-right: 34px; }
.combobox-clear {
  position: absolute; top: 50%; right: 8px; transform: translateY(-50%);
  border: none; background: none; color: var(--text-4); font-size: 16px;
  cursor: pointer; padding: 2px 6px; line-height: 1;
}
.combobox-clear:hover { color: var(--text-1); }
.combobox-list {
  position: absolute; z-index: 60; top: calc(100% + 4px); left: 0; right: 0;
  max-height: 240px; overflow-y: auto; margin: 0; padding: 4px;
  list-style: none;
  background: var(--dropdown); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}
/* Open upward when there is no room below the input (mobile keyboard
   open) - JS toggles this class (Kishan Aug 29). */
.combobox-list.combobox-up { top: auto; bottom: calc(100% + 4px); }
.combobox-list li {
  padding: 9px 10px; font-size: 13.5px; color: var(--text-1);
  border-radius: 6px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.combobox-list li:hover { background: rgba(113, 112, 255, 0.14); }
.combobox-list li.combobox-custom { color: var(--accent); }
.combobox-list li.combobox-custom strong { font-weight: 600; }
.combobox-list li.combobox-count {
  padding: 6px 10px; font-size: 11.5px; color: var(--text-4);
  cursor: default; pointer-events: none; letter-spacing: 0.02em;
}
.combobox-list li mark {
  background: rgba(113, 112, 255, 0.28); color: #fff;
  border-radius: 3px; padding: 0 1px;
}
.combobox-list li.combobox-active {
  background: rgba(113, 112, 255, 0.22);
  outline: none;
}
/* White theme: dropdown bg flips via --dropdown; soften the shadow and
   keep mark highlight readable on white (Kishan Aug 29). */
body.light .combobox-list {
  box-shadow: 0 10px 30px rgba(23, 24, 28, 0.16);
}
body.light .combobox-list li mark { color: var(--text-1); }
.field-hint { font-size: 11.5px; color: var(--text-4); margin-top: 6px; }

/* ================= GENERIC INPUT (standalone, dark theme) =================
   Used by invite modal + any non-.field input. Matches .field input look. */
.input {
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-1);
  background: var(--overlay-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.input::placeholder { color: var(--text-4); opacity: 1; }
.input:hover { border-color: var(--overlay-16); }
.input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(113, 112, 255, 0.15); }
input[type="number"].input { -moz-appearance: textfield; appearance: textfield; }
input[type="number"].input::-webkit-outer-spin-button,
input[type="number"].input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* ================= INVITE MODAL (Phase 2) ================= */
.invite-cand-list {
  max-height: 220px;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--overlay-2);
}
.invite-cand-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  cursor: pointer;
  border-bottom: 1px solid var(--border-subtle);
  transition: background 0.12s ease;
}
.invite-cand-row:last-child { border-bottom: none; }
.invite-cand-row:hover { background: rgba(113, 112, 255, 0.06); }
.invite-cand-row.checked { background: rgba(113, 112, 255, 0.08); }
.invite-cand-row.muted { opacity: 0.55; }
.invite-cand-row.muted:hover { background: transparent; cursor: not-allowed; }
.invite-cand-row input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  min-width: 16px;
  border: 1.5px solid var(--text-4);
  border-radius: 4px;
  background: var(--overlay-3);
  cursor: pointer;
  position: relative;
  transition: all 0.12s ease;
}
.invite-cand-row input[type="checkbox"]:hover { border-color: var(--text-3); }
.invite-cand-row input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.invite-cand-row input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 4.5px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.invite-cand-name { font-weight: 500; font-size: 13.5px; color: var(--text-1); }
.invite-cand-email { color: var(--text-3); font-size: 12px; }
.invite-cand-empty { padding: 14px; color: var(--text-4); text-align: center; font-size: 13px; }
.invite-note {
  font-size: 12px;
  color: var(--text-3);
  background: var(--overlay-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 12px;
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.invite-note svg { flex-shrink: 0; margin-top: 1px; }

/* ================= ASSIGNMENT LIST (detail modal) ================= */
.assign-stats { display: flex; flex-wrap: wrap; gap: 14px; font-size: 12px; color: var(--text-3); }
.assign-stats b { color: var(--text-1); font-weight: 600; }
.assign-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 2px;
  border-bottom: 1px solid var(--border-subtle);
}
.assign-row:last-child { border-bottom: none; }
.assign-row .name { font-weight: 500; font-size: 12.5px; color: var(--text-1); }
.assign-row .meta { font-size: 11.5px; color: var(--text-3); }
.assign-row .actions { display: flex; gap: 6px; flex-shrink: 0; }

.form-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; }

/* ============ INVITE MODALS - layout polish (Sep 7 2026) ============
   Shared by admin-exams (exam -> candidates) and admin-candidates
   (candidate -> exams) invite dialogs. Replaces the old inline-style
   cramping: status badges sit OUTSIDE the truncating text column (they
   were inside it, so long rows clipped the badge off the right edge),
   picker rows are two-line (title + muted meta), stats are chips, the
   expiry control wraps on narrow screens, and on phones the inner
   scroll-boxes collapse so the whole modal scrolls above the pinned
   footer (preview-list pattern, Aug 25). */
.modal-invite { max-width: 620px; }
.grid-invite { display: grid; gap: 14px; font-size: 13.5px; }
.sec-label { display: block; color: var(--text-3); font-size: 12px; font-weight: 500; margin-bottom: 6px; }
.w-full { width: 100%; }
.assign-list {
  display: none;
  max-height: 150px;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 4px 12px;
}
.assign-stats { gap: 8px; margin-bottom: 10px; }
.assign-stats span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--overlay-2);
  border: 1px solid var(--border-subtle);
  padding: 3px 10px;
  border-radius: 999px;
}
.assign-row { align-items: flex-start; padding: 9px 2px; }
.assign-row .name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.45; }
.assign-row .meta { line-height: 1.5; }
.assign-row .actions { padding-top: 3px; }
.invite-cand-row { align-items: flex-start; padding: 10px 12px; }
.invite-cand-row input[type="checkbox"] { margin-top: 2px; }
.ic-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.invite-cand-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.invite-cand-email {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-3);
  font-size: 11.5px;
  line-height: 1.4;
}
.ic-badge { flex-shrink: 0; align-self: flex-start; margin-left: 8px; padding-top: 1px; }
.expiry-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.expiry-hint { color: var(--text-4); font-size: 12px; line-height: 1.45; }
.sel-count { font-size: 12px; color: var(--text-4); margin-top: 6px; }

/* Phones: no fixed inner-scroll lists (content must scroll past the
   sticky footer), tighter vertical rhythm. */
@media (max-width: 600px) {
  .grid-invite { gap: 12px; }
  #inviteModal .assign-list,
  #candInviteModal .assign-list,
  #inviteModal .invite-cand-list,
  #candInviteModal .invite-cand-list {
    max-height: none;
    overflow: visible;
  }
}

/* ================= TOGGLE (access mode) ================= */
.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--overlay-2);
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  padding: 14px 16px;
}

.toggle-row .toggle-info strong {
  display: block;
  font-size: 13.5px;
  color: var(--text-1);
  font-weight: 500;
  margin-bottom: 2px;
}

.toggle-row .toggle-info span { font-size: 12px; color: var(--text-4); }

.switch { position: relative; display: inline-block; width: 40px; height: 22px; flex-shrink: 0; }

.switch input { opacity: 0; width: 0; height: 0; }

.switch .slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background: var(--surface-2);
  border-radius: 999px;
  transition: 0.2s;
}

.switch .slider::before {
  content: "";
  position: absolute;
  height: 16px;
  width: 16px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: 0.2s;
}

.switch input:checked + .slider { background: var(--brand); }
.switch input:checked + .slider::before { transform: translateX(18px); }

/* ================= SEGMENTED (IT / Non-IT exam type) ================= */
.segmented {
  display: flex;
  gap: 10px;
  margin-bottom: 2px;
}

.segmented-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
  min-height: 56px;
}

.segmented-btn:hover { border-color: var(--border-strong, var(--overlay-18)); }

.segmented-btn .segmented-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
  line-height: 1.2;
}

.segmented-btn .segmented-sub {
  font-size: 11.5px;
  color: var(--text-4);
  line-height: 1.3;
}

.segmented-btn.active {
  border-color: var(--brand);
  background: rgba(94, 106, 210, 0.12);
}

.segmented-btn.active .segmented-title { color: var(--brand); }
.segmented-btn.active .segmented-sub { color: var(--text-3); }

/* Question source segmented control (Kishan Aug 30 2026): the Manual
   option is greyed until the manual question editor ships. Disabled
   state: faded, dashed border, no hover lift, not-allowed cursor. */
.segmented-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  border-style: dashed;
  background: transparent;
}
.segmented-btn:disabled:hover { border-color: var(--border); }
.segmented-btn:disabled .segmented-title { color: var(--text-3); }
.segmented-btn:disabled .segmented-sub { color: var(--text-4); }

.upcoming-pill {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--brand);
  background: rgba(94, 106, 210, 0.14);
  border: 1px solid rgba(94, 106, 210, 0.28);
  border-radius: 999px;
  padding: 1px 7px;
  margin-left: 6px;
  vertical-align: 2px;
}

/* Blueprint match card (Layer 1, Aug 30 2026): the resolver suggestion
   shown in the create/edit exam form. Green-tinted to signal a
   confirmed mapping, with a compact action row that wraps on phones. */
.blueprint-match {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  border: 1px solid rgba(46, 204, 113, 0.35);
  background: rgba(46, 204, 113, 0.08);
  border-radius: 12px;
  padding: 12px 14px;
}

.blueprint-match-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-width: 0;
}

.blueprint-match-check {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(46, 204, 113, 0.18);
  color: #059669;
  font-size: 13px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}

.blueprint-match-title {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-1);
  line-height: 1.3;
}

.blueprint-match-meta {
  font-size: 11.5px;
  color: var(--text-3);
  line-height: 1.35;
  margin-top: 2px;
}

.blueprint-match-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

/* Paid-feature lock (Aug 30 2026): non-AI source options in an org
   WITHOUT the founder-enabled premium_sources flag. Adds a small lock
   glyph via ::after so org admins see the option is gated, not broken. */
.segmented-btn.paid-locked::after {
  content: '🔒';
  font-size: 11px;
  margin-left: auto;
  opacity: 0.75;
}

.segmented-btn.paid-locked .segmented-title {
  color: var(--text-3);
}

/* ================= MODAL ================= */
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  /* Above the mobile bottom nav (.sidebar z-index:200) - otherwise the
     nav covers the modal's submit buttons on phones (Kishan Aug 10:
     'cant add candidate' - buttons were hidden behind the dock). */
  z-index: 300;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  align-items: center;
  justify-content: center;
  padding: 20px;
  /* Stop scroll-chaining: when the modal's own scroll hits its edge,
     the page behind must NOT scroll (was causing 'jiggle' on mobile). */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* Modal scroll lock - while any modal is open, the body can't scroll
   behind it. html.modal-open is toggled by admin.js scrollLock(). */
html.modal-open,
html.modal-open body {
  overflow: hidden;
  height: 100%;
}

.modal-overlay.show { display: flex; }

.modal-lg { max-width: 720px; }

.modal {
  width: 100%;
  max-width: 520px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 24px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5);
  max-height: 90vh;
  overflow-y: auto;
}

/* Mobile (Kishan Aug 14): the notice/consent modal content is taller than
   a phone screen - the "I agree - start exam" button sat below the fold
   with no visible affordance. Pin the action row to the bottom of the
   modal viewport (sticky footer) so the primary action is ALWAYS visible
   while the rules scroll above it. Top-align + cap height so the modal
   never pushes off-screen. */
@media (max-width: 600px) {
  .modal-overlay {
    align-items: flex-start;
    overflow-y: auto;
    padding: 16px 12px;
  }
  .modal {
    max-height: 94vh;
    /* NOTE (Aug 26): NO padding-bottom here. Sticky bottom:0 pins the
       action bar to the CONTENT BOX bottom, so padding on the scroll
       container lifts the pinned bar that many px up the screen (it
       floated mid-card over the consent text). The bar is last in flow,
       so earlier content scrolls above it naturally. The 640px block
       below sets the real bottom padding. */
  }
  .modal .form-actions {
    position: sticky;
    bottom: 0;
    background: var(--panel);
    border-top: 1px solid var(--border-subtle);
    /* Mobile modal padding is 16px (desktop 24px): negative margins must
       match or the sticky bar overflows the viewport and clips the
       primary button (Kishan Aug 29 - Create exam button was cut off). */
    margin: 16px -16px 0;
    padding: 14px 16px;
  }
}

/* Candidate pre-exam notice (Kishan Sep 10 2026): on a phone the sticky
   footer floated over the consent card, so a candidate who pressed Start
   without ticking the box saw nothing happen - the "check the consent box"
   error was rendered in the card behind the button, and the checkbox itself
   was often scrolled out of view. Layout is now: stats, a compact scrollable
   rules block, the consent card (small, always visible), then the button in
   NORMAL FLOW below the consent. Nothing is pinned over anything. */
.notice-start-hint {
  display: none;
  margin: 10px 0 0;
  font-size: 12.5px;
  color: #dc2626;
  text-align: center;
}
.notice-start-hint.show { display: block; }

@media (max-width: 640px) {
  #noticeModal .modal {
    max-height: 92vh;
    padding: 16px;
  }
  /* Stats take a lot of height for two numbers - compact them so the rules,
     the consent and the button all fit above the fold. */
  #noticeModal .stat-card { padding: 8px 10px; }
  #noticeModal .stat-card-value { font-size: 18px !important; }
  /* The rules scroll inside their own box: the consent + button below stay
     put instead of being pushed off the screen by six bullets. */
  #noticeModal .notice-rules {
    max-height: 22vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    font-size: 12.5px;
    line-height: 1.5;
    margin-bottom: 10px;
    padding-right: 4px;
  }
  #noticeModal .notice-consent {
    padding: 12px;
    margin-bottom: 10px;
  }
  /* Kishan: "make it consent small scrollable and make fit on screen" - the
     explainer (plus the gaze note appended at runtime) scrolls in its own
     short box, so the consent card never grows taller than the screen. */
  #noticeModal .notice-consent-body {
    max-height: 20vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding-right: 4px;
    align-items: flex-start;
  }
  #noticeModal .notice-consent p { font-size: 12px; line-height: 1.45; margin-bottom: 4px !important; }
  #noticeModal .notice-consent-label {
    min-height: 44px;            /* real tap target, not a 13px line */
    font-size: 12.5px;
    align-items: center;
  }
  #noticeModal #webcamConsentCheck {
    width: 22px;
    height: 22px;
    flex: 0 0 22px;
    margin-top: 0;
  }
  #noticeModal .form-actions {
    position: static;            /* below the consent, never over it */
    margin: 0;
    padding: 0;
    border-top: 0;
    background: transparent;
  }
  #noticeModal #noticeStartBtn {
    width: 100%;
    min-height: 48px;
    font-size: 15px;
  }
  /* Attention cue when Start is pressed with the box unticked. */
  #noticeModal .notice-consent.flash {
    animation: noticeConsentFlash 600ms ease 3;
    border-color: #dc2626 !important;
  }
}

@keyframes noticeConsentFlash {
  0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
  50% { box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.45); }
}

/* Exam detail modal: spec grid collapses to ONE column on phones.
   Must be a class, NOT inline style - inline grid-template-columns
   beats the media query and leaves 2 cramped ~150px columns. */
.exam-detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 16px;
}
@media (max-width: 600px) {
  .exam-detail-grid { grid-template-columns: 1fr; gap: 8px; }
}

/* Preview AI questions row: allow the helper text to wrap under the
   button instead of overflowing the modal on narrow screens. */
.preview-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}

/* ---------- AI question preview list ---------- */
.preview-list {
  display: grid;
  gap: 12px;
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  font-size: 13.5px;
  color: var(--text-2);
  background: var(--panel);
}
/* On phones the exam-detail modal has a STICKY action bar (form-actions)
   pinned to the viewport bottom. A fixed 320px inner-scroll list here
   extends UNDER that bar and its answers slide behind the buttons.
   Fix: no inner scroll on phones - let the modal scroll everything, and
   the modal's own padding-bottom clears the sticky footer. (20260825) */
@media (max-width: 600px) {
  .preview-list { max-height: none; overflow-y: visible; }
}
.preview-list:empty { display: none; }

/* ================= PAST-PAPER REVIEW (Aug 31 2026) ================= */
.paper-q-card {
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  padding: 10px 12px;
  background: var(--overlay-2, rgba(255,255,255,0.03));
}
.paper-opt {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  padding: 5px 8px;
  cursor: pointer;
  transition: outline 0.15s ease;
}
.paper-opt:hover { border-color: var(--brand); }
.paper-opt .field-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  padding: 4px 2px;
}
.paper-opt .field-input:focus { outline: none; border: none; box-shadow: none; }
.preview-q {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  padding: 12px;
}
.preview-q-head {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 10px;
}
.preview-q-num {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: rgba(113, 112, 255, 0.14);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: center;
}
.preview-q-text {
  font-weight: 500;
  color: var(--text-1);
  line-height: 1.5;
}
.preview-opts {
  display: grid;
  gap: 6px;
  margin-left: 32px;
}
.preview-opt {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel);
  line-height: 1.45;
  font-size: 13px;
}
.preview-opt-letter {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-3);
  font-family: var(--mono);
  font-size: 10.5px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}
.preview-opt-correct {
  border-color: rgba(16, 185, 129, 0.45);
  background: rgba(16, 185, 129, 0.08);
}
.preview-opt-correct .preview-opt-letter {
  background: var(--green);
  color: #04120d;
  font-weight: 600;
}
.preview-opt-correct .preview-opt-text { color: var(--green); }
.preview-opt-check { margin-left: auto; flex-shrink: 0; color: var(--green); font-size: 12px; }
.preview-status { color: var(--text-3); }
.preview-status-error { color: var(--red); }

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}

.modal-head h3 { font-size: 17px; font-weight: 500; color: var(--text-1); letter-spacing: -0.01em; }

.modal-close {
  background: none;
  border: none;
  color: var(--text-4);
  font-size: 20px;
  cursor: pointer;
  line-height: 1;
  padding: 4px;
}

.modal-close:hover { color: var(--text-1); }

/* Shared modal form primitives (superadmin + assign-org modal).
   These were used unstyled - now part of the app's dark design system. */
.modal-body { padding: 0; }
.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--border-subtle);
}
.field-label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-3);
  margin-bottom: 6px;
}
.field-input {
  width: 100%;
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-1);
  background: var(--overlay-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.field-input::placeholder { color: var(--text-3); opacity: 1; }
.field-input:hover { border-color: var(--overlay-16); }
.field-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(113, 112, 255, 0.15);
}
select.field-input {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8f98' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 14px;
  padding-right: 36px;
  cursor: pointer;
}
select.field-input option { background: var(--bg-2); color: var(--text-1); }

/* ================= INVITE LINK BOX ================= */
.invite-box {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--overlay-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  margin-top: 10px;
}

.invite-box code {
  flex: 1;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--accent-hover);
  word-break: break-all;
}

.copy-btn {
  background: rgba(113, 112, 255, 0.12);
  color: var(--accent-hover);
  border: none;
  border-radius: 5px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  font-family: var(--font);
  white-space: nowrap;
}

.copy-btn:hover { background: rgba(113, 112, 255, 0.22); }

.copy-btn.copied { background: rgba(16, 185, 129, 0.15); color: #34d399; }

/* ================= ALERTS ================= */
.alert {
  display: none;
  padding: 12px 16px;
  border-radius: 6px;
  font-size: 13px;
  margin-bottom: 16px;
}

.alert.show { display: block; }

/* When a modal is open (z-index 300 overlay covers the viewport), the
   in-flow #pageAlert renders BEHIND it - errors looked like "nothing
   happened" (live: 409 duplicate-exam-title, Aug 26 2026). Float the
   alert above the overlay as a centered toast instead. */
body:has(.modal-overlay.show) .alert.show {
  position: fixed;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 500;
  max-width: calc(100vw - 32px);
  width: max-content;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  border-radius: 10px;
}

.alert-error { background: rgba(248, 113, 113, 0.08); border: 1px solid rgba(248, 113, 113, 0.3); color: #fca5a5; }
.alert-success { background: rgba(16, 185, 129, 0.08); border: 1px solid rgba(16, 185, 129, 0.3); color: #6ee7b7; }

/* ================= EXAM (candidate side) ================= */
.exam-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  max-width: 860px;
  margin: 0 auto;
  padding: 24px 24px 60px;
  position: relative;
  z-index: 1;
}

.exam-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0 18px;
  border-bottom: 1px solid var(--border-subtle);
  margin-bottom: 24px;
}

/* Mobile (Kishan Aug 14): brand + badges must wrap instead of clipping
   off-screen - "📹 Video monitoring" badge overflowed the viewport on
   iPhone (390px). Allow wrap + let badges shrink gracefully. */
@media (max-width: 600px) {
  .exam-topbar {
    flex-wrap: wrap;
    gap: 8px 12px;
    padding: 12px 0 14px;
  }
  .exam-topbar .badge {
    white-space: nowrap;
  }
}

.exam-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

.exam-brand-mark {
  width: 28px;
  height: 28px;
  border-radius: 7px;
  background: linear-gradient(135deg, var(--brand), var(--accent));
  display: flex;
  align-items: center;
  justify-content: center;
}

.exam-brand-mark svg { width: 15px; height: 15px; }

/* Phase 4 white-label: org logo inside the candidate-facing brand slot. */
.exam-brand-logo {
  width: 26px;
  height: 26px;
  border-radius: 6px;
  object-fit: cover;
  display: block;
}

.exam-brand-text { color: var(--text-1); font-size: 14px; font-weight: 500; }
.exam-brand-text span { color: var(--accent); }

.exam-timer {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 15px;
  color: var(--text-1);
  background: var(--overlay-3);
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  padding: 8px 16px;
}

.exam-timer.warning { color: var(--red); border-color: rgba(248, 113, 113, 0.4); }

.exam-timer svg { width: 15px; height: 15px; opacity: 0.8; }

.exam-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
}

.exam-progress .bar {
  flex: 1;
  height: 4px;
  background: var(--border-subtle);
  border-radius: 999px;
  overflow: hidden;
}

.exam-progress .bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--brand), var(--accent));
  border-radius: 999px;
  transition: width 0.3s ease;
}

.exam-progress span { font-size: 12px; color: var(--text-4); font-family: var(--mono); white-space: nowrap; }

.exam-question {
  background: var(--panel);
  border: 1px solid var(--border-subtle);
  border-radius: 12px;
  padding: 28px;
  margin-bottom: 20px;
}

.exam-question .q-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.exam-question h2 {
  font-size: 18px;
  font-weight: 500;
  color: var(--text-1);
  letter-spacing: -0.015em;
  line-height: 1.5;
  margin-bottom: 22px;
}

.options { display: flex; flex-direction: column; gap: 10px; }

.option {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  background: var(--overlay-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s ease;
  font-size: 14.5px;
  color: var(--text-2);
}

.option:hover { border-color: rgba(113, 112, 255, 0.4); background: rgba(113, 112, 255, 0.04); }

.option .opt-letter {
  width: 26px;
  height: 26px;
  border-radius: 6px;
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-3);
  flex-shrink: 0;
  transition: all 0.15s ease;
}

.option.selected {
  border-color: var(--accent);
  background: rgba(113, 112, 255, 0.08);
}

.option.selected .opt-letter {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

.exam-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 8px;
}

.palette {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 24px;
}

.palette .q-pill {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--overlay-2);
  color: var(--text-3);
  font-family: var(--mono);
  font-size: 12px;
  cursor: pointer;
  transition: all 0.12s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.palette .q-pill.current { border-color: var(--accent); color: var(--accent-hover); background: rgba(113, 112, 255, 0.1); }
.palette .q-pill.answered { background: var(--brand); border-color: var(--brand); color: #fff; }
.palette .q-pill:hover { transform: translateY(-1px); }

/* ================= RESPONSIVE ================= */
/* Tablet: sidebar becomes a top bar */
@media (max-width: 1024px) {
  .main { padding: 28px 24px 60px; }
  .admin-shell { flex-direction: column; }
  .sidebar {
    width: 100%; height: auto; position: sticky; top: 0; z-index: 50;
    flex-direction: row; flex-wrap: wrap; align-items: center;
    padding: 10px 16px; gap: 2px; border-right: none;
    border-bottom: 1px solid var(--border-subtle);
  }
  .sidebar-brand { border-bottom: none; margin-bottom: 0; padding: 0 12px 0 0; }
  /* Tenant strip becomes a compact pill in the top bar (Phase 4) */
  .tenant-strip {
    flex-direction: row;
    align-items: center;
    gap: 8px;
    margin: 0 8px 0 0;
    padding: 4px 10px;
    border-radius: 999px;
    order: 2;
  }
  .tenant-label { display: none; }
  .tenant-logo { width: 16px; height: 16px; border-radius: 4px; }
  .tenant-name { font-size: 12px; }
  .sidebar-label { display: none; }
  .sidebar-link { padding: 9px 12px; }
  /* Keep the account row reachable here: this range hides the sidebar
     labels, not the sign-out. Hiding the whole footer left tablets and
     phones with no way to log out (the mobile bottom bar shows tabs
     only). Phones hide the footer below and carry sign-out in the
     More sheet instead. */
  .sidebar-footer { display: block; padding: 10px 10px 0; }
  .admin-profile { padding: 6px 8px; gap: 8px; }
  .admin-profile-meta { display: none; }
  .admin-profile-more { margin-left: auto; min-width: 40px; min-height: 40px; justify-content: center; }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .exam-question { padding: 20px; }
  /* Wide tables scroll inside their panel instead of overflowing the
     viewport (exams/results tables are 7+ cols - at 768px they were
     pushing the page to 818-937px, Kishan Aug 10 responsiveness pass). */
  .panel { min-width: 0; }
  .tbl { display: block; overflow-x: auto; }
  /* Tablets are touch devices - row actions need a taller tap area
     (phone breakpoint below takes them to 44px). */
  .tbl tbody td .btn, .table tbody td .btn { min-height: 40px; padding: 9px 12px; }
  .page-head > .btn, .panel-head .btn, .page-actions .btn { min-height: 40px; display: inline-flex; align-items: center; }
}

/* Phone: bottom tab bar + card tables + bottom-sheet modals */
@media (max-width: 640px) {
  /* ---- Bottom tab navigation ---- */
  .admin-shell { flex-direction: column; }
  .sidebar {
    position: fixed;
    bottom: 0; left: 0; right: 0; top: auto;
    width: 100%;
    height: auto;
    z-index: 200;
    flex-direction: row;
    justify-content: space-around;
    align-items: stretch;
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
    gap: 2px;
    border-right: none;
    border-top: 1px solid var(--border);
    background: rgba(15, 16, 17, 0.97);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
  .sidebar-brand, .sidebar-label { display: none; }
  /* Short "Console" label in the bottom tab bar (long one wraps) */
  .sidebar-link .nav-label-long { display: none; }
  .sidebar-link .nav-label-short { display: inline; }
  /* Tenant strip moves out of the bottom tab bar - phones see the org
     name in the page header instead (org-badge injected by admin.js). */
  .tenant-strip { display: none; }
  .org-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    margin-top: 8px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--accent-soft, rgba(113, 112, 255, 0.12));
    color: var(--text-2);
    font-size: 12px;
    font-weight: 500;
  }
  .org-badge img { width: 14px; height: 14px; border-radius: 3px; object-fit: contain; }
  .org-badge span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .sidebar-link {
    flex: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 7px 2px;
    font-size: 10.5px;
    border-radius: 8px;
    text-align: center;
    min-width: 0;
  }
  .sidebar-link svg { width: 20px; height: 20px; opacity: 0.85; }
  .sidebar-footer { display: none; }
  .main {
    padding: 20px 14px calc(104px + env(safe-area-inset-bottom, 0px));
    max-width: 100%;
  }

  /* ---- Page head stacks ---- */
  .page-head { flex-direction: column; align-items: flex-start; gap: 12px; }
  .page-head h1 { font-size: 21px; }
  .page-actions { width: 100%; flex-wrap: wrap; }
  .page-actions .btn,
  .page-head > .btn { flex: 1; justify-content: center; padding: 12px 14px; min-height: 44px; width: 100%; }

  /* ---- IT / Non-IT segmented toggle: full-width stacked cards ---- */
  .segmented { flex-direction: column; }
  .segmented-btn { min-height: 52px; padding: 12px 14px; }
  /* Panel-head action links ("View flagged", "View all"…) must also be
     tappable on phones - btn-sm is 33px tall, below the 44px HIG. */
  .panel-head .btn { min-height: 40px; display: inline-flex; align-items: center; padding: 10px 14px; }

  /* ---- Stat cards: 2-col compact ---- */
  .stat-grid { grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px; }
  .stat-card { padding: 16px 14px; }
  .stat-card-value { font-size: 24px; }

  /* ---- Tables → stacked cards ---- */
  .table-wrap { overflow: visible; }
  .tbl, .table { border-collapse: collapse; }
  .tbl thead, .table thead { display: none; }
  .tbl tbody, .table tbody { display: block; }
  .tbl tbody tr, .table tbody tr {
    display: block;
    background: var(--panel);
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
    margin-bottom: 10px;
    padding: 6px 14px;
  }
  .tbl tbody td, .table tbody td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid rgba(255,255,255,0.04);
    text-align: right;
    white-space: normal;
  }
  .tbl tbody tr:last-child td, .table tbody tr:last-child td { border-bottom: 1px solid rgba(255,255,255,0.04); }
  .tbl tbody tr:last-child td:last-child, .table tbody tr:last-child td:last-child { border-bottom: none; }
  .tbl tbody td:last-child, .table tbody td:last-child { border-bottom: none; }
  .tbl tbody td::before, .table tbody td::before {
    content: attr(data-label);
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-4);
    font-weight: 500;
    text-align: left;
    flex-shrink: 0;
    padding-right: 10px;
  }
  .tbl tbody td[data-label=""]::before, .table tbody td[data-label=""]::before { display: none; }
  /* Action cell: buttons side by side, full width */
  .tbl tbody td:last-child, .table tbody td:last-child {
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 8px;
  }
  /* Action buttons size to content - the generic first-child flex:1
     would stretch the first action (e.g. "Invite") across the row. */
  .tbl tbody td:last-child > *:first-child, .table tbody td:last-child > *:first-child {
    flex: 0 0 auto;
  }
  .tbl tbody td .btn, .table tbody td .btn {
    padding: 12px 14px; font-size: 12.5px;
    min-height: 44px;          /* touch target - Apple/Google HIG */
    display: inline-flex; align-items: center; justify-content: center;
  }
  .tbl tbody td:first-child, .table tbody td:first-child { text-align: right; }
  /* Long unbroken values (emails, hashes) must wrap inside the card,
     not stretch the row past the screen (Kishan Aug 15 mobile pass).
     Use break-word (NOT anywhere): anywhere lets flex items shrink to
     near-zero and mid-word-breaks short names like "Aashita". */
  .tbl tbody td, .table tbody td { overflow-wrap: break-word; }
  /* EVERY child must be allowed to shrink below its min-content, or a long
     second child (email, category, code) with default min-width:auto eats
     the whole row and crushes the first child to ~0px - "GPSC" renders as
     G/P/S/C letter-by-letter, "Aashita" splits vertically (Aug 16 mobile
     pass). flex:1 goes to the FIRST child (the primary value); the rest
     wrap normally. */
  .tbl tbody td > *, .table tbody td > * { min-width: 0; }
  .tbl tbody td > *:first-child, .table tbody td > *:first-child { flex: 1; }
  .tbl .table-empty, .table .table-empty { text-align: center !important; justify-content: center; }
  .tbl .table-empty::before, .table .table-empty::before { display: none !important; }

  /* ---- Modals → bottom sheets ---- */
  .modal-overlay { padding: 0; align-items: flex-end; }
  /* While a modal is open the bottom dock is covered by the overlay
     (z 300 > 200); hide it outright so it can never sit over buttons. */
  html.modal-open .sidebar { display: none; }
  .modal {
    max-width: 100%;
    width: 100%;
    border-radius: 16px 16px 0 0;
    max-height: 92vh;
    padding: 20px 16px calc(28px + env(safe-area-inset-bottom, 0px));
  }
  /* The exam notice/consent modal has a STICKY footer (600px block above).
     NOTE (Aug 26): NO padding-bottom override here. The old 200px padding
     lifted the pinned "I agree - start exam" bar 200px up the screen
     (sticky bottom:0 resolves against the content box, so padding on the
     scroll container moves the bar, not the content) - it floated mid-card
     over the consent text with the checkbox below it. The bar sits LAST in
     flow, so the consent checkbox scrolls above it naturally with the
     normal bottom-sheet padding. */
  .modal-lg { max-width: 100%; }
  .modal-head { margin-bottom: 14px; }
  .modal-head h3 { font-size: 16px; }
  .modal-body .btn, .modal .btn { min-height: 44px; }
  .modal .form-grid { gap: 12px; }

  /* ---- Panels / forms ---- */
  .panel-head { padding: 14px 16px; }
  .panel-body { padding: 16px; }
  .invite-form { flex-direction: column; align-items: stretch; }
  .invite-form .invite-email,
  .invite-form .invite-role,
  .invite-form .invite-org { width: 100%; flex: none; }
  .invite-form input, .invite-form select { min-height: 44px; font-size: 16px; }
  /* Stacked layout: hints flow normally below the field again */
  .invite-org .field-hint,
  .invite-role .field-hint { position: static; margin-top: 6px; }
  .invite-form .btn { justify-content: center; min-height: 44px; }
  .form-grid { gap: 12px; }
  .form-grid input, .form-grid select, .form-grid textarea { font-size: 16px; }

  /* ---- Filters row ---- */
  .filter-row, [class*="filter"] { flex-wrap: wrap; }
  .filter-row select, [class*="filter"] select { flex: 1; min-width: 120px; }

  /* ---- Dashboard panels ---- */
  .sec-log-row { flex-wrap: wrap; gap: 4px; }
  .sec-log-row .log-time { margin-left: auto; }
}

/* ============================================================
   Admin Team page (admins + invites) - Aug 5 2026
   ============================================================ */
.panel-title { font-size: 14px; font-weight: 600; color: var(--text-1); margin: 0 0 16px; }

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-3); font-weight: 500; padding: 10px 12px; border-bottom: 1px solid rgba(255,255,255,.06); white-space: nowrap; }
.table td { padding: 12px; border-bottom: 1px solid rgba(255,255,255,.04); color: var(--text-2); vertical-align: middle; }
.table tr:last-child td { border-bottom: none; }
.table-empty { text-align: center; color: var(--text-3); padding: 24px !important; }

.cell-user { display: flex; align-items: center; gap: 10px; }
.cell-avatar { width: 30px; height: 30px; border-radius: 8px; background: rgba(113,112,255,.14); color: var(--accent-hover); display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 13px; flex-shrink: 0; }
.cell-user strong { display: block; color: var(--text-1); font-weight: 500; }
.cell-sub { display: block; color: var(--text-3); font-size: 12px; margin-top: 1px; }
.cell-muted { color: var(--text-3); font-size: 12.5px; }

.badge-accent { background: rgba(113,112,255,.14); color: var(--accent-hover); }

.invite-form { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
.invite-form .field-group { margin-bottom: 0; min-width: 0; }
.invite-email { flex: 1; }
.invite-role { width: 240px; position: relative; }
.invite-org { width: 220px; position: relative; }
/* Desktop-only (row layout): the hints must NOT affect the flex row's
   height - with align-items: flex-end an in-flow hint would push the
   email input below its siblings (its bottom edge aligns to the hint's
   bottom). Absolute positions each hint under its field so every
   control stays on one baseline. On <=1024px the form stacks and the
   hints flow normally (static reset lives in that media query). */
@media (min-width: 1025px) {
  .invite-org .field-hint,
  .invite-role .field-hint {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    margin-top: 0;
  }
}
.invite-form label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-3);
  margin-bottom: 6px;
}

/* ============================================================
   Admin Team page (admins + invites) - Aug 5 2026
   ============================================================ */
.invite-form input,
.invite-form select {
  width: 100%;
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-1);
  background: var(--overlay-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.invite-form input::placeholder { color: var(--text-3); opacity: 1; }
.invite-form input:hover, .invite-form select:hover { border-color: rgba(255,255,255,0.16); }
.invite-form input:focus, .invite-form select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(113, 112, 255, 0.15);
}
.invite-form select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8f98' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 14px;
  padding-right: 36px;
  cursor: pointer;
}
.invite-form select option { background: var(--bg-2); color: var(--text-1); }
.invite-form .btn { height: 40px; white-space: nowrap; }

/* ============ Admin Results (TestGorilla style, Aug 6 2026) ============ */
.qblock {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  margin-bottom: 12px;
  background: var(--overlay-1);
}
.qnum {
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--overlay-6);
  color: var(--text-2);
  font-size: 12px; font-weight: 500;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0; margin-top: 1px;
}
.qopt {
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 6px;
  font-size: 13px;
  color: var(--text-2);
  background: var(--overlay-1);
}
.qopt-right {
  border-color: rgba(16, 185, 129, 0.45);
  background: rgba(16, 185, 129, 0.07);
  color: #6ee7b7;
}
.qopt-wrong {
  border-color: rgba(239, 68, 68, 0.45);
  background: rgba(239, 68, 68, 0.07);
  color: #fca5a5;
}
.qopt-tag {
  font-size: 10.5px;
  color: var(--text-4);
  font-weight: 500;
  margin-left: 4px;
}

/* ============================================================
   WHITE ADMIN THEME (body.light) - Aug 29 2026
   Kishan: admin panels on white with clean light lines. The
   candidate exam pages (exam.html / result.html / exam-landing.html)
   keep the dark theme - only pages that add class="light" to <body>
   flip. Overlay variables keep every translucent fill readable.
   ============================================================ */
body.light {
  --bg: #f6f7f9;
  --panel: #ffffff;
  --surface: #f0f2f5;
  --surface-2: #e8ebf0;
  --text-1: #17181c;
  --text-2: #3f4450;
  --text-3: #6b7180;
  --text-4: #9aa1ad;
  --border-subtle: rgba(23, 24, 28, 0.06);
  --border: rgba(23, 24, 28, 0.10);
  --green: #059669;
  --amber: #b45309;
  --red: #dc2626;
  --accent-hover: #5a5fe0;  /* darker purple for contrast on white */
  /* Flip translucent overlays: dark-on-light instead of white-on-dark */
  --overlay-1: rgba(23, 24, 28, 0.03);
  --overlay-2: rgba(23, 24, 28, 0.04);
  --overlay-3: rgba(23, 24, 28, 0.05);
  --overlay-4: rgba(23, 24, 28, 0.06);
  --overlay-5: rgba(23, 24, 28, 0.07);
  --overlay-6: rgba(23, 24, 28, 0.08);
  --overlay-8: rgba(23, 24, 28, 0.10);
  --overlay-16: rgba(23, 24, 28, 0.16);
  --overlay-18: rgba(23, 24, 28, 0.18);
  --dropdown: #ffffff;
}

/* Sidebar brand glow - softer on white so the mark does not bloom */
body.light .sidebar-brand-mark { box-shadow: 0 0 14px rgba(94, 106, 210, 0.28); }

/* Modal scrim: black works on both themes; keep it slightly lighter so
   white panels pop cleanly against it */
body.light .modal-overlay { background: rgba(15, 18, 24, 0.45); }

/* Question review chips: light green/red text is unreadable on white */
body.light .qopt-right { color: #047857; background: rgba(16, 185, 129, 0.08); }
body.light .qopt-wrong { color: #b91c1c; background: rgba(239, 68, 68, 0.08); }
body.light .qopt-right .qopt-tag, body.light .qopt-wrong .qopt-tag { color: var(--text-3); }

/* Selection color stays readable on white */
body.light ::selection { background: rgba(113, 112, 255, 0.18); color: #17181c; }

/* Sidebar active link keeps its accent identity on white - accent-hover
   is darkened in the body.light vars above so the purple stays readable */
body.light .sidebar-link.active { color: var(--accent-hover); }

/* Stat cards / badges: darker accent text for contrast on white */
body.light .stat-card-value { color: var(--text-1); }
body.light .badge-green { color: #047857; }
body.light .badge-amber { color: #b45309; }
body.light .badge-red { color: #b91c1c; }

/* Empty-state circles (green tint) - darker border on white */
body.light .panel .badge-dot { box-shadow: none; }


/* Exam details modal - tabbed body (Kishan Sep 5 2026). A Manual bank
   can hold 190+ rows; tabs keep the modal fast to read and the
   Publish/Edit/Delete toolbar pinned so it never scrolls away, on any
   screen. Scoped to .exam-modal - every other modal is untouched. */
.modal.exam-modal {
  max-width: 940px;
  padding: 0;
  display: flex;
  flex-direction: column;
  height: min(90vh, 880px);
  overflow: hidden;
}
.exam-modal .modal-head {
  flex: none;
  margin: 0;
  padding: 16px 22px 12px;
}
.exam-actions {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
  padding: 12px 22px;
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  background: rgba(255, 255, 255, 0.02);
}
.actions-left, .actions-right { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.exam-tabs {
  flex: none;
  display: none;
  gap: 2px;
  padding: 0 22px;
  border-bottom: 1px solid var(--border-subtle);
  overflow-x: auto;
  scrollbar-width: thin;
}
.exam-tab {
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  color: var(--text-3);
  font: inherit;
  font-size: 13.5px;
  padding: 11px 14px 10px;
  white-space: nowrap;
}
.exam-tab:hover { color: var(--text-1); }
.exam-tab.active {
  color: var(--text-1);
  border-bottom-color: var(--brand, #5e6ad2);
  font-weight: 600;
}
.exam-tab .tab-count {
  margin-left: 6px;
  font-size: 11px;
  color: var(--text-3);
  background: rgba(255, 255, 255, 0.07);
  padding: 1px 7px;
  border-radius: 999px;
}
.tab-count:empty { display: none; }
.exam-panels {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 16px 22px 22px;
  min-height: 0;
}
.exam-panel[hidden] { display: none; }

/* The toolbar Close button exists for phones where the iOS URL bar can
   cover the header X - hidden on desktop which has the header X. */
@media (min-width: 601px) {
  .exam-close-btn { display: none; }
}

@media (max-width: 600px) {
  /* iOS Safari's floating URL pill overlays the top ~90px of fixed
     content, hiding the modal header. Push the exam modal below it and
     cap its height so nothing is clipped (Kishan Sep 5 2026). */
  .modal-overlay:has(.exam-modal) {
    padding-top: 96px;
    align-items: flex-start;
  }
  .modal.exam-modal {
    height: calc(100dvh - 118px);
    max-width: 100vw;
    border-radius: 12px;
  }
  .exam-modal .modal-head { padding: 14px 14px 10px; }
  .exam-actions { padding: 10px 14px; }
  .exam-tabs { padding: 0 6px; }
  .exam-tab { padding: 10px 12px 9px; }
  .exam-panels { padding: 12px 14px 16px; }
}

/* Admins page - mobile card polish (Kishan Sep 6 2026). Scoped to
   .admins-page: the first column (name/avatar or email) becomes the
   card header; the rest stay compact label/value rows. No other page
   is affected by these rules. */
@media (max-width: 640px) {
  .admins-page .invite-form { gap: 10px; }
  .admins-page .invite-form .btn { margin-top: 2px; }

  /* Card = one admin/invite; inner padding lives on the cells. */
  .admins-page .table tbody tr { padding: 0; overflow: hidden; }
  .admins-page .table tbody td { padding: 9px 14px; }
  .admins-page .table tbody td:first-child:not(.table-empty) {
    justify-content: flex-start;
    gap: 12px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--border-subtle);
  }
  /* No mini "ADMIN / EMAIL" label on the header row - the value is
     big enough to speak for itself. */
  .admins-page .table tbody td:first-child:not(.table-empty)::before { display: none; }
  .admins-page .cell-avatar { width: 38px; height: 38px; border-radius: 10px; font-size: 15px; }
  .admins-page .cell-user strong { font-size: 13.5px; }
  .admins-page .cell-sub { font-size: 11.5px; overflow-wrap: anywhere; }
  .admins-page .table tbody td:last-child { border-bottom: none; }
  /* Value rows keep the label:value split; values align right. */
  .admins-page .table tbody td:not(:first-child):not(:last-child) {
    justify-content: space-between;
  }
  .admins-page .table tbody td > * { min-width: 0; }
  /* Email header cell (pending invites): readable + breakable. */
  .admins-page .table tbody td:first-child strong { overflow-wrap: anywhere; }
}

/* ============================================================
   Phase B (Sep 2026): results leaderboard history + performance
   ============================================================ */
.results-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.att-subrow > td { background: var(--surface); }
.att-subrow > td::after { content: ''; display: block; height: 1px; margin: 0 18px; background: var(--border); }
.att-history { padding: 14px 18px 16px; }
.att-history-head { font-size: 12.5px; font-weight: 600; color: var(--text-1); margin-bottom: 10px; }
table.tbl.tbl-inner { border: 1px solid var(--border); border-radius: 10px; }
.tbl-inner th { font-size: 11px; padding: 8px 12px; }
.tbl-inner td { font-size: 12.5px; padding: 8px 12px; }
.att-history-note { font-size: 11.5px; color: var(--text-4); margin-top: 10px; }

/* Performance page: candidate row = a tap target that opens history. */
.perf-name { font-weight: 600; color: var(--accent-hover, var(--accent)); cursor: pointer; }
.perf-name:hover { text-decoration: underline; }
.perf-exam-trend { display: flex; align-items: center; gap: 10px; }

/* Big per-exam score-trend chart (Sep 7 2026) - replaces the tiny header
   sparkline on the candidate Performance detail. Card sits under the
   attempt table; svg scales fluidly (viewBox 760x250). */
.perf-trend { margin-top: 4px; }
.perf-trend-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin: 18px 2px 6px;
  padding-top: 14px;
  border-top: 1px solid var(--border-subtle);
}
.perf-trend-head span:first-child {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-trend-head span:last-child { font-size: 11px; color: var(--text-4); }
.perf-chart { width: 100%; height: auto; display: block; }

@media (max-width: 640px) {
  .att-history { padding: 12px; }
  .att-history .btn-sm, .res-row .btn-sm { min-height: 40px; }
}

/* Admin roles (Sep 7 2026): read_only tier */
.role-select {
  font-size: 12px;
  padding: 2px 6px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-1);
  border: 1px solid rgba(255, 255, 255, 0.14);
  max-width: 130px;
}
.badge-readonly {
  background: rgba(148, 163, 184, 0.16);
  color: var(--text-3);
}

/* Read-only admin mode (Sep 2026): body.read-only (set by admin.js from
   the session role) hides every WRITE control across all admin pages.
   Blanket danger/primary + method-driven selectors cover buttons created
   in JS templates; read actions (Details/View/History/bank contents)
   stay visible. Purely presentational - the backend enforces read_only
   with 403 regardless, so members never see dead write buttons. */
body.read-only .btn-primary,
body.read-only .btn-danger { display: none !important; }
body.read-only [onclick*="openCreate"],
body.read-only [onclick*="openEdit"],
body.read-only [onclick*="openInvite"],
body.read-only [onclick*="openQuestion"],
body.read-only [onclick*="openScanReview"],
body.read-only [onclick*="openPaperReview"],
body.read-only [onclick*="regenerateBank"],
body.read-only [onclick*="preview"],
body.read-only [onclick*="publish"],
body.read-only [onclick*="unpublish"],
body.read-only [onclick*="delete"],
body.read-only [onclick*="revoke"],
body.read-only [onclick*="resend"],
body.read-only [onclick*="sendInvites"],
body.read-only [onclick*="fetchPaper"],
body.read-only [onclick*="verifyPaper"],
body.read-only [onclick*="pickScanDoc"],
body.read-only [onclick*="approveScan"],
body.read-only [onclick*="cancelScan"],
body.read-only [onclick*="suggestAllScanAnswers"],
body.read-only [onclick*="webVerifyScanAnswers"],
body.read-only [onclick*="suggestScanAnswer"],
body.read-only [onclick*="saveScanQuestion"],
body.read-only [onclick*="setPaperAnswer"],
body.read-only [onclick*="useBlueprint"],
body.read-only [onclick*="ignoreBlueprint"],
body.read-only [onclick*="uploadCsv"],
body.read-only [onclick*="openModal('candidateModal')"],
body.read-only [onclick*="openModal('csvModal')"],
body.read-only [onclick*="openModal('candInviteModal')"],
body.read-only [onclick*="openModal('inviteModal')"],
body.read-only [onclick*="openModal('examModal')"],
body.read-only [onclick*="openModal('questionModal')"],
body.read-only [onclick*="openModal('scanModal')"],
body.read-only [onclick*="openModal('paperReviewModal')"],
body.read-only [onclick*="openModal('assignOrgModal')"],
body.read-only [onclick*="openModal('newOrgModal')"],
body.read-only [onclick*="openModal('deleteOrgModal')"] { display: none !important; }
body.read-only #previewWrap { display: none !important; }
/* Write-modals themselves (defense in depth for the few reachable via
   keyboard/shortcut): read views (detailModal, examDetailModal) stay. */
body.read-only #csvModal,
body.read-only #candInviteModal,
body.read-only #inviteModal,
body.read-only #examModal,
body.read-only #questionModal,
body.read-only #scanModal,
body.read-only #paperReviewModal,
body.read-only #assignOrgModal,
body.read-only #newOrgModal,
body.read-only #deleteOrgModal { display: none !important; }

.ro-banner {
  background: var(--overlay-2);
  border: 1px dashed var(--border);
  color: var(--text-2);
  font-size: 13px;
  padding: 8px 14px;
  border-radius: 10px;
  margin-bottom: 18px;
}

/* ---- Mobile "More" sheet (Sep 9 2026) -----------------------------------
   Phones get 5 bottom tabs (Home, Exams, Candidates, Results, More); the
   secondary admin destinations open in a slide-up sheet. Before this the
   bar rendered all 8 links in one row - labels collided ("Candidates"
   over "Performance") and "Custom domain" wrapped to two lines. Desktop
   and tablet are untouched: the button + sheet are display:none above
   640px and the normal sidebar is used. */
.nav-more-btn,
.nav-sheet,
.nav-sheet-backdrop { display: none; }

@media (max-width: 640px) {
  /* Bottom bar shows the 5 tabs only - everything else moves to the sheet */
  .sidebar-link { display: none; }
  .sidebar-link.nav-tab { display: flex; }
  .nav-more-btn { display: flex; }

  /* NOTE: [hidden] must win. The UA rule is `[hidden]{display:none}`,
     but any author `display:block` overrides it - which made the
     invisible backdrop a full-screen tap blocker (Sep 9 2026: nothing
     on the page was clickable on phones). Scope to :not([hidden]). */
  .nav-sheet-backdrop:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 410;
    background: rgba(8, 9, 10, 0.5);
    opacity: 0;
    transition: opacity 0.22s ease;
  }
  .nav-sheet-backdrop.open { opacity: 1; }

  .nav-sheet:not([hidden]) {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 420;
    max-height: 76vh;
    overflow-y: auto;
    background: var(--panel);
    border-top: 1px solid var(--border);
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -18px 44px rgba(8, 9, 10, 0.35);
    padding: 8px 12px calc(14px + env(safe-area-inset-bottom, 0px));
    transform: translateY(105%);
    transition: transform 0.26s cubic-bezier(0.22, 0.8, 0.3, 1);
  }
  .nav-sheet.open { transform: translateY(0); }
  .nav-sheet:focus { outline: none; }

  .nav-sheet-handle {
    width: 44px;
    height: 4px;
    border-radius: 999px;
    background: var(--overlay-18);
    margin: 4px auto 12px;
  }
  .nav-sheet-title {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-3);
    padding: 0 10px 8px;
  }
  .nav-sheet-list { display: flex; flex-direction: column; gap: 2px; }

  .nav-sheet-row {
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: 52px;
    padding: 8px 10px;
    border-radius: 12px;
    color: var(--text-1);
    text-decoration: none;
    font-size: 15px;
    font-weight: 500;
  }
  .nav-sheet-row:hover,
  .nav-sheet-row:focus-visible { background: var(--overlay-3); }
  .nav-sheet-row:focus { outline: none; }
  .nav-sheet-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
  .nav-sheet-row.active {
    background: rgba(113, 112, 255, 0.12);
    color: var(--accent-hover);
  }
  .nav-sheet-row svg:not(.nav-sheet-chev) {
    width: 20px;
    height: 20px;
    opacity: 0.85;
    flex-shrink: 0;
  }
  /* Sign out sits apart from the navigation rows: it ends the session
     rather than navigating deeper, so it takes no chevron. */
  .nav-sheet-row.nav-sheet-signout {
    margin-top: 8px;
    border-top: 1px solid var(--border-subtle);
    padding-top: 14px;
  }
  .nav-sheet-row .nav-sheet-chev {
    width: 18px;
    height: 18px;
    margin-left: auto;
    opacity: 0.35;
    flex-shrink: 0;
  }
}

/* ---------- Scan list rows (Sep 10 2026) ----------
   Reported on a phone: with two actions on one line, a long file name was
   clipped mid-word (the flex child could not shrink) and the row buttons
   were 31px chips. The name now ellipsizes and, on phones, the actions drop
   onto their own full-width line as 40px tap targets. */
.scan-row { display:flex; align-items:center; justify-content:space-between; gap:8px; font-size:12.5px; }
.scan-row-name { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.scan-row-actions { flex:0 0 auto; display:flex; gap:6px; }

@media (max-width: 640px) {
  .scan-row { flex-wrap:wrap; row-gap:8px; }
  .scan-row-name { flex:1 1 100%; }
  .scan-row-actions { flex:1 1 100%; justify-content:flex-end; }
  .scan-row .btn { min-height:40px; padding:8px 14px; }
}

@media (max-width: 640px) {
  /* Scan modal (Sep 10 2026): as a bottom sheet it can grow up into the
     zone iOS Safari's floating URL pill covers, hiding the "Scan a
     document" head and its close button. Reserve that space up front.
     Scoped to this modal - other sheets keep their layout. */
  #scanModal { padding-top: calc(92px + env(safe-area-inset-top)); }
  #scanModal .modal {
    max-height: calc(100vh - 104px - env(safe-area-inset-top));
    max-height: calc(100dvh - 104px - env(safe-area-inset-top));
  }
}

/* ---- Results table: keep the action column reachable (Sep 18 2026) -------
   On a phone the seven-column table overflowed the viewport and the trailing
   View button was clipped. The scroll is now intentional and styled, and the
   first and last columns stick so the candidate and the action stay visible
   while the middle columns scroll. */
.tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin; }
.tbl-wrap::-webkit-scrollbar { height: 8px; }
.tbl-wrap::-webkit-scrollbar-thumb { background: rgba(255,255,255,.18); border-radius: 999px; }
.tbl-wrap::-webkit-scrollbar-track { background: transparent; }
table.tbl th:last-child, table.tbl td:last-child {
  /* Match the panel behind the table: a hardcoded colour here painted
     dark blocks over the first and last columns. */
  position: sticky; right: 0; background: var(--panel);
  box-shadow: -10px 0 14px -10px rgba(0,0,0,.6);
}
table.tbl th:first-child, table.tbl td:first-child { position: sticky; left: 0; background: var(--panel); }
@media (max-width: 720px) {
  table.tbl { min-width: 720px; }
  table.tbl th, table.tbl td { padding-left: 10px; padding-right: 10px; }
}

/* ---- Custom domain page: DNS record rows (Sep 20 2026) -------------------
   Each record shows its name/value in a monospace block with a copy button.
   Values wrap rather than scroll, because a TXT value is long and an admin on
   a phone must be able to read it without horizontal scrolling. */
.dns-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  margin-bottom: 6px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: rgba(15, 23, 42, 0.02);
}
.dns-row .dns-k {
  flex: 0 0 auto;
  width: 54px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: .03em;
}
.dns-row code {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12.5px;
  word-break: break-all;
  color: var(--text-1);
}
.dns-row .dns-copy { flex: 0 0 auto; padding: 5px 10px; font-size: 12px; }
