/* ==========================================================================
   Shared animated page background

   Linked by every page, including the two tool pages, which do not load
   css/style.css — the background remover ships COEP: require-corp and
   self-hosts its fonts, so it keeps its own theme file. Pointer physics
   for this layer lives in js/main.js.
   ========================================================================== */

html { background: #070A10; }
body { background-color: transparent; position: relative; }

/* ==========================================================================
   Page background — an always-moving layer behind everything

   Sits at z-index -1, so ordinary in-flow content paints over it without
   needing a stacking context of its own. The section fills above it have to
   be translucent (see "Section rhythm") or they would simply cover it up.

   Absolute, not fixed: fixed pins the layer to the viewport, so the whole
   field travels down with you and nothing appears to pass by. Absolute
   anchors it to the document, so you scroll past the circles and leave them
   behind — which is what gives the page any sense of depth. It also gives
   the kick physics in js/main.js real walls to bounce off.
   ========================================================================== */
.page-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}

/* --- Mesh: large blurred colour fields on independent wandering paths -----
   The standard technique behind the Stripe/Linear/Arc-style backgrounds.
   `screen` blending is what matters on a dark page: where two fields overlap
   the colours add rather than muddy, so the mesh generates hues that aren't
   in the source list. Each field only animates transform, so the browser can
   cache the expensive blur as a texture and just move it. */
.page-bg__mesh {
  position: absolute;
  inset: 0 -10%;
  isolation: isolate;
  opacity: 0.85;
}
.page-bg__mesh i {
  position: absolute;
  border-radius: 50%;
  mix-blend-mode: screen;
  will-change: transform;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

/* Seven hues, seven sizes, seven paths, no two durations harmonically
   related — so the composition never visibly repeats. Tops are percentages
   of the whole document, so the fields stay spread out however long the
   page is. */
.page-bg__mesh i:nth-child(1) { top:  2%; left:  4%; width: 42vw; height: 42vw; background: radial-gradient(circle, rgba(91,157,255,0.42), transparent 68%); filter: blur(56px); animation-name: wander1; animation-duration: 61s; }
.page-bg__mesh i:nth-child(2) { top: 16%; left: 62%; width: 36vw; height: 36vw; background: radial-gradient(circle, rgba(124,108,255,0.36), transparent 68%); filter: blur(60px); animation-name: wander2; animation-duration: 74s; }
.page-bg__mesh i:nth-child(3) { top: 32%; left: 10%; width: 32vw; height: 32vw; background: radial-gradient(circle, rgba(56,211,196,0.26), transparent 68%); filter: blur(58px); animation-name: wander3; animation-duration: 53s; }
.page-bg__mesh i:nth-child(4) { top: 48%; left: 66%; width: 30vw; height: 30vw; background: radial-gradient(circle, rgba(240,169,60,0.24), transparent 68%); filter: blur(62px); animation-name: wander4; animation-duration: 89s; }
.page-bg__mesh i:nth-child(5) { top: 62%; left: 22%; width: 26vw; height: 26vw; background: radial-gradient(circle, rgba(164,107,255,0.28), transparent 68%); filter: blur(54px); animation-name: wander5; animation-duration: 67s; }
.page-bg__mesh i:nth-child(6) { top: 78%; left: 58%; width: 28vw; height: 28vw; background: radial-gradient(circle, rgba(255,122,138,0.20), transparent 68%); filter: blur(60px); animation-name: wander6; animation-duration: 47s; }
.page-bg__mesh i:nth-child(7) { top: 91%; left: 14%; width: 24vw; height: 24vw; background: radial-gradient(circle, rgba(56,211,159,0.22), transparent 68%); filter: blur(52px); animation-name: wander2; animation-duration: 81s; animation-direction: reverse; }

@keyframes wander1 {
  0%,100% { transform: translate3d(0,0,0) scale(1); }
  25%     { transform: translate3d(7vw,-5vh,0) scale(1.12); }
  50%     { transform: translate3d(3vw, 7vh,0) scale(0.92); }
  75%     { transform: translate3d(-6vw,3vh,0) scale(1.06); }
}
@keyframes wander2 {
  0%,100% { transform: translate3d(0,0,0) scale(1.05); }
  30%     { transform: translate3d(-8vw,4vh,0) scale(0.9); }
  60%     { transform: translate3d(-2vw,-6vh,0) scale(1.15); }
}
@keyframes wander3 {
  0%,100% { transform: translate3d(0,0,0) scale(0.95); }
  35%     { transform: translate3d(9vw,3vh,0) scale(1.1); }
  70%     { transform: translate3d(4vw,-7vh,0) scale(1); }
}
@keyframes wander4 {
  0%,100% { transform: translate3d(0,0,0) scale(1.08); }
  40%     { transform: translate3d(-7vw,-4vh,0) scale(0.94); }
  75%     { transform: translate3d(5vw,-8vh,0) scale(1.12); }
}
@keyframes wander5 {
  0%,100% { transform: translate3d(0,0,0) scale(1); }
  33%     { transform: translate3d(-5vw,8vh,0) scale(1.14); }
  66%     { transform: translate3d(8vw,4vh,0) scale(0.9); }
}
@keyframes wander6 {
  0%,100% { transform: translate3d(0,0,0) scale(1.02); }
  45%     { transform: translate3d(6vw,-9vh,0) scale(0.92); }
  80%     { transform: translate3d(-7vw,-3vh,0) scale(1.1); }
}

/* --- Structure: flat colour discs over the soft mesh ---------------------
   Evenly filled, no off-centre highlight — the gradient is centred purely to
   soften the edge, so these read as circles rather than glass spheres. No
   disc is tinted near the page colour, so each stays an object.

   The CSS animation owns `transform` (the ambient drift). Pointer repulsion
   in js/main.js writes the separate `translate` property instead, so the two
   compose rather than overwrite each other. */
.page-bg__dots {
  position: absolute;
  inset: 0;
}
.page-bg__dots i {
  position: absolute;
  border-radius: 50%;
  will-change: transform, translate;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
.page-bg__dots i:nth-child(1)  { top:  6%; left: 11%; width:  86px; height:  86px; background: radial-gradient(circle, rgba(91,157,255,0.24) 68%, rgba(91,157,255,0.06) 100%);   box-shadow: 0 0 26px rgba(91,157,255,0.12);  animation: wander3 58s infinite; }
.page-bg__dots i:nth-child(2)  { top: 13%; left: 78%; width: 140px; height: 140px; background: radial-gradient(circle, rgba(124,108,255,0.20) 68%, rgba(124,108,255,0.05) 100%); box-shadow: 0 0 32px rgba(124,108,255,0.11); animation: wander5 71s infinite; }
.page-bg__dots i:nth-child(3)  { top: 24%; left: 26%; width:  52px; height:  52px; background: radial-gradient(circle, rgba(56,211,196,0.24) 68%, rgba(56,211,196,0.06) 100%);   box-shadow: 0 0 22px rgba(56,211,196,0.12);  animation: wander1 46s infinite; }
.page-bg__dots i:nth-child(4)  { top: 33%; left: 63%; width: 108px; height: 108px; background: radial-gradient(circle, rgba(240,169,60,0.19) 68%, rgba(240,169,60,0.05) 100%);   box-shadow: 0 0 28px rgba(240,169,60,0.10);  animation: wander4 63s infinite; }
.page-bg__dots i:nth-child(5)  { top: 41%; left: 43%; width:  34px; height:  34px; background: radial-gradient(circle, rgba(164,107,255,0.26) 68%, rgba(164,107,255,0.07) 100%); box-shadow: 0 0 20px rgba(164,107,255,0.13); animation: wander6 39s infinite; }
.page-bg__dots i:nth-child(6)  { top: 49%; left:  8%; width:  64px; height:  64px; background: radial-gradient(circle, rgba(56,211,159,0.24) 68%, rgba(56,211,159,0.06) 100%);   box-shadow: 0 0 24px rgba(56,211,159,0.12);  animation: wander2 52s infinite; }
.page-bg__dots i:nth-child(7)  { top: 58%; left: 84%; width:  44px; height:  44px; background: radial-gradient(circle, rgba(255,122,138,0.24) 68%, rgba(255,122,138,0.06) 100%); box-shadow: 0 0 22px rgba(255,122,138,0.12); animation: wander5 44s infinite; }
.page-bg__dots i:nth-child(8)  { top: 67%; left: 34%; width:  72px; height:  72px; background: radial-gradient(circle, rgba(91,157,255,0.22) 68%, rgba(91,157,255,0.06) 100%);   box-shadow: 0 0 26px rgba(91,157,255,0.12);  animation: wander1 66s infinite; }
.page-bg__dots i:nth-child(9)  { top: 76%; left: 70%; width:  26px; height:  26px; background: radial-gradient(circle, rgba(240,169,60,0.28) 68%, rgba(240,169,60,0.08) 100%);   box-shadow: 0 0 18px rgba(240,169,60,0.14);  animation: wander3 35s infinite; }
.page-bg__dots i:nth-child(10) { top: 86%; left: 18%; width:  96px; height:  96px; background: radial-gradient(circle, rgba(124,108,255,0.20) 68%, rgba(124,108,255,0.05) 100%); box-shadow: 0 0 28px rgba(124,108,255,0.11); animation: wander6 77s infinite; }

/* --- Small screens -------------------------------------------------------
   Seventeen simultaneously-animating layers, several carrying a 50-60px
   blur, is a lot of compositing for a phone — and on touch the discs are
   purely decorative anyway, since the kick physics is pointer-only. Halve
   the element count, cut the blur radius, and drop the will-change hints so
   the compositor isn't asked to hold seventeen layers in memory. */
@media (max-width: 768px) {
  .page-bg__mesh i:nth-child(n + 5) { display: none; }
  .page-bg__dots i:nth-child(n + 7) { display: none; }
  .page-bg__mesh i { filter: blur(34px); will-change: auto; }
  .page-bg__dots i { will-change: auto; }
}

/* Coarse pointers get no kick interaction, so the discs never need their own
   compositor layer regardless of viewport width (a tablet in landscape is
   wider than the breakpoint above). */
@media (hover: none) and (pointer: coarse) {
  .page-bg__mesh i, .page-bg__dots i { will-change: auto; }
}

@media (prefers-reduced-motion: reduce) {
  /* The composition is designed to look right stopped, so it stays
     visible and simply holds still. */
  .page-bg__mesh i, .page-bg__dots i { animation: none !important; }
}
