# Art deco elevator 404

> A brass art deco dial shows the elevator floor; press 404 and the needle hits the end stop and trembles.

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

## Where to use it

Old hotels and office buildings still have those semicircular brass dials above the lift doors, and this error page builds one in inline SVG on a black lacquer background with a faint sunburst. The needle swings with a springy overshoot to each floor, and floor 404 sends it past the last number against the stop.

The floor buttons are real buttons with a pressed state, keyboard focus and a lit ring while the car travels. A short message announces that the floor does not exist. Adjust the gold accent and link the button to your lobby 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-elevator {
        --accent: #f2b84b;
        --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-elevator *,.n4-elevator *::before,.n4-elevator *::after {
        box-sizing: border-box;
      }
      
      .n4-elevator .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-elevator .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-elevator .n4-sub {
        margin: 0;
        max-width: 34em;
        font-size: clamp(13px,2.4cqmin,18px);
        color: #a1a1a6;
        text-wrap: balance;
      }
      
      .n4-elevator .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-elevator .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-elevator .n4-cta:hover {
        transform: translateY(-2px);
        box-shadow: 0 12px 32px -10px var(--accent);
      }
      
      .n4-elevator .n4-cta:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 3px;
      }
      
      .n4-elevator .n4-stars,.n4-elevator .n4-stars2 {
        position: absolute;
        inset: -4%;
        pointer-events: none;
      }
      
      .n4-elevator .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-elevator-tw calc(5s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-elevator .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-elevator-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
      }
      
      .n4-elevator [data-depth] {
        transition: transform .9s cubic-bezier(.2,.7,.2,1);
      }
      
      @keyframes n4-elevator-tw {
        from {
          opacity: .3;
        }
      }
      
      @keyframes n4-elevator-spin {
        to {
          transform: rotate(1turn);
        }
      }
      
      @keyframes n4-elevator-fade {
        from {
          opacity: 0;
          transform: translateY(10px);
        }
      }
      
      @media (prefers-reduced-motion:reduce) {
        .n4-elevator *,.n4-elevator *::before,.n4-elevator *::after {
          animation: none!important;
          transition: none!important;
        }
      }
      
      .n4-elevator {
        background: repeating-conic-gradient(from -90deg at 50% 112%,rgba(242,184,75,.07) 0 2deg,transparent 2deg 9deg),radial-gradient(80% 60% at 50% 30%,#241d12,#0b0906 75%);
        color: #f6ecd4;
        font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
      }
      
      .n4-elevator .n4-lift {
        display: flex;
        flex-direction: column;
        align-items: center;
        font-size: min(2cqmin,14px);
        margin-bottom: .5cqmin;
      }
      
      .n4-elevator .n4-dial {
        width: 22em;
        height: auto;
        overflow: visible;
        filter: drop-shadow(0 1.2em 1.4em rgba(0,0,0,.6));
      }
      
      .n4-elevator .n4-ray {
        stroke: rgba(242,184,75,.16);
        stroke-width: 1;
      }
      
      .n4-elevator .n4-tk {
        stroke: #f1cf73;
        stroke-width: 2.4;
        stroke-linecap: round;
      }
      
      .n4-elevator .n4-fl {
        font: 500 15px "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
        fill: #f6ecd4;
        text-anchor: middle;
      }
      
      .n4-elevator .n4-l404 {
        font: 700 11px ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        fill: #5a4a33;
        text-anchor: middle;
        transition: fill .3s;
      }
      
      .n4-elevator .n4-needle {
        transform-box: view-box;
        transform-origin: 120px 130px;
        transform: rotate(var(--a,-60deg));
        transition: transform calc(var(--d,1s) / var(--k)) cubic-bezier(.34,1.45,.5,1);
      }
      
      .n4-elevator .n4-lost .n4-needle {
        animation: n4-elevator-wob calc(.14s / var(--k)) linear infinite alternate;
      }
      
      .n4-elevator .n4-lost .n4-l404 {
        fill: #ff5b4a;
        filter: drop-shadow(0 0 4px #ff5b4a);
      }
      
      .n4-elevator .n4-btns {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: .8em;
        margin-top: 1.2em;
        padding: .9em 1.2em;
        border-radius: 1em;
        background: linear-gradient(135deg,#2c261c,#14110b);
        box-shadow: inset 0 0 0 1px rgba(242,184,75,.35),0 1em 1.6em -1em #000;
      }
      
      .n4-elevator .n4-fb {
        width: 3.3em;
        height: 3.3em;
        min-width: 30px;
        min-height: 30px;
        border: 0;
        border-radius: 50%;
        cursor: pointer;
        font: 600 1.15em/1 "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
        color: #1a140a;
        background: radial-gradient(circle at 40% 35%,#fff3c4,#d9a93f 55%,#8a5e14);
        box-shadow: 0 .2em 0 #5a3d0c,inset 0 0 0 .18em rgba(255,255,255,.25);
        transition: transform .12s,box-shadow .2s,filter .2s;
      }
      
      .n4-elevator .n4-fb.n4-x {
        width: auto;
        padding: 0 1em;
        border-radius: 999px;
        font-family: ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        font-size: 1em;
      }
      
      .n4-elevator .n4-fb:hover {
        filter: brightness(1.1);
      }
      
      .n4-elevator .n4-fb:active {
        transform: translateY(.15em);
        box-shadow: 0 .05em 0 #5a3d0c;
      }
      
      .n4-elevator .n4-fb[aria-pressed="true"] {
        box-shadow: 0 .2em 0 #5a3d0c,0 0 0 .2em #14110b,0 0 0 .38em var(--accent),0 0 1.4em var(--accent);
      }
      
      .n4-elevator .n4-fb:focus-visible {
        outline: 2px solid #fff;
        outline-offset: 5px;
      }
      
      .n4-elevator .n4-msg {
        min-height: 1.3em;
        margin: .8em 0 0;
        font: 700 .95em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        letter-spacing: .14em;
        text-transform: uppercase;
        color: #ff6b5b;
      }
      
      .n4-elevator .n4-tag {
        font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
        letter-spacing: .3em;
      }
      
      .n4-elevator .n4-title {
        font-size: clamp(20px,4.8cqmin,40px);
        font-weight: 500;
        letter-spacing: 0;
      }
      
      .n4-elevator .n4-sub {
        color: #c8b998;
      }
      
      .n4-elevator .n4-cta {
        background: var(--accent);
        color: #1a140a;
      }
      
      @keyframes n4-elevator-wob {
        from {
          rotate: -1.2deg;
        }
        to {
          rotate: 1.8deg;
        }
      }
    </style>
  </head>
  <body>
    <main class="n4-elevator">
      <div class="n4-copy">
        <div class="n4-lift">
          <svg class="n4-dial" viewBox="0 0 240 140" aria-hidden="true">
            <defs><linearGradient id="uvq17-brass" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#f7dc8c"/><stop offset=".45" stop-color="#b8862b"/><stop offset=".7" stop-color="#f1cf73"/><stop offset="1" stop-color="#8a5e14"/></linearGradient></defs>
            <path d="M8 132A112 112 0 0 1 232 132Z" fill="url(#uvq17-brass)"/>
            <path d="M20 130A100 100 0 0 1 220 130Z" fill="#15110b"/>
            <path class="n4-ray" d="M98.3 126.2L47.1 117.2"/><path class="n4-ray" d="M99.3 122.5L50.5 104.7"/><path class="n4-ray" d="M100.9 119.0L55.9 93.0"/><path class="n4-ray" d="M103.1 115.9L63.3 82.4"/><path class="n4-ray" d="M105.9 113.1L72.4 73.3"/><path class="n4-ray" d="M109.0 110.9L83.0 65.9"/><path class="n4-ray" d="M112.5 109.3L94.7 60.5"/><path class="n4-ray" d="M116.2 108.3L107.2 57.1"/><path class="n4-ray" d="M120.0 108.0L120.0 56.0"/><path class="n4-ray" d="M123.8 108.3L132.8 57.1"/><path class="n4-ray" d="M127.5 109.3L145.3 60.5"/><path class="n4-ray" d="M131.0 110.9L157.0 65.9"/><path class="n4-ray" d="M134.1 113.1L167.6 73.3"/><path class="n4-ray" d="M136.9 115.9L176.7 82.4"/><path class="n4-ray" d="M139.1 119.0L184.1 93.0"/><path class="n4-ray" d="M140.7 122.5L189.5 104.7"/><path class="n4-ray" d="M141.7 126.2L192.9 117.2"/><path class="n4-tk" d="M42.1 85.0L35.1 81.0"/><text class="n4-fl" x="52.5" y="96.0">0</text><path class="n4-tk" d="M67.1 57.2L62.4 50.7"/><text class="n4-fl" x="74.2" y="71.9">1</text><path class="n4-tk" d="M101.3 42.0L99.6 34.1"/><text class="n4-fl" x="103.8" y="58.7">2</text><path class="n4-tk" d="M138.7 42.0L140.4 34.1"/><text class="n4-fl" x="136.2" y="58.7">3</text><path class="n4-tk" d="M172.9 57.2L177.6 50.7"/><text class="n4-fl" x="165.8" y="71.9">4</text><path class="n4-tk" d="M197.9 85.0L204.9 81.0"/><text class="n4-fl" x="187.5" y="96.0">5</text>
            <text class="n4-l404" x="207" y="122">404</text>
            <g class="n4-needle"><path d="M117 130L120 40l3 90z" fill="url(#uvq17-brass)"/></g>
            <circle cx="120" cy="130" r="10" fill="url(#uvq17-brass)"/>
          </svg>
          <div class="n4-btns" role="group" aria-label="Elevator buttons">
            <button class="n4-fb" type="button" data-f="0" aria-pressed="false">0</button><button class="n4-fb" type="button" data-f="1" aria-pressed="false">1</button><button class="n4-fb" type="button" data-f="2" aria-pressed="false">2</button><button class="n4-fb" type="button" data-f="3" aria-pressed="false">3</button><button class="n4-fb" type="button" data-f="4" aria-pressed="false">4</button><button class="n4-fb" type="button" data-f="5" aria-pressed="false">5</button>
            <button class="n4-fb n4-x" type="button" data-f="404" aria-pressed="false">404</button>
          </div>
          <p class="n4-msg" aria-live="polite"></p>
        </div>
        <span class="n4-tag">Service elevator</span>
        <h1 class="n4-title">This elevator doesn't go to floor 404.</h1>
        <p class="n4-sub">The building has five floors and the page you're looking for isn't on any of them. Pick another or head down to the lobby.</p>
        <a class="n4-cta" href="/">Down to the lobby</a>
      </div>
    </main>
    <script>
      document.querySelectorAll(".n4-elevator").forEach((el) => {
        const btns = el.querySelectorAll(".n4-fb");
        const lift = el.querySelector(".n4-lift");
        const msg = el.querySelector(".n4-msg");
        const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
        const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
        const pos = (f) => (f === 404 ? 7 : f);
        let cur = 0, timer = 0;
        const go = (b) => {
          const f = Number(b.dataset.f);
          const steps = Math.abs(pos(f) - pos(cur));
          clearTimeout(timer);
          btns.forEach((x) => x.setAttribute("aria-pressed", String(x === b)));
          lift.classList.remove("n4-lost");
          msg.textContent = "";
          lift.style.setProperty("--d", 0.4 + steps * 0.25 + "s");
          lift.style.setProperty("--a", (f === 404 ? 86 : -60 + 24 * f) + "deg");
          cur = f;
          timer = setTimeout(() => {
            if (f !== 404) b.setAttribute("aria-pressed", "false");
            else {
              lift.classList.add("n4-lost");
              msg.textContent = "This floor doesn't exist";
            }
          }, rm ? 0 : (400 + steps * 250) / k + 120);
        };
        btns.forEach((b) => b.addEventListener("click", () => go(b)));
        const auto = setTimeout(() => go(btns[btns.length - 1]), rm ? 0 : 900 / k);
      });
    </script>
  </body>
</html>
```

### CSS

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

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

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

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

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

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

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

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

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

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

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

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

.n4-elevator {
  background: repeating-conic-gradient(from -90deg at 50% 112%,rgba(242,184,75,.07) 0 2deg,transparent 2deg 9deg),radial-gradient(80% 60% at 50% 30%,#241d12,#0b0906 75%);
  color: #f6ecd4;
  font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
}

.n4-elevator .n4-lift {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: min(2cqmin,14px);
  margin-bottom: .5cqmin;
}

.n4-elevator .n4-dial {
  width: 22em;
  height: auto;
  overflow: visible;
  filter: drop-shadow(0 1.2em 1.4em rgba(0,0,0,.6));
}

.n4-elevator .n4-ray {
  stroke: rgba(242,184,75,.16);
  stroke-width: 1;
}

.n4-elevator .n4-tk {
  stroke: #f1cf73;
  stroke-width: 2.4;
  stroke-linecap: round;
}

.n4-elevator .n4-fl {
  font: 500 15px "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  fill: #f6ecd4;
  text-anchor: middle;
}

.n4-elevator .n4-l404 {
  font: 700 11px ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  fill: #5a4a33;
  text-anchor: middle;
  transition: fill .3s;
}

.n4-elevator .n4-needle {
  transform-box: view-box;
  transform-origin: 120px 130px;
  transform: rotate(var(--a,-60deg));
  transition: transform calc(var(--d,1s) / var(--k)) cubic-bezier(.34,1.45,.5,1);
}

.n4-elevator .n4-lost .n4-needle {
  animation: n4-elevator-wob calc(.14s / var(--k)) linear infinite alternate;
}

.n4-elevator .n4-lost .n4-l404 {
  fill: #ff5b4a;
  filter: drop-shadow(0 0 4px #ff5b4a);
}

.n4-elevator .n4-btns {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .8em;
  margin-top: 1.2em;
  padding: .9em 1.2em;
  border-radius: 1em;
  background: linear-gradient(135deg,#2c261c,#14110b);
  box-shadow: inset 0 0 0 1px rgba(242,184,75,.35),0 1em 1.6em -1em #000;
}

.n4-elevator .n4-fb {
  width: 3.3em;
  height: 3.3em;
  min-width: 30px;
  min-height: 30px;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  font: 600 1.15em/1 "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  color: #1a140a;
  background: radial-gradient(circle at 40% 35%,#fff3c4,#d9a93f 55%,#8a5e14);
  box-shadow: 0 .2em 0 #5a3d0c,inset 0 0 0 .18em rgba(255,255,255,.25);
  transition: transform .12s,box-shadow .2s,filter .2s;
}

.n4-elevator .n4-fb.n4-x {
  width: auto;
  padding: 0 1em;
  border-radius: 999px;
  font-family: ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  font-size: 1em;
}

.n4-elevator .n4-fb:hover {
  filter: brightness(1.1);
}

.n4-elevator .n4-fb:active {
  transform: translateY(.15em);
  box-shadow: 0 .05em 0 #5a3d0c;
}

.n4-elevator .n4-fb[aria-pressed="true"] {
  box-shadow: 0 .2em 0 #5a3d0c,0 0 0 .2em #14110b,0 0 0 .38em var(--accent),0 0 1.4em var(--accent);
}

.n4-elevator .n4-fb:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 5px;
}

.n4-elevator .n4-msg {
  min-height: 1.3em;
  margin: .8em 0 0;
  font: 700 .95em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #ff6b5b;
}

.n4-elevator .n4-tag {
  font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  letter-spacing: .3em;
}

.n4-elevator .n4-title {
  font-size: clamp(20px,4.8cqmin,40px);
  font-weight: 500;
  letter-spacing: 0;
}

.n4-elevator .n4-sub {
  color: #c8b998;
}

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

@keyframes n4-elevator-wob {
  from {
    rotate: -1.2deg;
  }
  to {
    rotate: 1.8deg;
  }
}
```

### JavaScript

```js
document.querySelectorAll(".n4-elevator").forEach((el) => {
  const btns = el.querySelectorAll(".n4-fb");
  const lift = el.querySelector(".n4-lift");
  const msg = el.querySelector(".n4-msg");
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const pos = (f) => (f === 404 ? 7 : f);
  let cur = 0, timer = 0;
  const go = (b) => {
    const f = Number(b.dataset.f);
    const steps = Math.abs(pos(f) - pos(cur));
    clearTimeout(timer);
    btns.forEach((x) => x.setAttribute("aria-pressed", String(x === b)));
    lift.classList.remove("n4-lost");
    msg.textContent = "";
    lift.style.setProperty("--d", 0.4 + steps * 0.25 + "s");
    lift.style.setProperty("--a", (f === 404 ? 86 : -60 + 24 * f) + "deg");
    cur = f;
    timer = setTimeout(() => {
      if (f !== 404) b.setAttribute("aria-pressed", "false");
      else {
        lift.classList.add("n4-lost");
        msg.textContent = "This floor doesn't exist";
      }
    }, rm ? 0 : (400 + steps * 250) / k + 120);
  };
  btns.forEach((b) => b.addEventListener("click", () => go(b)));
  const auto = setTimeout(() => go(btns[btns.length - 1]), rm ? 0 : 900 / k);
});
```

### React

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

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

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

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

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

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

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

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

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

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

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

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

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

.n4-elevator {
  background: repeating-conic-gradient(from -90deg at 50% 112%,rgba(242,184,75,.07) 0 2deg,transparent 2deg 9deg),radial-gradient(80% 60% at 50% 30%,#241d12,#0b0906 75%);
  color: #f6ecd4;
  font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
}

.n4-elevator .n4-lift {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: min(2cqmin,14px);
  margin-bottom: .5cqmin;
}

.n4-elevator .n4-dial {
  width: 22em;
  height: auto;
  overflow: visible;
  filter: drop-shadow(0 1.2em 1.4em rgba(0,0,0,.6));
}

.n4-elevator .n4-ray {
  stroke: rgba(242,184,75,.16);
  stroke-width: 1;
}

.n4-elevator .n4-tk {
  stroke: #f1cf73;
  stroke-width: 2.4;
  stroke-linecap: round;
}

.n4-elevator .n4-fl {
  font: 500 15px "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  fill: #f6ecd4;
  text-anchor: middle;
}

.n4-elevator .n4-l404 {
  font: 700 11px ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  fill: #5a4a33;
  text-anchor: middle;
  transition: fill .3s;
}

.n4-elevator .n4-needle {
  transform-box: view-box;
  transform-origin: 120px 130px;
  transform: rotate(var(--a,-60deg));
  transition: transform calc(var(--d,1s) / var(--k)) cubic-bezier(.34,1.45,.5,1);
}

.n4-elevator .n4-lost .n4-needle {
  animation: n4-elevator-wob calc(.14s / var(--k)) linear infinite alternate;
}

.n4-elevator .n4-lost .n4-l404 {
  fill: #ff5b4a;
  filter: drop-shadow(0 0 4px #ff5b4a);
}

.n4-elevator .n4-btns {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .8em;
  margin-top: 1.2em;
  padding: .9em 1.2em;
  border-radius: 1em;
  background: linear-gradient(135deg,#2c261c,#14110b);
  box-shadow: inset 0 0 0 1px rgba(242,184,75,.35),0 1em 1.6em -1em #000;
}

.n4-elevator .n4-fb {
  width: 3.3em;
  height: 3.3em;
  min-width: 30px;
  min-height: 30px;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  font: 600 1.15em/1 "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  color: #1a140a;
  background: radial-gradient(circle at 40% 35%,#fff3c4,#d9a93f 55%,#8a5e14);
  box-shadow: 0 .2em 0 #5a3d0c,inset 0 0 0 .18em rgba(255,255,255,.25);
  transition: transform .12s,box-shadow .2s,filter .2s;
}

.n4-elevator .n4-fb.n4-x {
  width: auto;
  padding: 0 1em;
  border-radius: 999px;
  font-family: ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  font-size: 1em;
}

.n4-elevator .n4-fb:hover {
  filter: brightness(1.1);
}

.n4-elevator .n4-fb:active {
  transform: translateY(.15em);
  box-shadow: 0 .05em 0 #5a3d0c;
}

.n4-elevator .n4-fb[aria-pressed="true"] {
  box-shadow: 0 .2em 0 #5a3d0c,0 0 0 .2em #14110b,0 0 0 .38em var(--accent),0 0 1.4em var(--accent);
}

.n4-elevator .n4-fb:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 5px;
}

.n4-elevator .n4-msg {
  min-height: 1.3em;
  margin: .8em 0 0;
  font: 700 .95em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #ff6b5b;
}

.n4-elevator .n4-tag {
  font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  letter-spacing: .3em;
}

.n4-elevator .n4-title {
  font-size: clamp(20px,4.8cqmin,40px);
  font-weight: 500;
  letter-spacing: 0;
}

.n4-elevator .n4-sub {
  color: #c8b998;
}

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

@keyframes n4-elevator-wob {
  from {
    rotate: -1.2deg;
  }
  to {
    rotate: 1.8deg;
  }
}
`;

// 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 btns = el.querySelectorAll(".n4-fb");
  const lift = el.querySelector(".n4-lift");
  const msg = el.querySelector(".n4-msg");
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const pos = (f) => (f === 404 ? 7 : f);
  let cur = 0, timer = 0;
  const go = (b) => {
    const f = Number(b.dataset.f);
    const steps = Math.abs(pos(f) - pos(cur));
    clearTimeout(timer);
    btns.forEach((x) => x.setAttribute("aria-pressed", String(x === b)));
    lift.classList.remove("n4-lost");
    msg.textContent = "";
    lift.style.setProperty("--d", 0.4 + steps * 0.25 + "s");
    lift.style.setProperty("--a", (f === 404 ? 86 : -60 + 24 * f) + "deg");
    cur = f;
    timer = setTimeout(() => {
      if (f !== 404) b.setAttribute("aria-pressed", "false");
      else {
        lift.classList.add("n4-lost");
        msg.textContent = "This floor doesn't exist";
      }
    }, rm ? 0 : (400 + steps * 250) / k + 120);
  };
  btns.forEach((b) => b.addEventListener("click", () => go(b)));
  const auto = setTimeout(() => go(btns[btns.length - 1]), rm ? 0 : 900 / k);
  return () => { clearTimeout(timer); clearTimeout(auto); };
}

export default function NotFoundElevator() {
  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-elevator">
          <div className="n4-copy">
            <div className="n4-lift">
              <svg className="n4-dial" viewBox="0 0 240 140" aria-hidden="true">
                <defs><linearGradient id="uvq17-brass" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#f7dc8c" /><stop offset=".45" stopColor="#b8862b" /><stop offset=".7" stopColor="#f1cf73" /><stop offset="1" stopColor="#8a5e14" /></linearGradient></defs>
                <path d="M8 132A112 112 0 0 1 232 132Z" fill="url(#uvq17-brass)" />
                <path d="M20 130A100 100 0 0 1 220 130Z" fill="#15110b" />
                <path className="n4-ray" d="M98.3 126.2L47.1 117.2" /><path className="n4-ray" d="M99.3 122.5L50.5 104.7" /><path className="n4-ray" d="M100.9 119.0L55.9 93.0" /><path className="n4-ray" d="M103.1 115.9L63.3 82.4" /><path className="n4-ray" d="M105.9 113.1L72.4 73.3" /><path className="n4-ray" d="M109.0 110.9L83.0 65.9" /><path className="n4-ray" d="M112.5 109.3L94.7 60.5" /><path className="n4-ray" d="M116.2 108.3L107.2 57.1" /><path className="n4-ray" d="M120.0 108.0L120.0 56.0" /><path className="n4-ray" d="M123.8 108.3L132.8 57.1" /><path className="n4-ray" d="M127.5 109.3L145.3 60.5" /><path className="n4-ray" d="M131.0 110.9L157.0 65.9" /><path className="n4-ray" d="M134.1 113.1L167.6 73.3" /><path className="n4-ray" d="M136.9 115.9L176.7 82.4" /><path className="n4-ray" d="M139.1 119.0L184.1 93.0" /><path className="n4-ray" d="M140.7 122.5L189.5 104.7" /><path className="n4-ray" d="M141.7 126.2L192.9 117.2" /><path className="n4-tk" d="M42.1 85.0L35.1 81.0" /><text className="n4-fl" x="52.5" y="96.0">0</text><path className="n4-tk" d="M67.1 57.2L62.4 50.7" /><text className="n4-fl" x="74.2" y="71.9">1</text><path className="n4-tk" d="M101.3 42.0L99.6 34.1" /><text className="n4-fl" x="103.8" y="58.7">2</text><path className="n4-tk" d="M138.7 42.0L140.4 34.1" /><text className="n4-fl" x="136.2" y="58.7">3</text><path className="n4-tk" d="M172.9 57.2L177.6 50.7" /><text className="n4-fl" x="165.8" y="71.9">4</text><path className="n4-tk" d="M197.9 85.0L204.9 81.0" /><text className="n4-fl" x="187.5" y="96.0">5</text>
                <text className="n4-l404" x="207" y="122">404</text>
                <g className="n4-needle"><path d="M117 130L120 40l3 90z" fill="url(#uvq17-brass)" /></g>
                <circle cx="120" cy="130" r="10" fill="url(#uvq17-brass)" />
              </svg>
              <div className="n4-btns" role="group" aria-label="Elevator buttons">
                <button className="n4-fb" type="button" data-f="0" aria-pressed="false">0</button><button className="n4-fb" type="button" data-f="1" aria-pressed="false">1</button><button className="n4-fb" type="button" data-f="2" aria-pressed="false">2</button><button className="n4-fb" type="button" data-f="3" aria-pressed="false">3</button><button className="n4-fb" type="button" data-f="4" aria-pressed="false">4</button><button className="n4-fb" type="button" data-f="5" aria-pressed="false">5</button>
                <button className="n4-fb n4-x" type="button" data-f="404" aria-pressed="false">404</button>
              </div>
              <p className="n4-msg" aria-live="polite"></p>
            </div>
            <span className="n4-tag">Service elevator</span>
            <h1 className="n4-title">This elevator doesn't go to floor 404.</h1>
            <p className="n4-sub">The building has five floors and the page you're looking for isn't on any of them. Pick another or head down to the lobby.</p>
            <a className="n4-cta" href="/">Down to the lobby</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 “Art deco elevator 404” block (404) from AIMRAN Library to my project.

## What it is
A brass art deco dial shows the elevator floor; press 404 and the needle hits the end stop and trembles.

## Chosen settings
- Accent color: #f2b84b
- Speed: 1x (from 0.5 to 2x)
- Title: "Este ascensor no llega a la planta 404."
- Message: "El edificio tiene cinco plantas y la página que buscas no está en ninguna. Elige otra o baja al vestíbulo."
- Button: "Bajar al vestíbulo"

## 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 } from "react";

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

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

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

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

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

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

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

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

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

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

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

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

.n4-elevator {
  background: repeating-conic-gradient(from -90deg at 50% 112%,rgba(242,184,75,.07) 0 2deg,transparent 2deg 9deg),radial-gradient(80% 60% at 50% 30%,#241d12,#0b0906 75%);
  color: #f6ecd4;
  font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
}

.n4-elevator .n4-lift {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: min(2cqmin,14px);
  margin-bottom: .5cqmin;
}

.n4-elevator .n4-dial {
  width: 22em;
  height: auto;
  overflow: visible;
  filter: drop-shadow(0 1.2em 1.4em rgba(0,0,0,.6));
}

.n4-elevator .n4-ray {
  stroke: rgba(242,184,75,.16);
  stroke-width: 1;
}

.n4-elevator .n4-tk {
  stroke: #f1cf73;
  stroke-width: 2.4;
  stroke-linecap: round;
}

.n4-elevator .n4-fl {
  font: 500 15px "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  fill: #f6ecd4;
  text-anchor: middle;
}

.n4-elevator .n4-l404 {
  font: 700 11px ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  fill: #5a4a33;
  text-anchor: middle;
  transition: fill .3s;
}

.n4-elevator .n4-needle {
  transform-box: view-box;
  transform-origin: 120px 130px;
  transform: rotate(var(--a,-60deg));
  transition: transform calc(var(--d,1s) / var(--k)) cubic-bezier(.34,1.45,.5,1);
}

.n4-elevator .n4-lost .n4-needle {
  animation: n4-elevator-wob calc(.14s / var(--k)) linear infinite alternate;
}

.n4-elevator .n4-lost .n4-l404 {
  fill: #ff5b4a;
  filter: drop-shadow(0 0 4px #ff5b4a);
}

.n4-elevator .n4-btns {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .8em;
  margin-top: 1.2em;
  padding: .9em 1.2em;
  border-radius: 1em;
  background: linear-gradient(135deg,#2c261c,#14110b);
  box-shadow: inset 0 0 0 1px rgba(242,184,75,.35),0 1em 1.6em -1em #000;
}

.n4-elevator .n4-fb {
  width: 3.3em;
  height: 3.3em;
  min-width: 30px;
  min-height: 30px;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  font: 600 1.15em/1 "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  color: #1a140a;
  background: radial-gradient(circle at 40% 35%,#fff3c4,#d9a93f 55%,#8a5e14);
  box-shadow: 0 .2em 0 #5a3d0c,inset 0 0 0 .18em rgba(255,255,255,.25);
  transition: transform .12s,box-shadow .2s,filter .2s;
}

.n4-elevator .n4-fb.n4-x {
  width: auto;
  padding: 0 1em;
  border-radius: 999px;
  font-family: ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  font-size: 1em;
}

.n4-elevator .n4-fb:hover {
  filter: brightness(1.1);
}

.n4-elevator .n4-fb:active {
  transform: translateY(.15em);
  box-shadow: 0 .05em 0 #5a3d0c;
}

.n4-elevator .n4-fb[aria-pressed="true"] {
  box-shadow: 0 .2em 0 #5a3d0c,0 0 0 .2em #14110b,0 0 0 .38em var(--accent),0 0 1.4em var(--accent);
}

.n4-elevator .n4-fb:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 5px;
}

.n4-elevator .n4-msg {
  min-height: 1.3em;
  margin: .8em 0 0;
  font: 700 .95em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #ff6b5b;
}

.n4-elevator .n4-tag {
  font-family: "Futura","Century Gothic","Avenir Next","Gill Sans",system-ui,sans-serif;
  letter-spacing: .3em;
}

.n4-elevator .n4-title {
  font-size: clamp(20px,4.8cqmin,40px);
  font-weight: 500;
  letter-spacing: 0;
}

.n4-elevator .n4-sub {
  color: #c8b998;
}

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

@keyframes n4-elevator-wob {
  from {
    rotate: -1.2deg;
  }
  to {
    rotate: 1.8deg;
  }
}
`;

// 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 btns = el.querySelectorAll(".n4-fb");
  const lift = el.querySelector(".n4-lift");
  const msg = el.querySelector(".n4-msg");
  const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
  const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
  const pos = (f) => (f === 404 ? 7 : f);
  let cur = 0, timer = 0;
  const go = (b) => {
    const f = Number(b.dataset.f);
    const steps = Math.abs(pos(f) - pos(cur));
    clearTimeout(timer);
    btns.forEach((x) => x.setAttribute("aria-pressed", String(x === b)));
    lift.classList.remove("n4-lost");
    msg.textContent = "";
    lift.style.setProperty("--d", 0.4 + steps * 0.25 + "s");
    lift.style.setProperty("--a", (f === 404 ? 86 : -60 + 24 * f) + "deg");
    cur = f;
    timer = setTimeout(() => {
      if (f !== 404) b.setAttribute("aria-pressed", "false");
      else {
        lift.classList.add("n4-lost");
        msg.textContent = "This floor doesn't exist";
      }
    }, rm ? 0 : (400 + steps * 250) / k + 120);
  };
  btns.forEach((b) => b.addEventListener("click", () => go(b)));
  const auto = setTimeout(() => go(btns[btns.length - 1]), rm ? 0 : 900 / k);
  return () => { clearTimeout(timer); clearTimeout(auto); };
}

export default function NotFoundElevator() {
  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-elevator">
          <div className="n4-copy">
            <div className="n4-lift">
              <svg className="n4-dial" viewBox="0 0 240 140" aria-hidden="true">
                <defs><linearGradient id="uvq17-brass" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#f7dc8c" /><stop offset=".45" stopColor="#b8862b" /><stop offset=".7" stopColor="#f1cf73" /><stop offset="1" stopColor="#8a5e14" /></linearGradient></defs>
                <path d="M8 132A112 112 0 0 1 232 132Z" fill="url(#uvq17-brass)" />
                <path d="M20 130A100 100 0 0 1 220 130Z" fill="#15110b" />
                <path className="n4-ray" d="M98.3 126.2L47.1 117.2" /><path className="n4-ray" d="M99.3 122.5L50.5 104.7" /><path className="n4-ray" d="M100.9 119.0L55.9 93.0" /><path className="n4-ray" d="M103.1 115.9L63.3 82.4" /><path className="n4-ray" d="M105.9 113.1L72.4 73.3" /><path className="n4-ray" d="M109.0 110.9L83.0 65.9" /><path className="n4-ray" d="M112.5 109.3L94.7 60.5" /><path className="n4-ray" d="M116.2 108.3L107.2 57.1" /><path className="n4-ray" d="M120.0 108.0L120.0 56.0" /><path className="n4-ray" d="M123.8 108.3L132.8 57.1" /><path className="n4-ray" d="M127.5 109.3L145.3 60.5" /><path className="n4-ray" d="M131.0 110.9L157.0 65.9" /><path className="n4-ray" d="M134.1 113.1L167.6 73.3" /><path className="n4-ray" d="M136.9 115.9L176.7 82.4" /><path className="n4-ray" d="M139.1 119.0L184.1 93.0" /><path className="n4-ray" d="M140.7 122.5L189.5 104.7" /><path className="n4-ray" d="M141.7 126.2L192.9 117.2" /><path className="n4-tk" d="M42.1 85.0L35.1 81.0" /><text className="n4-fl" x="52.5" y="96.0">0</text><path className="n4-tk" d="M67.1 57.2L62.4 50.7" /><text className="n4-fl" x="74.2" y="71.9">1</text><path className="n4-tk" d="M101.3 42.0L99.6 34.1" /><text className="n4-fl" x="103.8" y="58.7">2</text><path className="n4-tk" d="M138.7 42.0L140.4 34.1" /><text className="n4-fl" x="136.2" y="58.7">3</text><path className="n4-tk" d="M172.9 57.2L177.6 50.7" /><text className="n4-fl" x="165.8" y="71.9">4</text><path className="n4-tk" d="M197.9 85.0L204.9 81.0" /><text className="n4-fl" x="187.5" y="96.0">5</text>
                <text className="n4-l404" x="207" y="122">404</text>
                <g className="n4-needle"><path d="M117 130L120 40l3 90z" fill="url(#uvq17-brass)" /></g>
                <circle cx="120" cy="130" r="10" fill="url(#uvq17-brass)" />
              </svg>
              <div className="n4-btns" role="group" aria-label="Elevator buttons">
                <button className="n4-fb" type="button" data-f="0" aria-pressed="false">0</button><button className="n4-fb" type="button" data-f="1" aria-pressed="false">1</button><button className="n4-fb" type="button" data-f="2" aria-pressed="false">2</button><button className="n4-fb" type="button" data-f="3" aria-pressed="false">3</button><button className="n4-fb" type="button" data-f="4" aria-pressed="false">4</button><button className="n4-fb" type="button" data-f="5" aria-pressed="false">5</button>
                <button className="n4-fb n4-x" type="button" data-f="404" aria-pressed="false">404</button>
              </div>
              <p className="n4-msg" aria-live="polite"></p>
            </div>
            <span className="n4-tag">Service elevator</span>
            <h1 className="n4-title">This elevator doesn't go to floor 404.</h1>
            <p className="n4-sub">The building has five floors and the page you're looking for isn't on any of them. Pick another or head down to the lobby.</p>
            <a className="n4-cta" href="/">Down to the lobby</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.
````
