:root {
  --bg: #f7f8fa;
  --surface: #ffffff;
  --surface-2: #f1f3f7;
  --border: #dfe3ea;
  --text: #1a1d23;
  --muted: #6b7280;
  --accent: #2f6feb;
  --accent-soft: #e7effd;
  --shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .08);

  --ok: #14804a;      --ok-bg: #e3f5eb;
  --bad: #c2334d;     --bad-bg: #fdeaee;
  --warn: #9a6400;    --warn-bg: #fdf1dc;
  --info: #2f6feb;    --info-bg: #e7effd;
  --neutral: #5b6472; --neutral-bg: #eceff4;

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --radius: 8px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #12141a;
    --surface: #191c23;
    --surface-2: #21252e;
    --border: #2c313c;
    --text: #e6e8ec;
    --muted: #949cab;
    --accent: #5b91ff;
    --accent-soft: #1b2740;
    --shadow: 0 1px 2px rgba(0, 0, 0, .3);

    --ok: #4ade80;      --ok-bg: #10291d;
    --bad: #f87f92;     --bad-bg: #2e1620;
    --warn: #eab661;    --warn-bg: #2b2113;
    --info: #7aa7ff;    --info-bg: #16203a;
    --neutral: #9aa3b2; --neutral-bg: #232833;
  }
}

* { box-sizing: border-box; }

/* The `hidden` attribute is enforced only by the UA stylesheet, which *any*
   author rule outranks — `label { display: block }` below was silently
   un-hiding hidden labels. Restore it with a rule nothing else can beat. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

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

/* ---------- layout ---------- */

.topbar {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 0 24px;
  height: 56px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 10;
}
.brand {
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -.02em;
  color: var(--text);
}
.brand:hover { text-decoration: none; }
.topbar nav { display: flex; gap: 4px; }
.topbar nav a {
  padding: 6px 12px;
  border-radius: var(--radius);
  color: var(--muted);
  font-weight: 500;
  font-size: 14px;
}
.topbar nav a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.topbar nav a.active { background: var(--accent-soft); color: var(--accent); }
.spacer { flex: 1; }
#account { display: flex; align-items: center; gap: 10px; font-size: 14px; }

main {
  max-width: 1120px;
  margin: 0 auto;
  padding: 28px 24px 64px;
}
main.wide { max-width: 1400px; }

.footer {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 24px 32px;
  color: var(--muted);
  font-size: 12.5px;
  font-family: var(--mono);
}

/* ---------- primitives ---------- */

h1 { font-size: 24px; letter-spacing: -.02em; margin: 0 0 4px; }
h2 { font-size: 18px; letter-spacing: -.01em; margin: 28px 0 10px; }
h3 { font-size: 15px; margin: 20px 0 8px; }
.page-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 18px; }
.muted { color: var(--muted); }
.small { font-size: 13px; }
.mono { font-family: var(--mono); }
.loading { color: var(--muted); padding: 40px 0; text-align: center; }
.empty {
  padding: 40px 20px; text-align: center; color: var(--muted);
  border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface);
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px 20px;
  margin-bottom: 18px;
}
.card > :first-child { margin-top: 0; }

.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.row.end { justify-content: flex-end; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }

/* A problem page is one thing you read and one thing you type into once. Split
 * evenly, the statement gets a narrow column while the other half runs out of
 * content below the code box, so the reading side takes the larger share. */
.problem-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
/* Deliberately not sticky. Pinning this column keeps the code box in view on a
 * long statement, but the column is taller than most windows, which leaves the
 * choice between an inner scrollbar and content that cannot be reached at all.
 * Neither is worth it. */
.problem-work textarea.code { min-height: 240px; resize: vertical; }
@media (max-width: 1080px) {
  .problem-layout { grid-template-columns: 1fr; }
}
@media (max-width: 820px) {
  .grid-2 { grid-template-columns: 1fr; }
  .topbar { padding: 0 14px; gap: 10px; }
  .topbar nav a { padding: 6px 8px; }
  main { padding: 20px 14px 48px; }
}

button, .btn {
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  padding: 7px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
/* `.btn` is the same control rendered as a link, so every state pairs the two. */
.btn { display: inline-block; }
button:hover:not(:disabled), .btn:hover { background: var(--surface-2); text-decoration: none; }
button:disabled { opacity: .55; cursor: not-allowed; }
button.primary, .btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
button.primary:hover:not(:disabled), .btn.primary:hover { filter: brightness(1.08); background: var(--accent); }
button.ghost { background: transparent; }
button.danger { color: var(--bad); border-color: var(--bad); background: transparent; }
/* An account that still has to confirm its email. Coloured like a warning
   rather than an error: nothing is broken, something is unfinished. */
button.warn, .btn.warn {
  background: var(--warn-bg); color: var(--warn); border-color: transparent;
}
button.small, .btn.small { padding: 4px 9px; font-size: 13px; }

/* A segmented control: two views of one list, joined so the pair reads as a
   choice with a current position. Deliberately quieter than .btn.primary,
   which is for the thing you press, not for where you already are. Centred
   against the heading rather than sitting on its baseline — .page-head aligns
   text, and a bordered box on a baseline hangs below the line. */
.segmented {
  display: inline-flex;
  align-self: center;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}
.segmented a {
  font-size: 13px;
  font-weight: 500;
  padding: 5px 12px;
  color: var(--muted);
}
.segmented a + a { border-left: 1px solid var(--border); }
.segmented a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
/* The current view. Tinted rather than filled: it is a position, not a button
   that has been pressed, and it sits beside a heading it must not shout over. */
.segmented a[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent);
}

input, select, textarea {
  font: inherit;
  font-size: 14px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  width: 100%;
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent-soft);
  border-color: var(--accent);
}
label { display: block; font-size: 13px; font-weight: 500; color: var(--muted); margin-bottom: 12px; }
label input, label select, label textarea { margin-top: 4px; font-weight: 400; color: var(--text); }
textarea.code {
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;
  min-height: 340px;
  tab-size: 4;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}
.error { color: var(--bad); font-size: 13px; }
input.search { width: 220px; }

/* A checkbox and its word sit on one line; every other label stacks. */
label.check { display: flex; align-items: center; gap: 6px; margin-bottom: 12px; }
label.check input { width: auto; margin: 0; }

.info {
  position: relative; align-self: center;
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  border: 1px solid var(--border); color: var(--muted);
  font-size: 12px; font-weight: 600; line-height: 1; cursor: help;
}
.info:hover, .info:focus { color: var(--text); border-color: var(--muted); }
.info-pop {
  position: absolute; top: calc(100% + 8px); left: -10px; z-index: 20;
  width: min(360px, 78vw); padding: 12px 14px; cursor: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  color: var(--muted); font-size: 13px; font-weight: 400; line-height: 1.55;
  visibility: hidden; opacity: 0; transition: opacity .12s;
}
.info:hover .info-pop, .info:focus .info-pop { visibility: visible; opacity: 1; }
.info-pop p { margin: 0 0 8px; }
.info-pop p:last-child { margin: 0; }

th.sort { cursor: pointer; user-select: none; }
th.sort:hover, th.sort.active { color: var(--text); }
th.sort .arrow { margin-left: 4px; }
.filters { margin-bottom: 14px; }
.filters input { width: auto; }

/* Chips are the multiselect: one per type, `.on` when picked. */
.chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
label .chips { margin-top: 4px; }
.chip {
  font-family: var(--mono); font-size: 12px; font-weight: 400;
  padding: 2px 8px; background: var(--surface-2); color: var(--muted);
}
.chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.chip.on:hover:not(:disabled) { background: var(--accent); filter: brightness(1.08); }
.chip-add { width: 100px; font-size: 12px; padding: 2px 8px; }

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

.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
th {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); font-weight: 600; background: var(--surface-2);
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface-2); }
td.num, th.num { text-align: right; font-family: var(--mono); font-size: 13px; }
td.wide { white-space: normal; }

/* ---------- badges ---------- */

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  font-family: var(--mono);
  letter-spacing: .01em;
  white-space: nowrap;
}
.v-AC { background: var(--ok-bg); color: var(--ok); }
.v-WA, .v-RE, .v-IE { background: var(--bad-bg); color: var(--bad); }
.v-TLE, .v-MLE, .v-OLE { background: var(--warn-bg); color: var(--warn); }
/* Aborted is neutral, like a compile error: the submission was never given a
   chance to be right or wrong, so colouring it as a failure would misreport it. */
.v-CE, .v-AB { background: var(--neutral-bg); color: var(--neutral); }
.v-PENDING, .v-JUDGING { background: var(--info-bg); color: var(--info); }
.v-JUDGING { animation: pulse 1.2s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .55; } }

.state-running { background: var(--ok-bg); color: var(--ok); }
.state-before { background: var(--info-bg); color: var(--info); }
.state-ended { background: var(--neutral-bg); color: var(--neutral); }

.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 8px; vertical-align: baseline; }
.dot.solved { background: var(--ok); }
.dot.attempted { background: var(--warn); }
.dot.untouched { background: var(--border); }

.pill {
  font-family: var(--mono); font-size: 12px; color: var(--muted);
  background: var(--surface-2); border: 1px solid var(--border);
  padding: 1px 7px; border-radius: 5px;
}
.pill.warn { background: var(--warn-bg); color: var(--warn); border-color: transparent; }

/* Which round a problem is in, and the letter it is set as. The letter is
   what people quote at each other, so it carries the weight and the title
   stays quiet beside it. */
.pill-origin { color: var(--muted); }
.pill-origin b { color: var(--text); font-weight: 600; margin-left: 1px; }
.pill-origin:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  text-decoration: none;
}
.pill-origin:hover b { color: var(--accent); }

/* A round that has not started yet. The word "upcoming" carries it — this
   only tints what the text already says, so it still reads in monochrome. */
.pill-upcoming { background: var(--info-bg); border-color: transparent; }
.pill-upcoming b { color: var(--info); }
.pill-upcoming i {
  font-style: normal;
  color: var(--info);
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.04em;
  margin-left: 2px;
}
.pill-upcoming:hover, .pill-upcoming:hover b, .pill-upcoming:hover i {
  color: var(--info);
}
.pill-upcoming:hover { border-color: color-mix(in srgb, var(--info) 45%, transparent); }

/* ---------- stream ---------- */

.post h2 { font-size: 20px; margin: 0 0 2px; }
.post-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 14px; }
.post .statement > :last-child { margin-bottom: 0; }

/* ---------- statement ---------- */

.statement { line-height: 1.65; }
.statement h1 { font-size: 19px; margin: 22px 0 8px; }
.statement h2 { font-size: 16px; margin: 22px 0 8px; }
.statement h3 { font-size: 14.5px; margin: 18px 0 6px; }
.statement p { margin: 0 0 12px; }
.statement ul, .statement ol { margin: 0 0 12px; padding-left: 22px; }
.statement li { margin-bottom: 4px; }
.statement code {
  font-family: var(--mono); font-size: .88em;
  background: var(--surface-2); border: 1px solid var(--border);
  padding: .5px 4px; border-radius: 4px;
}
.statement pre {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px 14px; overflow-x: auto;
}
.statement pre code { background: none; border: none; padding: 0; }

pre.io {
  font-family: var(--mono); font-size: 13px; line-height: 1.5;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 12px; margin: 0;
  overflow-x: auto; max-height: 260px; overflow-y: auto;
}
pre.source {
  font-family: var(--mono); font-size: 13px; line-height: 1.5;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px; overflow-x: auto; margin: 0;
}
.sample-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 14px; }
@media (max-width: 700px) { .sample-grid { grid-template-columns: 1fr; } }
.sample-grid h4 { margin: 0 0 6px; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }

/* ---------- scoreboard ---------- */

/* Let the name column absorb the slack so the problem cells stay compact. */
.scoreboard th:nth-child(2), .scoreboard td:nth-child(2) { width: 99%; }
.scoreboard td.cell { text-align: center; font-family: var(--mono); font-size: 13px; padding: 6px 10px; min-width: 74px; }
.cell.solved { background: var(--ok-bg); color: var(--ok); font-weight: 600; }
.cell.failed { background: var(--bad-bg); color: var(--bad); }
.cell.pending { background: var(--info-bg); color: var(--info); }
/* Frozen cells must read as "deliberately hidden", not as "nothing here" —
   the stripes distinguish them from an empty cell at a glance. */
.cell.frozen {
  background: repeating-linear-gradient(
    -45deg, var(--info-bg), var(--info-bg) 6px, var(--surface-2) 6px, var(--surface-2) 12px);
  color: var(--info);
}
.freeze-banner {
  background: var(--info-bg);
  color: var(--info);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 12px;
  font-size: 14px;
  font-weight: 500;
}
.cell .sub { display: block; font-size: 11px; opacity: .8; font-weight: 400; }
.rank { font-family: var(--mono); color: var(--muted); }

.countdown { font-family: var(--mono); font-size: 14px; font-weight: 600; }

/* ---------- toasts & dialog ---------- */

.toasts { position: fixed; right: 18px; bottom: 18px; display: flex; flex-direction: column; gap: 8px; z-index: 100; }
.toast {
  background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 10px 14px; font-size: 14px; max-width: 360px;
  animation: slide-in .18s ease-out;
}
.toast.bad { border-left-color: var(--bad); }
.toast.good { border-left-color: var(--ok); }
@keyframes slide-in { from { opacity: 0; transform: translateY(6px); } }

dialog {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  padding: 24px;
  width: min(380px, 92vw);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .18);
}
dialog::backdrop { background: rgba(10, 12, 16, .45); }
dialog h2 { margin: 0 0 16px; font-size: 18px; }
dialog .row { justify-content: flex-end; margin-top: 6px; }

/* ---------- markdown editor ---------- */

/* Source and preview are one control, so they share a border and the tab bar
   sits inside it. Which pane shows is a single attribute on the wrapper. */
.md {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.md-bar {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
}
.md-tabs, .md-tools { display: flex; gap: 2px; }
.md-tab, .md-tool {
  padding: 4px 12px; font-size: 13px;
  border-color: transparent; background: transparent; color: var(--muted);
}
.md-tool { width: 30px; padding: 4px 0; font-family: var(--mono); }
.md-tab:hover:not(:disabled), .md-tool:hover:not(:disabled) { background: var(--surface); color: var(--text); }
.md-tab.on { background: var(--surface); border-color: var(--border); color: var(--text); }

.md-panes { display: grid; grid-template-columns: 1fr; }
/* Scoped to .md so it outranks the `textarea.code` height set above. */
.md .md-src, .md-preview { min-height: 480px; }
.md .md-src { border: none; border-radius: 0; padding: 14px 16px; resize: vertical; }
.md .md-src:focus { outline: none; }
.md-preview { padding: 14px 16px; overflow: auto; }
.md[data-mode="write"] .md-preview, .md[data-mode="preview"] .md-src { display: none; }
.md[data-mode="split"] .md-panes { grid-template-columns: 1fr 1fr; }
.md[data-mode="split"] .md-preview { border-left: 1px solid var(--border); }
@media (max-width: 820px) {
  /* Two half-width columns are unreadable here, so split degrades to write. */
  .md[data-mode="split"] .md-panes { grid-template-columns: 1fr; }
  .md[data-mode="split"] .md-preview { display: none; }
}

/* A section of the admin index, with its "+ New" button on the heading line. */
.section-head { margin: 28px 0 10px; }
.section-head h2 { margin: 0; }

/* ---------- visibility ---------- */

/* Two states and, in words, who can see the thing right now. Hidden colours
   the whole bar rather than one control, so it is noticed without being read. */
.vis {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 12px; margin-bottom: 18px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.vis[data-on="0"] { background: var(--warn-bg); border-color: transparent; }
.vis-note { font-size: 13px; color: var(--muted); }
.vis[data-on="0"] .vis-note { color: var(--warn); }

.seg { display: flex; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.seg-btn {
  border: none; border-radius: 0; padding: 5px 14px; font-size: 13px;
  background: var(--surface); color: var(--muted);
}
.seg-btn + .seg-btn { border-left: 1px solid var(--border); }
.seg-btn.on { color: #fff; background: var(--accent); }
.seg-btn.on:hover:not(:disabled) { background: var(--accent); filter: brightness(1.08); }
.vis[data-on="0"] .seg-btn.on { background: var(--warn); }

/* ---------- identity ---------- */

/* Admins are visually distinct wherever a username appears, so nobody has to
   cross-reference who is staff. */
.user-link { color: var(--accent); font-weight: 500; }
.user-link:hover { text-decoration: underline; }
.user-admin {
  color: var(--bad);
  font-weight: 600;
}
.user-admin::after {
  content: "admin";
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  background: var(--bad-bg);
  color: var(--bad);
  border-radius: 4px;
  padding: 1px 5px;
  margin-left: 6px;
  vertical-align: 1px;
}

.points-pill {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 5px;
  padding: 1px 7px;
  white-space: nowrap;
}

.score-big { font-family: var(--mono); font-size: 30px; font-weight: 700; letter-spacing: -.02em; }
.weight-bar {
  display: inline-block; height: 6px; border-radius: 3px;
  background: var(--accent); vertical-align: middle; min-width: 2px;
}

/* ---------- submission calendar ---------- */

.cal-wrap { overflow-x: auto; padding-bottom: 2px; }
.cal { display: flex; gap: 3px; width: max-content; }
.cal-week { display: grid; grid-template-rows: repeat(7, 11px); gap: 3px; }
.cal-day { width: 11px; height: 11px; border-radius: 2px; background: var(--surface-2); }
.cal-day.l1 { background: color-mix(in srgb, var(--accent) 30%, var(--surface-2)); }
.cal-day.l2 { background: color-mix(in srgb, var(--accent) 55%, var(--surface-2)); }
.cal-day.l3 { background: color-mix(in srgb, var(--accent) 78%, var(--surface-2)); }
.cal-day.l4 { background: var(--accent); }
.cal-tip {
  position: fixed; transform: translate(-50%, -100%);
  background: var(--text); color: var(--surface);
  font-size: 12px; line-height: 1.4; white-space: nowrap;
  padding: 3px 8px; border-radius: 5px;
  pointer-events: none; z-index: 100;
}
.cal-months {
  display: flex; gap: 3px; margin-bottom: 4px; width: max-content;
  font-size: 11px; color: var(--muted);
}
.cal-months span { width: 11px; white-space: nowrap; }

/* A subtask boundary inside a submission's test list. */
tr.subtask-head td {
  background: var(--surface-2);
  font-weight: 600;
  font-size: 13px;
  border-top: 1px solid var(--border);
  padding-top: 10px;
  padding-bottom: 10px;
}

/* ---------- math ---------- */

/* MathML inherits the surrounding font size, which makes inline math sit a
   little small against the statement's body text. */
math { font-size: 1.06em; }

/* `display: block` alone would replace the element's *inner* display type —
   `math` — with `flow`, and every fraction, root and sum would collapse into a
   vertical stack of ordinary boxes. The two-value form keeps MathML layout
   while making the box block-level; `fit-content` plus auto margins is then
   what centres it, since text-align does not apply to a math box. */
math.math-display {
  display: block math;
  width: fit-content;
  max-width: 100%;
  margin: 14px auto;
  /* A derivation wider than the column scrolls itself rather than the page. */
  overflow-x: auto;
  overflow-y: hidden;
}
/* Fractions and roots inside a table cell must not inherit its nowrap. */
.statement math { white-space: normal; }

/* Every cell here holds a fixed-width input, so a right-aligned `.num` header
   would sit at the far edge of a column its content never reaches — the label
   ends up nowhere near the field it names. Left-align throughout. */
.limits-table th, .limits-table td { text-align: left; }
/* Then stop the columns sprawling: an auto-layout table shares its spare width
   between every column, which pushes each field away from its own heading. A
   token width collapses these to their content and hands the slack to the
   first column. */
.limits-table th:not(:first-child), .limits-table td:not(:first-child) { width: 1px; }

/* ---------- version state ---------- */

/* Blocking, by contrast: a mismatched pair cannot be reasoned about, so the
   site must not be usable at all until the two halves agree. */
.updating {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; text-align: center;
  background: var(--bg); color: var(--text);
}
.updating h1 { margin: 0 0 10px; }
.updating p { margin: 0 0 6px; color: var(--muted); }

/* Reference material, not part of the task on the page — collapsed by default
   and quieter than the problem list it sits under. */
.dmoj-card { margin-top: 22px; }
.dmoj-card > summary { color: var(--muted); font-size: 14px; }
.dmoj-table th, .dmoj-table td { text-align: left; vertical-align: baseline; }
/* Only the problem list wraps and soaks up the spare width; the three columns
   before it are short and fixed, so they should not be squeezed to fit. */
.dmoj-table th:last-child, .dmoj-table td:last-child { width: 100%; white-space: normal; }

/* Your own row in a ranking, so you can find yourself without reading names. */
tr.you { outline: 2px solid var(--accent); outline-offset: -2px; }

/* The bar is a single row of fixed-width items, so below about 500px it simply
   runs off the side and takes the whole page's horizontal scroll with it —
   every page scrolled sideways on a phone, not just wide ones. Let the nav
   scroll within itself instead, and shrink what does not carry information. */
@media (max-width: 560px) {
  .topbar { gap: 8px; padding: 0 10px; }
  .topbar nav {
    overflow-x: auto;
    scrollbar-width: none;          /* the row is short; a bar would dominate */
    flex: 1 1 auto;
    min-width: 0;
  }
  .topbar nav::-webkit-scrollbar { display: none; }
  .topbar nav a { white-space: nowrap; }
  .brand { font-size: 17px; }
  /* The account controls keep their width; only the nav gives ground, since
     it is the part that can scroll. Without this the buttons are squeezed
     until their labels wrap and the bar becomes two rows tall. */
  #account { gap: 6px; font-size: 13px; flex: 0 0 auto; }
  #account button, #account .btn { white-space: nowrap; padding: 5px 10px; }
  #account .badge { display: none; }  /* the name already says who you are */
}

/* ---------- competitive rank ---------- */

.rank-badge {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-family: var(--mono); font-size: 12px; font-weight: 600;
  letter-spacing: 0.2px; white-space: nowrap;
  border: 1px solid transparent;
}
/* Each tier is a tinted chip rather than a flat colour fill, so a rank reads
   at a glance without competing with the verdict badges beside it. The hues
   walk cool-to-warm up the ladder, so the tier is legible from colour alone. */
.rank-novice      { color: #8a8a8a; background: color-mix(in srgb, #8a8a8a 16%, transparent); border-color: color-mix(in srgb, #8a8a8a 34%, transparent); }
.rank-apprentice  { color: #7d8fa8; background: color-mix(in srgb, #7d8fa8 16%, transparent); border-color: color-mix(in srgb, #7d8fa8 34%, transparent); }
.rank-adept       { color: #35a3bd; background: color-mix(in srgb, #35a3bd 16%, transparent); border-color: color-mix(in srgb, #35a3bd 34%, transparent); }
.rank-specialist  { color: #1f9c62; background: color-mix(in srgb, #1f9c62 16%, transparent); border-color: color-mix(in srgb, #1f9c62 34%, transparent); }
.rank-expert      { color: #6f9c1f; background: color-mix(in srgb, #6f9c1f 16%, transparent); border-color: color-mix(in srgb, #6f9c1f 34%, transparent); }
.rank-master      { color: #d2a327; background: color-mix(in srgb, #d2a327 16%, transparent); border-color: color-mix(in srgb, #d2a327 34%, transparent); }
.rank-grandmaster { color: #d2762a; background: color-mix(in srgb, #d2762a 16%, transparent); border-color: color-mix(in srgb, #d2762a 34%, transparent); }
.rank-champion    { color: #d13c58; background: color-mix(in srgb, #d13c58 16%, transparent); border-color: color-mix(in srgb, #d13c58 34%, transparent); }
/* Legend is the only rank without divisions, and the only one that glows. */
.rank-legend {
  color: #1b1200;
  background: linear-gradient(100deg, #ffe27a, #fff8dc 45%, #ffd24a);
  border-color: #ffcf3f;
  box-shadow: 0 0 10px color-mix(in srgb, #ffd24a 55%, transparent);
}
.rank-unranked { color: var(--muted); background: var(--surface-2); border-color: var(--border); }

.rank-rating { font-family: var(--mono); font-size: 12px; color: var(--muted); margin-left: 6px; }

/* Rating movement. Neutral when a contest left you where you were. */
.delta { font-family: var(--mono); font-size: 13px; color: var(--muted); }
.delta.up   { color: var(--ok); }
.delta.down { color: var(--bad); }

.pill-rated { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }

/* The ladder legend: 25 rungs, so it has to stay compact. */
.ladder { display: flex; flex-wrap: wrap; gap: 6px; }
.ladder .rung { display: flex; align-items: center; gap: 6px; }
.ladder .rung .muted { font-size: 11px; }

/* The badge doubles as the way in to the explanation, so it must not look
   like ordinary link text. */
.rank-link { text-decoration: none; }
.rank-link:hover .rank-badge { filter: brightness(1.12); }

/* Member view: an admin browsing with their privileges set aside. Deliberately
   loud — mistaking it for the real site would cost more than it saves. */
.view-as-banner {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 18px; padding: 9px 14px; border-radius: 8px;
  font-size: 13px; line-height: 1.45;
  color: var(--warn, #8a5a00);
  background: color-mix(in srgb, #d2a327 14%, transparent);
  border: 1px solid color-mix(in srgb, #d2a327 45%, transparent);
}
.view-as-banner button { margin-left: auto; }

/* ---------- rating history graph ---------- */

.rating-graph { width: 100%; height: auto; display: block; }
.rating-graph .trend {
  fill: none; stroke: var(--text); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
}
.rating-graph .dot { fill: var(--surface); stroke: var(--text); stroke-width: 2; }
.rating-graph .dot:hover { fill: var(--text); }
.rating-graph .axis { fill: var(--muted); font-size: 11px; font-family: var(--mono); }
.rating-graph .band-name { fill: var(--muted); font-size: 10px; font-family: var(--mono); }

/* The bands are context, not content: strong enough to read the tier from,
   faint enough that the line stays the thing you look at. */
.rating-graph .band { opacity: 0.16; }
.rating-graph .band.tier-novice      { fill: #8a8a8a; }
.rating-graph .band.tier-apprentice  { fill: #7d8fa8; }
.rating-graph .band.tier-adept       { fill: #35a3bd; }
.rating-graph .band.tier-specialist  { fill: #1f9c62; }
.rating-graph .band.tier-expert      { fill: #6f9c1f; }
.rating-graph .band.tier-master      { fill: #d2a327; }
.rating-graph .band.tier-grandmaster { fill: #d2762a; }
.rating-graph .band.tier-champion    { fill: #d13c58; }
.rating-graph .band.tier-legend      { fill: #ffd24a; opacity: 0.3; }
