/* PyPath — the teacher dashboard.
   Reuses the tokens in pypath-theme.css and the --success/--danger fallbacks
   already used by unit-test.css. No !important, and no new z-index values:
   nothing here overlaps the fixed header. */

.cr { margin-top: 1.5rem; }

.cr h2 {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: 2rem 0 .75rem;
  font-size: 1.15rem;
}

/* ---------- the info button that explains a number ---------- */

/* Every metric gets one. A teacher who cannot interrogate a number does not
   trust it, and an untrusted number is worse than none because it still
   occupies the space a usable one would have. */
.cr-info {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  padding: 0;
  border-radius: 50%;
  font: inherit;
  font-size: .7rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  color: var(--muted, #475569);
  background: var(--bg-elevated, #f1f5f9);
  border: 1px solid var(--border, #cbd5e1);
}

.cr-info:hover { color: var(--text-strong, #0f172a); }
.cr-info:focus-visible { outline: 2px solid var(--primary, #0ea5e9); outline-offset: 2px; }

.cr-explain {
  margin: 1rem 0;
  padding: 1rem 1.1rem;
  border: 1px solid var(--border, #cbd5e1);
  border-left: 3px solid var(--primary, #0ea5e9);
  border-radius: .5rem;
  background: var(--panel, #fff);
}

.cr-explain h3 { margin: 0 0 .4rem; font-size: .95rem; }
.cr-explain p { margin: 0 0 .75rem; color: var(--text, #334155); font-size: .88rem; }

/* ---------- top bar ---------- */

.cr-bar {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.cr-bar__right { display: flex; flex-wrap: wrap; gap: .5rem; }

/* ---------- form controls: one look for every input on the page ---------- */

/* The dashboard had grown three different input treatments -- a select in the
   top bar, a date field in the assignment builder, a text field in the share
   form -- each with its own border weight and radius. They are all the same
   kind of thing to a teacher, so they now share one control: a 2px edge that
   the accent takes over on hover, a token radius, and the site focus ring. */
.cr select,
.cr input[type="text"],
.cr input[type="date"],
.cr input[type="search"],
.cr input[type="email"] {
  font: inherit;
  font-size: .88rem;
  font-weight: 600;
  padding: .5rem .7rem;
  border-radius: .6rem;
  color: var(--text-strong, #0f172a);
  background: var(--panel, #fff);
  border: 2px solid var(--border, #cbd5e1);
  transition: border-color var(--dur-fast, 150ms) ease,
              box-shadow var(--dur-fast, 150ms) ease,
              background-color var(--dur-fast, 150ms) ease;
}

.cr select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 2.1rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%234a7390' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .65rem center;
}

[data-theme="dark"] .cr select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2389a8ba' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

.cr select:hover:not(:disabled),
.cr input[type="text"]:hover:not(:disabled),
.cr input[type="date"]:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--primary, #0ea5e9) 55%, var(--border, #cbd5e1));
}

.cr select:focus-visible,
.cr input:focus-visible {
  outline: none;
  border-color: var(--primary, #0ea5e9);
  box-shadow: var(--ring, 0 0 0 4px rgba(14, 165, 233, .15));
}

/* A disabled lens is still readable -- it says "this view exists, it just has
   nothing behind it yet" rather than disappearing. */
.cr select:disabled {
  cursor: not-allowed;
  opacity: .55;
  background-color: var(--bg-elevated, #f1f5f9);
}

.cr input::placeholder { font-weight: 500; color: var(--muted, #475569); opacity: .8; }

/* Safari and Chrome hide the date field's own affordance behind a faint glyph.
   Give it the same weight as the select chevron so the two fields read as one
   family. */
.cr input[type="date"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: .55;
  transition: opacity var(--dur-fast, 150ms) ease;
}

.cr input[type="date"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
[data-theme="dark"] .cr input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(1); }

/* Ticks and radios. Native controls in this palette come out grey on every
   platform and grey is the one colour the grid below already uses for "not
   started", so they get drawn here instead. */
.cr input[type="checkbox"],
.cr input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0;
  cursor: pointer;
  background: var(--panel, #fff);
  border: 2px solid var(--border, #cbd5e1);
  border-radius: .35rem;
  transition: background-color var(--dur-fast, 150ms) ease,
              border-color var(--dur-fast, 150ms) ease;
}

.cr input[type="radio"] { border-radius: 50%; }

.cr input[type="checkbox"]:hover:not(:disabled),
.cr input[type="radio"]:hover:not(:disabled) { border-color: var(--primary, #0ea5e9); }

.cr input[type="checkbox"]:checked,
.cr input[type="radio"]:checked {
  background-color: var(--primary, #0ea5e9);
  border-color: var(--primary, #0ea5e9);
}

.cr input[type="checkbox"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 13 4 4 10-10'/%3E%3C/svg%3E");
  background-size: .7rem;
  background-repeat: no-repeat;
  background-position: center;
}

.cr input[type="radio"]:checked { box-shadow: inset 0 0 0 3px var(--panel, #fff); }

.cr input[type="checkbox"]:focus-visible,
.cr input[type="radio"]:focus-visible {
  outline: none;
  box-shadow: var(--ring, 0 0 0 4px rgba(14, 165, 233, .15));
}

.cr input[type="radio"]:checked:focus-visible {
  box-shadow: inset 0 0 0 3px var(--panel, #fff), var(--ring, 0 0 0 4px rgba(14, 165, 233, .15));
}

/* Unit 1 is ticked and cannot be unticked. It reads as settled rather than
   broken: still filled, just not offering a hand cursor. */
.cr input[type="checkbox"]:disabled,
.cr input[type="radio"]:disabled { cursor: not-allowed; opacity: .6; }

/* ---------- join code ---------- */

.cr-code {
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .9rem;
  background: var(--panel, #fff);
  box-shadow: var(--shadow, 0 4px 20px rgba(12, 69, 102, .07));
}

.cr-code__value {
  margin: .25rem 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: .18em;
  color: var(--text-strong, #0f172a);
}

.cr-code__hint { margin: 0 0 .75rem; color: var(--muted, #475569); font-size: .85rem; }

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

.cr-tablewrap { overflow-x: auto; }

.cr-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .88rem;
}

.cr-table th,
.cr-table td {
  padding: .5rem .6rem;
  text-align: left;
  border-bottom: 1px solid var(--border, #cbd5e1);
  vertical-align: top;
}

.cr-table thead th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted, #475569);
}

.cr-row__who { font-weight: 600; color: var(--text-strong, #0f172a); }
.cr-row__do { color: var(--muted, #475569); }
.cr-link { color: var(--primary-strong, #0284c7); }

/* A left edge that says how urgent, without relying on the colour alone --
   the reason text always states what happened. */
.cr-row--stuck { border-left: 3px solid var(--danger, #dc2626); }
.cr-row--concept { border-left: 3px solid var(--warn, #d97706); }
.cr-row--idle { border-left: 3px solid var(--muted, #475569); }
.cr-row--never-started { border-left: 3px solid var(--border, #cbd5e1); }

/* ---------- mastery grid ---------- */

/* The lens picker and the sort order are one toolbar, not two stray rows of
   inputs above the grid. */
.cr-controls {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem 1.25rem;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .85rem;
  padding: .6rem .75rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .8rem;
  background: color-mix(in srgb, var(--bg-elevated, #f1f5f9) 55%, var(--panel, #fff));
}

.cr-scope {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  align-items: center;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: .88rem;
}

/* Three views of the same class, so they read as one switch with three
   positions rather than three unrelated ticks. */
.cr-scope > label:not(.visually-hidden) {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .6rem;
  border: 2px solid transparent;
  border-radius: .55rem;
  font-weight: 600;
  color: var(--muted, #475569);
  cursor: pointer;
  transition: border-color var(--dur-fast, 150ms) ease,
              background-color var(--dur-fast, 150ms) ease,
              color var(--dur-fast, 150ms) ease;
}

.cr-scope > label:not(.visually-hidden):hover { color: var(--text-strong, #0f172a); }

.cr-scope > label:not(.visually-hidden):has(:checked) {
  border-color: var(--primary, #0ea5e9);
  background: color-mix(in srgb, var(--primary, #0ea5e9) 10%, var(--panel, #fff));
  color: var(--text-strong, #0f172a);
}

.cr-scope > label:not(.visually-hidden):has(:focus-visible) {
  border-color: var(--primary, #0ea5e9);
  box-shadow: var(--ring, 0 0 0 4px rgba(14, 165, 233, .15));
}

/* A lens with nothing behind it dims its own label too, so the row does not
   look like a live control with a dead select beside it. */
.cr-scope > label:not(.visually-hidden):has(:disabled) { opacity: .55; cursor: not-allowed; }

.cr-sort { display: flex; align-items: center; gap: .5rem; font-size: .88rem; }

.cr-sort label {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted, #475569);
}

.cr-key {
  display: flex;
  flex-wrap: wrap;
  gap: .9rem;
  margin: 0 0 .75rem;
  padding: 0;
  list-style: none;
  font-size: .8rem;
  color: var(--muted, #475569);
}

.cr-key__item { display: flex; align-items: center; gap: .35rem; }

.cr-tablewrap--grid { max-height: 70vh; overflow: auto; }

.cr-grid { border-collapse: separate; border-spacing: 0; }

.cr-grid th,
.cr-grid td { border-bottom: 1px solid var(--border, #cbd5e1); }

/* Sticky header row and first column, so a wide class stays readable while
   scrolling in either direction. */
.cr-grid thead th {
  position: sticky;
  top: 0;
  background: var(--panel, #fff);
}

.cr-grid__who,
.cr-grid__corner {
  position: sticky;
  left: 0;
  background: var(--panel, #fff);
  font-weight: 600;
  white-space: nowrap;
}

.cr-grid__corner { top: 0; }

.cr-grid__col { text-align: center; font-variant-numeric: tabular-nums; }
.cr-grid__pct { text-align: right; font-variant-numeric: tabular-nums; }

.cr-cell { padding: .15rem; text-align: center; }

.cr-cell__btn {
  display: block;
  width: 100%;
  min-width: 2rem;
  min-height: 2rem;
  padding: 0;
  border: 0;
  border-radius: .25rem;
  font: inherit;
  cursor: pointer;
  background: transparent;
}

.cr-cell__btn:focus-visible {
  outline: 2px solid var(--primary-strong, #0284c7);
  outline-offset: -2px;
}

/* The mark is the primary signal and the aria-label carries the word. Colour
   is the third channel, never the only one, so the grid still reads in
   greyscale and to a colourblind teacher. */
.cr-cell__mark { font-weight: 700; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.cr-state--not-opened { color: var(--muted, #475569); background: var(--bg-elevated, #f1f5f9); }
.cr-state--in-progress { color: var(--text, #334155); background: var(--bg-elevated, #f1f5f9); }
.cr-state--attempted { color: #92400e; background: #fef3c7; }
.cr-state--passed { color: #14532d; background: #dcfce7; }
.cr-state--verified { color: var(--panel, #fff); background: var(--success, #16a34a); }

[data-theme="dark"] .cr-state--attempted { color: #fde68a; background: #4a3410; }
[data-theme="dark"] .cr-state--passed { color: #bbf7d0; background: #14361f; }

/* The summary strip that used to live here -- five bordered tiles in a grid --
   is now one quiet line under the class name. See "the class, in one line"
   further down: these figures are context for the attention list, not a
   headline competing with it. */

/* ---------- create form, notes ---------- */

.cr-create { display: flex; flex-wrap: wrap; gap: .5rem; align-items: flex-end; margin: 1rem 0; }
.cr-create label {
  display: block;
  margin-bottom: .3rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted, #475569);
}

.cr-error { color: var(--danger, #dc2626); font-size: .88rem; }
.cr-empty-note { color: var(--muted, #475569); font-size: .88rem; line-height: 1.55; }

/* An empty section is an invitation, not a gap. A dashed edge says the space
   is waiting to be filled rather than that something failed to load. */
.cr-assign > .cr-empty-note,
.cr-attention > .cr-empty-note,
.cr-grid-section > .cr-empty-note {
  margin: 0;
  padding: .9rem 1rem;
  border: 1px dashed color-mix(in srgb, var(--primary, #0ea5e9) 40%, var(--border, #cbd5e1));
  border-radius: .7rem;
  background: color-mix(in srgb, var(--bg-elevated, #f1f5f9) 50%, var(--panel, #fff));
}
.cr-divider { margin: 3rem 0 1.5rem; border: 0; border-top: 1px solid var(--border, #cbd5e1); }
.cr-legacy-h { font-size: 1.05rem; }
.cr-legacy-note { color: var(--muted, #475569); font-size: .85rem; }

/* ---------- 375px ---------- */

@media (max-width: 30rem) {
  .cr-bar { align-items: stretch; }
  .cr-bar__right { width: 100%; }
  .cr-bar__right .btn { flex: 1 1 auto; }
  .cr-code__value { font-size: 1.5rem; letter-spacing: .12em; }
  .cr-stats { grid-template-columns: 1fr; }
  .cr-create { flex-direction: column; align-items: stretch; }
  .cr-assign__form > .cr-field { display: flex; margin-right: 0; max-width: none; }
  .cr-controls { align-items: stretch; }
  .cr-sort { justify-content: space-between; }
  .cr-sort select { flex: 1 1 auto; min-width: 0; }
  .cr-assign__units,
  .cr-access__units { grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr)); }

  /* The attention table stops being a table on a phone: four columns in
     375px leaves each one too narrow to read. Every cell keeps its header as
     a label, so nothing is lost. */
  .cr-attention .cr-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .cr-attention .cr-table tr { display: block; padding: .6rem 0; border-bottom: 1px solid var(--border, #cbd5e1); }
  .cr-attention .cr-table th,
  .cr-attention .cr-table td { display: block; border: 0; padding: .15rem .2rem; }
  .cr-attention .cr-row__why::before { content: 'What happened: '; color: var(--muted, #475569); }
  .cr-attention .cr-row__do::before { content: 'Next step: '; color: var(--muted, #475569); }
}

/* ---------- print ---------- */

/* Landscape, because the grid is wider than it is tall: ten unit columns plus
   a name column does not fit a portrait page without shrinking the text past
   readable. */
@page {
  size: landscape;
  margin: 12mm;
}

@media print {
  .site-header,
  .site-footer,
  .cr-bar__right,
  .cr-controls,
  .cr-explain,
  .cr-info,
  [data-cr-copy] { display: none; }

  .cr-tablewrap--grid { max-height: none; overflow: visible; }
  .cr-grid thead th,
  .cr-grid__who,
  .cr-grid__corner { position: static; }

  .cr-table { font-size: 9pt; }
  .cr-code__value { font-size: 48pt; letter-spacing: .2em; }

  /* One page. The grid is the thing being printed, so it gets the room and
     the sections that only make sense on screen give theirs up. */
  .cr-grid-section { break-inside: avoid; break-before: auto; }
  .cr-attention { break-after: auto; }
  .cr-explain,
  .cr-key { display: none; }
  .cr-stats { grid-template-columns: repeat(4, 1fr); }

  /* Cell state has to survive a printer that drops backgrounds, so the mark
     is the whole signal on paper. */
  .cr-cell__mark { font-size: 11pt; }

  /* Backgrounds do not print by default, so the state marks carry the whole
     meaning on paper. They are letters, so they do. */
  .cr-cell { border: 1px solid #999; }
  .cr-grid-section { break-inside: avoid; }
}

@media (prefers-reduced-motion: reduce) {
  .cr-cell__btn,
  .cr-info { transition: none; }
}

/* ---------- student drill-down ---------- */

.sd {
  margin: 1.5rem 0;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .6rem;
  background: var(--panel, #fff);
}

.sd-bar {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  align-items: center;
  justify-content: space-between;
}

.sd-name { margin: 0; font-size: 1.15rem; }

.sd-readonly {
  margin: .5rem 0 1rem;
  color: var(--muted, #475569);
  font-size: .82rem;
}

.sd h4 {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: 1.5rem 0 .6rem;
  font-size: .95rem;
}

.sd-header { margin-bottom: 1rem; }
.sd-num { text-align: right; font-variant-numeric: tabular-nums; }
.sd-state__label { font-size: .82rem; }
.sd-empty { color: var(--muted, #475569); font-size: .88rem; }

/* ---------- timeline ---------- */

.sd-day {
  border-bottom: 1px solid var(--border, #cbd5e1);
}

.sd-day > summary {
  display: flex;
  gap: .6rem;
  align-items: baseline;
  padding: .5rem .2rem;
  cursor: pointer;
  font-size: .88rem;
}

.sd-day > summary:focus-visible {
  outline: 2px solid var(--primary, #0ea5e9);
  outline-offset: -2px;
}

.sd-day__date { font-weight: 600; color: var(--text-strong, #0f172a); }
.sd-day__count { color: var(--muted, #475569); font-size: .8rem; }

.sd-events {
  margin: 0 0 .6rem;
  padding: 0 0 0 .2rem;
  list-style: none;
  display: grid;
  gap: .2rem;
}

.sd-event {
  display: grid;
  grid-template-columns: 4rem 1fr;
  gap: .5rem;
  font-size: .84rem;
}

.sd-event__at { color: var(--muted, #475569); font-variant-numeric: tabular-nums; }
.sd-event__what { color: var(--text, #334155); }

/* ---------- work and history ---------- */

.sd-work,
.sd-history { margin-bottom: 1.25rem; }

.sd-work h4,
.sd-history h4 { margin-top: 0; font-size: .85rem; color: var(--muted, #475569); }

.sd-code {
  margin: .4rem 0 0;
  padding: .7rem .8rem;
  max-height: 22rem;
  overflow: auto;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .4rem;
  background: var(--bg-elevated, #f1f5f9);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .82rem;
  line-height: 1.5;
  white-space: pre;
}

.sd-answer {
  margin: .4rem 0 0;
  padding: .6rem .7rem;
  border-left: 3px solid var(--border, #cbd5e1);
  color: var(--text, #334155);
  font-size: .88rem;
}

.sd-scrub { width: 100%; max-width: 30rem; }
.sd-scrub__label { display: block; font-size: .8rem; color: var(--muted, #475569); }
.sd-scrub:focus-visible { outline: 2px solid var(--primary, #0ea5e9); outline-offset: 2px; }

.sd-history__meta {
  margin: .3rem 0 0;
  color: var(--muted, #475569);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
}

/* Neutral by design. This is a label, not a verdict, so it gets no red and no
   warning iconography -- the tooltip beside it explains that typing fast and
   pasting look identical here. */
.sd-flag:not(:empty) {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  margin-top: .3rem;
  padding: .1rem .45rem;
  border-radius: 999px;
  font-size: .72rem;
  color: var(--muted, #475569);
  background: var(--bg-elevated, #f1f5f9);
  border: 1px solid var(--border, #cbd5e1);
}

@media (max-width: 30rem) {
  .sd { padding: .85rem .9rem; }
  .sd-event { grid-template-columns: 1fr; gap: 0; }
  .sd-code { font-size: .76rem; }
}

@media print {
  .sd-scrub,
  .sd-scrub__label,
  [data-sd-close] { display: none; }

  .sd-code { max-height: none; overflow: visible; white-space: pre-wrap; }
  .sd-day { break-inside: avoid; }
}

/* ---------- what your teacher can see ---------- */

.disclosure {
  margin: 1rem 0;
  padding: .9rem 1rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .5rem;
  background: var(--bg-elevated, #f1f5f9);
  font-size: .88rem;
}

.disclosure__title {
  margin: .8rem 0 .35rem;
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--muted, #475569);
}

.disclosure__title:first-child { margin-top: 0; }

.disclosure__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .25rem;
}

/* The marker is a character, not a background image, so it survives greyscale
   printing and a stylesheet that fails to load. */
.disclosure__list li { display: grid; grid-template-columns: 1.1rem 1fr; gap: .4rem; }
.disclosure__list li::before { font-weight: 700; }
.disclosure__list--yes li::before { content: '\2713'; color: var(--text-strong, #0f172a); }
.disclosure__list--no li::before { content: '\2715'; color: var(--muted, #475569); }

.disclosure__note {
  margin: .8rem 0 0;
  color: var(--muted, #475569);
  font-size: .82rem;
}

/* ---------- share and digest ---------- */

.cr-teachers {
  margin: .6rem 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .25rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .8rem;
  color: var(--muted, #475569);
}

.cr-digest__text {
  display: block;
  width: 100%;
  margin: .5rem 0;
  padding: .7rem .8rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .4rem;
  background: var(--bg-elevated, #f1f5f9);
  color: var(--text, #334155);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .82rem;
  line-height: 1.55;
  resize: vertical;
}

.cr-digest__text:focus-visible {
  outline: 2px solid var(--primary, #0ea5e9);
  outline-offset: 2px;
}

@media print {
  .cr-share,
  .cr-digest { display: none; }
}

/* ---------- student work beside what was expected ---------- */

.sd-pair {
  display: grid;
  grid-template-columns: 1fr;
  gap: .6rem;
}

/* Side by side once there is room for both to stay readable. Below that they
   stack, because two half-width columns of code are worse than one of each. */
@media (min-width: 60rem) {
  .sd-pair { grid-template-columns: 1.4fr 1fr; align-items: start; }
}

.sd-expected {
  padding: .7rem .8rem;
  border: 1px solid var(--border, #cbd5e1);
  border-left: 3px solid var(--primary, #0ea5e9);
  border-radius: .4rem;
  background: var(--panel, #fff);
}

.sd-expected h5 {
  margin: 0 0 .4rem;
  font-size: .78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--muted, #475569);
}

.sd-expected__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .45rem;
  font-size: .82rem;
}

.sd-expected__name { display: block; color: var(--text, #334155); }

.sd-expected__value {
  display: block;
  margin-top: .15rem;
  padding: .2rem .35rem;
  border-radius: .25rem;
  background: var(--bg-elevated, #f1f5f9);
  color: var(--muted, #475569);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .78rem;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

/* ---------- per-unit progress ---------- */

/* In a grid cell: the mark stays the primary signal and the percentage sits
   under it, small. The number is detail; the mark is what you scan for. */
.cr-cell__pct {
  display: block;
  margin-top: .05rem;
  font-size: .6rem;
  font-variant-numeric: tabular-nums;
  opacity: .85;
}

.cr-cell__btn { line-height: 1.15; padding: .15rem 0; }

.sd-unit__cell { min-width: 9rem; }

.sd-unit__meter {
  display: inline-block;
  width: 6rem;
  height: .5rem;
  vertical-align: middle;
  border-radius: 999px;
  overflow: hidden;
  background: var(--bg-elevated, #f1f5f9);
  border: 1px solid var(--border, #cbd5e1);
}

.sd-unit__meter .bar {
  height: 100%;
  background: var(--primary, #0ea5e9);
}

.sd-unit__pct {
  margin-left: .45rem;
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #475569);
}

@media print {
  /* The bar is a background and will not print, so the number carries it. */
  .sd-unit__meter { display: none; }
  .sd-unit__pct { margin-left: 0; }
}

/* ------------------------------------------------------------ assignments */

/* Same card as the join code and needs-attention, one step more solid: these
   two sections are the only ones on the page that change what students see,
   so they read as settings rather than as another read-out. Nothing here
   introduces a second visual language for a second kind of fact. */
.cr-assign,
.cr-access {
  margin: 0 0 1.5rem;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .9rem;
  background: var(--panel, #fff);
  box-shadow: var(--shadow, 0 4px 20px rgba(12, 69, 102, .07));
}

.cr-assign__list { margin: 0; padding: 0; list-style: none; }

.cr-assign__item {
  padding: .85rem 0;
  border-bottom: 1px solid var(--border, #cbd5e1);
}

.cr-assign__item:last-child { border-bottom: 0; }

.cr-assign__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem 1rem;
  justify-content: space-between;
}

.cr-assign__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-strong, #0f172a);
}

.cr-assign__due {
  margin: 0;
  padding: .1rem .5rem;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #475569);
  background: var(--bg-elevated, #f1f5f9);
}

.cr-assign__what { margin: .3rem 0 .55rem; font-size: .85rem; color: var(--muted, #475569); }

.cr-assign__tally {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: 0 0 .5rem;
  padding: 0;
  list-style: none;
}

/* A count is a number and a word, in that order, and it keeps the word even
   when the colour is gone. */
.cr-assign__count {
  display: flex;
  align-items: baseline;
  gap: .35rem;
  padding: .2rem .55rem;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 600;
  background: var(--bg-elevated, #f1f5f9);
  color: var(--text, #334155);
}

.cr-assign__n { font-weight: 800; font-variant-numeric: tabular-nums; }

.cr-assign--done-on-time { color: #14532d; background: #dcfce7; }
.cr-assign--done-late { color: #92400e; background: #fef3c7; }
.cr-assign--overdue { color: #7f1d1d; background: #fee2e2; }
.cr-assign--expired { color: var(--muted, #475569); background: var(--bg-elevated, #f1f5f9); }

[data-theme="dark"] .cr-assign--done-on-time { color: #bbf7d0; background: #14361f; }
[data-theme="dark"] .cr-assign--done-late { color: #fde68a; background: #4a3410; }
[data-theme="dark"] .cr-assign--overdue { color: #fecaca; background: #451a1a; }

.cr-assign__who { margin: 0 0 .5rem; font-size: .85rem; color: var(--text, #334155); }

/* The two standing caveats -- an assignment outranks the lock setting, a lock
   setting never cancels an assignment. Both are rules, not commentary, so they
   get an accent edge rather than being set as quiet grey prose nobody reads. */
.cr-assign__note,
.cr-access__note {
  margin: .85rem 0 0;
  padding: .55rem .75rem;
  border-left: 3px solid color-mix(in srgb, var(--primary, #0ea5e9) 55%, transparent);
  border-radius: .1rem .5rem .5rem .1rem;
  font-size: .82rem;
  line-height: 1.5;
  color: var(--muted, #475569);
  background: color-mix(in srgb, var(--primary, #0ea5e9) 6%, var(--panel, #fff));
}

/* ---------- the builder ---------- */

.cr-assign__new { margin-top: 1rem; }

/* On an empty class this summary is the only thing to do on the page, so it
   is drawn as the action it is. The marker is a chevron that turns, which is
   the same gesture the unit dropdowns in the header already use. */
.cr-assign__new > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .65rem .85rem;
  border: 2px solid var(--border, #cbd5e1);
  border-radius: .7rem;
  background: var(--bg-elevated, #f1f5f9);
  color: var(--text-strong, #0f172a);
  font-size: .9rem;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
  transition: border-color var(--dur-fast, 150ms) ease,
              color var(--dur-fast, 150ms) ease,
              background-color var(--dur-fast, 150ms) ease;
}

.cr-assign__new > summary::-webkit-details-marker { display: none; }

.cr-assign__new > summary::after {
  content: "";
  flex: none;
  width: .5rem;
  height: .5rem;
  margin-right: .2rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  opacity: .6;
  transition: transform var(--dur-base, 280ms) cubic-bezier(.16, 1, .3, 1),
              opacity var(--dur-fast, 150ms) ease;
}

.cr-assign__new > summary:hover,
.cr-assign__new > summary:focus-visible {
  border-color: var(--primary, #0ea5e9);
  color: var(--primary-strong, #0284c7);
  outline: none;
}

.cr-assign__new > summary:focus-visible { box-shadow: var(--ring, 0 0 0 4px rgba(14, 165, 233, .15)); }

.cr-assign__new[open] > summary {
  border-color: var(--primary, #0ea5e9);
  color: var(--primary-strong, #0284c7);
  background: color-mix(in srgb, var(--primary, #0ea5e9) 8%, var(--panel, #fff));
  border-radius: .7rem .7rem 0 0;
  border-bottom-color: transparent;
}

.cr-assign__new[open] > summary::after { transform: translateY(2px) rotate(225deg); opacity: 1; }

/* The open form is one continuous surface with the summary above it, so the
   disclosure reads as a panel opening rather than as a stack of loose fields. */
.cr-assign__form {
  margin: 0;
  padding: 1rem;
  border: 2px solid var(--primary, #0ea5e9);
  border-top: 0;
  border-radius: 0 0 .7rem .7rem;
  background: var(--panel, #fff);
  animation: cr-open var(--dur-base, 280ms) cubic-bezier(.16, 1, .3, 1);
}

@keyframes cr-open {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .cr-assign__form { animation: none; }
}

/* Name and due date belong to the same decision, so they sit on one line
   where there is room for it. */
.cr-assign__form > .cr-field {
  display: inline-flex;
  vertical-align: top;
  margin-right: .75rem;
}

.cr-field {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  margin: 0 0 .85rem;
  max-width: 22rem;
}

.cr-field label {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted, #475569);
}

.cr-field input,
.cr-field select { width: 100%; }

/* ---------- what the work covers ---------- */

.cr-assign__targets {
  margin: 0 0 .85rem;
  padding: .85rem .9rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .7rem;
  background: color-mix(in srgb, var(--bg-elevated, #f1f5f9) 55%, var(--panel, #fff));
}

.cr-assign__targets legend {
  margin-left: -.2rem;
  padding: .15rem .5rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: 999px;
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted, #475569);
  background: var(--panel, #fff);
}

.cr-assign__targets .cr-field { max-width: 16rem; margin-bottom: .7rem; }

/* Ten units in a row of chips: a fixed grid keeps "Unit 1" and "Unit 10" the
   same width, so the row scans as a set of ten rather than as ragged text. */
.cr-assign__units,
.cr-access__units {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(6.25rem, 1fr));
  gap: .4rem;
}

.cr-assign__lessons {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  max-height: 17rem;
  overflow-y: auto;
}

/* A tick is a target, and a target that is on should look chosen rather than
   look like a ticked box next to some text. */
.cr-check {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .45rem .6rem;
  border: 2px solid var(--border, #cbd5e1);
  border-radius: .55rem;
  background: var(--panel, #fff);
  font-size: .85rem;
  font-weight: 600;
  color: var(--text, #334155);
  cursor: pointer;
  transition: border-color var(--dur-fast, 150ms) ease,
              background-color var(--dur-fast, 150ms) ease,
              color var(--dur-fast, 150ms) ease;
}

.cr-check:hover { border-color: color-mix(in srgb, var(--primary, #0ea5e9) 55%, var(--border, #cbd5e1)); }

.cr-check:has(:checked) {
  border-color: var(--primary, #0ea5e9);
  background: color-mix(in srgb, var(--primary, #0ea5e9) 10%, var(--panel, #fff));
  color: var(--text-strong, #0f172a);
}

.cr-check:has(:focus-visible) {
  border-color: var(--primary, #0ea5e9);
  box-shadow: var(--ring, 0 0 0 4px rgba(14, 165, 233, .15));
}

.cr-check:has(:disabled) { cursor: default; opacity: .8; }
.cr-check:has(:disabled):hover { border-color: var(--primary, #0ea5e9); }

/* Lesson titles are sentences, not labels, so their rows run full width and
   wrap instead of being squeezed into a chip. */
.cr-assign__lessons .cr-check {
  border-width: 1px;
  border-radius: .5rem;
  font-weight: 500;
  align-items: flex-start;
  line-height: 1.4;
}

.cr-assign__lessons .cr-check input { margin-top: .1rem; }

.cr-assign__lessons:empty::after {
  content: "This unit has no lessons in the manifest yet.";
  font-size: .82rem;
  color: var(--muted, #475569);
}

.cr-assign__form .cr-error { margin: .6rem 0 0; }
.cr-assign__form .btn { margin-top: .25rem; }

/* ------------------------------------------------------------ unit access */

/* Three mutually exclusive rules for the whole class. Cards rather than a
   stack of radios, because the hint under each name is the part that decides
   it and needs to be read, not skimmed past. */
.cr-access__modes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: .5rem;
  margin: 0 0 .85rem;
  padding: 0;
  border: 0;
}

.cr-access__modes label {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .2rem .55rem;
  align-content: start;
  margin: 0;
  padding: .7rem .8rem;
  border: 2px solid var(--border, #cbd5e1);
  border-radius: .7rem;
  background: var(--panel, #fff);
  cursor: pointer;
  transition: border-color var(--dur-fast, 150ms) ease,
              background-color var(--dur-fast, 150ms) ease;
}

.cr-access__modes label:hover { border-color: color-mix(in srgb, var(--primary, #0ea5e9) 55%, var(--border, #cbd5e1)); }

.cr-access__modes label:has(:checked) {
  border-color: var(--primary, #0ea5e9);
  background: color-mix(in srgb, var(--primary, #0ea5e9) 8%, var(--panel, #fff));
}

.cr-access__modes label:has(:focus-visible) {
  border-color: var(--primary, #0ea5e9);
  box-shadow: var(--ring, 0 0 0 4px rgba(14, 165, 233, .15));
}

.cr-access__modes input { grid-row: 1 / 3; align-self: start; margin-top: .15rem; }
.cr-access__name { font-weight: 700; color: var(--text-strong, #0f172a); }
.cr-access__hint { font-size: .8rem; line-height: 1.45; color: var(--muted, #475569); }

.cr-access__units {
  margin: 0 0 .5rem;
  padding: .85rem .9rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .7rem;
  background: color-mix(in srgb, var(--bg-elevated, #f1f5f9) 55%, var(--panel, #fff));
}

/* ------------------------------------------- the assignment grid overlay */

/* An outline rather than a fill, because the cell's own fill is already
   carrying the mastery state and must stay readable underneath. The trailing
   character in .cr-cell__mark is what survives greyscale and a printout. */
.cr-assigned .cr-cell__btn { box-shadow: inset 0 0 0 2px currentColor; }
.cr-assigned--overdue .cr-cell__btn { box-shadow: inset 0 0 0 2px #dc2626; }
.cr-assigned--done-late .cr-cell__btn { box-shadow: inset 0 0 0 2px #d97706; }

/* --------------------------------------------- assigned, on one student */

.sd-assign--overdue th { color: #7f1d1d; }
.sd-assign--done-late th { color: #92400e; }
.sd-assign__parts { font-size: .85rem; color: var(--muted, #475569); }

[data-theme="dark"] .sd-assign--overdue th { color: #fecaca; }
[data-theme="dark"] .sd-assign--done-late th { color: #fde68a; }

@media print {
  /* The builder is a control, not a record, and the outline is a colour.
     The mark and the words carry both onto paper. */
  .cr-assign__new { display: none; }
  .cr-access__modes input { display: none; }
  .cr-assigned .cr-cell__btn { box-shadow: none; }
}

/* Says why the page looks empty. A teacher with no class was being shown a
   form with no explanation of what it unlocked, which reads as the features
   being absent rather than as there being nothing yet to attach them to. */
.cr-empty__why {
  padding: .6rem .8rem;
  border-left: 3px solid var(--primary, #0ea5e9);
  border-radius: .25rem;
  font-size: .9rem;
  background: var(--bg-elevated, #f1f5f9);
}

/* A student the live roster has just reported. Their progress has not been
   read yet, which is not the same fact as having none. */
.cr-grid__pending {
  display: block;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--primary-strong, #0284c7);
}

/* --------------------------------------------------- dropdown, on this page */

/* The widget itself lives in pypath-fast.css, beside the rest of the dropdown
   system and the layer scale it has to stack within. Only the two places this
   page constrains its width are here. */
.cr-field .sel { width: 100%; }
.cr-sort .sel { min-width: 11rem; }

/* ---------------------------------------------------------- certificates */

/* The one thing on this page a teacher owes a student rather than the other
   way round, so it gets a section rather than a column with a menu in it. */
.cr-certs {
  margin: 0 0 1.5rem;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .9rem;
  background: var(--panel, #fff);
  box-shadow: var(--shadow, 0 4px 20px rgba(12, 69, 102, .07));
}

.cr-certs__list { margin: 0; padding: 0; list-style: none; }

.cr-cert-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .25rem 1rem;
  align-items: center;
  padding: .75rem 0;
  border-bottom: 1px solid var(--border, #cbd5e1);
}

.cr-cert-row:last-child { border-bottom: 0; }

.cr-cert-row__who {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin: 0;
}

.cr-cert-row__when {
  grid-column: 1;
  margin: 0;
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #475569);
}

.cr-cert-row__do {
  grid-column: 2;
  grid-row: 1 / 3;
  display: flex;
  gap: .4rem;
  margin: 0;
}

/* Mark first, then the word. The colour is the third thing that says it, not
   the only one -- this list gets printed for a department meeting. */
.cr-cert-row__state {
  display: inline-flex;
  align-items: baseline;
  gap: .3rem;
  padding: .15rem .5rem;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 700;
  background: var(--bg-elevated, #f1f5f9);
  color: var(--text, #334155);
}

.cr-cert__mark {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 700;
}

.cr-cert--pending .cr-cert-row__state { color: #7c2d12; background: #ffedd5; }
.cr-cert--approved .cr-cert-row__state { color: #14532d; background: #dcfce7; }
.cr-cert--declined .cr-cert-row__state { color: #7f1d1d; background: #fee2e2; }
.cr-cert--earned .cr-cert-row__state { color: #14532d; background: #dcfce7; }

[data-theme="dark"] .cr-cert--pending .cr-cert-row__state { color: #fed7aa; background: #43220c; }
[data-theme="dark"] .cr-cert--approved .cr-cert-row__state,
[data-theme="dark"] .cr-cert--earned .cr-cert-row__state { color: #bbf7d0; background: #14361f; }
[data-theme="dark"] .cr-cert--declined .cr-cert-row__state { color: #fecaca; background: #451a1a; }

/* The grid's certificate cell: a mark, and the word to a screen reader. */
.cr-grid__cert { text-align: center; }
.cr-grid__cert .cr-cert__mark { font-size: .95rem; }
.cr-grid .cr-cert--pending { color: #9a3412; }
.cr-grid .cr-cert--approved,
.cr-grid .cr-cert--earned { color: #15803d; }
.cr-grid .cr-cert--declined { color: #b91c1c; }

[data-theme="dark"] .cr-grid .cr-cert--pending { color: #fdba74; }
[data-theme="dark"] .cr-grid .cr-cert--approved,
[data-theme="dark"] .cr-grid .cr-cert--earned { color: #86efac; }
[data-theme="dark"] .cr-grid .cr-cert--declined { color: #fca5a5; }

/* A waiting certificate is the only attention row that names something the
   teacher owes, so it gets the accent rather than a warning colour. */
.cr-row--certificate { border-left: 3px solid var(--primary, #0ea5e9); }

@media (max-width: 30rem) {
  .cr-cert-row { grid-template-columns: 1fr; }
  .cr-cert-row__do { grid-column: 1; grid-row: auto; }
}

/* =================================================== the page's four zones */

/* Nine flat sections became five things to look at: what needs you, the grid,
   what you have asked for, and the termly stuff folded away. Grouped by why a
   teacher came rather than by when each part happened to be built. */

/* ---------- the class bar ---------- */

.cr-bar__left {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .9rem;
}

/* Six characters, read aloud at the start of term and almost never after. It
   was a card with a heading, a paragraph and a button; it is now a line. */
.cr-joincode {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  padding: .3rem .3rem .3rem .7rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: 999px;
  background: var(--panel, #fff);
}

.cr-joincode__label {
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted, #475569);
}

.cr-joincode__value {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--text-strong, #0f172a);
}

/* ---------- the class, in one line ---------- */

/* Context for the list below rather than a headline of its own. The template
   answer is five tiles with big numbers at the top of the page; nobody has
   ever needed the median unit reached in the thirty seconds before a lesson. */
.cr-stats {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1.4rem;
  margin: 0 0 1.25rem;
  padding: .6rem .85rem;
  border-radius: .7rem;
  background: color-mix(in srgb, var(--bg-elevated, #f1f5f9) 60%, var(--panel, #fff));
}

.cr-stat { display: flex; align-items: baseline; gap: .4rem; }

.cr-stat dt {
  display: flex;
  align-items: center;
  gap: .25rem;
  font-size: .78rem;
  color: var(--muted, #475569);
}

.cr-stat dd {
  margin: 0;
  font-size: .95rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-strong, #0f172a);
}

/* ---------- zone 1: what needs you ---------- */

/* The thesis of the page. A named child stuck on the same exercise for the
   seventh time is the only thing here that can be acted on; a percentage is
   not. So this leads, and the figures above are the quiet line under the name
   of the class rather than the other way round. */
.cr-attention {
  margin: 0 0 1.5rem;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border, #cbd5e1);
  border-left: 3px solid var(--primary, #0ea5e9);
  border-radius: .9rem;
  background: var(--panel, #fff);
  box-shadow: var(--shadow, 0 4px 20px rgba(12, 69, 102, .07));
}

.cr-attention > h2 { margin-top: 0; }

/* ---------- zones 3 and 4 ---------- */

.cr-zone { margin: 2rem 0 0; }

.cr-zone__h {
  margin: 0 0 .75rem;
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted, #475569);
}

/* The zone heading names the group; the cards inside keep their own headings,
   so a section's h2 does not have to compete with the label above it. */
.cr-zone .cr-assign > h2,
.cr-zone .cr-access > h2 { font-size: 1.05rem; }

/* Unit access and solutions are two settings of the same kind, so they sit as
   a pair rather than as another thing further down the scroll. */
.cr-zone--work .cr-access { margin-bottom: 1rem; }

/* ---------- the folds ---------- */

.cr-fold {
  margin: 0 0 .5rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .8rem;
  background: var(--panel, #fff);
  overflow: hidden;
}

.cr-fold > summary {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .8rem 1rem;
  list-style: none;
  cursor: pointer;
  font-weight: 700;
  color: var(--text-strong, #0f172a);
  transition: background-color var(--dur-fast, 150ms) ease;
}

.cr-fold > summary::-webkit-details-marker { display: none; }

.cr-fold > summary::after {
  content: "";
  flex: none;
  order: 3;
  width: .5rem;
  height: .5rem;
  margin-left: auto;
  margin-right: .2rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  opacity: .5;
  transition: transform var(--dur-base, 280ms) cubic-bezier(.16, 1, .3, 1);
}

.cr-fold[open] > summary::after { transform: translateY(2px) rotate(225deg); opacity: 1; }
.cr-fold > summary:hover { background: var(--bg-elevated, #f1f5f9); }
.cr-fold > summary:focus-visible {
  outline: none;
  box-shadow: inset var(--ring, 0 0 0 4px rgba(14, 165, 233, .15));
}

.cr-fold[open] > summary {
  border-bottom: 1px solid var(--border, #cbd5e1);
  background: var(--bg-elevated, #f1f5f9);
}

.cr-fold__name { order: 1; }

/* What the shut section is holding. Anything in here that can accumulate work
   owed to a person says so on its own header, so folding cannot hide a
   student waiting on a decision. */
.cr-fold__count {
  order: 2;
  padding: .1rem .5rem;
  border-radius: 999px;
  font-size: .74rem;
  font-weight: 700;
  color: var(--muted, #475569);
  background: var(--bg-elevated, #f1f5f9);
}

.cr-fold__count.is-waiting { color: #7c2d12; background: #ffedd5; }
[data-theme="dark"] .cr-fold__count.is-waiting { color: #fed7aa; background: #43220c; }

.cr-fold[open] > summary .cr-fold__count { background: var(--panel, #fff); }

/* The sections inside a fold already carry their own card chrome, which would
   be a border inside a border. */
.cr-fold .cr-certs,
.cr-fold .cr-share,
.cr-fold .cr-digest,
.cr-fold__body {
  margin: 0;
  padding: 1rem 1.1rem;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: transparent;
}

.cr-fold .cr-certs > h2,
.cr-fold .cr-share > h2,
.cr-fold .cr-digest > h2 {
  margin-top: 0;
  font-size: 1rem;
}

.cr-fold__actions { display: flex; flex-wrap: wrap; gap: .5rem; margin: .75rem 0 0; }

@media (max-width: 30rem) {
  .cr-bar__left { align-items: stretch; }
  .cr-joincode { justify-content: space-between; }
  .cr-stats { gap: .3rem .9rem; }
}

@media print {
  /* The folds are opened for print by classroom-dashboard.js on beforeprint,
     not from here: a details element hides its own content through the user
     agent stylesheet, and the only way to override that in CSS is !important,
     which this file does not use and has a test saying so. */
  .cr-fold > summary { display: none; }
  .cr-fold, .cr-fold[open] { border: 0; }
  .cr-joincode { border: 0; padding-left: 0; }
  .cr-joincode button { display: none; }
}

/* ------------------------------------------------------ exercise solutions */

/* A different axis from unit access: that decides what a class can open, this
   decides what an exercise offers. Same card, so the two read as siblings. */
.cr-solutions {
  margin: 0;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: .9rem;
  background: var(--panel, #fff);
  box-shadow: var(--shadow, 0 4px 20px rgba(12, 69, 102, .07));
}

.cr-solutions__toggle { display: inline-flex; max-width: 100%; }

.cr-solutions__note {
  margin: .85rem 0 0;
  padding: .55rem .75rem;
  border-left: 3px solid color-mix(in srgb, var(--primary, #0ea5e9) 55%, transparent);
  border-radius: .1rem .5rem .5rem .1rem;
  font-size: .82rem;
  line-height: 1.5;
  color: var(--muted, #475569);
  background: color-mix(in srgb, var(--primary, #0ea5e9) 6%, var(--panel, #fff));
}

.cr-zone .cr-solutions > h2 { font-size: 1.05rem; margin-top: 0; }


/* ------------------------------------------------------------------ roster
   One row per student, built to be scanned by a teacher standing up with a
   class of forty on screen. The unit grid it sits beside is one cell per
   student per unit and stays the right tool for reading a single unit down
   the column; this is the one for reading people down the page.

   Everything here is quiet on purpose. The bar, the one flag mark and the
   below-70 dot are the only three things allowed to catch the eye, because a
   table where six things compete is the density problem this view exists to
   solve. */

.cr-viewbar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  align-items: flex-end;
  justify-content: space-between;
  margin: 0 0 1rem;
}

.cr-view {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  border: 0;
  margin: 0;
  padding: 0;
}

/* A segmented control rather than two loose radios: these are two views of one
   thing, and the shared track says so. */
.cr-view label {
  display: inline-flex;
  align-items: center;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--cr-line, rgba(0, 0, 0, 0.14));
  cursor: pointer;
  font-size: 0.9rem;
  line-height: 1.4;
  background: transparent;
}

.cr-view label:first-of-type { border-radius: 999px 0 0 999px; }
.cr-view label:last-of-type { border-radius: 0 999px 999px 0; margin-left: -1px; }
.cr-view input { position: absolute; opacity: 0; pointer-events: none; }
.cr-view label:has(input:checked) {
  background: var(--cr-ink, #14202e);
  border-color: var(--cr-ink, #14202e);
  color: #fff;
  font-weight: 600;
}
.cr-view label:has(input:focus-visible) { outline: 2px solid currentColor; outline-offset: 2px; }
.cr-view .cr-info { margin-left: 0.5rem; }

.cr-find { display: flex; align-items: center; gap: 0.5rem; }
.cr-find label { font-size: 0.85rem; color: var(--cr-muted, #5b6b7c); }
.cr-find select { min-width: 14rem; }

.cr-roster { width: 100%; }

.cr-roster__h { padding: 0; white-space: nowrap; }
.cr-roster__h--right { text-align: right; }

.cr-roster__sort {
  appearance: none;
  background: none;
  border: 0;
  padding: 0.5rem 0.65rem;
  font: inherit;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cr-muted, #5b6b7c);
  cursor: pointer;
  width: 100%;
  text-align: inherit;
}
.cr-roster__sort:hover { color: inherit; }
.cr-roster__sort.is-sorted { color: inherit; font-weight: 700; }
.cr-roster__arrow { margin-left: 0.3rem; }

.cr-roster__who { text-align: left; font-weight: 500; }
.cr-roster__name {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: inherit;
  cursor: pointer;
  text-align: left;
  text-decoration: underline;
  text-decoration-color: var(--cr-line, rgba(0, 0, 0, 0.25));
  text-underline-offset: 3px;
}
.cr-roster__name:hover { text-decoration-color: currentColor; }

.cr-roster__c { text-align: left; vertical-align: middle; }
.cr-roster__c--right { text-align: right; font-variant-numeric: tabular-nums; }

.cr-roster__row:hover { background: var(--cr-hover, rgba(0, 0, 0, 0.025)); }

/* The number is the fact; the bar is what makes forty rows read as a
   distribution rather than forty separate readings. */
.cr-roster__num { display: block; font-variant-numeric: tabular-nums; }
.cr-meter {
  display: block;
  width: 5.5rem;
  height: 4px;
  margin-left: auto;
  margin-top: 0.25rem;
  background: var(--cr-line, rgba(0, 0, 0, 0.12));
  border-radius: 999px;
  overflow: hidden;
}
.cr-meter__fill { display: block; height: 100%; background: var(--cr-ink, #14202e); }

.cr-roster__score { font-weight: 600; }
.cr-roster__score.is-below { color: var(--cr-warn-ink, #8a4b12); }
.cr-roster__unit { color: var(--cr-muted, #5b6b7c); font-size: 0.85em; }

.cr-roster__c.is-behind { color: var(--cr-warn-ink, #8a4b12); }
.cr-roster__c.is-stale { color: var(--cr-muted, #5b6b7c); }

.cr-roster__flag {
  display: inline-block;
  min-width: 1.25rem;
  text-align: center;
  font-weight: 700;
  color: var(--cr-warn-ink, #8a4b12);
  margin-right: 0.4rem;
}
.cr-roster__reason {
  font-size: 0.85rem;
  color: var(--cr-muted, #5b6b7c);
}
.cr-roster__pending { color: var(--cr-muted, #5b6b7c); font-size: 0.85rem; }

@media (max-width: 640px) {
  /* The two columns a phone can lose without changing what the table is for. */
  .cr-roster__h:nth-child(5), .cr-roster__c:nth-child(5),
  .cr-roster__h:nth-child(7), .cr-roster__c:nth-child(7) { display: none; }
  .cr-find select { min-width: 0; }
}


/* ------------------------------------------------------------- quiz picker
   Inside the existing "Set new work" form, not a section of its own: a quiz is
   a third kind of target alongside units and lessons, and putting it anywhere
   else would imply it has its own due date. */

.cr-quiz__kinds {
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  color: var(--cr-muted, #5b6b7c);
}

/* Scrolls rather than growing: a unit offers up to fifty-six questions and an
   un-capped list would push the Assign button off the page. */
.cr-quiz__list {
  max-height: 18rem;
  overflow-y: auto;
  border: 1px solid var(--cr-line, rgba(0, 0, 0, 0.14));
  border-radius: 0.5rem;
  padding: 0.35rem;
}

.cr-quiz__row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.4rem 0.5rem;
  border-radius: 0.35rem;
  cursor: pointer;
  font-size: 0.9rem;
}

.cr-quiz__row:hover { background: var(--cr-hover, rgba(0, 0, 0, 0.03)); }
.cr-quiz__row:has(input:checked) { background: var(--cr-hover, rgba(0, 0, 0, 0.05)); }
.cr-quiz__row input { margin-top: 0.25rem; flex: none; }

.cr-quiz__text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }

/* The kind is a word, never only a position in the list: a teacher scanning
   for "the matching ones" should not have to open them to find out. */
.cr-quiz__kind {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--cr-muted, #5b6b7c);
}

.cr-quiz__prompt { overflow-wrap: anywhere; }

.cr-quiz__count { margin: 0.6rem 0; font-size: 0.85rem; color: var(--cr-muted, #5b6b7c); }
.cr-quiz__count.is-over { color: var(--cr-warn-ink, #8a4b12); font-weight: 600; }

.cr-quiz__setting { margin-top: 0.6rem; }
