/* Figure: navigating a simplicial complex over sampled latent codes.
   Behaviour lives in static/js/simplicial-complex.js;
   markup is <d-figure id="figure-simplicial-complex"> in src/index.html.

   The viewBox is 1400 x 787.5 — 16:9 — and draws about 1180px wide at l-page, so
   sizes here render at roughly 0.84x — hence the slightly large-looking numbers. */

/* Colours come from the shared theme (static/js/theme.js); the literals here are
   only fallbacks for if it fails to load. Sample colours come from the theme's
   ramp, in the JS. */
.sx {
  /* inside the SVG: fixed, the panel stays on a light surface */
  --sx-ink: var(--vx-panel-ink, #16160f);
  --sx-ink-muted: var(--vx-panel-muted, #6b6a63);
  --sx-rule: var(--vx-panel-rule, #cfcec6);
  --sx-grid: var(--vx-panel-grid, #e6e5dd);
  --sx-hull: var(--vx-panel-hull, #f6f5f0);
  --sx-speck: var(--vx-panel-speck, #bcbcba);
  /* background sample dots */
  --sx-accent: var(--vx-accent, #eb6834);
  /* outside the SVG: follows the page theme */
  --sx-chrome-muted: var(--vx-muted, #6b6a63);
  --sx-chrome-rule: var(--vx-rule, #d8d7cf);
  margin: 2rem 0 2.5rem;
}

.sx-svg {
  display: block;
  width: 100%;
  height: auto;
  background: var(--vx-panel, #fff);
  border-radius: 3px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, sans-serif;
  touch-action: none;
}

.sx-math {
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
}

.sx-sub {
  font-size: 0.72em;
}

/* ---- the complex ---- */
/* Everything decorative lets the pointer through, so the hit rect underneath can
   resolve hover by point location once samples stop being their own elements. */
.sx-hull,
.sx-edge,
.sx-dots,
.sx-cell,
.sx-spoke,
.sx-mark {
  pointer-events: none;
}

.sx-hit {
  fill: transparent;
}

.sx-hull {
  fill: var(--sx-hull);
  stroke: none;
}

.sx-edge {
  fill: none;
  stroke: var(--sx-rule);
  stroke-width: 1.4;
}

/* Thousands of samples, drawn as one path: no per-sample colour, since at that
   size it would say nothing. The support and the hovered sample are redrawn as
   real circles on top. */
.sx-dots {
  fill: var(--sx-speck);
  stroke: none;
}

.sx-mark {
  stroke: #fff;
  stroke-width: 1.5;
}

.sx-mark.is-active {
  stroke: var(--sx-ink);
  stroke-width: 2;
}

/* The simplex z is inside, tinted with the colour z interpolates. */
.sx-cell {
  fill-opacity: 0.42;
  stroke: var(--sx-ink);
  stroke-opacity: 0.35;
  stroke-width: 1.5;
}

/* One line each while the support is small, one path per width band past that —
   hence fill:none, which a <line> did not need but a <path> very much does. */
.sx-spoke {
  fill: none;
  stroke: var(--sx-ink);
  stroke-opacity: 0.45;
  stroke-linecap: round;
}

/* The support drawn in bulk: one path per coarsened colour, in the panel and in
   the parameter square. Same look as the circles they stand in for, so crossing
   BULK_SUPPORT changes the element count and not the picture. */
.sx-mark-band {
  stroke: #fff;
  stroke-width: 1.5;
  pointer-events: none;
}

.sx-square-band {
  fill-opacity: 0.75;
  stroke: var(--sx-ink);
  stroke-width: 0.5;
  pointer-events: none;
}

/* ---- samples ---- */
.sx-vert-mark {
  stroke: #fff;
  stroke-width: 2;
}

.sx-vert-label {
  font-size: 12px;
  fill: var(--sx-ink);
  fill-opacity: 0.62;
  text-anchor: middle;
  pointer-events: none;
}

/* Too many samples to number them all: the label moves beside the circle and
   only appears for the support and whatever is hovered. */
.sx-vert-label.is-outside {
  text-anchor: start;
  paint-order: stroke;
  stroke: #fff;
  stroke-width: 2.5;
  stroke-linejoin: round;
}

.sx-verts-quiet .sx-vert-label {
  display: none;
}

.sx-verts-quiet .sx-vert.is-support .sx-vert-label,
.sx-verts-quiet .sx-vert.is-active .sx-vert-label {
  display: block;
  fill-opacity: 1;
}

.sx-vert.is-active .sx-vert-mark {
  stroke: var(--sx-ink);
  stroke-width: 2.5;
}

.sx-vert.is-active .sx-vert-label {
  fill-opacity: 1;
}

/* ---- the moving point ---- */
.sx-z {
  cursor: grab;
}

.sx-z:focus {
  outline: none;
}

.sx-z.is-dragging {
  cursor: grabbing;
}

.sx-z-hit {
  fill: transparent;
  /* transparent, not none: it still takes the pointer */
}

.sx-z-mark {
  stroke: var(--sx-ink);
  stroke-width: 2;
  stroke-opacity: 0.55;
}

.sx-z:hover .sx-z-mark,
.sx-z:focus-visible .sx-z-mark,
.sx-z.is-dragging .sx-z-mark {
  stroke: var(--sx-accent);
  stroke-width: 3;
  stroke-opacity: 1;
}

.sx-z-label {
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  /* sized to Z_R_MIN, which the 16:9 panel lowered from 13 to 12 */
  font-size: 17px;
  fill: #fff;
  text-anchor: middle;
  pointer-events: none;
}

.sx-z-label.is-dark {
  fill: var(--sx-ink);
}

/* ---- chart ---- */
.sx-title {
  font-size: 17px;
  font-weight: 700;
  fill: var(--sx-ink);
}

.sx-subtitle,
.sx-note {
  font-size: 13px;
  fill: var(--sx-ink-muted);
}

.sx-tick {
  font-size: 12px;
  fill: var(--sx-ink-muted);
  text-anchor: middle;
}

.sx-grid line {
  stroke: var(--sx-grid);
  stroke-width: 1;
}

.sx-axis {
  stroke: var(--sx-rule);
  stroke-width: 1.5;
}

.sx-row-hit {
  fill: transparent;
}

.sx-bar {
  stroke: var(--sx-rule);
  stroke-width: 0.75;
}

.sx-row-label {
  font-size: 13px;
  fill: var(--sx-ink-muted);
  text-anchor: end;
}

.sx-value {
  font-size: 12px;
  fill: var(--sx-ink-muted);
  text-anchor: start;
}

/* A sample outside the support: weight exactly zero, so the row recedes. */
.sx-row.is-off .sx-row-label {
  fill-opacity: 0.45;
}

.sx-row.is-active .sx-row-label,
.sx-row.is-active .sx-value {
  fill: var(--sx-ink);
  font-weight: 700;
}

.sx-row.is-active .sx-bar {
  stroke: var(--sx-accent);
  stroke-width: 1.5;
}

/* ---- controls ---- */
.sx-controls {
  margin-top: 10px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, sans-serif;
}

.sx-control-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
}

.sx-control-line+.sx-control-line {
  margin-top: 8px;
}

.sx-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.sx-field-label {
  font-size: 11px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--sx-chrome-muted);
}

.sx-field-value {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 12px;
  min-width: 1.6em;
  color: inherit;
}

.sx-slider input[type="range"] {
  width: 132px;
  /* 6…100 samples needs room to be steered one at a time */
  accent-color: var(--sx-accent);
}

/* k only shapes the mix in k-nearest mode, but moving it switches to that mode,
   so the control is dimmed rather than disabled. */
.sx-field.is-muted .sx-field-label,
.sx-field.is-muted .sx-field-value {
  opacity: 0.5;
}

.sx-field.is-muted input[type="range"] {
  opacity: 0.55;
}

.sx-btn {
  font: inherit;
  font-size: 12px;
  line-height: 1;
  padding: 6px 12px;
  color: inherit;
  background: transparent;
  border: 1px solid var(--sx-chrome-rule);
  border-radius: 4px;
  cursor: pointer;
}

.sx-btn:hover {
  border-color: var(--sx-chrome-muted);
}

.sx-btn i {
  font-family: Georgia, "Times New Roman", serif;
}

/* the local/global pair reads as one segmented control */
.sx-modes {
  display: inline-flex;
}

.sx-btn-mode {
  border-radius: 0;
  margin-left: -1px;
}

.sx-btn-mode:first-child {
  border-radius: 4px 0 0 4px;
  margin-left: 0;
}

.sx-btn-mode:last-child {
  border-radius: 0 4px 4px 0;
}

.sx-btn-mode.is-on {
  color: #fff;
  background: var(--sx-ink);
  border-color: var(--sx-ink);
}

.sx-hint {
  font-size: 12px;
  color: var(--sx-chrome-muted);
}

.sx-hint i {
  font-family: Georgia, "Times New Roman", serif;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .sx-btn-mode.is-on {
    color: #16160f;
    background: #e8e7df;
    border-color: #e8e7df;
  }
}

:root[data-theme="dark"] .sx-btn-mode.is-on {
  color: #16160f;
  background: #e8e7df;
  border-color: #e8e7df;
}

/* ---- the parameter square and the 4-D coordinates ---- */
.sx-square-box {
  fill: var(--sx-hull);
  stroke: var(--sx-rule);
  stroke-width: 1.5;
}

/* The support's own parameters, in the samples' own colours — which for a surface
   dataset are read off those very parameters, making the square its own legend.
   The fill is set in the JS; this is the fallback. */
.sx-square-dot {
  /* fill: var(--sx-ink); */
  fill-opacity: 0.75;
  stroke: var(--sx-ink);
  stroke-width: 0.5;
  pointer-events: none;
}

.sx-square-z {
  stroke: var(--sx-ink);
  stroke-width: 2;
  pointer-events: none;
}

/* The weighted average, as a rule standing among the dots it summarises. */
.sx-ambient-mark {
  fill: var(--sx-ink);
  pointer-events: none;
}

/* One neighbour each, stacked where they coincide, area carrying the weight …
   … and past BULK_SUPPORT the same dots batched into a path per radius band, so
   the row still shows every contributor the rule above it is averaging. */
.sx-ambient-dot,
.sx-ambient-band {
  fill: var(--sx-accent);
  fill-opacity: 0.6;
  stroke: var(--vx-panel, #fff);
  stroke-width: 0.6;
  pointer-events: none;
}

/* Edge identifications on the parameter square: single arrows where the pair is
   glued directly, double where it is glued with a flip. */
.sx-seam {
  fill: none;
  stroke: var(--sx-ink);
  stroke-opacity: 0.55;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

.sx-seams.is-hidden {
  display: none;
}

/* The smooth kernel's cutoff, as a ring around z on the complex itself. */
.sx-cutoff {
  fill: none;
  stroke: var(--sx-ink);
  stroke-opacity: 0.4;
  stroke-width: 1.5;
  stroke-dasharray: 6 5;
  pointer-events: none;
}

.sx-cutoff.is-hidden {
  display: none;
}

/* ---- the coordinate history ---- */
/* Zero is the line the coordinates are signed about, so it reads above the rest
   of the grid rather than as one more level. */
.sx-grid g.is-zero line {
  stroke: var(--sx-rule);
}

.sx-hist-level {
  text-anchor: end;
}

.sx-hist-lines {
  pointer-events: none;
}

/* Stroke colour is per series, from the theme's line set, and set in the JS. */
.sx-hist-line {
  fill: none;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* Where each line has got to, and the name tied back to it — the second cue the
   four line colours need, since two of them share a lightness. */
.sx-hist-now,
.sx-hist-tie,
.sx-hist-name {
  pointer-events: none;
}

.sx-hist-tie {
  stroke-width: 1;
  stroke-opacity: 0.55;
}

.sx-hist-name {
  font-size: 14px;
  text-anchor: start;
}

/* The samples on the parameter square, matching how the panel draws the same ones:
   their own colour while they are each their own element … */
.sx-square-vert {
  stroke: var(--vx-panel, #fff);
  stroke-width: 0.5;
  pointer-events: none;
}

/* … and one grey path once there are too many for that, which leaves colour free
   to mark the neighbourhood instead. */
.sx-square-speck {
  /* fill: var(--sx-speck); */
  fill: color-mix(in srgb, var(--sx-speck), white 60%);
  pointer-events: none;
}