/* UOW2 reporting dashboard.
 *
 * Tokens are semantic, never colour names: --status-completed rather than
 * --green, so a theme change is a token change and nothing else. Two themes,
 * dark first because one of these ends up on a projector.
 *
 * No framework and no webfont. Every number is tabular so a column of durations
 * compares by eye, and no status is signalled by colour alone.
 */

:root {
  --bg: #14171a;
  --bg-raised: #1c2126;
  --bg-sunken: #0f1214;
  --bg-hover: #232a31;
  --border: #2c343c;
  --border-strong: #3b454f;

  --text: #e6eaee;
  --text-dim: #97a3ae;
  --text-faint: #6b7783;

  --accent: #4a9d78;
  --accent-text: #0f1214;
  --focus: #6fb3ff;

  --status-completed: #4a9d78;
  --status-incomplete: #c99a3f;
  --status-unknown: #6b7783;
  --status-failed: #c76d63;
  --status-active: #5b8fc9;

  --phase-choice: #5b8fc9;
  --phase-consequence: #b07cc6;
  --phase-reading: #4a9d78;
  --phase-negotiation: #97a3ae;
  --phase-other: #4a545e;

  --warn-bg: #33291266;
  --warn-border: #7a6224;
  --error-bg: #3a1f1c66;
  --error-border: #8a4038;

  /* Pie slices: same family, different shade, so two wrongs are not one blob
     and two info options are not one blue. Never yellow for wrong. */
  --pie-wrong-0: #d0726a;
  --pie-wrong-1: #c44a62;
  --pie-wrong-2: #b55a40;
  --pie-wrong-3: #9a4d6e;
  --pie-info-0: #5b8fc9;
  --pie-info-1: #3d7ec4;
  --pie-info-2: #7aa3d4;
  --pie-info-3: #5a6ec9;

  --radius: 6px;
  --gap: 12px;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    sans-serif;
}

[data-theme="light"] {
  --bg: #f6f7f8;
  --bg-raised: #ffffff;
  --bg-sunken: #eceef0;
  --bg-hover: #e6e9ec;
  --border: #d7dce1;
  --border-strong: #b9c2cb;

  --text: #1a1f24;
  --text-dim: #5a656f;
  --text-faint: #8b959e;

  --accent: #2f6f4f;
  --accent-text: #ffffff;

  --status-completed: #2f6f4f;
  --status-incomplete: #97701d;
  --status-unknown: #8b959e;
  --status-failed: #a63e33;
  --status-active: #2f5f96;

  --phase-choice: #2f5f96;
  --phase-consequence: #7c4a92;
  --phase-reading: #2f6f4f;
  --phase-negotiation: #5a656f;
  --phase-other: #c3cad1;

  --warn-bg: #fdf5e2;
  --warn-border: #d8bd6a;
  --error-bg: #fcecea;
  --error-border: #dda49c;

  --pie-wrong-0: #b5443c;
  --pie-wrong-1: #9c2f48;
  --pie-wrong-2: #a14a32;
  --pie-wrong-3: #7a3558;
  --pie-info-0: #2f5f96;
  --pie-info-1: #1e5aa8;
  --pie-info-2: #4a7eb0;
  --pie-info-3: #3d4ea3;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.45;
  display: grid;
  grid-template-rows: auto auto auto 1fr;
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

a {
  color: inherit;
}

/* ---------------------------------------------------------------- shell ---- */

.shell {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--border);
  padding: 10px 16px 8px;
}

.shell-top {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.brand {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.brand-group {
  color: var(--accent);
}

.brand-sub {
  color: var(--text-dim);
  font-weight: 400;
}

.tabs {
  display: flex;
  gap: 2px;
  flex: 1;
}

.tabs a {
  padding: 5px 12px;
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text-dim);
  font-weight: 500;
}

.tabs a:hover {
  background: var(--bg-hover);
  color: var(--text);
}

.tabs a[aria-current="page"] {
  background: var(--accent);
  color: var(--accent-text);
}

.shell-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

.connection {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  color: var(--text-dim);
  font-size: 12px;
  white-space: nowrap;
}

.dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--status-unknown);
  flex: none;
}

.dot[data-state="live"] {
  background: var(--status-completed);
}

.dot[data-state="connecting"] {
  background: transparent;
  border: 2px solid var(--status-incomplete);
  animation: pulse 1.4s ease-in-out infinite;
}

.dot[data-state="offline"] {
  background: var(--status-failed);
}

@keyframes pulse {
  50% {
    opacity: 0.25;
  }
}

.status-line {
  margin: 6px 0 0;
  color: var(--text-dim);
  font-size: 12px;
}

button.ghost {
  background: none;
  border: 1px solid var(--border-strong);
  color: var(--text-dim);
  border-radius: var(--radius);
  padding: 4px 9px;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

button.ghost:hover {
  background: var(--bg-hover);
  color: var(--text);
}

/* --------------------------------------------------------------- banners --- */

.banner {
  padding: 8px 16px;
  font-size: 13px;
  border-bottom: 1px solid var(--border);
}

.banner[hidden] {
  display: none;
}

.banner-warn {
  background: var(--warn-bg);
  border-bottom-color: var(--warn-border);
}

.banner-error {
  background: var(--error-bg);
  border-bottom-color: var(--error-border);
}

/* ----------------------------------------------------------------- view ---- */

.view {
  padding: 16px;
  overflow: auto;
}

.view:focus {
  outline: none;
}

.section-title {
  margin: 22px 0 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.section-title:first-child {
  margin-top: 0;
}

.empty {
  padding: 22px 4px;
  color: var(--text-dim);
}

.note {
  color: var(--text-faint);
  font-size: 12px;
  margin: 4px 0 10px;
}

/* ---------------------------------------------------------------- cards ---- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--gap);
}

.card {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.card:hover {
  border-color: var(--border-strong);
  background: var(--bg-hover);
}

.card-name {
  font-weight: 600;
  font-size: 15px;
  margin-bottom: 6px;
}

.card-figure {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  color: var(--text-dim);
  font-size: 13px;
}

.card-figure b {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- tables ---- */

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--bg-sunken);
  border-bottom: 1px solid var(--border-strong);
  text-align: left;
  padding: 7px 9px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
}

tbody td {
  padding: 7px 9px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

tbody tr:hover {
  background: var(--bg-hover);
}

tbody tr[aria-selected="true"] {
  background: var(--bg-hover);
  box-shadow: inset 2px 0 0 var(--accent);
}

.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ------------------------------------------------------- students table ---- */

.student-row {
  cursor: pointer;
}

.student-row.open {
  background: var(--bg-hover);
}

.disclosure {
  display: inline-block;
  width: 12px;
  color: var(--text-faint);
}

/* A student who went round again. Worth noticing without reading the number. */
.retried {
  font-weight: 700;
  color: var(--status-active);
}

.student-attempts > td {
  background: var(--bg-sunken);
  padding: 4px 9px 10px 21px;
}

/* The inner table is a detail of one row, so its header must not float over the
   outer one. */
.student-attempts thead th {
  position: static;
  background: none;
  border-bottom: 1px solid var(--border);
}

.dim {
  color: var(--text-faint);
}

.nowrap {
  white-space: nowrap;
}

.mono {
  font-family: var(--mono);
  font-size: 12px;
}

.sub {
  display: block;
  color: var(--text-faint);
  font-size: 11px;
}

/* A duration the log could not support. Never rendered as a zero. */
.missing {
  color: var(--text-faint);
}

.flash {
  animation: flash 0.6s ease-out;
}

@keyframes flash {
  from {
    background: color-mix(in srgb, var(--accent) 35%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .flash {
    animation: none;
  }
  .dot[data-state="connecting"] {
    animation: none;
  }
}

/* ------------------------------------------------------- pills and chips --- */

.pill {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  border: 1px solid;
  white-space: nowrap;
}

.pill[data-status="completed"] {
  color: var(--status-completed);
  border-color: var(--status-completed);
}

.pill[data-status="incomplete"] {
  color: var(--status-incomplete);
  border-color: var(--status-incomplete);
}

.pill[data-status="unknown"] {
  color: var(--status-unknown);
  border-color: var(--status-unknown);
}

.pill[data-status="failed"] {
  color: var(--status-failed);
  border-color: var(--status-failed);
}

.pill[data-status="active"] {
  color: var(--status-active);
  border-color: var(--status-active);
}

.pill[data-status="not_started"] {
  color: var(--text-faint);
  border-color: var(--border);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
}

.chip {
  font-family: var(--mono);
  font-size: 11px;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  white-space: nowrap;
}

/* Green means the student picked the keyed correct answer. Red means they
   did not. Pale blue means every option on that node is fine (info). Grey
   (plain .chip) means we have no key for that node yet. */
.chip-correct {
  border-color: var(--accent);
  color: var(--accent);
}

.chip-wrong {
  border-color: var(--status-failed);
  color: var(--status-failed);
}

.chip-info {
  border-color: var(--status-active);
  color: var(--status-active);
}

/* One attempt's worth of answers inside a longer history. */
.chip-group {
  display: flex;
  gap: 3px;
  align-items: center;
}

.chip-group + .chip-group {
  margin-left: 8px;
  padding-left: 8px;
  border-left: 1px solid var(--border);
}

.chip-attempt {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text-faint);
}

.warn-marker {
  background: none;
  border: 1px solid var(--warn-border);
  color: var(--status-incomplete);
  border-radius: var(--radius);
  padding: 0 6px;
  font: inherit;
  font-size: 11px;
  cursor: pointer;
  white-space: nowrap;
}

/* --------------------------------------------------------------- filters --- */

.filters {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 12px;
  margin-bottom: 12px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.field label {
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}

input[type="datetime-local"] {
  min-width: 15.5em;
}

input,
select {
  background: var(--bg-sunken);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 5px 7px;
  font: inherit;
  font-size: 13px;
}

.spacer {
  flex: 1;
}

.button {
  display: inline-block;
  background: var(--accent);
  color: var(--accent-text);
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 6px 12px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.button:hover {
  filter: brightness(1.08);
}

.pager {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  color: var(--text-dim);
  font-size: 12px;
}

/* ------------------------------------------------------------- live feed --- */

.live-row {
  display: grid;
  grid-template-columns: 90px 1.4fr 1fr 110px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 15px;
}

.live-row .who {
  font-weight: 600;
}

.live-row .elapsed {
  font-variant-numeric: tabular-nums;
  color: var(--status-active);
  font-weight: 600;
}

.live-clock {
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
}

/* ------------------------------------------------------------------ bars --- */

.bar-row {
  display: grid;
  grid-template-columns: 56px 1fr 62px 54px 78px;
  gap: 10px;
  align-items: center;
  padding: 3px 0;
  font-size: 13px;
}

.bar-track {
  background: var(--bg-sunken);
  border-radius: 3px;
  height: 14px;
  overflow: hidden;
}

.bar-fill {
  height: 100%;
  background: var(--phase-choice);
  border-radius: 3px;
}

.bar-fill.bar-correct {
  background: var(--accent);
}

.bar-fill.bar-wrong {
  background: var(--status-failed);
}

.bar-fill.bar-info {
  background: var(--status-active);
}

.bar-mark-correct {
  color: var(--accent);
}

.bar-mark-wrong {
  color: var(--status-failed);
}

.bar-mark-info {
  color: var(--status-active);
}

/* ----------------------------------------------------------------- pies --- */

.choice-dists {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px 24px;
  margin: 0 0 12px;
}

.pie-block {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 12px;
  align-items: center;
}

.pie-wrap {
  width: 120px;
  height: 120px;
}

.pie {
  width: 100%;
  height: 100%;
}

.pie path,
.pie circle:not(.pie-empty) {
  stroke: var(--bg);
  stroke-width: 1.75;
}

.pie-empty {
  fill: var(--bg-sunken);
  stroke: var(--border-strong);
  stroke-width: 2;
}

.pie-slice-correct {
  fill: var(--accent);
  background: var(--accent);
}

.pie-slice-wrong-0 {
  fill: var(--pie-wrong-0);
  background: var(--pie-wrong-0);
}

.pie-slice-wrong-1 {
  fill: var(--pie-wrong-1);
  background: var(--pie-wrong-1);
}

.pie-slice-wrong-2 {
  fill: var(--pie-wrong-2);
  background: var(--pie-wrong-2);
}

.pie-slice-wrong-3 {
  fill: var(--pie-wrong-3);
  background: var(--pie-wrong-3);
}

.pie-slice-info-0 {
  fill: var(--pie-info-0);
  background: var(--pie-info-0);
}

.pie-slice-info-1 {
  fill: var(--pie-info-1);
  background: var(--pie-info-1);
}

.pie-slice-info-2 {
  fill: var(--pie-info-2);
  background: var(--pie-info-2);
}

.pie-slice-info-3 {
  fill: var(--pie-info-3);
  background: var(--pie-info-3);
}

.pie-slice-unkeyed {
  fill: var(--phase-negotiation);
  background: var(--phase-negotiation);
}

.pie-slice-unauthored {
  fill: var(--text-faint);
  background: var(--text-faint);
}

.pie-legend {
  display: grid;
  gap: 5px;
}

.pie-legend-row {
  display: grid;
  grid-template-columns: 12px 52px 48px 44px minmax(56px, 1fr);
  gap: 8px;
  align-items: center;
  font-size: 13px;
}

.pie-swatch {
  width: 12px;
  height: 12px;
  border-radius: 2px;
  box-shadow: inset 0 0 0 1px #0003;
}

.bar-row.drift .bar-fill {
  background: var(--status-failed);
}

/* A row where the two records of a choice disagree in the direction that means
   a log stamp is missing. */
tbody tr.drift,
tbody tr.drift:hover {
  background: var(--error-bg);
}

.answers-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 18px 0 4px;
  gap: 12px;
}

.dist-block {
  margin: 0 0 10px;
}

.dist-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin: 6px 0 2px;
  font-size: 12px;
}

/* ----------------------------------------------------------------- panel --- */

.backdrop {
  position: fixed;
  inset: 0;
  background: #0006;
  z-index: 30;
}

.backdrop[hidden],
.panel[hidden] {
  display: none;
}

.panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(560px, 100%);
  z-index: 31;
  background: var(--bg-raised);
  border-left: 1px solid var(--border-strong);
  overflow: auto;
  padding: 16px 18px 40px;
}

.panel-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 4px;
}

.panel h2 {
  margin: 0;
  font-size: 17px;
}

.panel-meta {
  color: var(--text-dim);
  margin: 2px 0;
  font-size: 13px;
}

.strip {
  display: flex;
  gap: 2px;
  height: 30px;
  margin: 12px 0 2px;
  background: var(--bg-sunken);
  border-radius: var(--radius);
  overflow: hidden;
}

.strip-seg {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
  overflow: hidden;
  white-space: nowrap;
  min-width: 2px;
}

.strip-seg[data-phase="choice"] {
  background: var(--phase-choice);
}

.strip-seg[data-phase="consequence"] {
  background: var(--phase-consequence);
}

.strip-seg[data-phase="reading"] {
  background: var(--phase-reading);
}

.strip-seg[data-phase="other"] {
  background: var(--phase-other);
  color: var(--text-dim);
}

/* An unpaired span: started and never ended. Deliberately looks unfinished. */
.strip-seg[data-unpaired="true"] {
  background: repeating-linear-gradient(
    45deg,
    var(--border-strong) 0 4px,
    transparent 4px 8px
  );
  min-width: 10px;
}

.legend {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  color: var(--text-dim);
  font-size: 11px;
}

.legend span::before {
  content: "";
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  margin-right: 4px;
  background: var(--phase-other);
}

.legend .choice::before {
  background: var(--phase-choice);
}
.legend .consequence::before {
  background: var(--phase-consequence);
}
.legend .reading::before {
  background: var(--phase-reading);
}

/* A legend whose items carry their own mark, so no colour swatch is drawn. */
.legend-marks span::before {
  content: none;
}

.legend-marks {
  margin-top: 12px;
  gap: 16px;
}

.warn-list {
  margin: 0;
  padding-left: 18px;
  color: var(--status-incomplete);
}

.warn-list li {
  margin-bottom: 5px;
}

.panel-link {
  display: block;
  margin-top: 18px;
  padding: 9px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  width: 100%;
}

.panel-link:hover {
  background: var(--bg-hover);
}

/* --------------------------------------------------------------- details --- */

details {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-raised);
  margin-bottom: 10px;
}

summary {
  padding: 9px 12px;
  cursor: pointer;
  font-weight: 600;
}

details > *:not(summary) {
  padding: 0 12px 12px;
}

/* -------------------------------------------------------------- skeleton --- */

.skeleton {
  height: 13px;
  margin: 9px 0;
  border-radius: 3px;
  background: var(--bg-hover);
  animation: shimmer 1.3s ease-in-out infinite;
}

@keyframes shimmer {
  50% {
    opacity: 0.45;
  }
}

/* ----------------------------------------------------------------- login --- */

.login-body {
  display: grid;
  place-items: center;
  min-height: 100%;
  background: var(--bg);
}

.login-card {
  width: min(400px, calc(100% - 32px));
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 26px 26px 22px;
}

.login-card h1 {
  margin: 0 0 4px;
  font-size: 19px;
}

.login-lead {
  margin: 0 0 18px;
  color: var(--text-dim);
}

.login-card form {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.login-card label {
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.login-card input {
  font-family: var(--mono);
}

.login-card button {
  margin-top: 6px;
  background: var(--accent);
  color: var(--accent-text);
  border: none;
  border-radius: var(--radius);
  padding: 9px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.login-card button[disabled] {
  opacity: 0.6;
  cursor: default;
}

.login-error {
  margin: 2px 0 0;
  padding: 7px 9px;
  border-radius: var(--radius);
  background: var(--error-bg);
  border: 1px solid var(--error-border);
  font-size: 13px;
}

.login-error[hidden] {
  display: none;
}

.login-note {
  margin: 18px 0 0;
  color: var(--text-faint);
  font-size: 12px;
}
