/* Sizes live here. This file loads after tailwind.css, so a rule here
   beats a lone text-xs / text-sm utility. Templates keep those classes
   for color and weight.

   Tailwind's text-xs is 0.75rem and text-sm is 0.875rem. The floor
   raises every one of them to 1rem: category headings in the test list,
   the notes under them, cohort captions, and the other short copy that
   is not a button or a link. Badges, the cart row button, and the
   word-cloud scale opt back out further down. */

.mm-reading {
  font-size: 1rem;
  line-height: 1.55;
  white-space: normal;
  overflow: visible;
  text-overflow: unset;
  max-width: 70ch;
}

.mm-reading table {
  width: 100%;
  max-width: 100%;
}

/* Imported tables carry a fixed width="471" and <col width> from the
   spreadsheet they came from. Stylesheet width beats those attributes, so
   the table fills its card and the columns share the space by content. */
.mm-reading col {
  width: auto;
}

/* Table cells are not paragraphs: no 70ch cap, tighter leading. */
.mm-table-scroll :where(th, td).mm-reading {
  max-width: none;
  line-height: 1.35;
}

button.text-xs,
button.text-sm,
a.text-xs,
a.text-sm,
summary > span.text-xs,
.mm-nav-cluster,
.mm-nav-cluster .text-xs,
.mm-nav-cluster .text-sm,
#round-control .text-xs,
#round-control .text-sm,
.text-xs,
.text-sm {
  font-size: 1rem;
  line-height: 1.4;
}

/* Add to Order is a repeated row button: one step smaller than other buttons. */
button.text-xs[data-cart-btn] {
  font-size: 0.8rem;
}

/* Diagnose uses the same box as the test-list Add to Order, so the shorter
   label does not draw a smaller control. Catalog cards are outside this row. */
.mm-exam-row .mm-exam-action {
  box-sizing: border-box;
  width: 8rem;
  justify-content: center;
  white-space: nowrap;
  line-height: 1.4;
}

summary > span.mm-exam-action {
  font-size: 0.8rem;
}

#round-control p {
  max-width: 70ch;
}

input,
textarea,
select {
  font-size: 1rem;
}

.mm-pill {
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border-radius: 999px;
  padding: 0.35rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.3;
  box-shadow: inset 0 0 0 1px rgba(46, 45, 41, 0.14);
}

/* :not(.hidden) so this file, loaded after Tailwind, does not
   override the cart badge's hidden state. */
.mm-count:not(.hidden) {
  display: inline-flex;
}

.mm-count {
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  line-height: 1;
  min-width: 1.25rem;
  min-height: 1.25rem;
  height: auto;
  width: auto;
  padding: 0.15rem 0.35rem;
}

.mm-eyebrow {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.3;
}

.mm-table-scroll {
  overflow-x: auto;
}

.mm-table-scroll :where(th, td) {
  white-space: normal;
  padding-top: 1.35rem;
  padding-bottom: 1.35rem;
}

.mm-nav {
  min-height: 4.25rem;
  height: auto;
  flex-wrap: wrap;
  align-items: center;
  row-gap: 0.35rem;
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
}

.mm-nav-id {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.4rem;
  padding-block: 0.2rem;
}

.mm-nav-name {
  font-size: 1rem;
  line-height: 1.2;
}

.mm-nav-role {
  font-size: 0.8125rem;
  line-height: 1.2;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.mm-nav-brandrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.5rem;
  min-width: 0;
  flex: 1 1 auto;
}

.mm-nav-links {
  display: none;
}

@media (min-width: 768px) {
  .mm-nav-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
  }
}

.mm-nav-links a {
  white-space: nowrap;
}

.mm-nav-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.75rem;
}

.mm-chrome {
  position: sticky;
  top: 0;
  z-index: 50;
}

.mm-exam-row {
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
}

/* Tests a TA delivers in person (Metabolite, Consult service): a visible
   1px brand-red outline so they read apart from ordinary test rows. */
div.mm-request-row {
  border: 1px solid #8c1515;
}

/* Alternate test/result cards: a touch darker than the white card. The
   element selector outranks Tailwind's .bg-paper. */
div.mm-zebra-alt {
  background-color: #dfdfdf;
}

@media (min-width: 640px) {
  .mm-exam-row {
    grid-template-columns: minmax(0, 1fr) 4.5rem 9rem;
  }

  /* No points cell on the diagnosis row. The control still lands in the
     action column, so it lines up with Add to Order. */
  .mm-exam-row > .mm-exam-action {
    grid-column: 3;
  }
}

/* An open request form (metabolite note + Confirm + Cancel), or a "waiting" pill, is wider than the
   fixed action column, so let the column grow to fit instead of overflowing. */
@media (min-width: 640px) {
  .mm-exam-row:has(form:not(.hidden)),
  .mm-exam-row:has(.mm-pill) {
    grid-template-columns: minmax(0, 1fr) 4.5rem auto;
  }
}

/* Toasts: bottom-right, polled from static/js/notifications.js. */
.mm-toasts {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: min(24rem, calc(100vw - 2rem));
  pointer-events: none;
}

.mm-toast {
  pointer-events: auto;
  flex: none;
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  background: #fff;
  border: 1px solid #eaeaea;
  border-left: 5px solid #8c1515;
  border-radius: 1rem;
  box-shadow: 0 10px 30px rgba(46, 45, 41, 0.18);
  color: #2e2d29;
  animation: mm-toast-in 0.25s ease-out;
}

.mm-toast-title {
  font-weight: 700;
}

.mm-toast-body {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.45;
  color: #585754;
}

.mm-toast-body a {
  color: #8c1515;
  font-weight: 600;
  text-decoration: underline;
}

.mm-toast-close {
  flex: none;
  min-width: 2rem;
  min-height: 2rem;
  margin: -0.25rem -0.5rem 0 0;
  border-radius: 0.5rem;
  background: transparent;
  color: #585754;
  line-height: 1;
}

.mm-toast-close:hover {
  background: #eaeaea;
}

@keyframes mm-toast-in {
  from { opacity: 0; transform: translateY(0.75rem); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .mm-toast { animation: none; }
}

/* Search inputs: the browser's built-in clear "x" doubles up with the page's
   own Clear search link, so hide the native one. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

/* Back-to-top button pinned to the bottom-right of a scrolling list. */
.mm-scroll-top {
  position: sticky;
  bottom: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  margin: 0 0.25rem 0 auto;
  border-radius: 9999px;
  background: #ffffff;
  border: 1px solid #d9d9d6;
  color: #43423e;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  cursor: pointer;
}
.mm-scroll-top[hidden] {
  display: none;
}
.mm-scroll-top:hover {
  background: #f2f2f0;
}

/* The rounded border is its own box. The scroller is the child, so the
   scrollbar is clipped inside the curve instead of painting over it. */
.mm-scroll-frame {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  border: 2px solid #c9c9c5;
  border-radius: 1rem;
  background: #f4f4f4;
}

[data-scroll-top] {
  padding: 0 0.25rem 0.875rem 0.875rem;
  scrollbar-gutter: stable;
}

.mm-scroll-frame > [data-scroll-top],
.mm-table-scroll,
#drawer-items-list {
  scrollbar-width: thin;
  scrollbar-color: #b7b5ae transparent;
}

.mm-scroll-frame > [data-scroll-top]::-webkit-scrollbar,
.mm-table-scroll::-webkit-scrollbar,
#drawer-items-list::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}

.mm-scroll-frame > [data-scroll-top]::-webkit-scrollbar-track,
.mm-table-scroll::-webkit-scrollbar-track,
#drawer-items-list::-webkit-scrollbar-track {
  margin-block: 0.85rem;
  background: transparent;
}

.mm-scroll-frame > [data-scroll-top]::-webkit-scrollbar-thumb,
.mm-table-scroll::-webkit-scrollbar-thumb,
#drawer-items-list::-webkit-scrollbar-thumb {
  border: 3px solid transparent;
  border-radius: 999px;
  background-color: #b7b5ae;
  background-clip: padding-box;
}
/* Top padding on the tests list lets category names scroll through the
   gap above the sticky column header. Results have no sticky header,
   so only that list gets the inset. */
.mm-scroll-pad {
  padding-top: 1rem;
}
/* The sticky Tests strip covers the full top edge of the frame, so a
   category heading cannot show above it while the list scrolls. */
.mm-scroll-box > .sticky {
  top: 0;
  z-index: 2;
  background-color: #f4f4f4;
}
/* The list starts under the nav and the patient header. 80vh from
   there runs past the window, so the category controls open off-screen.
   Cap the box to the space left in the viewport. */
.mm-scroll-box {
  max-height: max(18rem, calc(100dvh - 34rem));
}

/* The test list shows 7-8 rows at once (a row is about 5.3rem with its gap,
   plus the sticky header and a category heading), so the page scrolls a
   little on a short window rather than the list cutting off at 3-4 rows. */
#exam-list .mm-scroll-box {
  max-height: 46rem;
}

/* A patient chart is as tall as its tab needs. Only the framed lists
   scroll, capped by .mm-scroll-box, so History and the diagnosis box can
   run past the window and the page scrolls instead of clipping. */
.mm-chart {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.mm-chart > #patient-tab-content {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

.mm-chart .mm-tab-fill {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  padding-top: 1rem;
}

.mm-chart .mm-tab-fill > h2,
.mm-chart .mm-toolbar {
  flex: none;
}

.mm-chart #exam-list {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.75rem;
  min-height: 0;
}

.mm-chart #exam-list > .mm-scroll-frame,
.mm-chart .mm-tab-fill > .mm-scroll-frame {
  flex: 1 1 auto;
  min-height: 0;
}

.mm-chart .mm-scroll-box {
  flex: 0 1 auto;
  min-height: 0;
}

.mm-chart #exam-list > details {
  flex: 0 0 auto;
  /* The test rows sit inside the frame's border and the scroller's
     padding. Match that inset so the action column shares one right edge. */
  margin-left: calc(2px + 0.875rem);
  margin-right: calc(2px + 0.25rem);
}

/* Diagnose replaces the catalog. The form is taller than the leftover
   window, and the list is the column's slack, so leaving both up
   collapses the list to one row. Close brings the catalog back. A
   confirmed card is short, so the list stays. */
.mm-chart .mm-tab-fill:has(details[open]:not(.mm-confirmed)) > .mm-toolbar,
.mm-chart #exam-list:has(> details[open]:not(.mm-confirmed)) > .mm-scroll-frame {
  display: none;
}

.mm-scroll-controls {
  position: sticky;
  bottom: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  pointer-events: none;
}
/* The buttons sit over the last row. The box already pads ~1rem under
   them; leave that same amount between the last test and the buttons. */
.mm-scroll-box.space-y-3 > .mm-scroll-controls {
  margin-top: 1.75rem;
}
.mm-scroll-controls > * {
  pointer-events: auto;
}
.mm-scroll-controls .mm-scroll-top {
  position: static;
  margin: 0 0 0 auto;
}
.mm-scroll-next {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 2.5rem;
  padding: 0 1rem;
  border-radius: 9999px;
  background: #8c1515;
  color: #ffffff;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}
.mm-scroll-next[hidden] {
  display: none;
}
.mm-scroll-next:hover {
  background: #6f1010;
}

/* Category names between test rows. Body size, bold, and the ink colour
   so they read as headings rather than gray captions. */
.mm-category {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #2e2d29;
}

/* Search, then the count, then (on Results) the sort controls at the
   right. gap lives here because the compiled Tailwind file has gap-4
   but not gap-x-4, and it has ml-auto but not sm:ml-auto. */
.mm-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}

.mm-toolbar-sort {
  margin-left: auto;
}

/* Count beside a search field. Same size as the field's text, and the
   flex row centers it on that text. */
.mm-toolbar-count {
  margin: 0;
  font-size: 1rem;
  line-height: 1.5rem;
}

/* Every history, authored cards or a table, is rewritten into these
   sections before render so two patients cannot drift apart. */
.mm-history-card {
  margin: 0 0 1rem;
  padding: 1.25rem 1.5rem;
  border: 1px solid #e7e5e0;
  border-radius: 1rem;
  background: #fff;
}

.mm-history-card:last-child {
  margin-bottom: 0;
}

.mm-history-label {
  margin: 0 0 0.5rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.3;
  text-transform: uppercase;
  color: #6d6c69;
}

.mm-history-body {
  margin: 0;
  font-size: 1rem;
  line-height: 1.55;
  color: #43423e;
}

/* Session wrap-up: timeline markers and the word clouds. Cloud sizes are a
   5-step scale (wrapup.word_cloud assigns the level) so no size is inline. */
.mm-chip {
  font-size: 0.75rem;
  line-height: 1;
}

.mm-cloud-1 { font-size: 1rem; }
.mm-cloud-2 { font-size: 1.15rem; }
.mm-cloud-3 { font-size: 1.5rem; }
.mm-cloud-4 { font-size: 1.95rem; }
.mm-cloud-5 { font-size: 2.5rem; }

/* Show whole images (patient photos etc.) instead of cropping them. */
.object-cover {
  object-fit: contain;
  background: white;
}

/* ---- Solved moment (TA-confirmed diagnosis): see static/js/solved-moment.js ---- */

/* Verified diagnosis card (spec 4.5, 3.6). Hex on purpose: the Tailwind
   colour names point at the Stanford palette. Ring and tick render fully
   drawn; the draw runs only under an .is-arriving ancestor, which
   solved_poll puts on a fresh CHECK arrival and solved-moment.js strips
   once the moment settles. */
.mm-confirmed > summary,
.mm-confirmed > div {
  background-color: #E6F3EF;
  border-color: #8AB8A7;
}

.mm-confirmed-body {
  color: #014240;
}

/* The toast's check (.mm-solved-toast-check, below) shares these two strokes. */
.mm-confirmed-ring,
.mm-solved-toast-check circle {
  stroke: #008566;
}

.mm-confirmed-tick,
.mm-solved-toast-check path {
  stroke: #006F54;
}

@keyframes mm-confirmed-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.is-arriving .mm-confirmed-ring,
.is-arriving .mm-confirmed-tick {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
}

/* mm-draw (base.html) runs to dashoffset 0 from the 100 set above. */
.is-arriving .mm-confirmed-ring {
  animation: mm-draw 420ms cubic-bezier(0.2, 0.8, 0.28, 1) both;
}

.is-arriving .mm-confirmed-tick {
  animation: mm-draw 260ms cubic-bezier(0.2, 0.8, 0.28, 1) 320ms both;
}

.is-arriving .mm-confirmed-text {
  animation: mm-confirmed-fade 200ms cubic-bezier(0.2, 0.8, 0.28, 1) 480ms both;
}

/* ------------------------------------------------------------------
   Solved moment: stage, nav count-up, toast.
   Spec: docs/superpowers/specs/2026-10-08-solved-moment-design.md
   Durations mirror T in static/js/solved-moment.js; change both
   together. Colours are hex on purpose: the app's Tailwind colour
   names point at the Stanford palette, not the design tokens.
   The screen-reader line (#solved-moment-live) reuses Tailwind's
   .sr-only and needs nothing here.
   ------------------------------------------------------------------ */

/* The stage: every overlay and the toast are built inside it. Above the
   sticky chrome (50) and the order drawer, never clickable, and nothing
   in it takes focus. */
.mm-solved-root {
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  overflow: hidden;
}

/* The nav box while it animates: lifted so the 1.1x swell sits above
   Sign out. #header-team-stats is already `relative`. */
.mm-score-live {
  position: relative;
  z-index: 1;
}

/* Swell: 1 -> 1.1 over 200ms, ease-out. Held until the slam. */
.mm-score-swell {
  animation: mm-score-swell 200ms cubic-bezier(0.2, 0.8, 0.28, 1) both;
}

@keyframes mm-score-swell {
  from {
    scale: 1;
  }
  to {
    scale: 1.1;
  }
}

/* Slam: 1.1 -> 0.96 in 90ms (ease-in), then -> 1 in 220ms (spring),
   with a 240ms rotational jiggle from the moment of impact. */
.mm-score-slam {
  animation:
    mm-score-slam 310ms linear both,
    mm-score-jiggle 240ms 90ms ease-in-out both;
}

@keyframes mm-score-slam {
  0% {
    scale: 1.1;
    animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
  }
  29.03% {
    scale: 0.96;
    animation-timing-function: cubic-bezier(0.34, 1.32, 0.56, 1);
  }
  100% {
    scale: 1;
  }
}

@keyframes mm-score-jiggle {
  0% {
    rotate: 0deg;
  }
  25% {
    rotate: -1.5deg;
  }
  50% {
    rotate: 1.2deg;
  }
  75% {
    rotate: -0.6deg;
  }
  100% {
    rotate: 0deg;
  }
}

/* Orbit: one white segment, 18% of the border, travels once around the
   box in 460ms. The SVG is the box's last child; the JS sizes it to the
   box's border box (hence -1px) and un-hides it, which starts the run. */
.mm-score-orbit {
  position: absolute;
  top: -1px;
  left: -1px;
  overflow: visible;
  pointer-events: none;
}

.mm-score-orbit[hidden] {
  display: none;
}

/* As later siblings, the orbit and the +N pill would pick up the
   space-x-* margin; the id outranks that utility's selector. */
#header-team-stats > .mm-score-orbit,
#header-team-stats > .mm-score-plus {
  margin: 0;
}

.mm-score-orbit rect {
  fill: none;
  stroke: #FFFFFF;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 18 82;
  stroke-dashoffset: 0;
  opacity: 0;
}

.mm-score-orbit:not([hidden]) rect {
  animation: mm-score-orbit 460ms cubic-bezier(0.5, 0.05, 0.3, 1) both;
}

@keyframes mm-score-orbit {
  0% {
    stroke-dashoffset: 0;
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  85% {
    opacity: 1;
  }
  100% {
    stroke-dashoffset: -100;
    opacity: 0;
  }
}

/* Odometer: each place is a 1ch column holding a vertical strip of
   digits that the JS moves with translateY (transform only). Cell height
   is the nav's 1.4 line-height; ODO_CELL_EM in the JS must match. */
.mm-odo {
  display: inline-block;
  white-space: nowrap;
}

.mm-odo-col {
  display: inline-block;
  width: 1ch;
  height: 1.4em;
  overflow: hidden;
  vertical-align: top;
}

.mm-odo-strip {
  display: block;
  will-change: transform;
}

.mm-odo-strip > span {
  display: block;
  height: 1.4em;
  line-height: 1.4em;
  text-align: center;
}

/* +N: a notification badge whose centre sits on the box's top-right
   corner. Mint on cardinal is 7.6:1. Pops in over 160ms (spring
   overshoot), holds 1100ms, fades over 190ms. */
.mm-score-plus {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  translate: 50% -50%;
  padding: 0.125rem 0.5rem;
  border: 1px solid rgba(179, 228, 203, 0.45);
  border-radius: 999px;
  background: #820000;
  color: #B3E4CB;
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.3;
  white-space: nowrap;
  pointer-events: none;
  animation: mm-score-plus 1450ms cubic-bezier(0.2, 0.8, 0.28, 1) both;
}

@keyframes mm-score-plus {
  0% {
    opacity: 0;
    scale: 0.5;
    animation-timing-function: cubic-bezier(0.34, 1.32, 0.56, 1);
  }
  11.03% {
    opacity: 1;
    scale: 1;
  }
  86.9% {
    opacity: 1;
    scale: 1;
  }
  100% {
    opacity: 0;
    scale: 1;
  }
}

/* Toast: the off-card confirmation. Bottom-right with a 1rem inset at
   every width; slides up over 200ms, holds, fades over the last 200ms of
   its 5000ms. */
.mm-solved-toast {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 60;
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  max-width: min(22rem, calc(100vw - 2rem));
  padding: 0.75rem 1rem;
  border: 1px solid #8AB8A7;
  border-radius: 0.875rem;
  background: #E6F3EF;
  color: #014240;
  box-shadow: 0 0.75rem 2rem rgba(1, 66, 64, 0.18);
  animation: mm-solved-toast 5000ms cubic-bezier(0.2, 0.8, 0.28, 1) both;
}

@keyframes mm-solved-toast {
  0% {
    opacity: 0;
    transform: translateY(0.75rem);
  }
  4% {
    opacity: 1;
    transform: translateY(0);
  }
  96% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(0);
  }
}

.mm-solved-toast-title {
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
}

.mm-solved-toast-meta {
  margin-top: 0.125rem;
  font-size: 1rem;
  line-height: 1.35;
}

/* The toast's check draws like the confirmed card's: ring over 420ms,
   tick over 260ms from 320ms. mm-draw is defined in base.html. */
.mm-solved-toast-check {
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
}

.mm-solved-toast-check circle,
.mm-solved-toast-check path {
  fill: none;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
}

.mm-solved-toast-check circle {
  stroke-width: 1.75;
  animation: mm-draw 420ms cubic-bezier(0.2, 0.8, 0.28, 1) forwards;
}

.mm-solved-toast-check path {
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
  animation: mm-draw 260ms 320ms cubic-bezier(0.2, 0.8, 0.28, 1) forwards;
}

/* Reduced motion: every part lands on its end state instantly. The JS
   also reads prefers-reduced-motion at play time; this block also covers
   the classes the check and light variants animate (.mm-flash and
   .mm-bath are overlay elements inside the stage). */
@media (prefers-reduced-motion: reduce) {
  .mm-score-orbit,
  .mm-score-plus,
  .mm-flash,
  .mm-bath {
    display: none !important;
  }

  .mm-score-swell,
  .mm-score-slam,
  .mm-odo-strip,
  .mm-solved-toast,
  .mm-solved-toast-check circle,
  .mm-solved-toast-check path,
  .mm-lit,
  #header-team-stats.mm-lit::before,
  .mm-confirmed-ring,
  .mm-confirmed-tick,
  .is-arriving,
  .is-arriving * {
    animation: none !important;
    transition: none !important;
  }

  .mm-score-swell,
  .mm-score-slam {
    scale: none !important;
    rotate: none !important;
  }

  .mm-solved-toast-check circle,
  .mm-solved-toast-check path,
  .mm-confirmed-ring,
  .mm-confirmed-tick {
    stroke-dashoffset: 0 !important;
  }

  /* The card's draw and fade (.is-arriving, above) land on their end state:
     fully drawn, fully opaque. */
  .is-arriving .mm-confirmed-ring,
  .is-arriving .mm-confirmed-tick {
    stroke-dasharray: none;
  }

  .is-arriving .mm-confirmed-text {
    opacity: 1;
  }
}

/* ------------------------------------------------------------------
   Solved moment, check variant (spec 3.1, 3.6; exploration 03).
   One whole-viewport green flash: opacity 0 -> 1 in 120ms, then
   1 -> 0 in 330ms. 450ms = T.flashIn + T.flashOut in
   static/js/solved-moment.js; change both together. The card's draw
   is the .is-arriving block above and the toast's is .mm-solved-toast-check.
   The reduced-motion block above already hides .mm-flash.
   ------------------------------------------------------------------ */
.mm-flash {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: rgba(0, 133, 102, 0.16);
  opacity: 0;
  animation: mm-flash 450ms linear both;
}

@keyframes mm-flash {
  0% {
    opacity: 0;
    animation-timing-function: cubic-bezier(0.2, 0.8, 0.28, 1);
  }
  26.667% {
    opacity: 1;
    animation-timing-function: cubic-bezier(0.5, 0.05, 0.3, 1);
  }
  100% {
    opacity: 0;
  }
}

/* ------------------------------------------------------------------
   Solved moment, light variant (spec 3.2, 3.3, 3.6; exploration 41).
   2400ms = T.bath and 1000ms = T.lit in static/js/solved-moment.js;
   change both together. The JS sets each block's start time as
   --mm-lit-delay. The reduced-motion block above already hides
   .mm-bath and switches .mm-lit off.
   ------------------------------------------------------------------ */

/* The bath: a green radial wash over the whole page. Up by 18%, held
   to 64%, gone at 100%. The stage is its own stacking context, so the
   multiply has only the stage's empty backdrop to blend with and the
   wash composites as a plain translucent layer. Over paper that looks
   the same as multiply; over dark text it is slightly greener. */
.mm-bath {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(90% 76% at 50% 58%, rgba(0, 133, 102, 0.18), rgba(0, 133, 102, 0.06) 58%, transparent);
  mix-blend-mode: multiply;
  opacity: 0;
  animation: mm-bath 2400ms cubic-bezier(0.5, 0.05, 0.3, 1) both;
}

@keyframes mm-bath {
  0% {
    opacity: 0;
  }
  18% {
    opacity: 1;
  }
  64% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

/* A lit block glows once, peaking at 38% of 1000ms. The glow is a
   box-shadow on the block itself: the dashboard card is
   overflow-hidden, so nothing inside it could show one. The nav box
   runs the count-up's swell and slam on its own animation property,
   which this one would replace, so its glow rides on a pseudo-element
   laid over its border box instead. */
.mm-lit:not(#header-team-stats),
#header-team-stats.mm-lit::before {
  animation: mm-lit 1000ms var(--mm-lit-delay, 0ms) cubic-bezier(0.5, 0.05, 0.3, 1) both;
}

#header-team-stats.mm-lit::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
}

/* The diagnosis card is a bare <details> around two rounded panels
   (rounded-2xl); this radius shapes only its glow. */
details.mm-lit {
  border-radius: 1.25rem;
}

@keyframes mm-lit {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(89, 179, 169, 0), 0 0 0 0 rgba(138, 184, 167, 0);
  }
  38% {
    box-shadow: 0 0 30px -4px rgba(89, 179, 169, 0.9), 0 0 0 2px rgba(138, 184, 167, 0.9);
  }
}
