/* pgraph — one stylesheet, two surfaces.
 *
 * The app serves this file; screen/report.py inlines it, because a report is
 * mailed and filed and has to stand alone. Keeping one file means the screen a
 * customer signs into and the document they print cannot drift apart.
 *
 * Three decisions worth knowing before editing:
 *
 * NO RED. A possible match is a question about a named colleague, not a verdict.
 * Only an NPI match asserts anything, and even that routes to OIG for identity
 * confirmation. Colour here says what KIND of evidence exists; it never says
 * "guilty". Severity is carried by structure and weight instead.
 *
 * MONOSPACE IS THE STRUCTURAL VOICE. Not a developer affectation: this product's
 * material is government CSVs, ten-digit NPIs, statutory codes like 1128a1, and
 * verification dates. Those want digit-precise setting. It is also the only
 * characterful face available -- the CSP blocks external fonts by design, so
 * there is no display face to load, and the personality has to come from
 * treatment.
 *
 * LIGHT ONLY, BOTH SURFACES. Deliberate. The report gets printed and filed, and
 * a dark app beside a light document is a worse inconsistency than no dark mode.
 * Print styles are real for the same reason: compliance work ends up on paper.
 */

:root {
  --ink: #16202b;
  --ink-soft: #3d4b5c;
  --muted: #5c6a7a;
  --paper: #f7f8fa;
  --surface: #ffffff;
  --rule: #dfe3e9;
  --rule-strong: #c3cbd6;
  --accent: #2d4ec8;
  --accent-deep: #1e3a9e;

  /* Evidence signals only. Never status-of-person signals. */
  --verified: #0e6b5c;
  --attention: #8a5300;

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;

  --measure: 66rem;
}

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

body {
  margin: 0 auto 4rem;
  padding: 0 1.5rem;
  max-width: var(--measure);
  background: var(--paper);
  color: var(--ink);
  font: 15px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------------------
   Type scale. Tight tracking on the large sizes; the mono face is spaced wide
   so that uppercase labels read as record-keeping rather than as shouting.
   --------------------------------------------------------------------------- */

h1 {
  margin: 0 0 .35rem;
  font-size: 1.75rem;
  font-weight: 620;
  letter-spacing: -.021em;
  line-height: 1.2;
}

h2 {
  margin: 3rem 0 .25rem;
  font-size: 1.0625rem;
  font-weight: 620;
  letter-spacing: -.011em;
}

/* The structural voice. Used for eyebrows, column heads, and section kickers. */
.eyebrow, th, .tier, .seg-label {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted);
}

.meta { color: var(--muted); font-size: .8125rem; }
.meta strong { color: var(--ink-soft); font-weight: 600; }

/* Every identifier, date, and code. Tabular so columns of digits line up and a
   transposed NPI is visible rather than merely present. */
.mono, td.mono, .prov, .count, .num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

/* A timestamp is one token. On a narrow screen it was breaking into three lines
   ("2026-" / "08-05" / "08:17"), which reads as three values. */
td.mono { white-space: nowrap; }

.prov { font-size: .75rem; color: var(--muted); line-height: 1.45; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-deep); }

/* Quality floor, not decoration: keyboard users need to see where they are. */
a:focus-visible, button:focus-visible, input:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ---------------------------------------------------------------------------
   App chrome
   --------------------------------------------------------------------------- */

.bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 1.5rem;
  flex-wrap: wrap;
  margin: 0 -1.5rem 2.5rem;
  padding: 1rem 1.5rem .9rem;
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}

/* The wordmark is set in the same face as the data it presents. */
.brand {
  font-family: var(--mono);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--ink);
}
.brand-rule {
  display: inline-block;
  width: 1px;
  height: .8em;
  margin: 0 .6rem;
  background: var(--rule-strong);
  vertical-align: baseline;
}
.brand-note {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted);
}

.who { display: flex; align-items: baseline; gap: .75rem; font-size: .8125rem;
       color: var(--muted); }
.who form { display: inline; margin: 0; }

/* ---------------------------------------------------------------------------
   Controls
   --------------------------------------------------------------------------- */

button {
  font: 500 .875rem/1 var(--sans);
  padding: .6rem 1rem;
  border: 1px solid var(--accent);
  border-radius: 3px;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}
button:hover { background: var(--accent-deep); border-color: var(--accent-deep); }

button.quiet {
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-size: .8125rem;
  text-decoration: underline;
  text-underline-offset: 2px;
}
button.quiet:hover { background: none; color: var(--accent-deep); }

label { display: block; margin-bottom: .35rem; font-weight: 560; font-size: .875rem; }

input[type=email], input[type=text] {
  font: 15px/1.4 var(--mono);
  width: 100%;
  max-width: 22rem;
  padding: .6rem .7rem;
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
  background: var(--surface);
  color: var(--ink);
}

.stack { display: grid; gap: 1.1rem; justify-items: start; margin: 1.75rem 0; }

/* ---------------------------------------------------------------------------
   The ledger. Not cards: one row per record, hairline ruled, digits aligned.
   --------------------------------------------------------------------------- */

table {
  width: 100%;
  margin: .75rem 0 1rem;
  border-collapse: collapse;
  font-size: .875rem;
  background: var(--surface);
}

th {
  padding: .55rem .7rem;
  text-align: left;
  border-bottom: 1px solid var(--rule-strong);
  white-space: nowrap;
}

td {
  padding: .7rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--rule);
}

tbody tr:hover { background: #fbfcfd; }

.num { text-align: right; white-space: nowrap; }
/* De-emphasised, not unreadable. This was --rule-strong, about 1.9:1 on white:
   "0 confirmed" is a fact somebody is relying on, and a count they have to squint
   at is worse than one that competes slightly for attention. */
.zero { color: var(--muted); }

.summary {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin: 1.75rem 0;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: var(--surface);
  overflow: hidden;
}
.summary div {
  flex: 1 1 9rem;
  padding: .9rem 1rem;
  border-right: 1px solid var(--rule);
}
.summary div:last-child { border-right: 0; }
.count {
  display: block;
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.15;
}
.summary .eyebrow { display: block; margin-top: .2rem; }

.why { font-size: .8125rem; color: var(--ink-soft); line-height: 1.5; }

.guidance { margin: .3rem 0 1rem; color: var(--ink-soft); font-size: .875rem; }
.guidance em { color: var(--muted); font-style: normal; }

.empty {
  margin: 1.5rem 0;
  padding: 2rem 1.25rem;
  border: 1px dashed var(--rule-strong);
  border-radius: 3px;
  background: var(--surface);
  color: var(--muted);
  font-size: .875rem;
}

/* ---------------------------------------------------------------------------
   Notices. Amber for "you need to look at this", never red: the product does
   not accuse anyone.
   --------------------------------------------------------------------------- */

.note {
  margin: 1.25rem 0;
  padding: .8rem 1rem;
  border-left: 2px solid var(--attention);
  background: #fdf8f0;
  color: var(--ink-soft);
  font-size: .8125rem;
}
.note strong { color: var(--ink); }

/* A finished screening is not something to attend to, so it must not wear the
   amber. Teal is already "this is a verified fact" on the evidence bar, which is
   the same claim: the work ran and here is the result. Still no red anywhere --
   nothing this app says about a person warrants it. */
.note.good { border-left-color: var(--verified); background: #edf5f3; }

.flag {
  display: inline-block;
  padding: .1rem .35rem;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  background: var(--paper);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-soft);
  vertical-align: 1px;
}

/* ---------------------------------------------------------------------------
   THE EVIDENCE BAR — the signature.
   Five dimensions the matcher actually recorded, each at the strength it
   recorded. Not a score and not a severity: a picture of what is known. A row
   with one filled segment and four empty ones should look thin, because it is.
   --------------------------------------------------------------------------- */

.evidence { display: flex; gap: .3rem; margin: .1rem 0 .45rem; }

.seg {
  flex: 1 1 0;
  min-width: 2.1rem;
  max-width: 4.5rem;
}

.seg-bar {
  height: 5px;
  border: 1px solid var(--rule-strong);
  border-radius: 1px;
  background: var(--surface);
}

/* Exact: the assertion is solid. Teal, because it is a verified fact about the
   published record -- not a claim about the person. */
.seg-exact .seg-bar { background: var(--verified); border-color: var(--verified); }
.seg-exact .seg-label { color: var(--verified); }

/* Partial: a nickname, an initial, a phonetic hit, same year but not same day.
   Half-filled, so "similar" cannot be mistaken for "the same". */
.seg-near .seg-bar {
  background: linear-gradient(90deg, var(--attention) 50%, var(--surface) 50%);
  border-color: var(--attention);
}
.seg-near .seg-label { color: var(--attention); }

/* Absent: nothing to compare. Empty, and that emptiness is the point -- a
   roster with no dates of birth cannot reach the exact tier at all. */
.seg-absent .seg-bar { background: repeating-linear-gradient(
    135deg, var(--paper) 0 3px, var(--rule) 3px 4px); }

/* Conflict: the fields actively disagree. Marked, not coloured red: a
   disagreement is evidence AGAINST a match, which is good news. */
.seg-conflict .seg-bar {
  background: var(--surface);
  border-color: var(--ink-soft);
  position: relative;
  overflow: hidden;
}
.seg-conflict .seg-bar::after {
  content: "";
  position: absolute;
  inset: 1px 0;
  border-top: 1px solid var(--ink-soft);
  top: 50%;
}

.seg-label { display: block; margin-top: .3rem; font-size: 10px;
             letter-spacing: .09em; }

.tier {
  /* Block, not inline-block: the evidence bar used to separate this from the
     sentence below it, and once the bar was restricted to tier 4 the label ran
     straight into the text as "TIER 3Surname and given name match". */
  display: block;
  margin-bottom: .3rem;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------
   Sign-in. Deliberately small: everyone here already has an account, so a
   marketing hero would be answering a question nobody asked.
   --------------------------------------------------------------------------- */

.gate { max-width: 30rem; margin: 4rem auto 0; }
.gate h1 { font-size: 1.5rem; }
.gate .assert {
  margin: 1.25rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  color: var(--muted);
  font-size: .8125rem;
}

footer {
  margin-top: 3.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  color: var(--muted);
  font-size: .75rem;
  line-height: 1.55;
}

/* ---------------------------------------------------------------------------
   The decision control. App-only: the report is a document and has no buttons,
   which is why these live here and not in a second stylesheet.

   Both affirmative verdicts are set identically on purpose. "Is a match" is the
   consequential answer, and making it louder than "Not a match" would put a
   thumb on the scale of a decision about a named colleague -- the same reason
   there is no red anywhere in this file. Weight belongs on the evidence, not on
   the button the interface would prefer.
   --------------------------------------------------------------------------- */

.decide { display: grid; gap: .5rem; justify-items: start; min-width: 13rem; }
/* Narrower than the global 22rem: this sits inside a table cell beside three
   other columns, and a full-width field would push the evidence off screen. */
.decide input[type=text] { max-width: 13rem; font-size: 13px; padding: .45rem .55rem; }

.decide-buttons { display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem .6rem; }
.decide-buttons button { padding: .45rem .7rem; font-size: .8125rem; }
.decide-buttons button.quiet { padding: 0; }

/* ---------------------------------------------------------------------------
   Small screens. A roster is often read on a phone between other things.
   --------------------------------------------------------------------------- */

@media (max-width: 40rem) {
  body { font-size: 14px; padding: 0 1rem; }
  .bar { margin: 0 -1rem 1.75rem; padding: .9rem 1rem; }
  h1 { font-size: 1.375rem; }
  .summary div { flex-basis: 50%; border-bottom: 1px solid var(--rule); }
  /* Wide record tables scroll in their own box rather than the page. */
  .scroll { overflow-x: auto; }
  .scroll table { min-width: 34rem; }

  /* The review table does not scroll: it stacks.
     Horizontal scroll is fine for the report, which is read. This table is
     acted on, and at 390px the Decision column sat off the right edge -- the
     buttons that are the entire purpose of the page were reachable only by
     scrolling sideways with no indication they were there. Caught in
     bin/shots.py's mobile shot. Each row becomes one block instead, with the
     decision last, which is the order it is read in anyway. */
  .scroll:has(.decide-table) { overflow-x: visible; }
  /* `.scroll .decide-table` and not `.decide-table`: `.scroll table` above is
     (0,1,1) and beats a bare class at (0,1,0), so the 34rem minimum stayed in
     force and every row overflowed the right edge with the text clipped. The
     stacking worked and the reset silently did not. */
  .scroll .decide-table,
  .scroll .decide-table tbody,
  .scroll .decide-table tr,
  .scroll .decide-table td {
    display: block;
    min-width: 0;
    width: auto;
  }
  .scroll .decide-table thead { display: none; }  /* cells label themselves below */
  .scroll .decide-table tr {
    padding: .9rem 0;
    border-bottom: 1px solid var(--rule-strong);
  }
  .scroll .decide-table td { padding: .25rem 0; border: 0; }
  .scroll .decide-table td:last-child { padding-top: .6rem; }
  .scroll .decide-table .decide,
  .scroll .decide-table .decide input[type=text] { max-width: 100%; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------------------
   Print. Compliance work is filed, and a screening report is evidence that it
   was done. Provenance has to survive the printer: links resolve to visible
   URLs, nothing is clipped, and rows do not break across pages.
   --------------------------------------------------------------------------- */

@media print {
  :root { --paper: #fff; --surface: #fff; }
  body { max-width: none; padding: 0; font-size: 10.5pt; color: #000; }
  .bar, .who, button { display: none; }
  h2 { margin-top: 1.5rem; page-break-after: avoid; }
  tr, .note, .summary { page-break-inside: avoid; }
  table { font-size: 9pt; }
  thead { display: table-header-group; }
  .note { border-left-width: 3px; }
  /* A printed report that says "source file" and hides the URL is not evidence. */
  .prov a::after { content: " (" attr(href) ")"; font-size: 7.5pt; word-break: break-all; }
  footer { margin-top: 1.5rem; }
}
