/* OSIRIS scanner stream (after the reference 07 "scanner card stream"), paleta E (22 Oct 2026): member cards drift left under a
   light ray; the part of a card that has passed the 8px band turns into code. Sizes are the reference's at --k = 1 (card 400 x 250,
   gap 60, ray 2 x 280, code 11/13px); JS sets --k lower on narrow screens. Colours: white #f2f4f8, #7dd3fc, #38bdf8, #1d4ed8 only. */
.scan{--k:1;--cw:400px;--ch:250px;position:relative;width:100%;height:var(--scan-h,calc(340px * var(--k)));overflow:hidden;
  background:var(--bg,#06080f);-webkit-user-select:none;user-select:none;touch-action:pan-y;cursor:grab}
.scan.is-grabbing{cursor:grabbing}
.scan canvas{position:absolute;left:0;top:50%;width:100%;transform:translateY(-50%);pointer-events:none}
.scan__bg{z-index:0;height:calc(250px * var(--k))}
.scan__fx{z-index:10;height:calc(300px * var(--k));width:auto}
.scan__rail{position:absolute;left:0;right:0;top:50%;height:var(--ch);margin-top:calc(var(--ch) / -2);z-index:1}

/* one card: the member card (clipped from the left at the band) over its code (clipped from the right).
   Both cuts move with transforms only: a clip box slides, its content slides back the same amount. */
.scan__card{position:absolute;left:0;top:0;width:var(--cw);height:var(--ch);will-change:transform}
.scan__card[hidden]{display:none}
.scan__cut{position:absolute;top:0;left:0;height:100%;overflow-x:clip;will-change:transform}
.scan__cut--card{z-index:2;width:calc(var(--cw) + 90px)}
.scan__cut--code{z-index:1;width:var(--cw)}
.scan__in{position:absolute;top:0;left:0;width:var(--cw);height:100%;will-change:transform}
.scan__in .mcard{width:var(--cw)}
.scan__lift{position:absolute;inset:0;border-radius:calc(var(--cw) * .0375);box-shadow:0 15px 40px rgba(0,0,0,.45);pointer-events:none}
/* the reference brightens a card under the mouse (brightness/contrast 1.1 -> 1.25, 300 ms): a light film here */
.scan__shine{position:absolute;inset:0;z-index:3;border-radius:calc(var(--cw) * .0375);background:rgba(242,244,248,.06);opacity:0;transition:opacity .3s ease-in-out;pointer-events:none}
.scan__card:hover .scan__shine{opacity:1}
.scan__code{position:absolute;inset:0;margin:0;padding:0;overflow:hidden;border-radius:calc(var(--cw) * .0375);white-space:pre;text-align:left;
  font-family:var(--font-mono);font-size:calc(11px * var(--k));line-height:calc(13px * var(--k));font-weight:400;letter-spacing:0;color:rgba(242,244,248,.55);
  -webkit-mask-image:linear-gradient(to right,#000 0%,rgba(0,0,0,.8) 30%,rgba(0,0,0,.6) 50%,rgba(0,0,0,.4) 80%,rgba(0,0,0,.2) 100%);
          mask-image:linear-gradient(to right,#000 0%,rgba(0,0,0,.8) 30%,rgba(0,0,0,.6) 50%,rgba(0,0,0,.4) 80%,rgba(0,0,0,.2) 100%);
  animation:scanGlitch .1s infinite linear alternate-reverse}
.scan__code b{font-weight:400;color:#7dd3fc}
@keyframes scanGlitch{0%,16%,50%,100%{opacity:1}15%,99%{opacity:.9}49%{opacity:.8}}

/* the ray: 2 x 280, an ice core (#7dd3fc) in a #38bdf8 / #1d4ed8 halo instead of the reference's violet, pulsing 1.5 s */
.scan__ray{position:absolute;left:50%;top:50%;z-index:20;width:2px;height:calc(280px * var(--k));margin:calc(140px * var(--k) * -1) 0 0 -1px;border-radius:9999px;pointer-events:none;
  background:linear-gradient(to bottom,rgba(125,211,252,0),#7dd3fc 50%,rgba(125,211,252,0));
  box-shadow:0 0 10px #7dd3fc,0 0 20px #38bdf8,0 0 30px #38bdf8,0 0 50px #1d4ed8;animation:scanPulse 1.5s infinite alternate ease-in-out}
@keyframes scanPulse{0%{opacity:.75;transform:scaleY(1)}100%{opacity:1;transform:scaleY(1.03)}}
/* off screen (class set by scanner.js from its IntersectionObserver): the ray and the code stop pulsing */
.scan.is-off .scan__code,.scan.is-off .scan__ray{animation-play-state:paused}
