:root {
  /* AFRICOM Technologies brand colors, sampled directly from the company logo. */
  --sd-primary: #003ea3;
  --sd-primary-dark: #002c75;
  --sd-primary-light: #eaeff7;
  --sd-accent: #00ad4c;
  --sd-success: #2f9e6e;
  --sd-warning: #d9a72b;
  --sd-danger: #c94c4c;
  --sd-sidebar-bg: #172a3a;
  --sd-sidebar-hover: #22405a;
  --sd-sidebar-active: var(--sd-primary);
  --sd-body-bg: #f4f6f9;

  --sd-heading: #1c2b3a;
  --sd-body-text: #33475a;
  --sd-muted: #667085;
  --sd-border: #e6eaf0;
  --sd-border-strong: #d7dde5;

  --sd-card-radius: 0.75rem;
  --sd-radius-sm: 0.5rem;
  --sd-radius-lg: 1rem;
  --sd-sidebar-width: 250px;

  --sd-shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.04);
  --sd-shadow-sm: 0 2px 6px rgba(16, 24, 40, 0.06);
  --sd-shadow-md: 0 8px 24px rgba(16, 24, 40, 0.1);
  --sd-shadow-lg: 0 16px 40px rgba(16, 24, 40, 0.16);

  --sd-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --sd-transition-fast: 0.15s var(--sd-ease);
  --sd-transition: 0.2s var(--sd-ease);

  /* Display/body face: IBM Plex Sans -- calm, institutional, deliberately not the
     Inter/Plus-Jakarta-Sans look every generic SaaS dashboard reaches for.
     Data/utility face: IBM Plex Mono -- for anything that's a value to be scanned
     precisely (IDs, timestamps, confidence %) rather than prose to be read. */
  --sd-font-sans: "IBM Plex Sans", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif;
  --sd-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;

  /* Confidence-ring signature scale -- shared by the OCR review screen, the
     student-forms list, and the dashboard pipeline aggregate. */
  --sd-confidence-none: #c7d3e0;
  --sd-confidence-low: var(--sd-danger);
  --sd-confidence-mid: var(--sd-warning);
  --sd-confidence-high: var(--sd-accent);

  --bs-primary: var(--sd-primary);
  --bs-primary-rgb: 0, 62, 163;
  --bs-body-color: var(--sd-body-text);
  --bs-link-color: var(--sd-primary);
  --bs-link-hover-color: var(--sd-primary-dark);
  --bs-border-radius: var(--sd-radius-sm);
  --bs-border-radius-sm: 0.4rem;
  --bs-border-radius-lg: var(--sd-card-radius);
  --bs-focus-ring-color: rgba(0, 62, 163, 0.25);

  /* Bootstrap's bg-primary-subtle / text-primary-emphasis / border-primary-subtle utilities
     are precompiled to Bootstrap's stock blue and don't derive from --bs-primary at runtime,
     so they need their own override to actually match the brand blue. */
  --bs-primary-bg-subtle: var(--sd-primary-light);
  --bs-primary-border-subtle: #99b2da;
  --bs-primary-text-emphasis: var(--sd-primary-dark);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Base / typography ---------- */
html {
  scroll-behavior: smooth;
}

body {
  background-color: var(--sd-body-bg);
  color: var(--sd-body-text);
  font-family: var(--sd-font-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: 0.9375rem;
  line-height: 1.55;
}

/* Utility face for values meant to be scanned precisely: IDs, timestamps,
   confidence percentages, counts. Tabular figures keep columns of numbers
   aligned instead of jittering as digits change width. */
.font-data {
  font-family: var(--sd-font-mono);
  font-variant-numeric: tabular-nums;
}

h1, h2, h3, h4, h5, h6 {
  color: var(--sd-heading);
  font-weight: 700;
  letter-spacing: -0.01em;
}

h3 { font-size: 1.4rem; }
h4 { font-size: 1.2rem; }
h5 { font-size: 1.05rem; }
h6 { font-size: 0.9rem; }

.text-muted {
  color: var(--sd-muted) !important;
}

a {
  transition: color var(--sd-transition-fast);
}

::selection {
  background: rgba(0, 62, 163, 0.2);
}

/* Consistent, tasteful keyboard-focus ring on interactive elements */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
.nav-link:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible {
  outline: 2px solid var(--sd-primary);
  outline-offset: 2px;
}

/* Subtle one-time entrance for freshly-rendered page content.
   Opacity-only and no fill-mode: a lingering non-"none" transform (e.g. from
   fill-mode "both") on an .app-content ancestor would create a new containing
   block for any position:fixed descendant -- including Bootstrap modals nested
   anywhere inside the page -- breaking their full-viewport positioning. */
@media (prefers-reduced-motion: no-preference) {
  .app-content > * {
    animation: sd-fade-in 0.25s var(--sd-ease);
  }
  @keyframes sd-fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }
}

/* ---------- App shell ---------- */
.app-shell {
  display: flex;
  min-height: 100vh;
}

.app-sidebar {
  width: var(--sd-sidebar-width);
  flex-shrink: 0;
  background-color: var(--sd-sidebar-bg);
  color: #cdd8e3;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  overflow-y: auto;
  z-index: 1030;
  transition: transform var(--sd-transition) ease-in-out;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}

.app-sidebar::-webkit-scrollbar {
  width: 6px;
}

.app-sidebar::-webkit-scrollbar-thumb {
  background-color: rgba(255, 255, 255, 0.18);
  border-radius: 3px;
}

.app-sidebar .brand {
  padding: 1.25rem 1.25rem 1rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.app-sidebar .brand-logo-badge {
  background: #fff;
  border-radius: 0.5rem;
  padding: 0.35rem 0.6rem;
  display: inline-flex;
  align-items: center;
  box-shadow: var(--sd-shadow-sm);
}

.app-sidebar .brand-logo-img {
  height: 26px;
  width: auto;
  display: block;
}

.app-sidebar .brand-product-name {
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.01em;
  color: #fff;
}

.app-sidebar .nav-section-title {
  text-transform: uppercase;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  color: #7c93a8;
  padding: 1.1rem 1.5rem 0.4rem;
}

.app-sidebar .nav {
  padding: 0 0.75rem;
}

.app-sidebar .nav-section-title {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

.app-sidebar .nav-link {
  color: #cdd8e3;
  padding: 0.55rem 0.85rem;
  margin: 0.1rem 0;
  border-radius: var(--sd-radius-sm);
  display: flex;
  align-items: center;
  gap: 0.65rem;
  font-size: 0.92rem;
  transition: background-color var(--sd-transition-fast), color var(--sd-transition-fast), transform var(--sd-transition-fast);
}

.app-sidebar .nav-link:hover {
  background-color: var(--sd-sidebar-hover);
  color: #fff;
  transform: translateX(2px);
}

.app-sidebar .nav-link.active {
  background-color: var(--sd-sidebar-active);
  color: #fff;
  font-weight: 600;
  box-shadow: var(--sd-shadow-sm);
}

.app-sidebar .nav-link.active:hover {
  transform: none;
}

.app-sidebar .nav-link i {
  font-size: 1.05rem;
  width: 1.25rem;
  text-align: center;
  flex-shrink: 0;
}

.app-main {
  margin-left: var(--sd-sidebar-width);
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.app-topbar {
  background-color: #fff;
  border-bottom: 1px solid var(--sd-border);
  padding: 0.65rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: 1020;
  gap: 0.75rem;
}

.app-topbar .user-chip {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-width: 0;
}

.app-topbar .user-avatar {
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: var(--sd-primary-light);
  color: var(--sd-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05rem;
  flex-shrink: 0;
}

.app-topbar .user-meta {
  min-width: 0;
  line-height: 1.25;
}

.app-topbar .user-email {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 200px;
}

.app-content {
  padding: 1.5rem;
  flex-grow: 1;
}

.app-footer {
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--sd-border);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  color: var(--sd-muted);
  font-size: 0.8rem;
}

.app-footer-logo {
  height: 16px;
  width: auto;
  opacity: 0.85;
}

.sidebar-toggle-btn {
  display: none;
}

.sidebar-backdrop {
  display: none;
}

@media (max-width: 991.98px) {
  .app-sidebar {
    transform: translateX(-100%);
    box-shadow: var(--sd-shadow-lg);
  }
  .app-sidebar.show {
    transform: translateX(0);
  }
  .app-main {
    margin-left: 0;
  }
  .sidebar-toggle-btn {
    display: inline-flex;
  }
  .sidebar-backdrop.show {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 32, 0.45);
    z-index: 1025;
    animation: sd-fade-in-backdrop 0.15s ease-in-out both;
  }
  @keyframes sd-fade-in-backdrop {
    from { opacity: 0; }
    to { opacity: 1; }
  }
  .app-topbar .user-email {
    max-width: 120px;
  }
}

@media (max-width: 575.98px) {
  .app-content {
    padding: 1rem;
  }
  .app-topbar {
    padding: 0.6rem 1rem;
  }
  .app-topbar .role-badges {
    display: none;
  }
}

/* ---------- Buttons ---------- */
.btn {
  border-radius: var(--sd-radius-sm);
  font-weight: 500;
  touch-action: manipulation;
  transition: color var(--sd-transition-fast), background-color var(--sd-transition-fast),
    border-color var(--sd-transition-fast), box-shadow var(--sd-transition-fast),
    transform var(--sd-transition-fast);
}

.btn:hover {
  transform: translateY(-1px);
}

.btn:active {
  transform: translateY(0) scale(0.98);
}

.btn:disabled,
.btn.disabled {
  transform: none;
  opacity: 0.5;
}

.btn-primary,
.btn-success,
.btn-danger {
  box-shadow: var(--sd-shadow-xs);
}

.btn-primary:hover,
.btn-success:hover,
.btn-danger:hover {
  box-shadow: var(--sd-shadow-sm);
}

.btn-sm {
  border-radius: 0.4rem;
}

/* Bootstrap's .btn-sm (~31px tall) reads fine visually on desktop but is
   under the 44px touch-target minimum. Keep it compact for mouse use and
   only grow the tap area on touch/coarse-pointer devices, so dense admin
   tables don't get visually bloated on desktop. */
@media (hover: none), (pointer: coarse) {
  .btn-sm {
    min-height: 44px;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
    display: inline-flex;
    align-items: center;
  }
}

/* Loading state, toggled by site.js on form submit */
.btn.is-loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}

.btn.is-loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1rem;
  height: 1rem;
  margin: -0.5rem 0 0 -0.5rem;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  color: inherit;
  opacity: 0.85;
  animation: sd-spin 0.6s linear infinite;
}

.btn-primary.is-loading::after,
.btn-success.is-loading::after,
.btn-danger.is-loading::after {
  color: #fff;
}

.btn-outline-primary.is-loading::after,
.btn-outline-secondary.is-loading::after,
.btn-outline-success.is-loading::after,
.btn-outline-danger.is-loading::after {
  color: var(--sd-primary);
}

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

/* ---------- Forms ---------- */
.form-label {
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--sd-heading);
  margin-bottom: 0.35rem;
}

/* Add class="form-label required" to mark a field mandatory */
.form-label.required::after {
  content: " *";
  color: var(--sd-danger);
  font-weight: 700;
}

.form-control,
.form-select {
  border-color: var(--sd-border-strong);
  transition: border-color var(--sd-transition-fast), box-shadow var(--sd-transition-fast);
}

.form-control:hover:not(:disabled):not(:focus),
.form-select:hover:not(:disabled):not(:focus) {
  border-color: #b9c3d0;
}

.form-control:focus,
.form-select:focus {
  border-color: var(--sd-primary);
  box-shadow: 0 0 0 0.2rem rgba(0, 62, 163, 0.15);
}

/* Disabled = not applicable right now (muted, blocked cursor). Readonly =
   still valid data the user just can't edit here (kept legible, not grayed
   out) -- these are semantically different states and should look different. */
.form-control:disabled,
.form-select:disabled {
  background-color: #eef0f2;
  color: var(--sd-muted);
  cursor: not-allowed;
}

.form-control[readonly] {
  background-color: #fbfcfd;
  color: var(--sd-body-text);
  cursor: default;
}

.form-control::placeholder {
  color: #a3adba;
}

.form-text {
  font-size: 0.8rem;
}

@media (hover: none), (pointer: coarse) {
  .form-control,
  .form-select {
    min-height: 44px;
  }
}

/* Password show/hide toggle */
.password-toggle-wrap {
  position: relative;
}

.password-toggle-wrap .form-control {
  padding-right: 2.75rem;
}

.password-toggle-btn {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  color: var(--sd-muted);
  cursor: pointer;
  transition: color var(--sd-transition-fast);
}

.password-toggle-btn:hover {
  color: var(--sd-primary);
}

.password-toggle-btn:focus-visible {
  outline: 2px solid var(--sd-primary);
  outline-offset: -2px;
  border-radius: var(--sd-radius-sm);
}

.form-check-input {
  transition: background-color var(--sd-transition-fast), border-color var(--sd-transition-fast), box-shadow var(--sd-transition-fast);
}

.form-check-input:focus {
  box-shadow: 0 0 0 0.2rem rgba(0, 62, 163, 0.15);
}

.form-check-label,
label.form-check-label {
  cursor: pointer;
}

.invalid-feedback,
.text-danger.small {
  font-size: 0.8rem;
}

/* ---------- Step indicator (registration: record details -> documents) ---------- */
.step-indicator {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
}

.step-indicator-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--sd-muted);
  font-size: 0.85rem;
  font-weight: 500;
}

.step-indicator-number {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--sd-border);
  color: var(--sd-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 700;
  flex-shrink: 0;
}

.step-indicator-item.is-done .step-indicator-number {
  background: var(--sd-accent);
  color: #fff;
}

.step-indicator-item.is-current .step-indicator-number {
  background: var(--sd-primary);
  color: #fff;
}

.step-indicator-item.is-current {
  color: var(--sd-heading);
}

.step-indicator-connector {
  width: 2rem;
  height: 1px;
  background: var(--sd-border);
  flex-shrink: 0;
}

/* ---------- Sectioned record forms (Student/Employee Create & Edit) ---------- */
.record-form {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 1.5rem;
  align-items: start;
}

@media (max-width: 991.98px) {
  .record-form {
    grid-template-columns: 1fr;
  }
}

.record-form-nav {
  position: sticky;
  top: calc(1.5rem + 61px); /* app-topbar height + its own top offset */
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.record-form-nav-link {
  padding: 0.45rem 0.75rem;
  border-radius: var(--sd-radius-sm);
  color: var(--sd-muted);
  font-size: 0.85rem;
  font-weight: 500;
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: background-color var(--sd-transition-fast), color var(--sd-transition-fast), border-color var(--sd-transition-fast);
}

.record-form-nav-link:hover {
  background-color: var(--sd-primary-light);
  color: var(--sd-primary);
}

.record-form-nav-link.active {
  color: var(--sd-primary);
  border-left-color: var(--sd-primary);
  font-weight: 600;
  background-color: var(--sd-primary-light);
}

.record-form-sections {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  min-width: 0;
}

.form-section-card {
  background: var(--sd-surface, #fff);
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-card-radius);
  padding: 1.5rem;
  scroll-margin-top: calc(1.5rem + 61px);
}

.form-section-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--sd-heading);
  margin-bottom: 1rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--sd-border);
}

/* A field that differs from its value when the Edit page loaded. Left border +
   tint rather than a loud color, since a form full of these should still read
   as calm -- it's information, not an alarm. */
.form-field {
  position: relative;
  transition: padding-left var(--sd-transition);
}

.form-field--changed {
  padding-left: 0.6rem;
  border-left: 2px solid var(--sd-warning);
}

.form-field-changed-badge {
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--sd-warning);
  background: rgba(217, 167, 43, 0.14);
  border-radius: 50rem;
  padding: 0.1rem 0.45rem;
  margin-left: 0.4rem;
  vertical-align: middle;
}

.record-form-actions {
  position: sticky;
  bottom: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: var(--sd-surface, #fff);
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-card-radius);
  padding: 0.85rem 1.25rem;
  margin-top: 1.25rem;
  box-shadow: 0 -4px 12px rgba(16, 24, 40, 0.05);
}

.record-form-status {
  font-size: 0.8rem;
  color: var(--sd-muted);
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.record-form-status.is-dirty {
  color: var(--sd-warning);
}

.record-form-last-updated {
  background: var(--sd-primary-light);
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-radius-sm);
  padding: 0.6rem 0.9rem;
  font-size: 0.8rem;
  color: var(--sd-body-text);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
}

.record-form-last-updated i {
  color: var(--sd-primary);
}

/* ---------- Cards & summary tiles ---------- */
.card {
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-card-radius);
  box-shadow: var(--sd-shadow-xs);
  transition: box-shadow var(--sd-transition), transform var(--sd-transition), border-color var(--sd-transition);
}

.card-header {
  background-color: #fafbfc;
  border-bottom: 1px solid var(--sd-border);
  font-weight: 600;
  color: var(--sd-heading);
}

.card-title {
  font-weight: 700;
  color: var(--sd-heading);
}

/* Opt-in class for cards that act like interactive controls (radio-card pickers, etc.) */
.card-hoverable {
  cursor: pointer;
}

.card-hoverable:hover {
  box-shadow: var(--sd-shadow-md);
  transform: translateY(-2px);
  border-color: #c7d3e0;
}

.card-hoverable:active {
  transform: translateY(-1px) scale(0.99);
}

/* ---------- Dashboard ---------- */
.dash-section-title {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--sd-muted);
}

.dash-provider-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.85rem;
  background: #fff;
  border: 1px solid var(--sd-border);
  border-radius: 50rem;
  font-size: 0.85rem;
  color: var(--sd-body-text);
  transition: border-color var(--sd-transition-fast), box-shadow var(--sd-transition-fast);
}

.dash-provider-chip:hover {
  border-color: var(--sd-border-strong);
  box-shadow: var(--sd-shadow-xs);
  color: var(--sd-body-text);
}

.dash-provider-chip i {
  color: var(--sd-primary);
}

.dash-kpi {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.9rem 1rem;
  background: #fff;
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-card-radius);
  box-shadow: var(--sd-shadow-xs);
  height: 100%;
  transition: box-shadow var(--sd-transition), transform var(--sd-transition), border-color var(--sd-transition);
}

.dash-kpi:hover {
  box-shadow: var(--sd-shadow-sm);
  transform: translateY(-2px);
}

.dash-kpi-icon {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.15rem;
  flex-shrink: 0;
  background: var(--sd-primary-light);
  color: var(--sd-primary);
}

.dash-kpi-icon--lg {
  width: 3rem;
  height: 3rem;
  font-size: 1.35rem;
  color: #fff;
}

.dash-kpi--info .dash-kpi-icon { background: var(--sd-primary-light); color: var(--sd-primary); }
.dash-kpi--success .dash-kpi-icon { background: rgba(47, 158, 110, 0.12); color: var(--sd-success); }
.dash-kpi--danger .dash-kpi-icon { background: rgba(201, 76, 76, 0.12); color: var(--sd-danger); }
.dash-kpi--muted .dash-kpi-icon { background: #f1f3f5; color: var(--sd-muted); }

.dash-kpi-value {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--sd-heading);
  font-variant-numeric: tabular-nums;
}

.dash-kpi-label {
  color: var(--sd-muted);
  font-size: 0.8rem;
}

.dash-pipeline-bar {
  display: flex;
  height: 0.65rem;
  border-radius: 50rem;
  overflow: hidden;
  background: var(--sd-border);
}

.dash-pipeline-bar > span {
  transition: flex-grow var(--sd-transition);
}

.dash-action-card {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 1rem;
  background: #fff;
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-card-radius);
  text-decoration: none;
  color: inherit;
  height: 100%;
  box-shadow: var(--sd-shadow-xs);
  transition: box-shadow var(--sd-transition), transform var(--sd-transition), border-color var(--sd-transition);
}

.dash-action-card:hover {
  box-shadow: var(--sd-shadow-sm);
  transform: translateY(-2px);
  border-color: var(--sd-border-strong);
  color: inherit;
}

.dash-action-card:active {
  transform: translateY(-1px) scale(0.99);
}

@media (prefers-reduced-motion: no-preference) {
  .dash-spin {
    display: inline-block;
    animation: sd-spin-slow 2.5s linear infinite;
  }
}

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

@media (max-width: 575.98px) {
  .dash-kpi-value { font-size: 1.25rem; }
}

.bg-icon-primary { background-color: var(--sd-primary); }
.bg-icon-accent { background-color: var(--sd-accent); }
.bg-icon-success { background-color: var(--sd-success); }
.bg-icon-warning { background-color: var(--sd-warning); }
.bg-icon-danger { background-color: var(--sd-danger); }

/* ---------- Tables ---------- */
.table-modern {
  --bs-table-bg: transparent;
  font-size: 0.9rem;
}

.table-modern thead th {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--sd-muted);
  background-color: #fafbfc;
  border-bottom: 1px solid var(--sd-border);
  white-space: nowrap;
  padding: 0.85rem 1rem;
}

.table-modern td {
  vertical-align: middle;
  padding: 0.8rem 1rem;
  border-bottom-color: var(--sd-border);
}

.table-modern tbody tr {
  transition: background-color var(--sd-transition-fast);
}

.table-modern tbody tr:hover {
  background-color: var(--sd-primary-light);
}

.table-modern tbody tr:last-child td {
  border-bottom: none;
}

.table-modern a {
  text-decoration: none;
}

.table-modern th a:hover {
  color: var(--sd-primary);
}

.table-modern th a.sort-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.table-modern th a.sort-link i {
  font-size: 0.7rem;
}

.table-modern th[aria-sort="ascending"] a.sort-link,
.table-modern th[aria-sort="descending"] a.sort-link {
  color: var(--sd-primary);
}

/* Consistent empty-state treatment for table bodies with no rows */
.table-empty-state {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--sd-muted);
}

.table-empty-state i {
  display: block;
  font-size: 1.75rem;
  margin-bottom: 0.5rem;
  color: #c7d3e0;
}

.table-empty-state .table-empty-title {
  font-weight: 600;
  color: var(--sd-heading);
  margin-bottom: 0.15rem;
}

/* ---------- DataTables ---------- */
.dataTables_wrapper > .row:first-child {
  padding: 1rem 1rem 0.75rem;
  margin: 0;
}

.dataTables_wrapper > .row:last-child {
  padding: 0.75rem 1rem 1rem;
  margin: 0;
  align-items: center;
}

.dataTables_wrapper .dataTables_filter input {
  margin-left: 0.4rem;
  min-width: 200px;
}

.dataTables_wrapper .dataTables_length select {
  margin: 0 0.4rem;
}

.dataTables_wrapper .dataTables_info {
  color: var(--sd-muted);
  font-size: 0.85rem;
}

.dataTables_wrapper .dataTables_paginate .pagination {
  margin-bottom: 0;
}

.dataTables_wrapper table.dataTable thead th {
  outline: none;
}

@media (max-width: 575.98px) {
  .dataTables_wrapper > .row:first-child,
  .dataTables_wrapper > .row:last-child {
    text-align: center;
  }

  .dataTables_wrapper .dataTables_length,
  .dataTables_wrapper .dataTables_filter {
    margin-bottom: 0.5rem;
  }

  .dataTables_wrapper .dataTables_filter input {
    width: 100%;
    margin-left: 0;
    margin-top: 0.35rem;
  }
}

/* ---------- Badges ---------- */
.badge {
  font-weight: 600;
  letter-spacing: 0.01em;
  border-radius: 50rem;
  padding: 0.4em 0.75em;
}

/* Status colors are chosen by what they mean, not just alternating hues:
   neutral = waiting on the system, blue = system is actively working,
   teal = system is done and a human needs to act, red = broken, green = human-confirmed.
   Completed previously rendered in warning-yellow, which reads as "needs
   attention/problem" when it actually just means "OCR finished, ready to review." */
.badge-status-Pending { background-color: #e9ecef; color: #495057; }
.badge-status-Processing { background-color: #cfe2ff; color: #084298; }
.badge-status-Completed { background-color: #cff4fc; color: #055160; }
.badge-status-Failed { background-color: #f8d7da; color: #842029; }
.badge-status-Verified { background-color: #d1e7dd; color: #0f5132; }

/* ---------- Pagination ---------- */
.pagination .page-link {
  border-color: var(--sd-border);
  color: var(--sd-body-text);
  transition: background-color var(--sd-transition-fast), color var(--sd-transition-fast), border-color var(--sd-transition-fast);
}

.pagination .page-link:hover {
  background-color: var(--sd-primary-light);
  color: var(--sd-primary);
}

.pagination .page-item.active .page-link {
  box-shadow: var(--sd-shadow-xs);
}

/* ---------- Alerts ---------- */
.alert {
  border: 1px solid transparent;
  border-radius: var(--sd-radius-sm);
}

/* asp-validation-summary always renders the container -- with class
   "validation-summary-valid" and an empty (but present) list -- even when
   there are no errors. Without this rule, any form using the common
   `class="alert alert-danger py-2"` pattern (this one included) shows an
   empty red box on every clean page load. */
.validation-summary-valid {
  display: none;
}

/* ---------- Auth pages ---------- */
.auth-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, var(--sd-primary-dark), var(--sd-primary));
}

/* A quiet radial glow for depth, not decoration -- reinforces "calm and
   secure" rather than competing with the form for attention. */
.auth-shell::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 20% 15%, rgba(255, 255, 255, 0.1), transparent 45%),
    radial-gradient(circle at 85% 90%, rgba(0, 173, 76, 0.16), transparent 40%);
  pointer-events: none;
}

.auth-card {
  width: 100%;
  max-width: 400px;
  background: #fff;
  border-radius: var(--sd-card-radius);
  padding: 2rem;
  box-shadow: var(--sd-shadow-lg);
  position: relative;
}

@media (prefers-reduced-motion: no-preference) {
  .auth-card {
    animation: sd-auth-card-in 0.4s var(--sd-ease) backwards;
  }
  @keyframes sd-auth-card-in {
    from { opacity: 0; transform: translateY(10px) scale(0.98); }
    to { opacity: 1; transform: translateY(0) scale(1); }
  }
}

/* The validation-summary tag helper fully replaces its own inner content
   (the error <ul>), so an icon can't live inside it -- it lives beside it in
   this wrapper instead, shown only once the summary actually has errors. */
.auth-alert-wrap {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.auth-alert-wrap > i {
  display: none;
  color: var(--sd-danger);
  margin-top: 0.7rem;
  flex-shrink: 0;
}

.auth-alert-wrap:has(.validation-summary-errors) > i {
  display: block;
}

@media (prefers-reduced-motion: no-preference) {
  .auth-alert-wrap:has(.validation-summary-errors) {
    animation: sd-auth-error-in 0.3s var(--sd-ease);
  }
  @keyframes sd-auth-error-in {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: translateY(0); }
  }
}

.auth-demo-hint {
  background: var(--sd-primary-light);
  border: 1px solid var(--sd-primary-border-subtle, var(--sd-border));
  border-radius: var(--sd-radius-sm);
  padding: 0.6rem 0.75rem;
  font-size: 0.8rem;
  color: var(--sd-body-text);
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
}

.auth-demo-hint i {
  color: var(--sd-primary);
  margin-top: 0.15rem;
}

.auth-logo {
  height: 48px;
  width: auto;
}

.auth-footer-credit {
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.8rem;
  margin-top: 1.5rem;
  position: relative;
}

/* ---------- Detail pages (Student/Employee Details) ---------- */
.detail-tabs {
  border-bottom: 1px solid var(--sd-border);
  gap: 0.25rem;
}

.detail-tabs .nav-link {
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--sd-muted);
  font-weight: 500;
  padding: 0.6rem 0.25rem;
  margin-right: 1.25rem;
  transition: color var(--sd-transition-fast), border-color var(--sd-transition-fast);
}

.detail-tabs .nav-link:hover {
  color: var(--sd-primary);
  border-color: var(--sd-border-strong);
}

.detail-tabs .nav-link.active {
  color: var(--sd-primary);
  background: transparent;
  border-color: var(--sd-primary);
  font-weight: 600;
}

/* Clean key/value display for read-only record details -- replaces ad hoc
   dl.row markup with a consistent label/value rhythm across every detail card. */
.info-list {
  display: flex;
  flex-direction: column;
}

.info-list-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--sd-border);
}

.info-list-row:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.info-list-row:first-child {
  padding-top: 0;
}

.info-list-label {
  color: var(--sd-muted);
  font-size: 0.8rem;
  flex-shrink: 0;
}

.info-list-value {
  color: var(--sd-text-primary, var(--sd-heading));
  font-weight: 500;
  text-align: right;
}

/* A calmer empty-state treatment for cards with nothing to show yet, reused
   from the table empty-state pattern (the styling isn't table-specific). */
.card-empty-state {
  text-align: center;
  padding: 1.5rem 1rem;
  color: var(--sd-muted);
}

.card-empty-state i {
  display: block;
  font-size: 1.5rem;
  margin-bottom: 0.4rem;
  color: #c7d3e0;
}

/* ---------- File upload dropzone ---------- */
.dropzone {
  position: relative;
  border: 2px dashed var(--sd-border-strong);
  border-radius: var(--sd-radius-sm);
  background: var(--sd-body-bg);
  padding: 1.5rem 1rem;
  text-align: center;
  cursor: pointer;
  transition: border-color var(--sd-transition-fast), background-color var(--sd-transition-fast);
}

.dropzone:hover {
  border-color: var(--sd-primary);
}

.dropzone.is-dragover {
  border-color: var(--sd-primary);
  background: var(--sd-primary-light);
}

.dropzone input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.dropzone-empty i {
  font-size: 1.5rem;
  color: var(--sd-muted);
  display: block;
  margin-bottom: 0.4rem;
}

.dropzone-empty-text {
  color: var(--sd-muted);
  font-size: 0.85rem;
}

.dropzone-preview {
  display: none;
  align-items: center;
  gap: 0.75rem;
  text-align: left;
}

.dropzone.has-file .dropzone-empty {
  display: none;
}

.dropzone.has-file .dropzone-preview {
  display: flex;
}

.dropzone-thumb {
  width: 44px;
  height: 44px;
  border-radius: var(--sd-radius-sm);
  object-fit: cover;
  background: #fff;
  border: 1px solid var(--sd-border);
  flex-shrink: 0;
}

.dropzone-thumb-icon {
  width: 44px;
  height: 44px;
  border-radius: var(--sd-radius-sm);
  background: #fff;
  border: 1px solid var(--sd-border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  color: var(--sd-primary);
  flex-shrink: 0;
}

.dropzone-file-info {
  min-width: 0;
  flex-grow: 1;
}

.dropzone-file-name {
  font-weight: 600;
  color: var(--sd-heading);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dropzone-file-size {
  color: var(--sd-muted);
  font-size: 0.8rem;
}

.dropzone-remove {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
}

/* ---------- Document viewer ---------- */
.doc-viewer-frame {
  width: 100%;
  height: 100%;
  min-height: 420px;
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-radius-sm);
  background: #fff;
}

.doc-preview-body {
  height: 70vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: auto;
}

.doc-preview-body img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Bootstrap's .modal-content is already a flex column (header/body/footer) --
   in full screen it just needs to fill the viewport and let the preview body
   (rather than the fixed 70vh) grow into the freed-up space. */
.modal-content:fullscreen,
.modal-content:-webkit-full-screen {
  height: 100vh;
  border-radius: 0;
}

.modal-content:fullscreen .doc-preview-body,
.modal-content:-webkit-full-screen .doc-preview-body {
  height: auto;
  flex: 1 1 auto;
  min-height: 0;
}

.field-review-group {
  border: 1px solid var(--sd-border);
  border-radius: var(--sd-radius-sm);
  padding: 1rem;
  margin-bottom: 1rem;
  transition: border-color var(--sd-transition-fast);
}

.field-review-group:hover {
  border-color: var(--sd-border-strong);
}

.field-review-group h6 {
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--sd-muted);
  margin-bottom: 0.75rem;
}

/* OCR-sourced field, not yet reviewed by a human -- a blue tint (distinct from
   the amber "you changed this" indicator used on Student/Employee Edit) that
   fades away the moment the reviewer touches the field, since editing it IS
   the review. */
.field-ocr-pending {
  padding-left: 0.6rem;
  border-left: 2px solid var(--sd-primary);
  background: var(--sd-primary-light);
  border-radius: 0 var(--sd-radius-sm) var(--sd-radius-sm) 0;
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
  transition: background-color var(--sd-transition), border-color var(--sd-transition), padding var(--sd-transition);
}

.ocr-field-badge {
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--sd-primary);
  background: #fff;
  border-radius: 50rem;
  padding: 0.1rem 0.45rem;
  margin-left: 0.4rem;
  vertical-align: middle;
}

.field-label-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-bottom: 0.25rem;
}

/* ---------- Confidence ring (signature element) ----------
   A donut built from a conic-gradient track + an inset surface-colored circle
   cut out of the middle -- avoids SVG for something this small and reused this
   often. --pct is 0-100, set inline per instance. Registering it with @property
   lets the browser transition the fill in on load instead of snapping; browsers
   without @property support just render the final value immediately, which is
   still correct. */
@property --sd-ring-pct {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

.confidence-ring {
  --sd-ring-pct: 0;
  --sd-ring-color: var(--sd-confidence-none);
  width: var(--sd-ring-size, 20px);
  height: var(--sd-ring-size, 20px);
  border-radius: 50%;
  flex-shrink: 0;
  position: relative;
  background: conic-gradient(var(--sd-ring-color) calc(var(--sd-ring-pct) * 1%), var(--sd-border) 0);
}

.confidence-ring::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--sd-surface, #fff);
}

@media (prefers-reduced-motion: no-preference) {
  .confidence-ring {
    transition: --sd-ring-pct 0.6s var(--sd-ease);
  }
}

.confidence-ring-label {
  font-family: var(--sd-font-mono);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--sd-muted);
}

/* ---------- Motion utilities: staggered entrance ---------- */
@media (prefers-reduced-motion: no-preference) {
  /* fill-mode "backwards" (not "both"): we need the pre-delay "from" state so
     staggered items don't flash visible before their turn, but we must NOT
     hold a non-"none" transform after the animation ends -- a lingering
     transform of any kind creates a new containing block for position:fixed
     descendants (e.g. a Bootstrap modal nested inside a staggered card),
     which would trap it instead of positioning against the viewport. Once
     the animation completes without "forwards", the element reverts to its
     normal static styles, which already equal the "to" keyframe anyway. */
  .stagger-item {
    animation: sd-stagger-in 0.35s var(--sd-ease) backwards;
    animation-delay: calc(var(--stagger-i, 0) * 60ms);
  }
  @keyframes sd-stagger-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
  }
}

/* ---------- htmx swap polish ---------- */
.htmx-swapping {
  opacity: 0;
  transition: opacity 120ms ease-out;
}

.htmx-settling {
  opacity: 1;
}

/* ---------- Misc responsiveness ---------- */
@media (max-width: 575.98px) {
  h3 { font-size: 1.2rem; }
  .btn { font-size: 0.9rem; }
}
