/* ============================================================
   FYP Attendance — Design System
   ============================================================ */
:root {
  --c-bg: #f3f5fb;
  --c-surface: #ffffff;
  --c-surface-2: #f8fafc;
  --c-border: #e5e7eb;
  --c-border-2: #eef0f4;
  --c-text: #0f172a;
  --c-text-2: #475569;
  --c-muted: #94a3b8;

  --c-primary: #2a4b7f;
  --c-primary-hover: #203a63;
  --c-primary-soft: #eaeff6;
  --c-accent: #2a4b7f;

  --c-success: #16a34a;
  --c-success-bg: #dcfce7;
  --c-warning: #d97706;
  --c-warning-bg: #fef3c7;
  --c-danger: #dc2626;
  --c-danger-bg: #fee2e2;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 16px;

  --shadow-sm: 0 1px 2px rgba(15, 23, 42, .04), 0 1px 3px rgba(15, 23, 42, .04);
  --shadow: 0 4px 12px rgba(15, 23, 42, .06), 0 1px 3px rgba(15, 23, 42, .04);
  --shadow-lg: 0 20px 40px -10px rgba(15, 23, 42, .15), 0 8px 16px -8px rgba(15, 23, 42, .08);

  --transition: 150ms cubic-bezier(.4, 0, .2, 1);
  --ease: cubic-bezier(.4, 0, .2, 1);

  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei", sans-serif;
}

* {
  box-sizing: border-box;
}

html {
  height: 100%;
}

/* min-height (not height): a fixed height caps the body at one viewport,
   which breaks position:sticky for the topbar once the page scrolls
   past the first screen. */
body {
  min-height: 100%;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.55;
  color: var(--c-text);
  background:
    radial-gradient(1200px 600px at 100% -200px, rgba(42, 75, 127, .08), transparent 60%),
    radial-gradient(900px 500px at -10% 110%, rgba(42, 75, 127, .06), transparent 60%),
    var(--c-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body.centered {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
}

/* Typography ---------------------------------------------------- */
h1,
h2,
h3,
h4 {
  margin: 0 0 .5rem;
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--c-text);
}

h1 {
  font-size: 1.5rem;
}

h2 {
  font-size: 1.15rem;
}

h3 {
  font-size: 1rem;
  color: var(--c-text);
}

p {
  margin: .25rem 0;
}

.muted {
  color: var(--c-text-2);
}

.small {
  font-size: 12px;
}

.error {
  color: var(--c-danger);
  min-height: 1em;
  margin: .5rem 0 0;
  font-size: 13px;
}

code {
  background: var(--c-surface-2);
  border: 1px solid var(--c-border-2);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Login card --------------------------------------------------- */
.card {
  background: var(--c-surface);
  padding: 2.25rem;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 400px;
  max-width: 95vw;
  border: 1px solid var(--c-border-2);
}

.card h1 {
  font-size: 1.5rem;
  background: linear-gradient(135deg, var(--c-primary), var(--c-accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin-bottom: .25rem;
}

.card label {
  display: block;
  margin: 1rem 0 .35rem;
  font-size: 13px;
  font-weight: 500;
  color: var(--c-text-2);
}

.card input,
.card select,
.card textarea {
  width: 100%;
}

.card button[type="submit"] {
  width: 100%;
  margin-top: 1.25rem;
  padding: .65rem 1rem;
  font-size: 14px;
  font-weight: 600;
}

/* Form controls ------------------------------------------------ */
input,
select,
textarea {
  width: 100%;
  padding: .55rem .75rem;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-family: inherit;
  color: var(--c-text);
  background: var(--c-surface);
  transition: border-color var(--transition), box-shadow var(--transition);
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--c-primary);
  box-shadow: 0 0 0 3px rgba(42, 75, 127, .15);
}

input[type="file"] {
  padding: .35rem;
  background: var(--c-surface-2);
  cursor: pointer;
}

input[type="checkbox"] {
  width: auto;
  margin-right: .4rem;
  accent-color: var(--c-primary);
}

textarea {
  resize: vertical;
  min-height: 72px;
}

label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--c-text-2);
}

form label {
  margin-bottom: .25rem;
}

form label>input,
form label>select,
form label>textarea {
  margin-top: .25rem;
}

/* Buttons ------------------------------------------------------ */
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  margin: 0;
  padding: .5rem 1rem;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  background: var(--c-primary);
  color: #fff;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition), box-shadow var(--transition),
    transform var(--transition), opacity var(--transition);
}

button:hover {
  background: var(--c-primary-hover);
}

button:active {
  transform: translateY(1px);
}

button:disabled {
  opacity: .55;
  cursor: not-allowed;
  transform: none;
}

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

button.secondary:hover {
  background: var(--c-surface-2);
  border-color: #cbd5e1;
}

button.danger {
  background: var(--c-danger);
}

button.danger:hover {
  background: #b91c1c;
}

button.ghost {
  background: transparent;
  color: var(--c-text-2);
  border-color: transparent;
}

button.ghost:hover {
  background: var(--c-surface-2);
  color: var(--c-text);
}

/* Top bar ------------------------------------------------------ */
header.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .9rem 1.75rem;
  background: rgba(255, 255, 255, .85);
  backdrop-filter: saturate(180%) blur(10px);
  -webkit-backdrop-filter: saturate(180%) blur(10px);
  border-bottom: 1px solid var(--c-border-2);
}

header.topbar h1 {
  font-size: 1.05rem;
  font-weight: 600;
  margin: 0;
  display: flex;
  align-items: center;
  gap: .55rem;
}

header.topbar>div {
  display: flex;
  align-items: center;
  gap: .75rem;
}

header.topbar #who {
  font-size: 13px;
}

/* Tabs --------------------------------------------------------- */
.tabs {
  display: flex;
  gap: .25rem;
  padding: .5rem 1.25rem;
  background: var(--c-surface);
  border-bottom: 1px solid var(--c-border-2);
  overflow-x: auto;
  scrollbar-width: none;
}

.tabs::-webkit-scrollbar {
  display: none;
}

/* Mobile navigation dropdown — built from .tabs by app.js, shown only on
   narrow screens (see the responsive block below). */
.tabs-select {
  display: none;
}

.tabs button.tab-btn {
  position: relative;
  flex: none;
  padding: .55rem .9rem;
  background: transparent;
  color: var(--c-text-2);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: 500;
  white-space: nowrap;
  transition: background .2s ease, color .2s ease;
}

.tabs button.tab-btn:hover {
  background: var(--c-surface-2);
  color: var(--c-text);
}

.tabs button.tab-btn.active {
  color: var(--c-primary);
  background: var(--c-primary-soft);
}

.tabs button.tab-btn.active::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: -9px;
  height: 2px;
  background: var(--c-primary);
  border-radius: 2px;
}

/* Incomplete / work-in-progress feature — highlighted yellow so it is
   visually distinct from finished features. Add the `incomplete` class
   to any `.tab-btn` to flag the feature as not yet done. */
.tabs button.tab-btn.incomplete {
  background: #fde68a;
  color: #92400e;
}

.tabs button.tab-btn.incomplete:hover {
  background: #fcd34d;
  color: #78350f;
}

.tabs button.tab-btn.incomplete.active {
  background: #fbbf24;
  color: #78350f;
}

.tabs button.tab-btn.incomplete.active::after {
  background: #d97706;
}

/* Slide-out sub-menu (e.g. Courses sub-pages) ------------------ */
.submenu {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin-bottom: 0;
  padding: 0;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transform: translateY(-10px);
  transition: max-height .35s ease, opacity .3s ease,
    transform .35s ease, margin-bottom .35s ease;
}

.submenu.open {
  max-height: 120px;
  margin-bottom: 1.25rem;
  opacity: 1;
  transform: translateY(0);
}

.submenu .submenu-btn {
  flex: none;
  padding: .5rem .95rem;
  background: var(--c-surface-2);
  color: var(--c-text-2);
  border: 1px solid var(--c-border-2);
  border-radius: 999px;
  font-weight: 500;
  white-space: nowrap;
}

.submenu .submenu-btn:hover {
  color: var(--c-text);
  border-color: var(--c-primary);
}

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

/* Animate the active sub-page into view */
.subpage {
  animation: subpage-in .3s ease;
}

/* List-view header: title on the left, "+ create" action on the right */
.subpage-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.subpage-head h2 {
  margin: 0;
}

.subpage-head {
  margin-bottom: 1rem;
}

/* Read-only key/value detail table (e.g. User Details) */
.kv-table {
  max-width: 520px;
}

.kv-table th {
  width: 150px;
  text-align: left;
  color: var(--c-text-2);
  font-weight: 600;
  background: var(--c-surface-2);
}

.subpage-head+table {
  margin-top: 0;
}

.back-btn {
  margin-bottom: .5rem;
}

@keyframes subpage-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Layout ------------------------------------------------------- */
main {
  max-width: 1200px;
  margin: 0 auto;
  padding: 1.75rem 1.25rem 3rem;
}

.panel {
  background: var(--c-surface);
  padding: 1.5rem 1.5rem 1.25rem;
  border-radius: var(--radius);
  border: 1px solid var(--c-border-2);
  box-shadow: var(--shadow-sm);
  margin-bottom: 1.25rem;
  /* Smooth fade/slide-in whenever a panel becomes visible (tab switch). */
  animation: panel-in .32s ease;
}

.panel+.panel {
  margin-top: 0;
}

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

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ── Page transitions ──────────────────────────────────────────────
   Logging in is a real navigation, so the transition is two halves: the
   login card fades out (.is-leaving, below) and the dashboard chrome
   fades in here. Deliberately a plain CSS animation rather than the View
   Transitions API, so Chrome, Edge and Firefox render it identically.

   This doubles as the fix for the flash of empty dashboard: the chrome
   starts transparent, and requireAuth() — the first statement of every
   page script — has redirected a signed-out visitor long before the
   animation ends, so the empty shell is never seen.

   Two things this rule must never do:

   - Collapse to `body:not(.centered) > *`. .to-top and the calendar
     modal backdrop are position:fixed children of <body>; an animated
     ancestor with a transform would become their containing block and
     break the fixed positioning.
   - Grow an animation-fill-mode. `forwards` would hold translateY(0) as
     a computed matrix forever, which is the same problem permanently.
     Without a fill mode the animation also always ends at opacity 1 on
     its own, so a JS error can never strand a blank page.

   <main> is left out on purpose: its .panel children already animate
   with panel-in, and stacking two fades makes the content arrive late
   and dim. */
body:not(.centered)>header.topbar,
body:not(.centered)>.tabs,
body:not(.centered)>.browser-notice,
body:not(.centered)>.app-footer {
  animation: page-enter .38s var(--ease);
}

@keyframes page-enter {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* The other half: the login card drifts down and fades before the
   redirect fires. `forwards` holds the faded-out state so the card
   cannot flicker back during the navigation — index.html clears the
   class on pageshow, which is what makes Back work. */
.is-leaving {
  animation: page-leave .2s var(--ease) forwards;
  pointer-events: none;
}

@keyframes page-leave {
  from {
    opacity: 1;
    transform: translateY(0);
  }

  to {
    opacity: 0;
    transform: translateY(10px);
  }
}

/* Busy spinner for buttons. Buttons are already inline-flex with a gap,
   so this needs no layout rules — only a size and the ring itself.
   currentColor keeps it legible on primary, danger and secondary alike. */
.spinner {
  display: none;
  width: 14px;
  height: 14px;
  flex: none;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin .6s linear infinite;
}

.is-busy .spinner {
  display: inline-block;
}

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

/* Respect users who prefer reduced motion. */
@media (prefers-reduced-motion: reduce) {

  .panel,
  .subpage {
    animation: none;
  }

  /* Not `animation: none` — the movement goes, the fade stays. That fade
     is what keeps the signed-out shell off screen, and a cross-fade with
     no motion is what reduced-motion actually asks for. */
  body:not(.centered)>header.topbar,
  body:not(.centered)>.tabs,
  body:not(.centered)>.browser-notice,
  body:not(.centered)>.app-footer {
    animation: page-enter-flat .2s linear;
  }

  /* navigateWithFade() skips the leave animation outright for these
     users; this keeps the class harmless if applied by other means. */
  .is-leaving {
    animation: none;
    opacity: 0;
  }

  .spinner {
    animation-duration: 1.2s;
  }

  .submenu {
    transition: none;
  }
}

@keyframes page-enter-flat {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

.panel h2 {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding-bottom: .85rem;
  margin-bottom: 1.1rem;
  border-bottom: 1px solid var(--c-border-2);
}

.panel h3 {
  margin-top: 1.5rem;
  margin-bottom: .65rem;
  color: var(--c-text);
  font-size: 14px;
  font-weight: 600;
}

/* Forms / row grid -------------------------------------------- */
.row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem 1rem;
  align-items: end;
}

.row--compact {
  grid-template-columns: repeat(auto-fit, minmax(180px, 220px));
  max-width: 480px;
}

/* Session / course pickers. Their <option> labels carry an id, a course code
   and a timestamp, which the 220px compact column clipped mid-time — the
   teacher could not tell two sittings of the same course apart. Applied on
   top of .row--compact, so the rest of that row's styling still holds.

   340px is measured, not guessed: the longest label in use is the behaviour
   tab's "#142 CSIT226 (8/3/2026, 1:30 PM) [active]" at ~312px, and a select
   spends roughly another 28px on its dropdown arrow and padding.

   Plain px on purpose — minmax(min(100%, 340px), …) inside repeat(auto-fit)
   collapses the track to ~24px, because the percentage has no resolvable
   basis at track-sizing time. Narrow viewports are handled below instead. */
.row--wide-select {
  grid-template-columns: repeat(auto-fit, minmax(340px, 420px));
  max-width: none;
}

@media (max-width: 420px) {
  .row--wide-select {
    grid-template-columns: 1fr;
  }
}

/* Stacked single-column form (one field per row, typical sign-up layout) */
.form-stacked {
  grid-template-columns: 1fr;
  gap: 1rem;
  max-width: 420px;
}

.form-stacked>button {
  align-self: stretch;
  width: 100%;
  margin-top: .25rem;
}

/* Uniform control height inside form rows */
.row label,
form.row label {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  margin: 0;
  min-width: 0;
}

.row input,
.row select,
.row textarea,
form.row input,
form.row select,
form.row textarea {
  height: 38px;
  margin-top: 0;
}

.row textarea,
form.row textarea {
  height: auto;
  min-height: 76px;
}

.row input[type="file"],
form.row input[type="file"] {
  line-height: 1.4;
  padding: .4rem .55rem;
}

.row input[type="checkbox"],
form.row input[type="checkbox"] {
  height: auto;
  width: auto;
}

/* Inline checkbox-style label keeps checkbox + text on one line */
.row label:has(> input[type="checkbox"]),
form.row label:has(> input[type="checkbox"]) {
  flex-direction: row;
  align-items: center;
  gap: .5rem;
  height: 38px;
}

/* Submit button aligns with input row */
form.row>button,
.row>button {
  height: 38px;
  align-self: end;
  white-space: nowrap;
}

/* Attendance config form: top-align labels so all inputs line up even
   though only some fields carry a helper description below the input. */
#att-config-form {
  align-items: start;
}

#att-config-form>button {
  align-self: start;
}

form .row+button,
form>button {
  margin-top: 1rem;
}

form>button[type="submit"] {
  margin-top: 1rem;
}

/* Tables ------------------------------------------------------- */
/* Space between a filter row and the table it controls. */
.row+table,
.row+p+table {
  margin-top: 1rem;
}

table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
  background: var(--c-surface);
  border: 1px solid var(--c-border-2);
  border-radius: var(--radius);
  overflow: hidden;
}

th,
td {
  padding: .7rem .9rem;
  text-align: left;
  border-bottom: 1px solid var(--c-border-2);
  vertical-align: middle;
}

th {
  background: var(--c-surface-2);
  color: var(--c-text-2);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
}

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

tbody tr {
  transition: background var(--transition);
}

tbody tr:hover {
  background: var(--c-surface-2);
}

td button {
  padding: .35rem .65rem;
  font-size: 12px;
}

td button+button {
  margin-left: .35rem;
}

td button:disabled {
  opacity: .45;
  cursor: not-allowed;
}

/* Inline slide-out detail row (e.g. student My Attendance details) */
.detail-row:hover {
  background: transparent;
}

.detail-row>td {
  padding: 0;
  background: var(--c-surface-2);
}

.detail-slide {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .25s ease;
}

.detail-slide.open {
  grid-template-rows: 1fr;
}

.detail-slide>.detail-content {
  min-height: 0;
  overflow: hidden;
  padding: 0 1rem;
}

.detail-slide.open>.detail-content {
  padding: .85rem 1rem;
}

/* Status / badges --------------------------------------------- */
.status-present,
.status-absent,
.status-late,
.status-early_left,
.status-leave,
.status-pending {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  text-transform: capitalize;
}

.status-present {
  color: var(--c-success);
  background: var(--c-success-bg);
}

.status-late {
  color: var(--c-warning);
  background: var(--c-warning-bg);
}

.status-absent {
  color: var(--c-danger);
  background: var(--c-danger-bg);
}

.status-early_left {
  color: var(--c-warning);
  background: var(--c-warning-bg);
}

.status-leave {
  color: var(--c-primary);
  background: var(--c-primary-soft);
}

/* Undecided: the session is still running and this student has no record
   yet. Deliberately neutral — it must not read as a verdict either way. */
.status-pending {
  color: var(--c-text-2);
  background: var(--c-surface-2);
}

.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--c-primary-soft);
  color: var(--c-primary);
  font-size: 12px;
  font-weight: 500;
  text-transform: capitalize;
}

/* Media / camera ---------------------------------------------- */
video,
img.preview,
canvas {
  max-width: 100%;
  border-radius: var(--radius);
  border: 1px solid var(--c-border);
  background: #0f172a;
}

img.preview {
  background: var(--c-surface-2);
}

/* Analytics charts: clean light surface (override the dark camera canvas
   background) so the line/doughnut charts and their legends are readable. */
#ana-trend,
#ana-breakdown,
#sana-trend,
#sana-breakdown,
#monthly-chart {
  background: #ffffff;
  border-color: var(--c-border);
}

/* Centered camera stage (check-in & re-register) -------------- */
.camera-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  margin: 1rem auto 0;
  max-width: 520px;
}

.camera-frame {
  width: 100%;
  display: flex;
  justify-content: center;
  padding: .75rem;
  background: var(--c-surface-2);
  border: 1px solid var(--c-border-2);
  border-radius: var(--radius);
}

.camera-frame video,
.camera-frame canvas,
.camera-frame img.preview {
  display: block;
  width: 100%;
  max-width: 360px;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.camera-frame--dual {
  flex-wrap: wrap;
  gap: .75rem;
}

.camera-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem;
  width: 100%;
}

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

.camera-actions button {
  min-width: 140px;
}

/* Wider scan stage (teacher classroom scan) ------------------- */
.camera-stage--wide {
  max-width: 960px;
}

.camera-stage--wide .camera-frame video,
.camera-stage--wide .camera-frame canvas,
.camera-stage--wide .camera-frame img.preview {
  max-width: 100%;
}

/* Scan action grid: aligned columns --------------------------- */
.scan-actions {
  flex-wrap: nowrap;
  align-items: stretch;
  gap: .75rem;
}

.scan-actions__col {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.scan-actions__col--checks {
  justify-content: center;
}

.scan-actions__col--checks .small {
  display: flex;
  align-items: center;
  gap: .35rem;
}

@media (max-width: 640px) {
  .scan-actions {
    flex-wrap: wrap;
    justify-content: center;
  }
}

.camera-msg {
  width: 100%;
  text-align: center;
  margin: 0;
  min-height: 1em;
}

/* Upload form (re-register face) ------------------------------ */
.upload-form {
  max-width: 420px;
  margin: 1rem auto 0;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}

.upload-form button {
  align-self: flex-end;
  min-width: 140px;
}

/* Face-mode segmented control (used inside .panel) ------------ */
.face-mode-tabs {
  display: inline-flex;
  background: var(--c-surface-2);
  border: 1px solid var(--c-border-2);
  border-radius: 999px;
  padding: 3px;
  gap: 2px;
  margin-bottom: 1rem;
}

.face-mode-btn {
  margin: 0;
  padding: .35rem .9rem;
  background: transparent;
  color: var(--c-text-2);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  border: none;
}

.face-mode-btn:hover {
  background: rgba(15, 23, 42, .04);
  color: var(--c-text);
}

.face-mode-btn.active {
  background: var(--c-surface);
  color: var(--c-primary);
  box-shadow: var(--shadow-sm);
}

/* Responsive --------------------------------------------------- */
@media (max-width: 720px) {
  header.topbar {
    padding: .7rem 1rem;
    flex-wrap: wrap;
    gap: .35rem .75rem;
  }

  header.topbar h1 {
    font-size: .98rem;
  }

  /* Replace the horizontal tab bar with the dropdown on phones. */
  .tabs {
    display: none;
  }

  .tabs-select {
    display: block;
    width: 100%;
    border: none;
    border-bottom: 1px solid var(--c-border-2);
    border-radius: 0;
    background: var(--c-surface);
    padding: .7rem .9rem;
    font-weight: 600;
    color: var(--c-primary);
  }

  main {
    padding: 1rem .75rem 2rem;
  }

  .panel {
    padding: 1.1rem;
  }

  .card {
    padding: 1.5rem;
  }

  th,
  td {
    padding: .55rem .65rem;
  }

  /* Wide data tables: let each table scroll horizontally inside the panel
     instead of forcing the whole page wider than the screen. */
  .panel table {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  .panel table thead th,
  .panel table tbody td {
    white-space: nowrap;
  }

  /* Inline detail / slide-out rows should still wrap normally. */
  .panel table .detail-row td,
  .panel table .detail-content,
  .panel table .detail-content * {
    white-space: normal;
  }

  /* Prevent iOS from auto-zooming when focusing a small-font input. */
  input,
  select,
  textarea {
    font-size: 16px;
  }
}

@media (max-width: 480px) {
  header.topbar {
    padding: .6rem .8rem;
  }

  header.topbar h1 {
    font-size: .9rem;
  }

  /* The email/identity label eats width on tiny screens — hide it; the
     dashboard heading already says which role you're in. */
  header.topbar #who {
    display: none;
  }

  main {
    padding: .85rem .6rem 2rem;
  }

  .panel {
    padding: .9rem;
    border-radius: var(--radius);
  }

  .panel h2 {
    font-size: 1.15rem;
  }

  /* Filter / control rows: stack their inputs full-width so nothing is
     squashed below a usable size. */
  .att-filters>input,
  .att-filters>select,
  .att-filters>label {
    flex: 1 1 100% !important;
    min-width: 0 !important;
  }
}

/* ── Behaviour Analysis Settings (admin) ─────────────────────────────
   A vertical form: course, then the feature switches it applies to, then
   the sensitivity sliders. Deliberately not .form-stacked — that caps at
   420px, which is too narrow for a slider plus its guidance text. */
.beh-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  max-width: 780px;
}

.beh-course {
  max-width: 380px;
}

.beh-switches {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: .6rem 1.5rem;
  padding: .9rem 1.1rem;
  border: 1px solid var(--c-border-2, #e1e4e8);
  border-radius: var(--radius, 8px);
  background: var(--c-surface-2, #f8f9fa);
}

.beh-switches label {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  cursor: pointer;
}

.beh-switches input {
  margin: 0;
  flex: 0 0 auto;
}

.beh-sensitivity {
  border: 1px solid var(--c-border-2, #e1e4e8);
  border-radius: var(--radius, 8px);
  padding: 1rem 1.25rem 1.25rem;
  margin: 0;
}

.beh-sensitivity legend {
  padding: 0 .4rem;
  font-weight: 600;
  font-size: .9rem;
}

.beh-adaptive {
  padding-bottom: .9rem;
  margin-bottom: .4rem;
  border-bottom: 1px solid var(--c-border-2, #eee);
}

.beh-adaptive label {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  cursor: pointer;
}

.beh-adaptive p {
  margin: .3rem 0 0 1.6rem;
}

/* One slider block: header (name + value + reset), track, effect note. */
.beh-slider {
  padding: .9rem 0;
  border-bottom: 1px solid var(--c-border-2, #f0f2f5);
}

.beh-slider:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.beh-slider__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}

.beh-slider__name {
  font-weight: 600;
  font-size: .9rem;
}

.beh-slider__value {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--c-primary, #2a4b7f);
}

.beh-slider__value--default {
  color: var(--c-text-2, #666);
  font-weight: 400;
}

.beh-slider__reset {
  font-size: .75rem;
  padding: 2px 8px;
}

.beh-slider input[type="range"] {
  width: 100%;
  margin: .5rem 0 .35rem;
  accent-color: var(--c-primary, #2a4b7f);
}

.beh-slider__scale {
  display: flex;
  justify-content: space-between;
  font-size: .7rem;
  color: var(--c-text-2, #777);
  margin-top: -.25rem;
}

/* Live explanation of what the current position does to the model. */
.beh-slider__effect {
  font-size: .78rem;
  line-height: 1.5;
  margin: .4rem 0 0;
  padding: .45rem .6rem;
  border-radius: 6px;
  background: var(--c-surface-2, #f6f8fa);
  border-left: 3px solid var(--c-border-2, #d0d7de);
}

.beh-slider__effect--sensitive {
  background: #fff7ed;
  border-left-color: #e3a008;
}

.beh-slider__effect--strict {
  background: #eff6ff;
  border-left-color: #2a4b7f;
}

.beh-save {
  align-self: flex-start;
  min-width: 160px;
}

/* ── Browser support notice (dashboard footer) ─────────────────────── */
.browser-notice {
  margin: 24px auto 32px;
  padding: 12px 16px;
  max-width: 1200px;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-bg);
  color: var(--c-text-2);
}

.browser-notice p {
  margin: 0;
  line-height: 1.55;
}

.browser-notice p+p {
  margin-top: 6px;
}

.browser-notice strong {
  color: var(--c-text);
}

/* Raised to a warning only when the page is on an insecure origin, where the
   camera genuinely will not work — otherwise the notice stays informational. */
.browser-notice-warn {
  color: var(--c-danger);
}

.browser-notice-warn strong {
  color: var(--c-danger);
}

/* Browser marks inside the notice: sit on the text baseline without
   stretching the line, and never shrink when the line wraps. */
.browser-chip {
  white-space: nowrap;
}

.browser-mark {
  display: inline-block;
  width: 15px;
  height: 15px;
  margin-right: 3px;
  vertical-align: -3px;
  flex: none;
  object-fit: contain;
  /* the vendor logos differ in aspect ratio */
}

/* ── Back to top ───────────────────────────────────────────────────── */
.to-top {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 900;
  width: 42px;
  height: 42px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--c-border);
  border-radius: 50%;
  background: var(--c-surface);
  color: var(--c-primary);
  box-shadow: 0 2px 10px rgba(15, 23, 42, .14);
  cursor: pointer;

  /* Hidden by default; `visibility` (not just opacity) keeps it out of the
     tab order and away from clicks while it is faded out. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity .18s ease, transform .18s ease, visibility .18s;
}

.to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.to-top:hover {
  background: var(--c-primary-soft);
  border-color: var(--c-primary);
}

.to-top svg {
  width: 20px;
  height: 20px;
}

@media (max-width: 640px) {
  .to-top {
    right: 14px;
    bottom: 14px;
    width: 38px;
    height: 38px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .to-top {
    transition: none;
  }
}

/* ── Admin: Users omni-search ─────────────────────────────────────── */
.users-search {
  width: 100%;
  max-width: 480px;
  margin-top: .5rem;
}

/* ── Copyright footer ──────────────────────────────────────────────── */
.app-footer {
  margin: 8px auto 24px;
  padding: 14px 16px 0;
  max-width: 1200px;
  border-top: 1px solid var(--c-border);
  text-align: center;
}

.app-footer p {
  margin: 0;
  color: var(--c-muted);
}