.check-progress{background:#f5f7fa;border:1px solid #d4deeb;border-radius:20px;padding:28px;color:#0b2545}
.progress-heading{display:flex;gap:18px;align-items:center}.progress-heading img{flex:none;animation:check-breathe 2.4s ease-in-out infinite}.progress-heading h2{margin:0;font-size:1.3rem}.progress-heading p{margin:8px 0;font-size:1rem}
.progress-categories{display:flex;flex-wrap:wrap;gap:8px;margin:22px 0 14px}.progress-categories span{padding:8px 12px;border:1px solid #c4d4e9;border-radius:9px;background:#fff;font-size:.9rem}.progress-note{font-size:.9rem;color:#465a73;line-height:1.6}
/* SITE-106. The three outcomes, and the fourth state that is not one. A stage the
   run has not reached, or one carrying an outcome this page does not recognise,
   gets no rule here at all and keeps the plain chip above: no tick, no word, no
   claim. A skipped stage is deliberately NOT styled as a failure either, because
   "we did not look" is not "we looked and it was bad". */
.progress-categories [data-outcome]{display:inline-flex;align-items:baseline;gap:6px}
.progress-categories [data-outcome="found"]{border-color:#1f6b3f;color:#144d2d}
.progress-categories [data-outcome="none"]{border-color:#9db8d8}
.progress-categories [data-outcome="skipped"]{border-style:dashed;color:#465a73}
.progress-categories .tick{color:#1f6b3f;font-weight:700}
.progress-categories small{font-size:.78rem;color:#465a73}
/* THE BRANDED ILLUSTRATION. SITE-116, his words of 29 September: "I would like there
   to be a graphical branded animation as the check is going on to make it more
   interesting as it happens."

   DECORATION THAT MIRRORS THE ROW. The node states below are the same four the chips
   render, read through the same function, so nothing here can light up that the run
   has not reported. The ONE thing that moves on its own is .sweep, which carries no
   state and stops entirely under prefers-reduced-motion. */
.progress-art{margin:20px 0 4px}
.check-art{display:block;width:100%;height:auto;max-height:150px;
  filter:drop-shadow(0 12px 26px rgba(11,37,69,.16))}
.check-art .bg{fill:url(#mit-art-bg)}
.check-art .track{stroke:rgba(255,255,255,.22);stroke-width:3;stroke-linecap:round}
.check-art .sweep{fill:url(#mit-art-sweep);animation:check-sweep 2.8s cubic-bezier(.45,0,.55,1) infinite}
.check-art .ring{fill:#0B2545;stroke:rgba(255,255,255,.3);stroke-width:2.5}
.check-art .tick{fill:none;stroke:#0B2545;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;
  opacity:0}
.check-art .lbl{fill:rgba(255,255,255,.72);font:600 11px/1 'IBM Plex Mono',ui-monospace,monospace;
  text-anchor:middle;letter-spacing:.04em}
/* The three outcomes, and the fourth state that is not one: a node the run has not
   reached keeps the rules above and claims nothing. */
.check-art [data-outcome="found"] .ring{fill:#7FE3A1;stroke:#7FE3A1}
.check-art [data-outcome="none"] .ring{fill:#BFE6CF;stroke:#BFE6CF}
.check-art [data-outcome="found"] .tick,.check-art [data-outcome="none"] .tick{opacity:1}
.check-art [data-outcome="found"] .lbl,.check-art [data-outcome="none"] .lbl{fill:#fff}
.check-art [data-outcome="skipped"] .ring{fill:none;stroke:rgba(255,255,255,.42);stroke-dasharray:4 4}
.check-art [data-outcome="skipped"] .lbl{fill:rgba(255,255,255,.6)}
/* ON A PHONE THE LABELS COME OFF THE PICTURE AND THE CHIPS DO THE READING. A viewBox
   scales everything, so five monospace captions at 390px are four pixels tall: present,
   unreadable, and claiming to be information. The chips below carry every word. */
@media(max-width:560px){.check-art .lbl{display:none}.check-art{max-height:96px}}
@keyframes check-sweep{0%{transform:translateX(0)}50%{transform:translateX(286px)}100%{transform:translateX(0)}}

/* Said to a screen reader and not on screen. `found` carries its word this way
   because the tick already says it and five chips with a second visible line is a
   strip nobody reads. */
.check-progress .vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.report-copy{margin:20px 0;padding:26px;border:1px solid #b6cef0;border-radius:18px;background:#fff;color:#0b2545}.report-copy h3{margin:0 0 8px;font-size:1.25rem}.report-copy p{font-size:1rem;line-height:1.6}.report-copy label{font-size:1rem}.copy-fields{display:flex;gap:10px;margin:8px 0 18px}.copy-fields input{min-width:0;flex:1;border:1px solid #9caec6;border-radius:9px;padding:13px;font:inherit}.copy-fields button{border:0;background:#0b2545;color:#fff;border-radius:9px;padding:13px 20px;font:inherit;font-weight:600;cursor:pointer}.copy-fields button:disabled{opacity:.65}.copy-help{display:flex;gap:9px;align-items:flex-start}.copy-help input{margin-top:5px;width:18px;height:18px;flex:none}.report-copy .copy-privacy{font-size:.875rem;color:#465a73}.copy-status{font-weight:600}.report-copy[hidden]{display:none}.report-ready{padding:22px;background:#edf4ff;border-radius:14px;margin-bottom:22px}.report-ready a{font-weight:700;color:#0b2545}
@keyframes check-breathe{50%{opacity:.55;transform:scale(.94)}}
/* REDUCED MOTION TAKES THE MOTION AND LEAVES THE PICTURE. The sweep is the only thing
   that moves by itself, so stopping it leaves a static branded illustration whose
   nodes still light as the run reports them: the state was never the animation. */
@media(prefers-reduced-motion:reduce){.progress-heading img{animation:none}.check-art .sweep{animation:none;opacity:.5}}
@media(max-width:600px){.copy-fields{flex-direction:column}.check-progress,.report-copy{padding:20px}.progress-heading{align-items:flex-start}}
