/* A sand mandala is swept away on purpose. Nothing here persists, and nothing
   replaces it -- the page ends as empty ground and stays that way. */
:root { color-scheme: dark; }
html, body {
  margin: 0; height: 100%; overflow: hidden;
  /* Near-black, but in the navy family the dashboard was built from, so the
     ground the image sits on recedes instead of framing it. */
  background: #000a16;
}
#sand, #src { position: fixed; inset: 0; margin: auto; }

#sand {
  width: 100%; height: 100%; display: block;
  /* Blank until the first frame has actually been drawn. Revealing the canvas
     any earlier shows an empty rectangle; revealing the image instead shows a
     sharp still that the grains then replace, which reads as a glitch. */
  opacity: 0;
  transition: opacity 700ms ease-out;
}
#sand.ready { opacity: 1; }

/* Hidden, not merely behind the canvas: it must never be seen unless it is
   doing the work. `visibility` rather than `display` so the browser still
   fetches and decodes it -- it is the pixel source. */
#src {
  visibility: hidden;
  max-width: 100%; max-height: 100%;
  object-fit: contain;
}
/* The fallback: no WebGL, or an image that cannot be read into a canvas. The
   same gesture at lower fidelity rather than a different page. */
#src.fallback {
  visibility: visible;
  animation: sweep 55s ease-in 2s forwards;
}
@keyframes sweep {
  to { opacity: 0; filter: blur(14px) saturate(.3); transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  #sand { transition-duration: 250ms; }
  /* No drift, no acceleration -- just a long, quiet fade to the same end. */
  #src.fallback { animation: sweep 20s linear 1s forwards; }
}
