/* The visual explanation of a saved calculation.

   THREE CHANNELS, NOT ONE. A figure that was measured and a figure that was
   assumed must not look alike, and colour alone does not carry that: the
   report module already separates its three destinations by the word, the
   border style and the fill, in that order of reliability, so the page reads
   correctly from a black and white photocopy, on a colour-blind reader's
   screen and in a browser printing with background graphics switched off.
   This panel uses the same three channels for the same reason. The word is
   the origin chip, the border is solid, dashed, double or dotted, and the
   fill is plain or hatched.

   EVERY COLOUR IS A TOKEN. The previous version of these rules hard-coded
   #e5ecec, #276b70 and #438449, which are three light-theme colours on a
   product whose theme follows the operating system and can be overridden to
   dark from the header. In dark mode those bars were a pale slab in the
   middle of a dark panel. Tokens cost nothing and follow the theme.

   PHONE WIDTH IS A REQUIREMENT. The tool's header was already fixed once
   because /app had a document.scrollWidth of 971 px at a 400 px viewport, and
   a panel that sets its own floor would undo that fix from the inside. Every
   grid here collapses to one column, every long string can break, and the one
   thing allowed to scroll sideways is the bar chart inside its own box. */

.runoff-visual .body > * + * { margin-top: 16px; }
.runoff-visual .rv-h3 {
  font: 600 13px/1.4 var(--sans); letter-spacing: .02em;
  margin: 22px 0 6px; padding-top: 16px; border-top: 1px solid var(--line);
}

/* ---------- the three-step path ---------- */
.runoff-path {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px; list-style: none; padding: 0; margin: 0 0 22px;
}
.runoff-path li {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; padding: 14px; min-width: 0; overflow-wrap: anywhere;
}
.runoff-path span, .runoff-bar-row span {
  display: block; font-size: 12px; margin-top: 5px; color: var(--ink-soft);
}

/* ---------- the bars ----------

   The label column is a fixed 160 px at desktop so the bars start on one
   vertical line and can be compared by eye, which is the only thing a bar
   chart is for. At phone width it becomes a row of its own above the bar:
   squeezing three columns into 360 px gives a 40 px track, and a 40 px track
   comparing 1.588 in against 0.714 in shows nothing. */
.runoff-bars { margin: 0; }
.runoff-bar-row {
  display: grid; grid-template-columns: 160px minmax(0, 1fr) 95px;
  gap: 14px; align-items: center; margin: 18px 0; min-width: 0;
}
.runoff-bar-row > div:first-child { min-width: 0; overflow-wrap: anywhere; }
.runoff-track {
  background: var(--sunk); border: 1px solid var(--line);
  height: 26px; border-radius: 5px; overflow: hidden;
}
.runoff-track > div { height: 100%; background: var(--accent); min-width: 0; }
/* No bar, rather than a bar of length zero. A solid empty track beside the
   word Unavailable reads as "zero runoff", and a refusal is not a zero. */
.runoff-track.rv-track-absent {
  background: transparent; border-style: dashed; border-color: var(--line-strong);
}
.runoff-bar-row:nth-child(2) .runoff-track > div { background: var(--use); }
.rv-points { margin: 6px 0 0; }

/* ---------- freshness and the absences ----------

   A stale chart is the most dangerous object on this screen, so the stale
   treatment is not a caption. The panel takes a heavy rule, the figures are
   not drawn at all, and the box uses the same red the report uses for a
   historical run. */
/* No border-left here. .okbox, .warnbox and .errbox each set their own, and
   a shared declaration after them painted a grey rule down the side of a red
   box: the colour channel said "warning" and the border channel said
   "ordinary", which is the failure this panel's whole treatment is against. */
.rv-freshness, .rv-absence {
  padding: .6rem .75rem; font-size: 12.5px; margin: 0;
  overflow-wrap: anywhere;
}
.rv-absence.note, .rv-freshness.note {
  background: var(--sunk); border-left: 3px solid var(--line-strong);
  color: var(--ink-mid);
}
.runoff-visual[data-freshness="stale"] {
  border-color: var(--red); border-left: 4px solid var(--red);
}
.runoff-visual[data-freshness="stale"] > h2::after {
  content: " — OUT OF SYNC"; font-family: var(--mono); font-size: var(--fs-min);
  letter-spacing: .08em; color: var(--red);
}

/* ---------- the refusal list ---------- */
.rv-refusals { list-style: none; margin: 0; padding: 0; font-size: 12.5px; }
.rv-refusals li {
  border-left: 3px double var(--ochre-line); background: var(--ochre-soft);
  padding: .5rem .7rem; margin-bottom: 8px; overflow-wrap: anywhere;
}
.rv-rid { font-family: var(--mono); font-size: 11px; color: var(--ink); }
.rv-rclass {
  font-family: var(--mono); font-size: var(--fs-min); text-transform: uppercase;
  letter-spacing: .06em; color: var(--ochre); margin-right: 4px;
}

/* ---------- the figures ----------

   auto-fit with a 240 px minimum rather than a fixed column count: at 400 px
   it is one column, on a laptop it is two or three, and there is no
   breakpoint to keep in step with the rest of the stylesheet.

   min(240px, 100%) rather than a bare 240px. A bare minimum is a floor: in a
   container narrower than it -- a 320 px phone, or this panel nested in
   something narrower later -- the track stays 240 px wide and the page
   scrolls sideways, which is the exact defect the shell was fixed for once
   already. min() lets the floor collapse to the container. */
.rv-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 12px;
}
.rv-figure {
  border: 1px solid var(--line); border-left-width: 4px; border-radius: 8px;
  padding: 12px 14px; background: var(--surface); min-width: 0;
  overflow-wrap: anywhere;
}
.rv-fig-head {
  display: flex; gap: 8px; align-items: baseline;
  justify-content: space-between; flex-wrap: wrap;
}
.rv-fig-label {
  font: 600 11px/1.4 var(--mono); letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-soft);
}
.rv-fig-value { font: 600 17px/1.3 var(--sans); margin: 8px 0 6px; color: var(--ink); }

/* A figure the run publishes ONE PER SEGMENT, which is the shape the loss
   chain arrives in: a retention belongs to a curve number and the site does
   not have one, so the card lists what the run carries rather than reducing
   it to a single number the payload does not hold.

   A row and not a sentence. Four segments in one 17 px bold line is a
   paragraph a reader parses rather than a set of figures they scan, and a
   site of a dozen puts a wall of bold text where the panel's other cards have
   one number. Each row gives its name the space it needs and keeps the
   magnitude on the right, and `min-width: 0` on the name is what lets a long
   segment name wrap instead of setting a floor under the card, which is the
   defect the whole narrow layout above was fixed for. */
.rv-fig-rows { list-style: none; margin: 8px 0 6px; padding: 0; display: grid; gap: 4px; }
.rv-fig-rows li {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; min-width: 0;
  font: 400 13px/1.4 var(--sans); color: var(--ink-mid);
}
.rv-fig-rows li > span { min-width: 0; overflow-wrap: anywhere; }
/* The figure does not wrap. "2.500" over "in" reads as two things, and the
   magnitudes here are bounded -- a depth in inches to three places -- so
   holding them on one line cannot set a floor the name cannot absorb. */
.rv-fig-rows li > strong {
  font: 600 15px/1.4 var(--sans); color: var(--ink); white-space: nowrap;
}
.rv-fig-basis { font-size: 12px; line-height: 1.55; color: var(--ink-mid); margin: 0; }

/* A measured figure: solid rule, plain fill. */
.rv-figure.rv-measured { border-left-style: solid; border-left-color: var(--accent); }

/* An assumed figure: dashed rule AND a hatch, so the difference survives
   greyscale and a reader who never reads the chip. The hatch token is the
   same one the report uses for its filtration band. */
.rv-figure.rv-assumed {
  border-left-style: dashed; border-left-color: var(--ochre-line);
  background-image: repeating-linear-gradient(45deg,
    var(--hatch) 0, var(--hatch) 6px, transparent 6px, transparent 12px);
}
/* A deliberate override: a double rule, which is neither of the above. */
.rv-figure.rv-overridden {
  border-left-style: double; border-left-width: 6px; border-left-color: var(--ochre);
  background: var(--ochre-soft);
}
/* A figure this run does not carry: dotted, unfilled, and dimmed, because it
   is an absence and must not read as a value. */
.rv-figure.rv-absent {
  border-left-style: dotted; border-left-color: var(--line-strong);
  background: transparent;
}
.rv-figure.rv-absent .rv-fig-value {
  color: var(--ink-soft); font-weight: 500; font-style: italic;
}

/* The two origin words this layer adds to the engine's four. */
.origin.entered {
  color: var(--ochre); border-color: var(--ochre-line); background: transparent;
}
.origin.unpublished {
  color: var(--ink-soft); border-color: var(--line-strong); background: transparent;
}
.rv-legend .origin { margin: 0 1px; }

.runoff-visual details.rv-explainer {
  border-top: 1px solid var(--line); padding-top: 12px;
}
.runoff-visual details.rv-explainer summary { cursor: pointer; font-weight: 600; }

/* ---------- the calm pass (docs/CALM-UI.md) ----------

   The bars and the status stay in view; the figures behind them and the
   teaching are two closed folds under one hairline each. A status that asks
   for nothing is a quiet line with a dot, not a box. */
.runoff-visual details.rv-explainer summary {
  font: 500 13px/1.4 var(--sans); color: var(--ink-mid); list-style: none;
}
.runoff-visual details.rv-explainer summary::-webkit-details-marker { display: none; }
.runoff-visual details.rv-explainer summary::before { content: "\25B8"; font-size: 11px; margin-right: 6px; }
.runoff-visual details.rv-explainer[open] summary::before { content: "\25BE"; }
.runoff-visual details.rv-explainer summary:hover { color: var(--accent); }
.runoff-visual details.rv-explainer[open] > summary { margin-bottom: 12px; }
.runoff-visual details.rv-explainer + details.rv-explainer { margin-top: 0; }
.rv-how .rv-legend { margin: 0 0 12px; }
.rv-explainer .runoff-path { margin: 0 0 12px; }
.rv-explainer .runoff-path li { background: none; border: 0; border-left: 1px solid var(--line); border-radius: 0; padding: 2px 0 2px 12px; }
.rv-freshness.rv-quiet {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px; padding: 0;
  background: none; border: 0; color: var(--ink-mid); font-size: 13px;
}
.rv-freshness.rv-quiet strong { font-weight: 500; color: var(--ink); }
.rv-freshness.rv-quiet .calm-dot { background: var(--line-strong); }
.rv-freshness.rv-quiet-ok .calm-dot { background: var(--accent); }
.runoff-visual .rv-points { color: var(--ink-mid); }
.runoff-visual .rv-points strong { font-weight: 500; color: var(--ink); }

/* ---------- narrow ----------

   650 px covers a tablet in portrait and every phone. The bar row stacks: the
   label takes a full row, the track and the number share the next one, so the
   track keeps most of the width instead of being crushed to a stub. */
@media (max-width: 650px) {
  .runoff-path { grid-template-columns: 1fr; }
  .runoff-bar-row {
    grid-template-columns: minmax(0, 1fr) 82px;
    gap: 6px 10px; margin: 14px 0;
  }
  .runoff-bar-row > div:first-child { grid-column: 1 / -1; }
  .runoff-visual .rv-fig-value { font-size: 16px; }
}
