# Aquarium 404

> An aquarium with fish that swim on their own and dart away from the pointer; the brass plate says species 404 is missing.

- Category: [404](https://library.aimran.es/components/404)
- Built with: HTML + CSS
- Live editor: https://library.aimran.es/blocks/404-aquarium
- Library: AIMRAN Library (https://library.aimran.es), free, no sign-up, by Aimran Oukham

## Where to use it

Zoos, aquariums and pet shops can use this tank as their error page. Five colorful fish wander through blue water with moving caustic light, swaying weeds, rising bubbles and a sandy floor, and a brass plate in the corner names an absent species and notes that it was not found.

The fish swim with simple steering in JavaScript and scatter when the pointer or a finger gets close. Reduced motion keeps them still. The tank is decorative and hidden from screen readers. Adjust the yellow accent and link the button to your entrance page.

## Code

### HTML

```html
<!doctype html>
<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="robots" content="noindex" />
    <title>404 · Page not found</title>
    <style>
      body { margin: 0; background: #000; }
      .n4-aquarium {
        --accent: #ffb703;
        --k: 1;
        position: fixed;
        inset: 0;
        z-index: 0;
        overflow: hidden;
        container-type: size;
        display: grid;
        place-items: center;
        background: #000;
        color: #f5f5f7;
        font-family: -apple-system,BlinkMacSystemFont,"SF Pro Display","Inter","Segoe UI",system-ui,sans-serif;
        -webkit-font-smoothing: antialiased;
        text-align: center;
        line-height: 1.4;
      }
      
      .n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
        box-sizing: border-box;
      }
      
      .n4-aquarium .n4-copy {
        position: relative;
        z-index: 5;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.6cqmin;
        width: 100%;
        max-width: 680px;
        padding: 0 6cqw;
      }
      
      .n4-aquarium .n4-title {
        margin: 0;
        font-size: clamp(17px,4.2cqmin,36px);
        font-weight: 600;
        letter-spacing: -.02em;
        line-height: 1.15;
        text-wrap: balance;
      }
      
      .n4-aquarium .n4-sub {
        margin: 0;
        max-width: 34em;
        font-size: clamp(13px,2.4cqmin,18px);
        color: #a1a1a6;
        text-wrap: balance;
      }
      
      .n4-aquarium .n4-tag {
        font: 600 clamp(10px,1.9cqmin,13px)/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        letter-spacing: .16em;
        text-transform: uppercase;
        color: var(--accent);
      }
      
      .n4-aquarium .n4-cta {
        margin-top: 1.8cqmin;
        display: inline-flex;
        align-items: center;
        gap: .5em;
        padding: .85em 1.5em;
        border-radius: 999px;
        background: #f5f5f7;
        color: #000;
        font-size: clamp(13px,2.2cqmin,16px);
        font-weight: 600;
        text-decoration: none;
        transition: transform .3s cubic-bezier(.25,.1,.25,1),box-shadow .3s cubic-bezier(.25,.1,.25,1);
      }
      
      .n4-aquarium .n4-cta:hover {
        transform: translateY(-2px);
        box-shadow: 0 12px 32px -10px var(--accent);
      }
      
      .n4-aquarium .n4-cta:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 3px;
      }
      
      .n4-aquarium .n4-stars,.n4-aquarium .n4-stars2 {
        position: absolute;
        inset: -4%;
        pointer-events: none;
      }
      
      .n4-aquarium .n4-stars {
        background-image: radial-gradient(1px 1px at 8% 12%,#fff 60%,transparent),radial-gradient(1px 1px at 22% 68%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 35% 24%,#fff 60%,transparent),radial-gradient(1px 1px at 48% 82%,#fff 60%,transparent),radial-gradient(1px 1px at 57% 9%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 66% 44%,#fff 60%,transparent),radial-gradient(1px 1px at 74% 72%,#fff 60%,transparent),radial-gradient(1px 1px at 86% 18%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 93% 58%,#fff 60%,transparent),radial-gradient(1px 1px at 14% 42%,#fff 60%,transparent),radial-gradient(1px 1px at 40% 55%,#fff 60%,transparent),radial-gradient(1px 1px at 81% 90%,#fff 60%,transparent),radial-gradient(1px 1px at 4% 88%,#fff 60%,transparent),radial-gradient(1px 1px at 62% 30%,#fff 60%,transparent);
        opacity: .75;
        animation: n4-aquarium-tw calc(5s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-aquarium .n4-stars2 {
        background-image: radial-gradient(2px 2px at 18% 30%,rgba(255,255,255,.9) 50%,transparent),radial-gradient(1.5px 1.5px at 72% 20%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 30% 85%,rgba(255,255,255,.7) 50%,transparent),radial-gradient(1.5px 1.5px at 88% 70%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 52% 60%,rgba(255,255,255,.6) 50%,transparent),radial-gradient(1.5px 1.5px at 6% 55%,rgba(255,255,255,.8) 50%,transparent);
        opacity: .55;
        animation: n4-aquarium-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
      }
      
      .n4-aquarium [data-depth] {
        transition: transform .9s cubic-bezier(.2,.7,.2,1);
      }
      
      @keyframes n4-aquarium-tw {
        from {
          opacity: .3;
        }
      }
      
      @keyframes n4-aquarium-spin {
        to {
          transform: rotate(1turn);
        }
      }
      
      @keyframes n4-aquarium-fade {
        from {
          opacity: 0;
          transform: translateY(10px);
        }
      }
      
      @media (prefers-reduced-motion:reduce) {
        .n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
          animation: none!important;
          transition: none!important;
        }
      }
      
      .n4-aquarium {
        background: radial-gradient(80% 60% at 50% 28%,#0f4150,#03141a 75%);
        color: #e6f8fb;
      }
      
      .n4-aquarium .n4-tank {
        position: relative;
        overflow: hidden;
        width: min(68cqmin,470px);
        aspect-ratio: 16/9;
        font-size: min(2cqmin,14px);
        margin-bottom: 1.8cqmin;
        border-radius: 1em;
        background: linear-gradient(rgba(255,255,255,.22) 0 .8em,transparent .8em),linear-gradient(#45c4d8,#15829a 50%,#0a4f66);
        box-shadow: inset 0 0 0 .35em rgba(220,245,250,.35),0 0 0 .5em #0b2b36,0 2em 3em -1.5em rgba(0,0,0,.7);
        touch-action: none;
      }
      
      .n4-aquarium .n4-caus {
        position: absolute;
        inset: 0;
        background: repeating-radial-gradient(ellipse at 30% 20%,rgba(255,255,255,.09) 0 1em,transparent 1em 2.6em),repeating-radial-gradient(ellipse at 70% 10%,rgba(255,255,255,.07) 0 .8em,transparent .8em 2.2em);
        animation: n4-aquarium-caus calc(9s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-aquarium .n4-weed {
        position: absolute;
        left: 0;
        bottom: 8%;
        width: 100%;
        height: 56%;
      }
      
      .n4-aquarium .n4-weed path {
        fill: none;
        stroke: #2f9e62;
        stroke-width: 5;
        stroke-linecap: round;
        transform-box: fill-box;
        transform-origin: 50% 100%;
        animation: n4-aquarium-sway calc(var(--d) / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-aquarium .n4-weed path:nth-child(2n) {
        stroke: #5cc27f;
        stroke-width: 4;
      }
      
      .n4-aquarium .n4-sand {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: 14%;
        border-radius: 50% 50% 0 0/1.4em 1.4em 0 0;
        background: radial-gradient(circle,rgba(120,90,50,.35) 0 1px,transparent 1.5px) 0 0/.6em .6em,linear-gradient(#ead6a4,#cdb57d);
      }
      
      .n4-aquarium .n4-fish {
        position: absolute;
        left: var(--x);
        top: var(--y);
        width: calc(var(--s) * 4.6em);
        height: auto;
        translate: -50% -50%;
        scale: var(--f,1) 1;
        fill: var(--c);
        filter: drop-shadow(0 .3em .3em rgba(0,0,0,.2));
      }
      
      .n4-aquarium .n4-fish circle {
        fill: #111;
      }
      
      .n4-aquarium .n4-stripe {
        fill: none;
        stroke: rgba(255,255,255,.75);
        stroke-width: 2.5;
      }
      
      .n4-aquarium .n4-tail {
        transform-box: fill-box;
        transform-origin: 0 50%;
        animation: n4-aquarium-tail calc(.35s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-aquarium .n4-bub {
        position: absolute;
        bottom: 12%;
        left: var(--x);
        width: var(--s);
        height: var(--s);
        border-radius: 50%;
        border: 1px solid rgba(255,255,255,.7);
        background: radial-gradient(circle at 35% 30%,rgba(255,255,255,.85) 0 18%,transparent 24%);
        opacity: 0;
        animation: n4-aquarium-bub calc(var(--d) / var(--k)) linear var(--dl) infinite;
      }
      
      .n4-aquarium .n4-plate {
        position: absolute;
        z-index: 3;
        right: .9em;
        bottom: .7em;
        display: grid;
        gap: .15em;
        padding: .45em .75em;
        border-radius: .25em;
        text-align: left;
        background: linear-gradient(135deg,#f6dc8a,#b8862b 45%,#f1cf73 70%,#8a5e14);
        color: #2a1d05;
        box-shadow: 0 .2em .4em rgba(0,0,0,.4);
      }
      
      .n4-aquarium .n4-plate b {
        font: italic 600 1em/1 "Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif;
      }
      
      .n4-aquarium .n4-plate small {
        font: 700 .66em/1.1 "Helvetica Neue",Helvetica,Arial,system-ui,sans-serif;
        letter-spacing: .08em;
        text-transform: uppercase;
      }
      
      .n4-aquarium .n4-title {
        font-size: clamp(20px,5cqmin,42px);
        font-weight: 700;
        letter-spacing: -.025em;
      }
      
      .n4-aquarium .n4-sub {
        color: #9fc4cd;
      }
      
      .n4-aquarium .n4-cta {
        background: var(--accent);
        color: #1d1400;
      }
      
      @keyframes n4-aquarium-caus {
        to {
          background-position: 3em 1em,-2em 2em;
        }
      }
      
      @keyframes n4-aquarium-sway {
        from {
          rotate: -6deg;
        }
        to {
          rotate: 6deg;
        }
      }
      
      @keyframes n4-aquarium-tail {
        to {
          scale: 1 .7;
        }
      }
      
      @keyframes n4-aquarium-bub {
        0% {
          transform: translate(0,0);
          opacity: 0;
        }
        10% {
          opacity: 1;
        }
        50% {
          transform: translate(.6em,-7em);
        }
        90% {
          opacity: .9;
        }
        100% {
          transform: translate(-.3em,-14em);
          opacity: 0;
        }
      }
    </style>
  </head>
  <body>
    <main class="n4-aquarium">
      <div class="n4-copy">
        <div class="n4-tank" aria-hidden="true">
          <i class="n4-caus"></i>
          <svg class="n4-weed" viewBox="0 0 300 120" preserveAspectRatio="none"><path style="--d:4.2s" d="M18 120C10 96 28 80 18 56S26 24 20 6"/><path style="--d:5.4s" d="M34 120C40 100 28 86 36 66S30 40 34 30"/><path style="--d:4.8s" d="M252 120C246 98 262 82 254 60S262 30 256 14"/><path style="--d:6s" d="M270 120C278 102 266 90 272 72S266 50 270 40"/><path style="--d:5s" d="M286 120C280 104 292 94 286 80"/></svg>
          <i class="n4-sand"></i>
          <svg class="n4-fish" viewBox="0 0 44 26" style="--c:#ffb703;--s:1;--x:18%;--y:24%"><path class="n4-tail" d="M32 13L44 4l-3 9 3 9z"/><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z"/><path d="M18 6l6-5 2 7z"/><path class="n4-stripe" d="M21 5v16"/><circle cx="12" cy="11" r="1.8"/></svg><svg class="n4-fish" viewBox="0 0 44 26" style="--c:#fb8500;--s:0.8;--x:34%;--y:61%"><path class="n4-tail" d="M32 13L44 4l-3 9 3 9z"/><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z"/><path d="M18 6l6-5 2 7z"/><path class="n4-stripe" d="M21 5v16"/><circle cx="12" cy="11" r="1.8"/></svg><svg class="n4-fish" viewBox="0 0 44 26" style="--c:#8ecae6;--s:0.7;--x:50%;--y:52%"><path class="n4-tail" d="M32 13L44 4l-3 9 3 9z"/><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z"/><path d="M18 6l6-5 2 7z"/><path class="n4-stripe" d="M21 5v16"/><circle cx="12" cy="11" r="1.8"/></svg><svg class="n4-fish" viewBox="0 0 44 26" style="--c:#ff5d8f;--s:0.9;--x:66%;--y:43%"><path class="n4-tail" d="M32 13L44 4l-3 9 3 9z"/><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z"/><path d="M18 6l6-5 2 7z"/><path class="n4-stripe" d="M21 5v16"/><circle cx="12" cy="11" r="1.8"/></svg><svg class="n4-fish" viewBox="0 0 44 26" style="--c:#b8f2e6;--s:0.6;--x:82%;--y:34%"><path class="n4-tail" d="M32 13L44 4l-3 9 3 9z"/><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z"/><path d="M18 6l6-5 2 7z"/><path class="n4-stripe" d="M21 5v16"/><circle cx="12" cy="11" r="1.8"/></svg>
          <i class="n4-bub" style="--x:10%;--d:5.5s;--dl:0s;--s:0.5em"></i><i class="n4-bub" style="--x:14%;--d:6.5s;--dl:-2s;--s:0.35em"></i><i class="n4-bub" style="--x:84%;--d:5s;--dl:-1s;--s:0.45em"></i><i class="n4-bub" style="--x:88%;--d:7s;--dl:-4s;--s:0.3em"></i><i class="n4-bub" style="--x:60%;--d:6s;--dl:-3s;--s:0.4em"></i><i class="n4-bub" style="--x:40%;--d:7.5s;--dl:-5s;--s:0.3em"></i>
          <span class="n4-plate"><b translate="no">Pagina absens</b><small>Species not found · 404</small></span>
        </div>
        <h1 class="n4-title">This species doesn't live in our aquarium.</h1>
        <p class="n4-sub">We've looked behind every rock and the page is nowhere to be seen. Carry on through the other tanks or go back to the entrance.</p>
        <a class="n4-cta" href="/">Back to the entrance</a>
      </div>
    </main>
    <script>
      document.querySelectorAll(".n4-aquarium").forEach((el) => {
        const tank = el.querySelector(".n4-tank");
        const fish = Array.from(el.querySelectorAll(".n4-fish"));
        const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
        const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
        const st = fish.map((f, i) => ({ x: 0.18 + i * 0.16, y: 0.24 + ((i * 37) % 46) / 100, vx: (i % 2 ? -1 : 1) * 0.0015, vy: 0, f: i % 2 ? 1 : -1 }));
        let mx = -1, my = -1, raf = 0, last = performance.now();
        const put = () => st.forEach((s, i) => {
          fish[i].style.setProperty("--x", (s.x * 100).toFixed(2) + "%");
          fish[i].style.setProperty("--y", (s.y * 100).toFixed(2) + "%");
          fish[i].style.setProperty("--f", String(s.f));
        });
        const loop = (t) => {
          const dt = Math.min(3, (t - last) / 16.67) * k;
          last = t;
          st.forEach((s) => {
            s.vx += (Math.random() - 0.5) * 0.00014 * dt;
            s.vy += (Math.random() - 0.5) * 0.00012 * dt;
            if (mx >= 0) {
              const dx = s.x - mx, dy = (s.y - my) * 0.56, d = Math.hypot(dx, dy);
              if (d < 0.22) { s.vx += (dx / (d + 0.01)) * 0.0012 * dt; s.vy += (dy / (d + 0.01)) * 0.0012 * dt; }
            }
            if (s.x < 0.1) s.vx += 0.00025 * dt;
            if (s.x > 0.9) s.vx -= 0.00025 * dt;
            if (s.y < 0.18) s.vy += 0.00025 * dt;
            if (s.y > 0.72) s.vy -= 0.00025 * dt;
            const sp = Math.hypot(s.vx, s.vy);
            if (sp > 0.012) { s.vx *= 0.012 / sp; s.vy *= 0.012 / sp; }
            if (Math.abs(s.vx) < 0.0012) s.vx += s.vx < 0 ? -0.0001 : 0.0001;
            s.vx *= 0.985;
            s.vy *= 0.97;
            s.x += s.vx * dt;
            s.y += s.vy * dt;
            if (Math.abs(s.vx) > 0.0005) s.f = s.vx > 0 ? -1 : 1;
          });
          put();
          raf = requestAnimationFrame(loop);
        };
        const point = (e) => {
          const r = tank.getBoundingClientRect();
          mx = (e.clientX - r.left) / r.width;
          my = (e.clientY - r.top) / r.height;
        };
        tank.addEventListener("pointermove", point);
        tank.addEventListener("pointerdown", point);
        tank.addEventListener("pointerleave", () => { mx = -1; });
        put();
        if (!rm) raf = requestAnimationFrame(loop);
      });
    </script>
  </body>
</html>
```

### CSS

```css
.n4-aquarium {
  --accent: #ffb703;
  --k: 1;
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  container-type: size;
  display: grid;
  place-items: center;
  background: #000;
  color: #f5f5f7;
  font-family: -apple-system,BlinkMacSystemFont,"SF Pro Display","Inter","Segoe UI",system-ui,sans-serif;
  -webkit-font-smoothing: antialiased;
  text-align: center;
  line-height: 1.4;
}

.n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
  box-sizing: border-box;
}

.n4-aquarium .n4-copy {
  position: relative;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.6cqmin;
  width: 100%;
  max-width: 680px;
  padding: 0 6cqw;
}

.n4-aquarium .n4-title {
  margin: 0;
  font-size: clamp(17px,4.2cqmin,36px);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.15;
  text-wrap: balance;
}

.n4-aquarium .n4-sub {
  margin: 0;
  max-width: 34em;
  font-size: clamp(13px,2.4cqmin,18px);
  color: #a1a1a6;
  text-wrap: balance;
}

.n4-aquarium .n4-tag {
  font: 600 clamp(10px,1.9cqmin,13px)/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}

.n4-aquarium .n4-cta {
  margin-top: 1.8cqmin;
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .85em 1.5em;
  border-radius: 999px;
  background: #f5f5f7;
  color: #000;
  font-size: clamp(13px,2.2cqmin,16px);
  font-weight: 600;
  text-decoration: none;
  transition: transform .3s cubic-bezier(.25,.1,.25,1),box-shadow .3s cubic-bezier(.25,.1,.25,1);
}

.n4-aquarium .n4-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 32px -10px var(--accent);
}

.n4-aquarium .n4-cta:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.n4-aquarium .n4-stars,.n4-aquarium .n4-stars2 {
  position: absolute;
  inset: -4%;
  pointer-events: none;
}

.n4-aquarium .n4-stars {
  background-image: radial-gradient(1px 1px at 8% 12%,#fff 60%,transparent),radial-gradient(1px 1px at 22% 68%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 35% 24%,#fff 60%,transparent),radial-gradient(1px 1px at 48% 82%,#fff 60%,transparent),radial-gradient(1px 1px at 57% 9%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 66% 44%,#fff 60%,transparent),radial-gradient(1px 1px at 74% 72%,#fff 60%,transparent),radial-gradient(1px 1px at 86% 18%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 93% 58%,#fff 60%,transparent),radial-gradient(1px 1px at 14% 42%,#fff 60%,transparent),radial-gradient(1px 1px at 40% 55%,#fff 60%,transparent),radial-gradient(1px 1px at 81% 90%,#fff 60%,transparent),radial-gradient(1px 1px at 4% 88%,#fff 60%,transparent),radial-gradient(1px 1px at 62% 30%,#fff 60%,transparent);
  opacity: .75;
  animation: n4-aquarium-tw calc(5s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-stars2 {
  background-image: radial-gradient(2px 2px at 18% 30%,rgba(255,255,255,.9) 50%,transparent),radial-gradient(1.5px 1.5px at 72% 20%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 30% 85%,rgba(255,255,255,.7) 50%,transparent),radial-gradient(1.5px 1.5px at 88% 70%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 52% 60%,rgba(255,255,255,.6) 50%,transparent),radial-gradient(1.5px 1.5px at 6% 55%,rgba(255,255,255,.8) 50%,transparent);
  opacity: .55;
  animation: n4-aquarium-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
}

.n4-aquarium [data-depth] {
  transition: transform .9s cubic-bezier(.2,.7,.2,1);
}

@keyframes n4-aquarium-tw {
  from {
    opacity: .3;
  }
}

@keyframes n4-aquarium-spin {
  to {
    transform: rotate(1turn);
  }
}

@keyframes n4-aquarium-fade {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

@media (prefers-reduced-motion:reduce) {
  .n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
    animation: none!important;
    transition: none!important;
  }
}

.n4-aquarium {
  background: radial-gradient(80% 60% at 50% 28%,#0f4150,#03141a 75%);
  color: #e6f8fb;
}

.n4-aquarium .n4-tank {
  position: relative;
  overflow: hidden;
  width: min(68cqmin,470px);
  aspect-ratio: 16/9;
  font-size: min(2cqmin,14px);
  margin-bottom: 1.8cqmin;
  border-radius: 1em;
  background: linear-gradient(rgba(255,255,255,.22) 0 .8em,transparent .8em),linear-gradient(#45c4d8,#15829a 50%,#0a4f66);
  box-shadow: inset 0 0 0 .35em rgba(220,245,250,.35),0 0 0 .5em #0b2b36,0 2em 3em -1.5em rgba(0,0,0,.7);
  touch-action: none;
}

.n4-aquarium .n4-caus {
  position: absolute;
  inset: 0;
  background: repeating-radial-gradient(ellipse at 30% 20%,rgba(255,255,255,.09) 0 1em,transparent 1em 2.6em),repeating-radial-gradient(ellipse at 70% 10%,rgba(255,255,255,.07) 0 .8em,transparent .8em 2.2em);
  animation: n4-aquarium-caus calc(9s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-weed {
  position: absolute;
  left: 0;
  bottom: 8%;
  width: 100%;
  height: 56%;
}

.n4-aquarium .n4-weed path {
  fill: none;
  stroke: #2f9e62;
  stroke-width: 5;
  stroke-linecap: round;
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: n4-aquarium-sway calc(var(--d) / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-weed path:nth-child(2n) {
  stroke: #5cc27f;
  stroke-width: 4;
}

.n4-aquarium .n4-sand {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 14%;
  border-radius: 50% 50% 0 0/1.4em 1.4em 0 0;
  background: radial-gradient(circle,rgba(120,90,50,.35) 0 1px,transparent 1.5px) 0 0/.6em .6em,linear-gradient(#ead6a4,#cdb57d);
}

.n4-aquarium .n4-fish {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: calc(var(--s) * 4.6em);
  height: auto;
  translate: -50% -50%;
  scale: var(--f,1) 1;
  fill: var(--c);
  filter: drop-shadow(0 .3em .3em rgba(0,0,0,.2));
}

.n4-aquarium .n4-fish circle {
  fill: #111;
}

.n4-aquarium .n4-stripe {
  fill: none;
  stroke: rgba(255,255,255,.75);
  stroke-width: 2.5;
}

.n4-aquarium .n4-tail {
  transform-box: fill-box;
  transform-origin: 0 50%;
  animation: n4-aquarium-tail calc(.35s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-bub {
  position: absolute;
  bottom: 12%;
  left: var(--x);
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.7);
  background: radial-gradient(circle at 35% 30%,rgba(255,255,255,.85) 0 18%,transparent 24%);
  opacity: 0;
  animation: n4-aquarium-bub calc(var(--d) / var(--k)) linear var(--dl) infinite;
}

.n4-aquarium .n4-plate {
  position: absolute;
  z-index: 3;
  right: .9em;
  bottom: .7em;
  display: grid;
  gap: .15em;
  padding: .45em .75em;
  border-radius: .25em;
  text-align: left;
  background: linear-gradient(135deg,#f6dc8a,#b8862b 45%,#f1cf73 70%,#8a5e14);
  color: #2a1d05;
  box-shadow: 0 .2em .4em rgba(0,0,0,.4);
}

.n4-aquarium .n4-plate b {
  font: italic 600 1em/1 "Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif;
}

.n4-aquarium .n4-plate small {
  font: 700 .66em/1.1 "Helvetica Neue",Helvetica,Arial,system-ui,sans-serif;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.n4-aquarium .n4-title {
  font-size: clamp(20px,5cqmin,42px);
  font-weight: 700;
  letter-spacing: -.025em;
}

.n4-aquarium .n4-sub {
  color: #9fc4cd;
}

.n4-aquarium .n4-cta {
  background: var(--accent);
  color: #1d1400;
}

@keyframes n4-aquarium-caus {
  to {
    background-position: 3em 1em,-2em 2em;
  }
}

@keyframes n4-aquarium-sway {
  from {
    rotate: -6deg;
  }
  to {
    rotate: 6deg;
  }
}

@keyframes n4-aquarium-tail {
  to {
    scale: 1 .7;
  }
}

@keyframes n4-aquarium-bub {
  0% {
    transform: translate(0,0);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  50% {
    transform: translate(.6em,-7em);
  }
  90% {
    opacity: .9;
  }
  100% {
    transform: translate(-.3em,-14em);
    opacity: 0;
  }
}
```

### JavaScript

```js
document.querySelectorAll(".n4-aquarium").forEach((el) => {
  const tank = el.querySelector(".n4-tank");
  const fish = Array.from(el.querySelectorAll(".n4-fish"));
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const st = fish.map((f, i) => ({ x: 0.18 + i * 0.16, y: 0.24 + ((i * 37) % 46) / 100, vx: (i % 2 ? -1 : 1) * 0.0015, vy: 0, f: i % 2 ? 1 : -1 }));
  let mx = -1, my = -1, raf = 0, last = performance.now();
  const put = () => st.forEach((s, i) => {
    fish[i].style.setProperty("--x", (s.x * 100).toFixed(2) + "%");
    fish[i].style.setProperty("--y", (s.y * 100).toFixed(2) + "%");
    fish[i].style.setProperty("--f", String(s.f));
  });
  const loop = (t) => {
    const dt = Math.min(3, (t - last) / 16.67) * k;
    last = t;
    st.forEach((s) => {
      s.vx += (Math.random() - 0.5) * 0.00014 * dt;
      s.vy += (Math.random() - 0.5) * 0.00012 * dt;
      if (mx >= 0) {
        const dx = s.x - mx, dy = (s.y - my) * 0.56, d = Math.hypot(dx, dy);
        if (d < 0.22) { s.vx += (dx / (d + 0.01)) * 0.0012 * dt; s.vy += (dy / (d + 0.01)) * 0.0012 * dt; }
      }
      if (s.x < 0.1) s.vx += 0.00025 * dt;
      if (s.x > 0.9) s.vx -= 0.00025 * dt;
      if (s.y < 0.18) s.vy += 0.00025 * dt;
      if (s.y > 0.72) s.vy -= 0.00025 * dt;
      const sp = Math.hypot(s.vx, s.vy);
      if (sp > 0.012) { s.vx *= 0.012 / sp; s.vy *= 0.012 / sp; }
      if (Math.abs(s.vx) < 0.0012) s.vx += s.vx < 0 ? -0.0001 : 0.0001;
      s.vx *= 0.985;
      s.vy *= 0.97;
      s.x += s.vx * dt;
      s.y += s.vy * dt;
      if (Math.abs(s.vx) > 0.0005) s.f = s.vx > 0 ? -1 : 1;
    });
    put();
    raf = requestAnimationFrame(loop);
  };
  const point = (e) => {
    const r = tank.getBoundingClientRect();
    mx = (e.clientX - r.left) / r.width;
    my = (e.clientY - r.top) / r.height;
  };
  tank.addEventListener("pointermove", point);
  tank.addEventListener("pointerdown", point);
  tank.addEventListener("pointerleave", () => { mx = -1; });
  put();
  if (!rm) raf = requestAnimationFrame(loop);
});
```

### React

```tsx
// @ts-nocheck: setup() es JavaScript del DOM sin tipos.
import { useEffect, useRef, type CSSProperties } from "react";

const css = `
.n4-aquarium {
  --accent: #ffb703;
  --k: 1;
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  container-type: size;
  display: grid;
  place-items: center;
  background: #000;
  color: #f5f5f7;
  font-family: -apple-system,BlinkMacSystemFont,"SF Pro Display","Inter","Segoe UI",system-ui,sans-serif;
  -webkit-font-smoothing: antialiased;
  text-align: center;
  line-height: 1.4;
}

.n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
  box-sizing: border-box;
}

.n4-aquarium .n4-copy {
  position: relative;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.6cqmin;
  width: 100%;
  max-width: 680px;
  padding: 0 6cqw;
}

.n4-aquarium .n4-title {
  margin: 0;
  font-size: clamp(17px,4.2cqmin,36px);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.15;
  text-wrap: balance;
}

.n4-aquarium .n4-sub {
  margin: 0;
  max-width: 34em;
  font-size: clamp(13px,2.4cqmin,18px);
  color: #a1a1a6;
  text-wrap: balance;
}

.n4-aquarium .n4-tag {
  font: 600 clamp(10px,1.9cqmin,13px)/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}

.n4-aquarium .n4-cta {
  margin-top: 1.8cqmin;
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .85em 1.5em;
  border-radius: 999px;
  background: #f5f5f7;
  color: #000;
  font-size: clamp(13px,2.2cqmin,16px);
  font-weight: 600;
  text-decoration: none;
  transition: transform .3s cubic-bezier(.25,.1,.25,1),box-shadow .3s cubic-bezier(.25,.1,.25,1);
}

.n4-aquarium .n4-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 32px -10px var(--accent);
}

.n4-aquarium .n4-cta:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.n4-aquarium .n4-stars,.n4-aquarium .n4-stars2 {
  position: absolute;
  inset: -4%;
  pointer-events: none;
}

.n4-aquarium .n4-stars {
  background-image: radial-gradient(1px 1px at 8% 12%,#fff 60%,transparent),radial-gradient(1px 1px at 22% 68%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 35% 24%,#fff 60%,transparent),radial-gradient(1px 1px at 48% 82%,#fff 60%,transparent),radial-gradient(1px 1px at 57% 9%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 66% 44%,#fff 60%,transparent),radial-gradient(1px 1px at 74% 72%,#fff 60%,transparent),radial-gradient(1px 1px at 86% 18%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 93% 58%,#fff 60%,transparent),radial-gradient(1px 1px at 14% 42%,#fff 60%,transparent),radial-gradient(1px 1px at 40% 55%,#fff 60%,transparent),radial-gradient(1px 1px at 81% 90%,#fff 60%,transparent),radial-gradient(1px 1px at 4% 88%,#fff 60%,transparent),radial-gradient(1px 1px at 62% 30%,#fff 60%,transparent);
  opacity: .75;
  animation: n4-aquarium-tw calc(5s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-stars2 {
  background-image: radial-gradient(2px 2px at 18% 30%,rgba(255,255,255,.9) 50%,transparent),radial-gradient(1.5px 1.5px at 72% 20%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 30% 85%,rgba(255,255,255,.7) 50%,transparent),radial-gradient(1.5px 1.5px at 88% 70%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 52% 60%,rgba(255,255,255,.6) 50%,transparent),radial-gradient(1.5px 1.5px at 6% 55%,rgba(255,255,255,.8) 50%,transparent);
  opacity: .55;
  animation: n4-aquarium-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
}

.n4-aquarium [data-depth] {
  transition: transform .9s cubic-bezier(.2,.7,.2,1);
}

@keyframes n4-aquarium-tw {
  from {
    opacity: .3;
  }
}

@keyframes n4-aquarium-spin {
  to {
    transform: rotate(1turn);
  }
}

@keyframes n4-aquarium-fade {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

@media (prefers-reduced-motion:reduce) {
  .n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
    animation: none!important;
    transition: none!important;
  }
}

.n4-aquarium {
  background: radial-gradient(80% 60% at 50% 28%,#0f4150,#03141a 75%);
  color: #e6f8fb;
}

.n4-aquarium .n4-tank {
  position: relative;
  overflow: hidden;
  width: min(68cqmin,470px);
  aspect-ratio: 16/9;
  font-size: min(2cqmin,14px);
  margin-bottom: 1.8cqmin;
  border-radius: 1em;
  background: linear-gradient(rgba(255,255,255,.22) 0 .8em,transparent .8em),linear-gradient(#45c4d8,#15829a 50%,#0a4f66);
  box-shadow: inset 0 0 0 .35em rgba(220,245,250,.35),0 0 0 .5em #0b2b36,0 2em 3em -1.5em rgba(0,0,0,.7);
  touch-action: none;
}

.n4-aquarium .n4-caus {
  position: absolute;
  inset: 0;
  background: repeating-radial-gradient(ellipse at 30% 20%,rgba(255,255,255,.09) 0 1em,transparent 1em 2.6em),repeating-radial-gradient(ellipse at 70% 10%,rgba(255,255,255,.07) 0 .8em,transparent .8em 2.2em);
  animation: n4-aquarium-caus calc(9s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-weed {
  position: absolute;
  left: 0;
  bottom: 8%;
  width: 100%;
  height: 56%;
}

.n4-aquarium .n4-weed path {
  fill: none;
  stroke: #2f9e62;
  stroke-width: 5;
  stroke-linecap: round;
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: n4-aquarium-sway calc(var(--d) / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-weed path:nth-child(2n) {
  stroke: #5cc27f;
  stroke-width: 4;
}

.n4-aquarium .n4-sand {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 14%;
  border-radius: 50% 50% 0 0/1.4em 1.4em 0 0;
  background: radial-gradient(circle,rgba(120,90,50,.35) 0 1px,transparent 1.5px) 0 0/.6em .6em,linear-gradient(#ead6a4,#cdb57d);
}

.n4-aquarium .n4-fish {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: calc(var(--s) * 4.6em);
  height: auto;
  translate: -50% -50%;
  scale: var(--f,1) 1;
  fill: var(--c);
  filter: drop-shadow(0 .3em .3em rgba(0,0,0,.2));
}

.n4-aquarium .n4-fish circle {
  fill: #111;
}

.n4-aquarium .n4-stripe {
  fill: none;
  stroke: rgba(255,255,255,.75);
  stroke-width: 2.5;
}

.n4-aquarium .n4-tail {
  transform-box: fill-box;
  transform-origin: 0 50%;
  animation: n4-aquarium-tail calc(.35s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-bub {
  position: absolute;
  bottom: 12%;
  left: var(--x);
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.7);
  background: radial-gradient(circle at 35% 30%,rgba(255,255,255,.85) 0 18%,transparent 24%);
  opacity: 0;
  animation: n4-aquarium-bub calc(var(--d) / var(--k)) linear var(--dl) infinite;
}

.n4-aquarium .n4-plate {
  position: absolute;
  z-index: 3;
  right: .9em;
  bottom: .7em;
  display: grid;
  gap: .15em;
  padding: .45em .75em;
  border-radius: .25em;
  text-align: left;
  background: linear-gradient(135deg,#f6dc8a,#b8862b 45%,#f1cf73 70%,#8a5e14);
  color: #2a1d05;
  box-shadow: 0 .2em .4em rgba(0,0,0,.4);
}

.n4-aquarium .n4-plate b {
  font: italic 600 1em/1 "Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif;
}

.n4-aquarium .n4-plate small {
  font: 700 .66em/1.1 "Helvetica Neue",Helvetica,Arial,system-ui,sans-serif;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.n4-aquarium .n4-title {
  font-size: clamp(20px,5cqmin,42px);
  font-weight: 700;
  letter-spacing: -.025em;
}

.n4-aquarium .n4-sub {
  color: #9fc4cd;
}

.n4-aquarium .n4-cta {
  background: var(--accent);
  color: #1d1400;
}

@keyframes n4-aquarium-caus {
  to {
    background-position: 3em 1em,-2em 2em;
  }
}

@keyframes n4-aquarium-sway {
  from {
    rotate: -6deg;
  }
  to {
    rotate: 6deg;
  }
}

@keyframes n4-aquarium-tail {
  to {
    scale: 1 .7;
  }
}

@keyframes n4-aquarium-bub {
  0% {
    transform: translate(0,0);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  50% {
    transform: translate(.6em,-7em);
  }
  90% {
    opacity: .9;
  }
  100% {
    transform: translate(-.3em,-14em);
    opacity: 0;
  }
}
`;

// Parallax con el puntero: JavaScript del DOM, el mismo de la pestaña JS.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setup(el: any) {
  const tank = el.querySelector(".n4-tank");
  const fish = Array.from(el.querySelectorAll(".n4-fish"));
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const st = fish.map((f, i) => ({ x: 0.18 + i * 0.16, y: 0.24 + ((i * 37) % 46) / 100, vx: (i % 2 ? -1 : 1) * 0.0015, vy: 0, f: i % 2 ? 1 : -1 }));
  let mx = -1, my = -1, raf = 0, last = performance.now();
  const put = () => st.forEach((s, i) => {
    fish[i].style.setProperty("--x", (s.x * 100).toFixed(2) + "%");
    fish[i].style.setProperty("--y", (s.y * 100).toFixed(2) + "%");
    fish[i].style.setProperty("--f", String(s.f));
  });
  const loop = (t) => {
    const dt = Math.min(3, (t - last) / 16.67) * k;
    last = t;
    st.forEach((s) => {
      s.vx += (Math.random() - 0.5) * 0.00014 * dt;
      s.vy += (Math.random() - 0.5) * 0.00012 * dt;
      if (mx >= 0) {
        const dx = s.x - mx, dy = (s.y - my) * 0.56, d = Math.hypot(dx, dy);
        if (d < 0.22) { s.vx += (dx / (d + 0.01)) * 0.0012 * dt; s.vy += (dy / (d + 0.01)) * 0.0012 * dt; }
      }
      if (s.x < 0.1) s.vx += 0.00025 * dt;
      if (s.x > 0.9) s.vx -= 0.00025 * dt;
      if (s.y < 0.18) s.vy += 0.00025 * dt;
      if (s.y > 0.72) s.vy -= 0.00025 * dt;
      const sp = Math.hypot(s.vx, s.vy);
      if (sp > 0.012) { s.vx *= 0.012 / sp; s.vy *= 0.012 / sp; }
      if (Math.abs(s.vx) < 0.0012) s.vx += s.vx < 0 ? -0.0001 : 0.0001;
      s.vx *= 0.985;
      s.vy *= 0.97;
      s.x += s.vx * dt;
      s.y += s.vy * dt;
      if (Math.abs(s.vx) > 0.0005) s.f = s.vx > 0 ? -1 : 1;
    });
    put();
    raf = requestAnimationFrame(loop);
  };
  const point = (e) => {
    const r = tank.getBoundingClientRect();
    mx = (e.clientX - r.left) / r.width;
    my = (e.clientY - r.top) / r.height;
  };
  tank.addEventListener("pointermove", point);
  tank.addEventListener("pointerdown", point);
  tank.addEventListener("pointerleave", () => { mx = -1; });
  put();
  if (!rm) raf = requestAnimationFrame(loop);
  return () => cancelAnimationFrame(raf);
}

export default function NotFoundAquarium() {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const el = ref.current?.firstElementChild;
    return el ? setup(el) : undefined;
  }, []);

  return (
    <>
      <style>{css}</style>
      <div ref={ref}>
        <main className="n4-aquarium">
          <div className="n4-copy">
            <div className="n4-tank" aria-hidden="true">
              <i className="n4-caus"></i>
              <svg className="n4-weed" viewBox="0 0 300 120" preserveAspectRatio="none"><path style={{ "--d": "4.2s" } as CSSProperties} d="M18 120C10 96 28 80 18 56S26 24 20 6" /><path style={{ "--d": "5.4s" } as CSSProperties} d="M34 120C40 100 28 86 36 66S30 40 34 30" /><path style={{ "--d": "4.8s" } as CSSProperties} d="M252 120C246 98 262 82 254 60S262 30 256 14" /><path style={{ "--d": "6s" } as CSSProperties} d="M270 120C278 102 266 90 272 72S266 50 270 40" /><path style={{ "--d": "5s" } as CSSProperties} d="M286 120C280 104 292 94 286 80" /></svg>
              <i className="n4-sand"></i>
              <svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#ffb703", "--s": "1", "--x": "18%", "--y": "24%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#fb8500", "--s": "0.8", "--x": "34%", "--y": "61%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#8ecae6", "--s": "0.7", "--x": "50%", "--y": "52%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#ff5d8f", "--s": "0.9", "--x": "66%", "--y": "43%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#b8f2e6", "--s": "0.6", "--x": "82%", "--y": "34%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg>
              <i className="n4-bub" style={{ "--x": "10%", "--d": "5.5s", "--dl": "0s", "--s": "0.5em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "14%", "--d": "6.5s", "--dl": "-2s", "--s": "0.35em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "84%", "--d": "5s", "--dl": "-1s", "--s": "0.45em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "88%", "--d": "7s", "--dl": "-4s", "--s": "0.3em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "60%", "--d": "6s", "--dl": "-3s", "--s": "0.4em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "40%", "--d": "7.5s", "--dl": "-5s", "--s": "0.3em" } as CSSProperties}></i>
              <span className="n4-plate"><b translate="no">Pagina absens</b><small>Species not found · 404</small></span>
            </div>
            <h1 className="n4-title">This species doesn't live in our aquarium.</h1>
            <p className="n4-sub">We've looked behind every rock and the page is nowhere to be seen. Carry on through the other tanks or go back to the entrance.</p>
            <a className="n4-cta" href="/">Back to the entrance</a>
          </div>
        </main>
      </div>
    </>
  );
}
```

## Prompt for AI assistants

Paste this into ChatGPT, Claude, Cursor, v0 or Lovable to adapt the block to your stack (Tailwind, Vue, Svelte…):

````text
I want to add the “Aquarium 404” block (404) from AIMRAN Library to my project.

## What it is
An aquarium with fish that swim on their own and dart away from the pointer; the brass plate says species 404 is missing.

## Chosen settings
- Accent color: #ffb703
- Speed: 1x (from 0.5 to 2x)
- Title: "Esta especie no vive en nuestro acuario."
- Message: "Hemos mirado detrás de cada roca y la página no aparece. Sigue el recorrido por los demás tanques o vuelve a la entrada."
- Button: "Volver a la entrada"

## What I need
1. Add it to my project with the same look and animation as the reference code: same sizes, colours, radii, shadows, timings and easing.
2. It is built with plain HTML and CSS (the reference wraps it in a React component with its CSS). If my project uses something else (Vue, Svelte, Astro, plain HTML…), translate it without losing any behaviour. If I use Tailwind, turn the styles into classes; if not, keep the CSS in its own file.
3. Expose the settings above as props (or CSS variables) with those values as defaults.
4. Make it work well on phones: nothing that depends only on hover, touch targets of at least 44 px and no overflow on 320 px screens.
5. Make it look right in light and dark mode.
6. Keep it accessible: semantic HTML, roles and aria-* where needed, visible focus and keyboard support.
7. Respect prefers-reduced-motion: with reduced motion, no big animations but the same end result.

## Reference code
```tsx
// @ts-nocheck: setup() es JavaScript del DOM sin tipos.
import { useEffect, useRef, type CSSProperties } from "react";

const css = `
.n4-aquarium {
  --accent: #ffb703;
  --k: 1;
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  container-type: size;
  display: grid;
  place-items: center;
  background: #000;
  color: #f5f5f7;
  font-family: -apple-system,BlinkMacSystemFont,"SF Pro Display","Inter","Segoe UI",system-ui,sans-serif;
  -webkit-font-smoothing: antialiased;
  text-align: center;
  line-height: 1.4;
}

.n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
  box-sizing: border-box;
}

.n4-aquarium .n4-copy {
  position: relative;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.6cqmin;
  width: 100%;
  max-width: 680px;
  padding: 0 6cqw;
}

.n4-aquarium .n4-title {
  margin: 0;
  font-size: clamp(17px,4.2cqmin,36px);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.15;
  text-wrap: balance;
}

.n4-aquarium .n4-sub {
  margin: 0;
  max-width: 34em;
  font-size: clamp(13px,2.4cqmin,18px);
  color: #a1a1a6;
  text-wrap: balance;
}

.n4-aquarium .n4-tag {
  font: 600 clamp(10px,1.9cqmin,13px)/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}

.n4-aquarium .n4-cta {
  margin-top: 1.8cqmin;
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .85em 1.5em;
  border-radius: 999px;
  background: #f5f5f7;
  color: #000;
  font-size: clamp(13px,2.2cqmin,16px);
  font-weight: 600;
  text-decoration: none;
  transition: transform .3s cubic-bezier(.25,.1,.25,1),box-shadow .3s cubic-bezier(.25,.1,.25,1);
}

.n4-aquarium .n4-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 32px -10px var(--accent);
}

.n4-aquarium .n4-cta:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.n4-aquarium .n4-stars,.n4-aquarium .n4-stars2 {
  position: absolute;
  inset: -4%;
  pointer-events: none;
}

.n4-aquarium .n4-stars {
  background-image: radial-gradient(1px 1px at 8% 12%,#fff 60%,transparent),radial-gradient(1px 1px at 22% 68%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 35% 24%,#fff 60%,transparent),radial-gradient(1px 1px at 48% 82%,#fff 60%,transparent),radial-gradient(1px 1px at 57% 9%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 66% 44%,#fff 60%,transparent),radial-gradient(1px 1px at 74% 72%,#fff 60%,transparent),radial-gradient(1px 1px at 86% 18%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 93% 58%,#fff 60%,transparent),radial-gradient(1px 1px at 14% 42%,#fff 60%,transparent),radial-gradient(1px 1px at 40% 55%,#fff 60%,transparent),radial-gradient(1px 1px at 81% 90%,#fff 60%,transparent),radial-gradient(1px 1px at 4% 88%,#fff 60%,transparent),radial-gradient(1px 1px at 62% 30%,#fff 60%,transparent);
  opacity: .75;
  animation: n4-aquarium-tw calc(5s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-stars2 {
  background-image: radial-gradient(2px 2px at 18% 30%,rgba(255,255,255,.9) 50%,transparent),radial-gradient(1.5px 1.5px at 72% 20%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 30% 85%,rgba(255,255,255,.7) 50%,transparent),radial-gradient(1.5px 1.5px at 88% 70%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 52% 60%,rgba(255,255,255,.6) 50%,transparent),radial-gradient(1.5px 1.5px at 6% 55%,rgba(255,255,255,.8) 50%,transparent);
  opacity: .55;
  animation: n4-aquarium-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
}

.n4-aquarium [data-depth] {
  transition: transform .9s cubic-bezier(.2,.7,.2,1);
}

@keyframes n4-aquarium-tw {
  from {
    opacity: .3;
  }
}

@keyframes n4-aquarium-spin {
  to {
    transform: rotate(1turn);
  }
}

@keyframes n4-aquarium-fade {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

@media (prefers-reduced-motion:reduce) {
  .n4-aquarium *,.n4-aquarium *::before,.n4-aquarium *::after {
    animation: none!important;
    transition: none!important;
  }
}

.n4-aquarium {
  background: radial-gradient(80% 60% at 50% 28%,#0f4150,#03141a 75%);
  color: #e6f8fb;
}

.n4-aquarium .n4-tank {
  position: relative;
  overflow: hidden;
  width: min(68cqmin,470px);
  aspect-ratio: 16/9;
  font-size: min(2cqmin,14px);
  margin-bottom: 1.8cqmin;
  border-radius: 1em;
  background: linear-gradient(rgba(255,255,255,.22) 0 .8em,transparent .8em),linear-gradient(#45c4d8,#15829a 50%,#0a4f66);
  box-shadow: inset 0 0 0 .35em rgba(220,245,250,.35),0 0 0 .5em #0b2b36,0 2em 3em -1.5em rgba(0,0,0,.7);
  touch-action: none;
}

.n4-aquarium .n4-caus {
  position: absolute;
  inset: 0;
  background: repeating-radial-gradient(ellipse at 30% 20%,rgba(255,255,255,.09) 0 1em,transparent 1em 2.6em),repeating-radial-gradient(ellipse at 70% 10%,rgba(255,255,255,.07) 0 .8em,transparent .8em 2.2em);
  animation: n4-aquarium-caus calc(9s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-weed {
  position: absolute;
  left: 0;
  bottom: 8%;
  width: 100%;
  height: 56%;
}

.n4-aquarium .n4-weed path {
  fill: none;
  stroke: #2f9e62;
  stroke-width: 5;
  stroke-linecap: round;
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: n4-aquarium-sway calc(var(--d) / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-weed path:nth-child(2n) {
  stroke: #5cc27f;
  stroke-width: 4;
}

.n4-aquarium .n4-sand {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 14%;
  border-radius: 50% 50% 0 0/1.4em 1.4em 0 0;
  background: radial-gradient(circle,rgba(120,90,50,.35) 0 1px,transparent 1.5px) 0 0/.6em .6em,linear-gradient(#ead6a4,#cdb57d);
}

.n4-aquarium .n4-fish {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: calc(var(--s) * 4.6em);
  height: auto;
  translate: -50% -50%;
  scale: var(--f,1) 1;
  fill: var(--c);
  filter: drop-shadow(0 .3em .3em rgba(0,0,0,.2));
}

.n4-aquarium .n4-fish circle {
  fill: #111;
}

.n4-aquarium .n4-stripe {
  fill: none;
  stroke: rgba(255,255,255,.75);
  stroke-width: 2.5;
}

.n4-aquarium .n4-tail {
  transform-box: fill-box;
  transform-origin: 0 50%;
  animation: n4-aquarium-tail calc(.35s / var(--k)) ease-in-out infinite alternate;
}

.n4-aquarium .n4-bub {
  position: absolute;
  bottom: 12%;
  left: var(--x);
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.7);
  background: radial-gradient(circle at 35% 30%,rgba(255,255,255,.85) 0 18%,transparent 24%);
  opacity: 0;
  animation: n4-aquarium-bub calc(var(--d) / var(--k)) linear var(--dl) infinite;
}

.n4-aquarium .n4-plate {
  position: absolute;
  z-index: 3;
  right: .9em;
  bottom: .7em;
  display: grid;
  gap: .15em;
  padding: .45em .75em;
  border-radius: .25em;
  text-align: left;
  background: linear-gradient(135deg,#f6dc8a,#b8862b 45%,#f1cf73 70%,#8a5e14);
  color: #2a1d05;
  box-shadow: 0 .2em .4em rgba(0,0,0,.4);
}

.n4-aquarium .n4-plate b {
  font: italic 600 1em/1 "Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif;
}

.n4-aquarium .n4-plate small {
  font: 700 .66em/1.1 "Helvetica Neue",Helvetica,Arial,system-ui,sans-serif;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.n4-aquarium .n4-title {
  font-size: clamp(20px,5cqmin,42px);
  font-weight: 700;
  letter-spacing: -.025em;
}

.n4-aquarium .n4-sub {
  color: #9fc4cd;
}

.n4-aquarium .n4-cta {
  background: var(--accent);
  color: #1d1400;
}

@keyframes n4-aquarium-caus {
  to {
    background-position: 3em 1em,-2em 2em;
  }
}

@keyframes n4-aquarium-sway {
  from {
    rotate: -6deg;
  }
  to {
    rotate: 6deg;
  }
}

@keyframes n4-aquarium-tail {
  to {
    scale: 1 .7;
  }
}

@keyframes n4-aquarium-bub {
  0% {
    transform: translate(0,0);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  50% {
    transform: translate(.6em,-7em);
  }
  90% {
    opacity: .9;
  }
  100% {
    transform: translate(-.3em,-14em);
    opacity: 0;
  }
}
`;

// Parallax con el puntero: JavaScript del DOM, el mismo de la pestaña JS.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setup(el: any) {
  const tank = el.querySelector(".n4-tank");
  const fish = Array.from(el.querySelectorAll(".n4-fish"));
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const st = fish.map((f, i) => ({ x: 0.18 + i * 0.16, y: 0.24 + ((i * 37) % 46) / 100, vx: (i % 2 ? -1 : 1) * 0.0015, vy: 0, f: i % 2 ? 1 : -1 }));
  let mx = -1, my = -1, raf = 0, last = performance.now();
  const put = () => st.forEach((s, i) => {
    fish[i].style.setProperty("--x", (s.x * 100).toFixed(2) + "%");
    fish[i].style.setProperty("--y", (s.y * 100).toFixed(2) + "%");
    fish[i].style.setProperty("--f", String(s.f));
  });
  const loop = (t) => {
    const dt = Math.min(3, (t - last) / 16.67) * k;
    last = t;
    st.forEach((s) => {
      s.vx += (Math.random() - 0.5) * 0.00014 * dt;
      s.vy += (Math.random() - 0.5) * 0.00012 * dt;
      if (mx >= 0) {
        const dx = s.x - mx, dy = (s.y - my) * 0.56, d = Math.hypot(dx, dy);
        if (d < 0.22) { s.vx += (dx / (d + 0.01)) * 0.0012 * dt; s.vy += (dy / (d + 0.01)) * 0.0012 * dt; }
      }
      if (s.x < 0.1) s.vx += 0.00025 * dt;
      if (s.x > 0.9) s.vx -= 0.00025 * dt;
      if (s.y < 0.18) s.vy += 0.00025 * dt;
      if (s.y > 0.72) s.vy -= 0.00025 * dt;
      const sp = Math.hypot(s.vx, s.vy);
      if (sp > 0.012) { s.vx *= 0.012 / sp; s.vy *= 0.012 / sp; }
      if (Math.abs(s.vx) < 0.0012) s.vx += s.vx < 0 ? -0.0001 : 0.0001;
      s.vx *= 0.985;
      s.vy *= 0.97;
      s.x += s.vx * dt;
      s.y += s.vy * dt;
      if (Math.abs(s.vx) > 0.0005) s.f = s.vx > 0 ? -1 : 1;
    });
    put();
    raf = requestAnimationFrame(loop);
  };
  const point = (e) => {
    const r = tank.getBoundingClientRect();
    mx = (e.clientX - r.left) / r.width;
    my = (e.clientY - r.top) / r.height;
  };
  tank.addEventListener("pointermove", point);
  tank.addEventListener("pointerdown", point);
  tank.addEventListener("pointerleave", () => { mx = -1; });
  put();
  if (!rm) raf = requestAnimationFrame(loop);
  return () => cancelAnimationFrame(raf);
}

export default function NotFoundAquarium() {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const el = ref.current?.firstElementChild;
    return el ? setup(el) : undefined;
  }, []);

  return (
    <>
      <style>{css}</style>
      <div ref={ref}>
        <main className="n4-aquarium">
          <div className="n4-copy">
            <div className="n4-tank" aria-hidden="true">
              <i className="n4-caus"></i>
              <svg className="n4-weed" viewBox="0 0 300 120" preserveAspectRatio="none"><path style={{ "--d": "4.2s" } as CSSProperties} d="M18 120C10 96 28 80 18 56S26 24 20 6" /><path style={{ "--d": "5.4s" } as CSSProperties} d="M34 120C40 100 28 86 36 66S30 40 34 30" /><path style={{ "--d": "4.8s" } as CSSProperties} d="M252 120C246 98 262 82 254 60S262 30 256 14" /><path style={{ "--d": "6s" } as CSSProperties} d="M270 120C278 102 266 90 272 72S266 50 270 40" /><path style={{ "--d": "5s" } as CSSProperties} d="M286 120C280 104 292 94 286 80" /></svg>
              <i className="n4-sand"></i>
              <svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#ffb703", "--s": "1", "--x": "18%", "--y": "24%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#fb8500", "--s": "0.8", "--x": "34%", "--y": "61%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#8ecae6", "--s": "0.7", "--x": "50%", "--y": "52%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#ff5d8f", "--s": "0.9", "--x": "66%", "--y": "43%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg><svg className="n4-fish" viewBox="0 0 44 26" style={{ "--c": "#b8f2e6", "--s": "0.6", "--x": "82%", "--y": "34%" } as CSSProperties}><path className="n4-tail" d="M32 13L44 4l-3 9 3 9z" /><path d="M6 13C12 3 28 2 34 13 28 24 12 23 6 13z" /><path d="M18 6l6-5 2 7z" /><path className="n4-stripe" d="M21 5v16" /><circle cx="12" cy="11" r="1.8" /></svg>
              <i className="n4-bub" style={{ "--x": "10%", "--d": "5.5s", "--dl": "0s", "--s": "0.5em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "14%", "--d": "6.5s", "--dl": "-2s", "--s": "0.35em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "84%", "--d": "5s", "--dl": "-1s", "--s": "0.45em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "88%", "--d": "7s", "--dl": "-4s", "--s": "0.3em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "60%", "--d": "6s", "--dl": "-3s", "--s": "0.4em" } as CSSProperties}></i><i className="n4-bub" style={{ "--x": "40%", "--d": "7.5s", "--dl": "-5s", "--s": "0.3em" } as CSSProperties}></i>
              <span className="n4-plate"><b translate="no">Pagina absens</b><small>Species not found · 404</small></span>
            </div>
            <h1 className="n4-title">This species doesn't live in our aquarium.</h1>
            <p className="n4-sub">We've looked behind every rock and the page is nowhere to be seen. Carry on through the other tanks or go back to the entrance.</p>
            <a className="n4-cta" href="/">Back to the entrance</a>
          </div>
        </main>
      </div>
    </>
  );
}
```

Give me the complete final code, ready to paste, and tell me in one line where to put it in my project.
````
