/*
 * Every visual value the swarm exhibit uses is a --swarm-* custom property
 * declared here, with light defaults and a prefers-color-scheme: dark override.
 *
 * Unlike topology.css, most of these are consumed by canvas drawing code, which
 * cannot read custom properties: swarm-render.js reads them off the component
 * root with getComputedStyle. The tokens still live here - do not move any of
 * these values into JS.
 *
 * One rule that is not negotiable: the hostile swarm is PURPLE, never red-devil
 * imagery, matching the purple imp on the topology gremlin badge. Red is
 * reserved for node status and appears nowhere on the attackers.
 */

.swarm-viz {
  --swarm-field-bg: #f4f4f2;
  --swarm-field-border: #dcdcd6;
  --swarm-text: #1c1c1a;
  --swarm-muted: #76756f;

  /* The botnet. Purple, mechanical, impersonal. */
  --swarm-hostile: #7c3fbf;
  --swarm-hostile-locked: #6a26b0;

  --swarm-node-fill: #ffffff;
  --swarm-node-border: #b6b5ad;
  --swarm-node-text: #1c1c1a;

  /* Status semantics deliberately match the topology component so the
   * two exhibits read as one system. */
  --swarm-ok: #1aa674;
  --swarm-warn: #c48704;
  --swarm-down: #c0392f;

  --swarm-spawner: #8a8a82;
  /* Stroked, not filled - see the note in swarm-render.js. */
  --swarm-radius-ring: rgba(124, 63, 191, 0.42);
  /* One token for two elements on purpose: the expanding repulsion wave and the
   * cooldown bar saying when the next one can fire are the same mechanism seen
   * twice, so they share a colour by construction. Light blue reads as a shield
   * rather than a status - it sits next to the capacity meter without joining
   * the teal/amber/red health scale, and is not mistakable for the swarm. */
  --swarm-repulse: #2a9fd8;

  display: block;
  width: 100%;
}

@media (prefers-color-scheme: dark) {
  .swarm-viz {
    --swarm-field-bg: #17171a;
    --swarm-field-border: #2e2e33;
    --swarm-text: #e8e8e3;
    --swarm-muted: #9a998f;

    --swarm-hostile: #a97bea;
    --swarm-hostile-locked: #c39cf5;

    --swarm-node-fill: #232329;
    --swarm-node-border: #4a4a52;
    --swarm-node-text: #e8e8e3;

    --swarm-ok: #21c489;
    --swarm-warn: #fab219;
    --swarm-down: #e05a4e;

    --swarm-spawner: #6e6e78;
    --swarm-radius-ring: rgba(169, 123, 234, 0.45);
    --swarm-repulse: #5fc8f7;
  }
}

/* ---- scoreboard ----
 *
 * Off-field by design: the canvas carries only spawners, targets and boids, and
 * all text lives here above it. This is what makes the exhibit legible to
 * assistive tech at all, since a canvas is otherwise opaque. */

.swarm-scoreboard {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 10px;
}

.swarm-score {
  border: 1px solid var(--swarm-field-border);
  border-radius: 4px;
  padding: 7px 9px;
  background: var(--swarm-field-bg);
  min-width: 0;
}

.swarm-score-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: 5px;
}

.swarm-score-name {
  font-family: ui-monospace, "JetBrains Mono", "Cascadia Code", Consolas, monospace;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--swarm-node-text);
  letter-spacing: 0.02em;
}

.swarm-score-status {
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--swarm-ok);
}

.swarm-score[data-status="down"] .swarm-score-status {
  color: var(--swarm-down);
}

.swarm-score-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
}

.swarm-stat {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.swarm-stat-value {
  font-family: ui-monospace, "JetBrains Mono", "Cascadia Code", Consolas, monospace;
  font-size: 0.95rem;
  line-height: 1.1;
  color: var(--swarm-node-text);
  font-variant-numeric: tabular-nums;
}

.swarm-stat-label {
  font-size: 0.6rem;
  line-height: 1.25;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--swarm-muted);
}

/* ---- field ---- */

.swarm-canvas {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--swarm-field-border);
  border-radius: 4px;
  background: var(--swarm-field-bg);
}

/* Narrow screens: three score cards side by side stop being readable
 * well before the canvas does, so they stack. The three stats within a
 * card stay in a row - they are short numbers and reading them as a
 * group is the point. */
@media (max-width: 640px) {
  .swarm-scoreboard {
    grid-template-columns: 1fr;
    gap: 6px;
  }
}
