/* proximity.css — the four edge markers, and nothing else.
 *
 * Its own file on the fourth attempt to house it. It lived in mobile.css, which put
 * that file exactly on its ceiling, then in hud.css, which put THAT file exactly on
 * its ceiling twice. Both were the right subject and neither had the room, and
 * shaving a comment each time to fit is how a file ends up pinned at its budget
 * with the next person blocked and no diff explaining why.
 *
 * It costs one request. Measured before taking it: first load stayed inside its
 * budget, because the block is small and CSS comments never reach the wire
 * (precompress strips them). js/proximity.js carries the reach maths.
 */

/* ---- Proximity: what is just off your screen ---------------------------------
   Four edges; js/proximity.js carries the reach maths. Opacity is a function of
   DISTANCE, so it never oscillates: nothing flashes at any rate, and a mark is far
   under the third-of-viewport line that makes motion a vestibular problem. */
/* z-index 4: BELOW the HUD (5) and the touch controls (8). These are arena
   furniture, not chrome, so the score, clock and sticks draw over them. */
/* The CONTAINER is the play area, not the window, and that is what makes the four
   edges agree. #topBar is a flat 54px in every orientation (border-box, so notch
   padding eats into it rather than adding). Each edge then sits 4px off THIS box
   rather than carrying its own hand-picked inset, which is what had the bottom bar
   hovering 18px up while the sides ran to the glass. */
#proximity {
  position: fixed; left: 0; right: 0; top: 54px; bottom: 0;
  z-index: 4; pointer-events: none; opacity: 0;
}
#proximity.on { opacity: 1; }
.prox-edge { position: absolute; }
.prox-left, .prox-right { top: 0; bottom: 0; width: 3px; }
.prox-left { left: 0; }
.prox-right { right: 0; }
/* The HUD sits above them and covers the few marks it lands on, as it already does
   the left bar. */
.prox-top, .prox-bottom { left: 0; right: 0; height: 3px; }
.prox-top { top: 4px; }
.prox-bottom { bottom: 4px; }
/* --m is the threat's OWN colour, set per mark by js/proximity.js: a spike gets what
   the server draws it in, a player white until they prestige then their tier. The
   pale ring is not decoration: the dark spike is nearly black, and without it a black
   mark on a black edge is no mark at all. Two HELD shadows, never pulsed. */
.prox-mark {
  position: absolute; top: 0; left: 0; width: 3px; height: 15px; margin-top: -7.5px;
  border-radius: 2px; opacity: 0;
  background: var(--m, #ff8f6a);
  /* Tight shadow for a crisp edge, soft one for presence. The soft one was 18px at 5
     spread and every mark read as a smudge, which is worse than no glow: a blur has
     no position, and position is the entire message. */
  box-shadow: 0 0 3px 0 var(--m, #ff8f6a), 0 0 8px 1px var(--m, #ff8f6a),
              0 0 0 1px rgba(255,255,255,0.5);
  /* EXACTLY the update interval, and that is the whole trick. At 110ms against a
     66ms tick every transition was cut off at 60% and restarted from a new speed,
     which is a velocity discontinuity 15 times a second: the "jumpy" part. Matching
     the two means each one lands precisely as the next begins, so the mark moves at
     one constant speed and never re-aims mid-slide. */
  transition: opacity var(--t-base) var(--e-standard), transform 50ms linear;
  will-change: transform, opacity;
}
/* Shape as well as hue, so the difference survives any colour vision: a spike is a
   short stub, a player a long bar. */
.prox-mark.is-spike {
  height: 7px; margin-top: -3.5px; width: 5px; left: -1px; border-radius: 1px;
}
/* Lying down, and LONGER than the vertical ones on purpose: a short stub on a
   horizontal line reads as a speck of debris, which is exactly how the first cut
   looked on a real phone. Length is what makes it read as pointing at something. */
.prox-top .prox-mark, .prox-bottom .prox-mark {
  width: 22px; height: 3px; margin: 0 0 0 -11px; left: 0; top: 0; border-radius: 2px;
}
.prox-top .prox-mark.is-spike, .prox-bottom .prox-mark.is-spike {
  width: 11px; height: 3px; margin: 0 0 0 -5.5px; top: 0;
}
/* The fade is the only motion, and it is the first thing to go. The mark still
   arrives and still says where: intensity is lost, information is not. */
@media (prefers-reduced-motion: reduce) { .prox-mark { transition: none; } }

/* Something you have outgrown is FOOD, not a threat. It still shows, because a
   desktop player can see it and that is the gap this closes, but it is quieter and
   smaller so a crowded edge still reads at a glance as an edge with nothing on it
   to fear. The opacity half of this is set per mark in js/proximity.js, next to the
   distance it is already computing. */
.prox-mark.is-food { box-shadow: 0 0 3px 0 var(--m, #ff8f6a), 0 0 0 1px rgba(255,255,255,0.28); }
.prox-mark.is-spike.is-food { height: 5px; margin-top: -2.5px; }
.prox-top .prox-mark.is-spike.is-food,
.prox-bottom .prox-mark.is-spike.is-food { width: 8px; height: 3px; margin: 0 0 0 -4px; }
