/* The battlefield, read off a tactical display.
 *
 * The twenty-four points are not wedges of inlay any more - they are approach
 * lanes painted on the ice and lit up on the terminal: a threshold bar at the
 * outer edge, a dashed centreline running in towards the middle, a measuring
 * ladder along it, and a hairline where the lane narrows. Same triangles, same
 * geometry, same hit boxes - what changed is what they are pretending to be.
 *
 * Geometry constants mirror js/layout.js.
 */

:root {
  /* All four corners cut, which is what turns a rectangle into a screen. */
  --bezel: polygon(
    24px 0, calc(100% - 24px) 0, 100% 24px, 100% calc(100% - 24px),
    calc(100% - 24px) 100%, 24px 100%, 0 calc(100% - 24px), 0 24px);
  --bezel-sm: polygon(
    9px 0, calc(100% - 9px) 0, 100% 9px, 100% calc(100% - 9px),
    calc(100% - 9px) 100%, 9px 100%, 0 calc(100% - 9px), 0 9px);

  /* The alternation that lets you count lanes in pairs - the two armies' own
     colours, running down both columns regardless of whose ground it is, the
     way light and dark points do on a wooden board.

     Red lights a lane up. Black cannot, so the black lane is the one the light
     is taken out of instead, and it needs a heavier hand to register at all:
     hence a peak and a mid alpha per variant rather than one pair shared by
     both. The scan lines still run across it, so it reads as a lane with the
     lamps off rather than a hole in the display. */
  --lane-warm: 255, 59, 48;
  --lane-cold: 5, 8, 14;
}

#board {
  position: absolute;
  left: 0;
  top: 0;
  width: 700px;
  height: 878px;
  clip-path: var(--bezel);
  background: linear-gradient(150deg, rgba(140, 205, 255, 0.75), rgba(60, 116, 172, 0.5) 45%, rgba(120, 190, 250, 0.45));
  box-shadow: 0 30px 60px rgba(2, 6, 14, 0.7);
}

/* Snow terrain photographed from above, tiled, and then taken down to
   night. toptex-tile.png is toptex.png with its 2px navy UI frame cropped off,
   which would otherwise draw a grid of blue lines across the board. */
#surface {
  position: absolute;
  inset: 2px;
  clip-path: var(--bezel);
  background-image: url("../images/toptex-tile.png");
  background-size: 508px 446px;
  background-repeat: repeat;
  image-rendering: pixelated;
}

/* Night over the ice field.
   The snow texture is a daylight tile; these two layers composite it down to a
   mean of rgb(19,29,47), which is what gives the blaster bolts and the lit pads
   under the miniatures something to burn against. */
#surface::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 42%, rgba(46, 118, 178, 0.24) 0%, rgba(3, 10, 22, 0.72) 72%, rgba(2, 6, 14, 0.88) 100%),
    linear-gradient(to bottom, rgba(6, 18, 38, 0.78), rgba(3, 10, 24, 0.86));
}

/* ------------------------------------------------------------ the readout */

/* A survey grid over the terrain, and a scan running down it. Both are faint
   enough to be felt rather than looked at. */
#grid {
  position: absolute;
  inset: 2px;
  clip-path: var(--bezel);
  pointer-events: none;
  background-image:
    repeating-linear-gradient(to right, rgba(120, 195, 250, 0.055) 0 1px, transparent 1px 50px),
    repeating-linear-gradient(to bottom, rgba(120, 195, 250, 0.055) 0 1px, transparent 1px 50px);
  background-position: 14px 14px;
}
#grid::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 160px;
  top: -160px;
  background: linear-gradient(to bottom,
    rgba(120, 210, 255, 0) 0%, rgba(120, 210, 255, 0.05) 62%,
    rgba(150, 225, 255, 0.14) 92%, rgba(190, 240, 255, 0.28) 100%);
  animation: scan-sweep 9s linear infinite;
}
@keyframes scan-sweep {
  from { transform: translateY(0); }
  to { transform: translateY(1040px); }
}

/* The glass over the display: corner brackets and a cold sheen across it.
   Deliberately above the markings and below the miniatures - over the figures
   a bracket would cut across whoever is standing in the corner, and the whole
   thing is meant to be felt rather than looked at. */
#glass {
  position: absolute;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  clip-path: var(--bezel);
  background:
    /* four corner brackets, two strokes each */
    linear-gradient(var(--edge-hot), var(--edge-hot)) 26px 12px / 54px 2px no-repeat,
    linear-gradient(var(--edge-hot), var(--edge-hot)) 12px 26px / 2px 54px no-repeat,
    linear-gradient(var(--edge-hot), var(--edge-hot)) calc(100% - 26px) 12px / 54px 2px no-repeat,
    linear-gradient(var(--edge-hot), var(--edge-hot)) calc(100% - 12px) 26px / 2px 54px no-repeat,
    linear-gradient(var(--edge-hot), var(--edge-hot)) 26px calc(100% - 12px) / 54px 2px no-repeat,
    linear-gradient(var(--edge-hot), var(--edge-hot)) 12px calc(100% - 26px) / 2px 54px no-repeat,
    linear-gradient(var(--edge-hot), var(--edge-hot)) calc(100% - 26px) calc(100% - 12px) / 54px 2px no-repeat,
    linear-gradient(var(--edge-hot), var(--edge-hot)) calc(100% - 12px) calc(100% - 26px) / 2px 54px no-repeat,
    /* the sheen */
    linear-gradient(115deg, rgba(190, 235, 255, 0.05) 0%, transparent 26%, transparent 74%, rgba(190, 235, 255, 0.035) 100%);
}

/* The plinth the display stands on. */
#rim {
  position: absolute;
  left: 32px;
  right: 32px;
  top: 878px;
  height: 24px;
  clip-path: polygon(0 0, 100% 0, calc(100% - 14px) 100%, 14px 100%);
  background:
    repeating-linear-gradient(to right,
      rgba(0, 0, 0, 0.45) 0 3px, transparent 3px 11px),
    linear-gradient(to bottom, #24405e, #0c1a2c 55%, #050c18);
  box-shadow: 0 18px 30px rgba(2, 6, 14, 0.75);
}
#rim::before,
#rim::after {
  content: "";
  position: absolute;
  top: 5px;
  width: 44px;
  height: 3px;
}
#rim::before { left: 26px; background: var(--rebel); box-shadow: 0 0 10px rgba(255, 59, 48, 0.85); }
/* A 3px black stripe on a dark plinth is a gap in it rather than a marking, so
   the imperial end is lit steel. */
#rim::after { right: 26px; background: var(--empire-hot); box-shadow: 0 0 10px rgba(170, 212, 255, 0.7); }

/* ------------------------------------------------------------ the 24 lanes */

#points { position: absolute; inset: 0; }

/* Territory. The twelve lanes below the trench are the two home boards, and on
   a tactical display those are the ground each army is holding - so they are
   washed in that army's colour, deepening towards the evacuation pads they
   lead to. Painted behind the lanes, faint enough to be read as ground rather
   than as another marking.

   The Empire's colour is black, so its quadrant is not tinted but drained: the
   ground it holds is where the light on the field runs out. It is the one place
   a black wash works exactly as a coloured one would, because there is already
   a lit board underneath for it to take away from. */
#points::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(255, 59, 48, 0), rgba(255, 59, 48, 0.07)) 14px 446px / 286px 348px no-repeat,
    linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.42)) 400px 446px / 286px 348px no-repeat;
}

/* The demarcation line down the middle of the display, between the two
   columns of lanes and behind the printed numbers. */
#points::after {
  content: "";
  position: absolute;
  left: 349px;
  top: 14px;
  bottom: 14px;
  width: 2px;
  background: repeating-linear-gradient(to bottom,
    rgba(150, 210, 255, 0.35) 0 5px, transparent 5px 12px);
}

.point {
  position: absolute;
  width: 286px;
  height: 58px;
}
/* Lanes reach inwards from their own edge towards the centre line. */
.point.left { clip-path: polygon(0 0, 100% 50%, 0 100%); }
.point.right { clip-path: polygon(100% 0, 0 50%, 100% 100%); }

/* The wash: brightest at the threshold, gone well before the tip. Kept far
   weaker than a painted board triangle - it is meant to look projected onto
   the snow, not inlaid into a table. The horizontal banding is what does the
   work: a wedge of light with scan lines through it reads as a hologram, and
   a flat wedge of colour reads as a game board. */
.point .fill { position: absolute; inset: 0; }

.point.warm .fill { --lane: var(--lane-warm); --lane-peak: 0.22; --lane-mid: 0.08; }
.point.cold .fill { --lane: var(--lane-cold); --lane-peak: 0.62; --lane-mid: 0.26; }

.point.left .fill {
  background:
    repeating-linear-gradient(to bottom,
      rgba(255, 255, 255, 0.07) 0 1px, transparent 1px 4px),
    linear-gradient(to right,
      rgba(var(--lane), var(--lane-peak)) 0%, rgba(var(--lane), var(--lane-mid)) 46%, rgba(var(--lane), 0) 84%);
}
.point.right .fill {
  background:
    repeating-linear-gradient(to bottom,
      rgba(255, 255, 255, 0.07) 0 1px, transparent 1px 4px),
    linear-gradient(to left,
      rgba(var(--lane), var(--lane-peak)) 0%, rgba(var(--lane), var(--lane-mid)) 46%, rgba(var(--lane), 0) 84%);
}

/* A measuring ladder scored down the lane, fading out as the lane narrows. */
.point .fill::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(to right,
    rgba(226, 244, 255, 0.3) 0 1px, transparent 1px 18px);
}
.point.left .fill::after { mask-image: linear-gradient(to right, #000 10%, transparent 78%); }
.point.right .fill::after { mask-image: linear-gradient(to left, #000 10%, transparent 78%); }

/* The hairline where the lane narrows. */
.point .edge {
  position: absolute;
  inset: 0;
  clip-path: inherit;
  border: 1px solid rgba(190, 228, 255, 0.42);
}
.point.warm .edge { border-color: rgba(255, 132, 122, 0.5); }
.point.cold .edge { border-color: rgba(168, 186, 210, 0.45); }

/* The threshold bar at the outer end - where a lane starts. */
.point .edge::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 4px;
}
.point.left .edge::before { left: 0; }
.point.right .edge::before { right: 0; }
.point.warm .edge::before { background: rgba(255, 59, 48, 0.9); box-shadow: 0 0 9px rgba(255, 59, 48, 0.65); }
/* The threshold is the mark you count lanes off, so it is the one part of a
   black lane that has to be lit - the steel line again, not the black. */
.point.cold .edge::before { background: rgba(206, 226, 250, 0.8); box-shadow: 0 0 9px rgba(150, 194, 240, 0.45); }

/* The lane's centreline, running in towards the middle of the board. */
.point .edge::after {
  content: "";
  position: absolute;
  left: 8px;
  right: 8px;
  top: 50%;
  height: 1px;
  translate: 0 -0.5px;
  background: repeating-linear-gradient(to right,
    rgba(226, 244, 255, 0.5) 0 7px, transparent 7px 14px);
}

/* Sector numbers, printed in the channel between the two columns.
   They are siblings of the lanes rather than children: a lane is clipped to a
   triangle and clips its children with it, so a number at the tip - the one
   part a miniature never covers - was being sliced down to a few pixels. Out
   here it has room, and the two rows read as a scale down the middle. */
#points .num {
  position: absolute;
  width: 26px;
  height: 18px;
  display: flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
  color: rgba(178, 210, 240, 0.7);
  text-shadow: 0 0 8px rgba(10, 30, 60, 0.9);
  pointer-events: none;
}
#points .num.left { justify-content: flex-start; padding-left: 4px; }
#points .num.right { justify-content: flex-end; padding-right: 4px; }

/* A sector inside somebody's home board is numbered in their colour. */
#points .num.home-rebel { color: rgba(255, 152, 142, 0.9); }
#points .num.home-empire { color: rgba(206, 226, 250, 0.9); }

/* ---------------------------------------------------------- the trench line */

#bar-lane {
  position: absolute;
  left: 0;
  top: 362px;
  width: 100%;
  height: 84px;
  background:
    repeating-linear-gradient(-45deg,
      rgba(255, 171, 46, 0.09) 0 12px, transparent 12px 24px),
    linear-gradient(to bottom,
      rgba(2, 8, 18, 0.55), rgba(9, 24, 44, 0.8) 26%,
      rgba(9, 24, 44, 0.8) 74%, rgba(2, 8, 18, 0.55));
  box-shadow:
    inset 0 2px 0 rgba(150, 215, 255, 0.5),
    inset 0 -2px 0 rgba(150, 215, 255, 0.5),
    inset 0 0 34px rgba(0, 0, 0, 0.6);
}
.bar-label {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.42em;
  color: rgba(178, 214, 248, 0.5);
  text-transform: uppercase;
  pointer-events: none;
}
.bar-label { left: 16px; }
.bar-label.alt { left: auto; right: 16px; }

/* --------------------------------------------------------- evacuation pads */

.tray {
  position: absolute;
  top: 794px;
  width: 286px;
  height: 70px;
  clip-path: var(--bezel-sm);
  background:
    repeating-linear-gradient(-45deg,
      rgba(140, 200, 250, 0.055) 0 10px, transparent 10px 20px),
    linear-gradient(to bottom, rgba(3, 10, 22, 0.7), rgba(12, 28, 50, 0.5));
  box-shadow: inset 0 0 0 2px rgba(150, 215, 255, 0.34), inset 0 0 26px rgba(0, 0, 0, 0.6);
}
#tray-rebel { left: 14px; }
#tray-empire { left: 400px; }

.tray::after {
  content: attr(data-label);
  position: absolute;
  bottom: 4px;
  font-family: var(--font-mono);
  font-size: 8px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: rgba(178, 214, 248, 0.45);
}
/* The label sits on the inner side of the pad. Crates stack from the outer
   edge inwards, so a label out there is buried by the fourth evacuation. */
#tray-rebel::after { right: 10px; }
#tray-empire::after { left: 10px; }

/* The approach chevron, pointing the way off the board. */
.tray::before {
  content: "";
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  width: 16px;
  height: 16px;
  border-top: 2px solid;
  border-right: 2px solid;
}
#tray-rebel::before { left: 10px; rotate: -135deg; border-color: rgba(255, 59, 48, 0.65); }
#tray-empire::before { right: 10px; rotate: 45deg; border-color: rgba(206, 226, 250, 0.6); }

/* ---------------------------------------------------------------- the squad */

#checkers { position: absolute; inset: 0; }

.checker {
  position: absolute;
  left: 0;
  top: 0;
  width: 56px;
  height: 58px;
  transition: transform 0.34s cubic-bezier(0.22, 0.85, 0.28, 1);
  will-change: transform;
  z-index: 2;
}

/* Every sculpt stands on an identical 69px plinth flush with the left of its
   canvas, but the canvases differ in width because a raised rifle overhangs to
   the right. Sprites are scaled so their plinths - not their canvases - come
   out the same width, and are anchored on the plinth centre via --nudge.
   render.js sets both. Facing is positional: left column looks right, right
   column looks left, so whoever is opposite is being looked at. */
.checker .mini-wrap {
  position: absolute;
  left: 50%;
  bottom: 4px;
  transform: translateX(calc(-50% + var(--nudge, 0px)));
  transform-origin: 50% 100%;
  pointer-events: none;
}
.checker.face-left .mini-wrap {
  transform: translateX(calc(-50% - var(--nudge, 0px))) scaleX(-1);
}

/* A hard black outline so a figure survives a dark board, and a faction rim so
   the two armies read apart at a glance - red off the rebels, cold steel off
   the imperial armour.

   The rebel rim is pitched brighter than the lane it stands in. The lane wash
   is the same red at a fifth of the alpha over a near-black board, so it sits
   down around a dark brick; the ring is nearly white at its edge. Same colour,
   two ends of it, which is what keeps a figure off its own ground. */
.checker .mini {
  display: block;
  width: auto;
  image-rendering: pixelated;
  transform-origin: 50% 100%;
  filter:
    drop-shadow(1px 0 0 rgba(4, 10, 20, 0.95))
    drop-shadow(-1px 0 0 rgba(4, 10, 20, 0.95))
    drop-shadow(0 3px 3px rgba(2, 6, 16, 0.85));
}
.checker.rebel .mini { filter:
  drop-shadow(1px 0 0 rgba(4, 10, 20, 0.95))
  drop-shadow(-1px 0 0 rgba(4, 10, 20, 0.95))
  drop-shadow(0 0 5px rgba(255, 72, 60, 0.45))
  drop-shadow(0 3px 3px rgba(2, 6, 16, 0.85)); }
.checker.empire .mini { filter:
  drop-shadow(1px 0 0 rgba(4, 10, 20, 0.95))
  drop-shadow(-1px 0 0 rgba(4, 10, 20, 0.95))
  drop-shadow(0 0 5px rgba(206, 226, 250, 0.45))
  drop-shadow(0 3px 3px rgba(2, 6, 16, 0.85)); }

/* The lit pad each miniature is standing on. It is the first child of the
   checker, so it is painted behind the figure: the back half of the ring shows
   behind the boots and the front half below them, which is what a round stand
   looks like from the table. Painted in front - as it was - the disc simply cut
   across the miniature's shins. */
.checker .base {
  position: absolute;
  left: 50%;
  bottom: -2px;
  translate: -50% 0;
  width: 42px;
  height: 12px;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%, rgba(220, 240, 255, 0.2), rgba(6, 16, 30, 0.55) 72%);
}
.checker.rebel .base {
  box-shadow: 0 0 0 1px rgba(255, 156, 146, 1), 0 1px 12px rgba(255, 48, 36, 0.55), 0 3px 6px rgba(2, 8, 18, 0.7);
}
/* An imperial pad is the faction in miniature: a hard white ring with nothing
   inside it. The default pad has a pale centre, which is exactly the thing to
   take out here - the ring is the only part of the Empire that catches light. */
.checker.empire .base {
  background: radial-gradient(ellipse at 50% 50%, rgba(150, 186, 222, 0.14), rgba(1, 3, 7, 0.85) 70%);
  box-shadow: 0 0 0 1px rgba(214, 236, 255, 0.95), 0 1px 10px rgba(1, 3, 8, 0.9), 0 3px 6px rgba(2, 8, 18, 0.75);
}

/* Overflow badge when a lane holds more miniatures than fit. */
.checker .count {
  position: absolute;
  right: -3px;
  top: -3px;
  min-width: 21px;
  height: 18px;
  padding: 0 5px;
  clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  color: #04101f;
  background: #cfe6ff;
}
.checker.rebel .count { background: var(--rebel-hot); }
.checker.empire .count { background: var(--empire-hot); }

/* Interaction states. Inline z-index carries the stacking order, so these have
   to shout to lift a miniature above its neighbours. */
.checker.selectable { cursor: pointer; }

/* The pulse marks the miniatures that have a legal move. It is an aid rather
   than a rule, so `ready` is only added when the player asks for it - see the
   markMovable setting. `selectable` is left on regardless, for the cursor. */
/* A keyframe sets the whole box-shadow, so the resting frame has to restate the
   pad it is pulsing - which means one set of frames per army, or an imperial
   pad flashes rebel red every 1.6 seconds when the aid is on. */
.checker.selectable.ready .base { animation: base-ready 1.6s ease-in-out infinite; }
.checker.empire.selectable.ready .base { animation-name: base-ready-empire; }
@keyframes base-ready {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255, 156, 146, 1), 0 1px 12px rgba(255, 48, 36, 0.55), 0 3px 6px rgba(2, 8, 18, 0.7); }
  50% { box-shadow: 0 0 0 2px rgba(255, 208, 202, 1), 0 0 20px 5px rgba(255, 84, 68, 0.85), 0 3px 6px rgba(2, 8, 18, 0.7); }
}
@keyframes base-ready-empire {
  0%, 100% { box-shadow: 0 0 0 1px rgba(214, 236, 255, 0.95), 0 1px 10px rgba(1, 3, 8, 0.9), 0 3px 6px rgba(2, 8, 18, 0.75); }
  50% { box-shadow: 0 0 0 2px rgba(238, 248, 255, 1), 0 0 20px 5px rgba(170, 212, 255, 0.6), 0 3px 6px rgba(2, 8, 18, 0.75); }
}

.checker.selected { z-index: 300 !important; }
.checker.selected .mini {
  filter: drop-shadow(0 0 8px #ffe6a8) drop-shadow(0 0 3px #ffe6a8)
          drop-shadow(0 3px 3px rgba(2, 6, 16, 0.85));
}
.checker.selected .base {
  animation: none;
  box-shadow: 0 0 0 2px #ffe6a8, 0 0 22px 6px rgba(255, 190, 80, 0.9);
}

/* A ring of light rises off the pad of the miniature in hand. */
.checker.selected::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -6px;
  translate: -50% 0;
  width: 54px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid rgba(255, 214, 130, 0.55);
  animation: pad-ping 1.4s ease-out infinite;
  pointer-events: none;
}
@keyframes pad-ping {
  0% { transform: scale(0.6); opacity: 0.9; }
  100% { transform: scale(1.25); opacity: 0; }
}

.checker.landing .mini { animation: land-thump 0.34s ease-out; }
@keyframes land-thump {
  0% { transform: translateY(-14px) scale(1.08); }
  70% { transform: translateY(2px) scale(0.97); }
  100% { transform: none; }
}

/* Evacuated: the miniature is crated and loaded for dust-off. */
.checker.stowed { width: 16px; height: 52px; }
.checker.stowed .mini-wrap { display: none; }
.checker.stowed .count { display: none; }
.checker.stowed::after { display: none; }
.checker.stowed .base {
  animation: none;              /* a crate in the tray has nothing to pulse for */
  width: 14px;
  height: 48px;
  bottom: 2px;
  border-radius: 0;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%);
  background: linear-gradient(to bottom, rgba(190, 220, 250, 0.35), rgba(10, 24, 44, 0.9));
}
.checker.rebel.stowed .base { box-shadow: inset 0 0 0 1px rgba(255, 156, 146, 1), 0 0 10px rgba(255, 48, 36, 0.4); }
.checker.empire.stowed .base {
  background: linear-gradient(to bottom, rgba(170, 202, 236, 0.28), rgba(2, 5, 11, 0.95));
  box-shadow: inset 0 0 0 1px rgba(214, 236, 255, 0.95), 0 0 10px rgba(1, 3, 8, 0.8);
}

/* --------------------------------------------------------------- targeting */

#highlights { position: absolute; inset: 0; pointer-events: none; }

.hl {
  position: absolute;
  width: 286px;
  height: 58px;
  pointer-events: auto;
  cursor: pointer;
}
.hl.left { clip-path: polygon(0 0, 100% 50%, 0 100%); }
.hl.right { clip-path: polygon(100% 0, 0 50%, 100% 100%); }

.hl .glow { position: absolute; inset: 0; animation: hl-pulse 1.25s ease-in-out infinite; }
.hl.left .glow { background: linear-gradient(to right, rgba(111, 255, 180, 0.5), rgba(111, 255, 180, 0.04)); }
.hl.right .glow { background: linear-gradient(to left, rgba(111, 255, 180, 0.5), rgba(111, 255, 180, 0.04)); }
.hl.hit.left .glow { background: linear-gradient(to right, rgba(255, 72, 64, 0.62), rgba(255, 72, 64, 0.04)); }
.hl.hit.right .glow { background: linear-gradient(to left, rgba(255, 72, 64, 0.62), rgba(255, 72, 64, 0.04)); }

@keyframes hl-pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

/* A reticle over the exact box a miniature would land in: four corner brackets
   and a dot, which is what a targeting computer draws and what a ring of
   coloured light does not.
   It lives in its own layer above the miniatures rather than inside the lit
   lane, because the lane it points at is very often one this army is already
   standing in - down there the reticle was drawn behind the front rank, which
   is precisely the case where you want to see it. */
#reticles {
  position: absolute;
  inset: 0;
  z-index: 310;
  pointer-events: none;
}

.reticle {
  --rc: var(--lock);
  position: absolute;
  width: 26px;
  height: 26px;
  background:
    linear-gradient(var(--rc), var(--rc)) 0 0 / 9px 2px no-repeat,
    linear-gradient(var(--rc), var(--rc)) 0 0 / 2px 9px no-repeat,
    linear-gradient(var(--rc), var(--rc)) 100% 0 / 9px 2px no-repeat,
    linear-gradient(var(--rc), var(--rc)) 100% 0 / 2px 9px no-repeat,
    linear-gradient(var(--rc), var(--rc)) 0 100% / 9px 2px no-repeat,
    linear-gradient(var(--rc), var(--rc)) 0 100% / 2px 9px no-repeat,
    linear-gradient(var(--rc), var(--rc)) 100% 100% / 9px 2px no-repeat,
    linear-gradient(var(--rc), var(--rc)) 100% 100% / 2px 9px no-repeat,
    radial-gradient(circle at 50% 50%, var(--rc) 0 2px, transparent 2.5px);
  filter: drop-shadow(0 0 7px var(--rc));
  animation: reticle-lock 1.25s ease-in-out infinite;
}
.reticle.hit { --rc: #ff5a4e; }

@keyframes reticle-lock {
  0%, 100% { transform: scale(1); opacity: 0.85; }
  50% { transform: scale(1.16); opacity: 1; }
}

/* The evacuation pad lights up the same way when bearing off is legal. */
.hl-tray {
  position: absolute;
  top: 794px;
  width: 286px;
  height: 70px;
  pointer-events: auto;
  cursor: pointer;
  clip-path: var(--bezel-sm);
  background: rgba(111, 255, 180, 0.14);
  box-shadow: inset 0 0 0 2px rgba(111, 255, 180, 0.9), inset 0 0 26px rgba(111, 255, 180, 0.3);
  animation: hl-pulse 1.25s ease-in-out infinite;
}

/* A miniature waiting on the trench line gets its own call-out. */
.hl-bar {
  position: absolute;
  top: 362px;
  height: 84px;
  pointer-events: none;
  background:
    repeating-linear-gradient(-45deg,
      rgba(255, 200, 90, 0.16) 0 10px, transparent 10px 20px),
    rgba(255, 200, 90, 0.08);
  box-shadow: inset 0 0 0 2px rgba(255, 214, 130, 0.9), inset 0 0 24px rgba(255, 190, 70, 0.4);
  animation: hl-pulse 1.25s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  #grid::after { animation: none; opacity: 0; }
  .checker.selected::after { animation: none; opacity: 0; }
}
