/* ==========================================================================
   Math Memory — the backdrop
   --------------------------------------------------------------------------
   Two fixed layers behind everything, built from gradients and inline SVG
   tiles. No image files and nothing in the DOM, so it costs one paint and
   survives file://.

   Being FIXED is not decoration. The screen shake translates the app, and a
   background painted on the element that moves exposes the page behind it —
   which is where the white edges and the flickering scrollbar came from.
   Painting on the viewport instead leaves the shake nothing to reveal.

   Layer order, back to front:
     html                the base colour
     .app-body::before   soft colour blobs and a gentle vignette
     .app-body::after    maths symbols and pond bubbles, drifting slowly
     .app-shell          the app itself

   Tuning note: this is deliberately quiet. An earlier pass ran the texture at
   .13 opacity with nine marks per tile and it was a wall of symbols that was
   genuinely hard to read against.
   ========================================================================== */

.app-body::before,
.app-body::after {
  content: "";
  position: fixed;
  inset: -12%;               /* oversized so a drifting tile never shows an edge */
  pointer-events: none;
  z-index: 0;
}

/* --------------------------------------------------------------------------
   Colour: enough that the page is never one flat field, not so much that
   anything has to compete with it.

   The radii are written into each gradient (`58% 42% at 10% 2%`) rather than
   set with background-size. With background-size and no background-position
   every layer tiles from the top-left corner, so `at 10% 2%` would position
   the blob inside its own tile instead of on the page and they would all pile
   up in one corner.
   -------------------------------------------------------------------------- */
.app-body::before {
  background:
    radial-gradient(58% 42% at 10%  2%, rgba(255,  61, 139, .17), transparent 74%),
    radial-gradient(54% 38% at 90%  0%, rgba( 79, 227, 208, .12), transparent 74%),
    radial-gradient(58% 46% at 98% 58%, rgba(139,  61, 255, .22), transparent 74%),
    radial-gradient(50% 40% at  0% 70%, rgba(255, 171,  29, .12), transparent 74%),
    radial-gradient(95% 32% at 50% 106%, rgba( 52, 209, 192, .17), transparent 74%),
    /* a soft vignette, so the middle of the screen stays the quietest part */
    radial-gradient(80% 66% at 50% 46%, transparent 46%, rgba(12, 5, 34, .22) 100%);
}

/* --------------------------------------------------------------------------
   Texture: four maths marks on a big tile, and a few pond bubbles on a bigger
   one, drifting in opposite directions. Two scales moving at different rates
   reads as depth without a second element.
   -------------------------------------------------------------------------- */
.app-body::after {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'%3E%3Cg fill='none' stroke-width='5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M26 30 L44 48 M44 30 L26 48' stroke='%23ff8a2b'/%3E%3Cpath d='M160 44 h22 M171 33 v22' stroke='%231e8fff'/%3E%3Cpath d='M40 160 h22 M40 173 h22' stroke='%2312b06c'/%3E%3Cpath d='M150 168 l5 10.5 11.5 1.7 -8.3 8.1 2 11.5 -10.2 -5.4 -10.2 5.4 2 -11.5 -8.3 -8.1 11.5 -1.7 z' stroke='%23ffd76a' stroke-width='4'/%3E%3C/g%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='380' height='380' viewBox='0 0 380 380'%3E%3Cg fill='none' stroke='%23ffffff' stroke-width='3'%3E%3Ccircle cx='60' cy='84' r='20'/%3E%3Ccircle cx='300' cy='210' r='28'/%3E%3Ccircle cx='150' cy='320' r='13'/%3E%3C/g%3E%3C/svg%3E");
  background-repeat: repeat, repeat;
  opacity: .075;
  animation: bgdrift 190s linear infinite;
}

@keyframes bgdrift {
  from { background-position:    0px    0px,     0px     0px; }
  to   { background-position:  240px  720px, -380px -1140px; }
}

/* The app sits above all of it. */
.app-shell { position: relative; z-index: 1; }

/* The parent dashboard is the one light screen; it covers the backdrop
   rather than fighting it. */
.app-shell[data-surface="light"] { z-index: 2; }

/* There is deliberately NO per-screen wash. There used to be one, as a
   gradient on .screen with inset:0 — but .screen is only as wide as the 560px
   column, so on anything wider than a phone it drew a lighter rectangle with
   two hard vertical edges down the middle of the page. Anything that tints a
   screen has to live on the fixed viewport layers above, or it will show its
   own box. */

@media (prefers-reduced-motion: reduce) {
  .app-body::after { animation: none; }
}
