/* components.css — buttons, cards, tables, badges, toast, empty states. */

/* Buttons — 44px min touch target: logging a session happens on a phone. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-2) var(--sp-4);
  font: inherit;
  font-size: .9375rem;
  font-weight: 550;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  cursor: pointer;
  text-decoration: none;
  transition: background .12s ease, border-color .12s ease;
}
.btn:hover { background: var(--paper-3); }
.btn:active { transform: translateY(1px); }

.btn--primary {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}
.btn--primary:hover { filter: brightness(1.08); background: var(--accent); }

.btn--quiet { background: transparent; border-color: transparent; color: var(--ink-soft); }
.btn--quiet:hover { background: var(--paper-3); color: var(--ink); }

.btn--danger {
  color: var(--danger-ink);
  border-color: var(--danger-line);
  background: var(--danger-soft);
}

.btn--sm { min-height: 34px; padding: var(--sp-1) var(--sp-3); font-size: .875rem; }
.btn--block { width: 100%; }

.btn[disabled] { opacity: .5; cursor: not-allowed; }

.lang-toggle {
  min-height: 36px;
  padding: var(--sp-1) var(--sp-3);
  font: inherit;
  font-size: .875rem;
  font-weight: 550;
  color: var(--ink-soft);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
}
.lang-toggle:hover { color: var(--ink); background: var(--paper-3); }

/* Cards */

.card {
  padding: var(--sp-4);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}
.card__title {
  margin: 0 0 var(--sp-2);
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.stat__value {
  display: block;
  font-size: 2rem;
  font-weight: 680;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.stat__label { font-size: .875rem; color: var(--ink-soft); }

/* Badges */

.badge {
  display: inline-block;
  padding: 2px var(--sp-2);
  font-size: .75rem;
  font-weight: 600;
  border-radius: 999px;
  background: var(--paper-3);
  color: var(--ink-soft);
  white-space: nowrap;
}
.badge--good { background: var(--good-soft); color: var(--good); }
.badge--warn { background: var(--warn-soft); color: var(--warn); }
.badge--accent { background: var(--accent-soft); color: var(--accent); }

/* Tables — scroll the table, never the page. */

.table-wrap {
  overflow-x: auto;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
th, td { padding: var(--sp-3); text-align: left; white-space: nowrap; }
th {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-bottom: 1px solid var(--line);
}
tbody tr + tr td { border-top: 1px solid var(--line); }
tbody tr:hover td { background: var(--paper-2); }

/* Empty / placeholder states */

.empty {
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  background: var(--paper);
  border: 1px dashed var(--line);
  border-radius: var(--r-lg);
}
.empty h2 { margin-bottom: var(--sp-2); }
.empty p { max-width: 46ch; margin-inline: auto; color: var(--ink-soft); }
.empty__actions { margin-top: var(--sp-4); }

.placeholder {
  padding: var(--sp-5);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.placeholder__tag {
  display: inline-block;
  margin-bottom: var(--sp-3);
  padding: 2px var(--sp-2);
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: var(--r-sm);
}
.placeholder ul { color: var(--ink-soft); }

/* Toast */

.toast {
  position: fixed;
  left: 50%;
  bottom: var(--sp-5);
  transform: translate(-50%, 12px);
  max-width: min(90vw, 44ch);
  padding: var(--sp-3) var(--sp-4);
  font-size: .9375rem;
  color: var(--paper);
  background: var(--ink);
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
  z-index: 60;
}
.toast[data-open="true"] { opacity: 1; transform: translate(-50%, 0); }
.toast[data-tone="error"] { background: #7a1b1b; color: #ffffff; }

/* Forms */

.field { display: flex; flex-direction: column; gap: var(--sp-1); }
.field > label { font-size: .875rem; font-weight: 550; }
.field__hint { font-size: .8125rem; color: var(--ink-faint); }

input[type="text"], input[type="date"], input[type="time"],
input[type="number"], select, textarea {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-3);
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
textarea { min-height: 88px; resize: vertical; }

.file-drop {
  display: block;
  padding: var(--sp-5);
  text-align: center;
  color: var(--ink-soft);
  background: var(--paper-2);
  border: 1px dashed var(--line);
  border-radius: var(--r-lg);
  cursor: pointer;
}
.file-drop:hover { background: var(--paper-3); color: var(--ink); }
.file-drop[data-drag="true"] { border-color: var(--accent); background: var(--accent-soft); }

/* A file input styled as a button or drop zone: the label is the control, so
   the native "Choose File / No file chosen" widget must not also show. */
.file-drop input[type="file"],
.btn input[type="file"] { display: none; }

select {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-3);
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

/* Error text. A class rather than an inline style, so it follows the theme. */
.is-error { color: var(--danger-ink); }

/*
 * Touch targets.
 *
 * Compact controls are fine with a mouse and are not fine with a thumb, so on
 * a coarse pointer everything interactive grows to 44px — the size WCAG 2.5.5
 * asks for. Measured on the tutor dashboard, where the small chips, the nav
 * and the header controls were all landing between 34 and 39px.
 */
@media (pointer: coarse) {
  .btn--sm,
  .nav__link,
  .lang-toggle,
  .role-picker__select,
  .chip {
    min-height: 44px;
  }
  .nav__link { display: inline-flex; align-items: center; }
  .lang-toggle, .role-picker__select { padding-inline: var(--sp-3); }
}

/* Shown only while a view module is still arriving on a slow connection. */
.view-loading {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-5);
  color: var(--ink-soft);
}
.view-loading__spinner {
  width: 18px; height: 18px; flex: none;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: view-spin .7s linear infinite;
}
@keyframes view-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .view-loading__spinner { animation: none; border-top-color: var(--line); }
}

/* A control mid-action reads as busy to assistive tech, not just visually. */
.btn[data-busy="true"] { opacity: .7; cursor: progress; }

/* ------------------------------------------------------------------ *
 * Sample-data banner
 *
 * Sits above every screen while program.sampleData is true. Loud enough that
 * nobody demos the app and walks away thinking they saw real records, and
 * dismissible only by explicitly saying the data is real.
 * ------------------------------------------------------------------ */

.sample-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  max-width: 1040px;
  margin: 0 auto;
  padding: var(--sp-3) var(--sp-4);
  background: var(--warn-soft);
  border-bottom: 1px solid var(--warn);
  color: var(--ink);
}
.sample-banner__mark {
  display: grid;
  place-items: center;
  flex: none;
  width: 24px; height: 24px;
  font-weight: 700;
  color: var(--warn-soft);
  background: var(--warn);
  border-radius: 50%;
}
.sample-banner__body { flex: 1 1 260px; display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: baseline; }
.sample-banner__text { font-size: .875rem; color: var(--ink-soft); }
.sample-banner__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* The banner is chrome, not part of the record. */
@media print { .sample-banner { display: none; } }
