/* PaperSleuth BD — design system.
   Plain CSS on purpose: no Vite build step, so a deploy is "upload the files".
   Tokens mirror the approved mockup. Light only. */

/* Palette taken from the logo, not approximated from it: the navy, the green
   and the tagline grey are the median ink values sampled out of the artwork
   (#012046, #389351, #656B74). The old #012046/#389351 pair sat next to the
   mark and read as a near-miss, which is worse than no relationship at all.
   The ramps either side of those two are derived from them. */
:root{
  --navy-900:#012046; --navy-800:#062B54; --navy-700:#0C3A6B; --navy-500:#2A5C93;
  --green:#389351; --green-dk:#2B7440;
  --ground:#F2F5F9; --surface:#FFFFFF; --surface-2:#F9FBFD;
  --ink:#012046; --ink-2:#2F4159; --muted:#5C6B7E; --faint:#8794A5;
  --line:#DCE3EC; --line-2:#EAEEF4;
  --crit:#B8362B; --warn:#A9721A; --ok:#389351; --info:#2A5C93;
  --crit-bg:#FAEDEB; --warn-bg:#FAF3E6; --ok-bg:#EAF4EC; --info-bg:#EAF0F7;
  --shadow:0 1px 2px rgba(1,32,70,.06), 0 8px 24px -12px rgba(1,32,70,.18);
  --sans:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --serif:Georgia,"Iowan Old Style","Times New Roman",serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;
  color-scheme:light;

  /* Motion. Three durations and two curves, so nothing is timed by eye.
     The site is a correspondence section about research integrity, not a
     product tour: movement should read as paper settling, not as an effect.
     Anything longer than ~300ms starts to feel like waiting. */
  --dur-press:90ms;    /* the button goes down under the finger */
  --dur-state:170ms;   /* hover, tint, border — the common case */
  --dur-enter:260ms;   /* something arriving that was not there before */
  --ease:cubic-bezier(.4,0,.2,1);        /* standard, symmetric */
  --ease-out:cubic-bezier(.16,1,.3,1);   /* decelerating, for entrances */
}

*{box-sizing:border-box}
body{margin:0;background:var(--ground);color:var(--ink);font-family:var(--sans);
     font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased}
h1,h2,h3{text-wrap:balance;margin:0}
/* The hidden attribute must win.
   Any rule setting an explicit display — .field{display:grid}, .cbar{display:flex} —
   beats the UA stylesheet's [hidden]{display:none}, because author CSS outranks
   it. Progressive enhancement here relies on `hidden` actually hiding: the
   toolbar, preview pane and no-JS fallbacks all start hidden and are revealed
   by app.js. Without this the fallback and the enhanced control both render. */
[hidden]{display:none!important}

a{color:var(--navy-500);text-decoration:none}
a:hover{text-decoration:underline}
:focus-visible{outline:2px solid var(--green);outline-offset:2px;border-radius:4px}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
/* Full width, with gutters so nothing touches the viewport edge. The old
   1100px cap left most of a desktop screen empty — the search results,
   institution tables and moderation queue all have more to show than that. */
.wrap{width:100%;margin:0 auto;padding:0 32px}

/* Reading pages get a measure; data pages keep the width.
   Full width ran the comment column to 210 characters a line against a
   comfortable 65-75. 68rem brought that to 91, which reads well but left the
   thread looking marooned on a wide screen. 80rem is the middle: around 124
   characters — longer than ideal prose, but this is a technical thread with
   figures in it, and the card no longer floats in empty space.
   Tables, result lists and the admin queue keep the full width. */
.wrap-read{max-width:80rem;margin-inline:auto}
/* Between the two: the home list is a single centred column of entries, which
   wants a measure but not the full prose one — there is no thread beside it. */
.wrap-mid{max-width:58rem;margin-inline:auto}
@media (max-width:820px){.wrap{padding:0 18px}}

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

/* ---------- header ----------
   The masthead of a correspondence section: white, a hairline under it, and
   the logo carrying the name. Nothing else in the bar competes. */
.site-nav{background:var(--surface);border-bottom:1px solid var(--line)}
/* padding-block, not shorthand: these sit on .wrap, and `padding:12px 0`
   overwrites the container's horizontal gutter and pins the logo to the
   viewport edge. Invisible while .wrap was a centred 1100px column. */
.site-nav .inner{display:flex;align-items:center;gap:22px;padding-block:13px}
/* The supplied lockup, at its own proportions. Set as an image rather than
   rebuilt in HTML type: the wordmark is a geometric sans that nothing in the
   font stack matches, and a near-miss beside the real mark reads worse than
   the mark alone. Height-constrained so it stays crisp on any display. */
.brand{display:flex;align-items:center;flex:none}
.brand:hover{text-decoration:none}
.brand img{display:block;height:30px;width:auto}
@media (max-width:520px){.brand img{height:26px}}
.nav-links{display:flex;gap:19px;font-size:13px;color:var(--muted)}
.nav-links a{color:var(--muted)}
/* The logo's green is the magnifier — the act of looking. It marks where you
   are looking now, and elsewhere what has already been looked at: a verified
   author's reply, a paper carrying no notice, new activity this week. Keeping
   it to that one meaning is what stops it becoming decoration. */
.nav-links a[aria-current]{color:var(--ink);font-weight:650;
  box-shadow:inset 0 -2px 0 var(--green)}
.nav-sp{flex:1}

/* ---- search in the bar ----------------------------------------------------
   Until now the only way to look something up was the home page, so a reader
   holding a second DOI on a paper page had to navigate away first. Shares the
   .hero-search chrome at a smaller scale, and shares its typeahead.
   flex:1 with a min-width, not a fixed size: this row also carries a pseudonym
   of unknown length plus up to three buttons once signed in. */
.nav-search{flex:1 1 200px;max-width:340px;min-width:150px;margin-left:6px}
.nav-search input{padding:6px 11px;font-size:13px}
.nav-search button{padding:0 15px;font-size:12px}
.nav-toggle{display:none;background:none;border:1px solid var(--line);border-radius:7px;
            padding:6px 9px;cursor:pointer;color:var(--ink-2);font-size:15px;line-height:1}

/* The bug the audited site never fixed: below 820px the nav collapses
   behind a toggle instead of overflowing the viewport. */
@media (max-width:820px){
  /* No `order` here: the toggle must stay on the first line beside the brand.
     margin-left:auto pushes it right; the wrapped 100%-width panels fall below. */
  .nav-toggle{display:block;margin-left:auto}
  .site-nav .inner{flex-wrap:wrap}
  .nav-links,.nav-actions{display:none;width:100%;flex-direction:column;
                          align-items:flex-start;gap:4px;
                          padding:10px 0;border-top:1px solid var(--line-2)}
  .site-nav.open .nav-links,.site-nav.open .nav-actions{display:flex}
  .site-nav.open .nav-actions{border-top:0;padding-top:0}
  .nav-links a{padding:7px 0}
  .nav-sp{display:none}
  /* Search stays out of the collapsed menu. It is the reason the bar carries
     one at all, and burying it behind a toggle would undo that. */
  .nav-search{width:100%;max-width:none;margin:9px 0 3px}
}

/* Pill controls throughout. A correspondence page is set in curves and
   measures, not in the square chrome of an admin tool. */
.btn{display:inline-block;font-size:13px;font-weight:600;padding:7px 15px;border-radius:20px;
     border:1px solid var(--line);background:var(--surface);color:var(--ink-2);cursor:pointer;
     font-family:inherit;white-space:nowrap}
.btn:hover{text-decoration:none;border-color:var(--navy-900);color:var(--ink)}
.btn-primary{background:var(--navy-900);border-color:var(--navy-900);color:#fff}
.btn-primary:hover{background:var(--navy-700);border-color:var(--navy-700);color:#fff}
.btn-navy{background:var(--navy-900);border-color:var(--navy-900);color:#fff}
.btn-navy:hover{background:var(--navy-700);border-color:var(--navy-700);color:#fff}
.btn-ghost{border-color:transparent;color:var(--muted)}
.nav-actions{display:flex;gap:8px;align-items:center}

/* ---------- hero -----------------------------------------------------------
   Centred, the way a journal opens an issue. The masked grid, the green glow
   and the drop-shadowed evidence card all argued that this is a product; what
   the site actually offers is a place where concerns get written down and
   answered, so the page opens with the statement and the box you search it
   with, and nothing else. */
.hero{background:var(--surface);border-bottom:1px solid var(--line)}
.hero-in{display:block;padding-block:46px 36px;text-align:center}

.eyebrow{display:inline-flex;align-items:center;gap:8px;font-size:10.5px;font-weight:700;
  letter-spacing:.15em;text-transform:uppercase;color:var(--green-dk)}
.eyebrow i{width:5px;height:5px;border-radius:50%;background:var(--green);display:block}

.hero h1{font-family:var(--serif);color:var(--navy-900);
  font-size:clamp(28px,4vw,38px);line-height:1.16;letter-spacing:-.024em;
  margin:15px auto 0;font-weight:400;max-width:17ch}
.hero h1 span{font-style:italic}
.hero .sub{color:var(--muted);font-size:14.5px;margin:14px auto 0;max-width:54ch;line-height:1.62}
.hero .sub b{color:var(--ink);font-weight:700;font-variant-numeric:tabular-nums}

/* A slot, set as one rounded field with the control inside it.
   Shared by the hero box and the one in the bar, so the two are recognisably
   the same control at two sizes. Only measure and scale differ. */
.hero-search,.nav-search{display:flex;background:var(--ground);
  border-radius:26px;border:1px solid var(--line);padding:4px 4px 4px 6px;
  position:relative}
.hero-search{margin:24px auto 0;max-width:580px}
.hero-search input,.nav-search input{flex:1;border:0;padding:9px 13px;font-size:13.5px;
  font-family:inherit;color:var(--ink);min-width:0;background:transparent}
.hero-search input:focus,.nav-search input:focus{outline:none}
.hero-search:focus-within,.nav-search:focus-within{border-color:var(--navy-500);background:var(--surface)}
.hero-search button,.nav-search button{border:0;background:var(--navy-900);color:#fff;
  padding:0 21px;border-radius:22px;font-size:12.5px;font-weight:650;cursor:pointer;
  font-family:inherit}
.hero-search button:hover,.nav-search button:hover{background:var(--navy-700)}
/* Copyable specimens, set in the face the identifiers themselves are set in. */
.examples{display:flex;gap:18px;margin-top:13px;flex-wrap:wrap;justify-content:center;
  font-family:var(--mono);font-size:11px;color:var(--faint)}
.examples b{color:var(--muted);font-weight:600}

/* ---- search typeahead -----------------------------------------------------
   Hangs under the field rather than growing it, so the page behind does not
   reflow as rows arrive. Rows are entries in the same register as the record
   cards: title in the reading face, everything a machine cares about beneath.

   position:relative goes on the form because the panel must be measured from
   the field, and the form is the only element that wraps both. */
/* The panel matches its field, except in the bar — a 275px field makes every
   title wrap to two lines and truncates the byline to nothing. There it is
   allowed to grow past its anchor, bounded by the viewport. */
.nav-search .suggest{min-width:min(430px, calc(100vw - 36px))}
.suggest{
  position:absolute;left:0;right:0;top:calc(100% + 7px);z-index:40;
  background:var(--surface);border:1px solid var(--line);border-radius:6px;
  box-shadow:0 2px 4px rgba(1,32,70,.05),0 18px 40px -20px rgba(1,32,70,.4);
  max-height:min(60vh,420px);overflow-y:auto;overscroll-behavior:contain;
  text-align:left}
.suggest ul{list-style:none;margin:0;padding:4px}
.suggest-row{
  display:grid;gap:3px;padding:10px 12px;border-radius:4px;cursor:pointer;
  scroll-margin:4px}
.suggest-row.is-on{background:var(--ground)}
.suggest-title{
  font-family:var(--serif);font-size:14.5px;line-height:1.35;color:var(--ink);
  letter-spacing:-.008em}
.suggest-meta{font-size:12px;color:var(--muted);line-height:1.45;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.suggest-foot{display:flex;align-items:center;gap:11px;flex-wrap:wrap;
  font-size:11px;color:var(--muted);margin-top:2px}
.suggest-id{font-family:var(--mono);font-size:10.5px;color:var(--faint);
  overflow-wrap:anywhere}
/* The one row that is not a paper we hold: pasting an identifier we have is a
   match, pasting one we do not is an offer to go and get it. */
.suggest-tag{
  font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;font-weight:700;
  color:var(--green-dk)}

/* ---- holdings ----
   What the index contains. Four numbers on one line under the search box, in
   the same face the record titles use, because they are a fact about the
   corpus rather than a dashboard readout. */
.holdings{display:flex;justify-content:center;gap:clamp(22px,5vw,52px);
  flex-wrap:wrap;margin-top:30px}
.holdings h2{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}
.holdings ul{list-style:none;margin:0;padding:0;display:contents}
.holdings li{display:grid;gap:1px;text-align:center}
.holdings li span{font-size:10.5px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--faint);font-weight:700;order:2}
.holdings b{font-family:var(--serif);font-size:24px;color:var(--ink);letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;font-weight:400;order:1;line-height:1.2}
.holdings .is-flagged b{color:var(--warn)}
.holdings .is-retracted b{color:var(--crit)}

/* ---------- content ---------- */
.main{padding:30px 0 56px}
.cols{display:grid;grid-template-columns:minmax(0,1fr) clamp(250px,20vw,340px);
      gap:26px;align-items:start}
@media (max-width:820px){.cols{grid-template-columns:1fr}}
/* Page head on the listing pages: the statement, then what the page holds,
   with one rule closing the head off from the list. */
.idx-head{padding-bottom:22px;border-bottom:2px solid var(--navy-900);margin-bottom:26px}
.idx-title{font-family:var(--serif);font-size:clamp(24px,2.8vw,30px);font-weight:400;
  letter-spacing:-.022em;color:var(--navy-900);margin:0}
.idx-lede{margin:11px 0 0;font-size:14px;line-height:1.65;color:var(--muted);max-width:64ch}
.idx-head .holdings{justify-content:flex-start;margin-top:22px;
  gap:clamp(20px,4vw,42px)}
.idx-head .holdings li{text-align:left}
.idx-head .holdings b{font-size:21px}

/* A quiet standfirst above a list, not a bar across it. */
.section-label{font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);
  font-weight:700;margin:0 0 15px;display:flex;align-items:center;gap:10px}
.section-label .rule{flex:1}
/* On the home page there is one list and it is the page, so its label is
   centred over it like a section head in print. */
.is-centred .section-label{justify-content:center;text-align:center}

/* ---- records --------------------------------------------------------------
   Entries, set the way a contents page sets them: the title in the reading
   face at reading size, the byline under it, and everything a machine cares
   about — identifier, status, counts — held below a hairline where it does not
   compete with the title. */
.reclist{list-style:none;padding:0;margin:0;display:grid;gap:11px}
.rec{background:var(--surface);border:1px solid var(--line);border-radius:4px;
  padding:17px 20px}
.rec:hover{border-color:var(--green)}
.rec-title{font-family:var(--serif);font-size:18px;line-height:1.32;color:var(--ink);
  font-weight:400;letter-spacing:-.012em;display:block}
.rec-title:hover{color:var(--navy-700)}
.rec-authors{margin:6px 0 0;font-size:12.5px;color:var(--muted);line-height:1.55}
.rec-foot{margin:11px 0 0;padding-top:10px;border-top:1px solid var(--line-2);
  display:flex;align-items:center;gap:15px;flex-wrap:wrap;
  font-size:11.5px;color:var(--muted)}
.rec-foot .doi{font-family:var(--mono);font-size:11px;color:var(--faint)}
.rec-foot .count{font-variant-numeric:tabular-nums}

/* Status as a word, in the colour the journal's action deserves. A filled pill
   on every row makes an index of mostly-fine papers look like a charge sheet. */
.mark{white-space:nowrap;font-size:10px;letter-spacing:.09em;
  text-transform:uppercase;font-weight:700}
.mark-none{color:var(--green-dk)}
.mark-retracted,.mark-withdrawn{color:var(--crit)}
.mark-expression_of_concern{color:var(--warn)}
.mark-correction,.mark-erratum{color:var(--info)}
.mark-new_version{color:var(--muted)}

.paper-meta{font-size:12.5px;color:var(--muted)}
.paper-meta .doi{font-family:var(--mono);font-size:11.5px}

.pill{font-size:10.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:3px 8px;border-radius:5px;white-space:nowrap;display:inline-block}
.pill-retracted{background:var(--crit-bg);color:var(--crit)}
.pill-expression_of_concern{background:var(--warn-bg);color:var(--warn)}
.pill-correction{background:var(--info-bg);color:var(--info)}
.pill-none{background:var(--ground);color:var(--muted);border:1px solid var(--line)}
.pill-ok{background:var(--ok-bg);color:var(--green-dk)}
.pill-warn{background:var(--warn-bg);color:var(--warn)}

/* v2 widened papers.status from four values to seven. These are the three new
   ones — without them a withdrawn paper renders an unstyled badge. Withdrawn
   reads as serious as a retraction but is a different claim; erratum and new
   version are informational. */
.pill-withdrawn{background:var(--crit-bg);color:var(--crit)}
.pill-erratum{background:var(--info-bg);color:var(--info)}
.pill-new_version{background:var(--ground);color:var(--muted);border:1px solid var(--line)}

/* Bare .pill with no modifier (the Anonymous marker on the users page). */
.pill:not([class*=" pill-"]){background:var(--ground);color:var(--muted);border:1px solid var(--line)}

/* Ruled sections need room between them; the 10px that separated bordered
   boxes puts the next heading directly under the previous section's last row
   and the two read as one list. */
.side{display:grid;gap:24px;align-content:start}

/* ---- sidebar sections on catalogue pages ----------------------------------
   Not boxes. On a page whose whole argument is hairlines and no cards, three
   filled panels down the right edge are the loudest thing on it. Same content,
   same order, stated as ruled sections. */
/* align-content:start, or a section that shares a grid row with a taller one
   stretches and the free space is dealt out between its heading and its body —
   Affiliations sat 40px below its own rule beside a longer fact list. */
.side-sec{display:grid;gap:9px;align-content:start}
.side-sec>h2{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--faint);
  font-weight:700;margin:0;padding-bottom:7px;border-bottom:1px solid var(--line)}
.side-sec p{font-size:12.5px;color:var(--muted);margin:0;line-height:1.65}
.side-sec .stack{background:none;border:0;border-radius:0;padding:0;gap:10px}

/* Record details beside a thread: label/value pairs that stay readable in a
   narrow rail. */
.factlist{margin:0;display:grid;grid-template-columns:auto 1fr;gap:4px 10px;font-size:12.5px}
.factlist dt{color:var(--faint);white-space:nowrap}
.factlist dd{margin:0;color:var(--ink-2);overflow-wrap:anywhere}
.linklist{margin:0;padding:0;list-style:none;display:grid;gap:5px;font-size:12.5px}
.linklist a{overflow-wrap:anywhere}
.rank{display:grid;gap:9px;list-style:none;padding:0;margin:0}
.rank .r{display:flex;justify-content:space-between;gap:10px;font-size:12.5px;color:var(--ink-2)}
.rank b{font-variant-numeric:tabular-nums;color:var(--ink);font-weight:700}
.meter{height:3px;border-radius:2px;background:var(--line-2);overflow:hidden;margin-top:5px}
.meter i{display:block;height:100%;background:var(--navy-500);opacity:.55;border-radius:2px}

.empty{border:1px dashed var(--line);border-radius:6px;padding:26px;text-align:center;
  color:var(--muted);font-size:14px;background:var(--surface-2)}

/* ---------- footer ----------
   A plinth in the brand navy. The page ends on something solid instead of
   trailing off into the ground colour, and the space earns its keep: three
   links over a copyright line became the site's second navigation.

   Crediting Crossref, PubMed and arXiv is the substantive part. Every record
   here is fetched from them and nothing outside the About page said so. */
.site-foot{background:var(--navy-900);color:#C7D6E8;padding:36px 0 28px;font-size:12.5px}
/* Capped, unlike the data pages above it. Four columns dealt across 1500px
   leaves the first one's 34ch of prose marooned beside 200px of nothing. */
.site-foot .wrap{max-width:78rem;margin-inline:auto}
.foot-cols{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:34px}
@media (max-width:860px){.foot-cols{grid-template-columns:1fr 1fr;gap:26px}}
@media (max-width:560px){.foot-cols{grid-template-columns:1fr;gap:24px}}
.site-foot h2{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:#6F8CB0;
  font-weight:700;margin:0 0 11px}
.site-foot ul{list-style:none;margin:0;padding:0}
.site-foot li{margin:6px 0}
.site-foot a{color:#C7D6E8}
.site-foot a:hover{color:#fff}
.foot-about p{margin:0;line-height:1.6;color:#93AAC7;max-width:34ch}
/* The mark is navy line-work on opaque white, so it cannot be laid straight on
   the plinth and inverting it mechanically destroys the eye — white is a
   positive colour in this mark, not the ground. A white chip is the honest
   fallback until a dark-surface variant is drawn from vector source. */
.foot-mark{display:block;width:46px;height:46px;border-radius:10px;margin:0 0 13px}
.foot-src{font-family:var(--mono);font-size:11.5px}
.foot-note{margin:8px 0 0;font-size:11.5px;color:#7E9AC0}
.foot-base{display:flex;gap:18px;flex-wrap:wrap;align-items:baseline;
  margin-top:28px;padding-top:18px;border-top:1px solid var(--navy-700);
  font-size:11.5px;color:#7E9AC0}
.foot-base p{margin:0;max-width:78ch;line-height:1.6}
.foot-base .sp{flex:1}

/* ======================= forms =======================
   One centred column. Spanning the page was a relic of the layout going
   edge-to-edge — capping the controls at 920px and letting everything else run
   full width left a two-field sign-in form you had to read across a metre of
   screen, with its heading a metre away from it. Signing in is a single task
   with a single focus, so it gets a measure and sits in the middle. */
.authwrap{max-width:27rem;margin-inline:auto}
/* The fork and the wizard carry a step bar, a publication and a list of
   authors; they need room the login page does not. */
.authwrap.is-wide{max-width:37rem}
.auth-head{text-align:center;margin-bottom:24px}
.auth-h{font-family:var(--serif);font-size:clamp(24px,3vw,29px);font-weight:400;
  letter-spacing:-.024em;color:var(--navy-900);margin:0 0 8px}
.auth-sub{color:var(--muted);font-size:13.5px;margin:0;line-height:1.62;
  max-width:44ch;margin-inline:auto}
.auth-alt{margin-top:20px;font-size:13px;color:var(--muted);text-align:center;line-height:1.6}

.stack{display:grid;gap:14px;background:var(--surface);border:1px solid var(--line);
       border-radius:4px;padding:20px}
/* A form's own submit fills the card — there is one thing to do on it. Buttons
   paired in a .composer-row (Back / Continue) keep their natural width. */
.authwrap .stack>.btn{width:100%;text-align:center;padding-block:10px}

/* Two credentials, one card: an email account and an anonymous access code
   sign in at the same door. */
.authcard{background:var(--surface);border:1px solid var(--line);border-radius:4px;
  padding:20px;display:grid;gap:4px}
.authcard .stack{background:none;border:0;border-radius:0;padding:0}
.authcard .stack>.btn{width:100%;text-align:center;padding-block:10px}
.field{display:grid;gap:5px}
.field>span{font-size:12.5px;font-weight:650;color:var(--ink-2)}
.field input,.field textarea,.field select{border:1px solid var(--line);border-radius:7px;
  padding:9px 11px;font-size:14px;font-family:inherit;color:var(--ink);background:var(--surface);
  width:100%}
.field input:focus,.field textarea:focus{outline:2px solid var(--green);outline-offset:1px;
  border-color:var(--green)}
.field small{font-size:11.5px;color:var(--faint)}
.check{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink-2)}
.check input{width:16px;height:16px}
.form-errors{background:var(--crit-bg);border:1px solid rgba(184,54,43,.3);border-radius:4px;
  padding:11px 14px;margin-bottom:16px;color:var(--crit);font-size:13px}
.form-errors ul{margin:0;padding-left:18px}

/* ======================= tables ======================= */
.tablewrap{overflow-x:auto;border:1px solid var(--line);border-radius:6px;background:var(--surface)}
table.data{width:100%;border-collapse:collapse;font-size:13px;min-width:640px}
/* The hard rule under the head is the same device the section labels and the
   masthead use, so a table reads as one more ruled section. */
table.data th{text-align:left;font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint);font-weight:700;padding:10px 12px;border-bottom:1px solid var(--navy-900);
  background:var(--surface);white-space:nowrap}
table.data td{padding:12px;border-bottom:1px solid var(--line-2);color:var(--ink-2);
  vertical-align:top}
table.data tr:last-child td{border-bottom:0}
table.data .num{font-variant-numeric:tabular-nums;font-family:var(--mono);font-size:11.5px;
  color:var(--muted);white-space:nowrap}
/* A bar in a table cell stretches to the column, which on a wide screen turns
   a 22-of-58 reading into a rule running most of the page. */
table.data .meter{max-width:120px}

/* --- users & roles ------------------------------------------------------ */
/* Fixed layout with declared widths, rather than letting the auto layout
   distribute the slack. With width:100% and no widths the name column takes
   everything left over, which on a wide screen put ~850px of nothing between
   an address and the control that acts on it. Fixed also means a long email
   cannot widen a column — it wraps, via overflow-wrap below. */
.data-users{table-layout:fixed}
/* The three control columns are only as wide as a select and a button need to
   be; the slack goes to the text column, where it buys a longer paper title
   instead of an empty right margin. */
.data-users .c-member{width:57%}
.data-users .c-activity{width:17%}
.data-users .c-role{width:13%}
.data-users .c-actions{width:13%}

.data-users .u-name{display:flex;align-items:center;gap:7px;flex-wrap:wrap;line-height:1.3}
.data-users .u-name b{color:var(--ink);font-size:13.5px}
.data-users .u-claim{font-size:12px;color:var(--warn);line-height:1.45;margin-top:4px}
.data-users .u-id{font-size:12px;color:var(--muted);margin-top:4px;
  /* Addresses are long and unbreakable; without this one QA fixture widened
     the whole table and brought back the horizontal scrollbar. */
  overflow-wrap:anywhere}

.data-users .u-activity{font-size:12px;color:var(--muted);white-space:nowrap}
.data-users .u-count{font-family:var(--mono);font-variant-numeric:tabular-nums;
  font-size:14px;font-weight:700;color:var(--ink)}
.data-users .u-sub{font-family:var(--mono);font-size:11px;color:var(--faint);margin-top:3px}

/* Sized to their own text, not stretched to the column: a button as wide as
   its cell reads as a banner, and three of them down a page pull the eye away
   from the names they belong to. */
.data-users .u-actions{display:flex;flex-direction:column;align-items:flex-start;gap:6px}
.data-users .u-noaction{font-size:11.5px;color:var(--faint);font-style:italic}

@media (max-width:900px){
  /* Below this the four columns cannot hold their content without the wrap
     scrolling, and a scrolling table hides the actions on the right. */
  .data-users .c-activity{width:auto}
  .data-users .u-activity{white-space:normal}
}

/* ======================= pagination ======================= */
.pager{display:flex;align-items:center;justify-content:space-between;gap:14px;
  flex-wrap:wrap;margin-top:18px}
.pager-list{display:flex;align-items:center;gap:5px;flex-wrap:wrap;
  list-style:none;margin:0;padding:0}
.pager-link{display:inline-flex;align-items:center;justify-content:center;
  min-width:32px;min-height:32px;padding:0 10px;font-size:12.5px;font-weight:650;
  border:1px solid var(--line);border-radius:5px;background:var(--surface);
  color:var(--ink-2);text-decoration:none;white-space:nowrap}
a.pager-link:hover{border-color:var(--navy-500);color:var(--ink)}
.pager-link.is-on{background:var(--navy-900);border-color:var(--navy-900);color:#fff}
/* Present but not offered: the ends of the range keep their place so the row
   does not shift width as you page through it. */
.pager-link.is-off{color:var(--faint);background:var(--surface-2)}
.pager-gap{padding:0 3px;color:var(--faint);font-size:12.5px}
.pager-count{font-family:var(--mono);font-size:11.5px;color:var(--muted);margin:0;
  font-variant-numeric:tabular-nums}
.t-serif{font-family:var(--serif);font-size:14px;font-weight:600;color:var(--ink);line-height:1.35}
.excerpt{font-size:12px;color:var(--muted);margin-top:4px;line-height:1.45}
.reason{font-size:12px;color:var(--warn);margin-top:5px;padding:6px 9px;background:var(--warn-bg);
  border-radius:6px}
.reason b{color:var(--warn)}

/* ======================= kpis ======================= */
/* auto-fit, not a fixed four: a fifth tile was added and the row wrapped 4+1. */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:11px;margin-top:16px}
@media (max-width:760px){.kpis{grid-template-columns:repeat(2,1fr)}}
.kpi{border:1px solid var(--line);border-radius:6px;padding:12px 14px;background:var(--surface)}
.kpi span{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--faint);
  font-weight:650}
.kpi b{display:block;font-size:24px;font-weight:700;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;line-height:1.2;margin-top:2px}
.kpi small{font-size:11.5px;color:var(--muted);display:block}
.spark{display:flex;align-items:flex-end;gap:2px;height:26px;margin-top:8px}
.spark i{flex:1;background:rgba(56,147,81,.34);border-radius:1px;display:block}
.spark i.last{background:var(--green)}
.acct-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;
  flex-wrap:wrap;margin-bottom:4px}

/* ======================= admin shell =======================
   Same palette, same mark, same headings as the public site — but denser, and
   deliberately so. The public pages are read; this one is operated, a screen at
   a time, on rows that need to fit. So it takes the design language and leaves
   the centred measures, the reading-size serif body and the pill controls
   behind: a queue of 19 comments each needing three decisions cannot afford
   them. The rail shares its navy with the site footer, which is the one place
   the two surfaces meet. */
.admin-body{background:var(--ground)}
.admin{display:grid;grid-template-columns:206px 1fr;min-height:100vh}
@media (max-width:820px){.admin{grid-template-columns:1fr}}
.rail{background:var(--navy-900);padding:16px 0;display:flex;flex-direction:column;gap:1px}
.rail-brand{display:flex;align-items:center;gap:10px;padding:0 16px 15px;
  font-family:var(--serif);font-size:15px;color:#fff;letter-spacing:-.012em}
.rail-brand:hover{text-decoration:none}
.rail-brand em{font-style:normal;color:#79C795}
/* On a chip, for the same reason the footer mark is: the artwork is navy
   line-work on opaque white and cannot sit directly on the navy. */
.rail-mark{width:26px;height:26px;border-radius:7px;flex:none;display:block}
.rail-hd{color:#6F8CB0;font-size:10px;letter-spacing:.13em;text-transform:uppercase;
  padding:15px 16px 6px;font-weight:700;margin:0}
.rl{color:#C7D6E8;font-size:13px;padding:9px 16px;display:flex;gap:9px;align-items:center}
.rl:hover{color:#fff;background:rgba(255,255,255,.06);text-decoration:none}
.rl.on{color:#fff;background:rgba(255,255,255,.09);box-shadow:inset 3px 0 0 var(--green);
  font-weight:650}
.rl-btn{background:none;border:0;width:100%;text-align:left;cursor:pointer;font-family:inherit}
.rail-badge{margin-left:auto;background:var(--crit);color:#fff;font-size:10px;padding:1px 7px;
  border-radius:100px;font-weight:700;font-variant-numeric:tabular-nums}
.rail-sp{flex:1;min-height:20px}
.rail-me{color:#C7D6E8;font-size:12px;padding:11px 16px 4px;margin:0;
  border-top:1px solid var(--navy-700)}
.rail-me span{color:#6F8CB0;font-size:11px}
.admin-main{padding:24px 28px 56px;min-width:0}
@media (max-width:620px){.admin-main{padding:18px 16px 40px}}
.admin-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;
  flex-wrap:wrap;margin-bottom:6px}
/* Georgia, like every other page heading on the site. */
.admin-head h1{font-family:var(--serif);font-size:23px;font-weight:400;letter-spacing:-.02em;
  color:var(--navy-900)}
.flash{background:var(--ok-bg);border:1px solid rgba(56,147,81,.3);color:var(--green-dk);
  border-radius:4px;padding:10px 14px;font-size:13px;margin:0 0 16px}
.flash-bad{background:var(--crit-bg);border-color:rgba(184,54,43,.3);color:var(--crit)}


/* ---- row-level moderation actions ---- */
.acts{display:flex;gap:6px;flex-wrap:wrap;align-items:flex-start}
.mini{font-size:11.5px;font-weight:650;padding:5px 10px;border-radius:5px;
  border:1px solid var(--line);color:var(--ink-2);background:var(--surface);cursor:pointer;
  font-family:inherit;white-space:nowrap;display:inline-flex;align-items:center;
  justify-content:center;min-height:28px}

/* These are the moderation controls — Approve, Send back, Confirm rejection.
   At 26px they cleared WCAG 2.5.8's 24px floor and nothing else, and on a
   phone a mis-tap here publishes or rejects an allegation about a named
   person. Given the consequence, they get a proper touch target on small
   screens rather than the minimum that technically passes. */
@media (max-width:820px){
  .mini{min-height:40px;padding:9px 14px;font-size:12.5px}
  .inline-form{display:inline-flex}
}
/* 22px failed the 24px minimum target size for every pointer type, not just
   touch. Touch gets the fuller target; mouse density stays close to before. */
@media (pointer:coarse){
  .mini{min-height:32px;padding:7px 12px}
  .acts{gap:8px}
}
.mini:hover{border-color:var(--navy-500);color:var(--ink)}
.mini.ok{background:var(--green);border-color:var(--green);color:#fff}
.mini.ok:hover{background:var(--green-dk);border-color:var(--green-dk);color:#fff}
.mini.no{border-color:rgba(184,54,43,.42);color:var(--crit)}
.mini.no:hover{background:var(--crit);border-color:var(--crit);color:#fff}
/* Reason is required, so it opens inline via <details> — no JS, no modal. */
.reason-pop{position:relative}
.reason-pop>summary{list-style:none;display:inline-block}
.reason-pop>summary::-webkit-details-marker{display:none}
.reason-pop[open]>summary{background:var(--ground)}
.reason-pop form{position:absolute;right:0;top:calc(100% + 6px);z-index:20;width:250px;
  background:var(--surface);border:1px solid var(--line);border-radius:6px;padding:10px;
  box-shadow:var(--shadow);display:grid;gap:8px}
.reason-pop textarea{width:100%;border:1px solid var(--line);border-radius:6px;padding:8px;
  font-family:inherit;font-size:12.5px;resize:vertical;color:var(--ink)}
.inline-form select{border:1px solid var(--line);border-radius:6px;padding:5px 8px;
  font-size:12.5px;font-family:inherit;color:var(--ink);background:var(--surface)}
/* The popover above is anchored right:0 because in the admin queue it hangs off
   the last column, where floating over a dense table is the point.
   In a comment thread it floated over the NEXT person's comment, so there it
   expands inline instead — same as the reply composer. */
.reason-pop.pop-left{position:static}
.reason-pop.pop-left[open]{flex:1 0 100%;order:8}
.reason-pop.pop-left form{position:static;width:100%;max-width:420px;
  box-shadow:none;margin-top:8px}
.reason-pop.pop-left select{max-width:320px}
.reason-pop form{max-width:calc(100vw - 32px)}
.reason-pop select{width:100%;border:1px solid var(--line);border-radius:6px;padding:6px 8px;
  font-size:12.5px;font-family:inherit;color:var(--ink);background:var(--surface)}
.reason-pop form .mini{width:100%;justify-content:center}

/* A reply is a full composer, not a reason box — it expands the card inline
   rather than floating in a 250px popover it cannot fit inside. */
.reply-inline{position:static}
/* Closed, it sits inline with Report/Permalink. Open, it moves to the end and
   claims a full row, so the composer never splits that button row in half. */
.reply-inline[open]{flex:1 0 100%;order:9}
.reply-inline>summary{list-style:none;display:inline-block}
.reply-inline>summary::-webkit-details-marker{display:none}
.reply-inline[open]>summary{background:var(--ground)}
.reply-inline .composer{margin-top:10px;position:static;width:auto}

/* ---- comment composer ----
   White, so writing looks like the published comments above it rather than
   like a form appended to them, and the textarea is set in the face the
   comment will actually be published in. */
.composer{border:1px solid var(--line);border-radius:4px;padding:15px;background:var(--surface);
  margin-top:22px;display:grid;gap:11px}
.composer textarea{border:1px solid var(--line);border-radius:4px;padding:13px;min-height:120px;
  font-family:var(--serif);font-size:15px;line-height:1.7;resize:vertical;color:var(--ink);
  background:var(--surface);width:100%}
.composer textarea:focus{outline:2px solid var(--green);outline-offset:1px;border-color:var(--green)}
.composer-row{display:flex;gap:12px;align-items:center;flex-wrap:wrap;font-size:12.5px;
  color:var(--muted)}
.composer-row .sp{flex:1}
.radio-set{display:flex;gap:14px;flex-wrap:wrap}
.radio-set label{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--ink-2)}

/* --- comment bodies (markdown) --------------------------------------------
   Comments were plain text until v2. These are the block elements CommonMark
   emits, styled to the existing tokens so a formatted comment reads as part of
   the page rather than as pasted-in documentation. */
.comment-body > *:first-child{margin-top:0}
.comment-body > *:last-child{margin-bottom:0}
.comment-body p{margin:0 0 10px}
.comment-body ul,.comment-body ol{margin:0 0 10px;padding-left:22px}
.comment-body li{margin:3px 0}
.comment-body blockquote{
  margin:10px 0;padding:2px 0 2px 12px;
  border-left:3px solid var(--line);color:var(--muted)}
.comment-body code{
  font-family:var(--mono);font-size:12.5px;
  background:var(--surface-2);border:1px solid var(--line-2);
  border-radius:4px;padding:1px 4px}
.comment-body pre{
  margin:10px 0;padding:10px 12px;overflow-x:auto;
  background:var(--surface-2);border:1px solid var(--line-2);border-radius:7px}
.comment-body pre code{background:none;border:0;padding:0}
.comment-body h1,.comment-body h2,.comment-body h3,
.comment-body h4,.comment-body h5,.comment-body h6{
  margin:14px 0 6px;font-size:14px;font-weight:650;color:var(--ink)}
.comment-body hr{border:0;border-top:1px solid var(--line);margin:14px 0}
.comment-body table{border-collapse:collapse;margin:10px 0;font-size:13px;display:block;overflow-x:auto}
.comment-body th,.comment-body td{border:1px solid var(--line);padding:5px 9px;text-align:left}

/* Figures inserted as Markdown. Without this they render at natural size and
   push the whole page sideways — a screenshot of a journal page is routinely
   2000px wide, and every figure here arrives that way. The old <figure> markup
   carried max-width inline; Markdown images inherit nothing, so it belongs
   here where both paths pick it up. */
/* Bounded twice over.
   max-width:100% alone means "as wide as the column", and once the layout went
   full width that was ~1450px — a figure filled the screen and pushed the rest
   of the thread out of view. A journal figure is legible around 700px, and the
   lightbox is what full size is for.
   The height cap stops a tall portrait figure doing the same vertically. */
.comment-body img{
  display:block;
  max-width:min(100%, 780px);
  max-height:70vh;
  width:auto;height:auto;
  margin:12px 0;border:1px solid var(--line);border-radius:7px;
  background:var(--surface);cursor:zoom-in}
.comment-body img:hover{border-color:var(--green)}
.comment-body p>img:only-child{margin:12px 0}

/* Anything that genuinely cannot shrink scrolls inside its own box rather than
   widening the page. */
.comment-body pre,.comment-body table{max-width:100%}
.comment-body{overflow-wrap:anywhere}

/* --- figure lightbox -------------------------------------------------------
   Image forensics is the dominant use of this site: a reader has to be able to
   see whether two panels are the same pixels. Opening the raw file in a new tab
   loses the comment around it, so figures zoom in place.

   Bound from app.js, never inline — the CSP (script-src 'self') silently
   refuses to compile on* handlers, which QaCspCompatibilityTest enforces. */
.lightbox{
  position:fixed;inset:0;z-index:100;display:none;
  align-items:center;justify-content:center;
  background:rgba(1,32,70,.86);padding:24px;
  overscroll-behavior:contain}
.lightbox[open],.lightbox.is-open{display:flex}
.lightbox img{
  max-width:100%;max-height:100%;
  border-radius:7px;box-shadow:0 24px 64px -24px rgba(0,0,0,.7);
  cursor:zoom-out}
.lightbox-close{
  position:absolute;top:14px;right:18px;
  width:38px;height:38px;border-radius:50%;
  border:1px solid rgba(255,255,255,.28);
  background:rgba(255,255,255,.10);color:#fff;
  font-size:20px;line-height:1;cursor:pointer}
.lightbox-close:hover{background:rgba(255,255,255,.2)}
.lightbox-cap{
  position:absolute;left:0;right:0;bottom:14px;
  text-align:center;color:rgba(255,255,255,.82);font-size:12.5px;padding:0 24px}
.zoomable{cursor:zoom-in}

/* --- registration fork -----------------------------------------------------
   Two tiers, picked before anything is typed. The difference between them is
   what the site holds about you, so the choice gets a screen of its own rather
   than a checkbox hidden inside one form. */
.reg-choice{display:grid;gap:11px;margin-top:4px}
/* Native <details>, so the accordion opens with JavaScript off. */
.reg-option{
  background:var(--surface);border:1px solid var(--line);border-radius:4px;
  overflow:hidden}
.reg-option[open]{border-color:var(--navy-500)}
.reg-option>summary{
  position:relative;display:grid;gap:5px;
  padding:15px 40px 15px 16px;cursor:pointer;list-style:none}
.reg-option>summary::-webkit-details-marker{display:none}
.reg-option>summary::after{
  content:"›";position:absolute;right:18px;top:50%;
  transform:translateY(-50%);font-size:22px;line-height:1;color:var(--faint)}
.reg-option[open]>summary::after{content:"⌄";top:44%}
.reg-option>summary:hover{background:var(--surface-2)}
.reg-option>summary:focus-visible{outline:2px solid var(--green);outline-offset:-2px}
.reg-option[open]>summary{border-bottom:1px solid var(--line-2)}
.reg-option-h{font-family:var(--serif);font-size:17px;font-weight:400;
  letter-spacing:-.01em;color:var(--navy-900)}
.reg-option-b{font-size:13px;line-height:1.58;color:var(--muted)}
.reg-option-in{padding:16px;display:grid;gap:13px}
.reg-option-in>p{margin:0;font-size:13px;line-height:1.62;color:var(--muted)}
/* Inside an option the card is already drawn by the accordion. */
.reg-option-in .stack{background:none;border:0;border-radius:0;padding:0}

/* Publication → Author → Email. */
.steps{
  display:flex;align-items:flex-start;gap:0;margin:0 0 18px;padding:0;
  list-style:none;counter-reset:none}
.step{flex:1;display:grid;justify-items:center;gap:6px;position:relative;text-align:center}
.step::before{
  content:"";position:absolute;top:15px;left:-50%;width:100%;height:2px;
  background:var(--line);z-index:0}
.step:first-child::before{display:none}
.step.is-done::before,.step.is-on::before{background:var(--green)}
.step-dot{
  position:relative;z-index:1;
  width:32px;height:32px;border-radius:50%;
  display:grid;place-items:center;
  font-size:13px;font-weight:700;
  background:var(--line-2);color:var(--muted)}
.step.is-on .step-dot{background:var(--green);color:#fff}
.step.is-done .step-dot{background:var(--green-dk);color:#fff}
.step-label{font-size:12px;font-weight:600;color:var(--muted)}
.step.is-on .step-label{color:var(--ink)}

.step-h{font-family:var(--serif);font-size:20px;font-weight:400;letter-spacing:-.015em;
  color:var(--navy-900);margin:0 0 13px}

/* The paper being claimed, quoted back before you claim it. */
.claim-paper{
  padding:13px 15px;margin-bottom:15px;
  background:var(--surface);border:1px solid var(--line);
  border-left:2px solid var(--green);border-radius:0 4px 4px 0;
  font-family:var(--serif);font-size:14.5px;line-height:1.5;color:var(--ink)}
.claim-paper .paper-meta{font-family:var(--sans)}
.radio-stack{display:grid;gap:8px}
.radio-stack label{
  display:flex;gap:9px;align-items:center;
  padding:11px 13px;border:1px solid var(--line);border-radius:4px;
  background:var(--surface);cursor:pointer;font-size:14px}
.radio-stack label:hover{border-color:var(--green)}
.radio-stack input:checked+b{color:var(--green-dk)}

/* Shown exactly once and never again. Sized to be read off a screen and
   copied onto paper without transcription errors. */
.access-code{
  margin:0 0 18px;padding:20px 14px;
  font-family:var(--mono);font-size:clamp(16px,3.4vw,21px);letter-spacing:.09em;
  font-weight:600;text-align:center;color:var(--ink);
  background:var(--surface);border:2px dashed var(--green);border-radius:4px;
  user-select:all;word-break:break-all}

.notice{padding:13px 15px;border-radius:4px;font-size:13px;line-height:1.55;margin:0 0 16px}
.notice-warn{background:var(--warn-bg);border:1px solid #E7D6B2;color:#6A4A12}
.notice-info{background:var(--info-bg);border:1px solid #C7D6E9;color:var(--navy-700)}

.checkfield{
  grid-template-columns:auto 1fr;align-items:start;gap:9px;
  font-size:13px;color:var(--ink-2)}
.checkfield input{margin-top:2px}

/* Alternative sign-in path (access code) on the login page. */
.auth-sep{
  display:flex;align-items:center;gap:12px;
  margin:18px 0;font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:700;color:var(--faint)}
.auth-sep::before,.auth-sep::after{
  content:"";flex:1;height:1px;background:var(--line)}
.code-input{
  font-family:var(--mono);font-size:15px;letter-spacing:.08em;text-transform:uppercase}

/* --- comment composer ------------------------------------------------------
   Toolbar, Write/Preview tabs, drop zone and thumbnails. Every one of these
   starts `hidden` in the markup and is revealed by app.js, so the form still
   works as a plain textarea plus file input with JavaScript off. */
/* overflow:hidden because the active tab paints
   a white background with square corners at the bar's rounded top-left, and
   without the clip it cuts the corner off. The tab is a grandchild here, which
   is why a check that only looked at direct children missed it. */
.cbar{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  border:1px solid var(--line);border-bottom:0;
  border-radius:8px 8px 0 0;background:var(--surface-2);padding:0 8px 0 0;
  overflow:hidden}
.cbar+textarea{border-radius:0 0 8px 8px!important;margin-top:0!important}
.cbar-tabs{display:flex}
.cbar-tab{
  border:0;background:none;cursor:pointer;
  padding:10px 15px;font:inherit;font-size:13px;font-weight:600;
  color:var(--muted);border-bottom:2px solid transparent}
.cbar-tab:hover{color:var(--ink-2)}
.cbar-tab.is-on{color:var(--ink);background:var(--surface);border-bottom-color:var(--green)}
.cbar-tools{display:flex;gap:2px;margin-left:auto;flex-wrap:wrap}
.cbar-btn{
  border:1px solid transparent;background:none;cursor:pointer;
  min-width:30px;height:28px;padding:0 6px;border-radius:6px;
  font:inherit;font-size:13px;line-height:1;color:var(--muted)}
.cbar-btn:hover{background:var(--surface);border-color:var(--line);color:var(--ink)}
.cbar-btn code{font-size:11px;background:none;border:0;padding:0}

.cpreview{
  min-height:150px;max-height:60vh;overflow-y:auto;
  padding:13px 14px;font-size:14px;color:var(--ink-2);
  border:1px solid var(--line);border-top:0;border-radius:0 0 8px 8px;
  background:var(--surface)}

.cfoot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:-2px}
.cfoot-hint{font-size:11.5px;color:var(--faint);line-height:1.5}
.cfoot-hint code{
  font-family:var(--mono);font-size:11px;
  background:var(--surface-2);border:1px solid var(--line-2);
  border-radius:3px;padding:0 3px}
.cfoot-count{font-size:11.5px;color:var(--faint);white-space:nowrap}
.cfoot-count.is-short{color:var(--warn)}
.cfoot-count.is-ok{color:var(--green-dk)}

.cdrop{border-radius:8px;transition:background .12s,box-shadow .12s}
.cdrop.is-over{
  background:var(--ok-bg);
  box-shadow:0 0 0 2px var(--green) inset;
  padding:8px;margin:-8px}
/* --- insert-image modal ----------------------------------------------------
   Uploads happen here and land in the body as Markdown, so a figure sits where
   the argument refers to it. */
.modal{
  position:fixed;inset:0;z-index:120;
  display:flex;align-items:center;justify-content:center;padding:20px;
  background:rgba(1,32,70,.55)}
.modal-card{
  width:100%;max-width:480px;max-height:90vh;overflow:auto;
  background:var(--surface);border-radius:11px;
  box-shadow:0 24px 64px -20px rgba(1,32,70,.45)}
.modal-head{
  display:flex;align-items:center;gap:10px;
  padding:15px 16px 12px;border-bottom:1px solid var(--line-2)}
.modal-head h2{font-size:16px;margin:0;flex:1}
.modal-x{
  border:0;background:none;cursor:pointer;font-size:22px;line-height:1;
  color:var(--faint);padding:0 2px}
.modal-x:hover{color:var(--ink)}
.modal-tabs{display:flex;gap:2px;padding:10px 16px 0;border-bottom:1px solid var(--line-2)}
.modal-tab{
  border:0;background:none;cursor:pointer;font:inherit;font-size:13px;font-weight:600;
  padding:8px 12px;color:var(--muted);border-bottom:2px solid transparent}
.modal-tab:hover{color:var(--ink-2)}
.modal-tab.is-on{color:var(--ink);border-bottom-color:var(--green)}
.modal-body{padding:16px;display:grid;gap:12px}
.modal-foot{display:flex;justify-content:flex-end;padding:0 16px 16px}
.modal-msg{
  margin:0;font-size:12.5px;color:var(--crit);
  background:var(--crit-bg);border:1px solid #EFCDC8;border-radius:7px;padding:9px 11px}

.dropzone{
  width:100%;display:grid;gap:5px;justify-items:center;
  padding:34px 18px;cursor:pointer;font:inherit;
  background:var(--surface-2);
  border:2px dashed var(--line);border-radius:9px;color:var(--muted)}
.dropzone:hover{border-color:var(--green);background:var(--ok-bg)}
.dropzone-ico{font-size:26px;line-height:1;color:var(--faint)}
.dropzone-h{font-size:14px;font-weight:600;color:var(--ink-2)}
.dropzone-s{font-size:12px;color:var(--faint)}

.cattach{
  margin:0;padding:9px 12px;font-size:12.5px;color:var(--muted);
  background:var(--surface-2);border:1px solid var(--line);
  border-top:0;border-radius:0 0 8px 8px;margin-top:-2px}
.linkish{
  border:0;background:none;padding:0;font:inherit;cursor:pointer;
  color:var(--green-dk);text-decoration:underline}

/* --- toasts ---------------------------------------------------------------- */
/* Top right, clear of the header rather than tucked under it: .site-nav is 71px
   and static, so 79px leaves a visible gap below its bottom rule instead of
   sitting on it. One position for all of them — an upload confirmation and a
   "saved" confirmation are the same kind of thing and should not appear in
   different corners. */
.toasts{
  position:fixed;right:16px;top:79px;z-index:130;
  display:grid;gap:8px;justify-items:end;pointer-events:none}
/* No header bar on an admin page — the rail runs down the left — so there is
   nothing to clear and the toast sits in the corner. 24px matches
   .admin-main's own top padding, so it lines up with the heading beside it. */
.admin-body .toasts{top:24px}
.toast{
  pointer-events:auto;max-width:340px;
  padding:11px 14px;border-radius:9px;font-size:13px;font-weight:500;
  background:var(--surface);border:1px solid var(--line);
  box-shadow:0 12px 32px -12px rgba(1,32,70,.35);
  animation:toast-in .18s ease-out}
.toast-ok{border-left:3px solid var(--green);color:var(--ink-2)}
.toast-bad{border-left:3px solid var(--crit);color:var(--crit)}
.toast-busy{border-left:3px solid var(--info);color:var(--muted)}
.toast.is-out{opacity:0;transform:translateX(8px);transition:opacity .25s,transform .25s}
/* In from the right edge they sit against, and back out the same way. */
@keyframes toast-in{from{opacity:0;transform:translateX(10px)}to{opacity:1;transform:none}}

/* The one the server renders. Unlike the JS toasts it has no script behind it
   to take it away again, so the dismissal is an animation — it still clears
   with JavaScript off, where the close button does nothing. Longer than the
   3.2s the JS ones get: these carry a sentence, not two words. */
.toast-flash{display:flex;align-items:flex-start;gap:10px;line-height:1.5;font-weight:400;
  animation:toast-in .18s ease-out both, toast-gone .45s ease-in 9s forwards}
.toast-flash:hover,.toast-flash:focus-within{animation-play-state:paused}
.toast-flash p{margin:0}
.toast-x{flex:none;border:0;background:none;cursor:pointer;padding:0 1px;
  font-size:17px;line-height:1;color:var(--faint)}
.toast-x:hover{color:var(--ink)}
@keyframes toast-gone{to{opacity:0;visibility:hidden}}

@media (prefers-reduced-motion:reduce){
  .toast{animation:none}
  .toast.is-out{transition:none}
  /* Keep the dismissal — without it this one would never leave — but drop the
     movement and the fade in. */
  .toast-flash{animation:toast-gone .01s linear 9s forwards}
}

.queued-note{
  margin:0;padding:9px 14px;font-size:12.5px;line-height:1.5;
  color:#6A4A12;background:var(--warn-bg);
  border-bottom:1px solid #E7D6B2}

/* --- publication lookup (signed registration, step 1) ---------------------- */
.pub-result{margin:0}
.pub-result-h{margin:0 0 7px;font-size:14px;font-weight:650;color:var(--ink)}
.pub-card{
  padding:12px 14px;border-radius:8px;font-size:13.5px;line-height:1.5;
  background:var(--surface-2);
  border:1px solid var(--line);border-left:3px solid var(--green)}
.pub-card b{color:var(--ink)}
.pub-card .paper-meta{margin:4px 0 0}
.pub-miss{
  margin:0;padding:10px 12px;font-size:12.5px;border-radius:7px;
  color:var(--crit);background:var(--crit-bg);border:1px solid #EFCDC8}

/* --- publication type + subject tags --------------------------------------- */
.pill-type-article{background:var(--ground);color:var(--muted);border:1px solid var(--line)}
/* Preprint is the one that changes how a concern should be read — it has not
   been peer reviewed — so it is the one that gets a colour. */
.pill-type-preprint{background:var(--warn-bg);color:var(--warn)}
.pill-type-review{background:var(--info-bg);color:var(--info)}
.pill-type-dataset,.pill-type-chapter,
.pill-type-conference,.pill-type-other{background:var(--ground);color:var(--muted);border:1px solid var(--line)}

.relnote{
  margin:12px 0 0;padding:10px 13px;border-radius:8px;font-size:13px;line-height:1.55;
  background:var(--warn-bg);border:1px solid #E7D6B2;color:#6A4A12}
.relnote a{color:#6A4A12;text-decoration:underline}

.tagcloud{display:flex;flex-wrap:wrap;gap:6px}
.tag{
  display:inline-flex;align-items:center;gap:5px;
  padding:4px 9px;border-radius:20px;font-size:12px;
  background:var(--surface-2);border:1px solid var(--line);color:var(--ink-2)}
.tag:hover{border-color:var(--green);color:var(--green-dk);text-decoration:none}
.tag.is-on{background:var(--ok-bg);border-color:var(--green);color:var(--green-dk);font-weight:600}
.tag b{color:var(--faint);font-weight:600}
.tag.is-on b{color:var(--green-dk)}

/* ===========================================================================
   The paper page — correspondence
   ---------------------------------------------------------------------------
   The thread is what this page is for, so the page is set the way a journal
   sets its correspondence section: one measured column, Georgia at reading
   size, and contributors named in the margin rather than in a chat header
   stuck on top of what they wrote.

   The measure is narrower than .wrap-read's 80rem. That cap is right for the
   About page and for a thread full of 780px figures beside a sidebar; with the
   sidebar gone the text would run the full 1280px, which is 190 characters.
   =========================================================================== */
.corr{max-width:62rem;margin-inline:auto}

/* --- publication header ----------------------------------------------------
   Plain on the page rather than inside a card. The record is the page, and the
   hard rule under it is the same one the masthead uses — this is where the
   record ends and the discussion of it starts. */
.pubhead{margin-bottom:0;padding-bottom:16px;border-bottom:2px solid var(--navy-900)}
.pubhead-title{
  font-family:var(--serif);font-size:clamp(22px,2.6vw,27px);line-height:1.25;
  font-weight:400;letter-spacing:-.02em;
  color:var(--navy-900);margin:0 0 10px;max-width:34ch}
.pubhead-line{
  margin:0;font-size:13px;color:var(--muted);
  display:flex;gap:7px;align-items:center;flex-wrap:wrap}
.pubhead-line b{color:var(--ink-2);font-weight:650}
.pubhead-ids{
  margin:8px 0 0;font-family:var(--mono);font-size:11px;color:var(--faint);
  display:flex;gap:16px;flex-wrap:wrap}
.pubhead-ids a{color:var(--muted)}
/* Authors read as a byline, in the same face as the title, because on this
   page they are the people the discussion below is about. */
.pubhead-authors{
  margin:0 0 9px;font-family:var(--serif);font-size:15px;
  color:var(--ink-2);line-height:1.6;max-width:60ch}
/* An author who holds a verified account here — so a reader can see the person
   being written about is present and could reply. */
.authortick{
  display:inline-block;margin-left:3px;font-size:10px;
  color:#fff;background:var(--green);border-radius:50%;
  width:14px;height:14px;line-height:14px;text-align:center;vertical-align:1px}

.noticebar{
  display:flex;gap:9px;align-items:flex-start;
  padding:11px 14px;border-radius:8px;margin:14px 0 0;font-size:13px;
  border:1px solid rgba(0,0,0,.08)}
.noticebar-crit{background:var(--crit-bg);color:var(--crit)}
.noticebar-warn{background:var(--warn-bg);color:var(--warn)}
.noticebar a{color:inherit;text-decoration:underline}

/* --- what you can do with this paper ---------------------------------------
   A row of actions directly under the record, not a navy slab in a sidebar.
   The single column left nowhere for a rail, and the bottom of a long thread
   is the wrong place to first offer "comment on this paper" — the decision is
   made here, having just read what the paper is. */
.actionpanel{
  display:flex;gap:8px;flex-wrap:wrap;margin:16px 0 0}
.actionpanel form{display:contents}
.actionpanel-item{
  display:inline-flex;align-items:center;gap:8px;min-height:36px;
  padding:8px 14px;font:inherit;font-size:12.5px;text-align:left;
  background:var(--surface);border:1px solid var(--line);border-radius:20px;
  cursor:pointer;color:var(--ink-2);text-decoration:none}
.actionpanel-item:hover{
  border-color:var(--navy-900);color:var(--ink);text-decoration:none;background:var(--surface)}
/* Writing a comment is the one thing this page exists to let you do. */
.actionpanel-item.is-key{
  background:var(--navy-900);border-color:var(--navy-900);color:#fff;font-weight:600}
.actionpanel-item.is-key:hover{background:var(--navy-700);border-color:var(--navy-700);color:#fff}
.actionpanel-item.is-key .actionpanel-ico{color:rgba(255,255,255,.8)}
.actionpanel-ico{
  flex:none;text-align:center;font-size:13px;color:var(--faint)}

/* --- the thread ------------------------------------------------------------
   Each comment is a card carrying the same weight as the composer below it.
   Before this the composer was the only bordered object on the page, so on
   every thread the form outweighed the record it was attached to — which is
   the wrong way round, because the comments are the page.

   The header strip holds everything that is not the argument: the number the
   comment is cited by, who wrote it, what kind of account that is, and when.
   That leaves the body as nothing but prose. */
.thread{margin-top:26px}
/* No overflow:hidden here — the reply connector is drawn as a
   ::before hanging outside the card, and clipping to the border-radius would
   eat it. The header carries its own top radius instead, which is what the
   clip was for: a square-cornered painted band sitting on a rounded corner. */
.cmt{
  background:var(--surface);border:1px solid var(--line);border-radius:6px;
  margin-bottom:11px;scroll-margin-top:80px}
.cmt-hd{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:10px 15px;font-size:12.5px;border-radius:6px 6px 0 0;
  background:var(--surface-2);border-bottom:1px solid var(--line-2)}
.cmt-num{font-family:var(--mono);font-size:11px;color:var(--faint);flex:none}
.cmt-num:hover{color:var(--green-dk);text-decoration:none}
.cmt-name{font-weight:650;color:var(--ink);letter-spacing:-.005em}
/* Pushed right so the header reads name-first however many tags sit between. */
.cmt-time{margin-left:auto;font-size:11.5px;color:var(--faint)}
.cmt-meta{font-size:11.5px;color:var(--faint)}
.cmt-tag{
  font-size:9px;letter-spacing:.07em;text-transform:uppercase;white-space:nowrap;
  font-weight:700;border-radius:3px;padding:2px 6px}
.cmt-tag.is-author{color:var(--green-dk);border:1px solid rgba(56,147,81,.4)}
/* nowrap above matters here: "Awaiting moderation" is 19 characters and wraps
   to two lines the moment the header runs out of room. */
.cmt-tag.is-queued{color:var(--warn);border:1px solid rgba(184,121,26,.45)}
.cmt-in{padding:15px}
.cmt-body{font-size:15px;line-height:1.72;color:var(--ink-2)}
.cmt-acts{display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-top:11px;font-size:11.5px}

/* A confirmed author answering. The border and header carry it now — there is
   no margin column left to flip, so the colour has to do the work. */
.cmt.is-facing{border-color:rgba(56,147,81,.42)}
.cmt.is-facing .cmt-hd{background:var(--ok-bg);border-bottom-color:rgba(56,147,81,.28)}

/* Indented under its parent, with an elbow drawn in the gutter: down out of the
   card above, then a turn to the right pointing at this one.
   The indent and the #1.1 numbering said the same thing on their own, but shape
   is read before numerals are — an inset card reads as "emphasised" until you
   notice the decimal. The elbow says "answers the one above" at a glance. */
.cmt.is-reply{margin-left:30px;position:relative}
.cmt.is-reply::before{
  content:"";position:absolute;pointer-events:none;
  /* Up into the 11px gap so the stroke meets the parent's bottom edge, and
     down to the vertical middle of this card's header. */
  left:-18px;top:-12px;width:18px;height:32px;
  /* A step darker than --line. That token is tuned for a border enclosing
     white; the same value as a bare stroke on the page ground all but
     disappears, and a connector nobody sees is worse than no connector. */
  border-left:1px solid #C3CEDD;
  border-bottom:1px solid #C3CEDD;
  border-bottom-left-radius:7px}
/* Yours, still in the queue: dashed, because it is not part of the record yet. */
.cmt.is-queued{border-color:#E7D6B2;border-style:dashed}
.cmt.is-queued .cmt-hd{background:var(--warn-bg);border-bottom-color:#E7D6B2}
/* A root kept only to hold its replies together after being taken down. */
.cmt.is-removed{background:var(--surface-2);border-style:dashed}
.cmt-removed{color:var(--muted);font-size:13.5px;line-height:1.6}
.cmt-removed b{color:var(--ink-2)}

/* Actions read as marginal notes, not as a button bar — this is a discussion,
   and a row of chrome under every comment is the loudest thing in it. The
   28px floor stays: .mini is the same control the moderation queue uses and
   the consequence of a mis-tap is the same. */
.cmt-acts .mini{border-color:transparent;background:none;color:var(--muted);
  padding-left:0;padding-right:0}
.cmt-acts .mini:hover{border-color:transparent;color:var(--green-dk);text-decoration:underline}
.cmt-acts .mini.no{color:var(--crit);border-color:transparent}
.cmt-acts .reply-inline[open]>summary,
.cmt-acts .reason-pop[open]>summary{background:none;color:var(--ink);font-weight:700}
.cmt-acts .reason-pop form .mini{border:1px solid rgba(184,54,43,.42);padding:5px 10px}

/* Sits inside the card body, above the prose. */
.cmt .queued-note{
  border:1px solid #E7D6B2;border-radius:4px;margin:0 0 12px;padding:9px 12px}

/* --- record details, after the discussion ---------------------------------- */
.recfoot,.homefoot{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:30px;margin-top:38px;padding-top:24px;border-top:1px solid var(--navy-900)}

@media (max-width:720px){
  /* The timestamp gives up its right edge rather than forcing the header to
     wrap around it, and the indent shrinks so a reply to a reply still has a
     readable measure. */
  .cmt-hd{gap:8px;padding:9px 12px}
  .cmt-time{margin-left:0}
  .cmt-in{padding:13px 12px}
  /* Shorter indent, so the elbow shortens with it or it would reach back past
     the parent's own left edge. */
  .cmt.is-reply{margin-left:16px}
  .cmt.is-reply::before{left:-11px;width:11px;height:30px}
}

/* --- saved searches --------------------------------------------------------- */
.savedlist{display:grid;gap:8px}
.saveditem{
  display:flex;align-items:center;gap:12px;
  padding:12px 14px;background:var(--surface);
  border:1px solid var(--line);border-radius:6px}
.saveditem-main{flex:1;min-width:0}
.saveditem-label{font-size:14px;font-weight:650;color:var(--ink)}
.saveditem-label:hover{color:var(--green-dk)}
.saveditem .pill-warn{flex:none;text-decoration:none}

/* ===========================================================================
   About page
   ---------------------------------------------------------------------------
   No new palette and no new typeface: the CSP sets font-src 'self', so the
   page is built from the existing Georgia/system-ui stack and the decision
   colours the app already uses. Personality comes from scale and structure.

   Georgia carries the opening statement because it is the face the site sets
   paper titles in — the About page reads in the same voice as the records it
   describes.
   =========================================================================== */

.about-head{padding:10px 0 26px;border-bottom:2px solid var(--navy-900);margin-bottom:34px}
.about-eyebrow{
  font-size:11px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--green-dk);font-weight:700;margin:0 0 14px}
.about-thesis{
  font-family:var(--serif);font-size:clamp(26px,3.4vw,38px);line-height:1.22;
  letter-spacing:-.021em;font-weight:400;color:var(--navy-900);
  margin:0;max-width:26ch;text-wrap:balance}
/* The second clause answers the first, so it starts its own line rather than
   wrapping wherever the measure happens to break — "…published. This" left
   hanging reads as a typo. */
.about-thesis em{font-style:normal;color:var(--green-dk);display:block}
.about-lede{
  margin:16px 0 0;font-size:15.5px;line-height:1.65;color:var(--muted);max-width:56ch}

.about-sec{margin:0 0 38px}
.about-sec:last-child{margin-bottom:0}
.about-sec p{margin:0 0 13px;font-size:15px;line-height:1.72;color:var(--ink-2)}
.about-sec p:last-child{margin-bottom:0}
.about-sec p b{color:var(--ink)}
.about-sec .section-label{margin:0 0 15px}

/* One queue, three outcomes — a branch, not a sequence, because that is what
   actually happens. Numbering it 1/2/3 would assert an order that is not
   there. */
.about-queue{
  display:flex;align-items:center;gap:11px;
  padding:12px 15px;margin:0 0 4px;
  background:var(--navy-700);border-radius:9px;color:#fff;font-size:13.5px}
.about-queue b{font-weight:650}
.about-stem{width:2px;height:16px;background:var(--line);margin-left:26px}
.about-outcomes{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.about-outcome{
  border:1px solid var(--line);border-radius:9px;padding:13px 14px;
  background:var(--surface);border-top:3px solid var(--line)}
.about-outcome h3{
  font-size:11px;letter-spacing:.07em;text-transform:uppercase;
  margin:0 0 7px;font-weight:700}
.about-outcome p{font-size:13px;line-height:1.6;color:var(--muted);margin:0}
.about-outcome.is-ok{border-top-color:var(--green)}
.about-outcome.is-ok h3{color:var(--green-dk)}
.about-outcome.is-edit{border-top-color:var(--warn)}
.about-outcome.is-edit h3{color:var(--warn)}
.about-outcome.is-no{border-top-color:var(--crit)}
.about-outcome.is-no h3{color:var(--crit)}

/* The signature. The rule is "point at the record, not the person", and the
   fastest way to teach it is to show the same concern written both ways, in
   the chrome a real comment wears — including the decision it would get. */
.about-compare{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin:2px 0 16px}
.about-example{
  border:1px solid var(--line);border-radius:9px;overflow:hidden;background:var(--surface)}
.about-example-head{
  display:flex;align-items:center;gap:8px;
  padding:9px 13px;font-size:11px;letter-spacing:.05em;text-transform:uppercase;
  font-weight:700;border-bottom:1px solid var(--line-2)}
.about-example-body{
  padding:13px;font-size:14px;line-height:1.6;color:var(--ink-2);
  font-family:var(--serif)}
.about-example-why{
  padding:0 13px 13px;font-size:12.5px;line-height:1.55;color:var(--muted)}
.about-example.is-ok .about-example-head{background:var(--ok-bg);color:var(--green-dk)}
.about-example.is-ok{border-color:rgba(56,147,81,.34)}
.about-example.is-no .about-example-head{background:var(--crit-bg);color:var(--crit)}
.about-example.is-no{border-color:rgba(184,54,43,.3)}

.about-rules{margin:0;padding:0;list-style:none;display:grid;gap:9px}
.about-rules li{
  padding-left:17px;position:relative;font-size:14.5px;line-height:1.65;color:var(--ink-2)}
.about-rules li::before{
  content:"";position:absolute;left:0;top:9px;
  width:6px;height:6px;border-radius:50%;background:var(--line)}
.about-rules li b{color:var(--ink)}

/* Addressed to one reader — the author who has just found their own paper
   here. It is the only part of the page written to "you", so it is the only
   part that looks different. */
.about-callout{
  border:1px solid var(--line);border-left:3px solid var(--navy-700);
  border-radius:9px;padding:20px 22px;background:var(--surface)}
.about-callout h2{
  font-family:var(--serif);font-size:20px;letter-spacing:-.01em;
  font-weight:400;color:var(--navy-900);margin:0 0 11px}
.about-callout p{font-size:14.5px;line-height:1.7;color:var(--ink-2);margin:0 0 11px}
.about-callout p:last-child{margin-bottom:0}

.about-terms{border-top:1px solid var(--line);padding-top:20px}
.about-terms p{font-size:13.5px;line-height:1.68;color:var(--muted)}

.about-toc{position:sticky;top:16px;align-content:start}
.about-toc ol{margin:0;padding:0;list-style:none;counter-reset:toc}
.about-toc li{counter-increment:toc}
.about-toc a{
  display:flex;gap:9px;padding:7px 0;font-size:13px;color:var(--ink-2);
  border-bottom:1px solid var(--line-2)}
.about-toc li:last-child a{border-bottom:0}
.about-toc a::before{
  content:counter(toc,decimal-leading-zero);
  color:var(--faint);font-family:var(--mono);font-size:11px;padding-top:2px}
.about-toc a:hover{color:var(--green-dk);text-decoration:none}

@media (max-width:820px){
  .about-outcomes,.about-compare{grid-template-columns:1fr}
  .about-toc{position:static}
  .about-head{padding-bottom:22px;margin-bottom:26px}
}

/* ======================= audit log =======================
   A table of six columns made every row look like every other, which is the
   opposite of what this page is for: most entries are routine and a few — a
   role change, a suspension — are the ones anyone actually came to find. So it
   is a dated list with the action stated as a sentence, and the kind of action
   carried on a rail down the left where it can be scanned without reading. */
.audit-filters{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin:14px 0 16px}
.audit-filter-label{font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--faint);font-weight:700}
.audit-chip{font-size:12px;padding:4px 11px;border-radius:20px;border:1px solid var(--line);
  background:var(--surface);color:var(--ink-2);white-space:nowrap}
.audit-chip:hover{border-color:var(--navy-500);text-decoration:none}
.audit-chip.is-on{background:var(--navy-900);border-color:var(--navy-900);color:#fff;font-weight:600}

.audit{list-style:none;margin:0;padding:0;border:1px solid var(--line);border-radius:6px;
  background:var(--surface);overflow:hidden}
.audit-day{padding:9px 15px;font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  font-weight:700;color:var(--faint);background:var(--surface-2);
  border-block:1px solid var(--line-2)}
.audit>.audit-day:first-child{border-top:0}

.audit-row{display:grid;grid-template-columns:52px minmax(0,1fr) auto auto;gap:0 14px;
  align-items:start;padding:12px 15px;border-top:1px solid var(--line-2)}
.audit-day+.audit-row{border-top:0}
/* The rail. Colour means what the action did, not how it looked: green let
   something through, red stopped it, navy changed what a person may do. */
.audit-row{box-shadow:inset 3px 0 0 var(--line-2)}
.audit-row.is-allow{box-shadow:inset 3px 0 0 var(--green)}
.audit-row.is-deny{box-shadow:inset 3px 0 0 var(--crit)}
.audit-row.is-people{box-shadow:inset 3px 0 0 var(--navy-700)}
.audit-row.is-undone{box-shadow:inset 3px 0 0 var(--warn)}
.audit-row.is-reversed{background:var(--surface-2)}
/* Struck through, not hidden: the entry still happened. */
.audit-row.is-reversed .audit-line{text-decoration:line-through;color:var(--muted)}
.audit-row.is-reversed .audit-line b{color:var(--muted)}

.audit-time{font-family:var(--mono);font-size:11px;color:var(--faint);padding-top:2px}
.audit-line{margin:0;font-size:13.5px;color:var(--ink-2);line-height:1.5}
.audit-line b{color:var(--ink);font-weight:650}
.audit-subject{font-family:var(--mono);font-size:11px;color:var(--faint);margin-left:4px}
.audit-detail{margin:5px 0 0;display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:2px 10px;font-size:12px}
.audit-detail dt{color:var(--faint);white-space:nowrap}
.audit-detail dd{margin:0;color:var(--ink-2);overflow-wrap:anywhere}
.audit-reversed{margin:6px 0 0;font-size:11.5px;color:var(--warn)}
.audit-ip{font-family:var(--mono);font-size:10.5px;color:var(--faint);padding-top:3px;
  white-space:nowrap}
.audit-act{display:flex;justify-content:flex-end;min-width:0}
.audit-blocked{font-size:11px;color:var(--faint);max-width:20ch;text-align:right;line-height:1.4}

@media (max-width:900px){
  .audit-row{grid-template-columns:46px minmax(0,1fr);gap:0 12px}
  .audit-ip{display:none}
  .audit-act{grid-column:2;justify-content:flex-start;margin-top:8px}
  .audit-blocked{text-align:left;max-width:none}
}

/* --- audit entry detail ----------------------------------------------------
   Added because "Comment #259" answers nothing. The excerpt is what the entry
   is actually about, so it gets the reading face and a rule beside it; the
   identifiers stay small and mono where they belong. */
.audit-who{font-size:12.5px;color:var(--ink-2)}
.audit-subject{font-family:var(--mono);font-size:11px;color:var(--muted);margin-left:4px}
a.audit-subject:hover{color:var(--green-dk)}
.audit-subject.is-gone{color:var(--faint);text-decoration:line-through}
.audit-excerpt{margin:6px 0 0;padding:2px 0 2px 11px;border-left:2px solid var(--line);
  font-family:var(--serif);font-size:13px;line-height:1.55;color:var(--ink-2);
  overflow-wrap:anywhere}
.audit-on{margin:5px 0 0;font-size:11.5px;color:var(--muted)}
.audit-on a{color:var(--muted);text-decoration:underline}
.audit-on a:hover{color:var(--green-dk)}
.audit-drift{margin:5px 0 0;font-size:11.5px;color:var(--muted)}
.audit-drift b{color:var(--ink-2);font-weight:650}
.audit-id{display:block;font-size:9.5px;color:#9FAEC0;margin-top:1px}
.audit-row:target{background:var(--warn-bg);box-shadow:inset 3px 0 0 var(--warn)}

.audit-single{margin:0 0 14px;padding:9px 13px;border-radius:4px;font-size:12.5px;
  background:var(--info-bg);border:1px solid #C7D6E9;color:var(--navy-700)}
.audit-single a{color:var(--navy-700);text-decoration:underline}

/* --- challenge --------------------------------------------------------------
   A visible box, because an invisible check gives a reader nothing to trust and
   nothing to fix when it refuses them. It looks like the widget everyone knows,
   but nothing leaves this server: ticking it starts the browser hashing, and
   the state text says so. */
.challenge{display:grid;gap:6px}
.challenge-box{display:flex;align-items:center;gap:11px;padding:12px 14px;
  background:var(--surface);border:1px solid var(--line);border-radius:6px}
.challenge-tick{width:19px;height:19px;flex:none;accent-color:var(--green-dk);cursor:pointer}
.challenge-label{font-size:13.5px;color:var(--ink-2);cursor:pointer;user-select:none}
.challenge-state{margin-left:auto;font-size:11.5px;color:var(--faint);white-space:nowrap;
  display:flex;align-items:center;gap:6px}
.challenge-state.is-working::before{content:"";width:7px;height:7px;border-radius:50%;
  background:var(--green);display:block;animation:challenge-blip 1.1s ease-in-out infinite}
.challenge-state.is-done{color:var(--green-dk);font-weight:650}
.challenge-state.is-done::before{content:"\2713";font-weight:700}
@keyframes challenge-blip{0%,100%{opacity:1}50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){.challenge-state.is-working::before{animation:none}}
.challenge-error{margin:0;font-size:12.5px;color:var(--crit)}
/* Off-screen rather than hidden with display:none or type=hidden, because the
   crawlers worth catching skip both and a person never reaches it either way. */
.challenge-trap{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}

/* --- account settings ------------------------------------------------------
   One ruled section per thing that can change, because they are confirmed
   separately and a single save button would imply otherwise. */
.set-summary{margin-bottom:30px}
.set-form{margin-bottom:30px}
.set-form .stack{background:none;border:0;border-radius:0;padding:0;gap:13px}
.set-form .btn{justify-self:start}
.set-note{font-size:11.5px;color:var(--faint);line-height:1.55;margin:0}
.set-summary .factlist{grid-template-columns:auto minmax(0,1fr);gap:8px 14px;font-size:13px}
.set-summary .factlist dd{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.acct-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}

/* =========================================================================
   Motion
   =========================================================================
   Collected in one place rather than scattered through the components, so
   the timing of the whole site can be read — and changed — at once.

   Two rules govern everything below:

   1. Only opacity and transform are animated on anything that repeats.
      Those two are the properties a browser can move without laying the
      page out again; animating height, top or margin on a list of forty
      comments is how a page starts to feel cheap on a mid-range phone.

   2. Nothing moves that the reader did not ask to move. Hover and press
      respond to a pointer, entrances play once on arrival, and there is no
      ambient animation anywhere — this is a page people come to in order to
      read a dispute about somebody's data.

   The global prefers-reduced-motion switch near the top of this file turns
   all of it off, with one exception handled at the end: `*` does not match
   the ::view-transition pseudo-elements, so those are disabled separately.
   ========================================================================= */

/* ---- between pages ------------------------------------------------------
   A cross-document view transition, so a click through to a paper is a
   settle rather than a blink. Pure CSS: there is no router here and no
   script involved, which matters under `script-src 'self'`.

   Browsers without it navigate exactly as before, so the fallback is the
   old behaviour rather than a broken one. Firefox is the notable absence,
   and the @supports block below gives it the same arrival on its own. */
@view-transition{navigation:auto}

::view-transition-old(root){animation:page-out 120ms var(--ease) both}
::view-transition-new(root){animation:page-in var(--dur-enter) var(--ease-out) both}
@keyframes page-out{to{opacity:0}}
@keyframes page-in{from{opacity:0;transform:translateY(7px)}}

/* The masthead and the admin rail are fixtures. Naming them keeps them
   still while the page beneath changes, which is what makes the transition
   read as one document turning over rather than the whole window redrawing. */
.site-nav{view-transition-name:masthead}
.rail{view-transition-name:rail}
.site-foot{view-transition-name:plinth}

@supports not (view-transition-name:none){
  .main,.admin-main{animation:page-in var(--dur-enter) var(--ease-out) both}
}

/* ---- pressable things --------------------------------------------------- */
.btn,.mini,.pager-link,.actionpanel-item,.toast-x,.lightbox-close,.rl{
  transition:background-color var(--dur-state) var(--ease),
             border-color var(--dur-state) var(--ease),
             color var(--dur-state) var(--ease),
             box-shadow var(--dur-state) var(--ease),
             transform var(--dur-press) var(--ease)}
/* Down under the finger, and back. 1px is enough to feel and too little to
   reflow anything around it. */
.btn:active,.mini:active,.pager-link:active,.actionpanel-item:active{transform:translateY(1px)}
.btn-primary:hover{box-shadow:0 4px 14px -6px rgba(1,32,70,.5)}

a{transition:color var(--dur-state) var(--ease)}

/* ---- cards -------------------------------------------------------------- */
/* A result is a link the size of a paragraph, so it lifts a little to say so.
   The comment cards deliberately do not: they are not links, and a thread
   that shifts under the cursor while you read it is an irritation. */
.rec{transition:border-color var(--dur-state) var(--ease),
                box-shadow var(--dur-state) var(--ease),
                transform var(--dur-state) var(--ease)}
.rec:hover{box-shadow:0 8px 22px -14px rgba(1,32,70,.45);transform:translateY(-1px)}

.kpi,.sidebox,.cdrop,.institution-card{
  transition:border-color var(--dur-state) var(--ease),
             box-shadow var(--dur-state) var(--ease)}

/* ---- rows --------------------------------------------------------------- */
/* Worth having on a wide table: it is what keeps the eye on one member while
   it travels from the name to the button that acts on them. */
table.data tbody tr{transition:background-color var(--dur-state) var(--ease)}
table.data tbody tr:hover{background:var(--surface-2)}

/* ---- fields ------------------------------------------------------------- */
/* Border only. The focus ring is an outline and stays instant — a keyboard
   user needs to know where they are the moment they arrive, not 170ms later. */
.field input,.field textarea,.field select,.inline-form select,.code-input{
  transition:border-color var(--dur-state) var(--ease),
             box-shadow var(--dur-state) var(--ease)}

/* ---- things that appear ------------------------------------------------- */
/* All of these are revealed by removing [hidden] or adding a class, which
   takes them from display:none to displayed — and a CSS animation runs on
   that. No script is involved in the movement. */
.suggest{animation:drop-in var(--dur-enter) var(--ease-out) both}
@keyframes drop-in{from{opacity:0;transform:translateY(-6px)}}

.lightbox.is-open,.lightbox[open]{animation:fade-in 160ms var(--ease) both}
.lightbox.is-open img,.lightbox[open] img{animation:lift-in var(--dur-enter) var(--ease-out) both}
@keyframes fade-in{from{opacity:0}}
@keyframes lift-in{from{opacity:0;transform:scale(.97)}}

@media (max-width:820px){
  .site-nav.open .nav-links,.site-nav.open .nav-actions{
    animation:drop-in var(--dur-state) var(--ease-out) both}
}

/* ---- disclosure --------------------------------------------------------- */
/* The content fades and settles; the box itself snaps.
 *
 * Animating the height instead — ::details-content with block-size 0 to auto,
 * which is the modern way to do this — clipped a <details> that renders open
 * on first paint. There is no state change on load to drive the transition, so
 * it sat at the closed size with overflow:hidden over full-height content: the
 * registration page lost the second half of "nothing can be recovered if you
 * lose the code". A disclosure animation is not worth eating a warning.
 *
 * Opacity and transform touch no layout, so there is nothing to clip. */
details[open] > :not(summary){
  animation:reveal var(--dur-state) var(--ease-out) both}
@keyframes reveal{from{opacity:0;transform:translateY(-3px)}}

/* ---- reduced motion ----------------------------------------------------- */
/* `*` matches elements, and these are pseudo-elements the browser generates
   for the transition itself — so the switch at the top of this file does not
   reach them. Without this, someone who has asked their system for less
   movement still gets a page-sized cross-fade on every click. */
@media (prefers-reduced-motion:reduce){
  ::view-transition-old(root),::view-transition-new(root){animation:none!important}
  ::view-transition-group(*),::view-transition-image-pair(*){animation:none!important}
}
