/* ---- 雷达脉冲 game pass (ui/ping-game.css; loaded by its own link after number-effects.css) ----
   The ping reads as a skill: charge → release/push → aftermath, on the row's own jet cycle (--jet-p,
   --jet-delay, pinned by led.mjs on nfx-ping-ring), so every layer below is on the clock the number field
   pushes the background with. Nothing here changes the front's geometry: the box, R, k0, the radius curve
   (nfx-ping-ring's transform) and its .55 window stay exactly as number-effects.css draws them.
   - charge (.nfx-ping::after, desktop): four reticle brackets on the start ellipse (k0·R, the number's
     half width) close in from 2× over φ .66 → 1 on an accelerating ease and meet the front at φ = 0;
   - release: the brackets kick out to 1.3× and spring back (1.1×) as the front leaves (phones keep this
     recoil only); t6+ the existing burst (::before) is a hollow ring, never a filled flash on the digits;
   - push: the front's i carries no paint of its own; its ::after is the leading edge (a 1 px hot core on
     the outside, the tier colour just inside, lobe-weighted and unbroken) and its ::before the energy
     shell trailing inside it (faint from 70 %, the field's wake from 82 % of the radius, in range dashes).
     Its alpha falls linearly over the window, (1 − u) like the field's push, instead of with the radius;
   - aftermath: the t4+ range ring (i + i, .08 P behind, desktop) is unchanged and trails as the echo.
   The probe's lens gets a refraction fringe inside its arc; each echo carries a hit marker (b.nfx-hit,
   written by number-probe.mjs from ping-game.mjs pingHit). Intensity follows the row's real --led-energy.
   Transform and opacity only; no text is covered (everything is under the number, hollow at its centre);
   parked, held, paused, motion off, reduced motion and phones follow number-effects.css's own gates. */

#ladder-rows .nfx-ping { --pg-core: #e6fff0; --pg-g: calc(.5 + .5 * var(--led-energy, 0)); }
#ladder-rows .nfx-ping:is(.t3, .t4) { --pg-core: #e0fcff; }
#ladder-rows .nfx-ping:is(.t5, .t6, .t7) { --pg-core: #fff4cf; }

/* The front: the i is a carrier (its transform is the physics radius); its pseudo-elements paint. */
#ladder-rows .nfx-ping > i:first-child { border: 0; box-shadow: none; background: none; -webkit-mask: none; mask: none; }
#ladder-rows .nfx-ping > i:first-child::before,
#ladder-rows .nfx-ping > i:first-child::after { content: ""; position: absolute; inset: 0; border-radius: 50%; pointer-events: none; }
#ladder-rows .nfx-ping > i:first-child::before {
  background: radial-gradient(closest-side, transparent 70%, color-mix(in srgb, var(--nfx-wake) 35%, transparent) 82%, var(--nfx-wake) 93%, var(--nfx-glow) 100%);
  -webkit-mask: var(--nfx-lobes), var(--nfx-dash); -webkit-mask-composite: source-in;
  mask: var(--nfx-lobes), var(--nfx-dash); mask-composite: intersect; }
#ladder-rows .nfx-ping > i:first-child::after {
  border: 1px solid var(--pg-core); box-shadow: inset 0 0 0 1.5px var(--nfx-ring), inset 0 0 7px 1px var(--nfx-glow);
  -webkit-mask: var(--nfx-lobes); mask: var(--nfx-lobes); }

/* Charge and recoil: the start ellipse (the front at u = 0), hollow reticle brackets. */
#ladder-rows .nfx-ping::after { content: ""; position: absolute; border-radius: 50%; opacity: 0; pointer-events: none;
  left: calc(50% - var(--nfx-r) * var(--nfx-k0)); top: calc(50% - var(--nfx-r) * var(--nfx-k0) * .45);
  width: calc(2 * var(--nfx-r) * var(--nfx-k0)); height: calc(2 * var(--nfx-r) * var(--nfx-k0) * .45);
  border: 1.5px solid var(--nfx-echo); box-shadow: inset 0 0 5px var(--nfx-glow); transform: scale(2);
  -webkit-mask: repeating-conic-gradient(from -22deg, #000 0 44deg, transparent 44deg 90deg);
  mask: repeating-conic-gradient(from -22deg, #000 0 44deg, transparent 44deg 90deg); }

/* t6+ burst: hollow, so the digits above it never sit on a bright fill. */
#ladder-rows .nfx-ping::before { background: radial-gradient(closest-side, transparent 58%, color-mix(in srgb, var(--nfx-echo) 60%, transparent) 82%, transparent); }

/* Running: exactly number-effects.css's gate. The front keeps nfx-ping-ring first (its transform, and the
   animationstart led.mjs pins --jet-t with); ping-game-front, later in the list, sets its alpha. */
.ladder-wrap[data-num-fx="ping"]:not([data-fx-off]):not([data-rain-hold]):not([data-led-paused]) #ladder-rows .c-value[data-led]:not([data-led-idle]) .nfx-ping > i:first-child {
  animation: nfx-ping-ring var(--jet-p, 2.4s) linear infinite var(--jet-delay), ping-game-front var(--jet-p, 2.4s) linear infinite var(--jet-delay); }
.ladder-wrap[data-num-fx="ping"]:not([data-fx-off]):not([data-rain-hold]):not([data-led-paused]) #ladder-rows .c-value[data-led]:not([data-led-idle]) .nfx-ping::after {
  animation: ping-game-charge var(--jet-p, 2.4s) linear infinite var(--jet-delay); }

/* Probe: the lens is the front bent round the target, with a refraction fringe inside its arc; each echo
   carries a hit marker (four ticks, its tier's echo colour: gold from t5). */
.nfx-probe > i.nfx-lens { background: radial-gradient(closest-side, transparent 74%, var(--nfx-glow) 100%); }
.nfx-probe > i.nfx-lens::after { content: ""; position: absolute; inset: 16%; border-radius: 50%; opacity: .45;
  border: 1px solid var(--nfx-ring); }
.nfx-probe > i.nfx-echo > b { position: absolute; left: 50%; top: 50%; width: 26px; height: 26px; margin: -13px 0 0 -13px; opacity: 0;
  transform-origin: 50% 50%; pointer-events: none; }
.nfx-probe > i.nfx-echo > b::before { content: ""; position: absolute; inset: 0; transform: rotate(45deg);
  --pg-tick: var(--nfx-echo, var(--nfx-ring));
  background: linear-gradient(var(--pg-tick), var(--pg-tick)) 50% 0 / 2px 32% no-repeat,
    linear-gradient(var(--pg-tick), var(--pg-tick)) 50% 100% / 2px 32% no-repeat,
    linear-gradient(var(--pg-tick), var(--pg-tick)) 0 50% / 32% 2px no-repeat,
    linear-gradient(var(--pg-tick), var(--pg-tick)) 100% 50% / 32% 2px no-repeat; }

/* Phones (also turned to landscape): one clear front and the recoil only (no charge brackets). */
@media (max-width: 720px), (pointer: coarse) and (max-height: 720px) {
  .ladder-wrap[data-num-fx="ping"]:not([data-fx-off]):not([data-rain-hold]):not([data-led-paused]) #ladder-rows .c-value[data-led]:not([data-led-idle]) .nfx-ping::after {
    animation-name: ping-game-recoil; }
  #ladder-rows .nfx-ping > i:first-child::after { box-shadow: inset 0 0 0 1.5px var(--nfx-ring), inset 0 0 4px var(--nfx-glow); }
  .nfx-probe > i.nfx-echo > b { width: 18px; height: 18px; margin: -9px 0 0 -9px; }
}

@keyframes ping-game-front { 0% { opacity: calc(.72 + .23 * var(--led-energy, 0)); } 55%, 100% { opacity: 0; } }
@keyframes ping-game-charge {
  0% { opacity: calc(.8 * var(--pg-g)); transform: scale(1); animation-timing-function: cubic-bezier(.15, .75, .35, 1); }
  5% { opacity: calc(.5 * var(--pg-g)); transform: scale(1.3); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
  11% { opacity: calc(.2 * var(--pg-g)); transform: scale(1.1); animation-timing-function: ease-out; }
  17% { opacity: 0; transform: scale(1.18); }
  17.01%, 66% { opacity: 0; transform: scale(2); animation-timing-function: cubic-bezier(.6, 0, .9, .4); }
  100% { opacity: calc(.8 * var(--pg-g)); transform: scale(1); } }
@keyframes ping-game-recoil {
  0% { opacity: calc(.7 * var(--pg-g)); transform: scale(1); animation-timing-function: cubic-bezier(.15, .75, .35, 1); }
  5% { opacity: calc(.45 * var(--pg-g)); transform: scale(1.3); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
  11% { opacity: calc(.18 * var(--pg-g)); transform: scale(1.1); animation-timing-function: ease-out; }
  17%, 100% { opacity: 0; transform: scale(1.18); } }
