/* one column of controls, one of consequences.  the report is the point of
   the page, so it gets the width and the colour; everything else stays out
   of its way. */

:root {
  --ink: #1a1d21;
  --ink-soft: #5a6069;
  --ink-faint: #878d96;
  --bg: #f6f7f9;
  --panel: #ffffff;
  --line: #dfe3e8;
  /* three colours, one meaning each: blue says something, amber warns,
     red is wrong.  a fourth would have to mean something too, and nothing
     on this page is the good news that green would be claiming */
  --accent: #1f5fa9;
  --accent-soft: #eaf1fa;
  --warn: #8a5b00;
  --warn-soft: #fdf3e0;
  --bad: #a4242b;
  --bad-soft: #fbecec;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ink: #e8eaed;
    --ink-soft: #a8aeb6;
    --ink-faint: #7f858d;
    --bg: #14171a;
    --panel: #1c2024;
    --line: #333940;
    --accent: #7fb1ea;
    --accent-soft: #1b2a3d;
    --bad: #f08d92;
    --bad-soft: #382224;
    --warn: #e0b062;
    --warn-soft: #33291a;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 1rem 4rem;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

header, main, footer { max-width: 1180px; margin: 0 auto; }

header { padding: 2.2rem 0 1.4rem; }

h1 {
  margin: 0;
  font-size: 1.7rem;
  letter-spacing: -.01em;
}

.tagline {
  margin: .35rem 0 0;
  color: var(--ink-soft);
  max-width: 60ch;
}

/* what to know before starting: who each half of the page is for, and that
   nothing leaves the computer or survives leaving it.  one voice for all
   three -- a note set fainter than the lines above it reads as a footnote,
   and this one is the reason the save link matters.  no colour either, which
   below would mean error, warning or information and here would mean none */
.intro {
  margin: 1rem 0 0;
  padding-left: 1.1rem;
  max-width: 72ch;
  font-size: .9rem;
  color: var(--ink-soft);
}

.nowrap { white-space: nowrap; }

.intro li { margin-bottom: .4rem; }
.intro li::marker { color: var(--ink-faint); }
.intro strong { color: var(--ink); }

h2 {
  margin: 0 0 .7rem;
  font-size: .95rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-soft);
}

h2 .sub {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--ink-faint);
  margin-left: .5rem;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 1.1rem 1.2rem;
  margin-bottom: 1rem;
}

.hint {
  color: var(--ink-faint);
  font-size: .84rem;
  margin: .6rem 0 0;
}

/* ---- boot ---- */

.boot-line { margin: 0; display: flex; align-items: center; gap: .6rem; }

.spinner {
  width: 15px; height: 15px;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .8s linear infinite;
  flex: none;
}

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

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 3s; }
}

/* ---- header and file picking ---- */

/* the drop box is wide enough to hold "Assignments > Download Grades > CSV"
   on one line: a path that wraps reads as two steps rather than one */
.head-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(22rem, 33rem);
  gap: 1.5rem;
  align-items: start;
}

@media (max-width: 900px) {
  .head-grid { grid-template-columns: 1fr; }
}

/* One file per line.  Side by side they read as a trail of what was loaded;
   stacked, each one is a save button with a reason next to it, which is what
   they are for on a page that keeps nothing between visits. */
.files {
  margin: .9rem 0 0;
  font-size: .85rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .2rem;
}

.file-row {
  display: block;
  line-height: 1.5;
}

.file-k {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-faint);
}

.files a {
  font-family: var(--mono);
  color: var(--accent);
}

.file-note {
  font-size: .74rem;
  color: var(--ink-faint);
  margin-left: .3rem;
}

/* the first thing to do on the page, and it is a target: bigger is easier
   to hit with a file, and easier to find when you don't know what to do */
.drop {
  border: 2px dashed var(--line);
  border-radius: 8px;
  padding: 2.6rem 1.4rem;
  text-align: center;
  transition: background .12s, border-color .12s;
  background: var(--panel);
}

.drop.over {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.drop-main { margin: 0; font-size: 1.5rem; font-weight: 600; }
.drop-sub { margin: .5rem 0 0; color: var(--ink-soft); font-size: .92rem; }

/* the three ways in, one per line and all in the same voice: which of them
   applies to a reader depends on who they are, not on how loud it is */
.drop-sub + .drop-sub { margin-top: .25rem; }

/* where a gradebook export comes from.  left aligned even though the box is
   centred: these are paths to follow, and a centred path is hard to scan */
.drop-how {
  margin: .6rem auto 0;
  padding: .45rem .6rem;
  background: var(--bg);
  border-radius: 5px;
  text-align: left;
  display: table;
  font-size: .78rem;
  line-height: 1.7;
  color: var(--ink-faint);
  white-space: nowrap;
}

.drop-how .where {
  display: inline-block;
  min-width: 5.4rem;
  font-weight: 600;
  color: var(--ink-soft);
}

/* ---- the weight table, which is also the assignments editor ---- */

th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.sortable:hover { color: var(--accent); }

.chip.ass { margin-right: .2rem; }
.chip.ass .chip-k { color: var(--ink); }

.chip.ass.is-off {
  border-style: dashed;
  opacity: .7;
}

.chip.ass.is-off .chip-k { text-decoration: line-through; }

tr.add-row td { border-bottom: none; padding-top: .5rem; }
tr.add-row input { width: 100%; }
tr.add-row input.pct { width: 4.5rem; }

button.plus {
  width: 1.6rem;
  height: 1.6rem;
  padding: 0;
  border-radius: 50%;
  font-size: 1.1rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* the two places a drag can start behave the same way */
#weight-table [data-ass] { cursor: grab; touch-action: none; }

#drag-ghost.is-over { background: var(--accent); }

table.weights {
  margin-top: 1rem;
  margin-bottom: .4rem;
  /* widths come from the colgroup, so a chip appearing in one column can't
     re-lay the others out while the cursor is still over them */
  table-layout: fixed;
  width: 100%;
}
table.weights td.name, table.weights td:last-child {
  overflow-wrap: anywhere;
}
table.weights td.cat { font-weight: 600; }
table.weights tr.grp td { border-top: 1px solid var(--line); }
table.weights td.strong { font-weight: 600; }
table.weights th, table.weights td { padding-right: .8rem; }

/* one export's inputs, and only the selected one's are in the page */
#export-mode { margin-bottom: .9rem; }

.export-pane .row { margin-top: .8rem; }

.export-pane .drop-inline { margin-top: 0; }

/* ---- the canvas template box ---- */

.drop-inline {
  padding: .8rem 1rem;
  margin-bottom: .8rem;
  text-align: left;
}

.drop-inline .drop-main { font-size: .95rem; }
.drop-inline .drop-sub { margin-top: .2rem; }

.drop-inline.is-set {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent-soft);
}

.drop-inline.is-set .drop-main { color: var(--accent); }

.tick { font-weight: 700; margin-right: .2rem; }

/* ---- a problem shown where the thing it is about is ---- */

.row-warn {
  font-family: system-ui, sans-serif;
  font-size: .76rem;
  color: var(--warn);
  margin-top: .1rem;
}

tr.dropped td { opacity: .65; }
tr.dropped .row-warn { color: var(--ink-faint); }

/* ---- late days in the student card ---- */

.late-mini { gap: .35rem; }

.late-hit {
  font-variant-numeric: tabular-nums;
  color: var(--bad);
  font-weight: 600;
}

/* what the last edit moved, so a one-point change is not read as nothing */
.delta {
  font-size: .72rem;
  font-weight: 600;
  border-radius: 999px;
  padding: .05rem .35rem;
  margin-right: .35rem;
  vertical-align: middle;
  font-variant-numeric: tabular-nums;
}

/* which way a grade moved is information, not a verdict: an edit that
   lowers a grade is not an error, so the sign says the direction and the
   colour stays out of it */
.delta.up, .delta.down {
  background: var(--accent-soft);
  color: var(--accent);
}

.mini.waived .mini-v {
  color: var(--accent);
  font-style: italic;
}

/* ---- the score / late grids in the student card ---- */

.waive-row.block { display: block; }
.waive-row.block .field-k { display: block; margin-bottom: .4rem; }
.waive-row .field-k .sub { text-transform: none; letter-spacing: 0; }

.grid-group {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  margin-bottom: .35rem;
  flex-wrap: wrap;
}

.grid-k {
  font-family: var(--mono);
  font-size: .76rem;
  color: var(--ink-faint);
  min-width: 3.2rem;
}

.cat-means { margin-bottom: .5rem; }

.chip[role="button"] { user-select: none; }
.chip[role="button"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

button.chip, span.chip[role="button"] {
  display: inline-flex;
  align-items: baseline;
  gap: .3rem;
  font: inherit;
  font-size: .78rem;
  padding: .12rem .5rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink);
  cursor: pointer;
}

button.chip:hover { border-color: var(--accent); }

/* The text inside a chip is where anyone actually grabs it, and a drag that
   begins on a non-draggable child never starts at all -- so the children
   take no pointer events and every press lands on the chip itself. */
.chip-k, .chip-v { pointer-events: none; }

.chip-k { font-family: var(--mono); color: var(--ink-faint); }
.chip-v { font-variant-numeric: tabular-nums; }

/* a blank and a zero are both nothing, and mean different things */
.chip.is-missing { border-style: dashed; }
.chip.is-missing .chip-v { color: var(--ink-faint); font-style: italic; }
.chip.is-zero .chip-v { color: var(--bad); font-weight: 600; }

.chip.is-waived {
  background: var(--accent-soft);
  border-color: transparent;
}

.chip.is-waived .chip-v { color: var(--accent); font-style: italic; }

.chip.is-planned {
  border-style: dotted;
  opacity: .8;
}

.chip.is-planned .chip-v { color: var(--ink-faint); font-style: italic; }

.chip.is-late { background: var(--warn-soft); border-color: transparent; }
.chip.is-late .chip-v { color: var(--warn); font-weight: 600; }

/* a max standing for this student, with the way out of it */
.chip.is-max, .chip.is-sub {
  background: var(--accent-soft);
  border-color: transparent;
  padding-right: .2rem;
}

.chip.is-max .chip-v, .chip.is-sub .chip-v { color: var(--accent);
  font-family: var(--mono); }

.chip.is-max button, .chip.is-sub button {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 1rem;
  line-height: 1;
  padding: 0 .2rem;
  cursor: pointer;
}

.chip.is-max button:hover, .chip.is-sub button:hover { color: var(--bad); }

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

.sub-why { margin: 0 0 .4rem; max-width: 46ch; }

/* ---- dragging one score onto another ---- */

/* touch-action, or a touch drag scrolls the page instead of dragging */
#stud-card [data-score] { cursor: grab; touch-action: none; }

.chip.dragging { opacity: .4; cursor: grabbing; }

.chip.drop-target {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  background: var(--accent-soft);
}

/* the thing under the cursor while dragging: without it there is no way to
   tell a drag that started from one that silently didn't */
#drag-ghost {
  position: fixed;
  z-index: 50;
  pointer-events: none;
  font-family: var(--mono);
  font-size: .78rem;
  padding: .12rem .5rem;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
}

/* ---- the audit log ---- */

details.audit {
  margin-top: .7rem;
  border-top: 1px solid var(--line);
  padding-top: .5rem;
}

details.audit > summary {
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-faint);
  font-weight: 600;
  cursor: pointer;
}

details.audit > summary .sub {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  margin-left: .4rem;
}

.adj-k {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-faint);
  white-space: nowrap;
}

.audit-list {
  margin: .5rem 0 0;
  padding-left: 1.2rem;
  font-size: .82rem;
  line-height: 1.6;
}

.audit-list .ev { color: var(--ink-soft); }

.ev-k {
  display: inline-block;
  min-width: 4.6rem;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-faint);
  margin-right: .4rem;
}

.ev-final { color: var(--ink); font-weight: 600; }
.ev-penalty .ev-k, .ev-penalty { color: var(--warn); }
.ev-waive .ev-k, .ev-substitute .ev-k { color: var(--accent); }

.filebar {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  flex-wrap: wrap;
  margin-bottom: .8rem;
  font-size: .9rem;
}

.file-name { font-weight: 600; }
.file-facts { color: var(--ink-soft); }

/* ---- two column layout ---- */

/* equal halves.  the old 5:7 split was for a config pane beside a wide
   report; with that gone, every pair here is two peers */
.cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  align-items: start;
}

@media (max-width: 900px) {
  .cols { grid-template-columns: 1fr; }
}

textarea {
  width: 100%;
  min-height: 24rem;
  resize: vertical;
  font: 13px/1.5 var(--mono);
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: .7rem .8rem;
  tab-size: 2;
}

textarea:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ---- buttons ---- */

.row { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .7rem; }



button {
  font: inherit;
  font-size: .9rem;
  padding: .45rem .85rem;
  border-radius: 6px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}

button:hover:not(:disabled) { filter: brightness(1.08); }
button:disabled { opacity: .5; cursor: default; }

button.secondary {
  background: transparent;
  color: var(--ink-soft);
  border-color: var(--line);
}

button.link {
  background: none;
  border: none;
  color: var(--accent);
  padding: 0;
  text-decoration: underline;
  font-size: inherit;
}

/* ---- quick add category chips ---- */

.quick { margin-bottom: .6rem; display: flex; gap: .4rem; flex-wrap: wrap; }

.quick button {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: transparent;
  font-size: .82rem;
  padding: .25rem .6rem;
  font-family: var(--mono);
}

.quick .quick-label {
  font-size: .82rem;
  color: var(--ink-faint);
  align-self: center;
  margin-right: .1rem;
}

/* ---- category widgets ---- */

.cat-card {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: .6rem .7rem;
  margin-bottom: .55rem;
  background: var(--bg);
}

.cat-head {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
}

.cat-name {
  font-family: var(--mono);
  font-weight: 600;
  font-size: .95rem;
  min-width: 4rem;
}

.cat-share {
  font-size: .8rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  min-width: 3rem;
}

.cat-late { margin-top: .4rem; display: flex; gap: .8rem; flex-wrap: wrap; }

.cat-hit {
  margin-top: .4rem;
  font-size: .8rem;
  color: var(--ink-faint);
  font-family: var(--mono);
}

/* the same line, in prose rather than assignment names */
.cat-rule {
  margin-top: .4rem;
  font-size: .8rem;
  color: var(--ink-faint);
}

/* one field: its caption and its control, or a group that acts as one */
.f {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .82rem;
  color: var(--ink-soft);
}

/* a gradescope section name is a course, a CRN, a title and a term run
   together, so it is long: let it wrap rather than push its CRN box away */
.banner-sec {
  flex: 0 1 22rem;
  min-width: 0;
  word-break: break-word;
}

.f input[type="number"] {
  width: 4.2rem;
  font: inherit;
  font-size: .85rem;
  padding: .2rem .35rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--ink);
}

button.x {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--ink-faint);
  font-size: 1.15rem;
  line-height: 1;
  padding: 0 .25rem;
}

button.x:hover { color: var(--bad); }

.quick .other { background: transparent; border: 1px dashed var(--line);
  color: var(--ink-soft); }

/* ---- generic fields, chips, small controls ---- */

.field {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  flex-wrap: wrap;
  padding: .5rem 0;
  border-top: 1px solid var(--line);
}

.field:first-of-type { border-top: none; padding-top: 0; }

.field-k {
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-faint);
  min-width: 7.5rem;
}

.unit { font-size: .82rem; color: var(--ink-soft); }

select, input[type="text"], input[type="number"] {
  font: inherit;
  font-size: .85rem;
  padding: .25rem .4rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--panel);
  color: var(--ink);
  max-width: 100%;
}

select:focus-visible, input:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

input.pct { width: 4.5rem; }
input.ltr { width: 3.5rem; font-family: var(--mono); }

button.small { font-size: .8rem; padding: .25rem .6rem; }

.chips { display: flex; gap: .35rem; flex-wrap: wrap; flex: 1 1 8rem; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: .2rem;
  font-family: var(--mono);
  font-size: .8rem;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .1rem .3rem .1rem .55rem;
}

.chip button {
  background: none;
  border: none;
  color: var(--ink-faint);
  padding: 0 .15rem;
  font-size: 1rem;
  line-height: 1;
}

.chip button:hover { color: var(--bad); }

/* ---- substitutions ---- */

.sub-row {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
  font-size: .84rem;
  padding: .25rem 0;
}

.sub-row .name { font-family: var(--mono); }
.arrow { color: var(--ink-faint); font-size: .8rem; }

/* The list of what exists and the controls to add to it each own a line.
   Inside a wrapping flex .field they otherwise share one whenever the list
   happens to be short enough to leave room, so the row the user is aiming
   at moves depending on what is above it. */
#sub-list, #plan-list, .sub-add { flex: 1 0 100%; }

.sub-add {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
  margin-top: .4rem;
}

button.nag {
  background: var(--warn-soft);
  color: var(--warn);
  border-color: transparent;
}

/* ---- letter thresholds ---- */

/* only as wide as its four short columns: stretched across a panel, the eye
   has to travel from a percentage to a letter across empty space */
table.thresh { width: auto; margin-bottom: .3rem; }
table.thresh td { border: none; padding: .12rem .35rem .12rem 0; }
table.thresh td:first-child { padding-left: 0; }
table.thresh .unit { white-space: nowrap; }

/* ---- student card ---- */

.stud-card {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: .6rem .7rem;
  margin-top: .6rem;
}

.stud-head {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  flex-wrap: wrap;
}

/* ---- the note an instructor leaves themselves ---- */

.stud-note { margin: .5rem 0 .2rem; }

.stud-note textarea {
  /* half the panel: a note is a sentence, and a box the width of the page
     invites a paragraph nobody writes.  the tall min-height every other
     textarea here wants is for the yaml, not for three lines of prose */
  width: 50%;
  min-width: 20rem;
  min-height: 0;
  height: auto;
  padding: .3rem .5rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  font: inherit;
  font-size: .82rem;
  resize: vertical;
  background: transparent;
}

.stud-note textarea { color: var(--ink); }
.stud-note textarea::placeholder { color: var(--ink-faint); }
.stud-note textarea:focus { border-color: var(--accent); outline: none; }

.stud-name { font-weight: 600; }
.stud-email { font-family: var(--mono); font-size: .78rem;
  color: var(--ink-faint); }

.stud-file {
  font-family: var(--mono);
  font-size: .78rem;
}

.stud-grade {
  margin-left: auto;
  font-size: 1.1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.stud-letter {
  font-size: .8rem;
  background: var(--accent);
  color: #fff;
  border-radius: 4px;
  padding: .05rem .3rem;
  margin-left: .3rem;
  vertical-align: middle;
}

.stud-rows { margin: .5rem 0 .1rem; }

.mini-row { display: flex; gap: .8rem; flex-wrap: wrap; margin-bottom: .3rem; }
.mini-row.dim { opacity: .72; }

.mini { display: inline-flex; gap: .3rem; align-items: baseline;
  font-size: .8rem; }
.mini-k { font-family: var(--mono); color: var(--ink-faint); }
.mini-v { font-variant-numeric: tabular-nums; }

.waive-row {
  display: flex;
  gap: .5rem;
  align-items: baseline;
  flex-wrap: wrap;
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 1px solid var(--line);
}

/* ---- waivers ---- */

.waive-pick { display: flex; gap: .5rem; flex-wrap: wrap; }

.waive-pick input, .waive-pick select {
  font: inherit;
  font-size: .88rem;
  padding: .35rem .5rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--panel);
  color: var(--ink);
}

.waive-pick input { flex: 1 1 12rem; }

.checks {
  display: flex;
  gap: .8rem;
  flex-wrap: wrap;
  margin: .6rem 0 .2rem;
  padding: .3rem 0;
}

.checks label.f { font-family: var(--mono); font-size: .84rem; }

.waive-table { margin-top: .7rem; margin-bottom: 0; }
.waive-table td { font-size: .84rem; }

.tag.late { background: var(--ink-faint); color: #fff; }

details > summary {
  cursor: pointer;
  font-size: .95rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-soft);
  font-weight: 600;
}

details > summary .sub {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--ink-faint);
  margin-left: .5rem;
}

details[open] > summary { margin-bottom: .7rem; }

/* ---- report ---- */

.verdict {
  font-size: .9rem;
  font-weight: 600;
  padding: .5rem .75rem;
  border-radius: 6px;
  margin-bottom: .9rem;
}

.verdict.ok   { background: var(--accent-soft); color: var(--accent); }
.verdict.bad  { background: var(--bad-soft);  color: var(--bad); }
.verdict.busy { background: var(--accent-soft); color: var(--accent); }

table {
  width: 100%;
  border-collapse: collapse;
  font-size: .87rem;
  margin-bottom: 1.1rem;
}

caption {
  text-align: left;
  font-size: .8rem;
  color: var(--ink-faint);
  padding-bottom: .3rem;
}

th, td {
  text-align: left;
  padding: .3rem .5rem .3rem 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

th {
  font-weight: 600;
  color: var(--ink-soft);
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* the header has to sit over its own column, so both cells take the rule */
th.num, td.num { text-align: right; font-variant-numeric: tabular-nums; }
td.name, td.cat { font-family: var(--mono); font-size: .84rem; }

tr.flag-none td, tr.flag-many td { background: var(--warn-soft); }
tr.flag-error td { background: var(--bad-soft); }

.tag {
  font-family: system-ui, sans-serif;
  font-size: .74rem;
  padding: .05rem .4rem;
  border-radius: 999px;
  margin-left: .35rem;
  white-space: nowrap;
}

.tag.none, .tag.many, .tag.warn { background: var(--warn); color: #fff; }
.tag.error { background: var(--bad); color: #fff; }

.msg {
  font-size: .87rem;
  padding: .45rem .65rem;
  border-radius: 5px;
  margin-bottom: .4rem;
}

.msg.error { background: var(--bad-soft);  color: var(--bad); }
.msg.warn  { background: var(--warn-soft); color: var(--warn); }
/* blue: the page saying something, not warning about it -- nothing is wrong
   with a policy that was kept */
.msg.note  { background: var(--accent-soft); color: var(--accent); }

.msg .what { font-weight: 600; margin-right: .3rem; }

.msg.note .link {
  margin-left: .4rem;
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
}

.error { color: var(--bad); }

.empty { color: var(--ink-faint); font-size: .88rem; }

/* ---- grade distribution ---- */

.stats {
  display: flex;
  gap: 1.6rem;
  flex-wrap: wrap;
  margin: .8rem 0 1rem;
}

.stat .k {
  display: block;
  font-size: .74rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-faint);
}

.stat .v {
  font-size: 1.35rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.dist { display: flex; align-items: flex-end; gap: .5rem; height: 130px; }

.bar-wrap {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  height: 100%;
  min-width: 2.1rem;
}

.bar {
  width: 100%;
  background: var(--accent);
  border-radius: 3px 3px 0 0;
  min-height: 2px;
}

.bar-n { font-size: .78rem; color: var(--ink-soft); }
.bar-k { font-size: .8rem; font-weight: 600; margin-top: .2rem; }

/* ---- inspector ---- */

.grades-head {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: .3rem;
}

.grades-head h2 { margin-bottom: 0; }
.grades-head .row { margin-top: 0; margin-left: auto; }

.inspect-controls {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin-left: auto;
  align-items: center;
}

.seg { display: inline-flex; border: 1px solid var(--line);
  border-radius: 6px; overflow: hidden; }

.seg button {
  background: var(--panel);
  color: var(--ink-soft);
  border: none;
  border-left: 1px solid var(--line);
  border-radius: 0;
  font-size: .8rem;
  padding: .3rem .65rem;
}

.seg button:first-child { border-left: none; }
.seg button.on { background: var(--accent); color: #fff; }
.seg button:disabled { opacity: .4; }

#chart { min-height: 340px; }

#mode-hint { margin-bottom: .5rem; }

footer {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  color: var(--ink-faint);
  font-size: .85rem;
}

footer a { color: var(--accent); }

code {
  font-family: var(--mono);
  font-size: .85em;
  background: var(--bg);
  padding: .1rem .3rem;
  border-radius: 3px;
}

/* ------------------------------------------------------ a student's page

   One student in a gradebook is somebody looking at their own grade, and
   this is the same page with the instructor's half taken out rather than a
   second page saying the same things differently -- a second page is a
   second chance to disagree about what a policy means.  Everything that
   edits the policy goes; what is left reads. */

body.solo .instructor-only { display: none; }

/* a score, as a box holding what it is.  the same chip as everywhere else,
   with room for an answer in it */
.chip.whatif {
  padding-right: .45rem;
  cursor: text;
}

.chip.whatif .chip-v {
  display: inline-flex;
  align-items: baseline;
  gap: .15rem;
  pointer-events: auto;
}

.chip.whatif input {
  width: 3.2rem;
  font: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--ink);
  background: none;
  border: none;
  border-bottom: 1px solid var(--line);
  padding: 0 .1rem;
}

.chip.whatif input:focus {
  outline: none;
  border-bottom-color: var(--accent);
}

/* no spinners: fifteen pairs of arrows is a lot of furniture for a gesture
   nobody performs -- a score is typed, not nudged one point at a time */
.chip.whatif input::-webkit-outer-spin-button,
.chip.whatif input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}

.chip.whatif input {
  -moz-appearance: textfield;
  appearance: textfield;
}

.chip.whatif .of { color: var(--ink-faint); font-size: .75rem; }

/* a score that is supposed rather than given.  it has to be obvious at a
   glance which numbers on the page are real, because the page is about to
   be quoted back at somebody */
.chip.whatif.is-supposed {
  background: var(--accent-soft);
  border-color: var(--accent);
  border-style: dashed;
}

.chip.whatif.is-supposed input { color: var(--accent); font-weight: 600; }

.chip.whatif.is-planned { border-style: dashed; }
.chip.whatif.is-planned input::placeholder { color: var(--ink-faint); }

/* days late, which on a student's page is a box rather than a reading.  it
   sits in the same kind of chip as a score so the two rows read alike */
.chip.late-c.whatif input { width: 2.2rem; }

/* forgiving a penalty is a different act from saying how late it was, so it
   is its own target rather than the whole chip -- a student typing days into
   a box that also forgave on a stray click would forgive by accident */
.chip-forgive {
  pointer-events: auto;
  margin-left: .35rem;
  font: inherit;
  font-size: .7rem;
  color: var(--ink-faint);
  background: none;
  border: none;
  border-bottom: 1px dotted var(--line);
  padding: 0;
  cursor: pointer;
}

.chip-forgive:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* where this student's own letter falls, among the cutoffs that placed it */
.mini.is-mine {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 700;
}

/* what the estimate is assuming about this reader in particular.  the policy
   they were given is the class's, so anything here they put in themselves */
.waive-row.adjust .chips { margin-bottom: .4rem; }

.chip.is-adjust {
  background: var(--warn-soft);
  border-color: transparent;
  padding-right: .15rem;
}

.chip.is-adjust .chip-v { color: var(--warn); }

.chip.is-adjust button {
  background: none;
  border: none;
  color: var(--ink-faint);
  padding: 0 .15rem;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.chip.is-adjust button:hover { color: var(--bad); }

