/* ============================================================
   /instructors/managing-an-assignment — new components only.

   Loaded alongside walkthrough.css (the --wt-* tokens) and
   walkthrough-rig.css, which supplies the whole scroll rig — grid,
   sticky stage, step track, card centring, dot rail, the pointer,
   the hand-drawn ink engine — and every piece of frame furniture
   this page reuses unchanged: .wt2-tabs, .wt2-rail/.wt2-railbox/
   .wt2-railhead/.wt2-railcard/.wt2-create/.wt2-badge, .wt2-cols/
   .wt2-kv/.wt2-topics (the Assignment-details panel), .wt2-hatch-box
   + pre.wt2-ascii (the closing watermark), and .wt2-modes/.wt2-mode
   (reused here for the Partner Action radio choices — same "stacked
   rows, one filled" shape already used for Assignment vs QuickMatch).

   Everything below is new to this page: the roster table, the two
   kebab menus, the modal, and the QuickMatch row's toggle switch.
   Nothing here is read by create-an-assignment, which never
   loads this file.
   ============================================================ */

/* ---- Second rail box: QuickMatch Chats ----
   v2's rail only ever holds one box; this page's rail holds two,
   stacked, both always populated — there is no before-creation empty
   state to represent here the way v2's first screen needed one.
   Spaced by a margin rather than by making the rail a flex column with a
   gap: the rail is a plain block in walkthrough-rig.css, which hides it
   outright below 620px, and restating `display` here — this file loads
   second, at equal specificity — brought it back on exactly the screens
   too narrow to hold it. .wt2-railsel already carries the same 0.9em
   below itself, so this is the only gap block layout was missing. */
.wt2-railbox + .wt2-railbox { margin-top: 0.9em; }

.wt2-qmrow {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.5em;
  padding: 0.6em 0.6em 0.65em;
  background: var(--wt-accent-soft);
  border-left: 3px solid var(--wt-accent);
}
.wt2-qmrow > div:first-child { min-width: 0; }
.wt2-qmrow b {
  display: block;
  font-size: 0.68em;
  line-height: 1.45;
  color: var(--wt-ink-strong);
}
.page-content .wt2-qmrow span {
  display: block;
  font-size: 0.6em;
  line-height: 1.5;
  color: var(--text-soft);
}
.wt2-qmctrl {
  display: flex;
  align-items: center;
  gap: 0.55em;
  flex: 0 0 auto;
  margin-top: 0.15em;
}

/* ---- Toggle switch ---- */
.wt2-toggle {
  position: relative;
  display: inline-block;
  width: 2.1em;
  height: 1.15em;
  border: 1.5px solid var(--wt-faint);
  border-radius: 1em;
  background: var(--wt-paper);
  transition: background-color 0.25s ease, border-color 0.25s ease;
}
/* On from the moment the pointer presses it, and on for every screen after —
   the toggle is in the rail, which is shared shell, so it cannot carry the
   state per screen in its own markup. data-opens="qm-on" sets the first;
   a frame that comes after the press says so with data-qm-on. It starts off,
   so the press is a flip the reader can watch rather than a click on
   something already in the state it is being switched to. */
.wt2-toggle.is-on,
.wt2-window[data-open~="qm-on"] .wt2-toggle,
.wt2-window:has(.wt2-frame.is-on[data-qm-on]) .wt2-toggle {
  background: var(--wt-accent);
  border-color: var(--wt-accent);
}
.wt2-toggle-thumb {
  position: absolute;
  top: 0.13em;
  left: 0.13em;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  background: var(--wt-ink-strong);
  transition: left 0.25s cubic-bezier(0.22, 1, 0.36, 1), background-color 0.25s ease;
}
.wt2-toggle.is-on .wt2-toggle-thumb,
.wt2-window[data-open~="qm-on"] .wt2-toggle .wt2-toggle-thumb,
.wt2-window:has(.wt2-frame.is-on[data-qm-on]) .wt2-toggle .wt2-toggle-thumb {
  left: calc(100% - 0.75em - 0.13em);
  background: var(--wt-paper);
}

/* ---- Kebab trigger ----
   Plain characters, no border, matching how the wireframe already leaves
   small affordances (the pencil, the chevron) un-boxed. */
/* This is the control the whole screen is about — the thing the pointer
   reaches for and the only way to any of a row's actions — so it has to look
   like one. At the inherited size in the muted text colour it was a faint
   mark, easy to lose next to the pointer landing on it. */
.page-content span.wt2-kebab {
  display: inline-block;
  font-family: "Roboto Mono", monospace;
  font-size: 1.6em;
  font-weight: 700;
  line-height: 0.85;
  letter-spacing: -1px;
  color: var(--wt-ink-strong);
  padding: 0.1em 0.24em;
  border-radius: 3px;
}
/* It was also the one control the pointer presses that showed nothing for it. */
.wt2-kebab.is-pressed { background: var(--wt-accent-soft); color: var(--wt-accent); }

/* The kebab on the rail's assignment card. The rail sets its own small type,
   and the card sets every span inside it to 0.6em and block — so the kebab
   needs its size back, and the corner it sits in rather than a line of its
   own under the badge. */
.wt2-railcard { position: relative; }
/* The anchor goes out of the way so both the kebab and the menu resolve
   against the card: the kebab belongs in its top corner, and the menu has to
   clear the card's bottom edge. Hung off the kebab instead, the menu opened
   over the card's own title and badge — over the thing it was opened from. */
.wt2-railcard .wt2-menu-anchor { position: static; }
.page-content .wt2-railcard span.wt2-kebab {
  position: absolute;
  top: 0.1em;
  right: 0.1em;
  display: inline-block;
  font-size: 1.15em;
  line-height: 0.9;
  color: var(--wt-ink-strong);
}
/* Right-aligned: the rail is the window's left-hand column, and a menu
   dropping to the right would run out over the content pane. */
.wt2-railcard ul.wt2-menu {
  top: calc(100% + 0.25em);
  right: 0.1em;
  left: auto;
}

/* ---- Dropdown menu ----
   Same shape as .wt2-options in walkthrough-rig.css (bordered popover, paper
   background, cast shadow) — a different class because it hangs off a kebab
   rather than a select, and one item needs its own weight. */
.wt2-menu-anchor { position: relative; display: inline-block; }
.page-content ul.wt2-menu {
  display: none;
  position: absolute;
  /* Above the hand-ink layer (z-index 3, same value used by the table row
     below the menu — with a tie, the later row in DOM order was winning and
     drawing its own border line over the menu, since the menu happens to be
     nested inside an earlier row). */
  z-index: 4;
  top: calc(100% + 0.3em);
  right: 0;
  min-width: 11.5em;
  list-style: none;
  margin: 0;
  padding: 0.3em;
  border: 1.5px solid var(--wt-ink);
  border-radius: 4px;
  background: var(--wt-paper);
  box-shadow: 3px 3px 0 var(--wt-cast);
  text-align: left;
}
/* A menu opens one of two ways. On the screen where the reader watches it
   being opened, it waits for the pointer to press the kebab, which carries
   data-opens="menu" — nothing is open when the screen arrives. On a screen
   that inherits a menu the previous screen's last click already opened, it
   is up from the start, kept open by data-active rather than by data-open
   (which is cleared on every step change, by design — see apply() in
   walkthrough-rig.js) for as long as the screens sharing it say it should be.

   Two rosters (managing-an-assignment, rescuing-a-stalled-chat) now draw
   every row's menu once and hold that single drawing across several steps —
   see the "one drawing for four steps" comment where each roster is marked
   up. A table with more than one interactive row needs its rows told apart,
   so each menu-anchor that can open on its own carries data-row, and its own
   data-opens value (menu-riley, menu-devon) — never the bare "menu" the
   single-purpose rail/QuickMatch kebabs still use below — so pressing one
   row's kebab can never open a different row's menu, on a table with two. */
.wt2-menu-anchor.is-open > ul.wt2-menu,
.wt2-window[data-open~="menu"] .wt2-frame.is-on .wt2-menu-anchor > ul.wt2-menu,
.wt2-window[data-open~="menu-riley"] .wt2-frame.is-on [data-row="riley"] > ul.wt2-menu,
.wt2-window[data-open~="menu-devon"] .wt2-frame.is-on [data-row="devon"] > ul.wt2-menu,
.wt2-window[data-active="offer-cwg"] .wt2-frame.is-on [data-row="riley"] > ul.wt2-menu,
.wt2-window[data-active="partner-action"] .wt2-frame.is-on [data-row="riley"] > ul.wt2-menu,
.wt2-window[data-active="suspend"] .wt2-frame.is-on [data-row="devon"] > ul.wt2-menu { display: block; }
/* A menu hangs below the row it belongs to, and two ancestors clip it. The
   table itself gets overflow:hidden from site.css, which every table on the
   site takes for its rounded corners; .wt2-tablewrap sets overflow-x:auto for
   wide tables, which makes the other axis compute to auto and clip too. On a
   row near the bottom of a roster the two of them cut the menu off entirely,
   so the pointer went and pressed an item nobody could see. Neither of these
   rosters is wide enough to need scrolling and none has rounded corners under
   the drawn outline, so while a menu is open they do not clip. */
.wt2-tablewrap:has(.wt2-menu-anchor),
.page-content table.wt2-table:has(.wt2-menu-anchor) { overflow: visible; }
/* A rail menu is shared shell rather than frame-local, so it cannot carry an
   open class per screen. Same two ways in: pressed open on the screen about
   the menu, already open on the screens that use its items.
   The first of these has to ask which screen is showing. data-open is set on
   the whole window by whichever kebab the pointer pressed, and the rail is
   outside the frames, so an unscoped rule dropped every rail menu open
   whenever any kebab anywhere was pressed — pressing a student row's kebab on
   the Students tab opened the assignment's own menu beside it. A frame that
   owns the rail menu says so with data-rail-menu, and only then does a press
   reach the rail. */
.wt2-window[data-open~="menu"]:has(.wt2-frame.is-on[data-rail-menu]) .wt2-rail ul.wt2-menu,
.wt2-window[data-active="force-matches"] .wt2-rail ul.wt2-menu,
.wt2-window[data-active="force-completion"] .wt2-rail ul.wt2-menu,
/* Force Matches, Force Completion and Export Results are three consecutive
   screens about the same open menu — the reader never leaves it, so it must
   never close and reopen between them. Export's own frame carries no
   data-rail-menu (that attribute is what lets a *press* reach the rail; here
   the menu is inherited, already open, the same reasoning as the two Force…
   screens beside it), so without this line it fell through to no rule at
   all and the menu shut as this screen arrived, only to be pressed open
   again a moment later — a redraw of a menu the reader was already looking
   at. */
.wt2-window[data-active="qm-export-menu"] .wt2-rail ul.wt2-menu { display: block; }

/* ---- The menu as the actual subject of a screen ----
   Sitting open at its ordinary size, next to a card explaining it in depth,
   the menu read as an afterthought rather than the thing being explained.
   On the handful of screens where a menu really is the subject — its own
   introduction, or the two Force… deep-dives — it grows and gets a heavier
   shadow, popping in rather than just appearing, so it visibly outweighs
   everything else on the wireframe the way the card's own attention does. */
.wt2-window[data-open~="menu"] .wt2-frame.is-on .wt2-menu-anchor.is-focus > ul.wt2-menu,
.wt2-window[data-open~="menu-riley"] .wt2-frame.is-on [data-row="riley"] > ul.wt2-menu,
.wt2-window[data-active="offer-cwg"] .wt2-frame.is-on [data-row="riley"] > ul.wt2-menu,
.wt2-window[data-open~="menu-devon"] .wt2-frame.is-on [data-row="devon"] > ul.wt2-menu,
.wt2-window[data-active="suspend"] .wt2-frame.is-on [data-row="devon"] > ul.wt2-menu,
.wt2-window[data-open~="menu"]:has(.wt2-frame.is-on[data-rail-menu]) .wt2-rail ul.wt2-menu,
.wt2-window[data-active="force-matches"] .wt2-rail ul.wt2-menu,
.wt2-window[data-active="force-completion"] .wt2-rail ul.wt2-menu,
.wt2-window[data-active="qm-export-menu"] .wt2-rail ul.wt2-menu {
  transform-origin: top right;
  animation: wt2-menu-pop 0.42s cubic-bezier(0.22, 1, 0.36, 1) both;
  box-shadow: 6px 6px 0 var(--wt-cast);
  border-width: 2px;
}
@keyframes wt2-menu-pop {
  from { opacity: 0; transform: scale(0.8); }
  to { opacity: 1; transform: scale(1.3); }
}
@media (prefers-reduced-motion: reduce) {
  .wt2-menu-anchor.is-open.is-focus > ul.wt2-menu,
  .wt2-window[data-active="offer-cwg"] [data-row="riley"] > ul.wt2-menu,
  .wt2-window[data-active="suspend"] [data-row="devon"] > ul.wt2-menu,
  .wt2-window:has(.wt2-frame.is-on[data-rail-menu]) .wt2-rail ul.wt2-menu,
  .wt2-window[data-active="force-matches"] .wt2-rail ul.wt2-menu,
  .wt2-window[data-active="force-completion"] .wt2-rail ul.wt2-menu,
  .wt2-window[data-active="qm-export-menu"] .wt2-rail ul.wt2-menu {
    animation: none;
    opacity: 1;
    transform: scale(1.3);
  }
}
.page-content ul.wt2-menu li {
  font-family: "Roboto Mono", monospace;
  font-size: 0.72em;
  line-height: 1.95;
  color: var(--wt-ink);
  padding: 0 0.55em;
  margin: 0;
  border-radius: 2px;
  white-space: nowrap;
}
/* Suspend Account reads as the serious one. The wireframe's palette is
   deliberately monochrome ink plus one accent — there is no danger/red token
   anywhere on this site — so weight carries "destructive" instead of colour. */
.page-content ul.wt2-menu li.is-danger { font-weight: 700; color: var(--wt-ink-strong); }
.page-content ul.wt2-menu li.is-pressed { background: var(--wt-accent-soft); }
/* The two Force… screens each linger on one item in the shared QuickMatch
   menu — same shared-shell reasoning as the menu's own open state above. */
.wt2-window[data-active="force-matches"] .wt2-mi-force-matches,
.wt2-window[data-active="force-completion"] .wt2-mi-force-completion,
.wt2-window[data-active="qm-export-menu"] .wt2-mi-export {
  background: var(--wt-accent-soft);
  font-weight: 700;
  color: var(--wt-ink-strong);
}

.wt2-toggle.is-pressed { transform: scale(1.06); }

/* ---- Roster table ----
   The same .wt2-table look (border, cell padding, header fill) used for the
   Matches table on v2, left-aligned instead of centred, with a narrow last
   column for the kebab. */
.page-content table.wt2-table.wt2-roster th,
.page-content table.wt2-table.wt2-roster td { text-align: left; font-weight: 400; }
.page-content table.wt2-table.wt2-roster th:last-child,
.page-content table.wt2-table.wt2-roster td:last-child {
  width: 2.2em;
  text-align: center;
  position: relative;
}
.page-content table.wt2-table.wt2-roster td:first-child { font-size: 0.8em; }

/* ---- Modal ----
   A real modal dims the whole app, not just one pane of it — so .wt2-scrim
   lives outside the frame swap, as a sibling of .wt2-body directly under
   .wt2-window, covering rail and all. It, and the one modal inside it that
   should be showing, are driven by data-active (already tracked on
   .wt2-window for every frame change) exactly the way the rail's own
   QuickMatch menu is: three frames' worth of shared shell content, shown or
   hidden by which screen the reader is on rather than by a class fixed in
   the markup. */
.wt2-scrim {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 5;
  background: rgba(20, 16, 30, 0.32);
}
html.dark-mode .wt2-scrim { background: rgba(0, 0, 0, 0.55); }
/* The dimming covers the whole window, rail included — a real modal darkens
   the whole app, not one pane of it. But centering the modal box in that
   same full width lands it astride either edge: the rail on the left, or
   the card's own reserved gutter on the right (walkthrough-rig.css's
   .wt2-frame padding-right — the card floats there regardless of what the
   window is showing). So the centering is a separate inner box, sized to
   just the content pane, rather than something the full-bleed scrim itself
   does. 14.5em is the rail's own rendered width (12.5em flex-basis + its
   own padding and border) in the same em context the window and the rail
   both share, so it tracks the rail responsively without the two files
   needing to agree on a pixel figure. */
.wt2-modal-slot {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
@media (min-width: 901px) {
  .wt2-modal-slot { left: 14.5em; right: calc(24rem + 1.8rem); }
}
/* The first two open on the previous screen's own last click, so they are
   already up when their screen arrives. Suspend Account is reached from a
   menu on its own screen, so it waits for that click: data-open is set by
   the pointer pressing the item that carries data-opens. */
.wt2-window[data-active="offer-cwg"] .wt2-scrim,
.wt2-window[data-active="partner-action"] .wt2-scrim,
.wt2-window[data-open~="suspend"] .wt2-scrim { display: block; }

.wt2-modal { display: none; }
.wt2-window[data-active="offer-cwg"] .wt2-modal[data-modal="offer-cwg"],
.wt2-window[data-active="partner-action"] .wt2-modal[data-modal="partner-action"],
.wt2-window[data-open~="suspend"] .wt2-modal[data-modal="suspend"] { display: block; }
.wt2-modal {
  width: min(23em, 90%);
  border: 1.5px solid var(--wt-ink);
  border-radius: 6px;
  background: var(--wt-paper);
  box-shadow: 5px 5px 0 var(--wt-cast);
  overflow: hidden;
}
.wt2-modal-head {
  padding: 0.6em 0.8em;
  border-bottom: 1.5px solid var(--wt-ink);
  background: var(--wt-hatch);
  font-size: 0.8em;
  font-weight: 700;
  color: var(--wt-ink-strong);
}
.wt2-modal-body { padding: 0.85em 0.9em 0.3em; }
.page-content .wt2-modal-body p {
  font-family: "Roboto Mono", monospace;
  font-size: 0.68em;
  line-height: 1.7;
  color: var(--text-soft);
  margin: 0 0 0.7em;
}
.wt2-modal-warn {
  border-left: 2px solid var(--wt-ink-strong);
  padding: 0.1em 0 0.1em 0.6em;
  margin: 0.7em 0;
}
.page-content .wt2-modal-warn p { color: var(--wt-ink-strong); margin: 0; }
.wt2-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.7em;
  padding: 0.5em 0.8em 0.8em;
}
.wt2-modal-btn {
  border: 1.5px solid var(--wt-ink-strong);
  border-radius: 4px;
  padding: 0.32em 0.9em;
  font-size: 0.7em;
  font-weight: 700;
  color: var(--wt-ink-strong);
  box-shadow: 2px 2px 0 var(--wt-cast);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.wt2-modal-btn.is-primary { background: var(--wt-accent); border-color: var(--wt-accent); color: var(--wt-paper); }
.wt2-modal-btn.is-ghost { border-color: var(--wt-faint); color: var(--text-soft); box-shadow: none; }
.wt2-modal-btn.is-pressed { transform: translate(2px, 2px); box-shadow: none; }

/* ---- Partner Action radio rows ----
   .wt2-modes/.wt2-mode already exist in walkthrough-rig.css (Assignment vs
   QuickMatch) and already carry hand-ink; reused verbatim for "stacked rows,
   one filled," extended here only with a label + sublabel pair. */
.page-content ul.wt2-modes li.wt2-mode b { display: block; font-size: 1em; }
.page-content ul.wt2-modes li.wt2-mode span {
  display: block;
  font-size: 0.84em;
  font-weight: 400;
  margin-top: 0.2em;
  opacity: 0.82;
}
.page-content ul.wt2-modes li.wt2-mode.is-on span { opacity: 0.92; }
.wt2-modal-body ul.wt2-modes { margin: 0.5em 0 0.2em; }

/* ---- The exported spreadsheet ----
   A downloaded/emailed file isn't part of the chat.swaybeta.ai manage
   screen at all, so unlike every other screen on this page, it doesn't
   live inside the window's tabs or rail — .wt2-xlsx-view replaces .wt2-body
   instead, the same shared-shell/data-active pattern the scrim already
   uses (see the njk comment). The chrome bar above it is left alone: both
   are flex children of .wt2-window, so the file simply takes .wt2-body's
   slot rather than covering the whole window the way the scrim's dim
   deliberately does. */
.wt2-xlsx-view {
  display: none;
  flex: 1;
  min-height: 0;
  overflow: auto;
  background: var(--wt-paper);
  padding: 1.6em 1.9em;
}
/* The floating card still parks over this pane's right side, same as every
   other screen, so the table has to stop short of it. Six columns of
   monospace need more room than a 24rem card leaves at ordinary laptop
   widths, and this is the one screen whose card carries a short paragraph
   and a single note — so here, and only here, it gives a few rem back. The
   reserve is the card's own width: the two are set from the same figure and
   have to stay in step, or the table either runs under the card or stops
   short of where it could have reached. */
@media (min-width: 901px) {
  .wt2-step[data-frame="export-file"] .wt2-card { width: min(19rem, 42%); }
  .wt2-xlsx-view { padding-right: calc(19rem + 0.9rem); }
}
.wt2-window[data-active="export-file"] .wt2-body { display: none; }
.wt2-window[data-active="export-file"] .wt2-xlsx-view { display: block; }

.wt2-xlsx-name {
  font-family: "Roboto Mono", monospace;
  font-size: 0.62em;
  color: var(--text-soft);
  margin: 0 0 0.9em;
  /* A generated filename is one long token with nothing a normal line break
     can use, so on a narrow screen it would otherwise set a floor under the
     whole window rather than wrap. */
  overflow-wrap: anywhere;
}
/* Capped to the pane holding it rather than to the viewport: the row count
   here is arbitrary (six now, more if this example ever grows), and past
   that point a real spreadsheet scrolls its rows under a header that stays
   put, which is what .wt2-tablewrap's own overflow below does — but only
   while this box is short enough to leave it something to scroll within. */
.wt2-xlsx {
  display: flex;
  flex-direction: column;
  width: fit-content;
  max-width: 100%;
  max-height: 100%;
  border: 1.5px solid var(--wt-ink);
  border-radius: 4px;
  background: var(--wt-paper);
  box-shadow: 4px 4px 0 var(--wt-cast);
  padding: 0.9em 1em 1.1em;
}
.page-content .wt2-xlsx-head {
  font-family: "Roboto Mono", monospace;
  font-size: 0.8em;
  font-weight: 700;
  color: var(--wt-ink-strong);
  margin: 0 0 0.55em;
  flex: none;
}
.page-content .wt2-xlsx-kv {
  display: flex;
  gap: 0.7em;
  font-family: "Roboto Mono", monospace;
  font-size: 0.68em;
  color: var(--wt-ink);
  margin: 0 0 0.3em;
  flex: none;
}
.wt2-xlsx-kv b { min-width: 5.5em; color: var(--text-soft); font-weight: 400; }
/* No min-width clamp here on purpose: the box is meant to grow to whatever
   the table needs, and the gutter reserved above is a good deal wider than
   the card actually is, so growing into it still leaves the table well
   clear. Where there genuinely isn't room — a phone — the pane scrolls,
   which it can now do safely: .wt2-stage carries min-width:0, so an
   oversized wireframe no longer widens the page around it. */
.wt2-xlsx .wt2-tablewrap { margin-top: 0.7em; flex: 1; min-height: 0; overflow-y: auto; }
/* On a phone the six columns are wider than the window, so the wrapper
   scrolls sideways — and a column cut off mid-word at the edge reads as
   broken rather than as more to come. A fade over the last few pixels says
   the table continues. It sits above the table and takes no pointer events,
   so the scroll itself is untouched; scroll-driven, so it disappears once
   the reader reaches the end. */
@media (max-width: 860px) {
  .wt2-xlsx .wt2-tablewrap {
    position: relative;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
  }
  /* Once it is scrolled to the end there is nothing more to hint at, and the
     fade would just be eating the last column. */
  .wt2-xlsx .wt2-tablewrap.at-end {
    -webkit-mask-image: none;
    mask-image: none;
  }
}
/* .wt2-table's own base rule is width:100% (right for the roster and Matches
   tables, which should fill their column) — here it stretched every column
   to fill whatever width the full-window .wt2-xlsx-view happened to have,
   giving "100%" and "TRUE" acres of empty space they didn't need. Sizing to
   content instead is what actually makes the numeric columns narrow. */
.page-content table.wt2-table.wt2-xlsx-table { width: auto; }
/* Tighter than the Matches table this inherits from. That one is five short
   numeric columns with room to spare; this is a document with up to six
   text columns that has to sit beside the card, and cell padding is the
   cheapest width to give back — a real spreadsheet's cells are tight too. */
.page-content table.wt2-table.wt2-xlsx-table th,
.page-content table.wt2-table.wt2-xlsx-table td {
  text-align: left;
  font-weight: 400;
  padding: 0.5em 0.32em;
}
.page-content table.wt2-table.wt2-xlsx-table th:nth-child(2),
.page-content table.wt2-table.wt2-xlsx-table td:nth-child(2) { text-align: center; }
/* Every Student value is the same short "Name (email)" shape, narrow enough
   to tempt auto table layout into wrapping it mid-cell on just the longer
   ones, which staggers row heights for no reason. Chat partner carries the
   same shape most of the time, but not always — the assignment version's
   Chat-with-Guide row runs much longer ("Tess (tfarrow) (continued with
   Guide)"), and forcing that not to wrap drags the whole table wide enough
   to run under the card, so only Student gets this. */
.page-content table.wt2-table.wt2-xlsx-table th:nth-child(1),
.page-content table.wt2-table.wt2-xlsx-table td:nth-child(1) { white-space: nowrap; }
/* Chat partner holds the same short values most of the time — a floor
   instead of nowrap, so the one much longer Chat-with-Guide value on the
   assignment version can still wrap instead of dragging the whole column
   (and the table, and the window) that wide. */
.page-content table.wt2-table.wt2-xlsx-table td:nth-child(3) { min-width: calc(17ch + 0.64em); }

@media (max-width: 620px) {
  .wt2-modal { width: min(20em, 94%); }
}
