/* The Rift: the divider and the tug-of-war meter (designer round 7, 2026-09-18; straight, per the owner the same day).
   A straight seam of light down the centre, replacing the lightning bolt. Presence comes from four stacked strokes
   (dark feather, wide bloom, tight halo, pale core), never from width.
   The art halves are clipped to the same centre line, so the core stroke covers the join. Rule that must survive every
   future edit: .img.b overlaps .img.a by .06 lateral units (it paints on top) and the core is at least 2.5x that in
   device pixels, so no background can leak through at any pixel ratio.
   The .bolt / #bolt names stay: --shift, .stage.relayout, .bolt.hit, phone.css and arena.js scanPulse() all key off them. */
:root{
  --clipA: polygon(0 0, calc(50.03% + var(--shift)) 0, calc(50.03% + var(--shift)) 100%, 0 100%);
  --clipB: polygon(calc(49.97% + var(--shift)) 0, 100% 0, 100% 100%, calc(49.97% + var(--shift)) 100%);
}
.bolt{position:absolute;inset:0;z-index:1;pointer-events:none}
.bolt svg{width:100%;height:100%;overflow:visible;transform:translateX(var(--shift));transition:transform 1.2s cubic-bezier(.2,.8,.2,1)}
.bolt path{fill:none;stroke-linecap:round;stroke-linejoin:round}
/* Only the two unfiltered layers use non-scaling-stroke: vector-effect plus filter on one element is under-specified
   across engines. The filtered layers take plain user units and let the non-uniform viewBox scale do the work, which is
   what makes the blur anisotropic (wide across the seam, squashed along it, so the ends never smear into header or dock). */
.rift-shade{stroke:rgba(3,5,11,.24);stroke-width:.30;filter:url(#riftShade)}   /* a dark stripe with a faint tint in it reads as a seam: the shade must never out-weigh the core */
.rift-aura{stroke:url(#meter);stroke-width:.22;opacity:.16;filter:url(#riftAura);animation:riftBreath 11s ease-in-out infinite}
.rift-glow{stroke:url(#meter);stroke-width:.18;opacity:.50;filter:url(#riftGlow)}
/* Half the line always carries the loser's colour over the loser's own field (cyan on blue, amber on orange), which is
   why the core is mixed toward white and why its width and alpha are the two numbers that cannot be cut further. */
.rift-core{stroke:url(#meterLite);stroke-width:2.5;vector-effect:non-scaling-stroke;opacity:.92}
.rift-sweep{stroke:#fff;stroke-width:2.5;vector-effect:non-scaling-stroke;stroke-dasharray:110 890;stroke-dashoffset:1000;opacity:0}
/* A breath, not a stutter: on a hairline the old 4%/7% opacity snaps read as a dropped frame. Every keyframe is eased. */
@keyframes riftBreath{0%,100%{opacity:.13}34%{opacity:.19}61%{opacity:.16}63.4%{opacity:.07}66%{opacity:.16}82%{opacity:.12}}
/* Scan hit: brightness(3) on a 3px line would just blow out to white, so the scan sends a bright segment travelling the
   seam instead (pathLength=1000 normalises the dash arithmetic against the stretched viewBox). The breath keeps running
   underneath so it resumes when the sweep ends; .hit stays on the element until the next scan. */
.bolt.hit .rift-sweep{animation:riftSweep .9s cubic-bezier(.3,0,.2,1)}
.bolt.hit .rift-aura{animation:riftBreath 11s ease-in-out infinite, riftHit .9s ease-out}
@keyframes riftSweep{0%{stroke-dashoffset:1000;opacity:0}12%{opacity:.82}80%{opacity:.82}100%{stroke-dashoffset:-110;opacity:0}}
@keyframes riftHit{0%{opacity:.34}100%{opacity:.16}}
/* The node: the meter's readout, sitting exactly on the colour crossover.
   Owner 2026-09-18: not a ball and no dark rim — a welder's arc. The seam runs white-hot for a few pixels at the level
   and sprays sparks that fall fast and burn out at the tip. Nothing here is wider than the core stroke, so the level
   reads as the line doing something rather than as an object parked on it. HTML, not SVG: inside the stretched viewBox
   a round glow would come out an ellipse and a 1.5px spark would come out 20px wide.
   Stacked layouts rotate the whole .bolt 90deg, so the node counter-rotates there (phone.css) and the sparks keep falling
   down the screen instead of shooting sideways along the horizon.
   .riftshift carries the slide so the node tracks the seam frame for frame; no transition on the node itself, because
   updateMeter's 1.2s tween already drives --ny and a CSS transition would fight it. */
.bolt .riftshift{position:absolute;inset:0;transform:translateX(var(--shift));transition:transform 1.2s cubic-bezier(.2,.8,.2,1)}
.riftnode{position:absolute;left:50%;top:var(--ny,36%);width:3px;height:3px;margin:-1.5px 0 0 -1.5px;pointer-events:none;
  filter:drop-shadow(0 0 4px color-mix(in srgb,var(--nodec,#fff) 75%,transparent)) drop-shadow(0 0 13px color-mix(in srgb,var(--nodec,#fff) 45%,transparent))}
/* the hot length of seam: the same width as the core, fading into the line at both ends so it has no cap to notice */
.riftnode::before{content:"";position:absolute;left:50%;top:50%;width:2.5px;height:19px;margin:-9.5px 0 0 -1.25px;border-radius:1.25px;
  background:linear-gradient(180deg,transparent,#fff 32%,#fff 68%,transparent);animation:sparkHot 2.6s ease-in-out infinite}
/* the spray: ten sparks on tight staggers, each alive for well under a second, so there is always a handful falling.
   --k scales the fall for smaller screens without flattening the per-spark variation. */
.riftnode i{position:absolute;left:50%;top:50%;width:2px;height:5px;margin:-2.5px 0 0 -1px;border-radius:1px;background:#fff;opacity:0;
  animation:sparkFall var(--d) cubic-bezier(.3,0,.7,.5) var(--t) infinite}
/* every third one is a finer ember, so the spray is not a uniform shower */
.riftnode i:nth-child(3n){width:1.4px;height:3.5px;margin:-1.75px 0 0 -.7px}
.riftnode i:nth-child(1){--d:1.02s;--t:0.00s;--dx:5px;--dy:52px}
.riftnode i:nth-child(2){--d:1.30s;--t:0.10s;--dx:-11px;--dy:72px}
.riftnode i:nth-child(3){--d:0.88s;--t:0.20s;--dx:3px;--dy:42px;background:var(--nodec,#fff)}
.riftnode i:nth-child(4){--d:1.52s;--t:0.29s;--dx:-6px;--dy:84px}
.riftnode i:nth-child(5){--d:1.16s;--t:0.39s;--dx:14px;--dy:60px}
.riftnode i:nth-child(6){--d:1.62s;--t:0.49s;--dx:-4px;--dy:78px;background:var(--nodec,#fff)}
.riftnode i:nth-child(7){--d:0.95s;--t:0.58s;--dx:9px;--dy:47px}
.riftnode i:nth-child(8){--d:1.39s;--t:0.68s;--dx:-16px;--dy:66px}
.riftnode i:nth-child(9){--d:1.10s;--t:0.78s;--dx:17px;--dy:55px}
.riftnode i:nth-child(10){--d:1.25s;--t:0.88s;--dx:-9px;--dy:74px;background:var(--nodec,#fff)}
.riftnode i:nth-child(11){--d:0.86s;--t:0.97s;--dx:6px;--dy:38px}
.riftnode i:nth-child(12){--d:1.46s;--t:1.07s;--dx:-13px;--dy:80px}
.riftnode i:nth-child(13){--d:1.07s;--t:1.17s;--dx:11px;--dy:50px;background:var(--nodec,#fff)}
.riftnode i:nth-child(14){--d:1.66s;--t:1.26s;--dx:-7px;--dy:88px}
.riftnode i:nth-child(15){--d:0.98s;--t:1.36s;--dx:18px;--dy:45px}
.riftnode i:nth-child(16){--d:1.35s;--t:1.46s;--dx:-18px;--dy:69px}
.riftnode i:nth-child(17){--d:1.20s;--t:1.55s;--dx:8px;--dy:62px;background:var(--nodec,#fff)}
.riftnode i:nth-child(18){--d:0.91s;--t:1.65s;--dx:-10px;--dy:43px}
/* out fast at the tip: full brightness for most of the fall, then gone inside the last fifth of it */
@keyframes sparkFall{0%{transform:translate(0,0) scaleY(.5);opacity:0}6%{opacity:1;transform:translate(0,2px) scaleY(1)}64%{opacity:.95}84%{opacity:.28}100%{transform:translate(var(--dx),calc(var(--dy) * var(--k,1))) scaleY(.35);opacity:0}}
@keyframes sparkHot{0%,100%{opacity:.85}30%{opacity:1}48%{opacity:.72}72%{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .rift-aura{animation:none!important;opacity:.15}
  .bolt.hit .rift-sweep,.bolt.hit .rift-aura{animation:none!important}
  .rift-sweep{opacity:0}
  .riftnode i{display:none}
  .riftnode::before{animation:none!important;opacity:.95}
}
