/* ============================================================================
   PopQuest admin — design system.

   Tokens are defined ONCE, in :root below. No hex literal may appear anywhere
   else in this file; every component reads a variable. The old panel had four
   separate copies of a palette, one per view, already drifting apart.
   ========================================================================== */

:root {
  /* surfaces */
  --ground: #fcfcfd;
  --surface: #ffffff;
  --sunken: #f6f7f9;
  --border: #e4e7ec;
  --border-strong: #d0d5dd;

  /* ink */
  --ink: #101828;
  --ink-muted: #667085;
  --ink-subtle: #98a2b3;

  /* accent — primary action and current state only, never decoration */
  --accent: #5a3fc0;
  --accent-hover: #4b34a8;
  --accent-wash: #f1eefb;
  --accent-border: #ddd3f8;

  /* semantic — state only, kept separate from the accent */
  --success: #067647;
  --success-wash: #ecfdf3;
  --success-border: #abefc6;
  --warning: #b54708;
  --warning-deep: #93370d;
  --warning-wash: #fffaeb;
  --warning-border: #fedf89;
  --danger: #b42318;
  --danger-hover: #912018;
  --danger-deep: #912018;
  --danger-wash: #fef3f2;
  --danger-border: #fecdc9;

  /* spacing, 4px base */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;

  --r-badge: 4px;
  --r: 6px;
  --r-card: 8px;

  --h-control: 36px;
  --h-control-sm: 30px;
  --h-row: 44px;
  --w-sidebar: 216px;
  --h-topbar: 56px;

  --shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-pop: 0 20px 44px -12px rgba(16, 24, 40, 0.24), 0 0 0 1px rgba(16, 24, 40, 0.05);

  --font: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  font-size: 13.5px;
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-badge);
}

.mono { font-family: var(--mono); font-size: 12.5px; }
.muted { color: var(--ink-muted); }
.subtle { color: var(--ink-subtle); }

.lbl {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-subtle);
}

h1 { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
h2 { margin: 0; font-size: 15px; font-weight: 600; }

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

.shell { display: flex; min-height: 100%; }

.sidebar {
  width: var(--w-sidebar);
  flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}

.brand {
  height: var(--h-topbar);
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 var(--s4);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.brand-mark {
  width: 24px; height: 24px; border-radius: var(--r);
  background: var(--accent);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.brand-name { font-size: 13px; font-weight: 600; line-height: 1.2; }
.brand-sub { font-size: 10.5px; color: var(--ink-subtle); line-height: 1.2; }

/* flex:1 with min-height:0 lets the nav take the leftover height and scroll INSIDE itself, which
   is what keeps .sidebar-foot -- the signed-in name and the sign-out button -- pinned in view. It
   used to be pushed off the bottom, and the only way to reach sign-out was to scroll the page. */
.nav {
  padding: var(--s3) 10px;
  display: flex; flex-direction: column; gap: 2px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.nav-group { padding: var(--s2) 10px var(--s1); }

.navitem {
  display: flex; align-items: center; gap: 10px;
  height: 34px; padding: 0 10px;
  border-radius: var(--r);
  color: var(--ink-muted);
  font-size: 13px; font-weight: 500;
  text-decoration: none;
  transition: background 0.14s ease, color 0.14s ease;
}
.navitem:hover { background: var(--sunken); color: var(--ink); text-decoration: none; }
.navitem[aria-current="page"] { background: var(--accent-wash); color: var(--accent); font-weight: 600; }
.navitem .count { margin-left: auto; }

.sidebar-foot {
  margin-top: auto;
  flex-shrink: 0;
  padding: var(--s3);
  border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 9px;
}
.avatar {
  width: 28px; height: 28px; border-radius: var(--r);
  background: var(--sunken); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 11.5px; font-weight: 600; color: var(--ink-muted);
  flex-shrink: 0;
}

.main { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  height: var(--h-topbar);
  flex-shrink: 0;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--s4);
  padding: 0 var(--s5);
  position: sticky; top: 0; z-index: 5;
}
.crumbs { display: flex; align-items: center; gap: var(--s2); font-size: 13px; }
.crumbs a { color: var(--ink-subtle); }
.crumbs .sep { color: var(--ink-subtle); display: flex; }
.crumbs .current { font-weight: 600; }
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 10px; }

.page { padding: var(--s5); display: flex; flex-direction: column; gap: var(--s5); }
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s5); }
.page-head p { margin: var(--s1) 0 0; font-size: 13px; color: var(--ink-muted); max-width: 90ch; }

.divider { width: 1px; height: 22px; background: var(--border); }

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

.btn {
  height: var(--h-control);
  padding: 0 14px;
  border-radius: var(--r);
  border: 1px solid transparent;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  text-decoration: none;
  transition: background 0.14s ease, border-color 0.14s ease, color 0.14s ease;
}
.btn:hover { text-decoration: none; }
.btn-sm { height: var(--h-control-sm); padding: 0 11px; font-size: 12.5px; gap: 6px; }
.btn-icon { padding: 0 8px; }

.btn-primary { background: var(--accent); color: var(--surface); border-color: var(--accent); }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--surface); }

.btn-secondary { background: var(--surface); color: var(--ink); border-color: var(--border-strong); box-shadow: var(--shadow); }
.btn-secondary:hover { background: var(--sunken); color: var(--ink); }

.btn-ghost { background: transparent; color: var(--ink-muted); }
.btn-ghost:hover { background: var(--sunken); color: var(--ink); }

.btn-danger { background: var(--danger); color: var(--surface); border-color: var(--danger); }
.btn-danger:hover { background: var(--danger-hover); border-color: var(--danger-hover); color: var(--surface); }

.btn-danger-quiet { background: var(--surface); color: var(--danger); border-color: var(--danger-border); }
.btn-danger-quiet:hover { background: var(--danger-wash); color: var(--danger); }

.btn-warning { background: var(--warning); color: var(--surface); border-color: var(--warning); }

.btn[disabled], .btn[aria-disabled="true"] {
  background: var(--sunken);
  color: var(--ink-subtle);
  border-color: var(--border);
  cursor: not-allowed;
  box-shadow: none;
}

/* ----------------------------------------------------------------- inputs -- */

.field { display: flex; flex-direction: column; gap: var(--s1); }

.input {
  height: var(--h-control);
  width: 100%;
  padding: 0 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow);
  font-family: inherit;
  font-size: 13.5px;
  color: var(--ink);
}
textarea.input { height: auto; padding: 10px 11px; line-height: 1.6; resize: vertical; }
select.input { cursor: pointer; }
.input::placeholder { color: var(--ink-subtle); }
.input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-wash); }
.input[disabled] { background: var(--sunken); color: var(--ink-subtle); }

/* Only the offending input reddens. Scoping this as `.is-invalid .input` made marking a group
   (the options block, for a missing correct answer) redden all four inputs inside it. */
.input.is-invalid { border-color: var(--danger); box-shadow: 0 0 0 3px var(--danger-wash); }

/* Group-level invalid: label goes red, the inputs inside are left alone. */
.field.is-invalid > .lbl,
.field.is-invalid > div > .lbl { color: var(--danger); }

.field-error { font-size: 12px; color: var(--danger); display: flex; align-items: center; gap: 6px; }
.field-hint { font-size: 11.5px; color: var(--ink-subtle); }

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

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
}
.card-head {
  height: 48px;
  padding: 0 var(--s4);
  display: flex;
  align-items: center;
  gap: var(--s3);
  border-bottom: 1px solid var(--border);
}
.card-body { padding: var(--s4) 18px; }
.card-pad { padding: 14px var(--s4); }

.stat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s3); }
.stat { padding: 14px var(--s4); display: flex; flex-direction: column; gap: 7px; }
.stat-value { font-size: 22px; font-weight: 600; line-height: 1; }

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

.table-wrap { overflow-x: auto; }

table.data { width: 100%; border-collapse: collapse; }
table.data thead th {
  height: var(--h-control);
  padding: 0 var(--s4);
  text-align: left;
  background: var(--sunken);
  border-bottom: 1px solid var(--border);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-subtle);
  white-space: nowrap;
}
table.data tbody td {
  /* Pinned, not content-derived: skeleton rows must match exactly or the page jumps on load. */
  height: var(--h-row);
  padding: 0 var(--s4);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover { background: var(--sunken); }
.num { text-align: right; }
.nowrap { white-space: nowrap; }

/* Row actions appear on hover, and on keyboard focus so they are never unreachable. */
.rowact { display: flex; gap: 6px; justify-content: flex-end; }

/* Fading row actions in on hover is a desktop nicety, and it must stay one: a touch device never
   hovers, and :focus-within needs a descendant focused -- which means tapping a control that is
   invisible. Scoping the hiding to pointers that can actually hover leaves the buttons permanently
   visible on a phone, where they are the only way to publish, edit or delete anything. */
@media (hover: hover) and (pointer: fine) {
  .rowact { opacity: 0; transition: opacity 0.14s ease; }
  tr:hover .rowact, tr:focus-within .rowact { opacity: 1; }
}

/* --------------------------------------------------------- badges & chips -- */

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 var(--s2);
  border-radius: var(--r-badge);
  font-size: 11.5px; font-weight: 600;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge .dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }

/* `display` on a component class beats the hidden attribute's UA `display:none`, which left an
   empty badge painted in the sidebar. This restores the attribute's meaning for every component. */
[hidden] { display: none !important; }

.badge-ok { background: var(--success-wash); color: var(--success); border-color: var(--success-border); }
.badge-drift { background: var(--warning-wash); color: var(--warning); border-color: var(--warning-border); }
.badge-empty, .badge-danger { background: var(--danger-wash); color: var(--danger); border-color: var(--danger-border); }
.badge-neutral { background: var(--sunken); color: var(--ink-muted); border-color: var(--border); }
.badge-accent { background: var(--accent-wash); color: var(--accent); border-color: var(--accent-border); }

.chip {
  height: var(--h-control-sm);
  padding: 0 var(--s3);
  border-radius: var(--r);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--ink-muted);
  font-family: inherit; font-size: 12.5px; font-weight: 500;
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  transition: background 0.14s ease, color 0.14s ease, border-color 0.14s ease;
}
.chip:hover { background: var(--sunken); color: var(--ink); }
.chip[aria-pressed="true"] { background: var(--accent-wash); border-color: var(--accent-border); color: var(--accent); }
.chip .count { font-weight: 600; }

.toolbar { height: 52px; padding: 0 var(--s4); display: flex; align-items: center; gap: var(--s2); border-bottom: 1px solid var(--border); }

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

.banner {
  display: flex; gap: var(--s3);
  padding: 14px var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  background: var(--surface);
}
.banner svg { flex-shrink: 0; margin-top: 1px; }
.banner-body { display: flex; flex-direction: column; gap: 3px; flex-grow: 1; }
.banner-title { font-size: 13px; font-weight: 600; }
.banner-text { font-size: 12.5px; line-height: 1.55; }

.banner-warning { background: var(--warning-wash); border-color: var(--warning-border); }
.banner-warning .banner-title { color: var(--warning); }
.banner-warning .banner-text { color: var(--warning-deep); }

.banner-danger { background: var(--danger-wash); border-color: var(--danger-border); }
.banner-danger .banner-title { color: var(--danger); }
.banner-danger .banner-text { color: var(--danger-deep); }

.banner-accent { background: var(--accent-wash); border-color: var(--accent-border); }
.banner-accent .banner-title { color: var(--accent); }

/* ------------------------------------------------------- empty & skeleton -- */

.empty {
  padding: 48px var(--s5);
  display: flex; flex-direction: column; align-items: center; gap: var(--s3);
  text-align: center;
}
.empty-icon {
  width: 40px; height: 40px; border-radius: var(--r-card);
  background: var(--sunken); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
}
.empty-title { font-size: 13.5px; font-weight: 600; }
.empty-body { font-size: 12.5px; color: var(--ink-muted); max-width: 46ch; line-height: 1.55; }

.skel {
  background: linear-gradient(90deg, var(--sunken) 0%, var(--border) 50%, var(--sunken) 100%);
  background-size: 200% 100%;
  border-radius: var(--r-badge);
  height: 11px;
  animation: shimmer 1.4s ease-in-out infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }

/* ---------------------------------------------------------------- toasts -- */

#toasts {
  position: fixed; bottom: var(--s4); right: var(--s4);
  display: flex; flex-direction: column; gap: var(--s2);
  z-index: 50;
}
.toast {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 7px;
  box-shadow: var(--shadow-pop);
  font-size: 13px;
  max-width: 460px;
}
.toast-ok svg { color: var(--success); }
.toast-danger { border-color: var(--danger-border); }
.toast-danger svg { color: var(--danger); }
.toast-info svg { color: var(--accent); }

/* --------------------------------------------------------------- dialogs -- */

dialog.sheet {
  padding: 0;
  border: 0;
  border-radius: 10px;
  box-shadow: var(--shadow-pop);
  background: var(--surface);
  color: var(--ink);
  width: 540px;
  max-width: calc(100vw - 32px);
}
dialog.sheet::backdrop { background: rgba(16, 24, 40, 0.35); }
.sheet-head { padding: 20px 22px 0; display: flex; gap: 14px; align-items: flex-start; }
.sheet-icon {
  width: 38px; height: 38px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.sheet-icon-danger { background: var(--danger-wash); border: 1px solid var(--danger-border); color: var(--danger); }
.sheet-icon-warning { background: var(--warning-wash); border: 1px solid var(--warning-border); color: var(--warning); }
.sheet-title { font-size: 15px; font-weight: 600; }
.sheet-sub { font-size: 13px; color: var(--ink-muted); line-height: 1.55; }
.sheet-body { padding: 18px 22px 20px; display: flex; flex-direction: column; gap: 14px; }
.sheet-foot {
  padding: 14px 22px;
  border-top: 1px solid var(--border);
  background: var(--sunken);
  display: flex; align-items: center; gap: 9px;
}
.sheet-foot .right { margin-left: auto; display: flex; gap: 9px; }

/* -------------------------------------------------------------- questions -- */

.q-list { display: flex; flex-direction: column; gap: 14px; }
.q-row { display: flex; gap: 14px; align-items: flex-start; }
.q-num {
  flex-shrink: 0;
  width: 22px; height: 22px;
  border-radius: 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: 11.5px; font-weight: 600; color: var(--ink-muted);
  display: flex; align-items: center; justify-content: center;
  margin-top: 1px;
}
.q-body { display: flex; flex-direction: column; gap: 9px; flex-grow: 1; min-width: 0; }
.q-statement { font-size: 13.5px; font-weight: 500; line-height: 1.5; }

.opt-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s2); }

.opt {
  display: flex; align-items: center; gap: 10px;
  min-height: 38px; padding: 6px 12px;
  border-radius: var(--r);
  border: 1px solid var(--border);
  background: var(--surface);
}
.opt-correct { border-color: var(--success-border); background: var(--success-wash); }
.opt-ring {
  width: 16px; height: 16px; border-radius: 50%;
  border: 1.5px solid var(--border-strong);
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.opt-correct .opt-ring { border-color: var(--success); }
.opt-ring i { width: 8px; height: 8px; border-radius: 50%; background: var(--success); display: block; }
.opt-text { font-size: 13px; color: var(--ink-muted); flex-grow: 1; min-width: 0; }
.opt-correct .opt-text { color: var(--ink); }
.opt-key { font-size: 9.5px; }

/* Editor options: the radio is the control, the whole row is the label. */
.opt-edit { cursor: pointer; padding: 0; border: 0; background: none; display: flex; align-items: center; gap: var(--s2); }
.opt-edit input[type="radio"] { width: 16px; height: 16px; accent-color: var(--success); flex-shrink: 0; cursor: pointer; margin: 0; }
.opt-edit .input { flex-grow: 1; }
.opt-edit:has(input:checked) .input { border-color: var(--success-border); background: var(--success-wash); }

.editor-card-invalid { border-color: var(--danger-border); }
.editor-card-invalid .card-head { background: var(--danger-wash); }

/* ---------------------------------------------------------------- health -- */

.issue { display: flex; align-items: center; gap: 14px; padding: 15px var(--s4); border-bottom: 1px solid var(--border); }
.issue:last-child { border-bottom: 0; }
.issue:hover { background: var(--sunken); }
.issue-stripe { width: 6px; height: 34px; border-radius: 3px; flex-shrink: 0; }
.issue-body { display: flex; flex-direction: column; gap: 3px; flex-grow: 1; min-width: 0; }
.issue-title { font-size: 13.5px; font-weight: 600; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.issue-detail { font-size: 12.5px; color: var(--ink-muted); line-height: 1.5; }

.sev-blocking { background: var(--danger); }
.sev-critical { background: var(--danger); }
.sev-drift { background: var(--warning); }
.sev-review { background: var(--ink-subtle); }

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

.login-wrap {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 40px;
}
/* min(), not a flat 380px. The wrapper's 40px of padding each side put the minimum width of this
   page at 460px, so the sign-in card ran off the right edge of every phone -- on the one screen
   nobody can skip, and the one place a cut-off form is most alarming. */
.login-col { width: min(380px, 100%); display: flex; flex-direction: column; gap: 20px; }
.login-mark {
  width: 36px; height: 36px; border-radius: var(--r-card);
  background: var(--accent);
  display: flex; align-items: center; justify-content: center;
}

/* ------------------------------------------------------------ tracking -- */

/* A checkbox and a two-line label. Used by the App tracking page for both the switches and the
   level list, so a switch and a level row line up on the same grid. */
.track-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  /* The whole row is the target, not just the 13px box -- this is the tap area on a phone. */
  padding: 2px 0;
}
.track-row input[type="checkbox"] {
  /* Aligns the box with the first line of text rather than the middle of the block. */
  margin: 2px 0 0;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  accent-color: var(--accent);
}
.track-row > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.track-row strong { font-weight: 600; font-size: 13px; }
.track-row code { font-size: 11px; word-break: break-all; }

.track-level {
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 9px 11px;
  background: var(--surface);
}
.track-level:hover { background: var(--sunken); }
.track-level:has(input:checked) { border-color: var(--accent); background: var(--accent-wash, var(--sunken)); }

/* ------------------------------------------------------------ responsive -- */

/* The panel is used from a phone to check a level or publish a quiz between other things, so
   everything below has to work at 390px, not merely avoid overflowing. Measured widths, not
   guesses: the sidebar is a fixed 216px, which is 55% of a 390px screen, and the two tables are
   650px and 710px of columns. */

@media (max-width: 1024px) {
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .opt-grid { grid-template-columns: 1fr; }
}

/* Base state: neither exists on a desktop. Declared BEFORE the media query
   below, because both are single-class selectors -- equal specificity, so
   source order is what decides, and a base rule placed after the query would
   silently win at every width and leave the drawer with no way to open. */
.nav-toggle { display: none; flex-shrink: 0; padding: 0 8px; }
.nav-scrim { display: none; }

/* -- the sidebar becomes a drawer ------------------------------------------
   Below this width the sidebar is taking more room than the content it is
   there to navigate. It leaves the flow entirely and slides over instead. The
   markup does not change: the same <aside> is the drawer, so there is no
   second copy of the nav to keep in step. */
@media (max-width: 860px) {
  .sidebar {
    position: fixed;
    z-index: 60;
    top: 0;
    left: 0;
    width: min(280px, 84vw);
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    box-shadow: 0 0 0 1px var(--border), 0 12px 32px rgba(16, 24, 40, 0.16);
  }
  .sidebar.is-open { transform: translateX(0); }

  /* Covers the page while the drawer is open. `hidden` is what makes it
     unhittable the rest of the time -- a permanently present transparent
     overlay would swallow every click on the page underneath. */
  .nav-scrim:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgba(16, 24, 40, 0.38);
  }

  .nav-toggle { display: inline-flex; }

  /* The topbar is the only chrome left, so the breadcrumb has to give way
     before the toggle does. */
  .topbar { padding: 0 var(--s3); gap: var(--s2); }
  .crumbs { min-width: 0; overflow: hidden; }
  /* All but the immediate parent, which is the only crumb anyone taps -- it is
     the way back from a level to the list. The drawer covers everything else. */
  .crumbs a, .crumbs .sep { display: none; }
  .crumbs a:last-of-type { display: inline-block; }
  .crumbs a:last-of-type + .sep { display: inline-flex; }
  .crumbs .current { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  .page { padding: var(--s4) var(--s3); }

  /* The switcher popover is anchored to a sidebar that is now off-screen. */
  .app-menu { left: 12px; right: 12px; width: auto; }
}

/* -- phones ---------------------------------------------------------------- */
@media (max-width: 640px) {
  .page-head { flex-direction: column; align-items: stretch; gap: var(--s3); }
  .page-head > div:last-child { display: flex; flex-wrap: wrap; gap: 8px; }

  /* Two up, not one. These hold a short number or an id, and stacking them made
     four cards' worth of scrolling sit between the page heading and the quiz
     list -- which is the thing the page is actually for. */
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* 16px is not a design choice. Any smaller and iOS Safari zooms the page on
     focus, which leaves the operator scrolled sideways into a form they then
     have to pinch back out of -- on every single field. */
  .input, select.input, textarea.input { font-size: 16px; }

  /* 36px is below every touch-target guideline, and these are the controls
     that publish and delete content. */
  :root { --h-control: 44px; --h-control-sm: 38px; }

  /* Both tables are far wider than a phone. They already scroll inside
     .table-wrap, so nothing breaks -- but the useful columns are off-screen
     until you scroll to them. Dropping the two that answer nothing at a glance
     brings the rest into view. Both are still on the level's own page.

     Indices, so header and cells cannot fall out of step: whichever rule hides
     column N hides it in <thead> and <tbody> together.

     The quiz list drops its question count as well. With the actions column
     pinned to the right there is only room for one more, and it has to be
     Status: Draft against Live is the whole point of that page, while the
     count is a badge you can read by expanding the row.

     The level list drops Stored and Actual for the same reason. They are the
     raw numbers behind the Status badge, and that badge already says which way
     they disagree -- squeezed in beside it they left Status too narrow, and its
     badges collapsed into a stack of coloured dots. */
  .table-levels th:nth-child(2), .table-levels td:nth-child(2),   /* ID */
  .table-levels th:nth-child(3), .table-levels td:nth-child(3),   /* Stored */
  .table-levels th:nth-child(4), .table-levels td:nth-child(4),   /* Actual */
  .table-levels th:nth-child(6), .table-levels td:nth-child(6),   /* Created */
  .table-quizzes th:nth-child(2), .table-quizzes td:nth-child(2), /* Quiz ID */
  .table-quizzes th:nth-child(3), .table-quizzes td:nth-child(3), /* Created */
  .table-quizzes th:nth-child(4), .table-quizzes td:nth-child(4)  /* Questions */
    { display: none; }

  /* Freed of the fixed widths above, the remaining columns can size to content. */
  .table-levels th, .table-quizzes th { width: auto !important; }

  /* Row actions keep their 38px height -- they are the publish and delete
     controls and must stay easy to hit -- but lose horizontal padding. */
  .rowact .btn { padding: 0 10px; font-size: 12px; gap: 4px; }

  /* Status can hold two badges -- the level's state, and a draft count. Given
     room they sit side by side; given less they wrap as whole badges rather
     than tearing apart mid-badge. */
  .table-levels td:nth-child(5) { white-space: normal; }
  .table-levels td:nth-child(5) .badge { margin: 1px 0; }

  /* And the actions column is pinned to the right edge, so Publish and Delete
     stay on screen while the data columns scroll underneath. Trimming columns
     alone could not fix this: the actions cell is the widest one, so whatever
     else was removed it still ended up half off the screen -- and clipped at
     the edge it gives no hint that anything is there to scroll to.

     The background is required. Without it the scrolling cells show through the
     pinned one, which reads as a rendering fault rather than a fixed column. */
  .table-levels td:last-child, .table-levels th:last-child,
  .table-quizzes td:last-child, .table-quizzes th:last-child {
    position: sticky;
    right: 0;
    background: var(--surface);
    box-shadow: -1px 0 0 var(--border);
  }
  .table-levels tbody tr:hover td:last-child,
  .table-quizzes tbody tr:hover td:last-child { background: var(--sunken); }
  .table-levels th:last-child, .table-quizzes th:last-child { background: var(--sunken); }

  /* A dialog defaults to a comfortable desktop width and overflows a phone. */
  .sheet { width: calc(100vw - 24px); max-width: none; max-height: 88vh; }
  .sheet-body { max-height: 60vh; overflow-y: auto; }

  .card-head { flex-wrap: wrap; gap: 8px; }

  /* 40px a side is a desktop margin; on a phone it is a fifth of the screen. */
  .login-wrap { padding: 24px 16px; }

  /* The filter chips plus a right-aligned count do not fit one line on a phone.
     Letting the row wrap puts the count on its own line instead of squeezing it
     into a three-line column beside the chips. */
  .toolbar { flex-wrap: wrap; row-gap: 8px; }
  .toolbar #showing { margin-left: 0 !important; width: 100%; }

  /* The nav is the drawer's whole reason to exist, so its entries are the last
     thing that should be hard to hit. 34px is below every touch guideline. */
  .navitem { height: 44px; }
  .app-menu-item { min-height: 44px; }

  /* The answer radios are 16px squares sitting next to a full-width text input.
     Enlarging the control itself is the only thing that helps -- the label
     around it is already tall, and tapping the label's text lands in the input
     rather than on the radio.

     The selector has to match .opt-edit's own, at line ~521 -- a bare
     input[type=radio] loses to it on specificity and does nothing. */
  .opt-edit input[type="radio"],
  input[type="radio"], input[type="checkbox"] { width: 22px; height: 22px; flex-shrink: 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------- two apps --
   The panel renders byte-identical pages for two different datasets, one of
   which is read by an app with ~100k installs. Everything below exists for that
   one risk: making which app you are in visible without having to read a label.

   The accent is overridden per app on <body>, so it repaints the sidebar, every
   primary button, every focus ring and every accent badge -- on every page,
   including empty and error states, which a header banner alone would miss. */

body.app-guru {
  --accent: #b54708;          /* amber: QuizGuru, the published app */
  --accent-hover: #93370d;
  --accent-wash: #fffaeb;
  --accent-border: #fedf89;
}

body.app-popquest {
  --accent: #5a3fc0;          /* violet: PopQuest, the panel's original palette */
}

/* Shown ONLY when this app's store points at real user data. Local runs get no
   strip at all, so the ABSENCE of it is the signal -- a badge that reads "local"
   is one you stop seeing after a day. */
/* Replaces the full-width red strip. Same warning, no band of vertical space: it rides on the app
   switcher, which is the control that decides which dataset you are editing. */
.live-pill {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: var(--r-badge);
  background: var(--danger);
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  vertical-align: 1px;
}

/* The brand doubles as the app switcher, so it has to read as pressable without
   becoming a button that shouts. Same box as the old static brand, plus a caret. */
.brand-switch {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-radius: 9px;
  transition: background .12s ease;
}
.brand-switch:hover { background: var(--sunken); }
.brand-switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.brand-caret { color: var(--ink-subtle); flex-shrink: 0; }

/* Pinned under the brand rather than anchored to it: CSS anchor positioning is not
   everywhere yet, and the sidebar is a fixed-width column at a fixed corner, so the
   position is knowable without it. */
.app-menu {
  position: fixed;
  top: 62px;
  left: 12px;
  width: 236px;
  margin: 0;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  /* An explicit opaque colour, not a token that might not exist and not `inherit`.
     A popover renders in the TOP LAYER, above the page, so anything less than fully
     opaque shows the sidebar straight through it -- which is exactly what happened
     when this said var(--panel): no such token is defined, so it resolved to nothing
     and the menu was transparent. */
  background-color: var(--surface);
  box-shadow: var(--shadow-pop);
  overflow: visible;
}
.app-menu::backdrop { background: transparent; }
/* The trigger keeps its hover tint while the menu is open, so the two read as one control. */
.brand-switch:has(+ .app-menu:popover-open) { background: var(--sunken); }

.app-menu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 9px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--ink);
}
.app-menu-item:hover { background: var(--sunken); }
.app-menu-item[aria-current="true"] { background: var(--accent-wash); color: var(--accent); }
.app-menu-name { display: block; font-size: 13px; font-weight: 600; }
.app-menu-sub { display: block; font-size: 10.5px; color: var(--ink-subtle); }

/* Each row carries its OWN app's accent, not the current page's -- so the colour you
   are about to switch into is visible before you commit to it. */
.app-menu-item .app-dot {
  width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; background: var(--accent);
}
.app-menu-item.app-guru { --accent: #b54708; --accent-wash: #fffaeb; }
.app-menu-item.app-popquest { --accent: #5a3fc0; --accent-wash: #f1eefb; }

/* ------------------------------------------------------------ import page --
   Two columns on a desktop: the controls at a fixed 560px and the preview
   taking the rest. Below the drawer width they stack -- the fixed width with
   flex-shrink:0 forced the page itself to 705px on a 390px phone, which is the
   one thing .table-wrap cannot rescue, because it is the page scrolling and
   not a table. */
.import-cols { display: flex; gap: 20px; align-items: flex-start; }
.import-side { width: 560px; flex-shrink: 0; display: flex; flex-direction: column; gap: 14px; }

@media (max-width: 1100px) {
  .import-cols { flex-wrap: wrap; }
  .import-side { width: 100%; flex-shrink: 1; }
  .import-cols > .card { min-width: 0; width: 100%; }
}
