/* ==========================================================================
   SCREEN — the effect laid over everything
   --------------------------------------------------------------------------
   Settings live in the Screen menu and are remembered between reboots:

     #crt-0 / #crt-1 / #crt-2   none / scanlines / grid
     #crv-0 / #crv-sq / #crv-ci none / square corners / circular corners
                                (circular is the default, at 26)
     --crt-alpha                how strongly the lines show   (slider)
                                the slider's full travel reaches 0.7, not 1.0,
                                so 15% on the readout is 0.105 here
     --crv-depth                how dark each vignette ring is
     --crv-dist                 how far the rings reach inward

   TWO JOBS, TWO ELEMENTS
     Trying to build the curve out of the element that draws the fall-off is
     what broke this repeatedly, so they are separate:

       .crt-vig    the fall-off: six scaled copies of the screen, each
                   painting one flat translucent layer outside itself. Scaling
                   is the point — it multiplies the corner radius along with
                   the box, so a ring cannot be squarer than the frame. See
                   the long note further down for why inset shadows could not
                   do this.
       .crt-curve  the glass edge, exactly as v3 drew it: a rounded rectangle
                   with one enormous SOLID spread outside it. Opaque, so
                   there is no seam, and it is the only thing that cuts the
                   corner.

   PIXEL ALIGNMENT
     The overlay is fixed to the viewport, not to the window. A centred window
     can land on a half pixel when the viewport is an odd number of pixels
     wide, and a scanline drawn from a half-pixel origin smears across two
     rows. Anchoring to the viewport gives it an integer origin every time.
     The pitch is 3px and the stroke is 2px, which is the pair that stays
     legible; 1px vanished and 3px read as a filter over the whole screen.
   ========================================================================== */

body {
  --crt-alpha: 0.105;            /* the script writes these */
  --crt-curve: 26px;
  --crt-line: 2px;
  --crt-pitch: 3px;
  --crv-depth: 0.40;
  --crv-dist: 0.40;

  /* 0 for square corners, whatever the Curvature slider says for circular.
     One value feeds both the rings and the glass, so they can never disagree
     about the shape. */
  --vig-radius: 0px;
}

/* THE SCREEN EFFECT SCALES WITH THE INTERFACE.

   Everything in this file is measured in viewport pixels, which was right
   while the window was one fixed size and became wrong the moment it started
   scaling. The scanline pitch is the clearest case: 3px against 11px type is
   a visible stripe, and it stays 3px however large the interface is drawn.
   On a 5K panel the window is three times its design size and the stripes
   are still 3px, so there are around 960 of them down the screen — far too
   fine to read as scanlines and close enough together to blend into a flat
   grey film over everything. That is the washed-out look, and it is not
   blur; it is the effect being applied at the wrong scale.

   Multiplying by --fit restores the ratio the effect was drawn at, so 3px
   against 11px type stays 3px against 11px type at every resolution. The
   same argument applies to the glass corner and to how far the vignette
   reaches: both are fractions of the interface, not of the panel.

   The slider writes --crt-curve onto .crt, so anything derived from it has
   to be computed there too — a value declared on <body> resolves against
   body's copy and would never see it. */
.crt {
  --vig-radius: 0px;
  --line-f:  calc(var(--crt-line)  * var(--fit, 1));
  --pitch-f: calc(var(--crt-pitch) * var(--fit, 1));
}

/* A rounded rectangle, not an oval. The radius was scaling with a viewport
   unit on top of the slider, so on a wide screen it ran away and the corners
   swallowed the edges. A fixed multiple of the slider keeps it a rectangle
   with generous corners at every size. */
body:has(#crv-ci:checked) .crt { --vig-radius: calc(var(--crt-curve) * var(--fit, 1)); }

.crt {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 300;
  pointer-events: none;
}
/* The overlay carries the scanlines AND the corners. It used to be shown
   only for a screen type, so choosing Square or Circular while Screen Type
   was None did nothing whatsoever — the corner setting worked or not
   depending on an unrelated control. Any of the five brings it up now. */
body:has(#crt-1:checked) .crt,
body:has(#crt-2:checked) .crt,
body:has(#crv-sq:checked) .crt,
body:has(#crv-ci:checked) .crt { display: block; }


/* -- scanlines ------------------------------------------------------------- */

/* Gated on the screen type, not merely on the overlay being up. The overlay
   now also comes up for a corner setting alone, so an ungated .crt-lines drew
   scanlines over everything with Screen Type set to None — the one setting
   whose whole job is to stop drawing them. */
.crt-lines { display: none; }
body:has(#crt-1:checked) .crt-lines,
body:has(#crt-2:checked) .crt-lines { display: block; }

.crt-lines {
  position: absolute;
  inset: 0;
  opacity: var(--crt-alpha);
  background-image: repeating-linear-gradient(
    180deg,
    #000000 0 var(--line-f),
    transparent var(--line-f) var(--pitch-f));
}

/* Grid adds the vertical pass over the horizontal one. */
body:has(#crt-2:checked) .crt-lines {
  background-image:
    repeating-linear-gradient(180deg, #000000 0 var(--line-f),
      transparent var(--line-f) var(--pitch-f)),
    repeating-linear-gradient(90deg,
      color-mix(in srgb, #000000 55%, transparent) 0 var(--line-f),
      transparent var(--line-f) var(--pitch-f));
}


/* -- the vignette ---------------------------------------------------------- */

/* SIX RINGS, EACH A SCALED COPY OF THE SCREEN.

   WHY NOT INSET SHADOWS
     Every version of this until now drew the fall-off as six inset shadows
     with growing spreads on one rounded element. That cannot work, and the
     reason is in the definition: the inner edge of an inset shadow is the
     border box shrunk by the spread, and its corner radius is the element's
     radius MINUS that spread, floored at zero. So each ring is less round
     than the one outside it, and every ring whose spread exceeds the radius
     is exactly square. The rings nearest the middle went square first and
     the outermost ring squared off last — which is precisely what it looked
     like: a curve that tapered away as the distance came up, whatever the
     curvature was set to. No amount of tuning fixes it; the shape is wrong
     by construction.

     A scaled copy has no such problem. `transform: scale()` multiplies the
     corner radius by the same factor as the box, so every ring is
     geometrically similar to the screen — same shape, smaller. A ring can
     never be squarer than the frame, at any distance or any curvature.

   HOW THEY STACK
     Each ring paints OUTWARD, one flat translucent colour beyond its own
     rounded edge, the same mechanism .crt-curve uses below. Six of them
     overlap, so the area outside every ring takes every layer and the area
     just inside the screen edge takes only the outermost. That accumulation
     is the gradient; no ring has to be a gradient itself.
   -------------------------------------------------------------------------- */

.crt-vig {
  position: absolute;
  inset: 0;
  display: none;
}

.crt-vig i {
  position: absolute;
  inset: 0;
  border-radius: var(--vig-radius);
}

/* Scaled for the same reason the pitch is: the softness of the vignette's
   inner edge is a proportion of the interface it falls across, so a fixed
   60px reads as a wide gradient at the design size and a hard ring at 3x. */
.crt { --vig-blur: calc((var(--crv-dist) * 60px + 8px) * var(--fit, 1)); }

/* --crv-dist is how far in the fall-off reaches: at 0 the rings sit on the
   edge and nothing is visible, at 1 the innermost has shrunk to 40%. */
.crt-vig i:nth-child(1) { transform: scale(calc(1 - var(--crv-dist) * 0.06)); }
.crt-vig i:nth-child(2) { transform: scale(calc(1 - var(--crv-dist) * 0.14)); }
.crt-vig i:nth-child(3) { transform: scale(calc(1 - var(--crv-dist) * 0.24)); }
.crt-vig i:nth-child(4) { transform: scale(calc(1 - var(--crv-dist) * 0.36)); }
.crt-vig i:nth-child(5) { transform: scale(calc(1 - var(--crv-dist) * 0.48)); }
.crt-vig i:nth-child(6) { transform: scale(calc(1 - var(--crv-dist) * 0.60)); }

/* --crv-depth scales all six together. 50vmax is simply "past the corner of
   any viewport", so the fill never runs out before the screen edge does. */
.crt-vig i:nth-child(1) { box-shadow: 0 0 var(--vig-blur) 50vmax color-mix(in srgb, #000 calc(var(--crv-depth) * 22%), transparent); }
.crt-vig i:nth-child(2) { box-shadow: 0 0 var(--vig-blur) 50vmax color-mix(in srgb, #000 calc(var(--crv-depth) * 18%), transparent); }
.crt-vig i:nth-child(3) { box-shadow: 0 0 var(--vig-blur) 50vmax color-mix(in srgb, #000 calc(var(--crv-depth) * 14%), transparent); }
.crt-vig i:nth-child(4) { box-shadow: 0 0 var(--vig-blur) 50vmax color-mix(in srgb, #000 calc(var(--crv-depth) * 11%), transparent); }
.crt-vig i:nth-child(5) { box-shadow: 0 0 var(--vig-blur) 50vmax color-mix(in srgb, #000 calc(var(--crv-depth) *  8%), transparent); }
.crt-vig i:nth-child(6) { box-shadow: 0 0 var(--vig-blur) 50vmax color-mix(in srgb, #000 calc(var(--crv-depth) *  6%), transparent); }

body:has(#crv-sq:checked) .crt-vig,
body:has(#crv-ci:checked) .crt-vig { display: block; }


/* -- the glass edge, circular only -----------------------------------------
   v3's recipe, unchanged because it was right: a rounded rectangle with a
   single solid spread beyond it. Solid, so the edge is opaque rather than a
   translucent seam, and nothing underneath is scaled or warped, so the text
   stays on its pixel grid.
   -------------------------------------------------------------------------- */

.crt-curve {
  display: none;
  position: absolute;
  inset: 0;
  border-radius: var(--vig-radius);
  box-shadow: 0 0 0 400px #000000;
}
body:has(#crv-ci:checked) .crt-curve { display: block; }
