/* Admin interface — deliberately a different surface from the public pages.
   Dense, full-width, desk-first. The public side is for children; this is an
   instrument.

   The palette is not invented. db/packs/4-mathematics-en/generate_assets.py
   declares INK/ACCENT/SHADE/GRID and draws every diagram with them, so the
   admin adopts the same values and the SVGs sit natively in the page instead
   of clashing with it. */

:root {
  --ink:    #1a1a1a;
  --accent: #0b6fa4;
  --shade:  #f4a340;  /* attention ONLY — missing figure, difficulty 3, warning */
  --grid:   #c9ccd1;
  --paper:  #fbfbfa;
  --slate:  #0f1720;

  --rail-width: 260px;
  --bar-height: 52px;

  /* Red is forbidden on the child-facing surface and always will be. It is
     allowed here because this file dresses staff screens only, and a teacher
     deleting a class needs the validation list and the destructive control to
     read as exactly that. Kept as properties so the two never drift apart. */
  --error:      #b3261e;
  --error-tint: #fdecea;

  /* IBM Plex first: one superfamily covers Latin, Devanagari and monospace, so
     `title` and `title_ne` sit on the same skeleton instead of Devanagari being
     a fallback bolted onto a Latin face. The stack degrades to system faces
     that also carry Devanagari, so nothing renders as tofu if Plex is absent. */
  --font-ui:   "IBM Plex Sans", "IBM Plex Sans Devanagari", "Noto Sans Devanagari", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

body.admin {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.5;
}

/* ── Top bar ───────────────────────────────────────────────────────── */

.admin-bar {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  height: var(--bar-height);
  padding: 0 1rem;
  background: var(--slate);
  color: var(--paper);
}

.admin-bar__mark {
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--paper);
  text-decoration: none;
}

.admin-bar__context { flex: 1; color: var(--grid); }

.admin-bar__user {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--grid);
}

.admin-bar__signout {
  background: none;
  border: 1px solid var(--grid);
  border-radius: 3px;
  color: var(--paper);
  cursor: pointer;
  font: inherit;
  padding: 0.2rem 0.6rem;
}

/* ── Body: full-height rail beside a full-width canvas ─────────────── */

.admin-body {
  display: flex;
  min-height: calc(100vh - var(--bar-height));
}

.admin-rail {
  width: var(--rail-width);
  flex: 0 0 var(--rail-width);
  background: var(--slate);
  color: var(--grid);
  padding: 1rem 0;
  overflow-y: auto;
}

.admin-rail:empty { display: none; }

/* No max-width. The content is dense and wide and the admin is at a desk. */
.admin-canvas { flex: 1; min-width: 0; padding: 1.5rem 2rem; }

.admin-canvas h1 { font-size: 1.4rem; font-weight: 600; margin: 0 0 1rem; }

/* Stable ids are data — they key the importer and get quoted in bug reports —
   so they read as data rather than as prose. */
.id { font-family: var(--font-mono); font-size: 0.85em; color: var(--accent); }

@media (max-width: 900px) {
  .admin-body { flex-direction: column; }
  .admin-rail { width: auto; flex: none; }
}

/* ── The library ───────────────────────────────────────────────────── */

.admin-grade { margin-bottom: 2rem; }

.admin-grade__heading {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--grid);
  padding-bottom: 0.35rem;
  margin: 0 0 0.75rem;
}

.admin-grade__slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.75rem;
}

.admin-slot {
  display: block;
  border: 1px solid var(--grid);
  border-radius: 4px;
  padding: 0.75rem;
  background: #fff;
  color: var(--ink);
  text-decoration: none;
}

a.admin-slot:hover { border-color: var(--accent); }

.admin-slot--empty { background: transparent; border-style: dashed; opacity: 0.6; }

.admin-slot__subject { display: block; font-weight: 600; }

.admin-slot__counts {
  display: block;
  font-size: 0.8rem;
  color: #5b6570;
  margin-bottom: 0.5rem;
}

.admin-slot__warn {
  display: inline-block;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  color: var(--shade);
  font-weight: 600;
}

/* ── Coverage ribbon ───────────────────────────────────────────────── */

.ribbon { display: flex; gap: 1px; height: 8px; margin-bottom: 2px; }

.ribbon__segment {
  display: flex;
  position: relative;
  gap: 1px;
  min-width: 2px;
  background: var(--grid);
}

.ribbon__band { display: block; }

/* Difficulty reads as increasing weight, not as three unrelated hues.
   Level 3 lands on --shade because multi-step items are what an operator
   checks a thin lesson for. */
.ribbon__band--d1 { background: #a9c9dd; }
.ribbon__band--d2 { background: var(--accent); }
.ribbon__band--d3 { background: var(--shade); }

.ribbon__notch {
  position: absolute;
  inset: 0;
  border: 1.5px solid var(--shade);
  border-radius: 1px;
}

/* ── Rail contents ─────────────────────────────────────────────────── */

.rail-pack {
  padding: 0 1rem 0.75rem;
  font-weight: 600;
  color: var(--paper);
  border-bottom: 1px solid #22303c;
  margin-bottom: 0.5rem;
}

.rail-lesson {
  display: block;
  padding: 0.4rem 1rem;
  color: var(--grid);
  text-decoration: none;
  border-left: 3px solid transparent;
}

.rail-lesson:hover { background: #16222c; }

.rail-lesson--current { border-left-color: var(--accent); background: #16222c; color: var(--paper); }

.rail-lesson__title { display: block; }

.rail-lesson__title-ne { display: block; font-size: 0.85em; color: #8b96a1; }

/* ── Canvas furniture ──────────────────────────────────────────────── */

.admin-meta { color: #5b6570; margin: 0 0 1rem; }

.admin-title-ne { font-size: 0.85em; color: #5b6570; }

.admin-warnings {
  border-left: 3px solid var(--shade);
  background: #fdf6ec;
  padding: 0.75rem 1rem;
  margin-bottom: 1.5rem;
}

.admin-warnings h2 { font-size: 0.85rem; margin: 0 0 0.5rem; text-transform: uppercase; letter-spacing: 0.06em; }

.admin-warnings ul { margin: 0; padding-left: 1.1rem; font-family: var(--font-mono); font-size: 0.8rem; }

.admin-table { width: 100%; border-collapse: collapse; }

.admin-table th {
  text-align: left;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #5b6570;
  border-bottom: 1px solid var(--grid);
  padding: 0.4rem 0.5rem;
}

.admin-table td { border-bottom: 1px solid var(--grid); padding: 0.5rem; vertical-align: top; }

.admin-table a { color: var(--ink); text-decoration: none; }
.admin-table a:hover { color: var(--accent); }

.admin-table__ribbon { width: 40%; }
.admin-table__ribbon .ribbon { height: 12px; margin: 0; }

/* ── Pack switcher ─────────────────────────────────────────────────── */

.pack-switcher select {
  font: inherit;
  background: #16222c;
  color: var(--paper);
  border: 1px solid #22303c;
  border-radius: 3px;
  padding: 0.2rem 0.4rem;
}

/* ── Lesson screen ─────────────────────────────────────────────────── */

.admin-block { margin-bottom: 1.75rem; }

.admin-block h2 {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #5b6570;
  border-bottom: 1px solid var(--grid);
  padding-bottom: 0.3rem;
  margin: 0 0 0.6rem;
}

.admin-block ul { margin: 0; padding-left: 1.1rem; }

/* The error half of a misconception is quoted student thinking, not a
   warning — so it is set apart without --shade, which means attention. */
.admin-misconception__error { color: #5b6570; font-style: italic; }

/* ── Topic screen ──────────────────────────────────────────────────── */

.topic-assets { display: flex; flex-wrap: wrap; gap: 1rem; }

.topic-asset { margin: 0; border: 1px solid var(--grid); padding: 0.5rem; background: #fff; }
.topic-asset img { display: block; max-width: 320px; height: auto; }
.topic-asset figcaption { font-size: 0.8rem; color: #5b6570; margin-top: 0.4rem; }

.worked-steps { margin: 0.4rem 0; padding-left: 1.3rem; }
.worked-answer { font-weight: 600; }

.item__difficulty { font-family: var(--font-mono); letter-spacing: 0.1em; white-space: nowrap; }

.item__choices { margin: 0.3rem 0 0; padding-left: 1.1rem; font-size: 0.9em; }
.item__choice--answer { font-weight: 600; color: var(--accent); }

.item__aid { color: #5b6570; font-size: 0.9em; }

.item__figure { max-width: 240px; height: auto; display: block; margin-top: 0.4rem; }

/* A declared figure that is not on disk. --shade earns its use here: this is
   the incompleteness the admin exists to reveal. */
.item--asset-missing { background: #fdf6ec; }
.item__missing { color: var(--shade); font-weight: 600; font-family: var(--font-mono); font-size: 0.8rem; }

/* ── Items screen ──────────────────────────────────────────────────── */

.admin-filters {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.75rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--grid);
}

.admin-filters select {
  font: inherit;
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--grid);
  border-radius: 3px;
  background: #fff;
  color: var(--ink);
}

.admin-filters__clear { color: var(--accent); font-size: 0.85rem; }

/* ── Sidebar sections ──────────────────────────────────────────────── */

/* The rail used to be contextual only -- the pack spine, hidden by
   .admin-rail:empty everywhere else. It now carries persistent nav above that
   spine, so the two need a visible seam or they read as one long list. The
   seam only appears when there is contextual content beneath it. */

.rail-nav:not(:last-child) {
  border-bottom: 1px solid #22303c;
  margin-bottom: 0.75rem;
  padding-bottom: 0.75rem;
}

/* Same idiom as .rail-lesson above: dark ground, --grid text, a left border
   that lights up --accent for the current one. */
.rail-nav__item {
  display: block;
  padding: 0.4rem 1rem;
  color: var(--grid);
  text-decoration: none;
  border-left: 3px solid transparent;
}

.rail-nav__item:hover { background: #16222c; }

.rail-nav__item--current { border-left-color: var(--accent); background: #16222c; color: var(--paper); }

/* ── Forms and actions ─────────────────────────────────────────────── */

/* New surface, not a restyle. The admin was read-only, so it had no form,
   input or button rules at all; /teach rendering under this layout is what
   needs them.
   Scoped to .admin-canvas rather than body.admin: the top bar has its own
   treatments (.admin-bar__signout, .pack-switcher select) that a broader
   selector would quietly outrank. */

.admin-button,
.admin-canvas input[type="submit"] {
  display: inline-block;
  font: inherit;
  background: var(--accent);
  color: var(--paper);
  border: 1px solid var(--accent);
  border-radius: 3px;
  padding: 0.35rem 0.8rem;
  margin: 0 0.5rem 1rem 0;
  text-decoration: none;
  cursor: pointer;
}

/* Darkened by filter rather than a second hex, so the hover cannot drift out
   of step if --accent is ever retuned. */
.admin-button:hover,
.admin-canvas input[type="submit"]:hover { filter: brightness(0.9); }

.admin-canvas .field { margin-bottom: 1rem; }

/* Labels read as column headings do -- small, uppercase, muted -- so a form
   and a table look like the same instrument. */
.admin-canvas .field label {
  display: block;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #5b6570;
  margin-bottom: 0.25rem;
}

/* Values copied from .admin-filters select above, which already settled what
   a control looks like on this surface. */
.admin-canvas input[type="text"],
.admin-canvas input[type="email"],
.admin-canvas input[type="password"],
.admin-canvas select,
.admin-canvas textarea {
  font: inherit;
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--grid);
  border-radius: 3px;
  background: #fff;
  color: var(--ink);
}

.admin-canvas input[type="text"],
.admin-canvas input[type="email"],
.admin-canvas input[type="password"],
.admin-canvas textarea { width: 20rem; max-width: 100%; }

.admin-canvas input:focus,
.admin-canvas select:focus,
.admin-canvas textarea:focus { border-color: var(--accent); }

.admin-canvas .field--checkbox { display: grid; grid-template-columns: auto 1fr; gap: 8px; align-items: center; }
.admin-canvas .field--checkbox .field__hint { grid-column: 1 / -1; margin: 0; font-size: 0.9em; opacity: 0.75; }

.admin-canvas .hint { font-size: 0.8rem; color: #5b6570; margin: 0.25rem 0 0; }

.admin-canvas .form-errors {
  border-left: 3px solid var(--error);
  background: var(--error-tint);
  color: var(--error);
  margin: 0 0 1.25rem;
  padding: 0.75rem 1rem 0.75rem 2.2rem;
}

/* Rails renders button_to as a <form>, which is block -- so Remove would drop
   to its own line and pull every table row taller. */
.admin-canvas .button_to { display: inline-block; }

/* Deliberately not .admin-button: Remove destroys a class and every child in
   it, so it stays quiet until you are actually on it, then reads red.
   :not(.admin-button) because this selector outranks .admin-button on
   specificity -- without the exclusion it captured every button_to on the
   staff surface, which made the review queue's Publish button look exactly
   like a destructive one and left the two verbs indistinguishable. */
.admin-canvas .button_to button:not(.admin-button) {
  font: inherit;
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--grid);
  border-radius: 3px;
  padding: 0.2rem 0.6rem;
  cursor: pointer;
}

.admin-canvas .button_to button:not(.admin-button):hover { border-color: var(--error); color: var(--error); }

/* ── Student report ────────────────────────────────────────────────── */

/* One child, read by a teacher: who they are, how they are doing, and what
   they actually typed. Every rule below serves one of two distinctions the
   page is not allowed to blur — an unscored pool is not a zero, and a
   self-check is not a grade — so neither of them is carried by colour alone.
   No new hex: the whole section is built from the properties above. */

.student-facts,
.student-tally { display: flex; flex-wrap: wrap; gap: 2rem; margin: 0 0 1.5rem; }

.student-facts dt,
.student-tally dt {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #5b6570;
}

.student-facts dd, .student-tally dd { margin: 0.15rem 0 0; }

.student-tally {
  border-top: 1px solid var(--grid);
  border-bottom: 1px solid var(--grid);
  padding: 0.75rem 0;
}

.student-tally dd { font-size: 1.4rem; font-weight: 600; line-height: 1.1; }

/* The share of the figures beside it that nothing checked (D-02). Set apart
   with --shade because "some of this is the child's own word" is exactly the
   kind of thing a teacher should notice before trusting the rest. */
.student-tally__figure--self dt { color: var(--shade); }
.student-tally__figure--self dd { color: var(--shade); }

.student-empty { font-style: italic; }

.student-badges { list-style: none; padding: 0; display: grid; gap: 4px; }

/* ── Mastery ───────────────────────────────────────────────────────── */

.admin-table__mastery { width: 9rem; }

.mastery { display: flex; align-items: center; gap: 0.5rem; white-space: nowrap; }

.mastery__bar {
  display: block;
  width: 4rem;
  height: 6px;
  background: var(--grid);
  border-radius: 3px;
  overflow: hidden;
}

.mastery__fill { display: block; height: 100%; background: var(--accent); }

.mastery__figure { font-family: var(--font-mono); font-size: 0.85em; }

/* A pool with no counted items has no mastery, which is not the same thing as
   scoring zero — so it gets words and no bar at all. A bar drawn at 0% width
   would read as a failing child; the empty track alone would read as one too. */
.mastery--unscored { color: #5b6570; font-style: italic; font-size: 0.85em; }

/* ── Outcome pills ─────────────────────────────────────────────────── */

.outcome {
  display: inline-block;
  border: 1px solid var(--grid);
  border-radius: 10px;
  padding: 0.1rem 0.55rem;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

/* Graded: solid border, the app's own two verdicts. Red is allowed here —
   this file dresses staff screens only, and the child never sees it. */
.outcome--graded-yes { border-color: var(--accent); color: var(--accent); }
.outcome--graded-no { border-color: var(--error); background: var(--error-tint); color: var(--error); }

/* Self-marked: a dashed border, so the difference from a graded verdict
   survives a greyscale print and a colour-blind reader — the label already
   says who judged, and this makes it visible before the label is read. */
.outcome--self {
  border-style: dashed;
  border-color: var(--shade);
  background: #fdf6ec;
  color: #8a5a13;
}

/* Recorded and never judged (a `task` item): deliberately the quietest. */
.outcome--none { color: #5b6570; }

/* ── Answers ───────────────────────────────────────────────────────── */

.answers__when { white-space: nowrap; font-size: 0.85em; color: #5b6570; }

/* "Correct on the third try" is what a teacher is scanning for, so the retry
   is marked and a first try is left unmarked. */
.answers__try {
  display: inline-block;
  margin-left: 0.35rem;
  border: 1px solid var(--shade);
  border-radius: 2px;
  padding: 0 0.25rem;
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--shade);
}

.answers__prompt { max-width: 28rem; }

.answers__where { display: block; font-size: 0.8em; color: #5b6570; margin-top: 0.2rem; }

/* The two answers sit side by side and must not be confusable at a glance:
   what the child wrote is the loud one, in ink; what was expected is quiet
   and dashed off to one side. */
.answers__given { font-family: var(--font-mono); font-weight: 600; max-width: 16rem; word-break: break-word; }

.answers__expected {
  font-family: var(--font-mono);
  font-size: 0.85em;
  color: #5b6570;
  border-left: 2px solid var(--grid);
  padding-left: 0.5rem;
  max-width: 16rem;
  word-break: break-word;
}

/* A correct answer needs no expected answer beside it, so the cell is empty —
   and the rule above would otherwise draw a border down a column of nothing,
   which reads as a missing value rather than as one that was never needed. */
.answers__expected:empty { border-left: 0; }

/* ── Deep lesson review ────────────────────────────────────────────── */

/* The D-13 queue. Status is carried by the word first -- these rules only
   reinforce it -- so the screen still reads correctly in greyscale. */
.admin-status {
  display: inline-block;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--grid);
  border-radius: 3px;
  color: #5b6570;
}

.admin-status--ready { border-color: var(--accent); color: var(--accent); }
.admin-status--published { border-color: #2e7d4f; color: #2e7d4f; }
.admin-status--refused,
.admin-status--failed { border-color: var(--shade); color: #96601a; }

/* button_to renders a <form>, so the row is laid out on the forms rather
   than on the buttons inside them. */
.admin-actions { display: flex; gap: 0.75rem; align-items: center; }
.admin-actions .button_to { margin: 0; }

/* The destructive verb must not look like the primary one. Outline rather
   than filled, so publishing stays the obvious action on the screen. */
.admin-button--quiet {
  background: transparent;
  color: var(--ink);
  border-color: var(--grid);
}

.admin-button--quiet:hover { filter: none; border-color: var(--ink); }

.admin-review-example { border-left: 3px solid var(--grid); padding-left: 1rem; margin-bottom: 1.25rem; }

.admin-review-example svg,
.admin-table svg { max-width: 100%; height: auto; }

.admin-link { color: var(--accent); }
