/* ============================================================
   reach-ui.css — BSU REACH component library
   ============================================================
   Loaded AFTER reach-tokens.css and the per-tree sheet.

   Everything here is prefixed rx- and is NEW markup: the page
   templates opt in by using the classes. Nothing here overrides
   an old rule by selector weight, so a page that has not been
   converted is untouched.

   MOTION POLICY
   Layout never transitions. Width, height, top/left, grid and
   flex sizing all change instantly - that is what "snappy"
   means here. Only paint properties get a transition, and only
   for 70-110ms. A prefers-reduced-motion block at the end turns
   even those off.

   RESPONSIVE
   Five real steps, not desktop-then-mobile:
     >=1280  full: rail + content + facet column
      1024   facet column folds into a drawer
       900   rail collapses to icons
       768   rail goes off-canvas, rows stack
       480   single column, full-width targets
   ============================================================ */

/* ------------------------------------------------------------
   [hidden] must win.

   The UA stylesheet sets [hidden] { display: none }, but ANY author
   rule with a class selector beats it. .rx-highlights { display: grid }
   therefore un-hid an element that carried the hidden attribute, and
   the empty highlight placeholders showed on a repository with no
   publications in it. This is the standard fix and it has to sit
   before the components that set display.
   ------------------------------------------------------------ */
[hidden] { display: none !important; }

/* ============================================================
   1. APP SHELL
   ============================================================ */

.rx-shell {
  display: flex;
  min-height: calc(100vh - var(--header-h));
  background: var(--page);
}
.rx-main {
  flex: 1;
  min-width: 0;                 /* lets children shrink instead of overflow */
  padding: var(--s-6);
}
.rx-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: var(--s-6);
  align-items: start;
  max-width: var(--content-max);
  margin: 0 auto;
}
.rx-content-narrow { display: block; max-width: 920px; margin: 0 auto; }

/* ============================================================
   2. TOPBAR
   ============================================================ */

.rx-topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  height: var(--header-h);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: 0 var(--s-4);
  background: var(--surface);
  /* The 3px green rule that sat above the header is gone. It read as a
   * browser chrome artefact rather than a deliberate edge, and the header
   * already separates itself from the page with its bottom border. */
  border-bottom: 1px solid var(--border);
}
.rx-brand {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  text-decoration: none;
  flex-shrink: 0;
}
.rx-brand img { height: 30px; width: auto; display: block; }
.rx-brand-text { display: flex; flex-direction: column; line-height: 1.05; }
.rx-brand-name {
  font-family: var(--font-title);
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  color: var(--brand);
  letter-spacing: -0.01em;
}
.rx-brand-sub {
  font-size: 9px;
  font-weight: var(--fw-medium);
  letter-spacing: 0.06em;
  color: var(--text-muted);
  text-transform: uppercase;
}

/* icon button, used across the chrome */
.rx-iconbtn {
  width: 40px; height: 40px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--r-pill);
  color: var(--text-muted);
  font-size: 1rem;
  cursor: pointer;
  position: relative;
  text-decoration: none;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-iconbtn:hover { background: var(--surface-sunken); color: var(--text); }
.rx-iconbtn:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.rx-avatar {
  width: 34px; height: 34px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  border: none;
  border-radius: 50%;
  background: var(--brand-strong);
  color: #fff;
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  transition: box-shadow var(--t-fast) var(--ease);
}
.rx-avatar:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* search: one pill, real form, real submit */
.rx-search { flex: 1; display: flex; justify-content: center; min-width: 0; }
.rx-search form { display: flex; width: 100%; max-width: 620px; }
.rx-search-field {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  height: 38px;
  padding: 0 var(--s-4);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-pill);
  transition: border-color var(--t-fast) var(--ease);
}
.rx-search-field i { color: var(--text-subtle); font-size: 0.85rem; flex-shrink: 0; }
.rx-search-field input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  color: var(--text);
}
.rx-search-field input::placeholder { color: var(--text-subtle); }
.rx-search-field:focus-within { border-color: var(--text-muted); }

/* Custom X button for webkit search input */
.rx-search-field input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
  height: 14px;
  width: 14px;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='18' y1='6' x2='6' y2='18'></line><line x1='6' y1='6' x2='18' y2='18'></line></svg>") no-repeat center center;
  cursor: pointer;
  opacity: 0.7;
}
.rx-search-field input::-webkit-search-cancel-button:hover { opacity: 1; }

.rx-topbar-actions { display: flex; align-items: center; gap: var(--s-1); flex-shrink: 0; }

.rx-dot {
  position: absolute;
  top: 5px; right: 5px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}

/* Unread count on the account avatar, small screens only (the bell moves
   into the account menu there). The ring separates it from the avatar. */
.rx-avatar-dot {
  top: -4px; right: -4px;
  pointer-events: none;
  box-shadow: 0 0 0 2px var(--surface);
}
/* A plain dot, no number: the admin burger when the drawer has counts. */
.rx-dot-plain {
  top: 7px; right: 6px;
  min-width: 0; width: 9px; height: 9px;
  padding: 0;
  box-shadow: 0 0 0 2px var(--surface);
}
/* On the avatar the plain dot sits on the corner, like the count. */
.rx-avatar-dot.rx-dot-plain { top: -1px; right: -1px; width: 11px; height: 11px; }

/* Collection Type / Institutional Unit rows (pick-rows.js): one dropdown
   per item, with the same x and + buttons as the author rows. */
.pick-rows { display: flex; flex-direction: column; gap: 8px; }
.pick-row { display: flex; align-items: stretch; gap: var(--s-2); }
.pick-row select { flex: 1 1 auto; min-width: 0; width: auto; margin: 0; }

/* Watch-list words (Core/WordFilter.php): a note on the review screen
   and a small tag in the publication and request lists. */
.rx-note.rx-note-warning {
  text-align: left;
  background: var(--warning-surface, #FEF6DC);
  border-color: color-mix(in srgb, var(--warning, #7A4A02) 30%, transparent);
  color: var(--warning, #7A4A02);
}
.rx-flag-list { margin: var(--s-2) 0 0; padding-left: 1.2em; }
.rx-flag-list li { margin: 2px 0; }
.rx-flag-field { font-weight: var(--fw-semibold, 600); }
.rx-note.rx-note-warning mark { background: color-mix(in srgb, var(--warning, #7A4A02) 18%, transparent); color: inherit; padding: 0 3px; border-radius: 3px; }
.rx-flag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px;
  border-radius: var(--r-pill, 999px);
  background: var(--warning-surface, #FEF6DC);
  color: var(--warning, #7A4A02);
  border: 1px solid color-mix(in srgb, var(--warning, #7A4A02) 30%, transparent);
  font-size: var(--fs-xs, 0.75rem);
  font-weight: var(--fw-semibold, 600);
  white-space: nowrap;
  cursor: help;
}

/* ============================================================
   3. NAV RAIL
   ============================================================ */

.rx-rail {
  width: var(--sidebar-w);
  flex-shrink: 0;
  box-sizing: border-box;
  padding: var(--s-3) var(--s-2);
  background: var(--surface);
  border-right: 1px solid var(--border);
  /* NO width transition. The rail snaps between states. */
}
.rx-rail-group { display: flex; flex-direction: column; gap: 2px; }
.rx-rail-label {
  padding: var(--s-3) var(--s-3) var(--s-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-subtle);
  white-space: nowrap;
}
.rx-rail-sep { height: 1px; background: var(--border); margin: var(--s-3) var(--s-2); }

.rx-navitem {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  height: 40px;
  padding: 0 var(--s-3);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-navitem i { width: 20px; text-align: center; font-size: 1rem; flex-shrink: 0; }
.rx-navitem-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rx-navitem:hover { background: var(--surface-sunken); color: var(--text); }
.rx-navitem[aria-current="page"] {
  background: var(--brand-tint);
  color: var(--brand-ink);
  font-weight: var(--fw-semibold);
}
.rx-navitem[aria-current="page"] i { color: var(--brand); }
.rx-navitem:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* The public rail's links still carry reachhome.css's legacy `.mini-nav-*`
 * classes alongside `.rx-navitem`. That sheet pins every item to a 40px
 * square puck centred by `margin: 0 auto`, with the label at
 * `opacity: 0; display: none`, and only expands it again under
 * `.sidebar.expanded` / `.sidebar.active` - two class names the markup
 * stopped using when the rail became `.rx-rail`. The expanded form was
 * therefore unreachable at every width: a 210px column of unlabelled
 * icons on desktop, and four icons floating down the middle of the open
 * drawer on a phone.
 *
 * `.rx-navitem` above is the real definition; these two only undo the
 * legacy collapse, so they sit with it rather than in a media query. The
 * 900 band below re-collapses them deliberately - that narrow icon rail
 * is the intended desktop form, not this accident. */
.rx-rail .mini-nav-item {
  width: auto;
  margin: 0;
  justify-content: flex-start;
  padding: 0 var(--s-3);
}
.rx-rail .mini-nav-item i { width: 20px; font-size: 1rem; }
.rx-rail .mini-nav-item span {
  display: block;
  opacity: 1;
  width: auto;
  margin-left: 0;
}

.rx-navcount {
  flex-shrink: 0;
  min-width: 20px; height: 20px;
  padding: 0 6px;
  box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}
.rx-navcount-alert { background: var(--accent); color: #fff; }

.rx-rail-foot { margin-top: var(--s-4); }
.rx-rail-foot a {
  display: block;
  padding: var(--s-2) var(--s-3);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  text-decoration: none;
  border-radius: var(--r-sm);
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-rail-foot a:hover { background: var(--surface-sunken); color: var(--text); }

.rx-scrim {
  position: fixed;
  /* Starts below the header, so the burger that opened the drawer is
   * still the thing you click to close it. */
  inset: var(--header-h) 0 0 0;
  /* Under the rail, not over it. At --z-overlay (1900) this sat on top
   * of the rail (1500): the drawer slid in, then got dimmed and had
   * every one of its links swallowed by the scrim. */
  z-index: calc(var(--z-sidebar) - 1);
  background: rgba(17, 24, 39, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease);
}
.rx-scrim.is-open { opacity: 1; pointer-events: auto; }

/* ============================================================
   4. PAGE HEADER + TOOLBAR
   ============================================================ */

.rx-pagehead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-bottom: var(--s-4);
}
.rx-pagetitle {
  margin: 0;
  font-size: var(--fs-2xl);
  font-weight: var(--fw-semibold);
  color: var(--text);
  line-height: var(--lh-tight);
}
.rx-pagecount { margin: var(--s-1) 0 0; font-size: var(--fs-md); color: var(--text-muted); }
.rx-pagecount strong { color: var(--text); font-weight: var(--fw-semibold); }

.rx-toolbar {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin-bottom: var(--s-4);
}
.rx-field-inline { display: flex; align-items: center; gap: var(--s-2); }
.rx-field-inline label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}
.rx-select {
  height: 36px;
  padding: 0 var(--s-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  color: var(--text);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.rx-select:focus-visible { outline: none; border-color: var(--brand); box-shadow: var(--focus-ring); }

/* segmented control (list / grid) */
.rx-seg { display: inline-flex; gap: 2px; padding: 3px; background: var(--surface-sunken); border-radius: var(--r-md); }
.rx-seg button {
  min-width: 34px; height: 30px;
  padding: 0 var(--s-2);
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-seg button:hover { color: var(--text); }
.rx-seg button[aria-pressed="true"] {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}
.rx-seg button:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* active filter chips */
.rx-chips { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-4); }
.rx-chips-label { font-size: var(--fs-sm); color: var(--text-muted); }
.rx-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  height: 26px;
  padding: 0 var(--s-2) 0 var(--s-3);
  border: 1px solid var(--brand-tint-line);
  border-radius: var(--r-pill);
  background: var(--brand-tint);
  color: var(--brand-ink);
  font-size: var(--fs-sm);
  text-decoration: none;
  transition: background-color var(--t-fast) var(--ease);
}
.rx-chip:hover { background: var(--brand-tint-line); }
.rx-chip i { font-size: 0.65rem; }

/* ============================================================
   5. FACETS
   ============================================================ */

.rx-facets {
  position: sticky;
  top: calc(var(--header-h) + var(--s-6));
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.rx-facet {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
}
.rx-facet-title {
  margin: 0 0 var(--s-3);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--text);
}
.rx-facet-group + .rx-facet-group { margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--border); }
.rx-facet-legend {
  margin-bottom: var(--s-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.rx-check { display: flex; align-items: center; gap: var(--s-2); min-height: 28px; cursor: pointer; }
.rx-check input { width: 15px; height: 15px; margin: 0; accent-color: var(--brand); flex-shrink: 0; cursor: pointer; }
.rx-check span { flex: 1; min-width: 0; font-size: var(--fs-md); color: var(--text); }
.rx-check em { font-size: var(--fs-sm); color: var(--text-subtle); font-style: normal; font-variant-numeric: tabular-nums; }
.rx-check:hover span { color: var(--brand-ink); }

.rx-stat-row { display: flex; align-items: baseline; justify-content: space-between; font-size: var(--fs-md); }
.rx-stat-row + .rx-stat-row { margin-top: var(--s-2); }
.rx-stat-row span { color: var(--text-muted); }
.rx-stat-row strong { color: var(--text); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }

/* facets as a drawer on smaller screens */
.rx-btn.rx-facet-toggle { display: none; }

/* ============================================================
   6. RESULT LIST — the core repository component
   ============================================================ */

.rx-results {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.rx-result {
  display: flex;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  transition: background-color var(--t-fast) var(--ease);
}
.rx-result + .rx-result { border-top: 1px solid var(--border); }
.rx-result:hover { background: var(--n-25); }

.rx-result-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-2); }

.rx-result-tags { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }

.rx-type {
  display: inline-flex;
  align-items: center;
  height: 21px;
  padding: 0 var(--s-2);
  border-radius: var(--r-sm);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.rx-type-article { background: var(--brand-tint); color: var(--brand-ink); }
.rx-type-thesis  { background: var(--info-surface); color: var(--info); }
.rx-type-report  { background: var(--warning-surface); color: var(--warning); }
.rx-type-link    { background: var(--surface-sunken); color: var(--text-muted); }

.rx-access { display: inline-flex; align-items: center; gap: var(--s-1); font-size: var(--fs-xs); font-weight: var(--fw-semibold); white-space: nowrap; }
.rx-access-open { color: var(--success); }
.rx-access-gated { color: var(--warning); }
/* Restricted, but this reader may open it (an approved request, their own
   submission, or staff). Still the restricted colour: the record did not
   become open access. */
.rx-access-granted { color: var(--warning); }
.rx-access-granted .rx-access-sep { color: var(--text-subtle); font-weight: var(--fw-regular, 400); }
.rx-access-granted .rx-access-yes { color: var(--success); }

/* The title is a real link. It used to be a div with onclick, which meant
   no middle-click, no open-in-new-tab, no keyboard focus, and nothing for
   a screen reader to announce as a link. */
.rx-result-title {
  margin: 0;
  font-family: var(--font-title);
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  line-height: 1.3;
}
.rx-result-title a {
  color: var(--brand-strong);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease);
}
.rx-result-title a:hover { color: var(--brand); text-decoration: underline; }
.rx-result-title a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 2px; }

.rx-byline { font-size: var(--fs-md); color: var(--text-muted); }
.rx-byline a { color: var(--link); text-decoration: none; }
.rx-byline a:hover { text-decoration: underline; }

.rx-source { font-size: var(--fs-sm); color: var(--text-muted); }
.rx-source .rx-doi { font-variant-numeric: tabular-nums; }

/* Two-line abstract clamp: enough to judge relevance, not enough to
   swamp the list. */
.rx-abstract {
  margin: 0;
  font-family: var(--font-title);
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.rx-metrics { display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap; margin-top: var(--s-1); }
.rx-metric { display: inline-flex; align-items: center; gap: var(--s-1); font-size: var(--fs-sm); color: var(--text-muted); }
.rx-metric i { color: var(--text-subtle); font-size: 0.8rem; }
.rx-metric strong { color: var(--text-muted); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }

.rx-result-actions {
  flex-shrink: 0;
  width: 128px;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

/* ============================================================
   7. RESULT GRID (the other layout mode)
   ============================================================ */

.rx-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-4);
}
@media (max-width: 768px) {
  .rx-cards { grid-template-columns: minmax(0, 1fr); }
}

.rx-card {
  display: flex;
  flex-direction: row;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.rx-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.rx-card-cover {
  width: 96px;
  min-height: 128px;
  background: var(--surface-sunken);
  border-right: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
}
.rx-card-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rx-card-cover i { font-size: 2.5rem; color: var(--text-subtle); }
.rx-card-body { 
  flex: 1; display: flex; flex-direction: column; gap: 6px; 
  padding: 12px; 
  min-width: 0; 
}
.rx-card-title {
  margin: 0;
  font-family: var(--font-title);
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  line-height: 1.3;
}
.rx-card-title a { color: var(--brand-strong); text-decoration: none; }
.rx-card-title a:hover { color: var(--brand); text-decoration: underline; }
.rx-card-meta { font-size: 14px; color: var(--text-muted); }
.rx-card-foot { margin-top: auto; display: flex; gap: var(--s-3); font-size: 13px; }

/* ============================================================
   8. HIGHLIGHTS — replaces the dark auto-rotating carousel
   ============================================================
   The old one was a 250px dark-green slab that auto-advanced
   every 5 seconds, which moves content out from under a reader.
   These are three static, equal cards: same information, no
   motion, and each number is a real link.
   ============================================================ */

.rx-highlights {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-4);
  margin-bottom: var(--s-6);
}
.rx-highlight {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--r-md);
  height: 170px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.rx-highlight:hover { box-shadow: var(--shadow-sm); }
.rx-highlight-label {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.rx-highlight-label i { color: var(--accent); }
.rx-highlight-stat {
  font-size: 1.5rem;
  font-weight: var(--fw-bold);
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.rx-highlight-stat small { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-muted); margin-left: var(--s-1); }
.rx-highlight-title {
  margin: 0;
  font-family: var(--font-title);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  line-height: 1.32;
  height: 2.64em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.rx-highlight-title a { color: var(--brand-strong); text-decoration: none; }
.rx-highlight-title a:hover { color: var(--brand); text-decoration: underline; }
.rx-highlight-meta { 
  font-size: var(--fs-sm); 
  color: var(--text-muted); 
  line-height: 1.4;
  height: 2.8em;
  display: -webkit-box; 
  -webkit-line-clamp: 2; 
  -webkit-box-orient: vertical; 
  overflow: hidden;
}

/* ============================================================
   9. PAGINATION
   ============================================================ */

.rx-pager { display: flex; align-items: center; justify-content: center; gap: var(--s-1); padding-top: var(--s-4); flex-wrap: wrap; }
.rx-pager button, .rx-pager a {
  min-width: 34px; height: 34px;
  padding: 0 var(--s-2);
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--text-muted);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.rx-pager button:hover, .rx-pager a:hover { background: var(--surface-sunken); color: var(--text); }
.rx-pager [aria-current="page"] { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: var(--fw-semibold); }
.rx-pager [aria-current="page"]:hover { background: var(--brand-strong); color: #fff; }
.rx-pager button:disabled { opacity: 0.4; cursor: not-allowed; }
.rx-pager button:focus-visible, .rx-pager a:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.rx-pager-gap { color: var(--text-subtle); padding: 0 var(--s-1); }

/* ============================================================
   10. SKELETONS — no shimmer sweep, just a static tint
   ============================================================ */

.rx-skel { background: var(--surface-sunken); border-radius: var(--r-sm); }
.rx-skel-line { height: 14px; margin-bottom: var(--s-2); }
.rx-skel-result { display: flex; gap: var(--s-4); padding: var(--s-4) var(--s-5); }
.rx-skel-result + .rx-skel-result { border-top: 1px solid var(--border); }
.rx-skel-result .rx-skel-body { flex: 1; min-width: 0; }

/* ============================================================
   11. PANELS, BUTTONS, PILLS, DANGER ZONE, META, EMPTY
   ============================================================ */

.rx-panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--s-5) var(--s-6); }
.rx-panel + .rx-panel { margin-top: var(--s-5); }

.rx-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: 36px;
  padding: 0 var(--s-3);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.rx-btn[disabled], .rx-btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.rx-btn-primary { background: var(--brand); color: var(--text-on-brand); }
.rx-btn-primary:hover { background: var(--brand-strong); color: var(--text-on-brand); }
.rx-btn-secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.rx-btn-secondary:hover { background: var(--surface-sunken); }
.rx-btn-ghost { background: transparent; color: var(--text-muted); }
.rx-btn-ghost:hover { background: var(--surface-sunken); color: var(--text); }
/* Destructive is OUTLINED and only fills on hover: a filled red button is
   the loudest thing on a page, which is wrong for the action you least
   want clicked by accident. */
.rx-btn-danger { background: var(--surface); color: var(--danger); border-color: var(--danger-line); }
.rx-btn-danger:hover { background: var(--danger); color: #fff; border-color: var(--danger); }
.rx-btn-warning { background: var(--surface); color: var(--warning); border-color: #F3DFAE; }
.rx-btn-warning:hover { background: var(--warning-surface); }
.rx-btn-lg { min-height: 42px; padding: 0 var(--s-4); font-size: var(--fs-lg); }
.rx-btn-block { width: 100%; }

.rx-pill {
  display: inline-flex; align-items: center; gap: var(--s-1);
  height: 23px; padding: 0 var(--s-2);
  border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); white-space: nowrap;
}
.rx-pill-published { background: var(--brand-tint); color: var(--brand-ink); }
.rx-pill-pending   { background: var(--warning-surface); color: var(--warning); }
.rx-pill-declined  { background: var(--danger-surface); color: var(--danger); }
.rx-pill-archived  { background: var(--surface-sunken); color: var(--text-muted); }
.rx-pill-open      { background: var(--success-surface); color: var(--success); }
.rx-pill-neutral   { background: var(--surface-sunken); color: var(--text-muted); }

.rx-danger-zone { margin-top: var(--s-10); border: 1px solid var(--danger-line); border-radius: var(--r-lg); background: var(--surface); overflow: hidden; }
.rx-danger-zone-head { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-3) var(--s-5); background: var(--danger-surface); border-bottom: 1px solid var(--danger-line); }
.rx-danger-zone-head h2, .rx-danger-zone-head h3 { margin: 0; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--danger); }
.rx-danger-zone-head i { color: var(--danger); }
.rx-danger-row { display: flex; align-items: center; gap: var(--s-6); padding: var(--s-4) var(--s-5); }
.rx-danger-row + .rx-danger-row { border-top: 1px solid var(--border); }
.rx-danger-row-text { flex: 1; min-width: 0; }
.rx-danger-row-text strong { display: block; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text); margin-bottom: var(--s-1); }
.rx-danger-row-text p { margin: 0; font-size: var(--fs-base); line-height: var(--lh-normal); color: var(--text-muted); }
.rx-danger-row .rx-btn { flex-shrink: 0; }

.rx-meta-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4) var(--s-8); }
.rx-meta-item { display: flex; flex-direction: column; gap: var(--s-1); min-width: 0; }
.rx-meta-label { font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-subtle); }
.rx-meta-value { font-size: var(--fs-md); color: var(--text); word-break: break-word; }

.rx-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-2); padding: var(--s-12) var(--s-6); text-align: center; }
.rx-empty i { font-size: 1.75rem; color: var(--text-subtle); margin-bottom: var(--s-1); }
.rx-empty strong { font-size: var(--fs-lg); font-weight: var(--fw-semibold); color: var(--text); }
.rx-empty p { margin: 0; font-size: var(--fs-md); color: var(--text-muted); max-width: 44ch; }

.rx-visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.rx-stack { display: flex; flex-direction: column; gap: var(--s-3); }
.rx-row { display: flex; align-items: center; gap: var(--s-3); }
.rx-spacer { flex: 1 1 auto; }
.rx-num { font-variant-numeric: tabular-nums; }
/* Skip link — first thing in the tab order, invisible until focused. */
.rx-skip {
  position: absolute;
  left: var(--s-4);
  top: -60px;
  z-index: calc(var(--z-header) + 10);
  padding: var(--s-2) var(--s-4);
  background: var(--surface);
  border: 1px solid var(--brand);
  border-radius: var(--r-md);
  color: var(--brand-ink);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}
.rx-skip:focus { top: var(--s-2); }

/* ============================================================
   12. RESPONSIVE — five real steps
   ============================================================ */

/* 1280: keep the facet column but tighten it */
@media (max-width: 1280px) {
  .rx-content { grid-template-columns: minmax(0, 1fr) 260px; gap: var(--s-5); }
  .rx-main { padding: var(--s-5); }
}

/* 1024: facets become a drawer above the results. This is the band that
   did not exist before - laptops and landscape tablets got the full
   desktop layout with no adjustment at all. */
@media (max-width: 1024px) {
  .rx-content { grid-template-columns: minmax(0, 1fr); }
  .rx-facets {
    position: static;
    order: -1;
    display: none;
  }
  .rx-facets.is-open { display: flex; }
  .rx-btn.rx-facet-toggle { display: inline-flex; }
  .rx-highlights { gap: var(--s-3); }
}

/* 900: rail collapses to icons. No transition - it snaps. */
@media (max-width: 900px) {
  .rx-rail { width: var(--rail-w); padding: var(--s-3) var(--s-1); }
  .rx-navitem { justify-content: center; padding: 0; height: 44px; }
  .rx-navitem-text, .rx-rail-label, .rx-rail-foot { display: none; }
  .rx-navitem i { width: auto; }
  /* Same collapse for the legacy .mini-nav-* twins, at the specificity
   * needed to beat the un-collapse in section 5. */
  .rx-rail .mini-nav-item { width: 40px; margin: 0 auto; justify-content: center; padding: 0; }
  .rx-rail .mini-nav-item i { width: 40px; font-size: 1.1rem; }
  .rx-rail .mini-nav-item span { display: none; }
  /* Only the icon-only rail turns counts into corner badges. This used
     to match every .rx-navcount, including the one on Notifications/Inbox
     in the account menu, which then floated to the menu's top corner
     beside the user's name instead of sitting on its row. */
  .rx-rail .rx-navcount {
    position: absolute;
    top: 4px; right: 4px;
    min-width: 17px; height: 17px;
    padding: 0 4px;
    font-size: 10px;
  }
  .rx-navitem { position: relative; }
  .rx-highlights { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .rx-highlight-stat { font-size: 1.25rem; }
}

/* 768: rail goes off-canvas; results stack their actions */
@media (max-width: 768px) {
  .rx-rail {
    position: fixed;
    left: 0;
    top: var(--header-h);
    bottom: 0;
    width: min(84vw, 210px);
    z-index: var(--z-sidebar);
    padding: 0 var(--s-2) var(--s-3) var(--s-2);
    overflow-y: auto;
    overscroll-behavior: contain;   /* the page behind must not scroll */
    background: var(--surface);
    border-right: 1px solid var(--border);
    /* Off-canvas by translation, not by animating width or left. */
    transform: translateX(-100%);
    transition: transform var(--t-base) var(--ease);
    box-shadow: var(--shadow-lg);
  }
  .rx-rail.is-open { transform: translateX(0); }
  .rx-rail .rx-navitem { justify-content: flex-start; padding: 0 var(--s-3); }
  .rx-rail .rx-navitem-text, .rx-rail .rx-rail-label, .rx-rail .rx-rail-foot { display: block; }
  .rx-rail .rx-navcount { position: static; min-width: 20px; height: 20px; font-size: var(--fs-xs); }

  /* Off-canvas the rail is a full drawer again, not the 900-band icon
   * strip, so the legacy .mini-nav-* collapse is undone a second time -
   * see the note in section 5. */
  .rx-rail .mini-nav-item {
    width: auto;
    margin: 0;
    justify-content: flex-start;
    padding: 0 var(--s-3);
  }
  .rx-rail .mini-nav-item i { width: 20px; font-size: 1rem; }
  .rx-rail .mini-nav-item span { display: block; opacity: 1; width: auto; margin-left: 0; }

  .rx-main { padding: var(--s-4); }

  .rx-result { flex-direction: column; gap: var(--s-3); padding: var(--s-4); }
  .rx-result-actions { width: 100%; flex-direction: row; justify-content: flex-start; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-1); }

  .rx-highlights { grid-template-columns: minmax(0, 1fr); }
  .rx-meta-grid { grid-template-columns: minmax(0, 1fr); }

  .rx-search { order: 3; flex-basis: 100%; }
  .rx-search.is-hidden { display: none; }

  .rx-desktop-only { display: none !important; }

  .rx-danger-row { flex-direction: column; align-items: stretch; gap: var(--s-3); }
  .rx-danger-row .rx-btn { width: 100%; }
}

@media (min-width: 769px) {
  .rx-mobile-only { display: none !important; }
}

/* 480: single column, full-width targets */
@media (max-width: 480px) {
  .rx-main { padding: var(--s-3); }
  .rx-topbar { padding: 0 var(--s-2); gap: var(--s-1); }
  .rx-brand-sub { display: none; }
  .rx-result { padding: var(--s-3); }
  .rx-result-title { font-size: var(--fs-lg); }
  .rx-cards { grid-template-columns: minmax(0, 1fr); }
  .rx-pagehead { flex-direction: column; align-items: stretch; }
  .rx-toolbar { flex-wrap: nowrap; gap: var(--s-2); }
  .rx-toolbar .rx-spacer { display: none; }
  .rx-toolbar .rx-field-inline { flex: 1; min-width: 0; }
  .rx-toolbar .rx-field-inline label { display: none; }
  .rx-toolbar .rx-select { width: 100%; }
}

/* --- Phone-width header ---------------------------------------------
 * The topbar's minimum content width was 517px: the burger (44), the
 * brand locked at flex 0 0 auto (253) and the action cluster (199) could
 * none of them shrink, so below ~520px the DOCUMENT widened to 517 and
 * the whole public site scrolled sideways. The fixed overlays then
 * inherited that 517 and made it obvious.
 *
 * The fix is to let the brand give way, the way every app header does at
 * this size: the wordmark goes, the logo stays, and the mark shrinks
 * again on the narrowest phones. */
@media (max-width: 640px) {
  .rx-brand      { flex: 0 1 auto; min-width: 0; }
  .rx-brand-text { display: none; }
  .rx-brand img  { height: 26px; }
}

@media (max-width: 480px) {
  .rx-brand img { height: 22px; }
}
/* Touch devices get 44px minimum targets regardless of width. */
@media (pointer: coarse) {
  .rx-btn { min-height: 44px; }
  .rx-iconbtn { width: 44px; height: 44px; }
  .rx-check { min-height: 44px; }
  .rx-pager button, .rx-pager a { min-width: 40px; height: 40px; }
  .rx-select { height: 44px; }
  .rx-seg button { min-width: 42px; height: 38px; }
}

/* ============================================================
   13. REDUCED MOTION
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   14. PUBLICATION RECORD — DESIGN.md §4.2 / §5
   ============================================================ */

.rx-breadcrumb { font-size: var(--fs-sm); color: var(--text-muted); margin-bottom: var(--s-4); }
.rx-breadcrumb a { color: var(--link); text-decoration: none; }
.rx-breadcrumb a:hover { text-decoration: underline; }
.rx-breadcrumb span.sep { padding: 0 var(--s-2); color: var(--text-subtle); }

.rx-record {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-8) var(--s-8);
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}
.rx-record-title {
  margin: 0;
  font-family: var(--font-title);
  font-size: var(--fs-3xl);
  font-weight: var(--fw-bold);
  line-height: 1.22;
  letter-spacing: -0.01em;
  color: var(--brand-strong);
}
.rx-record-authors { font-size: var(--fs-lg); line-height: var(--lh-normal); color: var(--text-muted); }
.rx-record-authors a { color: var(--link); text-decoration: none; font-weight: var(--fw-semibold); }
.rx-record-authors a:hover { text-decoration: underline; }
.rx-record-affil { display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-sm); color: var(--text-muted); }
.rx-record-rule { height: 1px; background: var(--border); }

.rx-record-section-title {
  margin: 0 0 var(--s-2);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text);
}
.rx-record-abstract {
  margin: 0;
  font-family: var(--font-title);
  font-size: var(--fs-lg);
  line-height: var(--lh-relaxed);
  color: var(--text-muted);
}

.rx-keywords { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.rx-keyword {
  display: inline-flex; align-items: center;
  height: 27px; padding: 0 var(--s-3);
  border-radius: var(--r-pill);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  text-decoration: none;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-keyword:hover { background: var(--brand-tint); color: var(--brand-ink); }

/* ---- Citation block ---- */
.rx-cite { border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.rx-cite-bar {
  display: flex; align-items: center; gap: var(--s-1);
  padding: var(--s-2) var(--s-3);
  background: var(--page);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.rx-cite-bar-label {
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--text-muted); margin-right: auto; padding-right: var(--s-2);
}
.rx-cite-tab {
  height: 28px; padding: 0 var(--s-3);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-ui); font-size: var(--fs-sm); font-weight: var(--fw-medium);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-cite-tab:hover { color: var(--text); background: var(--surface-sunken); }
.rx-cite-tab[aria-selected="true"] {
  background: var(--surface);
  border-color: var(--brand-tint-line);
  color: var(--brand-ink);
  font-weight: var(--fw-semibold);
}
.rx-cite-tab:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.rx-cite-body { display: flex; gap: var(--s-4); align-items: flex-start; padding: var(--s-4); background: var(--surface); }
.rx-cite-text {
  flex: 1; min-width: 0; margin: 0;
  font-family: var(--font-title);
  font-size: var(--fs-md); line-height: var(--lh-normal);
  color: var(--text-muted);
  overflow-wrap: break-word;
  -webkit-user-select: none;
  user-select: none;
}
.rx-cite-text.is-mono { font-family: var(--font-mono); font-size: var(--fs-sm); white-space: pre-wrap; }

/* ---- Right rail ---- */
.rx-rail-right { display: flex; flex-direction: column; gap: var(--s-3); position: sticky; top: calc(var(--header-h) + var(--s-6)); }

.rx-filecard { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--s-4); display: flex; flex-direction: column; gap: var(--s-3); }
.rx-filecard-preview {
  height: 168px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-2);
}
.rx-filecard-preview i { font-size: 2rem; color: var(--text-subtle); }
.rx-filecard-preview span { font-size: var(--fs-sm); color: var(--text-muted); }

.rx-metric-tiles { display: flex; gap: var(--s-2); }
.rx-metric-tile {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: var(--s-3) var(--s-1);
  border-radius: var(--r-md);
  background: var(--page);
}
.rx-metric-tile strong { font-size: 1.25rem; font-weight: var(--fw-bold); color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1; }
.rx-metric-tile span { font-size: var(--fs-xs); color: var(--text-muted); }
/* Citations are the impact number — the one place gold is allowed. */
.rx-metric-tile-accent { background: var(--accent-tint); }
.rx-metric-tile-accent strong, .rx-metric-tile-accent span { color: var(--accent-ink); }

.rx-related { display: flex; flex-direction: column; gap: var(--s-3); }
.rx-related-item { display: flex; flex-direction: column; gap: 2px; text-decoration: none; }
.rx-related-item strong {
  font-family: var(--font-title); font-size: var(--fs-md); font-weight: var(--fw-semibold);
  color: var(--brand-strong); line-height: 1.32;
}
.rx-related-item:hover strong { color: var(--brand); text-decoration: underline; }
.rx-related-item span { font-size: var(--fs-sm); color: var(--text-muted); }
.rx-related-sep { height: 1px; background: var(--border); }

/* ---- Gated / external notice ---- */
.rx-notice {
  display: flex; flex-direction: column; align-items: center; gap: var(--s-3);
  padding: var(--s-10) var(--s-6);
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.rx-notice i { font-size: 1.75rem; }
.rx-notice-gated i { color: var(--warning); }
.rx-notice-external i { color: var(--accent); }
.rx-notice strong { font-size: var(--fs-lg); font-weight: var(--fw-semibold); color: var(--text); }
.rx-notice p { margin: 0; font-size: var(--fs-md); color: var(--text-muted); max-width: 52ch; line-height: var(--lh-normal); }

/* ---- PDF viewer (pdf.js) ---- */
.rx-pdf { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
.rx-pdf-bar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  background: var(--page);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.rx-pdf-group { display: flex; align-items: center; gap: var(--s-2); }
.rx-pdf-btn {
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-pdf-btn:hover:not(:disabled) { background: var(--surface-sunken); color: var(--text); }
.rx-pdf-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.rx-pdf-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.rx-pdf-pageinfo { font-size: var(--fs-base); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.rx-pdf-stage { padding: var(--s-4); background: var(--surface-sunken); overflow: auto; display: flex; justify-content: center; }
.rx-pdf-stage canvas { max-width: 100%; height: auto; box-shadow: var(--shadow-md); background: #fff; }

@media (max-width: 1024px) {
  .rx-rail-right { position: static; }
}
@media (max-width: 768px) {
  .rx-record { padding: var(--s-5) var(--s-4); }
  .rx-record-title { font-size: 1.5rem; }
  .rx-cite-body { flex-direction: column; }
  .rx-cite-body .rx-btn { width: 100%; }
}

/* ============================================================
   15. DATA TABLES — DESIGN.md §4.4
   ============================================================ */

.rx-tablewrap { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
.rx-table { width: 100%; border-collapse: collapse; font-size: var(--fs-base); }
.rx-table thead th {
  padding: var(--s-3) var(--s-4);
  background: var(--page);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: left;
  white-space: nowrap;
}
.rx-table tbody td { padding: 13px var(--s-4); border-bottom: 1px solid var(--border); color: var(--text); vertical-align: middle; }
.rx-table tbody tr:last-child td { border-bottom: none; }
.rx-table tbody tr { transition: background-color var(--t-fast) var(--ease); }
.rx-table tbody tr:hover { background: var(--n-25); }
.rx-table tbody tr[aria-selected="true"] { background: var(--brand-tint); }

/* Title cell matches the result row so the two read as one system. */
.rx-table-title { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rx-table-title a {
  font-family: var(--font-title);
  font-size: 0.9rem;
  font-weight: var(--fw-semibold);
  line-height: 1.32;
  color: var(--brand-strong);
  text-decoration: none;
}
.rx-table-title a:hover { color: var(--brand); text-decoration: underline; }
.rx-table-title small { font-size: var(--fs-sm); color: var(--text-muted); }

.rx-table .num, .rx-table .rx-num { text-align: right; font-variant-numeric: tabular-nums; }
.rx-table .actions { text-align: right; white-space: nowrap; }
.rx-table .actions > * + * { margin-left: var(--s-2); }
.rx-table .shrink { width: 1%; white-space: nowrap; }
.rx-table input[type="checkbox"] { width: 15px; height: 15px; margin: 0; accent-color: var(--brand); }

.rx-tablebar {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  background: var(--page);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.rx-tablebar-count { font-size: var(--fs-base); color: var(--text-muted); }

/* Below 900 the table scrolls in place rather than widening the page. */
@media (max-width: 900px) {
  .rx-tablewrap { overflow-x: auto; }
  .rx-table { min-width: 720px; }
}

/* ============================================================
   16. FORMS — DESIGN.md §4.5
   ============================================================ */

.rx-form { display: flex; flex-direction: column; gap: var(--s-5); }
.rx-fieldset { border: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-4); }
.rx-fieldset legend {
  padding: 0;
  margin-bottom: var(--s-1);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--text);
}
.rx-field { display: flex; flex-direction: column; gap: var(--s-2); min-width: 0; }
/* Label ABOVE the field, never floating: a floating label hides the
   question once the field is filled, which is wrong for a long form. */
.rx-field > label { font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text); }
.rx-req { font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; margin-left: var(--s-2); }

.rx-input, .rx-textarea, .rx-selectfield {
  width: 100%;
  box-sizing: border-box;
  min-height: 40px;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  color: var(--text);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.rx-textarea { min-height: 120px; line-height: var(--lh-normal); resize: vertical; }
.rx-input::placeholder, .rx-textarea::placeholder { color: var(--text-subtle); }
.rx-input:focus, .rx-textarea:focus, .rx-selectfield:focus {
  outline: none; border-color: var(--brand); box-shadow: var(--focus-ring);
}
.rx-help { font-size: var(--fs-sm); color: var(--text-muted); }
.rx-error { display: flex; align-items: center; gap: var(--s-1); font-size: var(--fs-sm); color: var(--danger); font-weight: var(--fw-medium); }
.rx-field-invalid .rx-input,
.rx-field-invalid .rx-textarea,
.rx-field-invalid .rx-selectfield { border-color: var(--danger); }

.rx-field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4); }
@media (max-width: 768px) { .rx-field-row { grid-template-columns: minmax(0, 1fr); } }

.rx-formactions { display: flex; gap: var(--s-3); padding-top: var(--s-2); }
@media (max-width: 480px) {
  .rx-formactions { flex-direction: column; }
  .rx-formactions .rx-btn { width: 100%; }
}

/* ============================================================
   17. PRINT — DESIGN.md §11
   ============================================================ */

@media print {
  @page { size: A4; margin: 15mm; }

  .rx-topbar, .rx-rail, .rx-scrim, .rx-facets, .rx-facet-toggle,
  .rx-pager, .rx-toolbar, .rx-seg, .rx-skip, .rx-highlights,
  .rx-result-actions, .rx-filecard, .rx-pdf-bar, .rx-danger-zone,
  .global-header, .sidebar, footer, .main-footer,
  .rx-btn, button { display: none !important; }

  html, body { background: #fff !important; }
  body { font-size: 11pt; line-height: 1.45; color: #000; }

  .rx-shell, .rx-main, .rx-content, .rx-content-narrow {
    display: block !important;
    padding: 0 !important;
    margin: 0 !important;
    max-width: none !important;
  }

  .rx-panel, .rx-record, .rx-results, .rx-tablewrap, .rx-cite {
    border: none !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    background: #fff !important;
  }

  .rx-record-title, .rx-pagetitle { font-family: var(--font-title); color: #000; }
  .rx-result-title a, .rx-table-title a, .rx-record-title { color: #000 !important; text-decoration: none !important; }
  .rx-abstract, .rx-record-abstract, .rx-cite-text { color: #000 !important; -webkit-line-clamp: unset !important; overflow: visible !important; }

  /* Pills become outlined text — a printed colour fill wastes toner and
     often comes out as an unreadable grey block. */
  .rx-pill, .rx-type, .rx-keyword {
    background: none !important;
    color: #000 !important;
    border: 1pt solid #000 !important;
    padding: 0 3pt !important;
  }

  .rx-table { font-size: 9pt; }
  .rx-table thead { display: table-header-group; }   /* repeat header per page */
  .rx-table tfoot { display: table-footer-group; }
  .rx-table thead th { background: none !important; border-bottom: 1pt solid #000 !important; color: #000 !important; }
  .rx-table tbody td { border-bottom: 0.5pt solid #666 !important; }
  .rx-table tbody tr, .rx-result, .rx-meta-item { break-inside: avoid; page-break-inside: avoid; }

  /* Print the destination of a link, since a printed link is useless. */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 8pt; color: #333; word-break: break-all; }
  a[href^="#"]::after, a[href^="/"]::after { content: ""; }
}

/* =====================================================================
 *  18. BEHAVIOUR STATES
 *
 *  Classes the JavaScript refactor needs. Everything here replaces
 *  something that used to be written in JavaScript as an inline style
 *  assignment or an on* attribute - which is why they look small and
 *  scattered: each one is the CSS half of a handler that was deleted.
 *
 *  The pattern throughout: JS says WHICH STATE an element is in, CSS
 *  says what that state looks like. Nothing in a .js file sets a colour,
 *  a border or a display value any more.
 * ===================================================================== */

/* --- 18.1 Hover rows -------------------------------------------------
 * 26 onmouseover/onmouseout pairs did exactly this, in JavaScript, with
 * the hex value repeated at both ends of every pair. */
.notif-item,
.ledger-row,
.rx-hover-row {
  transition: background-color var(--t-fast) var(--ease);
}
.notif-item:hover,
.ledger-row:hover,
.rx-hover-row:hover,
tbody tr.rx-hover-row:hover {
  background: var(--surface-sunken);
}

/* --- 18.2 Text-style action buttons ---------------------------------
 * The Edit / Delete controls on the taxonomy pages were <span onclick>,
 * which is not focusable, not keyboard-operable and not announced as a
 * control. They are real buttons now and need to be un-styled back to
 * looking like the links they replaced. */
.rx-linkbtn {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: var(--fw-semibold);
  color: var(--brand);
  cursor: pointer;
  border-radius: var(--r-sm);
}
.rx-linkbtn:hover { text-decoration: underline; }
.rx-linkbtn:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.rx-linkbtn-danger { color: var(--danger); }

/* --- 18.3 Tag and pill remove buttons -------------------------------
 * Was <i onclick="this.parentElement.remove()">. */
.tag-item-x,
.filter-tag-x,
.rx-pill-x {
  background: none;
  border: 0;
  padding: 0 0 0 var(--s-1);
  margin: 0;
  font: inherit;
  font-size: 0.85em;
  line-height: 1;
  color: currentColor;
  opacity: 0.6;
  cursor: pointer;
}
.tag-item-x:hover,
.filter-tag-x:hover,
.rx-pill-x:hover { opacity: 1; color: var(--danger); }
.tag-item-x:focus-visible,
.filter-tag-x:focus-visible,
.rx-pill-x:focus-visible { outline: var(--focus-ring); outline-offset: 2px; opacity: 1; }

/* --- 18.4 Active states ---------------------------------------------
 * rx-core.js marks the chosen tab/filter with .is-active. The existing
 * stylesheets use .active for the same thing, so both are honoured -
 * .active for what PHP renders on first paint, .is-active for what the
 * script sets afterwards. Keeping both avoids a flash where a tab looks
 * unselected until the JS runs. */
/* Matched to the existing .active rules, not reinvented - a tab must
 * not change appearance just because the script, rather than PHP, is
 * the thing marking it selected. */
.filter-tag.is-active {
  background-color: var(--brand);
  color: var(--text-on-brand);
  border-color: var(--brand);
}
.filter-tab.is-active { background: var(--n-100); color: var(--brand); }
.report-tab.is-active { color: var(--brand); border-bottom-color: var(--brand); }

/* The report/log tab strips are <button> now, not <div>. */
/* These two were <div> and <a> and are <button> now, so they need the
 * browser's button defaults taken off - but ONLY those. The background,
 * border and padding still come from the component rules, otherwise the
 * tabs would lose their look the moment this sheet loaded. */
button.report-tab,
button.filter-tag {
  font: inherit;
  cursor: pointer;
  text-align: inherit;
}
button.report-tab:focus-visible,
button.filter-tag:focus-visible { outline: var(--focus-ring); outline-offset: -2px; }

/* --- 18.5 Admin profile menu ----------------------------------------
 * Was toggled with element.style.display = 'flex' / 'none' from
 * JavaScript, which meant the menu could not be restyled from CSS at
 * all. The class owns the display value now. */
.admin-profile-wrap { position: relative; }
.admin-profile-menu { display: none; }
.admin-profile-menu.open { display: flex; }

/* --- 18.6 File pickers ----------------------------------------------
 * publication-form.js sets one class instead of six inline style
 * assignments per state change. */
#pdf_upload_box.is-filled,
#cover_wrapper_box.is-filled {
  border-color: var(--brand);
  background: var(--brand-tint);
}
#cover_wrapper_box.is-cleared {
  border-color: var(--danger-border, var(--danger));
  background: var(--danger-surface, transparent);
}

/* --- 18.7 Table loading / error states ------------------------------
 * reports.js and audit-logs.js write one of these into the table area
 * while a query runs, instead of an HTML string carrying its own inline
 * styles. */
.rx-tablestate {
  padding: var(--s-8) var(--s-4);
  text-align: center;
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
}
.rx-tablestate-error { color: var(--danger); }

/* --- 18.8 Dialog fields ---------------------------------------------
 * The two dialogs that need a real form (add a unit, broadcast a policy
 * update) used to carry ~15 inline style attributes inside a JavaScript
 * template string. */
.rx-swal-field { text-align: left; margin-bottom: var(--s-4); }
.rx-swal-field label {
  display: block;
  margin-bottom: var(--s-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text);
}
.rx-swal-field .rx-input { width: 100%; box-sizing: border-box; }

.rx-swal-warn {
  display: flex;
  gap: var(--s-2);
  align-items: flex-start;
  text-align: left;
  padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-4);
  border: 1px solid var(--danger-border, var(--danger));
  border-radius: var(--r-md);
  background: var(--danger-surface, var(--danger-50));
  color: var(--danger-700, var(--danger));
  font-size: var(--fs-sm);
}

/* --- 18.9 Modal Dialog ------------------------------------------------
 * Every dialog - confirmations, alerts, forms and the notice you open to
 * read - is styled once, in "DIALOGS" in reach-chrome.css, and built by
 * assets/js/rx-dialogs.js. The .rx-modal-* set that used to live here
 * is gone. */

/* --- 18.10 Buttons inside dialogs -----------------------------------
 * Deliberately empty. The dialogs reuse .rx-btn / .rx-btn-primary, which
 * are already defined in the buttons section above.
 *
 * This section first redefined them here, at the end of the file - AFTER
 * the responsive media queries. A bare `.rx-btn { display: inline-flex }`
 * at this point outranks `@media (max-width: 768px) { .rx-desktop-only
 * { display: none } }`, because both are one class and the later rule
 * wins. The effect was that the desktop-only Submit button reappeared in
 * the phone header, pushing the topbar minimum width to 517px and giving
 * the whole public site a horizontal scrollbar below ~520px.
 *
 * The rule to take from this: component definitions belong ABOVE the
 * media queries. Anything added after them silently outranks every
 * responsive override in the file.
 * -------------------------------------------------------------------- */

/* --- 18.11 Small badges --------------------------------------------- */
.rx-badge-new {
  display: inline-block;
  margin-left: var(--s-2);
  padding: 2px 6px;
  border-radius: var(--r-pill);
  background: var(--danger);
  color: #fff;
  font-size: 0.65rem;
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  vertical-align: middle;
}

/* --- 18.12 Cards that became links ----------------------------------
 * centers.php and library.php drove navigation from
 * onclick="window.location.href=..." on a <div>. They are anchors now,
 * so they need the link underline and colour taken back off. */
a.classification-card { text-decoration: none; color: inherit; }
a.classification-card:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

/* --- 18.13 Busy state ----------------------------------------------- */
.is-busy { opacity: 0.7; pointer-events: none; }

/* =====================================================================
 *  19. REPORTING CHROME  (tab strip, filter bar, export, table skin)
 *
 *  This section is a port, not new work. reports.php, system_logs.php,
 *  manage_users.php and manage_departments.php each carried an inline
 *  <style> block - 126 lines between them - and those four blocks were
 *  three copies of the same two patterns:
 *
 *    .report-tabs / .report-tab   duplicated in reports and system_logs
 *    .filter-tab                  duplicated in users and departments
 *    the DataTables pager skin    duplicated in reports and system_logs
 *
 *  Written once here, with the hardcoded values replaced by tokens. The
 *  originals hardcoded #e2e8f0, #f8fafc, #f1f5f9, #166534, #bbf7d0 and
 *  #ef4444, which is why the palette could not be changed in one place.
 * ===================================================================== */

/* --- 19.1 Tab strip -------------------------------------------------- */
.report-tabs {
  display: flex;
  gap: var(--s-6);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--s-5);
  overflow-x: auto;
  white-space: nowrap;
}
.report-tab {
  padding: 10px 4px 14px;
  background: none;
  border: 0;
  border-bottom: 3px solid transparent;
  font-weight: var(--fw-bold);
  font-size: var(--fs-base);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.report-tab:hover { color: var(--brand); }
.report-tab.active,
.report-tab.is-active { color: var(--brand); border-bottom-color: var(--brand); }

/* --- 19.2 Filter surfaces -------------------------------------------- */
.filter-card,
.filter-bar {
  background: var(--surface);
  padding: var(--s-6);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  margin-bottom: var(--s-6);
}
.filter-bar {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--s-5);
}

.filter-section-title {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  font-weight: var(--fw-bold);
  color: var(--brand);
  letter-spacing: 0.5px;
  margin-bottom: var(--s-4);
  padding-bottom: var(--s-2);
  border-bottom: 1px dashed var(--border);
}

.filter-grid,
.range-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--s-5);
  margin-bottom: var(--s-5);
}
.range-grid { margin-bottom: 0; }

.filter-group {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;                 /* lets a grid child shrink instead of overflowing */
}
.filter-bar .filter-group { flex: 1; min-width: 240px; }
.filter-group label {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  font-weight: var(--fw-bold);
  letter-spacing: 0.5px;
  color: var(--text-muted);
}

.filter-input {
  width: 100%;
  min-width: 0;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--page);
  font-family: inherit;
  font-size: var(--fs-base);
  color: var(--text);
  outline: none;
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.filter-input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-tint);
}

.range-inputs { display: flex; align-items: center; gap: var(--s-3); }
.range-inputs span { font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-muted); }

.filter-tags-container {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-1);
}

.action-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
  padding-top: var(--s-4);
  margin-top: var(--s-3);
  border-top: 1px solid var(--border);
}

/* --- 19.3 Filter buttons --------------------------------------------- */
.btn-add,
.btn-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--page);
  color: var(--text-muted);
  font: inherit;
  font-weight: var(--fw-bold);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}
.btn-clear { padding: 10px 20px; background: transparent; }
.btn-add:hover   { background: var(--n-100); color: var(--brand); }
.btn-clear:hover { background: var(--n-100); color: var(--text); }
.btn-add:focus-visible,
.btn-clear:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

.export-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 10px 20px;
  border: 1px solid var(--brand-tint-line, var(--border));
  border-radius: var(--r-md);
  background: var(--brand-tint);
  color: var(--brand-ink, var(--brand));
  font: inherit;
  font-weight: var(--fw-bold);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}
.export-btn:hover { background: var(--green-100, var(--brand-tint)); }
.export-btn:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

/* --- 19.4 Role filter chips (manage_users, manage_departments) ------- */
.filter-tab {
  padding: 8px 16px;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-weight: var(--fw-semibold);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}
.filter-tab:hover { background: var(--surface-sunken); color: var(--text); }
.filter-tab.active,
.filter-tab.is-active { background: var(--n-100); color: var(--brand); }
.filter-tab:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

#customSearch:focus { border-color: var(--brand); outline: none; }

/* --- 19.5 DataTables skin --------------------------------------------
 * DataTables writes its own markup and its own class names, so this is
 * the one place in the system where !important is unavoidable: the
 * library's stylesheet loads after ours and sets these inline-level
 * defaults itself. It was previously duplicated across two pages. */
.dataTables_wrapper .bottom,
.bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-5);
  border-top: 1px solid var(--border);
  background: var(--surface);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.dt-left { display: flex; align-items: center; gap: var(--s-5); flex-wrap: wrap; }

.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_length {
  color: var(--text-muted);
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  padding-top: 0 !important;
  float: none !important;
  clear: none !important;
  margin: 0;
}
.dataTables_wrapper .dataTables_length select {
  padding: 6px 12px;
  margin: 0 var(--s-1);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: inherit;
  outline: none;
}
.dataTables_wrapper .dataTables_paginate {
  display: flex;
  gap: var(--s-1);
  float: none !important;
  padding-top: 0 !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button {
  padding: 6px 14px !important;
  margin: 0 !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--r-sm) !important;
  background: var(--surface) !important;
  color: var(--text-muted) !important;
  font-weight: var(--fw-bold);
  font-size: var(--fs-base);
  transition: background-color var(--t-fast) var(--ease);
}
.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
  background: var(--surface-sunken) !important;
  color: var(--brand) !important;
  border-color: var(--brand) !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.current,
.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
  background: var(--brand) !important;
  color: var(--text-on-brand) !important;
  border-color: var(--brand) !important;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled {
  opacity: 0.5;
  pointer-events: none;
}

table.dataTable {
  width: 100% !important;
  margin-bottom: var(--s-5) !important;
  border-bottom: none !important;
  border-collapse: collapse !important;
}
table.dataTable thead th {
  padding: 14px 18px !important;
  text-align: left !important;
  background: var(--surface-sunken) !important;
  border-top: none !important;
  border-bottom: 2px solid var(--border-strong, var(--border)) !important;
  color: var(--text-muted) !important;
  font-size: var(--fs-sm) !important;
  text-transform: uppercase !important;
  letter-spacing: 0.5px !important;
}
table.dataTable tbody td {
  padding: 14px 18px !important;
  vertical-align: middle;
  border-bottom: 1px solid var(--border) !important;
}
table.dataTable tbody tr { transition: background-color var(--t-fast) var(--ease); }
table.dataTable tbody tr:hover { background-color: var(--surface-sunken) !important; }

/* --- 19.6 Multi-select filter pills ---------------------------------- */
.filter-tag-pill,
.filter-tags-container .filter-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--n-100);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  cursor: default;
}

/* --- 18.14 Submission ledger: withdraw control -----------------------
 * The contributor's own submissions table. Withdraw is offered only while
 * the research office has not opened the record; after that the same slot
 * shows why, so the row never presents a control that would be refused. */
.ledger-status-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-2);
}
.ledger-withdraw {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  color: var(--danger);
  cursor: pointer;
}
.ledger-withdraw:hover { text-decoration: underline; }
.ledger-withdraw:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

.ledger-withdraw-locked {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  cursor: help;
}

/* --- 18.15 Contributor notifications: row actions --------------------- */
.rx-notif-actions { display: flex; gap: var(--s-2); flex-wrap: wrap; }

.rx-notif-del {
  margin-left: var(--s-2);
  padding: 4px 6px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-subtle);
  font: inherit;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
/* Revealed on hover on a pointer device, but ALWAYS present for keyboard
   and touch users - an action that only exists on hover does not exist on
   a phone. */
.notif-item:hover .rx-notif-del,
.rx-notif-del:focus-visible { opacity: 1; }
@media (hover: none) { .rx-notif-del { opacity: 1; } }

.rx-notif-del:hover { color: var(--danger); background: var(--danger-surface, transparent); }
.rx-notif-del:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }

/* =====================================================================
 *  20. PUBLIC CHROME CORRECTIONS
 *
 *  Five reported faults, four of them the same underlying problem: the
 *  markup still carried classes from reachhome.css while the behaviour was
 *  written against reach-ui.css, and the two sheets disagreed about what
 *  the chrome should do. The JavaScript then toggled a third set of names
 *  again. Nothing was broken in isolation; they simply were not talking to
 *  each other.
 *
 *  The class names are settled here: `is-open` opens a drawer, `is-hidden`
 *  hides the search. layout.js uses those and nothing else.
 * ===================================================================== */

/* --- 20.1 The mobile drawer actually opens --------------------------
 * The rail is parked off-canvas below 768 and slides back on `is-open`.
 * That geometry lives in the 768 band of section 19 and ONLY there -
 * what was missing was never the rule, it was anything setting the
 * class. A second copy used to sit here restating the same selectors
 * further down the sheet, which is precisely the arrangement that lets
 * a later edit silently outrank the rule you are reading. Merged back
 * up; the scrim's own open state was already declared with the rest of
 * .rx-scrim in section 4, so nothing is restated here either. */

/* Honour a reduced-motion preference: the drawer still opens, it just
 * arrives rather than travels. */
@media (prefers-reduced-motion: reduce) {
  .rx-rail { transition-duration: 1ms; }
}


/* --- 20.2 Header layout below 768 -----------------------------------
 * Two goes at this. The first made .rx-topbar wrap so the search could
 * drop onto a second row - which fixed the Sign in button landing in the
 * middle, but created a worse problem: a wrapping header is a header
 * that changes height. Revealing the search grew the sticky bar by a
 * whole row, which shoved the page content down and, because the bar is
 * `position: sticky; top: 0`, made the header itself appear to jump.
 *
 * The search is a temporary surface, so it behaves like one: it is taken
 * out of the flow entirely and hangs below the bar as an overlay. The
 * header keeps one row and one height, and nothing under it moves. */
@media (max-width: 768px) {
  .rx-topbar {
    flex-wrap: nowrap;
    height: var(--header-h);
  }

  /* Whatever else shares the row, the actions end it, hard against the
   * right edge. */
  .rx-topbar-actions { margin-left: auto; }

  /* Out of the flow: anchored to .rx-topbar, which is `sticky` and so is
   * a positioned ancestor. */
  .rx-search {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    padding: var(--s-2) var(--s-3);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-md);
  }
  .rx-search form { max-width: none; }
  .rx-search.is-hidden { display: none; }
}

/* Above 768 the search is always in the bar, so the small-screen default
 * class must not be able to hide it. */
@media (min-width: 769px) {
  .rx-search.is-hidden { display: flex; }

  /* --- 20.4 The burger does something on desktop too ----------------
   * Below 768 the burger opens the drawer. Above it, the rail is a
   * static column and `is-open` moves nothing, so the button was dead -
   * you could click it all day on a full-screen window and watch
   * nothing happen. The admin portal's burger has always collapsed its
   * rail to an icon strip and remembered the choice; this is the same
   * behaviour under the rail's own class names.
   *
   * Only ever collapses. Between 769 and 900 the rail is already an
   * icon strip by media query, so the toggle has nothing left to do
   * there and correctly does nothing. */
  .rx-rail.is-collapsed {
    width: var(--rail-w);
    padding: var(--s-3) var(--s-1);
  }
  .rx-rail.is-collapsed .rx-navitem-text,
  .rx-rail.is-collapsed .rx-rail-label,
  .rx-rail.is-collapsed .rx-rail-foot { display: none; }
  .rx-rail.is-collapsed .rx-navitem { justify-content: center; padding: 0; }
  .rx-rail.is-collapsed .mini-nav-item { width: 40px; margin: 0 auto; justify-content: center; padding: 0; }
  .rx-rail.is-collapsed .mini-nav-item i { width: 40px; font-size: 1.1rem; }
  .rx-rail.is-collapsed .mini-nav-item span { display: none; }
  .rx-rail.is-collapsed .rx-rail-sep { margin: var(--s-3) var(--s-1); }
}


/* --- 20.3 Footer ----------------------------------------------------
 * It was a solid block of brand green with a gold bar under it, which
 * fought the off-white page above it and made the foot of every page the
 * loudest thing on screen.
 *
 * The brief puts green in the header and as an accent - not as a second
 * full-bleed surface. So the footer becomes a quiet sunken panel: page
 * neutrals, ordinary text, green reserved for the column headings and the
 * link hover, and a single rule along the top to separate it from the
 * content rather than a change of colour doing that work.
 *
 * Both footers, because they are the same footer with two class names:
 * .global-footer on the public site, .admin-footer in the portal, and
 * reachadmin.css says its version is "mapped exactly from reachhome.css".
 * The two must not drift apart again. */
.global-footer,
.admin-footer {
  background: var(--surface-sunken);
  color: var(--text);
  border: none;
  border-top: 1px solid var(--border);
}

/* Except on the admin side, where the content already ends in a bordered
 * .dashboard-panel. Its bottom edge and this rule landed a few pixels
 * apart and read as one doubled line above the footer. The change of
 * surface is enough separation once there is already an edge there. */
.admin-footer { border-top: none; }

/* The columns' bottom border sat directly above .footer-bottom-wrapper's
 * own border-top - two rules drawing one separation. The strip's is the
 * one that belongs to a change of surface, so it keeps it. */
.global-footer .footer-container,
.admin-footer .footer-container {
  border-bottom: none;
}

.global-footer .footer-col h4,
.admin-footer .footer-col h4 {
  color: var(--brand);
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
}

.global-footer .footer-sub-brand,
.admin-footer .footer-sub-brand { color: var(--text); font-weight: var(--fw-semibold); }

/* reachadmin.css hardcodes #cbd5e1 here - a light grey chosen for the old
 * green panel, and invisible on this one. */
.global-footer .footer-contact-info,
.admin-footer .footer-contact-info { color: var(--text-muted); }

/* --text-subtle is 2.43:1 and is icons-only by the contrast rules in
 * DESIGN.md - which is exactly what this is. */
.global-footer .footer-icon,
.admin-footer .footer-icon { color: var(--accent); }

.global-footer .footer-link,
.admin-footer .footer-link {
  color: var(--text-muted);
  border-radius: var(--r-sm);
}
.global-footer .footer-link:hover,
.admin-footer .footer-link:hover {
  background: var(--brand-tint);
  color: var(--brand);
}
.global-footer .footer-link:focus-visible,
.admin-footer .footer-link:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

/* The bottom strip was gold-on-dark. It is the quietest line on the page,
 * so it gets the quietest treatment: one shade down from the panel, muted
 * text, separated by a rule.
 *
 * Unprefixed on purpose. In the public tree this div sits INSIDE
 * .global-footer; in the admin tree it is a sibling of .admin-footer, so
 * a descendant selector would silently miss it there and leave a gold bar
 * under a grey footer. */
.footer-bottom-wrapper {
  background: var(--n-200);
  border-top: 1px solid var(--border);
  padding: var(--s-4) var(--s-6);
}
.footer-bottom {
  color: var(--text-muted);
  font-weight: var(--fw-medium);
  gap: var(--s-4);
  flex-wrap: wrap;
}

@media (max-width: 600px) {
  .global-footer .footer-container { gap: var(--s-8); padding: var(--s-8) var(--s-4); }
  .global-footer .footer-bottom { justify-content: center; text-align: center; }
}


/* =====================================================================
 *  21. SECOND CORRECTION ROUND
 *
 *  Reported together, and they divide into four groups: the header row
 *  never lined up; the drawer's close button sat in the wrong corner and
 *  left a hole above the nav; the admin portal had the same class-name
 *  mismatch the public rail had, so its drawer never opened; and the
 *  whole system was still sized for a desktop on a phone.
 * ===================================================================== */

/* --- 21.1 The header actions line up --------------------------------
 * Submit, the bell and the avatar were three different heights sitting
 * on three different baselines. Two causes:
 *
 *   .profile-dropdown-container was a plain block, so the avatar inside
 *   it sat on a text baseline with the line-box's descender space under
 *   it - which is why it rode lower than the icon buttons beside it.
 *
 *   .rx-avatar had no `display`, so it was an inline-block being aligned
 *   as if it were a letter.
 *
 * Everything in the actions group is now the same box, vertically
 * centred by the flex row rather than by luck. */
.profile-dropdown-container { display: flex; align-items: center; }

.rx-topbar-actions { gap: var(--s-2); }
.rx-topbar-actions .rx-iconbtn { width: 36px; height: 36px; }
.rx-topbar-actions .rx-btn { min-height: 36px; }
.rx-topbar .rx-avatar {
  width: 36px; height: 36px;
}

/* --- 21.2 The drawer's close button ---------------------------------
 * It was the first child of the rail, full width, so it sat top-LEFT and
 * then pushed the nav down by its own height plus the rail's padding -
 * a visible hole between the burger and the first link.
 *
 * Right-aligned, and its row IS the gap: the rail loses its top padding
 * so nothing is added above or below the button. */
@media (max-width: 768px) {
  .rx-rail { padding-top: 0; }
  .rx-rail .close-sidebar-btn {
    display: flex;
    margin: var(--s-1) 0 var(--s-1) auto;   /* auto on the left = flush right */
  }
}

/* --- 21.3 Highlights: one card, stepped through ---------------------
 * Three cards side by side is three columns of a phone's width each,
 * and the green bar down the left of every one made the top of the page
 * read as a warning strip.
 *
 * One card now, with the other two behind it. The reader steps; nothing
 * moves on its own - the reason the original carousel was removed was
 * that it auto-advanced, not that it was a carousel. */
.rx-highlights {
  display: block;
  position: relative;
  margin-bottom: var(--s-5);
}
.rx-highlight {
  border-left: 1px solid var(--border);   /* was 3px solid var(--brand) */
  gap: var(--s-1);
  padding: var(--s-4) var(--s-5);
}
/* Only the current slide is in the flow; the rest are not rendered, so
 * the card is exactly as tall as what it is showing. */
.rx-highlight[hidden] { display: none; }

.rx-highlight-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}
.rx-highlight-nav { display: flex; align-items: center; gap: var(--s-1); }
.rx-highlight-dots { display: flex; align-items: center; gap: 5px; margin: 0 var(--s-1); }
.rx-highlight-dot {
  width: 6px; height: 6px;
  padding: 0;
  border: none;
  border-radius: var(--r-pill);
  background: var(--border-strong);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}
.rx-highlight-dot[aria-current="true"] { background: var(--brand); }
.rx-highlight-dot:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.rx-highlight-step {
  width: 28px; height: 28px;
  font-size: 0.75rem;
}

/* --- 21.4 Tighter cards ---------------------------------------------
 * Every card was built on --s-4 gaps and --s-5/--s-6 padding, which on a
 * phone spends most of the screen on air. One step down across the
 * board; the rhythm is unchanged, it is just closer together. */
.rx-result { gap: var(--s-3); padding: var(--s-4); }
.rx-result-body { gap: var(--s-1); }
.rx-card { padding: var(--s-4); }
.rx-panel { padding: var(--s-4); }
.rx-facets { gap: var(--s-4); }
.rx-facet-group { gap: var(--s-2); }
.rx-toolbar { gap: var(--s-2); margin-bottom: var(--s-4); }
.rx-pagehead { margin-bottom: var(--s-4); }

/* --- 21.5 Small screens get small-screen sizes ----------------------
 * The type scale was a desktop scale shown on a phone. Phone screens
 * have the resolution to carry smaller text now, and the alternative -
 * desktop sizes in a 375px column - is four words per line.
 *
 * Done by moving the tokens rather than by restating rules, so every
 * component that reads them comes down together and nothing drifts. */
@media (max-width: 768px) {
  :root {
    /* One notch down the existing scale, in the same order it was
     * written - note --fs-base (13px) is SMALLER than --fs-md (14px) in
     * this system; --fs-md is the body size, --fs-base is dense UI. */
    --fs-xs:   0.625rem;    /* 11 -> 10 */
    --fs-sm:   0.6875rem;   /* 12 -> 11 */
    --fs-base: 0.75rem;     /* 13 -> 12 */
    --fs-md:   0.8125rem;   /* 14 -> 13 */
    --fs-lg:   0.875rem;    /* 16 -> 14 */
    --fs-xl:   1rem;        /* 19 -> 16 */
    --fs-2xl:  1.1875rem;   /* 22 -> 19 */
    --fs-3xl:  1.5rem;      /* 32 -> 24 */

    --s-4: 0.75rem;   /* 16 -> 12 */
    --s-5: 1rem;      /* 20 -> 16 */
    --s-6: 1.25rem;   /* 24 -> 20 */
    --s-8: 1.5rem;    /* 32 -> 24 */
  }
  .rx-main { padding: var(--s-4) var(--s-3); }
  .rx-highlight-stat { font-size: 1.125rem; }
  .rx-highlight { padding: var(--s-4); }
}

@media (max-width: 480px) {
  .rx-main { padding: var(--s-3) var(--s-2); }
}

/* --- 21.6 The secondary pages run flush -----------------------------
 * library.php, centers.php, advanced-search.php, terms.php and
 * privacy.php were built on the pre-rx wrappers: .main-content-area
 * carried an inline padding: 30px, .dashboard-panel added its own, and
 * the two stacked into a wide empty margin down both sides that the
 * home page does not have.
 *
 * Those pages are converted to .rx-shell / .rx-main; this strips what is
 * left of the old wrappers so nothing double-pads if one is missed. */
.rx-main > .rx-content-flush { max-width: none; width: 100%; }
.rx-main .dashboard-panel,
.rx-main .main-content-area,
.rx-main .content { padding: 0; margin: 0; max-width: none; background: none; box-shadow: none; border: none; }


/* --- 21.7 The admin portal becomes responsive -----------------------
 * The admin sidebar "did not work on other screen sizes" for exactly the
 * reason the public one did not: reachadmin.css parks it off-canvas
 * below 768 and slides it back on `.admin-sidebar.active`, while
 * admin-chrome.js only ever toggled `.collapsed`. Nothing set `active`,
 * so the rail sat at left: -100% and the burger looked dead.
 *
 * admin-chrome.js sets it now. What is missing on this side is the
 * scrim, the scroll lock and any breakpoint between 768 and the desktop
 * layout - the portal had 768 and 480 and nothing else. */

/* The drawer must clear the admin header, which is 70px, not --header-h. */
.admin-scrim {
  position: fixed;
  inset: 70px 0 0 0;
  z-index: 1999;                 /* .admin-sidebar is 2000 when open */
  background: rgba(17, 24, 39, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease);
}
.admin-scrim.is-open { opacity: 1; pointer-events: auto; }

.admin-sidebar-close { display: none; }

@media (max-width: 768px) {
  .admin-sidebar {
    width: min(84vw, 210px);
    box-shadow: var(--shadow-lg);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-top: 0;
  }
  .admin-sidebar.active { width: min(84vw, 210px); }

  /* Same correction as the public drawer: the close control is top
   * right, and its row is the only gap above the first nav item. */
  .admin-sidebar-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px; height: 40px;
    margin: var(--s-1) var(--s-1) var(--s-1) auto;
    background: transparent;
    border: none;
    border-radius: var(--r-pill);
    color: var(--text-muted);
    font-size: 1rem;
    cursor: pointer;
  }
  .admin-sidebar-close:hover { background: var(--surface-sunken); color: var(--text); }
  .admin-sidebar-close:focus-visible { outline: none; box-shadow: var(--focus-ring); }

  /* Below 768 the rail is a drawer, so it is never the icon strip. */
  .admin-sidebar { width: min(84vw, 210px); }
  .admin-sidebar .nav-item { justify-content: flex-start; padding: 0 15px; width: auto; margin: 0; }
  .admin-sidebar .nav-item span:not(.nav-badge) { display: inline; opacity: 1; }
  .admin-sidebar .nav-badge { position: relative; top: 0; right: 0; width: auto; height: 20px; padding: 0 6px; }

  .admin-header { height: 56px; }
  .admin-sidebar { top: 56px; height: calc(100vh - 56px); }
  .admin-scrim { inset: 56px 0 0 0; }
  .admin-layout-wrapper { min-height: calc(100vh - 56px); }
}

/* The steps the portal never had. Content padding comes down with the
 * viewport instead of staying at a desktop 30px. */
@media (max-width: 1024px) {
  .admin-content-area { padding: var(--s-5); }
  .dashboard-panel { padding: var(--s-5); }
}
@media (max-width: 900px) {
  .admin-content-area { padding: var(--s-4); }
  .dashboard-panel { padding: var(--s-4); }
  /* auto-fit with a 400px minimum cannot fit two columns below 900 and
     will not drop to one on its own once the gap is counted. */
  .chart-grid { grid-template-columns: minmax(0, 1fr); }
  .form-row-2, .form-row-equal { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  .form-layout-grid { gap: var(--s-6); }
}
@media (max-width: 768px) {
  .admin-content-area { padding: var(--s-4) var(--s-3); }
  .dashboard-panel { padding: var(--s-3); border-radius: var(--r-md); }
  .header-actions { padding-right: var(--s-3); }
}
@media (max-width: 560px) {
  .admin-content-area { padding: var(--s-3) var(--s-2); }
}

/* A table cannot reflow, so below the tablet step it scrolls inside its
 * own box rather than making the whole page scroll sideways. */
@media (max-width: 900px) {
  .admin-content-area .table-wrapper,
  .admin-content-area .dataTables_wrapper,
  .admin-content-area .dataTables_scroll { overflow-x: auto; }
  .admin-content-area table { min-width: 640px; }
}

/* --- 21.8 The admin control rows fit the screen ---------------------
 * Every manage view opens with a row of controls - a 260px search box, a
 * sort select, a couple of buttons - laid out as a flex row with fixed
 * widths. On a phone that row is 445px wide inside a 390px column, so
 * the sort control and half the search box sat outside the window.
 *
 * They wrap and go full width below the tablet step instead. The fixed
 * 260px is the only reason they could not. */
@media (max-width: 768px) {
  .manage-controls,
  .view-controls,
  .sort-control-wrapper,
  .multi-select-wrapper,
  .repo-pagination-wrapper { flex-wrap: wrap; gap: var(--s-2); }

  .search-form-wrapper { width: 100%; }
  .search-input-box { width: 100%; box-sizing: border-box; }

  .manage-controls > *,
  .view-controls > * { min-width: 0; }
  .manage-controls select,
  .view-controls select { flex: 1 1 auto; min-width: 0; max-width: 100%; }

  /* A table cannot reflow; it scrolls inside its own box rather than
   * taking the page sideways with it. */
  .admin-table-wrapper { overflow-x: auto; }
  .admin-table { min-width: 560px; }
}

/* --- 21.9 The admin list rows stack ---------------------------------
 * .repo-list-card is a flex row: a text column, then a stats block, then
 * the action buttons - all `flex-shrink: 0` except the text. On a phone
 * the buttons alone are wider than the column, so the text was squeezed
 * to a clientWidth of ZERO and every title showed as an ellipsis. The
 * page listed publications without naming any of them.
 *
 * The row becomes a stack below the tablet step, and the title wraps
 * instead of truncating - there is room for two lines here and no room
 * at all for a single one. */
/* The desktop truncation manage_content.php used to write inline. Kept as
 * a class so a media query can undo it - which is the whole reason it was
 * moved out of the markup. */
.repo-list-title {
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 500px;
  display: inline-block;
}

@media (max-width: 768px) {
  /* Below the tablet step there is room for two lines and no room at all
   * for one, so the title wraps rather than ending in an ellipsis. */
  .repo-list-title {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    max-width: none;
    display: block;
  }
  .repo-list-card { flex-direction: column; align-items: stretch; gap: var(--s-3); }
  .repo-list-main { padding-right: 0; }
  .repo-list-title { font-size: 1rem; }
  .repo-list-meta { font-size: 0.8125rem; }
  .repo-list-stats { gap: var(--s-4); flex-wrap: wrap; }
  .stat-item { text-align: left; }

  .manage-header-row { flex-direction: column; align-items: stretch; gap: var(--s-3); }
  .repo-pagination-wrapper { gap: var(--s-2); }
}

/* ============================================================
   UNIFIED COMPONENTS  —  one design across home and admin
   ------------------------------------------------------------
   The frontend is the baseline. Everything below is defined in
   design tokens only, and this file loads LAST on both sides,
   so these rules win over reachhome.css and reachadmin.css.

   Covers the four families that had drifted apart:
     1. modals        (moved to reach-chrome.css "DIALOGS")
     2. pagination    (.rx-pager)
     3. tables        (.rx-table / .rx-tablewrap)
     4. notice lists  (.notif-item, used by notifications AND
                       the admin feedback inbox)

   Legacy class names are aliased rather than deleted, so a view
   that has not been converted yet still picks up the new look.
   ============================================================ */

/* ---------- 1. MODAL --------------------------------------- */

/* Moved: "DIALOGS" in reach-chrome.css covers every dialog on both
   sides. The page-level overlays (.rx-modal-overlay, .notif-modal-*,
   .feedback-modal-*) are no longer used. */

/* ---------- 2. PAGINATION ---------------------------------- */

/* .rx-pager is the frontend's numbered pager. The admin views used
   .repo-pagination-wrapper, which was prev / current / next with no
   page numbers; home/profile.php used a third set. All three now
   render as the numbered pager. */
.repo-pagination-wrapper,
.pagination-bar,
.pagination-controls-group {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  padding-top: var(--s-4);
  flex-wrap: wrap;
}
.pagination-bar { justify-content: space-between; }
.pagination-info { font-size: var(--fs-sm); color: var(--text-muted); }

.repo-pagination-wrapper > a,
.repo-pagination-wrapper > button,
.repo-page-btn,
.btn-page,
.repo-page-current {
  min-width: 34px;
  height: 34px;
  padding: 0 var(--s-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--text-muted);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.repo-pagination-wrapper > a:hover,
.repo-pagination-wrapper > button:hover,
.repo-page-btn:hover:not(:disabled),
.btn-page:hover:not(:disabled) { background: var(--surface-sunken); color: var(--text); }

.repo-page-current {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-weight: var(--fw-semibold);
  cursor: default;
}
.repo-page-btn:disabled,
.btn-page:disabled { opacity: 0.4; cursor: not-allowed; }
.repo-pagination-wrapper > a:focus-visible,
.repo-pagination-wrapper > button:focus-visible,
.repo-page-btn:focus-visible,
.btn-page:focus-visible { outline: none; box-shadow: var(--focus-ring); }

@media (max-width: 640px) {
  .repo-pagination-wrapper > a,
  .repo-pagination-wrapper > button,
  .repo-page-btn, .btn-page, .repo-page-current { min-width: 40px; height: 40px; }
  .pagination-bar { flex-direction: column; gap: var(--s-3); }
}

/* ---------- 3. TABLES -------------------------------------- */

/* .admin-table and .ledger-table were two more copies of the same
   idea with different padding, type scale and border colours.
   Both now resolve to the .rx-table treatment. */
.admin-table-wrapper,
.ledger-table-wrapper {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  overflow-x: auto;
}
.admin-table,
.ledger-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-base);
}
.admin-table thead th,
.ledger-table th {
  padding: var(--s-3) var(--s-4);
  background: var(--page);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: left;
  white-space: nowrap;
}
.admin-table tbody td,
.ledger-table td {
  padding: 13px var(--s-4);
  border-bottom: 1px solid var(--border);
  color: var(--text);
  vertical-align: middle;
}
.admin-table tbody tr:last-child td,
.ledger-table tr:last-child td { border-bottom: none; }
.admin-table tbody tr,
.ledger-table tr { transition: background-color var(--t-fast) var(--ease); }
.admin-table tbody tr:hover,
.ledger-table tr:hover td { background: var(--n-25); }
.admin-table .actions,
.ledger-table .actions { text-align: right; white-space: nowrap; }
.admin-table .actions > * + * { margin-left: var(--s-2); }
.admin-table .num,
.ledger-table .num { text-align: right; font-variant-numeric: tabular-nums; }

@media (max-width: 768px) {
  .admin-table, .ledger-table { min-width: 720px; }
}

/* ---------- 4. NOTICE LIST --------------------------------- */

/* One list design for the contributor's notifications, the admin
   inbox and the admin feedback inbox. Previously three. */
.notif-container,
.notif-list-wrapper {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
}
.notif-item {
  padding: var(--s-5) var(--s-6);
  border-bottom: 1px solid var(--border);
  display: flex;
  gap: var(--s-5);
  align-items: flex-start;
  background: var(--surface);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--surface-hover, var(--n-25)); }
.notif-item.unread { background: var(--brand-tint, rgba(32, 101, 10, 0.03)); }
.notif-item.unread:hover { background: rgba(32, 101, 10, 0.06); }

.notif-icon {
  width: 45px;
  height: 45px;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 1.2rem;
  border: 1px solid var(--border);
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.notif-item.unread .notif-icon { background: var(--brand); color: #fff; border-color: var(--brand); }

.notif-content { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; }
.notif-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; gap: var(--s-2); }
.notif-title { margin: 0; font-size: var(--fs-md); color: var(--text); font-weight: var(--fw-bold); }
.notif-item.unread .notif-title { color: var(--brand); }
.notif-badge {
  font-size: var(--fs-xs);
  background: var(--danger);
  color: #fff;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  margin-left: var(--s-2);
  text-transform: uppercase;
  font-weight: var(--fw-bold);
  letter-spacing: 0.05em;
  vertical-align: middle;
}
.notif-date { font-size: var(--fs-sm); color: var(--text-muted); white-space: nowrap; flex-shrink: 0; }
.notif-message {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.notif-item.unread .notif-message { color: var(--text); font-weight: var(--fw-semibold); }

.notif-empty-state,
.inbox-empty {
  min-height: 380px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--s-8) var(--s-5);
  text-align: center;
  color: var(--text-muted);
}

/* The per-row dismiss. Sits inside the row but outside the area
   that opens it, so removing a notice never also opens it. */
.rx-notif-del {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--r-pill);
  color: var(--text-subtle);
  font-size: var(--fs-md);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.notif-item:hover .rx-notif-del,
.rx-notif-del:focus-visible { opacity: 1; }
.rx-notif-del:hover { background: var(--danger-tint, rgba(220, 38, 38, 0.08)); color: var(--danger); }
.rx-notif-del:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Touch devices have no hover, so the control must always be there. */
@media (hover: none) {
  .rx-notif-del { opacity: 1; }
}

/* The bulk actions above the list. */
.rx-notif-actions { display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: center; }

@media (max-width: 560px) {
  .notif-item { padding: var(--s-4); gap: var(--s-3); }
  .notif-icon { width: 32px; height: 32px; font-size: 1rem; border-radius: var(--r-sm); }
  .notif-header { flex-wrap: wrap; }
  .rx-notif-actions { width: 100%; }
  .rx-notif-actions > * { flex: 1 1 auto; justify-content: center; }
}

/* ---------- 5. STRAY: .rx-eyebrow --------------------------- */

/* detail.php and reader.js both render .rx-eyebrow ("Metrics",
   "More publications") and no stylesheet ever defined it, so those
   labels shipped as unstyled body text. Defined here so the record
   page reads the same on both sides. */
.rx-eyebrow {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ---------- 6. STATUS BADGES, LABELS, NOTES ----------------- */

/* The admin views drew status chips with inline styles and hardcoded
   hex - "background: #dcfce7; color: #16a34a" repeated in six files,
   each with slightly different padding and radius. One chip, four
   tones, defined once. */
.rx-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 4px var(--s-3);
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  line-height: 1.4;
}
.rx-badge-ok {
  background: var(--ok-50, #dcfce7);
  color: var(--ok-700, #15803d);
  border-color: var(--ok-200, #bbf7d0);
}
.rx-badge-warn {
  background: var(--warn-50, #fef3c7);
  color: var(--warn-700, #b45309);
  border-color: var(--warn-200, #fde68a);
}
.rx-badge-danger {
  background: var(--danger-50, #fee2e2);
  color: var(--danger-700, #b91c1c);
  border-color: var(--danger-200, #fecaca);
}
.rx-badge-muted {
  background: var(--surface-sunken);
  color: var(--text-muted);
  border-color: var(--border);
}

/* Form label, to match .rx-select and .rx-input. */
.rx-label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text);
}

/* A short inline notice - "no source material found". */
.rx-note {
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  text-align: center;
}
.rx-note-danger {
  background: var(--danger-50, #fee2e2);
  border-color: var(--danger-200, #fecaca);
  color: var(--danger-700, #b91c1c);
}

/* ---------- 7. FILE CARD PREVIEW: IMAGE VARIANT --------------- */

/* .rx-filecard-preview was written for the reader, where it only ever
   holds an icon and a caption - so reach-ui.css styled `i` and `span`
   inside it and nothing else. The admin record view puts a real cover
   image in the same box, and with no rule to constrain it the image
   rendered at its natural size: a 2000px logo burst out of the 168px
   card and across the page.

   Absolutely positioned rather than flex-sized, because the parent is a
   centring flex column and percentage heights inside one are unreliable
   across browsers. inset:0 pins the image to the box whatever it is. */
.rx-filecard-preview {
  position: relative;
  overflow: hidden;
}
.rx-filecard-preview img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ============================================================
   22. METRIC CHIPS - views, downloads, citations
   ------------------------------------------------------------
   Identical at the end of BOTH copies of this file.

   They were grey 12px text in a row - the quietest thing on a
   card, although they are the numbers people compare records
   by. Each is now a small pill in the chip style the site
   already uses (the green of the active nav item, the gold of
   the accent), with the number set bold and darker than its
   word:

       views, downloads   brand tint   (green)
       citations          accent tint  (gold - scholarly use)

   A zero stays a plain neutral chip: a bright "0 citations"
   highlights nothing and makes every new record look worse.

   Every card, row and list that shows these numbers builds
   them with one helper - RX.metrics() in rx-core.js on the
   page, Metrics::chips() in PHP - so they cannot drift apart
   again (the grid had no labels, the admin list had no
   citations and called downloads "accesses" on one page and
   "downloads" on the next).

   .rx-metrics-compact (the grid cards) shows icon and number
   only; the word stays in the markup for screen readers and
   in the tooltip.
   ============================================================ */
.rx-metrics { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-top: var(--s-2); }

.rx-metric {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 10px;
  box-sizing: border-box;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: 1;
  white-space: nowrap;
}
.rx-metric i { font-size: 0.75rem; color: var(--text-subtle); }
.rx-metric strong {
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.rx-metric-views,
.rx-metric-downloads { background: var(--brand-tint); border-color: var(--brand-tint-line); color: var(--brand-ink); }
.rx-metric-views i,
.rx-metric-downloads i { color: var(--brand); }
.rx-metric-views strong,
.rx-metric-downloads strong { color: var(--brand-ink); }

.rx-metric-citations { background: var(--accent-tint); border-color: var(--accent-tint); color: var(--accent-ink); }
.rx-metric-citations i,
.rx-metric-citations strong { color: var(--accent-ink); }

/* Nothing to highlight yet. */
/* Muted, not faint: the number must still meet text contrast. */
.rx-metric.is-zero { background: var(--surface-sunken); border-color: var(--border); color: var(--text-muted); }
.rx-metric.is-zero i { color: var(--text-subtle); }
.rx-metric.is-zero strong { color: var(--text-muted); font-weight: var(--fw-semibold); }

/* Grid cards: icon + number; the word is for screen readers. */
.rx-metrics-compact { gap: 6px; }
.rx-metrics-compact .rx-metric { height: 24px; padding: 0 8px; gap: 5px; }
.rx-metrics-compact .rx-metric-label {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* On a card the chips sit at the foot, under the author. */
.rx-card-foot { flex-wrap: wrap; gap: 6px; }
.rx-card-foot .rx-metrics { margin-top: 0; }

/* =====================================================================
 *  23. ADVANCED SEARCH  (home/advanced-search.php)
 *
 *  The form: keywords take two columns, everything else one, on a grid
 *  that goes 3 -> 2 -> 1 columns with the screen. The results below use
 *  the home page's rows, cards and pager unchanged.
 * ===================================================================== */
.adv-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-5) var(--s-5);
  align-items: start;
}
.adv-wide { grid-column: span 2; }

/* A label that is not a <label> (it names a group of inputs). */
.adv-label { font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text); }

.adv-range { display: flex; align-items: center; gap: var(--s-2); }
.adv-range .rx-input { flex: 1; min-width: 0; }
.adv-range > span { font-size: var(--fs-sm); color: var(--text-muted); }


.adv-pills:empty { display: none; }

.adv-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--s-2);
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--border);
}

.adv-results { margin-top: var(--s-6); }
.adv-chip-key { font-weight: var(--fw-semibold); }

/* While the next page loads, the current one stays in place, dimmed,
   instead of the list collapsing and the page jumping. */
#adv-results.is-loading { opacity: 0.55; pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  #adv-results { transition: opacity var(--t-fast) var(--ease); }
}

@media (max-width: 1100px) {
  .adv-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .adv-wide { grid-column: 1 / -1; }
}
.adv-toggle { display: none; }

@media (max-width: 640px) {
  .adv-toggle { display: flex; width: 100%; min-height: 42px; justify-content: flex-start; }
  .adv-toggle-chev { margin-left: auto; }
  .adv-panel:not(.is-collapsed) .adv-toggle { margin-bottom: var(--s-4); }
  .adv-panel:not(.is-collapsed) .adv-toggle-chev { transform: rotate(180deg); }
  .adv-panel.is-collapsed { padding: var(--s-3); }
  .adv-panel.is-collapsed .adv-form { display: none; }
  .adv-grid { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  .adv-actions { flex-direction: column-reverse; }
  .adv-actions .rx-btn { width: 100%; min-height: 42px; }
}

/* =====================================================================
 *  24. PLACEHOLDERS
 *
 *  The one-time-code box is set in large, widely spaced digits. Its
 *  placeholder is an instruction ("Enter the 6-digit code"), not six
 *  dashes, so it is drawn at normal size and spacing to fit the box.
 * ===================================================================== */
.auth-otp-input::placeholder {
  font-size: var(--fs-md);
  font-weight: var(--fw-regular);
  letter-spacing: normal;
  color: var(--text-subtle);
}

/* =====================================================================
 *  25. MY PROFILE AND THE SUBMISSIONS LEDGER  (home/profile.php)
 *
 *  The profile was the last page on the pre-rx wrappers, with the old
 *  .profile-header-wrapper / .metrics-grid / .metric-card set on top:
 *  roughly double the margins of every other page, a header whose long
 *  lines (a center's full name) ran off the right edge and pushed the
 *  page sideways on a phone, and figures that did nothing when pressed.
 *
 *  One vertical rhythm now (--s-5 between blocks, the same as the home
 *  page), every text line allowed to wrap inside its column, and the
 *  ledger built from the repository's own list and card components.
 * ===================================================================== */
.rx-profile { display: flex; flex-direction: column; gap: var(--s-5); }

/* --- identity --- */
.rx-profile-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-4) var(--s-5);
  padding: var(--s-5) var(--s-6);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.rx-profile-avatar {
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: var(--brand);
  color: var(--text-on-brand);
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  letter-spacing: 0.02em;
  flex-shrink: 0;
}
.rx-profile-id { min-width: 0; }
.rx-profile-namerow { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2) var(--s-3); }
.rx-profile-namerow .rx-pagetitle { overflow-wrap: anywhere; }
.rx-profile-meta {
  list-style: none;
  margin: var(--s-2) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-5);
}
.rx-profile-meta li {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  min-width: 0;
  max-width: 100%;
  font-size: var(--fs-md);
  color: var(--text-muted);
}
.rx-profile-meta li i { flex-shrink: 0; width: 14px; text-align: center; color: var(--text-subtle); font-size: 0.8rem; }
.rx-profile-meta li span { min-width: 0; overflow-wrap: anywhere; }
.rx-profile-actions { display: flex; gap: var(--s-2); }

/* --- the figures: each one a way into the ledger --- */
.rx-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-3); }
.rx-kpi {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--s-4) var(--s-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  color: var(--text);
  text-decoration: none;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.rx-kpi:hover { border-color: var(--brand); box-shadow: var(--shadow-sm); }
.rx-kpi:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.rx-kpi-label { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text-muted); }
.rx-kpi-label i { color: var(--text-subtle); font-size: 0.8rem; }
.rx-kpi-value { font-size: var(--fs-3xl); font-weight: var(--fw-bold); line-height: 1.15; font-variant-numeric: tabular-nums; color: var(--text); }
.rx-kpi-hint { display: flex; align-items: center; gap: var(--s-1); font-size: var(--fs-sm); color: var(--text-subtle); transition: color var(--t-fast) var(--ease); }
.rx-kpi-hint i { font-size: 0.7rem; }
.rx-kpi:hover .rx-kpi-hint, .rx-kpi:focus-visible .rx-kpi-hint { color: var(--brand-ink); }

/* --- the ledger --- */
.rx-ledger { scroll-margin-top: calc(var(--header-h) + var(--s-4)); outline: none; }
.rx-ledger-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s-4); margin-bottom: var(--s-3); }
.rx-sectiontitle { margin: 0; font-size: var(--fs-xl); font-weight: var(--fw-semibold); line-height: var(--lh-tight); color: var(--text); }

/* Status: one row of toggles, each with its count. */
.rx-statusbar { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-3); }
.rx-statusbar button {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  height: 32px;
  padding: 0 var(--s-2) 0 var(--s-3);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--text-muted);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.rx-statusbar button:hover { border-color: var(--border-strong); color: var(--text); }
.rx-statusbar button:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.rx-statusbar button span {
  min-width: 22px;
  height: 20px;
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-pill);
  background: var(--surface-sunken);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}
.rx-statusbar button[aria-pressed="true"] { background: var(--brand-tint); border-color: var(--brand-tint-line); color: var(--brand-ink); }
.rx-statusbar button[aria-pressed="true"] span { background: var(--surface); }
.rx-statusbar button[hidden] { display: none; }

.rx-ledger-search { flex: 1 1 240px; max-width: 360px; height: 36px; }
.rx-field-inline[hidden] { display: none; }
button.rx-chip { font-family: var(--font-ui); cursor: pointer; }
.rx-chips[hidden] { display: none; }

.rx-btn-sm { min-height: 30px; padding: 0 var(--s-2); font-size: var(--fs-sm); gap: var(--s-1); }

/* List rows: the actions column holds one button. */
.rx-ledger-row .rx-result-actions { width: auto; min-width: 140px; }
.rx-ledger-row .rx-result-title span { color: var(--text-muted); }

/* Grid cards: status on top, the date or the counts and one action at
   the foot. */
.rx-ledger-card .rx-card-body { gap: var(--s-2); }
.rx-ledger-card .rx-card-title { font-size: var(--fs-md); overflow-wrap: anywhere; }
.rx-ledger-card .rx-card-title span { color: var(--text-muted); }
.rx-ledger-card .rx-card-meta { font-size: var(--fs-sm); overflow-wrap: anywhere; }
.rx-ledger-card .rx-card-foot { flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.rx-ledger-card .rx-card-foot .rx-metrics { margin-top: 0; gap: var(--s-3); }
.rx-card-date { font-size: var(--fs-sm); color: var(--text-muted); }
.rx-card-actions { margin-left: auto; display: flex; gap: var(--s-2); }

#pagination-controls:empty { display: none; }
.rx-profile .rx-danger-zone { margin-top: var(--s-5); }

@media (max-width: 1024px) {
  .rx-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 768px) {
  .rx-profile-head { grid-template-columns: auto minmax(0, 1fr); padding: var(--s-4); }
  .rx-profile-actions { grid-column: 1 / -1; }
  .rx-profile-actions .rx-btn { flex: 1; }
  .rx-ledger-row .rx-result-actions { min-width: 0; }
  /* The toolbar wraps on a phone: search on its own line, the three
     selects share the next, the layout toggle ends it. */
  .rx-toolbar.rx-ledger-toolbar { flex-wrap: wrap; }
  .rx-ledger-search { flex-basis: 100%; max-width: none; }
  .rx-ledger-toolbar .rx-spacer { display: none; }
  .rx-ledger-toolbar .rx-field-inline { flex: 1 1 0; min-width: 0; }
  .rx-ledger-toolbar .rx-field-inline label { display: none; }
  .rx-ledger-toolbar .rx-select { width: 100%; min-width: 0; }
  /* Status toggles scroll sideways rather than stacking four deep. */
  .rx-statusbar { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
  .rx-statusbar::-webkit-scrollbar { display: none; }
}
@media (max-width: 480px) {
  .rx-profile { gap: var(--s-4); }
  .rx-profile-avatar { width: 48px; height: 48px; font-size: var(--fs-lg); }
  .rx-profile-head { gap: var(--s-3) var(--s-4); align-items: start; }
  .rx-ledger-toolbar .rx-field-inline { flex: 1 1 calc(50% - var(--s-2)); }
  .rx-profile-meta { flex-direction: column; }
  .rx-kpis { gap: var(--s-2); }
  .rx-kpi { padding: var(--s-3) var(--s-4); }
  .rx-kpi-value { font-size: var(--fs-2xl); }
  .rx-kpi-hint { display: none; }
  .rx-toolbar.rx-ledger-toolbar { flex-wrap: wrap; }
}

/* =====================================================================
 *  26. CHOICE CARDS  (.rx-choice)  -  a radio group you can read
 *
 *  Used for the submission format on the three publication forms
 *  (home/submit.php, admin form_smart.php and edit_content.php). It was
 *  two plain radios, "PDF Document" and "External Link", while the file
 *  box under them said "PDF/Image" - so an image had to be uploaded
 *  under a choice called PDF. PDF, Image and External link are three
 *  cards now, each saying what it is for.
 *
 *      <div class="rx-choice" role="radiogroup" aria-label="...">
 *        <label class="rx-choice-item">
 *          <input type="radio" name="format_type" value="pdf">
 *          <span class="rx-choice-body">
 *            <i class="fas fa-file-pdf"></i>
 *            <span><strong>PDF document</strong><small>...</small></span>
 *          </span>
 *        </label>
 *        ...
 *      </div>
 * ===================================================================== */
/* Side by side where there is room for three readable cards, one per
   row where there is not (the form's narrow right-hand column). */
.rx-choice { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: var(--s-2); }
.rx-choice-item { position: relative; display: flex; margin: 0; cursor: pointer; }
.rx-choice-item input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.rx-choice-body {
  flex: 1;
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.rx-choice-body > i {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: 0.95rem;
}
.rx-choice-body > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rx-choice-body strong { font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text); line-height: var(--lh-tight); }
.rx-choice-body small { font-size: var(--fs-sm); font-weight: var(--fw-regular); color: var(--text-muted); line-height: var(--lh-normal); }
.rx-choice-item:hover .rx-choice-body { border-color: var(--text-subtle); }
.rx-choice-item input:checked + .rx-choice-body { border-color: var(--brand); background: var(--brand-tint); box-shadow: inset 0 0 0 1px var(--brand); }
.rx-choice-item input:checked + .rx-choice-body > i { background: var(--brand); color: var(--text-on-brand); }
.rx-choice-item input:focus-visible + .rx-choice-body { box-shadow: inset 0 0 0 1px var(--brand), var(--focus-ring); }

/* ---- Citations: details page and profile (assets/js/citations.js) ---- */
.rx-cite-btns { display: flex; flex-direction: column; gap: var(--s-2); align-items: stretch; flex-shrink: 0; }
a.rx-metric-tile { text-decoration: none; color: inherit; }
a.rx-metric-tile:hover { box-shadow: 0 0 0 1px var(--brand-tint-line) inset; }
.rx-citedby { margin-top: var(--s-6); scroll-margin-top: calc(var(--header-h) + var(--s-4)); }
.rx-citedby-count {
  display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: 999px;
  background: var(--accent-tint); color: var(--text); font-size: var(--fs-sm); vertical-align: middle;
}
.rx-citedby-empty { margin: 0; color: var(--text-muted); font-size: var(--fs-sm); }
.rx-citedby-list { margin: 0; padding-left: 1.4em; display: flex; flex-direction: column; gap: var(--s-3); }
.rx-citedby-title { font-weight: var(--fw-semibold); line-height: var(--lh-normal); overflow-wrap: anywhere; }
.rx-citedby-title a, .rx-cite-item-title a, .rx-cite-item-meta a { color: var(--brand-ink); text-decoration: none; }
.rx-citedby-title a:hover, .rx-cite-item-title a:hover, .rx-cite-item-meta a:hover { text-decoration: underline; }
.rx-citedby-meta { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.rx-citedby-tag {
  display: inline-block; margin-left: 4px; padding: 0 6px; border-radius: var(--r-sm);
  background: var(--brand-tint); color: var(--brand-ink); font-size: var(--fs-xs); font-weight: var(--fw-semibold); vertical-align: middle;
}
.rx-cite-form { display: flex; flex-direction: column; gap: var(--s-3); text-align: left; }
.rx-cite-form .rx-field > span { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text); }
.rx-cite-form .rx-field small { font-weight: normal; color: var(--text-muted); }
.rx-cite-form textarea.rx-input { min-height: 72px; resize: vertical; }
.rx-cite-form-row { display: grid; grid-template-columns: 1fr 140px; gap: var(--s-3); }
.rx-cite-form-lead { margin: 0 0 var(--s-3); color: var(--text-muted); font-size: var(--fs-sm); text-align: left; }
.rx-cite-form-or { text-align: center; color: var(--text-muted); font-size: var(--fs-sm); }
.rx-citations-panel { margin-top: var(--s-8); scroll-margin-top: calc(var(--header-h) + var(--s-4)); outline: none; }
.rx-cite-block { margin-top: var(--s-4); }
.rx-cite-block-title { margin: 0 0 var(--s-1); font-size: var(--fs-md); font-weight: var(--fw-semibold); display: flex; gap: 8px; align-items: center; }
.rx-cite-block .rx-help { margin: 0 0 var(--s-3); }
.rx-cite-empty { margin: 0; color: var(--text-muted); font-size: var(--fs-sm); }
.rx-cite-item {
  display: flex; gap: var(--s-4); justify-content: space-between; align-items: flex-start;
  padding: var(--s-3) var(--s-4); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); margin-bottom: var(--s-2);
}
.rx-cite-item-main { min-width: 0; flex: 1; }
.rx-cite-item-title { font-weight: var(--fw-semibold); overflow-wrap: anywhere; }
.rx-cite-item-meta { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.rx-cite-item-note { font-size: var(--fs-sm); color: var(--text); margin-top: var(--s-1); overflow-wrap: anywhere; }
.rx-cite-item-side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--s-2); flex-shrink: 0; max-width: 45%; }
.rx-cite-item-actions { display: flex; gap: var(--s-2); flex-wrap: wrap; justify-content: flex-end; }
.rx-cite-pill { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); text-align: right; }
.rx-cite-pill.is-wait { background: #fef3c7; color: #92400e; }
.rx-cite-pill.is-ok { background: var(--brand-tint); color: var(--brand-ink); }
.rx-cite-pill.is-off { background: var(--surface-sunken); color: var(--text-muted); }
@media (max-width: 640px) {
  .rx-cite-body { flex-direction: column; }
  .rx-cite-btns { flex-direction: row; flex-wrap: wrap; width: 100%; }
  .rx-cite-item { flex-direction: column; }
  .rx-cite-item-side { align-items: flex-start; max-width: none; }
  .rx-cite-item-actions { justify-content: flex-start; }
  .rx-cite-form-row { grid-template-columns: 1fr; }
}

/* ---- Submit revision dialog (profile.js) ---- */
.rx-revise { display: flex; flex-direction: column; gap: var(--s-3); text-align: left; }
.rx-revise label { display: block; font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text); margin-bottom: 4px; }
.rx-revise .rx-input { width: 100%; box-sizing: border-box; }
.rx-revise textarea.rx-input { min-height: 96px; resize: vertical; }
.rx-revise .rx-hint { font-size: var(--fs-xs); color: var(--text-muted); margin-top: 4px; }
.rx-revise-kind { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }
.rx-revise-box { padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--page); font-size: var(--fs-sm); overflow-wrap: anywhere; }
.rx-revise-box > strong { display: block; margin-bottom: 4px; color: var(--text); }
.rx-revise-forms { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.rx-revise-forms li + li { border-top: 1px solid var(--border); padding-top: var(--s-2); }
.rx-revise-forms a { display: inline-flex; gap: 6px; align-items: center; margin-top: 4px; color: var(--brand-ink); font-weight: var(--fw-semibold); text-decoration: none; }
.rx-revise-forms a:hover { text-decoration: underline; }
.rx-revise-notes { color: var(--text-muted); font-style: italic; margin-top: 2px; }

/* submit.php?revise=ID - revising a returned submission */
.rx-revise-panel { display: flex; flex-direction: column; gap: var(--s-3); margin-bottom: var(--s-5); border-left: 4px solid var(--warning); }
.rx-revise-panel-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-2) var(--s-3); }
.rx-revise-panel-head h3 { margin: 0; font-size: var(--fs-lg); color: var(--text); display: flex; gap: var(--s-2); align-items: baseline; min-width: 0; overflow-wrap: anywhere; }
.rx-revise-panel-head h3 i { color: var(--warning); flex-shrink: 0; }
.rx-revise-current { margin: 0 0 var(--s-2); display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-3); align-items: center; font-size: var(--fs-sm); color: var(--text); overflow-wrap: anywhere; }
.rx-revise-current i { color: var(--text-muted); }
.rx-revise-current a { color: var(--brand-ink); font-weight: var(--fw-semibold); }
.rx-hint-inline { margin: 0 0 var(--s-2); font-size: var(--fs-xs); color: var(--text-muted); overflow-wrap: anywhere; }
.rx-revise-missing { display: flex; flex-direction: column; align-items: center; gap: var(--s-3); text-align: center; padding: var(--s-8) var(--s-5); }
.rx-revise-missing > i { font-size: 2rem; color: var(--text-muted); }
.rx-revise-missing p { margin: 0; color: var(--text); }

/* Cited by: ten a page, numbered pages under the list */
.rx-citedby-range { margin: -4px 0 var(--s-3); font-size: var(--fs-sm); color: var(--text-muted); }
.rx-citedby-pager { padding-top: var(--s-4); }
.rx-citedby-pager:empty { display: none; }
.rx-citedby-pager[aria-busy="true"] { opacity: .6; }
/* One column: under the Metrics in the right rail, as its own panel */
.rx-citedby.is-in-rail {
  margin-top: 0; padding: var(--s-4); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-lg);
}
.rx-citedby.is-in-rail .rx-record-section-title { margin-top: 0; }

/* ---- References: one box per reference (reference-fields.js) ---------- */
.ref-fields { display: flex; flex-direction: column; gap: 8px; }
.ref-list { display: flex; flex-direction: column; gap: 8px; counter-reset: none; }
.ref-row {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) 30px; gap: 8px; align-items: start;
  padding: 6px 6px 6px 8px; border: 1px solid var(--border, #e2e8f0); border-radius: 10px;
  background: var(--surface, #fff); transition: border-color .15s ease, box-shadow .15s ease;
}
.ref-row:focus-within { border-color: var(--brand, var(--primary-color, #20650a)); box-shadow: 0 0 0 3px rgba(32, 101, 10, .12); }
.ref-num {
  margin-top: 7px; width: 24px; height: 24px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-sunken, #f1f5f9); color: var(--text-muted, #64748b);
  font-size: 0.72rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.ref-row:focus-within .ref-num { background: var(--brand, var(--primary-color, #20650a)); color: #fff; }
.ref-input {
  display: block; width: 100%; min-height: 38px; margin: 0; padding: 8px 2px; box-sizing: border-box;
  border: 0; outline: 0; background: transparent; resize: none; overflow: hidden;
  font: inherit; font-size: 0.9rem; line-height: 1.5; color: var(--text, var(--text-main, #0f172a));
  overflow-wrap: anywhere;
}
.ref-input::placeholder { color: var(--text-subtle, #94a3b8); }
.ref-remove {
  margin-top: 4px; width: 30px; height: 30px; border-radius: 8px; border: 1px solid transparent;
  background: transparent; color: var(--text-muted, #64748b); font-size: 1.15rem; line-height: 1; cursor: pointer;
}
.ref-remove:hover, .ref-remove:focus-visible { color: #dc2626; background: #fef2f2; border-color: #fecaca; outline: none; }
.ref-remove[hidden] { display: block; visibility: hidden; }
.ref-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.ref-add {
  display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 8px; cursor: pointer;
  border: 1px dashed var(--border-strong, #cbd5e1); background: transparent;
  color: var(--brand-ink, var(--primary-color, #20650a)); font: inherit; font-size: 0.88rem; font-weight: 600;
}
.ref-add:hover { border-style: solid; border-color: var(--brand, var(--primary-color, #20650a)); background: rgba(32, 101, 10, .05); }
.ref-add:disabled { opacity: .5; cursor: not-allowed; }
.ref-count { font-size: 0.8rem; color: var(--text-muted, #64748b); font-variant-numeric: tabular-nums; }
.ref-hint { margin: 0; font-size: 0.78rem; color: var(--text-muted, #64748b); }
@media (max-width: 640px) {
  .ref-row { grid-template-columns: 22px minmax(0, 1fr) 30px; gap: 6px; padding-left: 6px; }
  .ref-num { width: 22px; height: 22px; }
}

/* ---- Citations added by hand: marks, and the profile block ------------ */
.rx-citedby-tag.is-manual   { background: #eff6ff; color: #1d4ed8; }
.rx-citedby-tag.is-proven   { background: #f0fdf4; color: #15803d; }
.rx-citedby-tag.is-unproven { background: #fffbeb; color: #b45309; }
.rx-citedby-kinds { margin: -4px 0 var(--s-3); font-size: var(--fs-sm); color: var(--text-muted); }
.rx-cite-block-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap; }
.rx-cite-block-head .rx-cite-block-title { margin: 0; }
.rx-cite-form-hint { display: block; margin-top: 2px; font-size: var(--fs-xs); color: var(--text-muted); font-weight: normal; }
.rx-cite-range { margin: 0 0 var(--s-2); font-size: var(--fs-sm); color: var(--text-muted); }
.rx-cite-pager { padding-top: var(--s-3); }

/* ============================================================
   TIPS - short, friendly help under a field or section (they replaced
   the long "How to add" boxes). A small icon and one or two lines of
   muted text; no box, so they never shout over the form.
   ============================================================ */
.rx-tip { display: flex; align-items: flex-start; gap: 8px; margin: 8px 0 0; font-size: var(--fs-sm); line-height: 1.45; color: var(--text-muted); text-align: left; }
.rx-tip > i { flex: none; margin-top: 2px; font-size: 0.95em; color: var(--accent, #D88302); }
.rx-tip > i.fa-circle-info { color: var(--text-subtle, #9CA3AF); }
.rx-tip strong { color: var(--text); font-weight: var(--fw-semibold); }
.rx-tip-lead { margin: 0 0 var(--s-4); }
