# Vintage radio 404

> A wooden radio with an FM scale, a magic eye and static: drag the dial, and on 100.4 only the 404 noise plays.

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

## Where to use it

This error page is a walnut tabletop radio with a cloth speaker grille, a green magic eye tuning tube and a backlit FM scale. On load the red needle sweeps up the band; drag the scale or use the arrow keys to tune, and the eye opens as you approach a station while the static fades.

Most stations play and the grille gently pulses, but 404 FM on 100.4 has a perfect signal and nothing on air. The scale is an accessible slider that reads the frequency aloud. Adjust the amber accent and the speed.

## 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-radio {
        --accent: #ffb347;
        --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-radio *,.n4-radio *::before,.n4-radio *::after {
        box-sizing: border-box;
      }
      
      .n4-radio .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-radio .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-radio .n4-sub {
        margin: 0;
        max-width: 34em;
        font-size: clamp(13px,2.4cqmin,18px);
        color: #a1a1a6;
        text-wrap: balance;
      }
      
      .n4-radio .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-radio .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-radio .n4-cta:hover {
        transform: translateY(-2px);
        box-shadow: 0 12px 32px -10px var(--accent);
      }
      
      .n4-radio .n4-cta:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 3px;
      }
      
      .n4-radio .n4-stars,.n4-radio .n4-stars2 {
        position: absolute;
        inset: -4%;
        pointer-events: none;
      }
      
      .n4-radio .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-radio-tw calc(5s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-radio .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-radio-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
      }
      
      .n4-radio [data-depth] {
        transition: transform .9s cubic-bezier(.2,.7,.2,1);
      }
      
      @keyframes n4-radio-tw {
        from {
          opacity: .3;
        }
      }
      
      @keyframes n4-radio-spin {
        to {
          transform: rotate(1turn);
        }
      }
      
      @keyframes n4-radio-fade {
        from {
          opacity: 0;
          transform: translateY(10px);
        }
      }
      
      @media (prefers-reduced-motion:reduce) {
        .n4-radio *,.n4-radio *::before,.n4-radio *::after {
          animation: none!important;
          transition: none!important;
        }
      }
      
      .n4-radio {
        background: radial-gradient(70% 60% at 50% 30%,#3d2b1d,#140d08 75%);
        color: #f7ead2;
      }
      
      .n4-radio .n4-set {
        --v: 0;
        --sig: 0;
        --noise: 1;
        width: min(64cqmin,450px);
        font-size: min(2cqmin,14px);
        margin-bottom: 1.6cqmin;
        padding: 1.5em 1.6em 1.1em;
        border-radius: 5em 5em 1.2em 1.2em/3.4em 3.4em 1.2em 1.2em;
        background: repeating-linear-gradient(93deg,rgba(0,0,0,.07) 0 .25em,transparent .25em .9em,rgba(255,220,180,.04) .9em 1.2em,transparent 1.2em 2em),linear-gradient(160deg,#8f4f25,#5a2d12 60%,#3b1d0a);
        box-shadow: inset 0 .25em .3em rgba(255,255,255,.2),inset 0 -.5em .8em rgba(0,0,0,.45),0 2em 3em -1.4em #000;
      }
      
      .n4-radio .n4-top {
        display: flex;
        gap: 1.2em;
        height: 8.5em;
      }
      
      .n4-radio .n4-grille {
        position: relative;
        flex: 1;
        overflow: hidden;
        border-radius: 2.6em 2.6em .6em .6em;
        background: repeating-linear-gradient(90deg,transparent 0 1.6em,#4a240d 1.6em 2em),repeating-linear-gradient(45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),repeating-linear-gradient(-45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),#cdb68a;
        box-shadow: inset 0 0 0 .3em #3b1d0a,inset 0 0 1.4em rgba(0,0,0,.5);
      }
      
      .n4-radio .n4-on .n4-grille {
        animation: n4-radio-thump calc(.45s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-radio .n4-static {
        position: absolute;
        inset: -10px;
        opacity: var(--noise);
        background: repeating-radial-gradient(circle at 27% 38%,rgba(255,255,255,.55) 0 1px,transparent 1px 3px),repeating-radial-gradient(circle at 71% 63%,rgba(0,0,0,.45) 0 1px,transparent 1px 4px);
        animation: n4-radio-noise calc(.18s / var(--k)) steps(3) infinite;
      }
      
      .n4-radio .n4-side {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: space-between;
        width: 5.4em;
      }
      
      .n4-radio .n4-eye {
        width: 3.6em;
        height: 3.6em;
        border-radius: 50%;
        background: radial-gradient(circle,#0b1a10 0 22%,transparent 23%),conic-gradient(from calc(180deg - var(--uvq17-w)),#0b1a10 0 calc(var(--uvq17-w) * 2),#6dff8a 0);
        --uvq17-w: calc((1 - var(--sig)) * 70deg + 4deg);
        box-shadow: 0 0 0 .35em #2a160a,0 0 0 .5em #b78a4a,0 0 1.2em rgba(109,255,138,calc(var(--sig) * .7));
        transition: --uvq17-w .2s;
      }
      
      .n4-radio .n4-knob {
        width: 2.6em;
        height: 2.6em;
        border-radius: 50%;
        background: repeating-conic-gradient(#e9d8b4 0 8deg,#b99b66 8deg 16deg);
        box-shadow: inset 0 0 0 .5em #f3e6c8,0 .2em .3em rgba(0,0,0,.5);
        rotate: calc(var(--v) * 3.6deg);
      }
      
      .n4-radio .n4-k2 {
        rotate: calc(var(--v) * -1.2deg);
      }
      
      .n4-radio .n4-scale {
        position: relative;
        height: 3.2em;
        margin-top: 1.1em;
        border-radius: .5em;
        cursor: ew-resize;
        touch-action: none;
        background: linear-gradient(#f6e7bf,#e2c98d);
        box-shadow: inset 0 0 0 .2em #3b1d0a,inset 0 0 1.6em rgba(255,170,60,.55);
      }
      
      .n4-radio .n4-scale:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 3px;
      }
      
      .n4-radio .n4-track {
        position: absolute;
        inset: 0 6%;
        background: repeating-linear-gradient(90deg,#3b1d0a 0 1px,transparent 1px 2%) 0 100%/100% 28% no-repeat;
      }
      
      .n4-radio .n4-nums b {
        position: absolute;
        top: .35em;
        left: calc(var(--p) * 1%);
        translate: -50% 0;
        font: 700 .95em/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        color: #3b1d0a;
      }
      
      .n4-radio .n4-needle {
        position: absolute;
        top: .25em;
        bottom: .25em;
        left: calc(var(--v) * 1%);
        width: .2em;
        margin-left: -.1em;
        border-radius: .1em;
        background: #d7261e;
        box-shadow: 0 0 .4em rgba(215,38,30,.6);
      }
      
      .n4-radio .n4-station {
        min-height: 1.3em;
        margin: .7em 0 0;
        font: 600 1em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        letter-spacing: .04em;
        color: #f6e7bf;
      }
      
      .n4-radio .n4-tag {
        color: var(--accent);
      }
      
      .n4-radio .n4-title {
        font-size: clamp(20px,5cqmin,42px);
        font-weight: 700;
        letter-spacing: -.025em;
      }
      
      .n4-radio .n4-sub {
        color: #cdb79b;
      }
      
      .n4-radio .n4-cta {
        background: var(--accent);
        color: #2a1406;
      }
      
      @property --uvq17-w {
        syntax: "<angle>";
        inherits: true;
        initial-value: 74deg;
      }
      
      @keyframes n4-radio-noise {
        33% {
          background-position: 3px 1px,-2px 3px;
        }
        66% {
          background-position: -1px -3px,2px -1px;
        }
      }
      
      @keyframes n4-radio-thump {
        to {
          transform: scale(1.012);
        }
      }
    </style>
  </head>
  <body>
    <main class="n4-radio">
      <div class="n4-copy">
        <div class="n4-set">
          <div class="n4-top" aria-hidden="true">
            <div class="n4-grille"><i class="n4-static"></i></div>
            <div class="n4-side"><i class="n4-eye"></i><i class="n4-knob"></i><i class="n4-knob n4-k2"></i></div>
          </div>
          <div class="n4-scale" role="slider" tabindex="0" aria-label="Tuning dial" aria-valuemin="880" aria-valuemax="1080" aria-valuenow="880" aria-valuetext="88,0 MHz">
            <div class="n4-track"><span class="n4-nums" aria-hidden="true" translate="no"><b style="--p:0">88</b><b style="--p:20">92</b><b style="--p:40">96</b><b style="--p:60">100</b><b style="--p:80">104</b><b style="--p:100">108</b></span><i class="n4-needle" aria-hidden="true"></i></div>
          </div>
          <p class="n4-station" aria-live="polite">Searching for a station…</p>
        </div>
        <span class="n4-tag">Frequency 100.4 MHz</span>
        <h1 class="n4-title">Nobody broadcasts on this frequency.</h1>
        <p class="n4-sub">The page you're looking for has lost its signal. Turn the dial or go back home, there's always something on there.</p>
        <a class="n4-cta" href="/">Back to home</a>
      </div>
    </main>
    <script>
      document.querySelectorAll(".n4-radio").forEach((el) => {
        const set = el.querySelector(".n4-set");
        const scale = el.querySelector(".n4-scale");
        const track = el.querySelector(".n4-track");
        const label = el.querySelector(".n4-station");
        const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
        const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
        const ST = [[914, "Onda Jazz"], [965, "24 hour news"], [1004, "404 FM: broadcast not found"], [1052, "Late night boleros"]];
        const SEARCH = "Searching for a station…";
        let v = 880, shown = SEARCH, raf = 0;
        const render = () => {
          let best = 0, name = SEARCH, lost = false;
          for (const [f, n] of ST) {
            const s = Math.max(0, 1 - Math.abs(v - f) / 10);
            if (s > best) { best = s; if (s > 0.55) { name = n; lost = f === 1004; } }
          }
          set.style.setProperty("--v", ((v - 880) / 2).toFixed(2));
          set.style.setProperty("--sig", best.toFixed(2));
          set.style.setProperty("--noise", (lost ? 0.75 : 1 - best * 0.9).toFixed(2));
          set.classList.toggle("n4-on", best > 0.55 && !lost);
          scale.setAttribute("aria-valuenow", String(v));
          scale.setAttribute("aria-valuetext", (v / 10).toFixed(1).replace(".", ",") + " MHz");
          if (name !== shown) { shown = name; label.textContent = name; }
        };
        const tune = (n) => { cancelAnimationFrame(raf); v = Math.max(880, Math.min(1080, Math.round(n))); render(); };
        const fromX = (e) => { const r = track.getBoundingClientRect(); tune(880 + ((e.clientX - r.left) / r.width) * 200); };
        let down = false;
        scale.addEventListener("pointerdown", (e) => { down = true; scale.setPointerCapture(e.pointerId); fromX(e); });
        scale.addEventListener("pointermove", (e) => { if (down) fromX(e); });
        scale.addEventListener("pointerup", () => { down = false; });
        scale.addEventListener("pointercancel", () => { down = false; });
        scale.addEventListener("keydown", (e) => {
          const d = { ArrowRight: 1, ArrowUp: 1, ArrowLeft: -1, ArrowDown: -1, PageUp: 10, PageDown: -10 }[e.key];
          if (d) { e.preventDefault(); tune(v + d); }
          else if (e.key === "Home") { e.preventDefault(); tune(880); }
          else if (e.key === "End") { e.preventDefault(); tune(1080); }
        });
        const t0 = performance.now();
        const sweep = (t) => {
          const p = Math.min(1, (t - t0) / (2400 / k));
          v = Math.round(880 + 124 * (1 - Math.pow(1 - p, 3)));
          render();
          if (p < 1) raf = requestAnimationFrame(sweep);
        };
        if (rm) { v = 1004; render(); } else raf = requestAnimationFrame(sweep);
      });
    </script>
  </body>
</html>
```

### CSS

```css
.n4-radio {
  --accent: #ffb347;
  --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-radio *,.n4-radio *::before,.n4-radio *::after {
  box-sizing: border-box;
}

.n4-radio .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-radio .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-radio .n4-sub {
  margin: 0;
  max-width: 34em;
  font-size: clamp(13px,2.4cqmin,18px);
  color: #a1a1a6;
  text-wrap: balance;
}

.n4-radio .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-radio .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-radio .n4-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 32px -10px var(--accent);
}

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

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

.n4-radio .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-radio-tw calc(5s / var(--k)) ease-in-out infinite alternate;
}

.n4-radio .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-radio-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
}

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

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

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

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

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

.n4-radio {
  background: radial-gradient(70% 60% at 50% 30%,#3d2b1d,#140d08 75%);
  color: #f7ead2;
}

.n4-radio .n4-set {
  --v: 0;
  --sig: 0;
  --noise: 1;
  width: min(64cqmin,450px);
  font-size: min(2cqmin,14px);
  margin-bottom: 1.6cqmin;
  padding: 1.5em 1.6em 1.1em;
  border-radius: 5em 5em 1.2em 1.2em/3.4em 3.4em 1.2em 1.2em;
  background: repeating-linear-gradient(93deg,rgba(0,0,0,.07) 0 .25em,transparent .25em .9em,rgba(255,220,180,.04) .9em 1.2em,transparent 1.2em 2em),linear-gradient(160deg,#8f4f25,#5a2d12 60%,#3b1d0a);
  box-shadow: inset 0 .25em .3em rgba(255,255,255,.2),inset 0 -.5em .8em rgba(0,0,0,.45),0 2em 3em -1.4em #000;
}

.n4-radio .n4-top {
  display: flex;
  gap: 1.2em;
  height: 8.5em;
}

.n4-radio .n4-grille {
  position: relative;
  flex: 1;
  overflow: hidden;
  border-radius: 2.6em 2.6em .6em .6em;
  background: repeating-linear-gradient(90deg,transparent 0 1.6em,#4a240d 1.6em 2em),repeating-linear-gradient(45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),repeating-linear-gradient(-45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),#cdb68a;
  box-shadow: inset 0 0 0 .3em #3b1d0a,inset 0 0 1.4em rgba(0,0,0,.5);
}

.n4-radio .n4-on .n4-grille {
  animation: n4-radio-thump calc(.45s / var(--k)) ease-in-out infinite alternate;
}

.n4-radio .n4-static {
  position: absolute;
  inset: -10px;
  opacity: var(--noise);
  background: repeating-radial-gradient(circle at 27% 38%,rgba(255,255,255,.55) 0 1px,transparent 1px 3px),repeating-radial-gradient(circle at 71% 63%,rgba(0,0,0,.45) 0 1px,transparent 1px 4px);
  animation: n4-radio-noise calc(.18s / var(--k)) steps(3) infinite;
}

.n4-radio .n4-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  width: 5.4em;
}

.n4-radio .n4-eye {
  width: 3.6em;
  height: 3.6em;
  border-radius: 50%;
  background: radial-gradient(circle,#0b1a10 0 22%,transparent 23%),conic-gradient(from calc(180deg - var(--uvq17-w)),#0b1a10 0 calc(var(--uvq17-w) * 2),#6dff8a 0);
  --uvq17-w: calc((1 - var(--sig)) * 70deg + 4deg);
  box-shadow: 0 0 0 .35em #2a160a,0 0 0 .5em #b78a4a,0 0 1.2em rgba(109,255,138,calc(var(--sig) * .7));
  transition: --uvq17-w .2s;
}

.n4-radio .n4-knob {
  width: 2.6em;
  height: 2.6em;
  border-radius: 50%;
  background: repeating-conic-gradient(#e9d8b4 0 8deg,#b99b66 8deg 16deg);
  box-shadow: inset 0 0 0 .5em #f3e6c8,0 .2em .3em rgba(0,0,0,.5);
  rotate: calc(var(--v) * 3.6deg);
}

.n4-radio .n4-k2 {
  rotate: calc(var(--v) * -1.2deg);
}

.n4-radio .n4-scale {
  position: relative;
  height: 3.2em;
  margin-top: 1.1em;
  border-radius: .5em;
  cursor: ew-resize;
  touch-action: none;
  background: linear-gradient(#f6e7bf,#e2c98d);
  box-shadow: inset 0 0 0 .2em #3b1d0a,inset 0 0 1.6em rgba(255,170,60,.55);
}

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

.n4-radio .n4-track {
  position: absolute;
  inset: 0 6%;
  background: repeating-linear-gradient(90deg,#3b1d0a 0 1px,transparent 1px 2%) 0 100%/100% 28% no-repeat;
}

.n4-radio .n4-nums b {
  position: absolute;
  top: .35em;
  left: calc(var(--p) * 1%);
  translate: -50% 0;
  font: 700 .95em/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color: #3b1d0a;
}

.n4-radio .n4-needle {
  position: absolute;
  top: .25em;
  bottom: .25em;
  left: calc(var(--v) * 1%);
  width: .2em;
  margin-left: -.1em;
  border-radius: .1em;
  background: #d7261e;
  box-shadow: 0 0 .4em rgba(215,38,30,.6);
}

.n4-radio .n4-station {
  min-height: 1.3em;
  margin: .7em 0 0;
  font: 600 1em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .04em;
  color: #f6e7bf;
}

.n4-radio .n4-tag {
  color: var(--accent);
}

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

.n4-radio .n4-sub {
  color: #cdb79b;
}

.n4-radio .n4-cta {
  background: var(--accent);
  color: #2a1406;
}

@property --uvq17-w {
  syntax: "<angle>";
  inherits: true;
  initial-value: 74deg;
}

@keyframes n4-radio-noise {
  33% {
    background-position: 3px 1px,-2px 3px;
  }
  66% {
    background-position: -1px -3px,2px -1px;
  }
}

@keyframes n4-radio-thump {
  to {
    transform: scale(1.012);
  }
}
```

### JavaScript

```js
document.querySelectorAll(".n4-radio").forEach((el) => {
  const set = el.querySelector(".n4-set");
  const scale = el.querySelector(".n4-scale");
  const track = el.querySelector(".n4-track");
  const label = el.querySelector(".n4-station");
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const ST = [[914, "Onda Jazz"], [965, "24 hour news"], [1004, "404 FM: broadcast not found"], [1052, "Late night boleros"]];
  const SEARCH = "Searching for a station…";
  let v = 880, shown = SEARCH, raf = 0;
  const render = () => {
    let best = 0, name = SEARCH, lost = false;
    for (const [f, n] of ST) {
      const s = Math.max(0, 1 - Math.abs(v - f) / 10);
      if (s > best) { best = s; if (s > 0.55) { name = n; lost = f === 1004; } }
    }
    set.style.setProperty("--v", ((v - 880) / 2).toFixed(2));
    set.style.setProperty("--sig", best.toFixed(2));
    set.style.setProperty("--noise", (lost ? 0.75 : 1 - best * 0.9).toFixed(2));
    set.classList.toggle("n4-on", best > 0.55 && !lost);
    scale.setAttribute("aria-valuenow", String(v));
    scale.setAttribute("aria-valuetext", (v / 10).toFixed(1).replace(".", ",") + " MHz");
    if (name !== shown) { shown = name; label.textContent = name; }
  };
  const tune = (n) => { cancelAnimationFrame(raf); v = Math.max(880, Math.min(1080, Math.round(n))); render(); };
  const fromX = (e) => { const r = track.getBoundingClientRect(); tune(880 + ((e.clientX - r.left) / r.width) * 200); };
  let down = false;
  scale.addEventListener("pointerdown", (e) => { down = true; scale.setPointerCapture(e.pointerId); fromX(e); });
  scale.addEventListener("pointermove", (e) => { if (down) fromX(e); });
  scale.addEventListener("pointerup", () => { down = false; });
  scale.addEventListener("pointercancel", () => { down = false; });
  scale.addEventListener("keydown", (e) => {
    const d = { ArrowRight: 1, ArrowUp: 1, ArrowLeft: -1, ArrowDown: -1, PageUp: 10, PageDown: -10 }[e.key];
    if (d) { e.preventDefault(); tune(v + d); }
    else if (e.key === "Home") { e.preventDefault(); tune(880); }
    else if (e.key === "End") { e.preventDefault(); tune(1080); }
  });
  const t0 = performance.now();
  const sweep = (t) => {
    const p = Math.min(1, (t - t0) / (2400 / k));
    v = Math.round(880 + 124 * (1 - Math.pow(1 - p, 3)));
    render();
    if (p < 1) raf = requestAnimationFrame(sweep);
  };
  if (rm) { v = 1004; render(); } else raf = requestAnimationFrame(sweep);
});
```

### React

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

const css = `
.n4-radio {
  --accent: #ffb347;
  --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-radio *,.n4-radio *::before,.n4-radio *::after {
  box-sizing: border-box;
}

.n4-radio .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-radio .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-radio .n4-sub {
  margin: 0;
  max-width: 34em;
  font-size: clamp(13px,2.4cqmin,18px);
  color: #a1a1a6;
  text-wrap: balance;
}

.n4-radio .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-radio .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-radio .n4-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 32px -10px var(--accent);
}

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

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

.n4-radio .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-radio-tw calc(5s / var(--k)) ease-in-out infinite alternate;
}

.n4-radio .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-radio-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
}

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

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

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

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

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

.n4-radio {
  background: radial-gradient(70% 60% at 50% 30%,#3d2b1d,#140d08 75%);
  color: #f7ead2;
}

.n4-radio .n4-set {
  --v: 0;
  --sig: 0;
  --noise: 1;
  width: min(64cqmin,450px);
  font-size: min(2cqmin,14px);
  margin-bottom: 1.6cqmin;
  padding: 1.5em 1.6em 1.1em;
  border-radius: 5em 5em 1.2em 1.2em/3.4em 3.4em 1.2em 1.2em;
  background: repeating-linear-gradient(93deg,rgba(0,0,0,.07) 0 .25em,transparent .25em .9em,rgba(255,220,180,.04) .9em 1.2em,transparent 1.2em 2em),linear-gradient(160deg,#8f4f25,#5a2d12 60%,#3b1d0a);
  box-shadow: inset 0 .25em .3em rgba(255,255,255,.2),inset 0 -.5em .8em rgba(0,0,0,.45),0 2em 3em -1.4em #000;
}

.n4-radio .n4-top {
  display: flex;
  gap: 1.2em;
  height: 8.5em;
}

.n4-radio .n4-grille {
  position: relative;
  flex: 1;
  overflow: hidden;
  border-radius: 2.6em 2.6em .6em .6em;
  background: repeating-linear-gradient(90deg,transparent 0 1.6em,#4a240d 1.6em 2em),repeating-linear-gradient(45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),repeating-linear-gradient(-45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),#cdb68a;
  box-shadow: inset 0 0 0 .3em #3b1d0a,inset 0 0 1.4em rgba(0,0,0,.5);
}

.n4-radio .n4-on .n4-grille {
  animation: n4-radio-thump calc(.45s / var(--k)) ease-in-out infinite alternate;
}

.n4-radio .n4-static {
  position: absolute;
  inset: -10px;
  opacity: var(--noise);
  background: repeating-radial-gradient(circle at 27% 38%,rgba(255,255,255,.55) 0 1px,transparent 1px 3px),repeating-radial-gradient(circle at 71% 63%,rgba(0,0,0,.45) 0 1px,transparent 1px 4px);
  animation: n4-radio-noise calc(.18s / var(--k)) steps(3) infinite;
}

.n4-radio .n4-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  width: 5.4em;
}

.n4-radio .n4-eye {
  width: 3.6em;
  height: 3.6em;
  border-radius: 50%;
  background: radial-gradient(circle,#0b1a10 0 22%,transparent 23%),conic-gradient(from calc(180deg - var(--uvq17-w)),#0b1a10 0 calc(var(--uvq17-w) * 2),#6dff8a 0);
  --uvq17-w: calc((1 - var(--sig)) * 70deg + 4deg);
  box-shadow: 0 0 0 .35em #2a160a,0 0 0 .5em #b78a4a,0 0 1.2em rgba(109,255,138,calc(var(--sig) * .7));
  transition: --uvq17-w .2s;
}

.n4-radio .n4-knob {
  width: 2.6em;
  height: 2.6em;
  border-radius: 50%;
  background: repeating-conic-gradient(#e9d8b4 0 8deg,#b99b66 8deg 16deg);
  box-shadow: inset 0 0 0 .5em #f3e6c8,0 .2em .3em rgba(0,0,0,.5);
  rotate: calc(var(--v) * 3.6deg);
}

.n4-radio .n4-k2 {
  rotate: calc(var(--v) * -1.2deg);
}

.n4-radio .n4-scale {
  position: relative;
  height: 3.2em;
  margin-top: 1.1em;
  border-radius: .5em;
  cursor: ew-resize;
  touch-action: none;
  background: linear-gradient(#f6e7bf,#e2c98d);
  box-shadow: inset 0 0 0 .2em #3b1d0a,inset 0 0 1.6em rgba(255,170,60,.55);
}

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

.n4-radio .n4-track {
  position: absolute;
  inset: 0 6%;
  background: repeating-linear-gradient(90deg,#3b1d0a 0 1px,transparent 1px 2%) 0 100%/100% 28% no-repeat;
}

.n4-radio .n4-nums b {
  position: absolute;
  top: .35em;
  left: calc(var(--p) * 1%);
  translate: -50% 0;
  font: 700 .95em/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color: #3b1d0a;
}

.n4-radio .n4-needle {
  position: absolute;
  top: .25em;
  bottom: .25em;
  left: calc(var(--v) * 1%);
  width: .2em;
  margin-left: -.1em;
  border-radius: .1em;
  background: #d7261e;
  box-shadow: 0 0 .4em rgba(215,38,30,.6);
}

.n4-radio .n4-station {
  min-height: 1.3em;
  margin: .7em 0 0;
  font: 600 1em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .04em;
  color: #f6e7bf;
}

.n4-radio .n4-tag {
  color: var(--accent);
}

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

.n4-radio .n4-sub {
  color: #cdb79b;
}

.n4-radio .n4-cta {
  background: var(--accent);
  color: #2a1406;
}

@property --uvq17-w {
  syntax: "<angle>";
  inherits: true;
  initial-value: 74deg;
}

@keyframes n4-radio-noise {
  33% {
    background-position: 3px 1px,-2px 3px;
  }
  66% {
    background-position: -1px -3px,2px -1px;
  }
}

@keyframes n4-radio-thump {
  to {
    transform: scale(1.012);
  }
}
`;

// 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 set = el.querySelector(".n4-set");
  const scale = el.querySelector(".n4-scale");
  const track = el.querySelector(".n4-track");
  const label = el.querySelector(".n4-station");
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const ST = [[914, "Onda Jazz"], [965, "24 hour news"], [1004, "404 FM: broadcast not found"], [1052, "Late night boleros"]];
  const SEARCH = "Searching for a station…";
  let v = 880, shown = SEARCH, raf = 0;
  const render = () => {
    let best = 0, name = SEARCH, lost = false;
    for (const [f, n] of ST) {
      const s = Math.max(0, 1 - Math.abs(v - f) / 10);
      if (s > best) { best = s; if (s > 0.55) { name = n; lost = f === 1004; } }
    }
    set.style.setProperty("--v", ((v - 880) / 2).toFixed(2));
    set.style.setProperty("--sig", best.toFixed(2));
    set.style.setProperty("--noise", (lost ? 0.75 : 1 - best * 0.9).toFixed(2));
    set.classList.toggle("n4-on", best > 0.55 && !lost);
    scale.setAttribute("aria-valuenow", String(v));
    scale.setAttribute("aria-valuetext", (v / 10).toFixed(1).replace(".", ",") + " MHz");
    if (name !== shown) { shown = name; label.textContent = name; }
  };
  const tune = (n) => { cancelAnimationFrame(raf); v = Math.max(880, Math.min(1080, Math.round(n))); render(); };
  const fromX = (e) => { const r = track.getBoundingClientRect(); tune(880 + ((e.clientX - r.left) / r.width) * 200); };
  let down = false;
  scale.addEventListener("pointerdown", (e) => { down = true; scale.setPointerCapture(e.pointerId); fromX(e); });
  scale.addEventListener("pointermove", (e) => { if (down) fromX(e); });
  scale.addEventListener("pointerup", () => { down = false; });
  scale.addEventListener("pointercancel", () => { down = false; });
  scale.addEventListener("keydown", (e) => {
    const d = { ArrowRight: 1, ArrowUp: 1, ArrowLeft: -1, ArrowDown: -1, PageUp: 10, PageDown: -10 }[e.key];
    if (d) { e.preventDefault(); tune(v + d); }
    else if (e.key === "Home") { e.preventDefault(); tune(880); }
    else if (e.key === "End") { e.preventDefault(); tune(1080); }
  });
  const t0 = performance.now();
  const sweep = (t) => {
    const p = Math.min(1, (t - t0) / (2400 / k));
    v = Math.round(880 + 124 * (1 - Math.pow(1 - p, 3)));
    render();
    if (p < 1) raf = requestAnimationFrame(sweep);
  };
  if (rm) { v = 1004; render(); } else raf = requestAnimationFrame(sweep);
  return () => cancelAnimationFrame(raf);
}

export default function NotFoundRadio() {
  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-radio">
          <div className="n4-copy">
            <div className="n4-set">
              <div className="n4-top" aria-hidden="true">
                <div className="n4-grille"><i className="n4-static"></i></div>
                <div className="n4-side"><i className="n4-eye"></i><i className="n4-knob"></i><i className="n4-knob n4-k2"></i></div>
              </div>
              <div className="n4-scale" role="slider" tabIndex={0} aria-label="Tuning dial" aria-valuemin="880" aria-valuemax="1080" aria-valuenow="880" aria-valuetext="88,0 MHz">
                <div className="n4-track"><span className="n4-nums" aria-hidden="true" translate="no"><b style={{ "--p": "0" } as CSSProperties}>88</b><b style={{ "--p": "20" } as CSSProperties}>92</b><b style={{ "--p": "40" } as CSSProperties}>96</b><b style={{ "--p": "60" } as CSSProperties}>100</b><b style={{ "--p": "80" } as CSSProperties}>104</b><b style={{ "--p": "100" } as CSSProperties}>108</b></span><i className="n4-needle" aria-hidden="true"></i></div>
              </div>
              <p className="n4-station" aria-live="polite">Searching for a station…</p>
            </div>
            <span className="n4-tag">Frequency 100.4 MHz</span>
            <h1 className="n4-title">Nobody broadcasts on this frequency.</h1>
            <p className="n4-sub">The page you're looking for has lost its signal. Turn the dial or go back home, there's always something on there.</p>
            <a className="n4-cta" href="/">Back to home</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 “Vintage radio 404” block (404) from AIMRAN Library to my project.

## What it is
A wooden radio with an FM scale, a magic eye and static: drag the dial, and on 100.4 only the 404 noise plays.

## Chosen settings
- Accent color: #ffb347
- Speed: 1x (from 0.5 to 2x)
- Title: "En esta frecuencia no emite nadie."
- Message: "La página que buscas se ha quedado sin señal. Gira el dial o vuelve al inicio, que ahí siempre hay programa."
- Button: "Volver al inicio"

## 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-radio {
  --accent: #ffb347;
  --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-radio *,.n4-radio *::before,.n4-radio *::after {
  box-sizing: border-box;
}

.n4-radio .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-radio .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-radio .n4-sub {
  margin: 0;
  max-width: 34em;
  font-size: clamp(13px,2.4cqmin,18px);
  color: #a1a1a6;
  text-wrap: balance;
}

.n4-radio .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-radio .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-radio .n4-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 32px -10px var(--accent);
}

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

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

.n4-radio .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-radio-tw calc(5s / var(--k)) ease-in-out infinite alternate;
}

.n4-radio .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-radio-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
}

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

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

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

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

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

.n4-radio {
  background: radial-gradient(70% 60% at 50% 30%,#3d2b1d,#140d08 75%);
  color: #f7ead2;
}

.n4-radio .n4-set {
  --v: 0;
  --sig: 0;
  --noise: 1;
  width: min(64cqmin,450px);
  font-size: min(2cqmin,14px);
  margin-bottom: 1.6cqmin;
  padding: 1.5em 1.6em 1.1em;
  border-radius: 5em 5em 1.2em 1.2em/3.4em 3.4em 1.2em 1.2em;
  background: repeating-linear-gradient(93deg,rgba(0,0,0,.07) 0 .25em,transparent .25em .9em,rgba(255,220,180,.04) .9em 1.2em,transparent 1.2em 2em),linear-gradient(160deg,#8f4f25,#5a2d12 60%,#3b1d0a);
  box-shadow: inset 0 .25em .3em rgba(255,255,255,.2),inset 0 -.5em .8em rgba(0,0,0,.45),0 2em 3em -1.4em #000;
}

.n4-radio .n4-top {
  display: flex;
  gap: 1.2em;
  height: 8.5em;
}

.n4-radio .n4-grille {
  position: relative;
  flex: 1;
  overflow: hidden;
  border-radius: 2.6em 2.6em .6em .6em;
  background: repeating-linear-gradient(90deg,transparent 0 1.6em,#4a240d 1.6em 2em),repeating-linear-gradient(45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),repeating-linear-gradient(-45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),#cdb68a;
  box-shadow: inset 0 0 0 .3em #3b1d0a,inset 0 0 1.4em rgba(0,0,0,.5);
}

.n4-radio .n4-on .n4-grille {
  animation: n4-radio-thump calc(.45s / var(--k)) ease-in-out infinite alternate;
}

.n4-radio .n4-static {
  position: absolute;
  inset: -10px;
  opacity: var(--noise);
  background: repeating-radial-gradient(circle at 27% 38%,rgba(255,255,255,.55) 0 1px,transparent 1px 3px),repeating-radial-gradient(circle at 71% 63%,rgba(0,0,0,.45) 0 1px,transparent 1px 4px);
  animation: n4-radio-noise calc(.18s / var(--k)) steps(3) infinite;
}

.n4-radio .n4-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  width: 5.4em;
}

.n4-radio .n4-eye {
  width: 3.6em;
  height: 3.6em;
  border-radius: 50%;
  background: radial-gradient(circle,#0b1a10 0 22%,transparent 23%),conic-gradient(from calc(180deg - var(--uvq17-w)),#0b1a10 0 calc(var(--uvq17-w) * 2),#6dff8a 0);
  --uvq17-w: calc((1 - var(--sig)) * 70deg + 4deg);
  box-shadow: 0 0 0 .35em #2a160a,0 0 0 .5em #b78a4a,0 0 1.2em rgba(109,255,138,calc(var(--sig) * .7));
  transition: --uvq17-w .2s;
}

.n4-radio .n4-knob {
  width: 2.6em;
  height: 2.6em;
  border-radius: 50%;
  background: repeating-conic-gradient(#e9d8b4 0 8deg,#b99b66 8deg 16deg);
  box-shadow: inset 0 0 0 .5em #f3e6c8,0 .2em .3em rgba(0,0,0,.5);
  rotate: calc(var(--v) * 3.6deg);
}

.n4-radio .n4-k2 {
  rotate: calc(var(--v) * -1.2deg);
}

.n4-radio .n4-scale {
  position: relative;
  height: 3.2em;
  margin-top: 1.1em;
  border-radius: .5em;
  cursor: ew-resize;
  touch-action: none;
  background: linear-gradient(#f6e7bf,#e2c98d);
  box-shadow: inset 0 0 0 .2em #3b1d0a,inset 0 0 1.6em rgba(255,170,60,.55);
}

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

.n4-radio .n4-track {
  position: absolute;
  inset: 0 6%;
  background: repeating-linear-gradient(90deg,#3b1d0a 0 1px,transparent 1px 2%) 0 100%/100% 28% no-repeat;
}

.n4-radio .n4-nums b {
  position: absolute;
  top: .35em;
  left: calc(var(--p) * 1%);
  translate: -50% 0;
  font: 700 .95em/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color: #3b1d0a;
}

.n4-radio .n4-needle {
  position: absolute;
  top: .25em;
  bottom: .25em;
  left: calc(var(--v) * 1%);
  width: .2em;
  margin-left: -.1em;
  border-radius: .1em;
  background: #d7261e;
  box-shadow: 0 0 .4em rgba(215,38,30,.6);
}

.n4-radio .n4-station {
  min-height: 1.3em;
  margin: .7em 0 0;
  font: 600 1em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .04em;
  color: #f6e7bf;
}

.n4-radio .n4-tag {
  color: var(--accent);
}

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

.n4-radio .n4-sub {
  color: #cdb79b;
}

.n4-radio .n4-cta {
  background: var(--accent);
  color: #2a1406;
}

@property --uvq17-w {
  syntax: "<angle>";
  inherits: true;
  initial-value: 74deg;
}

@keyframes n4-radio-noise {
  33% {
    background-position: 3px 1px,-2px 3px;
  }
  66% {
    background-position: -1px -3px,2px -1px;
  }
}

@keyframes n4-radio-thump {
  to {
    transform: scale(1.012);
  }
}
`;

// 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 set = el.querySelector(".n4-set");
  const scale = el.querySelector(".n4-scale");
  const track = el.querySelector(".n4-track");
  const label = el.querySelector(".n4-station");
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const ST = [[914, "Onda Jazz"], [965, "24 hour news"], [1004, "404 FM: broadcast not found"], [1052, "Late night boleros"]];
  const SEARCH = "Searching for a station…";
  let v = 880, shown = SEARCH, raf = 0;
  const render = () => {
    let best = 0, name = SEARCH, lost = false;
    for (const [f, n] of ST) {
      const s = Math.max(0, 1 - Math.abs(v - f) / 10);
      if (s > best) { best = s; if (s > 0.55) { name = n; lost = f === 1004; } }
    }
    set.style.setProperty("--v", ((v - 880) / 2).toFixed(2));
    set.style.setProperty("--sig", best.toFixed(2));
    set.style.setProperty("--noise", (lost ? 0.75 : 1 - best * 0.9).toFixed(2));
    set.classList.toggle("n4-on", best > 0.55 && !lost);
    scale.setAttribute("aria-valuenow", String(v));
    scale.setAttribute("aria-valuetext", (v / 10).toFixed(1).replace(".", ",") + " MHz");
    if (name !== shown) { shown = name; label.textContent = name; }
  };
  const tune = (n) => { cancelAnimationFrame(raf); v = Math.max(880, Math.min(1080, Math.round(n))); render(); };
  const fromX = (e) => { const r = track.getBoundingClientRect(); tune(880 + ((e.clientX - r.left) / r.width) * 200); };
  let down = false;
  scale.addEventListener("pointerdown", (e) => { down = true; scale.setPointerCapture(e.pointerId); fromX(e); });
  scale.addEventListener("pointermove", (e) => { if (down) fromX(e); });
  scale.addEventListener("pointerup", () => { down = false; });
  scale.addEventListener("pointercancel", () => { down = false; });
  scale.addEventListener("keydown", (e) => {
    const d = { ArrowRight: 1, ArrowUp: 1, ArrowLeft: -1, ArrowDown: -1, PageUp: 10, PageDown: -10 }[e.key];
    if (d) { e.preventDefault(); tune(v + d); }
    else if (e.key === "Home") { e.preventDefault(); tune(880); }
    else if (e.key === "End") { e.preventDefault(); tune(1080); }
  });
  const t0 = performance.now();
  const sweep = (t) => {
    const p = Math.min(1, (t - t0) / (2400 / k));
    v = Math.round(880 + 124 * (1 - Math.pow(1 - p, 3)));
    render();
    if (p < 1) raf = requestAnimationFrame(sweep);
  };
  if (rm) { v = 1004; render(); } else raf = requestAnimationFrame(sweep);
  return () => cancelAnimationFrame(raf);
}

export default function NotFoundRadio() {
  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-radio">
          <div className="n4-copy">
            <div className="n4-set">
              <div className="n4-top" aria-hidden="true">
                <div className="n4-grille"><i className="n4-static"></i></div>
                <div className="n4-side"><i className="n4-eye"></i><i className="n4-knob"></i><i className="n4-knob n4-k2"></i></div>
              </div>
              <div className="n4-scale" role="slider" tabIndex={0} aria-label="Tuning dial" aria-valuemin="880" aria-valuemax="1080" aria-valuenow="880" aria-valuetext="88,0 MHz">
                <div className="n4-track"><span className="n4-nums" aria-hidden="true" translate="no"><b style={{ "--p": "0" } as CSSProperties}>88</b><b style={{ "--p": "20" } as CSSProperties}>92</b><b style={{ "--p": "40" } as CSSProperties}>96</b><b style={{ "--p": "60" } as CSSProperties}>100</b><b style={{ "--p": "80" } as CSSProperties}>104</b><b style={{ "--p": "100" } as CSSProperties}>108</b></span><i className="n4-needle" aria-hidden="true"></i></div>
              </div>
              <p className="n4-station" aria-live="polite">Searching for a station…</p>
            </div>
            <span className="n4-tag">Frequency 100.4 MHz</span>
            <h1 className="n4-title">Nobody broadcasts on this frequency.</h1>
            <p className="n4-sub">The page you're looking for has lost its signal. Turn the dial or go back home, there's always something on there.</p>
            <a className="n4-cta" href="/">Back to home</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.
````
