/* PM4 base. Mobile physics are non-negotiable:
   16px inputs (below it iOS Safari auto-zooms on focus), 54px inputs, 48px buttons,
   100svh not vh, no horizontal scroll to 380px, pinch-zoom never disabled. */

*, *::before, *::after { box-sizing: border-box; }

/* The `hidden` attribute must win over any author `display` rule. Without this, a
   `.btn` (display:inline-flex) marked `hidden` still shows — which is exactly how the
   retry button appeared with zero failures. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg-black);
  color: var(--text-white);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

body.app-respondent { font-size: 16px; }

/* Browsers give <p> a 1em margin. We drive vertical rhythm from the spacing scale,
   so reset it and let .stack / explicit margins do the work. */
p { margin: 0; }
p + p { margin-top: var(--s3); }

/* Focus: global, never suppressed. Cyan is used for nothing else. */
:focus-visible {
  outline: 3px solid var(--accent-cyan);
  outline-offset: 3px;
}

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

.topbar {
  position: sticky; top: 0; z-index: 10;
  height: 64px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--s4);
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
}

.topbar__brand {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-gray);
}

.topbar__who { font-size: 13px; color: var(--text-dim); }
@media (max-width: 768px) { .topbar__who { display: none; } }

.wrap { max-width: 980px; margin: 0 auto; padding: var(--s6) var(--s4) var(--s9); }
.wrap--narrow { max-width: 460px; }

.center-screen {
  min-height: 100svh;
  display: flex; align-items: center; justify-content: center;
  padding: var(--s4);
}

/* ---------- type ---------- */

h1, h2, h3 { margin: 0 0 var(--s3); font-weight: 700; line-height: 1.2; }
h1 { font-size: 28px; }
h2 { font-size: 21px; }
h3 { font-size: 17px; }

.kicker {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: var(--s2);
}

.muted { color: var(--text-muted); }
.dim   { color: var(--text-dim); font-size: 13px; }

/* Intro paragraph under a heading — needs room before the content it introduces. */
.lede { color: var(--text-muted); margin-bottom: var(--s5); }

/* ---------- card ---------- */

.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: var(--s6);
}

.card + .card { margin-top: var(--s4); }

.card--link {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--bg-interactive);
}
.card--link:hover { border-color: var(--border-light); }

.card__title { margin: var(--s3) 0 var(--s1); font-size: 17px; font-weight: 700; }

.link { color: var(--text-gray); }
.link:hover { color: var(--text-white); }

/* ---------- forms ---------- */

.field { margin-bottom: var(--s4); }

.label {
  display: block;
  margin-bottom: var(--s2);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-gray);
}

.input {
  width: 100%;
  min-height: 54px;
  padding: 0 var(--s4);
  font-size: 16px;               /* iOS zoom threshold — do not lower */
  font-family: var(--font);
  color: var(--text-white);
  background: var(--bg-interactive);
  border: 1px solid var(--border-light);
  border-radius: var(--r-control);
}

.input--pin { font-family: var(--mono); letter-spacing: .3em; }

/* Style the native file button. NEUTRAL, not teal — teal is reserved for the primary
   action, and on the import screen that is "Import", not "Choose File". */
.input[type="file"] { padding-top: 12px; }
.input::file-selector-button {
  min-height: 40px;
  margin-right: var(--s3);
  padding: 0 var(--s4);
  font-family: var(--font);
  font-weight: 700;
  font-size: 13px;
  color: var(--text-white);
  background: var(--bg-elevated);
  border: 1px solid var(--border-light);
  border-radius: var(--r-control);
  cursor: pointer;
}
.input::file-selector-button:hover { background: var(--bg-disabled); }

@media (max-width: 768px) {
  .center-screen .input { min-height: 58px; font-size: 18px; }
}

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%;
  min-height: 48px;
  padding: 0 var(--s5);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  font-family: var(--font);
  color: var(--text-inverse);
  background: var(--accent-teal);
  border: 0;
  border-radius: var(--r-control);
  cursor: pointer;
}

.btn:hover { background: var(--accent-teal-h); }
.btn:disabled { background: var(--bg-disabled); color: var(--text-dim); cursor: not-allowed; }

.btn--ghost {
  background: transparent;
  color: var(--text-gray);
  border: 1px solid var(--border-light);
}
.btn--ghost:hover { background: var(--bg-elevated); }
.btn--small { min-height: 44px; width: auto; }

/* ---------- alerts ---------- */

.alert {
  padding: var(--s3) var(--s4);
  border-radius: var(--r-control);
  border: 1px solid var(--border-light);
  background: var(--bg-elevated);
  font-size: 14px;
  margin-bottom: var(--s4);
}

.alert--error   { border-color: var(--error);   color: var(--error); }
.alert--success { border-color: var(--success); color: var(--success); }
.alert--warn    { border-color: var(--warning); color: var(--warning); }

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

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  border: 1px solid var(--border-light);
  color: var(--text-gray);
}

.badge--teal  { border-color: var(--accent-teal); color: var(--accent-teal); }
.badge--warn  { border-color: var(--warning);     color: var(--warning); }
.badge--error { border-color: var(--error);       color: var(--error); }

/* ---------- utility ---------- */

/* ---------- the dump ---------- */

.note { background: var(--bg-elevated); margin-bottom: var(--s5); }
.note p + p { margin-top: var(--s2); }

/* The picker is the primary action of the whole product, so it is the loudest thing
   on the page. PM2 fully restyles the native control for the same reason. */
.picker {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  min-height: 132px;
  padding: var(--s5);
  text-align: center;
  background: var(--accent-teal);
  color: var(--text-inverse);
  border-radius: var(--r-card);
  cursor: pointer;
}
.picker:hover { background: var(--accent-teal-h); }
.picker__title { font-size: 18px; font-weight: 700; letter-spacing: .04em; }
.picker__hint  { font-size: 13px; opacity: .8; }
.picker:focus-within { outline: 3px solid var(--accent-cyan); outline-offset: 3px; }

#dump.is-over .picker { background: var(--accent-teal-h); }

.upload-status { min-height: 20px; margin-top: var(--s4); font-size: 14px; color: var(--text-muted); }
.upload-status--warn { color: var(--warning); }
.upload-status--ok   { color: var(--success); }

.count { margin-top: var(--s1); font-size: 13px; color: var(--text-dim); }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--s2);
  margin-top: var(--s4);
}

.shot { margin: 0; }
.shot__img {
  aspect-ratio: 3 / 4;
  background: var(--bg-well);
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  overflow: hidden;
}
.shot__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shot__state { margin-top: var(--s1); font-size: 11px; color: var(--text-dim); }

.shot[data-state="busy"]  .shot__img { border-color: var(--accent-cyan); }
.shot[data-state="error"] .shot__img { border-color: var(--error); }
.shot[data-state="error"] .shot__state { color: var(--error); }
.shot[data-state="dupe"]  .shot__state { color: var(--text-muted); }

.done-form { margin-top: var(--s7); }

/* ---------- staff: roster + review ---------- */

.wrap--wide { max-width: 1400px; }

/* .input carries width:100% from the base. In a flex row that becomes the flex basis,
   so `flex: 0 0 auto` pins the select at the full container width and shoves its
   siblings off-screen — which is why the search box had collapsed to 34px. Anything
   that must not grow needs width:auto here, and search needs min-width:0 to be allowed
   to shrink below its intrinsic size. */
.filters { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s4); }
.filters .input { min-height: 44px; }
.filters input[type="search"] { flex: 1 1 220px; min-width: 0; }
.filters select { flex: 0 0 auto; width: auto; }
.filters .btn { flex: 0 0 auto; }

/* Table and cards both render; CSS picks. No JS, no horizontal scroll, ever. */
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th, .table td { padding: var(--s3); text-align: left; border-bottom: 1px solid var(--border); }
.table th {
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-dim); font-weight: 700;
}
.table tbody tr:hover { background: var(--bg-card); }
.table .num { text-align: right; }
.cards { display: none; }

@media (max-width: 900px) {
  .table { display: none; }
  .cards { display: block; }
  .cards .card + .card { margin-top: var(--s3); }
}

/* Evidence left and large; fields right. The single layout decision both predecessors
   prove matters: PM3 inverted it and its reviewers never used the screen. */
.review { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: var(--s5); align-items: start; }
@media (max-width: 1100px) { .review { grid-template-columns: 1fr; } }

.evidence-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--s3); }
.evidence {
  display: block;
  /* Reserve the box BEFORE the image loads. Without this the box has no height until
     the (internet-latency) image arrives, so the grid renders as collapsed thin lines
     and looks broken. A phone screenshot is portrait, so reserve 3:4. */
  aspect-ratio: 3 / 4;
  background: var(--bg-well) center / 22px no-repeat;
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
  position: relative;
}
.evidence::after {
  /* a quiet "loading" affordance visible only while the box is empty */
  content: "";
  position: absolute; inset: 0;
  background: repeating-linear-gradient(45deg, transparent, transparent 10px, rgba(255,255,255,.02) 10px, rgba(255,255,255,.02) 20px);
}
.evidence:hover { border-color: var(--accent-cyan); }
.evidence img {
  position: relative;              /* sits above the ::after placeholder once loaded */
  width: 100%; height: 100%;
  object-fit: cover; object-position: top;   /* top of a screenshot carries the status/date */
  display: block;
  /* an inset edge so a near-white screenshot still has definition and doesn't read as empty */
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}

.review__fields .card + .card { margin-top: var(--s3); }

.field-row { display: grid; grid-template-columns: 84px 1fr 108px; gap: var(--s2); align-items: center; margin-bottom: var(--s2);
  padding: 2px var(--s2); border-radius: var(--r-control); }
.field-row__code { font-size: 11px; color: var(--text-dim); }
.field-row__src  { font-size: 10px; text-align: right; color: var(--text-dim); }
.input--slim { min-height: 38px; font-size: 14px; padding: 0 var(--s3); }

/* A cross-model disagreement is the one signal the structural checks can't produce.
   Draw the reviewer's eye and show what the second reader saw, so they can resolve it. */
.field-row--disagree { background: rgba(255, 102, 102, .08); }
.field-row--disagree .input { border-color: var(--error); }
/* nowrap: the 2nd reading is a date and must never fracture mid-token (2026-05- / 30). */
.field-row__alt { font-size: 10px; text-align: right; color: var(--error); font-family: var(--mono); white-space: nowrap; }
.field-row--nf .input { border-style: dashed; }

/* Confidence as a dot+label, not a pill — so it reads as a distinct quality signal beside
   the status pill instead of a second red pill that blurs into it. */
.conf { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-gray); white-space: nowrap; }
.conf::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--text-dim); flex: 0 0 auto; }
.conf--low::before    { background: var(--error); }
.conf--medium::before { background: var(--warning); }
.conf--high::before   { background: var(--success); }
.conf--low    { color: var(--error); }

/* Utilities last: they must win over component rules of equal specificity.
   .mono defined before .input silently lost the font-family battle, and machine
   identifiers rendered in sans. */
.mono { font-family: var(--mono); }

.stack > * + * { margin-top: var(--s4); }
.row { display: flex; align-items: center; gap: var(--s3); }
.spread { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
