/* The review app's stylesheet. Same palette and the same provenance
   vocabulary as the course site: colour means a human stands behind it. */

:root {
  --bg: #eef2ec;
  --fg: #1a2420;
  --line: #c9d3c9;
  --accent: #064c33;
  --quiet: #5c6b62;
  --card: #ffffff;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #142219;
    --fg: #dcefe3;
    --line: #2c4436;
    --accent: #6fd9a5;
    --quiet: #93a89b;
    --card: #1b2c22;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.5;
}

header {
  padding: 0.8rem 1.5rem;
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}

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

/* Who the next approval will be signed by. Pushed to the far end, because it
   is a standing fact rather than something to read on the way in. */
.who {
  margin-left: auto;
  font-weight: 400;
  font-size: 0.9rem;
  color: var(--quiet);
}

main { padding: 1.5rem; max-width: 1400px; margin: 0 auto; }

h1 { font-size: 1.3rem; margin: 0 0 0.8rem; }
h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.06em;
     color: var(--quiet); margin: 2rem 0 1rem; }

a { color: var(--accent); }
.quiet { color: var(--quiet); font-size: 0.9rem; }
code { font-size: 0.9em; }

/* The first line of the overview: whose move it is, before any total. */
.lead { font-size: 1.15rem; margin: 0 0 0.4rem; }
.go {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.15rem 0.7rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-size: 0.85rem;
  text-decoration: none;
  vertical-align: middle;
}

/* A type with its meaning on hover. Dotted rather than underlined, so it
   reads as "there is more here" rather than as a link. */
.kind {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  cursor: help;
}

/* Back, position, skip: one line, spaced out, above the record itself. */
.whereabouts { display: flex; align-items: center; gap: 0.8rem; }
.whereabouts .quiet { margin-left: auto; }

/* Section headings inside the record panel. Quieter than the page's own
   headings: they divide, they do not announce. */
.facet {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--quiet);
  margin: 1.4rem 0 0.3rem;
  font-weight: 600;
}
.facet:first-of-type { margin-top: 0.8rem; }

/* The abstract, which with no copy held is the only thing there is to decide
   on, so it is set to be read rather than skimmed. */
.abstract {
  max-width: 62ch;
  margin: 0.4rem 0;
  white-space: pre-wrap;
}

.tag {
  display: inline-block;
  padding: 0.05rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.8rem;
  color: var(--quiet);
}

/* Which catalogues were asked. Answered ones stand out; the rest are there to
   show the question was put to them at all. */
.tried {
  display: inline-block;
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  font-size: 0.75rem;
  border: 1px solid var(--line);
  color: var(--quiet);
  cursor: help;
}
.tried.answered { border-color: var(--accent); color: var(--accent); font-weight: 600; }

/* A remark, and what people made of it. */
.note { margin: 0.9rem 0; }
.note-head { display: flex; align-items: baseline; gap: 0.8rem; }
.note-head b { flex: 1; }
.note .abstract { margin: 0.4rem 0 0.6rem; }
.note form { margin-top: 0.4rem; }
.note button { padding: 0.3rem 0.8rem; font-size: 0.9rem; }

/* Never judged shows a dot, not a nought: nobody has read it is a different
   thing from two people disagreed. */
.score {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  cursor: help;
}
.score.unjudged { color: var(--quiet); font-weight: 400; }
.score.liked { color: var(--accent); border-color: var(--accent); }
.score.disliked { opacity: 0.75; }

.inline { display: flex; gap: 0.5rem; }

/* What just happened, above the page it happened on. Not a replacement for
   the page: an action that fails should cost neither your place nor what you
   had typed. */
.banner {
  padding: 0.6rem 1rem;
  margin: 0 0 1rem;
  border-radius: 0.25rem;
  border-left: 3px solid var(--accent);
  background: var(--card);
  font-size: 0.95rem;
}
.banner.bad { border-left-color: #b3261e; }
@media (prefers-color-scheme: dark) { .banner.bad { border-left-color: #ff8a80; } }

.tally { display: flex; gap: 1.5rem; flex-wrap: wrap; font-size: 0.95rem; }
.tally b { font-size: 1.3rem; color: var(--accent); }

.card { background: var(--card); padding: 0.9rem 1.1rem; border-radius: 0.25rem; }

/* A card's title reads as text, not as a link. The ring around the card is
   already carrying the green, and colouring the title as well made a page of
   endorsed references almost entirely green — at which point the colour stops
   distinguishing anything. Underlined on hover, so it is still plainly
   something to click. */
.card a { text-decoration: none; color: var(--fg); }
.card a:hover { text-decoration: underline; }

.row { padding: 0.5rem 0; border-bottom: 1px solid var(--line); }
.row a { text-decoration: none; }

table { border-collapse: collapse; width: 100%; }
th { text-align: left; vertical-align: top; padding: 0.35rem 1rem 0.35rem 0;
     color: var(--quiet); font-weight: 500; white-space: nowrap; width: 1%; }
td { padding: 0.35rem 0; word-break: break-word; }

.split { display: flex; gap: 1.5rem; align-items: flex-start; flex-wrap: wrap; }
.pane { flex: 1 1 420px; min-width: 0; }

iframe { width: 100%; height: 80vh; border: 1px solid var(--line);
         border-radius: 0.25rem; background: var(--card); }

.why { margin: 1.2rem 0; padding: 0.8rem 1rem; background: var(--card);
       border-left: 3px solid var(--line); border-radius: 0.25rem; }

.decide { display: flex; gap: 0.8rem; margin: 1.2rem 0; flex-wrap: wrap;
          align-items: center; }
.decide form { display: flex; gap: 0.5rem; }
button { font: inherit; padding: 0.5rem 1.2rem; border-radius: 0.25rem;
         border: 1px solid var(--line); cursor: pointer; background: var(--card);
         color: var(--fg); }
button.approve { background: var(--accent); color: var(--bg); border-color: var(--accent);
                 font-weight: 600; }
/* The cheaper of the two ways in, and it should look cheaper: a plain button
   beside the emphatic one, so the endorsing act stays the deliberate one. */
button.letthrough { color: var(--quiet); }
input[type=text] { font: inherit; padding: 0.5rem 0.7rem; border-radius: 0.25rem;
                   border: 1px solid var(--line); background: var(--card);
                   color: var(--fg); min-width: 14rem; }

/* Provenance, in three rings.

   Grey with the AI badge: nobody has vouched for this. A proposal, a request,
   and — importantly — a record let into the bibliography as plausible without
   anybody endorsing it. That last one is why the badge is not simply "not yet
   reviewed": it can be reviewed and still carry no endorsement.

   Green: somebody read it and stands behind it. This is what a citation leans
   on, and it should be the only thing that looks like an endorsement.

   Rainbow: reserved, and meant to stay under a percent of what is on screen.
   It was the approved ring, and using it for every approval made the whole
   page shout. Something that is on all the time is not emphasis. */
.quality-box { position: relative; margin: 1.2em 0; }
.quality-box::before {
  content: ""; position: absolute; inset: -4px;
  border-radius: calc(0.25rem + 4px); pointer-events: none; z-index: 2;
}
.quality-box.quality-generated::before { box-shadow: 0 0 0 2px #b8b8b8; }
@media (prefers-color-scheme: dark) {
  .quality-box.quality-generated::before { box-shadow: 0 0 0 2px #5a5a5a; }
}
.quality-box.quality-generated::after {
  content: ""; position: absolute; top: -12px; left: -12px;
  width: 22px; height: 22px; background-size: 100% 100%;
  background-repeat: no-repeat; pointer-events: none; z-index: 3;
  background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iQ2FscXVlXzEiIGRhdGEtbmFtZT0iQ2FscXVlIDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iODkuMjggMTAwLjcxIDM2NS41IDM2NS41Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmNscy0xIHsKICAgICAgICBmaWxsLXJ1bGU6IGV2ZW5vZGQ7CiAgICAgIH0KCiAgICAgIC5jbHMtMiB7CiAgICAgICAgZmlsbDogI2ZmZjsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMjcyLjAzLDEwMC43MmMxMDAuOTIsMCwxODIuNzQsODEuODIsMTgyLjc0LDE4Mi43NXMtODEuODIsMTgyLjc0LTE4Mi43NCwxODIuNzQtMTgyLjc1LTgxLjgyLTE4Mi43NS0xODIuNzQsODEuODItMTgyLjc1LDE4Mi43NS0xODIuNzUiLz4KICA8Zz4KICAgIDxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTE3MC43OSwzNTMuNzRjLTEuMDgsMC0yLjA1LS40My0yLjkyLTEuMzEtLjg4LS44Ny0xLjMxLTEuODQtMS4zMS0yLjkyLDAtLjY3LjA3LTEuMjcuMi0xLjgxbDQ3LjM0LTEyOS4zMmMuNC0xLjQ4LDEuMjQtMi43OSwyLjUyLTMuOTMsMS4yNy0xLjE0LDMuMDUtMS43MSw1LjM0LTEuNzFoMjkuODFjMi4yOCwwLDQuMDYuNTcsNS4zNCwxLjcxLDEuMjcsMS4xNCwyLjExLDIuNDUsMi41MiwzLjkzbDQ3LjE0LDEyOS4zMmMuMjcuNTQuNCwxLjE0LjQsMS44MSwwLDEuMDgtLjQ0LDIuMDUtMS4zMSwyLjkycy0xLjkxLDEuMzEtMy4xMiwxLjMxaC0yNC43OGMtMi4wMSwwLTMuNTItLjUtNC41My0xLjUxLTEuMDEtMS4wMS0xLjY1LTEuOTEtMS45MS0yLjcybC03Ljg2LTIwLjU1aC01My43OGwtNy42NSwyMC41NWMtLjI3LjgxLS44OCwxLjcxLTEuODEsMi43Mi0uOTQsMS4wMS0yLjU1LDEuNTEtNC44MywxLjUxaC0yNC43OFpNMjE4LjEzLDI5OS45NmgzNy40N2wtMTguOTMtNTMuMTgtMTguNTMsNTMuMThaIi8+CiAgICA8cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zMjguMTEsMzUzLjc0Yy0xLjQ4LDAtMi42OS0uNDctMy42My0xLjQxLS45NC0uOTQtMS40MS0yLjE1LTEuNDEtMy42M3YtMTMwLjkzYzAtMS40OC40Ny0yLjY4LDEuNDEtMy42M3MyLjE1LTEuNDEsMy42My0xLjQxaDI2Ljk5YzEuNDgsMCwyLjY4LjQ3LDMuNjMsMS40MS45NC45NCwxLjQxLDIuMTUsMS40MSwzLjYzdjEzMC45M2MwLDEuNDgtLjQ3LDIuNjktMS40MSwzLjYzLS45NC45NC0yLjE1LDEuNDEtMy42MywxLjQxaC0yNi45OVoiLz4KICA8L2c+Cjwvc3ZnPg==");
}
@media (prefers-color-scheme: dark) {
  .quality-box.quality-generated::after {
    background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iQ2FscXVlXzEiIGRhdGEtbmFtZT0iQ2FscXVlIDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iODkuMjggMTAwLjcxIDM2NS41IDM2NS41Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmNscy0xIHsKICAgICAgICBmaWxsOiAjZmZmOwogICAgICAgIGZpbGwtcnVsZTogZXZlbm9kZDsKICAgICAgfQoKICAgICAgLmNscy0yIHsKICAgICAgICBmaWxsOiAjMWQxZDFiOwogICAgICB9CiAgICA8L3N0eWxlPgogIDwvZGVmcz4KICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0yNzIuMDMsMTAwLjcyYzEwMC45MiwwLDE4Mi43NCw4MS44MiwxODIuNzQsMTgyLjc1cy04MS44MiwxODIuNzQtMTgyLjc0LDE4Mi43NC0xODIuNzUtODEuODItMTgyLjc1LTE4Mi43NCw4MS44Mi0xODIuNzUsMTgyLjc1LTE4Mi43NSIvPgogIDxnPgogICAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMTcwLjc5LDM1My43NGMtMS4wOCwwLTIuMDUtLjQzLTIuOTItMS4zMS0uODgtLjg3LTEuMzEtMS44NC0xLjMxLTIuOTIsMC0uNjcuMDctMS4yNy4yLTEuODFsNDcuMzQtMTI5LjMyYy40LTEuNDgsMS4yNC0yLjc5LDIuNTItMy45MywxLjI3LTEuMTQsMy4wNS0xLjcxLDUuMzQtMS43MWgyOS44MWMyLjI4LDAsNC4wNi41Nyw1LjM0LDEuNzEsMS4yNywxLjE0LDIuMTEsMi40NSwyLjUyLDMuOTNsNDcuMTQsMTI5LjMyYy4yNy41NC40LDEuMTQuNCwxLjgxLDAsMS4wOC0uNDQsMi4wNS0xLjMxLDIuOTJzLTEuOTEsMS4zMS0zLjEyLDEuMzFoLTI0Ljc4Yy0yLjAxLDAtMy41Mi0uNS00LjUzLTEuNTEtMS4wMS0xLjAxLTEuNjUtMS45MS0xLjkxLTIuNzJsLTcuODYtMjAuNTVoLTUzLjc4bC03LjY1LDIwLjU1Yy0uMjcuODEtLjg4LDEuNzEtMS44MSwyLjcyLS45NCwxLjAxLTIuNTUsMS41MS00LjgzLDEuNTFoLTI0Ljc4Wk0yMTguMTMsMjk5Ljk2aDM3LjQ3bC0xOC45My01My4xOC0xOC41Myw1My4xOFoiLz4KICAgIDxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTMyOC4xMSwzNTMuNzRjLTEuNDgsMC0yLjY5LS40Ny0zLjYzLTEuNDEtLjk0LS45NC0xLjQxLTIuMTUtMS40MS0zLjYzdi0xMzAuOTNjMC0xLjQ4LjQ3LTIuNjgsMS40MS0zLjYzczIuMTUtMS40MSwzLjYzLTEuNDFoMjYuOTljMS40OCwwLDIuNjguNDcsMy42MywxLjQxLjk0Ljk0LDEuNDEsMi4xNSwxLjQxLDMuNjN2MTMwLjkzYzAsMS40OC0uNDcsMi42OS0xLjQxLDMuNjMtLjk0Ljk0LTIuMTUsMS40MS0zLjYzLDEuNDFoLTI2Ljk5WiIvPgogIDwvZz4KPC9zdmc+");
  }
}
.quality-box.quality-human::before {
  box-shadow: 0 0 0 2px var(--accent);
}

.quality-box.quality-special::before {
  inset: -6px; border-radius: calc(0.25rem + 6px); padding: 2px;
  /* Visible spectrum, 340nm (top-left) to 820nm (bottom-right), sampled every
     20nm, matching the course site. Dan Bruton's wavelength-to-RGB
     approximation, gamma 0.8, with his intensity falloff continued past both
     ends: the corners go dark as the spectrum runs into ultraviolet and
     infrared. */
  background: linear-gradient(
    to bottom right,
    #000000 0%, #3f003f 4%, #6e006e 8%, #6e0098 12%, #6a00ff 17%,
    #0000ff 21%, #007bff 25%, #00d5ff 29%, #00ff92 33%, #36ff00 38%,
    #81ff00 42%, #c3ff00 46%, #ffff00 50%, #ffbe00 54%, #ff7700 58%,
    #ff2100 62%, #ff0000 67%, #ff0000 75%, #a60000 79%, #8b0000 83%,
    #6e0000 88%, #500000 92%, #2e0000 96%, #000000 100%
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
/* A request is machine work like any other: nobody has vouched for the thing
   it names, and it was ringed in the endorsement colour, which said the
   opposite. */
.quality-box.quality-requested::before { box-shadow: 0 0 0 2px #b8b8b8; }
@media (prefers-color-scheme: dark) {
  .quality-box.quality-requested::before { box-shadow: 0 0 0 2px #5a5a5a; }
}

.search { display: flex; gap: 0.5rem; margin: 1rem 0; }
.search input { flex: 1 1 auto; max-width: 30rem; }

.stats th { padding-right: 2rem; }
.stats td { font-variant-numeric: tabular-nums; }

/* Every box you act in looks the same: the file, the sets, the annotations,
   sending back, turning down. Only the bibliographic card is different, and it
   is different on purpose — it carries the grey or green ring that says who
   stands behind the record, and a page where five things compete for that
   distinction gives it to none of them. */
.source, .sets, .annotations, .reject-block {
  background: var(--card);
  padding: 0.9rem 1.1rem;
  border-radius: 0.25rem;
  margin: 1.2rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: flex-start;
}
.source form, .sets form { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.source label, .sets label, .annotations label, .reject-block label {
  display: flex; flex-direction: column; gap: 0.3rem; font-weight: 600; width: 100%;
}
.source label .quiet, .reject-block label .quiet { font-weight: 400; }
.annotations, .reject-block { width: 100%; }
.reject-block { align-items: flex-start; }
/* The form is the box's own shape: heading, the line explaining it just
   under, the field, then air before the button. Without the gap the button
   sits against the textarea and reads as part of it. */
.reject-block form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.8rem;
  width: 100%;
}
.reject-block label { gap: 0.35rem; }
.reject-block label .quiet { margin-bottom: 0.15rem; }
.source form { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.source.held { border-left: 3px solid var(--accent); }

.held { color: var(--accent); }
label.quiet { display: flex; align-items: center; gap: 0.3rem; }

.tabs { display: flex; gap: 0.25rem; padding: 0 1.5rem;
        border-bottom: 1px solid var(--line); }
/* Every tab is bold at every moment, so the row never reflows when the
   active one changes. Only colour moves. */
.tab { padding: 0.6rem 1.1rem; text-decoration: none; color: var(--quiet);
       border-bottom: 2px solid transparent; margin-bottom: -1px;
       font-weight: 600; }
.tab:hover { color: var(--fg); }
.tab.on { color: var(--fg); border-bottom-color: var(--accent); }

.badge { display: inline-block; min-width: 1.4em; padding: 0 0.35em;
         border-radius: 1em; background: var(--line); color: var(--fg);
         font-size: 0.8em; text-align: center; font-weight: 600; }
.badge.urgent { background: var(--accent); color: var(--bg); }

.submit { display: flex; flex-direction: column; gap: 0.8rem; max-width: 40rem;
          background: var(--card); padding: 1.2rem; border-radius: 0.25rem; }
.submit label { display: flex; flex-direction: column; gap: 0.25rem; font-weight: 600; }
.submit label .quiet { font-weight: 400; }
.submit input { width: 100%; }
.submit button { align-self: flex-start; }

.warn { color: #b3261e; font-weight: 600; }
@media (prefers-color-scheme: dark) { .warn { color: #ff8a80; } }

footer {
  margin-top: 3rem; padding: 1rem 1.5rem;
  border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  font-size: 0.85rem; color: var(--quiet);
}
footer a { color: var(--quiet); }
.tiny-image { height: 1em; margin-left: 0.2em; vertical-align: -0.1em;
              display: inline-block; width: 1em;
              background-size: contain; background-repeat: no-repeat;
              background-position: center; }
.tiny-image.cc { background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxMy4wLjIsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDE0OTQ4KSAgLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMC8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAxL1JFQy1TVkctMjAwMTA5MDQvRFREL3N2ZzEwLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMCIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iNjRweCIgaGVpZ2h0PSI2NHB4IiB2aWV3Qm94PSI1LjUgLTMuNSA2NCA2NCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyA1LjUgLTMuNSA2NCA2NCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Y2lyY2xlIGZpbGw9IiNGRkZGRkYiIGN4PSIzNy43ODUiIGN5PSIyOC41MDEiIHI9IjI4LjgzNiIvPg0KCTxwYXRoIGQ9Ik0zNy40NDEtMy41YzguOTUxLDAsMTYuNTcyLDMuMTI1LDIyLjg1Nyw5LjM3MmMzLjAwOCwzLjAwOSw1LjI5NSw2LjQ0OCw2Ljg1NywxMC4zMTQNCgkJYzEuNTYxLDMuODY3LDIuMzQ0LDcuOTcxLDIuMzQ0LDEyLjMxNGMwLDQuMzgxLTAuNzczLDguNDg2LTIuMzE0LDEyLjMxM2MtMS41NDMsMy44MjgtMy44Miw3LjIxLTYuODI4LDEwLjE0Mw0KCQljLTMuMTIzLDMuMDg1LTYuNjY2LDUuNDQ4LTEwLjYyOSw3LjA4NmMtMy45NjEsMS42MzgtOC4wNTcsMi40NTctMTIuMjg1LDIuNDU3cy04LjI3Ni0wLjgwOC0xMi4xNDMtMi40MjkNCgkJYy0zLjg2Ni0xLjYxOC03LjMzMy0zLjk2MS0xMC40LTcuMDI3Yy0zLjA2Ny0zLjA2Ni01LjQtNi41MjQtNy0xMC4zNzJTNS41LDMyLjc2Nyw1LjUsMjguNWMwLTQuMjI5LDAuODA5LTguMjk1LDIuNDI4LTEyLjINCgkJYzEuNjE5LTMuOTA1LDMuOTcyLTcuNCw3LjA1Ny0xMC40ODZDMjEuMDgtMC4zOTQsMjguNTY1LTMuNSwzNy40NDEtMy41eiBNMzcuNTU3LDIuMjcyYy03LjMxNCwwLTEzLjQ2NywyLjU1My0xOC40NTgsNy42NTcNCgkJYy0yLjUxNSwyLjU1My00LjQ0OCw1LjQxOS01LjgsOC42Yy0xLjM1NCwzLjE4MS0yLjAyOSw2LjUwNS0yLjAyOSw5Ljk3MmMwLDMuNDI5LDAuNjc1LDYuNzM0LDIuMDI5LDkuOTEzDQoJCWMxLjM1MywzLjE4MywzLjI4NSw2LjAyMSw1LjgsOC41MTZjMi41MTQsMi40OTYsNS4zNTEsNC4zOTksOC41MTUsNS43MTVjMy4xNjEsMS4zMTQsNi40NzYsMS45NzEsOS45NDMsMS45NzENCgkJYzMuNDI4LDAsNi43NS0wLjY2NSw5Ljk3My0xLjk5OWMzLjIxOS0xLjMzNSw2LjEyMS0zLjI1Nyw4LjcxMy01Ljc3MWM0Ljk5LTQuODc2LDcuNDg0LTEwLjk5LDcuNDg0LTE4LjM0NA0KCQljMC0zLjU0My0wLjY0OC02Ljg5NS0xLjk0My0xMC4wNTdjLTEuMjkzLTMuMTYyLTMuMTgtNS45OC01LjY1NC04LjQ1OEM1MC45ODQsNC44NDQsNDQuNzk1LDIuMjcyLDM3LjU1NywyLjI3MnogTTM3LjE1NiwyMy4xODcNCgkJbC00LjI4NywyLjIyOWMtMC40NTgtMC45NTEtMS4wMTktMS42MTktMS42ODUtMmMtMC42NjctMC4zOC0xLjI4Ni0wLjU3MS0xLjg1OC0wLjU3MWMtMi44NTYsMC00LjI4NiwxLjg4NS00LjI4Niw1LjY1Nw0KCQljMCwxLjcxNCwwLjM2MiwzLjA4NCwxLjA4NSw0LjExM2MwLjcyNCwxLjAyOSwxLjc5MSwxLjU0NCwzLjIwMSwxLjU0NGMxLjg2NywwLDMuMTgxLTAuOTE1LDMuOTQ0LTIuNzQzbDMuOTQyLDINCgkJYy0wLjgzOCwxLjU2My0yLDIuNzkxLTMuNDg2LDMuNjg2Yy0xLjQ4NCwwLjg5Ni0zLjEyMywxLjM0My00LjkxNCwxLjM0M2MtMi44NTcsMC01LjE2My0wLjg3NS02LjkxNS0yLjYyOQ0KCQljLTEuNzUyLTEuNzUyLTIuNjI4LTQuMTktMi42MjgtNy4zMTNjMC0zLjA0OCwwLjg4Ni01LjQ2NiwyLjY1Ny03LjI1N2MxLjc3MS0xLjc5LDQuMDA5LTIuNjg2LDYuNzE1LTIuNjg2DQoJCUMzMi42MDQsMTguNTU4LDM1LjQ0MSwyMC4xMDEsMzcuMTU2LDIzLjE4N3ogTTU1LjYxMywyMy4xODdsLTQuMjI5LDIuMjI5Yy0wLjQ1Ny0wLjk1MS0xLjAyLTEuNjE5LTEuNjg2LTINCgkJYy0wLjY2OC0wLjM4LTEuMzA3LTAuNTcxLTEuOTE0LTAuNTcxYy0yLjg1NywwLTQuMjg3LDEuODg1LTQuMjg3LDUuNjU3YzAsMS43MTQsMC4zNjMsMy4wODQsMS4wODYsNC4xMTMNCgkJYzAuNzIzLDEuMDI5LDEuNzg5LDEuNTQ0LDMuMjAxLDEuNTQ0YzEuODY1LDAsMy4xOC0wLjkxNSwzLjk0MS0yLjc0M2w0LDJjLTAuODc1LDEuNTYzLTIuMDU3LDIuNzkxLTMuNTQxLDMuNjg2DQoJCWMtMS40ODYsMC44OTYtMy4xMDUsMS4zNDMtNC44NTcsMS4zNDNjLTIuODk2LDAtNS4yMDktMC44NzUtNi45NDEtMi42MjljLTEuNzM2LTEuNzUyLTIuNjAyLTQuMTktMi42MDItNy4zMTMNCgkJYzAtMy4wNDgsMC44ODUtNS40NjYsMi42NTgtNy4yNTdjMS43Ny0xLjc5LDQuMDA4LTIuNjg2LDYuNzEzLTIuNjg2QzUxLjExNywxOC41NTgsNTMuOTM4LDIwLjEwMSw1NS42MTMsMjMuMTg3eiIvPg0KPC9nPg0KPC9zdmc+DQo="); }
.tiny-image.by { background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxMy4wLjIsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDE0OTQ4KSAgLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMC8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAxL1JFQy1TVkctMjAwMTA5MDQvRFREL3N2ZzEwLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMCIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iNjRweCIgaGVpZ2h0PSI2NHB4IiB2aWV3Qm94PSI1LjUgLTMuNSA2NCA2NCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyA1LjUgLTMuNSA2NCA2NCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Y2lyY2xlIGZpbGw9IiNGRkZGRkYiIGN4PSIzNy42MzciIGN5PSIyOC44MDYiIHI9IjI4LjI3NiIvPg0KCTxnPg0KCQk8cGF0aCBkPSJNMzcuNDQzLTMuNWM4Ljk4OCwwLDE2LjU3LDMuMDg1LDIyLjc0Miw5LjI1N0M2Ni4zOTMsMTEuOTY3LDY5LjUsMTkuNTQ4LDY5LjUsMjguNWMwLDguOTkxLTMuMDQ5LDE2LjQ3Ni05LjE0NSwyMi40NTYNCgkJCUM1My44NzksNTcuMzE5LDQ2LjI0Miw2MC41LDM3LjQ0Myw2MC41Yy04LjY0OSwwLTE2LjE1My0zLjE0NC0yMi41MTQtOS40M0M4LjY0NCw0NC43ODQsNS41LDM3LjI2Miw1LjUsMjguNQ0KCQkJYzAtOC43NjEsMy4xNDQtMTYuMzQyLDkuNDI5LTIyLjc0MkMyMS4xMDEtMC40MTUsMjguNjA0LTMuNSwzNy40NDMtMy41eiBNMzcuNTU3LDIuMjcyYy03LjI3NiwwLTEzLjQyOCwyLjU1My0xOC40NTcsNy42NTcNCgkJCWMtNS4yMiw1LjMzNC03LjgyOSwxMS41MjUtNy44MjksMTguNTcyYzAsNy4wODYsMi41OSwxMy4yMiw3Ljc3LDE4LjM5OGM1LjE4MSw1LjE4MiwxMS4zNTIsNy43NzEsMTguNTE0LDcuNzcxDQoJCQljNy4xMjMsMCwxMy4zMzQtMi42MDcsMTguNjI5LTcuODI4YzUuMDI5LTQuODM4LDcuNTQzLTEwLjk1Miw3LjU0My0xOC4zNDNjMC03LjI3Ni0yLjU1My0xMy40NjUtNy42NTYtMTguNTcxDQoJCQlDNTAuOTY3LDQuODI0LDQ0Ljc5NSwyLjI3MiwzNy41NTcsMi4yNzJ6IE00Ni4xMjksMjAuNTU3djEzLjA4NWgtMy42NTZ2MTUuNTQyaC05Ljk0NFYzMy42NDNoLTMuNjU2VjIwLjU1Nw0KCQkJYzAtMC41NzIsMC4yLTEuMDU3LDAuNTk5LTEuNDU3YzAuNDAxLTAuMzk5LDAuODg3LTAuNiwxLjQ1Ny0wLjZoMTMuMTQ0YzAuNTMzLDAsMS4wMSwwLjIsMS40MjgsMC42DQoJCQlDNDUuOTE4LDE5LjUsNDYuMTI5LDE5Ljk4Niw0Ni4xMjksMjAuNTU3eiBNMzMuMDQyLDEyLjMyOWMwLTMuMDA4LDEuNDg1LTQuNTE0LDQuNDU4LTQuNTE0czQuNDU3LDEuNTA0LDQuNDU3LDQuNTE0DQoJCQljMCwyLjk3MS0xLjQ4Niw0LjQ1Ny00LjQ1Nyw0LjQ1N1MzMy4wNDIsMTUuMywzMy4wNDIsMTIuMzI5eiIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K"); }

.paste {
  min-height: 12rem; max-height: 60vh; overflow-y: auto;
  padding: 0.7rem; border: 1px solid var(--line); border-radius: 0.25rem;
  background: var(--bg); font-weight: 400;
}
.paste:empty::before { content: attr(data-placeholder); color: var(--quiet); }
.paste:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.paste a { color: var(--accent); }

.inline { margin: -0.6rem 0 1.4rem 0.2rem; }


textarea { font: inherit; width: 100%; padding: 0.5rem 0.7rem; resize: vertical;
           border-radius: 0.25rem; border: 1px solid var(--line);
           background: var(--bg); color: var(--fg); }
textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

/* Chips: a year or an author is a short label in a long row of them, and a
   row of underlined links is unreadable at that density. */
.chip {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  margin: 0 0.25rem 0.35rem 0;
  border: 1px solid var(--line);
  border-radius: 1rem;
  text-decoration: none;
  font-size: 0.9rem;
}
.chip:hover { border-color: var(--fg); }

/* A form sitting inside a sentence, for recording one number without leaving
   the page it is about. */
form.inline { display: inline; }
form.inline label { display: inline; }
form.inline input { width: 5rem; }

/* An author with a page of their own, so a row of names shows at a glance
   which have been looked into. */
.chip.known { border-color: var(--ok, #2f7d5b); }

/* Committed here, not yet anywhere else. In the header because it is a state
   the whole app is in, not a place to go. */
.unsent {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: auto;
  font-size: 0.85rem;
  color: var(--warn, #a8631b);
}
.unsent button { font-size: 0.85rem; padding: 0.1rem 0.5rem; }

/* Annotations: what somebody thought, under the paper it is about. Ringed
   like everything else here — green for a person's judgement, grey and the
   badge for a machine's suggestion. */
.annotations { margin-top: 1.5rem; }
.quality-box.note { padding: 0.7rem 0.9rem; margin: 0.7rem 0; }
.quality-box.note .body p { margin: 0 0 0.4rem; }
.quality-box.note .body p:last-child { margin-bottom: 0; }
.annotations textarea { width: 100%; }
button.plain {
  background: none;
  border: none;
  padding: 0;
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
}

/* The two feedback boxes, side by side under both columns. Deciding is not
   part of reading the record or reading the paper, so it sits below both
   rather than at the bottom of whichever column had room. */
.split.below { margin-top: 1.5rem; align-items: stretch; }
.split.below .pane { min-width: 0; display: flex; }
/* Equal height, because they are two answers to one question and one of them
   looking bigger is an argument for it. The textarea takes up the slack. */
.split.below .reject-block { flex: 1; }
.split.below .reject-block label { flex: 1; }
.split.below textarea { flex: 1; min-height: 5rem; }

/* Set membership, in a box like the other things you fill in, so the left
   column reads as: what the work is, then where it belongs. */
.sets select { max-width: 14rem; }

/* How the record got here, below the box holding what it says. Quieter than
   the bibliographic tables: it is read when something is wrong, not when
   somebody is looking up where a paper appeared. */
.whence { margin: 1rem 0; font-size: 0.9rem; }
.whence table { width: 100%; }
.whence th { text-align: left; font-weight: normal; color: var(--quiet, #667); width: 9rem; }

/* Two buttons on one line inside the file box. */
.source .row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.source input[type="url"] { width: 100%; }

/* A remark of four words was drawing a box four words wide, because the
   surrounding box packs its children to the left. They are a column of
   entries: a stack of ragged widths reads as a mess, and the ring around each
   one is a statement about provenance that should be the same size whatever
   the remark says. */
.annotations .quality-box.note { width: 100%; align-self: stretch; }

/* What was asked to be put right, above the correction that answers it. The
   same box a remark gets, because it is the same thing: somebody's words,
   with their line breaks, under their name. Requests quote their evidence — a
   BibTeX entry off a catalogue page, a line from a publisher — and that is
   the useful kind, so it has to survive being displayed. */
.quality-box.note.asked { width: 100%; }
.quality-box.note.asked .body { white-space: pre-wrap; max-width: 72ch; }
.quality-box.note.asked .body p { white-space: pre-wrap; }

/* Field by field, what a correction does to the published record. Two columns
   of values with the field name down the side, so the eye runs across one line
   rather than between two tables on two pages. */
.changed { margin: 0.8rem 0 1.2rem; font-size: 0.95rem; }
.changed th:first-child { width: 9rem; }
.changed tr > th:not(:first-child) { color: var(--quiet); font-weight: 500; }
.changed td { width: 45%; word-break: break-word; }
.changed td:first-of-type { color: var(--quiet); }

/* What the agent was sent looking for. The instruction is the heading of its
   own box; what came back sits under it, set apart, because those are two
   people's words and the second is the one being judged. */
.quality-box.note.asked .body.found {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--line);
}
.quality-box.note.asked .body.found p { white-space: pre-wrap; }
/* The asking reads as the heading of its box. Not a <b> around it: what a
   person typed is paragraphs, and a block inside an inline element is markup
   no browser is obliged to make sense of. */
.quality-box.note.asked .body.ask p { font-weight: 600; }
.quality-box.note.asked .body.ask p.quiet { font-weight: 400; }

/* The BibTeX entry, which is a thing to take away rather than to read. Set in
   the monospace the rest of the code here uses, and allowed to scroll on its
   own so a long title cannot push the page sideways. */
.bibtex pre {
  margin: 0.4rem 0 0;
  padding: 0.7rem 0.9rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 0.25rem;
  overflow-x: auto;
  font-size: 0.85rem;
  line-height: 1.5;
}
.bibtex code { white-space: pre; }

/* The ways in, as cards rather than as one long list. Each is a question
   somebody arrives with — which venue, which subject, whose work — and a page
   that answered all of them at once was the pile a way in exists to avoid. */
.ways {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 0.8rem;
  margin: 1.2rem 0;
}
.way {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  text-decoration: none;
  color: var(--fg);
  border: 1px solid var(--line);
}
.way:hover { border-color: var(--accent); }
.way b { font-size: 1.05rem; }

/* What changed since a record was signed. Read before a signature is
   restated, so the two kinds of line have to be told apart at a glance. */
.diff {
  margin: 1rem 0;
  padding: 0.8rem 1rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 0.25rem;
  overflow-x: auto;
  font-size: 0.85rem;
  line-height: 1.5;
}
.diff span { display: block; white-space: pre; }
.diff .add { color: #0b6b3a; }
.diff .del { color: #a11; }
.diff .hunk { color: var(--quiet); }
@media (prefers-color-scheme: dark) {
  .diff .add { color: #7fd6a4; }
  .diff .del { color: #ff9b93; }
}
/* The record as it stands, under whatever changed about it. Long, and meant
   to be: it is the thing a signature is over. */
.diff.signing { max-height: 32rem; overflow-y: auto; }
.diff.signing span { color: var(--fg); }


/* The way to the public site, in the header before whoever is signed in.
   A person approving records is deciding what a reader will see, and until
   this was here the only way to find out what that looked like was to publish
   it and go and look. */
.preview-link {
  margin-left: auto;
  padding: 0.15rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.85rem;
  text-decoration: none;
  color: var(--fg);
}
.preview-link:hover { border-color: var(--accent); }
/* When something is unsent, that notice has already taken the space on the
   right, so the button sits next to it rather than pushing it about. */
.unsent + .preview-link { margin-left: 0.5rem; }
.preview-link + .who { margin-left: 0.5rem; }

/* Over the previewed site: what is live, what is not, and the one button that
   changes it. Fixed, because the page under it is a whole site to scroll
   through and the state of it should not scroll away. */
.preview-bar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  align-items: center;
  padding: 0.5rem 1.5rem;
  background: var(--accent);
  color: #fff;
  font-size: 0.85rem;
}
.preview-bar a { color: #fff; }
.preview-bar .quiet { color: rgba(255, 255, 255, 0.8); }
.preview-bar .right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.8rem;
}
.preview-bar form { margin: 0; }
.preview-bar button {
  padding: 0.15rem 0.8rem;
  border: 1px solid #fff;
  border-radius: 999px;
  background: transparent;
  color: #fff;
  font: inherit;
  cursor: pointer;
}
.preview-bar button:hover { background: #fff; color: var(--accent); }


/* The AI badge's explanation.
 *
 * The badge the stylesheet draws is a pseudo-element and cannot be hovered, so
 * this sits on top of it and carries the words — which matters more here than
 * anywhere else, because a reader will otherwise take "machine generated" to be
 * about the paper rather than about the catalogue entry describing it.
 *
 * A button rather than a `title`: a title reaches a mouse and nothing else. On
 * a phone there is no hover, and the ring alone does not say what it means to
 * somebody meeting it for the first time, so the thing that explains it has to
 * be tappable — and a button is what a browser already knows how to tap, focus
 * and read out. */
.quality-box .ai-what {
  position: absolute;
  top: -12px;
  left: -12px;
  width: 22px;
  height: 22px;
  z-index: 4;
  cursor: help;
  padding: 0;
  border: 0;
  background: transparent;
  /* The badge is drawn underneath; this is only the target over it. */
  font-size: 0;
  border-radius: 50%;
}
.quality-box .ai-what:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* What it says, on hover, on focus, and while it is being tapped. Kept in the
   document rather than in a `title` so a screen reader reaches it through
   `aria-describedby` whatever the pointer is. */
.quality-box .ai-note {
  position: absolute;
  top: 16px;
  left: -12px;
  z-index: 5;
  width: max-content;
  max-width: min(34rem, calc(100vw - 3rem));
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 0.25rem;
  background: var(--card);
  color: var(--fg);
  box-shadow: 0 2px 10px rgb(0 0 0 / 12%);
  font-size: 0.85rem;
  line-height: 1.45;
  text-align: left;
  /* Hidden without being taken out of the accessibility tree. */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease;
}
.quality-box .ai-what:hover + .ai-note,
.quality-box .ai-what:focus + .ai-note,
.quality-box .ai-note:hover {
  opacity: 1;
  visibility: visible;
}
@media (prefers-reduced-motion: reduce) {
  .quality-box .ai-note { transition: none; }
}

/* Room to breathe on a record's own page, where the box holds a title, a table
   of facts and an abstract rather than two lines of card. */
.quality-box.record {
  background: var(--card);
  border-radius: 0.25rem;
  padding: 1.6rem 1.8rem;
}
.quality-box.record h1 { margin: 0 0 1rem; }
.quality-box.record table { margin-bottom: 0.5rem; }

/* What the public site needs on top of the review app's stylesheet.
 *
 * The app is the renderer for both, so everything about how a record looks —
 * the rings, the AI badge, the cards, the chips, the tables — is already
 * defined over there and is deliberately not repeated here. What differs is
 * the frame: this has a navigation bar and a licence footer where the app has
 * tabs and a queue count. */

.site-nav {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  padding: 0.8rem 1.5rem;
  border-bottom: 1px solid var(--line);
  background: var(--card);
}
.site-nav a {
  text-decoration: none;
  font-weight: 600;
  color: var(--fg);
}
.site-nav a:hover { color: var(--accent); }
/* The way home, on the right and sized to the bar: it is a way back, not a
   heading. */
.site-nav .mark { margin-left: auto; display: flex; }
.site-nav .mark img { height: 26px; width: auto; display: block; }

/* The years the listing is divided by. Quieter than a heading that announces
   something: it divides, and the cards under it are what is being read. */
h2.year {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--quiet);
  margin: 1.8rem 0 0.4rem;
  border: 0;
}

/* One set to a box, on the pages that list them. */
.card.set { margin: 0.8rem 0; border: 1px solid var(--line); }
.card.set p { margin: 0.4rem 0 0; }
/* A proceedings inside a venue is a smaller thing, not a thing in a frame in a
   frame: set in from its parent and drawn more quietly. */
.card.set.inside { background: transparent; border-style: dashed; }

.chips { line-height: 2.2; }

/* Hidden by the filter box rather than removed, so typing backwards brings
   everything back without asking anybody for anything. */
.found.hidden { display: none; }
h2.year.hidden { display: none; }

/* Where this record lives, and the promise that it goes on living there.
   No rule above it: the box it follows is already a separation, and a line
   under a box draws a second edge on something that has one. */
.stable {
  margin-top: 1.2rem;
  font-size: 0.9rem;
  color: var(--quiet);
}

footer {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  margin: 3rem 0 0;
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
  color: var(--quiet);
}
footer a { color: inherit; }
