/* =============================================================
   ratiovis.css  -  appearance of the ratio-ball picture (ratiovis.js)
   Shared file, identical in both apps. Everything is prefixed rv-.
   Tokens only (design-system.css). --lim-* / --exc-* / --inset belong to
   the app's own styles.css, so each is read with a fallback: an app that
   does not define them still gets the same look.

   Reading the picture: outlined ball = what the equation needs; solid =
   what you have; dashed = missing or extra. Lavender / apricot = the two
   reactants before the verdict; willow (--lim-*) = limiting, lavender
   (--exc-*) = excess once it is known. Colour is never the only signal:
   outline style, a one-word tag and the numbers say the same thing.
   ============================================================= */

.rv {
  --rv-panel: var(--inset, color-mix(in srgb, var(--card-2) 55%, var(--card)));
  --rv-umax: 40px;                /* biggest ball slot on screen (ball = 85 % of it) */
  --rv-umin: 26px;                /* smallest slot before the columns stack */
  --rv-ctl: 34px;                 /* height of a fit-control segment */

  position: relative; display: block; box-sizing: border-box; max-width: 100%;
  padding: var(--sp-4);
  background: var(--rv-panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--ink);
  font-family: var(--font-body);
}
.rv--sm { --rv-umax: 28px; --rv-umin: 20px; --rv-ctl: 30px; padding: var(--sp-3); }
.rv--sm .rv-pic { gap: var(--sp-3); }
.rv--sm .rv-cols { gap: var(--sp-3) var(--sp-4); }
.rv--sm .rv-f { font-size: 1rem; }
.rv--sm .rv-n, .rv--sm .rv-sum__v { font-size: 1rem; }
.rv--sm .rv-cell { gap: 4px; }
.rv--sm .rv-cap { min-height: 24px; }
.rv sub, .rv sup { font-size: .66em; }
.rv-nw { white-space: nowrap; }

/* ---------- tones: the colours a reactant's balls and tags take ----------
   a / b = the two reactants before the verdict, lim / exc = limiting / excess
   after it, prod = the product. Values live in the --rv-<tone>-* tokens below
   so the dark-mode switch is written once per tone, not once per rule. */
.rv {
  --rv-a-line: var(--lav-600);  --rv-a-fill: var(--lav-200);   --rv-a-ink: var(--lav-700);  --rv-a-tag: var(--lav-50);
  --rv-b-line: color-mix(in srgb, var(--warn) 72%, var(--warn-ink)); --rv-b-fill: color-mix(in srgb, var(--warn) 52%, var(--card)); --rv-b-ink: var(--warn-ink); --rv-b-tag: var(--warn-soft);
  --rv-lim-line: var(--lim-ink, var(--grn-900)); --rv-lim-fill: var(--lim-bg, var(--grn-200)); --rv-lim-ink: var(--lim-ink, var(--grn-900)); --rv-lim-tag: var(--lim-bg, var(--grn-200));
  --rv-exc-line: var(--exc-ink, var(--lav-900)); --rv-exc-fill: var(--exc-bg, var(--lav-100));  --rv-exc-ink: var(--exc-ink, var(--lav-900)); --rv-exc-tag: var(--exc-bg, var(--lav-100));
  --rv-prod-line: var(--grn-700); --rv-prod-fill: var(--grn-400); --rv-prod-ink: var(--grn-900); --rv-prod-tag: var(--grn-50);
}
[data-theme="dark"] .rv {
  --rv-a-line: var(--lav-200);  --rv-a-fill: var(--lav-400);  --rv-a-ink: var(--lav-100); --rv-a-tag: var(--card-2);
  --rv-b-line: var(--warn);     --rv-b-fill: color-mix(in srgb, var(--warn) 52%, var(--card)); --rv-b-ink: var(--warn-ink); --rv-b-tag: var(--warn-soft);
  --rv-lim-line: var(--grn-300); --rv-lim-fill: color-mix(in srgb, var(--lim-bg, var(--grn-200)) 78%, var(--rv-panel));
  --rv-exc-line: var(--lav-200); --rv-exc-fill: color-mix(in srgb, var(--exc-bg, var(--lav-100)) 62%, var(--rv-panel));
  --rv-prod-line: var(--grn-300); --rv-prod-fill: var(--grn-400); --rv-prod-ink: var(--grn-200); --rv-prod-tag: var(--accent-soft);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .rv {
    --rv-a-line: var(--lav-200);  --rv-a-fill: var(--lav-400);  --rv-a-ink: var(--lav-100); --rv-a-tag: var(--card-2);
    --rv-b-line: var(--warn);     --rv-b-fill: color-mix(in srgb, var(--warn) 52%, var(--card)); --rv-b-ink: var(--warn-ink); --rv-b-tag: var(--warn-soft);
    --rv-lim-line: var(--grn-300); --rv-lim-fill: color-mix(in srgb, var(--lim-bg, var(--grn-200)) 78%, var(--rv-panel));
    --rv-exc-line: var(--lav-200); --rv-exc-fill: color-mix(in srgb, var(--exc-bg, var(--lav-100)) 62%, var(--rv-panel));
    --rv-prod-line: var(--grn-300); --rv-prod-fill: var(--grn-400); --rv-prod-ink: var(--grn-200); --rv-prod-tag: var(--accent-soft);
  }
}
.rv-tone--a    { --rv-line: var(--rv-a-line);    --rv-fill: var(--rv-a-fill);    --rv-ink: var(--rv-a-ink);    --rv-tag: var(--rv-a-tag); }
.rv-tone--b    { --rv-line: var(--rv-b-line);    --rv-fill: var(--rv-b-fill);    --rv-ink: var(--rv-b-ink);    --rv-tag: var(--rv-b-tag); }
.rv-tone--lim  { --rv-line: var(--rv-lim-line);  --rv-fill: var(--rv-lim-fill);  --rv-ink: var(--rv-lim-ink);  --rv-tag: var(--rv-lim-tag); }
.rv-tone--exc  { --rv-line: var(--rv-exc-line);  --rv-fill: var(--rv-exc-fill);  --rv-ink: var(--rv-exc-ink);  --rv-tag: var(--rv-exc-tag); }
.rv-tone--prod { --rv-line: var(--rv-prod-line); --rv-fill: var(--rv-prod-fill); --rv-ink: var(--rv-prod-ink); --rv-tag: var(--rv-prod-tag); }
.rv-col { --rv-soft: color-mix(in srgb, var(--rv-fill) 45%, var(--rv-panel)); }   /* extra balls: a paler fill */

/* ---------- layout ----------
   One column per reactant (and one for the product). Columns sit side by
   side while the widest group in the picture still gets a ball slot of at
   least --rv-umin; below that they stack, so nothing ever scrolls sideways.
   Each column is a subgrid, so a row (head / need / have) lines up across columns.
   (The ratio line and the pick badge sit outside the grid on purpose: an item
   spanning every track would keep auto-fit from dropping the empty ones.) */
.rv-pic { display: flex; flex-direction: column; gap: var(--sp-4); }
.rv-cols {
  display: grid; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, max(calc(var(--rv-max, 4) * var(--rv-umin)), 112px)), 1fr));
  gap: var(--sp-4) var(--sp-5);
}
.rv-col {
  display: grid; grid-template-rows: subgrid; grid-row: span var(--rv-rows, 3);
  row-gap: var(--sp-2); min-width: 0;
}
@supports not (grid-template-rows: subgrid) {
  .rv-col { display: flex; flex-direction: column; gap: var(--sp-2); }
}
.rv-head {
  display: flex; align-items: center; gap: 6px; min-height: 28px;
  font: var(--t-quantity); font-size: 1.0625rem; color: var(--ink); overflow-wrap: anywhere;
}
.rv-op { color: var(--muted); font-weight: var(--w-semi); padding-right: 2px; }
.rv-cell { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.rv-rowlab { font: var(--t-label); text-transform: uppercase; letter-spacing: var(--tr-label); color: var(--muted); }
.rv-balls { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 6px 8px; }

/* the SVG is sized so every ball in the picture is the same size on screen:
   --c balls wide, each at most --rv-umax, shrunk together if the column is narrow */
.rv-svg {
  display: block; flex: 0 0 auto; max-width: 100%; height: auto; overflow: visible;
  width: min(calc(var(--c) / var(--rv-max, 4) * 100%), calc(var(--c) * var(--rv-umax)));
}

/* ---------- balls ---------- */
.rv-b {
  fill: none; stroke: var(--rv-line); stroke-width: 1.6px; vector-effect: non-scaling-stroke;
  transform-box: fill-box; transform-origin: center;
}
.rv-part { transform-box: fill-box; transform-origin: center; }
.rv-b--ghost { fill: color-mix(in srgb, var(--rv-line) 7%, transparent); }      /* what the equation needs */
.rv-b--solid { fill: var(--rv-fill); }                                          /* what you have */
.rv-b--miss  { stroke-dasharray: 3.5px 3px; }                                   /* the part you lack */
.rv-b--extra { stroke-dasharray: 3.5px 3px; fill: var(--rv-soft); }             /* beyond the recipe */

/* ---------- captions: number, tags ---------- */
.rv-cap { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-height: 26px; }
.rv-n { font: var(--w-semi) 1.0625rem/1.2 var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink); }
.rv-amt { font: var(--t-mono); color: var(--ink-2); }
.rv-tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 9px; min-height: 22px; border-radius: var(--r-pill);
  font: var(--t-label); letter-spacing: .01em; line-height: 1.3; white-space: nowrap;
  background: var(--rv-tag); color: var(--rv-ink); border: 1.5px solid var(--rv-ink);
}
.rv-tag--extra, .rv-tag--left { border-style: dashed; }          /* excess = dashed, like .chip--exc; limiting stays solid, like .chip--lim */
.rv-tag--match { padding: 1px 7px; }
.rv-tag--theo, .rv-tag--used { background: transparent; }
.rv-tag--act  { background: var(--rv-fill); color: var(--grn-900); }
.rv-more {
  display: inline-flex; align-items: center; padding: 0 8px; min-height: 22px; margin-bottom: 4px;
  border: 1.5px dashed var(--rv-ink); border-radius: var(--r-pill);
  font: var(--w-semi) var(--fs-label)/1.3 var(--font-mono); color: var(--rv-ink); background: var(--rv-tag);
}
.rv-ic { width: 1em; height: 1em; flex: none; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }

/* the learner's pick (Practice): a round badge on the picked column, or "Neither" */
.rv-mark {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 22px; height: 22px; border-radius: 50%; font-size: .8125rem;
  border: 1.5px solid currentColor;
}
.rv-mark--ok { color: var(--success); background: var(--success-soft); }
.rv-mark--no { color: var(--danger);  background: var(--danger-soft); }
.rv-pick {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 8px;
  padding: 2px 4px 2px 12px; border-radius: var(--r-pill); border: 1.5px solid currentColor;
  font: var(--t-body-strong); line-height: 1.3;
}
.rv-pick--ok { color: var(--success); background: var(--success-soft); }
.rv-pick--no { color: var(--danger);  background: var(--danger-soft); }
.rv-pick .rv-mark { border: 0; background: transparent; }

/* ---------- ratio line, scale label, fit control ---------- */
.rv-sum {
  display: flex; flex-wrap: wrap; gap: 4px var(--sp-5);
  padding-top: var(--sp-3); border-top: 1px dashed var(--line-strong);
}
.rv-sum__i { display: inline-flex; align-items: baseline; gap: 8px; }
.rv-sum__l { font: var(--t-label); text-transform: uppercase; letter-spacing: var(--tr-label); color: var(--muted); }
.rv-sum__v { font: var(--w-semi) 1.0625rem/1.3 var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink); }

.rv-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-3);
}
.rv-scale { display: inline-flex; align-items: center; gap: 8px; font: var(--t-mono); color: var(--ink-2); }
.rv-scale b { font-weight: var(--w-semi); color: var(--ink); }
.rv-dot { flex: none; width: 14px; height: 14px; border-radius: 50%; background: var(--rv-a-fill); border: 1.6px solid var(--rv-a-line); }

.rv-fit { display: inline-flex; align-items: center; gap: var(--sp-2); }
.rv-fit__lab { font: var(--t-label); text-transform: uppercase; letter-spacing: var(--tr-label); color: var(--muted); }
/* the look of .seg (design-system.css), copied so the picture never depends on it */
.rv-seg {
  display: inline-flex; flex-wrap: wrap; gap: 3px; padding: 3px;
  border: 1px solid var(--line-strong); border-radius: calc(var(--rv-ctl) / 2 + 4px); background: var(--bg-tint);
}
.rv-seg__btn {
  appearance: none; display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--rv-ctl); min-width: 44px; padding: 4px var(--sp-4); margin: 0;
  border: 0; border-radius: var(--r-pill); background: transparent; color: var(--muted);
  font: var(--w-semi) var(--fs-small)/1.3 var(--font-mono); cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.rv-seg__btn:hover { color: var(--ink); }
.rv-seg__btn[aria-pressed="true"] { background: var(--primary-soft); color: var(--primary-soft-ink); box-shadow: inset 0 0 0 1px var(--primary); }
.rv-seg__btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: var(--focus-ring); }

.rv-live { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

@media (max-width: 480px) {
  .rv { padding: var(--sp-3); }
  .rv-cols { column-gap: var(--sp-4); }
}

/* ---------- the working: how moles become balls ---------- */
.rv-work { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px dashed var(--line-strong); font-size: .9375rem; line-height: 1.5; color: var(--ink); }
.rv-work__h { margin: 0 0 var(--sp-2); font: var(--t-label); text-transform: uppercase; letter-spacing: var(--tr-label); color: var(--muted); }
.rv-work p { margin: 0 0 var(--sp-2); max-width: none; }
.rv-work ol, .rv-work ul { margin: 0; padding-left: 1.3em; }
.rv-work ul { margin: 2px 0 0; list-style: none; padding-left: .2em; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.rv-work li { margin-bottom: 4px; }
.rv-work li::marker { color: var(--primary); font-weight: var(--w-semi); }
.rv-work sub, .rv-work sup { font-size: .66em; }

/* ---------- the ELI5 button (top right of the picture) and its dialogue ---------- */
.rv-top { display: flex; justify-content: flex-end; margin: calc(var(--sp-1) * -1) 0 var(--sp-2); }
.rv-help {
  appearance: none; display: inline-flex; align-items: center; gap: 6px; margin: 0; padding: 3px 12px 3px 4px;
  min-height: 32px; border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--card);
  color: var(--primary-soft-ink); font: var(--w-semi) var(--fs-small)/1 var(--font-body); cursor: pointer;
  transition: background-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.rv-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.rv-help:hover { background: var(--primary-soft); box-shadow: inset 0 0 0 1px var(--primary); }
.rv-help:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: var(--focus-ring); }
.rv-help__i {
  display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%;
  background: var(--primary-soft); color: var(--primary-soft-ink); box-shadow: inset 0 0 0 1px var(--primary);
  font: italic var(--w-semi) .95rem/1 var(--font-display, Georgia, serif);
}
.rv-dialog {
  box-sizing: border-box; width: min(34rem, calc(100vw - 2rem)); max-height: calc(100dvh - 2rem); margin: auto; padding: 0;
  border: 1px solid var(--line-strong); border-radius: var(--r-lg); background: var(--card); color: var(--ink);
  box-shadow: var(--shadow-3); font-family: var(--font-body);
}
.rv-dialog::backdrop { background: var(--overlay, rgba(46, 27, 82, .48)); }
.rv-dialog__card { display: flex; flex-direction: column; max-height: calc(100dvh - 2rem); }
.rv-dialog__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-5) var(--sp-5) var(--sp-2); }
.rv-dialog__eyebrow { font: var(--t-label); text-transform: uppercase; letter-spacing: var(--tr-label); color: var(--link, var(--primary-soft-ink)); }
.rv-dialog__title { margin: 2px 0 0; font: var(--w-display, 700) 1.375rem/1.25 var(--font-display, var(--font-body)); }
.rv-dialog__x {
  appearance: none; flex: none; display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; padding: 0;
  border: 1px solid var(--line-strong); border-radius: 50%; background: transparent; color: var(--ink); cursor: pointer;
}
.rv-dialog__x:hover { background: var(--primary-soft); }
.rv-dialog__x:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: var(--focus-ring); }
.rv-dialog__x .rv-ic { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.rv-dialog__body { overflow-y: auto; padding: var(--sp-2) var(--sp-5) var(--sp-3); font-size: 1.0625rem; line-height: 1.55; }
.rv-dialog__body p { margin: 0 0 var(--sp-3); max-width: none; }
.rv-dialog__body ul { margin: 0 0 var(--sp-3); padding-left: 1.2em; }
.rv-dialog__body li { margin-bottom: 6px; }
.rv-dialog__body li::marker { color: var(--primary); }
.rv-dialog__body sub, .rv-dialog__body sup { font-size: .66em; }
.rv-dialog__foot { display: flex; justify-content: flex-end; padding: var(--sp-3) var(--sp-5) var(--sp-5); }
.rv-key { display: inline-block; vertical-align: -3px; width: 16px; height: 16px; margin-right: 4px; border-radius: 50%; border: 2px solid var(--lav-400, var(--primary)); box-sizing: border-box; }
.rv-key--solid { background: var(--lav-400, var(--primary)); }
.rv-key--dash { border-style: dashed; }

/* Windows high-contrast: keep the three states apart without relying on colour */
@media (forced-colors: active) {
  .rv-b { stroke: CanvasText; }
  .rv-b--ghost, .rv-b--miss { fill: Canvas; }
  .rv-b--solid { fill: Highlight; }
  .rv-b--extra { fill: Canvas; }
}
