/*
  wikipathways-submit — design system
  --------------------------------------------------
  Visual idea: the curation desk. WPIDs are treated like museum/herbarium
  accession numbers (a serif "ledger" numeral in a tagged chip with a
  grommet), pathway diffs are shown as two labelled frames joined by a
  single edge — the same node + edge grammar GPML itself uses. Palette is
  a desaturated sage/forest range (not the generic cream+terracotta or
  near-black+neon defaults), sans UI chrome, serif for accession numbers
  and headline emphasis only, monospace for identifiers/paths.
*/

/* ---------- tokens ---------- */
:root {
  color-scheme: light dark;

  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-2: #f7f8fa;
  --ink: #1c2634;
  --ink-muted: #5a6472;
  /* Darkened and retinted onto the same blue-grey ink ramp as --ink/--ink-muted. The old
     #828282 measured 3.7-4.0:1 at the 13-14px sizes it drives — the preview's Before/After
     captions, "not annotated" in the data-node table, the checklist notes — which is under AA,
     and it was the one pure neutral in an otherwise blue-tinted set. */
  --ink-faint: #66717f;
  --line: #e2e5ea;
  --line-strong: #cdd2db;

  /* WikiPathways brand: indigo primary (#3955E7) + green accent (#008558). */
  --moss: #3955e7;
  --moss-strong: #2740b8;
  --moss-tint: #eaedfc;
  --moss-contrast: #ffffff;

  --wp-green: #008558;
  --wp-green-strong: #036b48;
  --wp-green-tint: #e2f1ea;

  --amber: #8a5a10;
  --amber-tint: #f4e8d2;

  --brick: #93362b;
  --brick-tint: #f5e0dc;
  /* Label colours for text sitting *on* --brick / --slate. Hardcoded #fff worked in light mode
     and vanished in dark, where those tokens lighten to #e2897d and #a7bcc4. */
  --brick-contrast: #ffffff;

  --slate: #46565f;
  --slate-tint: #e6ebec;
  --slate-contrast: #ffffff;

  --focus: #3955e7;

  --container: 1080px;
  --radius-s: 6px;
  --radius-m: 10px;
  --radius-l: 18px;
  --shadow-card: 0 1px 2px rgba(28, 38, 52, 0.06), 0 10px 28px -18px rgba(28, 38, 52, 0.35);
  --shadow-pop: 0 4px 10px rgba(28, 38, 52, 0.1), 0 18px 40px -20px rgba(28, 38, 52, 0.4);

  --font-display: -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-body: -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-accession: Georgia, "Iowan Old Style", "Times New Roman", serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #10151c;
    --surface: #182029;
    --surface-2: #121821;
    --ink: #e8ecf2;
    --ink-muted: #a6b0be;
    --ink-faint: #7c8794;
    --line: #263141;
    --line-strong: #37475c;

    --moss: #8ea2ff;
    --moss-strong: #adbcff;
    --moss-tint: rgba(89, 110, 231, 0.20);
    --moss-contrast: #0b1020;

    --wp-green: #4cc795;
    --wp-green-strong: #6fd6ab;
    --wp-green-tint: rgba(0, 133, 88, 0.20);

    --amber: #d8ab5c;
    --amber-tint: rgba(216, 171, 92, 0.14);

    --brick: #e2897d;
    --brick-tint: rgba(226, 137, 125, 0.14);
    --brick-contrast: #2b1512;

    --slate: #a7bcc4;
    --slate-tint: rgba(167, 188, 196, 0.12);
    --slate-contrast: #101a1f;

    --focus: #8ea2ff;

    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.35), 0 10px 28px -18px rgba(0, 0, 0, 0.6);
    --shadow-pop: 0 4px 10px rgba(0, 0, 0, 0.4), 0 18px 40px -20px rgba(0, 0, 0, 0.7);
  }
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* Author-origin `display` on a component beats the UA's [hidden] rule; restore it. */
[hidden] { display: none !important; }
html {
  color-scheme: light dark;
  /* The header is sticky at ~57px (taller once it wraps), so a skip-link jump or a restored
     scroll position lands the target underneath it. */
  scroll-padding-top: 4.5rem;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.6 var(--font-body);
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: var(--moss); text-decoration-thickness: 1.5px; text-underline-offset: 2px; }
a:hover { color: var(--moss-strong); }
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 700; line-height: 1.25; margin: 0 0 0.4em; color: var(--ink); }
p { margin: 0 0 0.9em; color: var(--ink); }
.lede { max-width: 60ch; color: var(--ink-muted); font-size: 1rem; margin-bottom: 1.6rem; }
code, .mono { font-family: var(--font-mono); }
button { font: inherit; }

:focus { outline: none; }
:focus-visible {
  outline: 2.5px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -3rem;
  background: var(--moss);
  color: var(--moss-contrast);
  padding: 0.6em 1em;
  border-radius: var(--radius-s);
  z-index: 100;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 1rem; }

/* ---------- shell / header ---------- */
.shell { min-height: 100vh; display: flex; flex-direction: column; }

.site-header {
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 20;
}
.site-header__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  max-width: var(--container);
  margin: 0 auto;
  width: 100%;
  padding: 0 1.5rem;   /* match .container so the brand lines up with page content */
}
/* Standing service notice, shown on every page when WPSUBMIT_SITE_NOTICE is set. It sits under
   the header and above the content because it qualifies the promise the submit form makes:
   "the database publishes it" is not true on every target this app can be pointed at. Not
   dismissible, since it stays true all session, and a notice you can close is one a submitter
   closes before reading. */
.site-notice {
  background: var(--amber-tint);
  color: var(--amber);
  border-bottom: 1px solid color-mix(in srgb, var(--amber) 35%, transparent);
}
/* .container carries the page's 2.2rem/4rem vertical padding, which inside a one-line banner
   reads as a huge empty amber block. Reuse it for the horizontal gutter and alignment only. */
.site-notice .container {
  padding-top: 0;
  padding-bottom: 0;
}
.site-notice p {
  margin: 0;
  padding: 0.7rem 0;
  font-size: 0.88rem;
  line-height: 1.5;
  font-weight: 500;
}

.site-header__brand {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  font-size: 1.05rem;
}
.site-header__logo {
  height: 2rem; width: auto; flex: none; display: block;
}
.site-header__portal {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink-muted);
  padding-left: 0.6rem;
  margin-left: 0.1rem;
  border-left: 1px solid var(--line-strong);
}
/* The WikiPathways logo is a dark monochrome SVG; lift it on dark backgrounds. */
@media (prefers-color-scheme: dark) {
  .site-header__logo { filter: invert(1) hue-rotate(180deg) brightness(1.1); }
}
.site-header__nav {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  margin-left: auto;
  flex-wrap: wrap;
}
.site-header__nav a {
  color: var(--ink-muted);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.92rem;
  padding: 0.3em 0.1em;
  border-bottom: 2px solid transparent;
}
.site-header__nav a:hover,
.site-header__nav a[aria-current="page"] {
  color: var(--moss-strong);
  border-bottom-color: var(--moss);
}
.site-header__who {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--ink-muted);
  font-size: 0.88rem;
}
.site-header__who .badge { font-size: 0.72rem; }

main { flex: 1; }
.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 2.2rem 1.5rem 4rem;
}

.site-footer {
  border-top: 1px solid var(--line);
  padding: 1.2rem 1.5rem;
  color: var(--ink-faint);
  font-size: 0.82rem;
  text-align: center;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.55em 1.1em;
  border-radius: var(--radius-s);
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--ink);
  font-weight: 600;
  font-size: 0.92rem;
  cursor: pointer;
  transition: transform 0.08s ease, background 0.12s ease, border-color 0.12s ease;
}
.btn:hover { background: var(--surface); border-color: var(--moss); }
.btn:active { transform: translateY(1px); }
.btn:disabled,
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.5;
  transform: none !important;
}

.btn--primary {
  background: var(--moss);
  border-color: var(--moss);
  color: var(--moss-contrast);
}
.btn--primary:hover { background: var(--moss-strong); border-color: var(--moss-strong); }

.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--ink-muted);
}
.btn--ghost:hover { color: var(--moss-strong); background: var(--moss-tint); }

.btn--approve {
  background: var(--moss);
  border-color: var(--moss);
  color: var(--moss-contrast);
  width: 100%;
  justify-content: center;
  padding: 0.7em 1.1em;
}
.btn--approve:hover { background: var(--moss-strong); }
.btn--approve[aria-disabled="true"] {
  /* The generic .btn:disabled opacity stacks with the muted palette below and takes the
     dashboard's primary action to roughly 1.8:1 — a blank grey slab. One or the other. */
  opacity: 1;
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--ink-faint);
}

.btn--sm { padding: 0.35em 0.75em; font-size: 0.82rem; }
.btn svg { width: 1.05em; height: 1.05em; flex: none; }

/* GitHub CTA — distinct from generic primary blue button */
.btn--github {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
  font-size: 1rem;
  padding: 0.75em 1.4em;
}
.btn--github:hover { background: var(--moss-strong); border-color: var(--moss-strong); }
@media (prefers-color-scheme: dark) {
  .btn--github { background: var(--surface-2); border-color: var(--line-strong); color: var(--ink); }
  .btn--github:hover { background: var(--moss); color: var(--moss-contrast); border-color: var(--moss); }
}

/* ---------- badges / chips ---------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.18em 0.65em;
  border-radius: 999px;
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge--new { background: var(--moss-tint); color: var(--moss-strong); }
.badge--update { background: var(--slate-tint); color: var(--slate); }
.badge--open { background: var(--amber-tint); color: var(--amber); }
.badge--merged { background: var(--moss-tint); color: var(--moss-strong); }
.badge--closed { background: var(--brick-tint); color: var(--brick); }
.badge--curator { background: var(--wp-green-tint); color: var(--wp-green-strong); }
/* Provenance rather than state: this pull request was opened on GitHub, not through the portal.
   Outlined rather than filled so it reads as a note beside the state badges, not as another
   state. */
.badge--adopted {
  background: transparent;
  color: var(--slate);
  border-color: var(--rule);
}
/* The rest of ReviewStatus. Without these the states a pipeline-mode review actually spends its
   life in fell through to the bare .badge rule: transparent, borderless, unreadable. */
.badge--changes_requested { background: var(--amber-tint); color: var(--amber); }
.badge--approved { background: var(--moss-tint); color: var(--moss-strong); }
.badge--published { background: var(--wp-green-tint); color: var(--wp-green-strong); }
.badge--publish_failed { background: var(--brick-tint); color: var(--brick); }
.badge--rejected { background: var(--brick-tint); color: var(--brick); }

/* ---------- accession tag (signature element) ---------- */
.tag-wpid {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.3rem 0.85rem 0.3rem 0.6rem;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-m);
}
.tag-wpid__dot {
  width: 0.6rem; height: 0.6rem;
  border-radius: 50%;
  border: 1.5px solid var(--moss);
  background: var(--surface);
  flex: none;
}
.tag-wpid__id {
  font-family: var(--font-accession);
  font-size: 1.15rem;
  font-variant-numeric: oldstyle-nums;
  letter-spacing: 0.01em;
  color: var(--ink);
}
.tag-wpid--lg .tag-wpid__id { font-size: 1.5rem; }

/* ---------- hero (index, anonymous) ---------- */
.hero {
  padding: 3.5rem 0 2.5rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 3rem;
}
/* The mark sits beside the headline at full strength, never cropped: no absolute positioning,
   no overflow clipping, and it drops out entirely when the column no longer fits. */
.hero__graphic {
  width: 17rem;
  height: 17rem;
  /* --ink, not black, so it stays the headline's colour and flips with the dark theme. */
  color: var(--ink);
  pointer-events: none;
}
@media (max-width: 860px) {
  .hero { grid-template-columns: minmax(0, 1fr); }
  .hero__graphic { display: none; }
}
.hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--moss-strong);
  margin-bottom: 1rem;
}
.hero__eyebrow::before {
  content: "";
  width: 1.4rem; height: 1px;
  background: var(--moss);
}
.hero h1 {
  font-size: clamp(1.9rem, 4vw, 2.7rem);
  max-width: 18ch;
  letter-spacing: -0.015em;
}
.hero__lede {
  max-width: 52ch;
  font-size: 1.05rem;
  color: var(--ink-muted);
}
.hero__cta { margin-top: 1.6rem; display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
/* Wide enough to read as a sentence beside the button, narrow enough not to stretch the row. */
.hero__cta-note { color: var(--ink-faint); font-size: 0.85rem; max-width: 42ch; line-height: 1.45; }

@media (prefers-reduced-motion: no-preference) {
  .reveal {
    animation: reveal-up 0.6s cubic-bezier(.2,.7,.3,1) both;
  }
  .reveal:nth-child(1) { animation-delay: 0s; }
  .reveal:nth-child(2) { animation-delay: 0.08s; }
  .reveal:nth-child(3) { animation-delay: 0.16s; }
  .reveal:nth-child(4) { animation-delay: 0.24s; }
  @keyframes reveal-up {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: none; }
  }
}

/* how it works */
.steps {
  list-style: none;
  margin: 3rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  counter-reset: step;
}
.steps li {
  counter-increment: step;
  border-top: 2px solid var(--line-strong);
  padding-top: 0.9rem;
}
.steps li::before {
  content: counter(step);
  font-family: var(--font-accession);
  font-size: 1.6rem;
  color: var(--moss);
  display: block;
  margin-bottom: 0.3rem;
}
.steps h3 { font-size: 1rem; margin-bottom: 0.25rem; }
.steps p { color: var(--ink-muted); font-size: 0.9rem; margin: 0; }
@media (max-width: 720px) { .steps { grid-template-columns: 1fr; } }

/* ---------- submit flow (index, logged in) ---------- */
.stepper-flow { display: flex; flex-direction: column; gap: 1.6rem; max-width: 640px; }

/* new / update tabs */
.tabs { display: flex; gap: 0.4rem; max-width: 640px; margin: 0 0 1rem; border-bottom: 1px solid var(--line); }
.tab {
  appearance: none;
  border: 1px solid transparent;
  border-bottom: none;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--ink-faint);
  padding: 0.6rem 1rem;
  border-radius: var(--radius-s) var(--radius-s) 0 0;
  cursor: pointer;
  margin-bottom: -1px;
}
.tab:hover { color: var(--ink); }
.tab--active {
  color: var(--moss-strong);
  border-color: var(--line);
  border-bottom-color: var(--surface);
  background: var(--surface);
}
.tab-panel--hidden { display: none; }
.wpid-status { margin: 0.2rem 0 0; font-size: 0.85rem; }
.wpid-status--checking { color: var(--ink-muted); }
.wpid-status--error { color: var(--brick); }
.wpid-status--ok { color: var(--wp-green-strong); }
.wpid-status--pending { color: var(--amber); }
.wpid-status--err { color: var(--brick); }

.step-card {
  max-width: 640px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-l);
  padding: 1.4rem 1.5rem;
  box-shadow: var(--shadow-card);
}
.step-card[data-disabled="true"] { opacity: 0.55; }
.step-card__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--moss-strong);
  display: block;
  margin-bottom: 0.4rem;
}
.step-card h2 { font-size: 1.05rem; }
.step-card p.hint { color: var(--ink-muted); font-size: 0.9rem; }

.file-field {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin: 1rem 0;
}
.file-field input[type="file"] {
  font: inherit;
  color: var(--ink-muted);
  max-width: 100%;
}
.file-field input[type="file"]::file-selector-button {
  font: inherit;
  font-weight: 600;
  padding: 0.5em 1em;
  margin-right: 0.8em;
  border-radius: var(--radius-s);
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--ink);
  cursor: pointer;
}
.file-field input[type="file"]::file-selector-button:hover { border-color: var(--moss); }

/* Update an existing pathway */
.update-card { margin-top: 1.25rem; }
.update-fields {
  display: flex;
  gap: 1rem;
  align-items: flex-end;
  flex-wrap: wrap;
  margin: 1rem 0;
}
.update-fields .file-field { margin: 0; flex: 1 1 14rem; }
.wpid-field { display: flex; flex-direction: column; gap: 0.35rem; flex: none; }
.wpid-field__label {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-family: var(--font-mono);
}
.wpid-field input {
  width: 8rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}
.wpid-field input:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: var(--focus);
}

.change-set { border: 1px solid var(--line); border-radius: var(--radius-s); padding: 0.7rem 0.9rem 0.85rem; margin: 0.9rem 0 0; }
.change-set legend { font-size: 0.85rem; padding: 0 0.35rem; color: var(--ink); }
.change-set__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: 0.35rem 0.9rem; margin-top: 0.4rem; }
.change-set__grid label { display: flex; align-items: center; gap: 0.4rem; font-size: 0.88rem; cursor: pointer; }
.change-set__grid input { accent-color: var(--moss); }

.note-field { display: flex; flex-direction: column; gap: 0.35rem; margin: 0.9rem 0 0; }
.note-field__label {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-family: var(--font-mono);
}
.note-field textarea {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  resize: vertical;
}
.note-field textarea:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: var(--focus);
}

.preview-card {
  margin-top: 1rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-m);
  padding: 0.9rem 1.1rem;
  background: var(--surface-2);
}
.preview-card dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.3rem 1rem;
  margin: 0;
}
.preview-card dt { color: var(--ink-faint); font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.03em; }
.preview-card dd { margin: 0; font-family: var(--font-mono); font-size: 0.92rem; }

.result-card {
  margin-top: 1rem;
  border-radius: var(--radius-m);
  padding: 1rem 1.2rem;
  background: var(--moss-tint);
  border: 1px solid var(--moss);
  color: var(--ink);
}
.result-card a { font-weight: 700; }

/* ---------- review cards / dashboard ---------- */
.queue-filter {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--line);
  padding-bottom: 0;
  /* Eight tabs do not fit a phone. They scroll sideways as their own strip rather than giving
     the whole document a horizontal scrollbar, and the underline stays continuous because the
     rule is on the scrolling element. */
  overflow-x: auto;
  scrollbar-width: thin;
}
.queue-filter a {
  white-space: nowrap;
  flex: none;
  text-decoration: none;
  color: var(--ink-muted);
  font-weight: 600;
  font-size: 0.9rem;
  padding: 0.55rem 0.9rem;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.queue-filter a:hover { color: var(--moss-strong); }
.queue-filter a[aria-current="page"] {
  color: var(--moss-strong);
  border-bottom-color: var(--moss);
}

.review-list { display: flex; flex-direction: column; gap: 1.25rem; }

/* Queue pager (issue #17). Both steps are always present, disabled rather than absent, so the
   Next control does not move under the pointer when the last page is reached. */
.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  flex-wrap: wrap;
}
.pager__step {
  display: inline-flex;
  align-items: center;
  padding: 0.5em 1em;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  background: var(--surface-2);
  color: var(--ink);
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
  white-space: nowrap;
}
a.pager__step:hover { background: var(--surface); border-color: var(--moss); }
.pager__step[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.pager__count {
  margin: 0;
  color: var(--ink-muted);
  font-size: 0.88rem;
  text-align: center;
}
/* The page number sits under the span on a phone and beside it with room to spare, so the
   ordinal never crowds the count it qualifies. */
.pager__page { display: block; }
@media (min-width: 30rem) {
  .pager__page::before { content: "\00b7"; padding: 0 0.4em; }
  .pager__page { display: inline; }
}

.review-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-l);
  padding: 1.4rem 1.5rem 1.6rem;
  box-shadow: var(--shadow-card);
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.review-card:hover { border-color: var(--line-strong); box-shadow: var(--shadow-pop); }
.review-card--expanded { padding: 1.8rem 2rem 2.2rem; }

.review-card__head {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  flex-wrap: wrap;
}
.review-card__meta { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.review-card__pr {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--ink-muted);
  text-decoration: none;
}
.review-card__pr:hover { color: var(--moss); }
.review-card__expand {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--moss);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  padding: 0.3rem 0.5rem;
  border-radius: var(--radius-s);
  white-space: nowrap;
}
.review-card__expand:hover { color: var(--moss-strong); background: var(--moss-tint); }
.review-card__expand svg { width: 0.85rem; height: 0.85rem; flex: none; }

.review-card__submitter { overflow-wrap: anywhere;
  color: var(--ink-muted);
  font-size: 0.9rem;
  margin: 0.8rem 0 1.1rem;
}
.review-card__submitter strong { color: var(--ink); }

/* before/after preview — signature edge motif */
.preview { display: flex; align-items: stretch; gap: 0; margin-bottom: 1.1rem; }
.preview__frame {
  flex: 1;
  min-width: 0;
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface-2);
  overflow: hidden;
}
.preview__frame--solo { flex: 1 1 100%; }
.preview__frame figcaption {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--line);
}
.preview__frame > img { width: 100%; height: 19rem; object-fit: contain; background: var(--surface); padding: 0.5rem; }

/* pan / zoom preview */
.zoom { position: relative; background: var(--surface); }
.zoom__viewport {
  height: 19rem;
  overflow: hidden;
  /* Vertical swipes scroll the queue; once zoomed, the gesture pans the diagram instead. */
  touch-action: pan-y;
  display: flex;
  align-items: center;
  justify-content: center;
  /* The breathing room used to sit on the image itself. It moved here so the stage wraps the
     drawing exactly: hotspots are percentages of the drawing, and padding inside the measured
     box would offset every one of them by half a rem. */
  padding: 0.5rem;
  box-sizing: border-box;
}
.review-card--expanded .zoom__viewport { height: 30rem; }

/* ---------- queue density ----------
   The card macro is used at two densities from one definition, and the queue's job is triage: a
   curator scanning twenty submissions needs the state, the shape of the diagram and the controls
   in one screen. At full size the diagram alone pushed the checklist and every decision button —
   Approve, Reject, Request changes, Assign — below the fold on every card, so the queue was a
   list you could read but not act on. The detail page keeps the full-size treatment. */
.review-card:not(.review-card--expanded) .zoom__viewport { height: 13rem; }
.review-card:not(.review-card--expanded) .preview__frame > img { height: 13rem; }
/* Everything this panel says is either repeated by the automated-checks block above (a failed
   run) or is detail for a curator who has already committed to the review. */
.review-card:not(.review-card--expanded) .pipeline-panel { display: none; }
.review-card:not(.review-card--expanded) .checklist__item { padding: 0.35rem 0; }
.review-card:not(.review-card--expanded) .checklist { margin-bottom: 0.8rem; }
.zoom--zoomed .zoom__viewport { cursor: grab; touch-action: none; }
.zoom--zoomed .zoom__viewport:active { cursor: grabbing; }
/* Zoom and pan are applied to the stage, not the image, so the hotspot overlay moves with the
   drawing instead of being left behind. */
.zoom__stage {
  position: relative;
  display: block;
  line-height: 0;
  max-width: 100%;
  max-height: 100%;
  will-change: transform;
}
.zoom .zoom__img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  user-select: none;
  -webkit-user-drag: none;
}
/* Zoomed, JS gives the stage an explicit pixel size; the image fills it. */
.zoom--zoomed .zoom__stage > .zoom__img { width: 100%; height: 100%; }

/* ---------- clickable data nodes (issue #14) ---------- */
/* Box set by JS from the image's measured position, not inset:0 — the image is letterboxed
   inside the stage, so filling the stage would offset every hotspot. */
.zoom__hotspots { position: absolute; }
.hotspot {
  position: absolute;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  cursor: pointer;
  /* Invisible until wanted: the drawing is the review, and forty outlined boxes over it is
     noise. Hover, focus and the active selection are the only times it shows itself. */
  transition: background-color 120ms ease, border-color 120ms ease;
}
.hotspot:hover,
.hotspot:focus-visible,
.hotspot--active {
  background: color-mix(in srgb, var(--moss) 16%, transparent);
  border-color: var(--moss);
  outline: none;
}
.zoom--interactive .zoom__viewport { cursor: default; }

/* ---------- before/after diff (issue #24) ---------- */
/* The colours are the summary. Kept as variables so the legend swatch, the hotspot and the
   panel tag cannot drift into three different greens. */
:root {
  --diff-added: #1a9850;
  --diff-removed: #c0392b;
  --diff-reannotated: #b8860b;
  --diff-relabelled: #7b4fa8;
  --diff-moved: #6b7785;
}
/* Persistent, unlike the plain hotspot: a changed node has to be findable without hovering
   every box on the diagram, which is the entire point. Unchanged nodes stay invisible. */
.zoom--diffed .hotspot--added { background: color-mix(in srgb, var(--diff-added) 20%, transparent); border-color: var(--diff-added); }
.zoom--diffed .hotspot--removed { background: color-mix(in srgb, var(--diff-removed) 20%, transparent); border-color: var(--diff-removed); }
.zoom--diffed .hotspot--reannotated { background: color-mix(in srgb, var(--diff-reannotated) 24%, transparent); border-color: var(--diff-reannotated); }
.zoom--diffed .hotspot--relabelled { background: color-mix(in srgb, var(--diff-relabelled) 20%, transparent); border-color: var(--diff-relabelled); }
.zoom--diffed .hotspot--moved { background: color-mix(in srgb, var(--diff-moved) 14%, transparent); border-color: var(--diff-moved); border-style: dashed; }
/* Colour alone is not a distinction for everyone reading this, and five hues over a diagram
   that is itself coloured is a lot to ask of any eye. The border weight and dashes carry the
   same information, and the hotspot's own aria-label says the word. */
.zoom--diffed .hotspot--added,
.zoom--diffed .hotspot--removed,
.zoom--diffed .hotspot--reannotated,
.zoom--diffed .hotspot--relabelled { border-width: 2px; }
.zoom--diffed .hotspot--reannotated { border-style: double; border-width: 3px; }
.zoom--diffed .hotspot--removed { border-style: dotted; border-width: 2px; }
/* Drops the colour, keeps the button: the node is still clickable and still readable. */
.review-card--hide-moved .hotspot--moved { background: transparent; border-color: transparent; }

.diff-summary {
  margin: 0 0 0.5rem;
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--moss);
  border-radius: var(--radius-s);
  background: var(--surface-2);
}
.diff-summary--quiet { border-left-color: var(--line-strong); }
.diff-summary__line { margin: 0; font-size: 0.88rem; }
.diff-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.9rem;
  margin: 0.4rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.8rem;
  color: var(--ink-muted);
}
.diff-legend__item { display: flex; align-items: center; gap: 0.3rem; }
.diff-legend__swatch {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 2px;
  border: 2px solid currentColor;
}
.diff-legend__item--added .diff-legend__swatch { color: var(--diff-added); background: color-mix(in srgb, var(--diff-added) 20%, transparent); }
.diff-legend__item--removed .diff-legend__swatch { color: var(--diff-removed); border-style: dotted; background: color-mix(in srgb, var(--diff-removed) 20%, transparent); }
.diff-legend__item--reannotated .diff-legend__swatch { color: var(--diff-reannotated); border-style: double; border-width: 3px; background: color-mix(in srgb, var(--diff-reannotated) 24%, transparent); }
.diff-legend__item--relabelled .diff-legend__swatch { color: var(--diff-relabelled); background: color-mix(in srgb, var(--diff-relabelled) 20%, transparent); }
.diff-legend__item--moved .diff-legend__swatch { color: var(--diff-moved); border-style: dashed; background: color-mix(in srgb, var(--diff-moved) 14%, transparent); }
.diff-summary__toggle {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.4rem;
  font-size: 0.8rem;
  color: var(--ink-muted);
}
.node-panel__change {
  display: inline-block;
  vertical-align: middle;
  padding: 0.05rem 0.35rem;
  border-radius: 999px;
  border: 1px solid currentColor;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: lowercase;
}
.node-panel__change--added { color: var(--diff-added); }
.node-panel__change--removed { color: var(--diff-removed); }
.node-panel__change--reannotated { color: var(--diff-reannotated); }
.node-panel__change--relabelled { color: var(--diff-relabelled); }
.node-panel__change--moved { color: var(--diff-moved); }
.node-panel__props s { color: var(--ink-muted); }

.node-panel {
  position: absolute;
  left: 0.4rem;
  right: 0.4rem;
  bottom: 0.4rem;
  max-height: 62%;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.7rem 0.9rem;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
  z-index: 2;
}
.node-panel__close {
  position: absolute;
  top: 0.3rem;
  right: 0.45rem;
  border: 0;
  background: transparent;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  color: var(--ink-muted);
}
.node-panel__close:hover { color: var(--ink); }
.node-panel__title {
  margin: 0 1.2rem 0.4rem 0;
  font-weight: 700;
  font-size: 0.95rem;
}
.node-panel__props {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.7rem;
  margin: 0;
  font-size: 0.85rem;
}
.node-panel__props dt { color: var(--ink-muted); }
.node-panel__props dd { margin: 0; overflow-wrap: anywhere; }
.zoom__controls {
  position: absolute;
  right: 0.4rem;
  bottom: 0.4rem;
  display: flex;
  gap: 0.25rem;
  opacity: 0.55;
  transition: opacity 0.15s;
}
.zoom:hover .zoom__controls,
.zoom:focus-within .zoom__controls,
.zoom--zoomed .zoom__controls { opacity: 1; }
.zoom__btn {
  font: inherit;
  font-size: 0.75rem;
  line-height: 1;
  min-width: 1.6rem;
  padding: 0.3rem 0.4rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
}
.zoom__btn:hover { border-color: var(--moss); color: var(--moss); }

/* curation metadata panel */
.meta-panel { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.4rem 0 1rem; }
/* The submitter's own words, lifted out of the collapsible metadata block. It is the only part
   of that panel written by a person, and it is what a curator reads first. */
.meta-panel--lead { margin-bottom: 0.6rem; }
.meta-panel__block { border: 1px solid var(--line); border-radius: var(--radius-s); padding: 0.6rem 0.75rem; background: var(--surface-2); }
.meta-panel__block--note { background: var(--moss-tint); border-color: transparent; }
.meta-panel__block h3 { margin: 0 0 0.3rem; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-faint); }
.meta-panel__block p { margin: 0; font-size: 0.9rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.meta-panel__block > summary { cursor: pointer; font-size: 0.8rem; font-weight: 600; color: var(--ink); }
.meta-panel__block[open] > summary { margin-bottom: 0.5rem; }
.meta-panel__empty { color: var(--ink-faint); font-size: 0.85rem; margin: 0; }
.datanodes__scroll { overflow-x: auto; }
.datanodes { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.datanodes th, .datanodes td { text-align: left; padding: 0.3rem 0.5rem; border-bottom: 1px solid var(--line); white-space: nowrap; }
.datanodes th { color: var(--ink-faint); font-weight: 600; }
.datanodes code { font-size: 0.9em; }
.datanodes__missing { color: var(--ink-faint); font-style: italic; }
.datanodes__row--unmapped td { background: var(--amber-tint); }
.meta-list { margin: 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.85rem; }
.meta-list__src { color: var(--ink-faint); font-size: 0.8em; }
.checklist__auto {
  margin-left: 0.4rem;
  padding: 0.05rem 0.35rem;
  border-radius: 999px;
  font-size: 0.62rem;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--moss-strong);
  background: var(--moss-tint);
  vertical-align: middle;
}
.preview__empty, .preview__failed {
  height: 19rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  color: var(--ink-faint);
  font-size: 0.82rem;
  padding: 0.75rem;
  text-align: center;
}
.preview__failed { color: var(--brick); }
.preview__dots { display: flex; gap: 0.3rem; }
.preview__dots span {
  width: 0.4rem; height: 0.4rem; border-radius: 50%;
  background: var(--ink-faint);
}
@media (prefers-reduced-motion: no-preference) {
  .preview__dots span { animation: pulse-dot 1.1s ease-in-out infinite; }
  .preview__dots span:nth-child(2) { animation-delay: 0.15s; }
  .preview__dots span:nth-child(3) { animation-delay: 0.3s; }
  @keyframes pulse-dot { 0%, 80%, 100% { opacity: 0.25; } 40% { opacity: 1; } }
}
.preview__edge {
  flex: none;
  width: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--moss);
}
.preview__edge svg { width: 1.9rem; height: 1.9rem; }
@media (prefers-reduced-motion: no-preference) {
  .preview__edge .edge-flow { stroke-dasharray: 4 4; animation: edge-flow 1.4s linear infinite; }
  @keyframes edge-flow { to { stroke-dashoffset: -16; } }
}
@media (max-width: 640px) {
  .preview { flex-direction: column; }
  .preview__edge { width: auto; height: 1.75rem; }
  .preview__edge svg { transform: rotate(90deg); }
}

.review-card__links { display: flex; gap: 1rem; font-size: 0.85rem; margin: -0.4rem 0 1.1rem; }

/* The target repository's own full pathway page, sitting directly under the diagram. Given more
   weight than the plain link rows because it answers a different question from the render above
   it: not "what changed" but "what will this actually look like". */
.preview__site-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 0.7rem;
  margin: 0.55rem 0 1.1rem;
  padding: 0.6rem 0.8rem;
  border-radius: var(--radius-s);
  background: var(--surface-2);
}
.preview__site-link a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.9rem;
  font-weight: 600;
}
/* Sized in em so it tracks the link text rather than the root, and flex-shrink:0 so a long
   label on a narrow screen cannot squash the glyph into a sliver. */
.preview__site-link a svg { width: 0.85em; height: 0.85em; flex-shrink: 0; }
.preview__site-hint { font-size: 0.83rem; color: var(--ink-muted); }

/* checklist */
.checklist__title {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  margin: 0 0 0.6rem;
}
.checklist ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.checklist__item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
  padding: 0.55rem 0.7rem;
  border-radius: var(--radius-s);
  background: var(--surface-2);
}
.checklist__label { font-size: 0.92rem; }
.checklist__note { color: var(--ink-faint); font-size: 0.82rem; font-style: italic; }
.req { color: var(--brick); margin-left: 0.25em; }

.state-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.2em 0.6em;
  border-radius: 999px;
  min-width: 4.4em;
  justify-content: center;
}
.state-pill svg { width: 0.85em; height: 0.85em; }
.state-pill--pending { background: var(--surface); color: var(--ink-faint); border: 1px solid var(--line-strong); }
.state-pill--pass { background: var(--moss-tint); color: var(--moss-strong); }
.state-pill--fail { background: var(--brick-tint); color: var(--brick); }
.state-pill--na { background: var(--slate-tint); color: var(--slate); }

.checklist__controls { display: inline-flex; gap: 0.3rem; margin-left: auto; }
.chip-btn {
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-muted);
  font-size: 0.76rem;
  font-weight: 600;
  padding: 0.28em 0.65em;
  border-radius: var(--radius-s);
  cursor: pointer;
}
.chip-btn:hover { border-color: var(--moss); color: var(--moss-strong); }
.chip-btn[aria-pressed="true"] { background: var(--moss); border-color: var(--moss); color: var(--moss-contrast); }
.chip-btn--fail[aria-pressed="true"] { background: var(--brick); border-color: var(--brick); color: var(--brick-contrast); }
.chip-btn--na[aria-pressed="true"] { background: var(--slate); border-color: var(--slate); color: var(--slate-contrast); }

/* actions / assignment */
.review-card__actions {
  margin-top: 1.3rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}
.assign { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; color: var(--ink-muted); }
.assign select {
  font: inherit;
  padding: 0.35em 0.6em;
  border-radius: var(--radius-s);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
}
.review-card__actions .action-buttons { display: flex; gap: 0.5rem; margin-left: auto; flex-wrap: wrap; }
.review-card__actions .btn--approve { flex: 0 0 auto; width: auto; }
.review-card__actions .btn--changes { flex: 0 0 auto; width: auto; }
.review-card__readonly { color: var(--ink-faint); font-size: 0.85rem; margin: 1.1rem 0 0; }

.changes-panel { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.8rem; }
.changes-panel .changes-note {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  resize: vertical;
}
.changes-panel .btn--changes-send { align-self: flex-start; width: auto; }

.review-card__resolved {
  margin-top: 1.1rem;
  padding: 0.7rem 1rem;
  border-radius: var(--radius-s);
  font-size: 0.88rem;
  font-weight: 600;
}
.review-card__resolved--merged { background: var(--moss-tint); color: var(--moss-strong); }
.review-card__resolved--closed { background: var(--brick-tint); color: var(--brick); }
.review-card__resolved--changes { background: var(--amber-tint); color: var(--amber); }

/* empty states */
.empty-state {
  text-align: center;
  padding: 3.5rem 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-l);
  color: var(--ink-muted);
}
.empty-state svg { width: 2.6rem; height: 2.6rem; color: var(--moss); margin-bottom: 0.8rem; }
.empty-state h2 { font-size: 1.05rem; color: var(--ink); }

/* breadcrumb */
.breadcrumb {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--ink-muted);
  text-decoration: none;
  font-size: 0.88rem;
  font-weight: 600;
  margin-bottom: 1.2rem;
}
.breadcrumb:hover { color: var(--moss-strong); }
.breadcrumb svg { width: 1em; height: 1em; }

/* ---------- toasts ---------- */
.toast-region {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  z-index: 60;
  max-width: min(24rem, calc(100vw - 2rem));
}
.toast {
  background: var(--ink);
  color: var(--bg);
  padding: 0.75rem 1rem;
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-pop);
  font-size: 0.88rem;
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}
.toast--error { background: var(--brick); color: var(--brick-contrast); }
.toast--success { background: var(--moss-strong); color: var(--moss-contrast); }
.toast__close {
  margin-left: auto;
  background: transparent;
  border: none;
  color: inherit;
  opacity: 0.75;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  font-size: 1rem;
}
.toast__close:hover { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .toast { animation: toast-in 0.2s ease both; }
  @keyframes toast-in { from { opacity: 0; transform: translateY(6px); } }
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* Inline notices inside a review card. Used where something upstream of us went wrong and the
   curator would otherwise have to go digging in the Actions tab to find out. */
.notice {
  margin: 0 0 1.1rem;
  padding: 0.85rem 1rem;
  border-radius: 10px;
  font-size: 0.9rem;
  line-height: 1.5;
  border-left: 3px solid transparent;
}
.notice strong { display: block; margin-bottom: 0.2rem; }
.notice a { color: inherit; }
.notice--warn {
  background: var(--amber-tint);
  color: var(--amber);
  border-left-color: var(--amber);
}

/* Revision upload on an open new-pathway review — the submitter's way to answer a change
   request without touching git, which is the point of the portal. */
.revise-panel { margin: 0 0 1.1rem; padding: 0.9rem 1rem; border: 1px dashed var(--line); border-radius: 10px; }
.revise-panel__label { display: block; font-size: 0.82rem; font-weight: 600; margin-bottom: 0.5rem; }
.revise-panel__hint { margin: 0.5rem 0 0; font-size: 0.82rem; color: var(--ink-muted); }
.revise-file { display: block; margin-bottom: 0.6rem; font-size: 0.85rem; }

/* ---------- review state, labels, and the repository's own output ---------- */
/* One banner per card carrying the state and, where there is one, the reason: the note is the
   only place "the accepted label has been on for 40 minutes and nothing published" appears. */
.review-state {
  margin: 0 0 1rem;
  padding: 0.7rem 0.9rem;
  border-radius: var(--radius-m);
  border-left: 3px solid var(--line-strong);
  background: var(--surface-2);
  font-size: 0.9rem;
  overflow-wrap: anywhere;
}
.review-state__note { display: block; margin-top: 0.35rem; color: var(--ink-muted); }
.review-state--warn { background: var(--amber-tint); border-left-color: var(--amber); }
.review-state--info { background: var(--moss-tint); border-left-color: var(--moss); }
.review-state--ok { background: var(--wp-green-tint); border-left-color: var(--wp-green); }
.review-state--bad { background: var(--brick-tint); border-left-color: var(--brick); }
.review-state--muted { background: var(--surface-2); border-left-color: var(--line-strong); }

/* The repository's own labels, so the dashboard and the pull request are visibly one review. */
.gh-labels { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: -0.4rem 0 0.9rem; }
.gh-label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  padding: 0.15em 0.5em;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  color: var(--ink-muted);
  background: var(--surface-2);
}

.pipeline-panel {
  margin: 0 0 1.1rem;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface-2);
}
.pipeline-panel h3 { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-muted); margin-bottom: 0.5rem; }
.pipeline-panel h3 code { text-transform: none; letter-spacing: 0; font-size: 0.85em; }
.pipeline-panel__facts { list-style: none; display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; margin: 0 0 0.5rem; padding: 0; font-size: 0.88rem; }
.pipeline-panel__slug { font-family: var(--font-mono); font-size: 0.85em; color: var(--ink-muted); }
.pipeline-panel__links { display: flex; flex-wrap: wrap; gap: 0.9rem; margin: 0 0 0.4rem; font-size: 0.88rem; }
.pipeline-panel__hint { margin: 0; font-size: 0.83rem; color: var(--ink-muted); }

/* ---------- pre-flight on the submit form ----------
   The same findings the review card shows, at the moment the file is chosen. Deliberately not
   styled as an error: nothing here blocks the button, and a red box on a file that will submit
   fine teaches people to ignore it. */
.preflight {
  margin: 0 0 1rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius-m);
  background: var(--surface-2);
  font-size: 0.88rem;
}
.preflight--warn { border-left-color: var(--amber); }
.preflight--fail { border-left-color: var(--brick); }
.preflight--clean { border-left-color: var(--wp-green); }
.preflight__lede { display: block; color: var(--ink-muted); line-height: 1.5; }
.preflight__list { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 0.5rem; }
.preflight__item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.6rem;
  align-items: baseline;
}
.preflight__pill {
  grid-row: 1; grid-column: 1;
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.15rem 0.45rem; border-radius: 999px; white-space: nowrap;
  background: var(--amber-tint); color: var(--amber);
}
.preflight__pill--fail, .preflight__pill--block { background: var(--brick-tint); color: var(--brick); }
.preflight__title { grid-row: 1; grid-column: 2; font-weight: 600; }
.preflight__detail { grid-row: 2; grid-column: 2; color: var(--ink-muted); line-height: 1.5; }

/* ---------- automated checks (app/quality) ----------
   Sits above the checklist and is deliberately not styled like it: the checklist is what a curator
   has decided, this is what was measured. Same card grammar as .pipeline-panel, with a left rule
   that carries the rollup severity so the state is legible before any of the text is read. */
.quality {
  margin: 0 0 1.1rem;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius-m);
  background: var(--surface-2);
}
.quality--warn { border-left-color: var(--amber); }
.quality--fail, .quality--block { border-left-color: var(--brick); }
.quality__heading {
  font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-muted); margin: 0 0 0.55rem;
}
.quality__pipeline {
  margin: 0 0 0.7rem; padding: 0.6rem 0.75rem; border-radius: var(--radius-s);
  background: var(--amber-tint); color: var(--amber); font-size: 0.86rem; line-height: 1.5;
}
.quality__pipeline strong { display: block; margin-bottom: 0.2rem; }
.quality__pipeline a { color: inherit; }
.quality__clean { margin: 0; font-size: 0.88rem; color: var(--ink-muted); }
.quality__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.quality__item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.6rem;
  align-items: baseline;
  font-size: 0.88rem;
}
.quality__pill {
  grid-row: 1; grid-column: 1;
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.15rem 0.45rem; border-radius: 999px; white-space: nowrap;
  background: var(--slate-tint); color: var(--slate);
}
.quality__pill--warn { background: var(--amber-tint); color: var(--amber); }
.quality__pill--fail, .quality__pill--block { background: var(--brick-tint); color: var(--brick); }
.quality__pill--pass { background: var(--wp-green-tint); color: var(--wp-green-strong); }
.quality__title { grid-row: 1; grid-column: 2; font-weight: 600; }
.quality__detail { grid-row: 2; grid-column: 2; color: var(--ink-muted); line-height: 1.5; }
/* The repository's own answer to the same test, when its workflow has reported one. Quiet by
   design — it is corroboration, and only interesting when it disagrees. */
.quality__echo {
  grid-row: 3; grid-column: 2;
  font-size: 0.78rem; color: var(--ink-faint);
}
.quality__echo--review { color: var(--amber); }
.quality__rest { margin-top: 0.6rem; }
.quality__rest > summary {
  cursor: pointer; font-size: 0.82rem; color: var(--ink-muted);
  padding: 0.15rem 0; list-style-position: outside;
}
.quality__rest > summary:hover { color: var(--moss-strong); }
/* The queue's summary is the whole panel, not a footnote to it. */
.review-card:not(.review-card--expanded) .quality__rest { margin-top: 0; }
.review-card:not(.review-card--expanded) .quality__rest > summary {
  font-size: 0.9rem; font-weight: 600; color: var(--ink);
}
.quality__rest[open] > summary { margin-bottom: 0.5rem; }

/* ---------- terminal actions ---------- */
.btn--danger { color: var(--brick); border-color: color-mix(in srgb, var(--brick) 45%, transparent); }
.btn--danger:hover:not(:disabled) { background: var(--brick-tint); }

.reject-panel,
.publish-panel {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.8rem;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface-2);
}
.reject-panel { border-color: color-mix(in srgb, var(--brick) 35%, var(--line)); }
.reject-note, .changes-note { width: 100%; font: inherit; padding: 0.5em 0.6em; border: 1px solid var(--line-strong); border-radius: var(--radius-s); background: var(--surface); color: var(--ink); }
.reject-panel__warn { margin: 0; font-size: 0.83rem; color: var(--brick); }
.publish-panel h3 { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-muted); margin: 0; }
.publish-panel__hint { margin: 0; font-size: 0.85rem; color: var(--ink-muted); }
.published-wpid { font-family: var(--font-mono); padding: 0.5em 0.6em; border: 1px solid var(--line-strong); border-radius: var(--radius-s); background: var(--surface); color: var(--ink); max-width: 12rem; }
.reject-panel .btn, .publish-panel .btn { align-self: flex-start; }

/* ---------- assorted corrections ---------- */
/* .muted was used three times and defined nowhere, so "(optional)" inherited the uppercase
   mono field label and shouted the one word telling an author they may skip the field. */
.muted { color: var(--ink-muted); font-weight: 400; text-transform: none; letter-spacing: 0; }

/* The card's accessible name. Present for assistive technology, invisible in the layout, which
   already carries the same information as a WPID chip and a row of badges. */
.review-card__title {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.queue-filter__count {
  font-family: var(--font-mono);
  font-size: 0.78em;
  padding: 0.05em 0.4em;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink-muted);
}
.queue-filter__mine { margin-left: auto; }

.state-pill__text { display: inline-block; }

.result-card--error { border-color: color-mix(in srgb, var(--brick) 45%, var(--line)); background: var(--brick-tint); }

/* Long unbroken strings — a pasted PMC URL, a 39-character login — used to push past the card
   and give the whole page a horizontal scrollbar. */
.meta-panel__block p,
.review-card__submitter,
.result-card { overflow-wrap: anywhere; }

/* The empty/failed placeholders were pinned at the queue's 19rem, so on the detail page they
   sat two-thirds the height of a ready frame beside them. */
.review-card--expanded .preview__empty,
.review-card--expanded .preview__failed { min-height: 30rem; }

/* ---------- narrow viewports ---------- */
/* The header was a nowrap row of ~185px of brand plus up to 350px of identity in ~327px of
   space, so a phone got a horizontal scrollbar and Log out went off-screen. */
@media (max-width: 720px) {
  .site-header__inner { flex-wrap: wrap; row-gap: 0.4rem; }
  .site-header__portal { display: none; }
  .site-header__nav { margin-left: 0; width: 100%; gap: 0.8rem; }
  .site-header__who { min-width: 0; overflow-wrap: anywhere; }
  .queue-filter__mine { margin-left: 0; }
}
