/* © 2026 MEK.txt. All rights reserved. Part of the MEK design system; not licensed for reuse. */
/* MEK design system · part: screen effects
   The game kit's screen effects, on a game's screen (any element) or the whole page: a shake, a flash, a fade and an
   iris (a closing circle) for moving between scenes, and a low-health vignette; and the tube, a CRT's glass over a
   DOM page. Drawn on a canvas of 2px pixels in an 8×8 Bayer dither, at 24 frames a second. Opt-in: link it after
   mek.css, with js/fx.js:
     await mekFx.fade(screen, "out");  …change the scene…  await mekFx.fade(screen, "in");
   In the mek.parts layer, so a project's CSS wins. */

@layer mek.parts {

/* ---------- Dials ---------- */
/* on every themed area too, so a box in another theme works these out from its own colours */
:root, [data-theme] {
  --fx-cell: 2px;                      /* one effect pixel: whole CSS pixels, so it stays crisp */
  --fx-fps: 24;                        /* frames a second: film rate, as the shimmer and the sound */
  --fx-fade: var(--bg);                /* what a fade and an iris close to: the ground */
  --fx-flash: var(--text-strong);      /* a flash: the strongest ink (light on Dark, dark on Light) */
  --fx-hurt: var(--bad);               /* the vignette, and a flash given { color: "hurt" } */
  --fx-tube: var(--bg);                /* the tube's bezel, its dark edges and its grain: the ground */
}

/* ---------- Layer ----------
   js/fx.js puts a .fx-layer over its target: absolute over an element (made position: relative if it was static),
   fixed over the window for the page (above toasts: --z-fx). It never takes clicks. Its canvas is a pixel per
   --fx-cell, scaled up crisp. */
.fx-host { position: relative; }
.fx-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 1; }
.fx-layer.page { position: fixed; z-index: var(--z-fx); }
.fx-layer > canvas { position: absolute; left: 0; top: 0; image-rendering: pixelated; }

/* ---------- The tube ----------
   mekFx.tube(el, on): the CRT look for a DOM page, the canvas version being the code bank's fx/crt. One .fx-layer.fx-tube
   over the target, above its other effects, in the theme's own colours (no repaint on a theme change):
   - ::before, the scanlines: --scanlines, as core .scanlines draws them (a faithful theme: a solid ground row every 4px),
     held still;
   - .fx-tube-edge, the glass's edge: a stepped-pixel bezel in each corner and the vignette's 8×8 Bayer dither, held
     still, thickening to the corners. js/fx.js paints it once a size as a mask (--fx-tube-edge) over --fx-tube;
   - ::after, the grain: a few pixels of --fx-tube in 4 frames of noise (--fx-tube-grain), stepped through at --fx-fps
     by moving the mask, so no script runs a frame. Still under reduced motion; paused off screen (mek.loops) and while
     the tab is hidden (the browser stops it).
   Over the page it's a popover in the top layer, shown again when a modal dialog or another popover opens, so it covers
   the window over them too (without popovers: fixed at --z-fx). It never takes clicks, never changes layout, and
   doesn't print (print.css hides .fx-layer). */
.fx-tube { z-index: 2; }
.fx-tube.page { z-index: calc(var(--z-fx) + 1); }
/* over the page it's a popover in the top layer (js/fx.js): none of a popover's own box */
.fx-tube[popover] { inset: 0; width: auto; height: auto; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: none; color: inherit; overflow: hidden; }
.fx-tube::before, .fx-tube::after, .fx-tube-edge { content: ""; position: absolute; inset: 0; pointer-events: none; }
.fx-tube::before { background: var(--scanlines); }
.fx-tube-edge, .fx-tube::after { background: var(--fx-tube); image-rendering: pixelated; }
.fx-tube-edge { -webkit-mask: var(--fx-tube-edge, linear-gradient(transparent, transparent)) 0 0 / var(--fx-tube-size, 100% 100%) no-repeat; mask: var(--fx-tube-edge, linear-gradient(transparent, transparent)) 0 0 / var(--fx-tube-size, 100% 100%) no-repeat; }
/* the grain: 4 frames of 64×64 effect pixels, stacked; a step a frame shows the next */
.fx-tube::after {
  -webkit-mask: var(--fx-tube-grain, linear-gradient(transparent, transparent)) 0 0 / calc(var(--fx-cell) * 64) calc(var(--fx-cell) * 256) repeat;
  mask: var(--fx-tube-grain, linear-gradient(transparent, transparent)) 0 0 / calc(var(--fx-cell) * 64) calc(var(--fx-cell) * 256) repeat;
  animation: mek-fx-grain calc(4s / var(--fx-fps)) steps(4) infinite; }
@keyframes mek-fx-grain { to { -webkit-mask-position: 0 calc(var(--fx-cell) * -256); mask-position: 0 calc(var(--fx-cell) * -256); } }
@media (prefers-reduced-motion: reduce) { .fx-tube::after { animation: none; } }

}
