/*
 * TdkRadar: a decorative radar dish (radar/radar.js has the markup and the animation). Plain
 * CSS, so server-rendered pages can use it with the same markup; it needs tokens.css and
 * severity.css for the colors below.
 *
 * Three layers share one grid cell: the dish (rings, axes and bearing ticks), the sweep (a
 * conic gradient, so its trail fades smoothly) and the contacts on top. Colors are four roles,
 * each a kit token, and can be overridden per radar:
 *   --tdk-radar-dish    rings, ticks, face and centre: categorical slot 6 (teal in the Tyler
 *                       palette), so data palettes re-theme it
 *   --tdk-radar-signal  the beam and ordinary contacts: green, nothing wrong
 *   --tdk-radar-threat  a contact flagged as a threat and its target lock: critical red
 *   --tdk-radar-track   the tracked target, its trail and heading: medium yellow, worth watching
 * --tdk-radar-size sets the width (TdkRadar's `size`) and --tdk-radar-period one turn of the beam.
 */

.tdk-radar {
  --tdk-radar-size: 280px;
  --tdk-radar-period: 4s;
  --tdk-radar-dish: var(--tdk-chart-6);
  --tdk-radar-signal: var(--tdk-sev-low);
  --tdk-radar-threat: var(--tdk-sev-critical);
  /* Tyler yellow is under 2:1 on white, so light theme takes it toward its text shade. */
  --tdk-radar-track: color-mix(in srgb, var(--tdk-sev-medium) 60%, var(--tdk-sev-medium-text));
  /* The beam's leading edge. */
  --tdk-radar-edge: var(--tdk-radar-signal);
  display: grid;
  width: var(--tdk-radar-size);
  max-width: 100%;
  aspect-ratio: 1;
}

/* On dark surfaces the dish and beam lift toward white, as on a lit scope. :where() keeps this
 * at the specificity of .tdk-radar, so a page's own .hero .tdk-radar { --tdk-radar-dish: … } wins. */
:where(:root[data-theme='dark']) .tdk-radar {
  --tdk-radar-dish: color-mix(in srgb, var(--tdk-chart-6) 72%, var(--tdk-color-heading));
  --tdk-radar-signal: color-mix(in srgb, var(--tdk-sev-low) 85%, var(--tdk-color-heading));
  --tdk-radar-track: var(--tdk-sev-medium);
  --tdk-radar-edge: color-mix(in srgb, var(--tdk-radar-signal) 45%, var(--tdk-color-heading));
}

.tdk-radar > * {
  grid-area: 1 / 1;
}

.tdk-radar svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* ---- Dish ---- */
.tdk-radar__stop {
  stop-color: var(--tdk-radar-dish);
  stop-opacity: 0.16;
}

.tdk-radar__stop--edge {
  stop-opacity: 0.04;
}

.tdk-radar__ring {
  fill: none;
  stroke: var(--tdk-radar-dish);
  stroke-opacity: 0.32;
  stroke-width: 1;
}

.tdk-radar__ring--outer {
  stroke-opacity: 0.7;
}

.tdk-radar__axis {
  stroke: var(--tdk-radar-dish);
  stroke-opacity: 0.22;
  stroke-width: 1;
}

.tdk-radar__axis--diagonal {
  stroke-dasharray: 2 4;
}

.tdk-radar__tick {
  stroke: var(--tdk-radar-dish);
  stroke-opacity: 0.42;
  stroke-width: 1;
}

.tdk-radar__tick--major {
  stroke-opacity: 0.85;
  stroke-width: 1.5;
}

.tdk-radar__scan-ring {
  fill: none;
  stroke: var(--tdk-radar-signal);
  stroke-opacity: 0.45;
  stroke-width: 1;
  stroke-dasharray: 2 9;
  transform-origin: 100px 100px;
  animation: tdk-radar-turn calc(var(--tdk-radar-period) * 12) linear infinite reverse;
}

/* The beam: a bright leading edge with a trail fading behind it. Inset to the dish, whose
 * 92-unit radius in the 200-unit viewBox leaves 4% on each side. radar.js times the contacts
 * from this element's animation. */
.tdk-radar__sweep {
  margin: 4%;
  border-radius: 50%;
  background: conic-gradient(
    transparent 0deg 240deg,
    color-mix(in srgb, var(--tdk-radar-signal) 28%, transparent) 357deg,
    color-mix(in srgb, var(--tdk-radar-edge) 90%, transparent) 359deg 360deg
  );
  animation: tdk-radar-turn var(--tdk-radar-period) linear infinite;
}

.tdk-radar__core {
  fill: var(--tdk-radar-dish);
}

.tdk-radar__core-halo {
  fill: none;
  stroke: var(--tdk-radar-dish);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  animation: tdk-radar-halo 3s ease-out infinite;
}

/* ---- Contacts: a blip, a ping ring that spreads as the beam crosses it, and corner brackets
 * that lock onto a threat. ---- */
.tdk-radar__blip {
  fill: var(--tdk-radar-signal);
  opacity: 0;
  animation: tdk-radar-blip var(--tdk-radar-period) ease-out infinite;
}

.tdk-radar__ping,
.tdk-radar__lock {
  fill: none;
  stroke: var(--tdk-radar-signal);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.tdk-radar__ping {
  animation: tdk-radar-ping var(--tdk-radar-period) ease-out infinite;
}

.tdk-radar__lock {
  display: none;
  stroke-width: 1.5;
  animation: tdk-radar-lock var(--tdk-radar-period) ease-out infinite;
}

.tdk-radar__contact--threat .tdk-radar__blip {
  fill: var(--tdk-radar-threat);
}

.tdk-radar__contact--threat .tdk-radar__ping,
.tdk-radar__contact--threat .tdk-radar__lock {
  stroke: var(--tdk-radar-threat);
}

.tdk-radar__contact--threat .tdk-radar__lock {
  display: inline;
}

/* Without radar.js, each contact lights as the beam reaches its bearing in the markup: the
 * fraction of a turn to the default spots in radar.js (SPOTS). */
.tdk-radar__contact:nth-child(1) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.125);
}
.tdk-radar__contact:nth-child(2) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.62);
}
.tdk-radar__contact:nth-child(3) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.357);
}
.tdk-radar__contact:nth-child(4) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.861);
}
.tdk-radar__contact:nth-child(5) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.447);
}
.tdk-radar__contact:nth-child(6) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.738);
}
.tdk-radar__contact:nth-child(7) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.005);
}
.tdk-radar__contact:nth-child(8) > * {
  animation-delay: calc(var(--tdk-radar-period) * 0.234);
}

/* radar.js places and times the contacts itself (tdk-radar--live), and draws the tracked
 * target (tdk-radar--tracking): its last few paints and its heading. */
.tdk-radar--live .tdk-radar__contact > * {
  animation: none;
}

.tdk-radar__track {
  display: none;
}

.tdk-radar--tracking .tdk-radar__track {
  display: inline;
}

.tdk-radar__echo {
  fill: var(--tdk-radar-track);
  opacity: 0;
}

.tdk-radar__vector {
  stroke: var(--tdk-radar-track);
  stroke-width: 1.5;
  stroke-linecap: round;
  opacity: 0;
}

@keyframes tdk-radar-turn {
  to {
    transform: rotate(360deg);
  }
}

@keyframes tdk-radar-blip {
  0% {
    opacity: 1;
  }
  70% {
    opacity: 0.15;
  }
  100% {
    opacity: 0;
  }
}

@keyframes tdk-radar-ping {
  0% {
    opacity: 0.9;
    transform: scale(1);
  }
  30%,
  100% {
    opacity: 0;
    transform: scale(4.5);
  }
}

@keyframes tdk-radar-lock {
  0% {
    opacity: 0;
    transform: scale(1.8);
  }
  8%,
  60% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(1);
  }
}

@keyframes tdk-radar-halo {
  0% {
    opacity: 0.6;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(2.4);
  }
}

/* A still picture: the beam part way round, the contacts lit, and the threat locked. */
@media (prefers-reduced-motion: reduce) {
  .tdk-radar__sweep,
  .tdk-radar__scan-ring,
  .tdk-radar__core-halo,
  .tdk-radar__contact > * {
    animation: none;
  }

  .tdk-radar__sweep {
    transform: rotate(50deg);
  }

  .tdk-radar__blip {
    opacity: 0.8;
  }

  .tdk-radar__contact--threat .tdk-radar__lock {
    opacity: 1;
  }
}

@media (forced-colors: active) {
  .tdk-radar {
    --tdk-radar-dish: CanvasText;
    --tdk-radar-signal: CanvasText;
    --tdk-radar-edge: CanvasText;
    --tdk-radar-threat: Highlight;
    --tdk-radar-track: Highlight;
  }
}
