Retro Grid — Free HTML CSS Synthwave Hero Background Snippet

Retro Grid · Heroes · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

CSS perspective floor
rotateX plus a low perspective recede the grid.
Seamless forward race
background-position shifts one tile and loops.
Gradient grid lines
Two layered gradients, no image.
Masked retro sun
Slats banded by a mask gradient.
Outrun palette
Indigo-to-magenta sky with neon type.
Glowing headline
Clipped gradient text with a soft glow.
Battery-aware
Animation pauses when the tab is hidden.
Runtime speed API
A tiny helper retunes the run speed.

About this UI Snippet

Retro Grid — Animated Synthwave Perspective Floor

Screenshot of the Retro Grid snippet rendered live

The retro grid is the 80s synthwave staple: a glowing neon grid floor that recedes to a horizon and races endlessly toward the viewer, lit by a striped retro sun. It is the backdrop of choice for vaporwave, outrun, and game-themed sites. This snippet builds the whole scene with pure CSS perspective and a couple of optional lines of JavaScript — no canvas, no images.

The perspective floor

The grid lives in a container with perspective: 240px and a child plane that is rotated flat with transform: rotateX(72deg) and transform-origin: bottom. That low perspective value combined with the steep rotation tips the plane almost flat and exaggerates the foreshortening, so the lines compress toward a vanishing point — the signature receding-floor look. The plane itself is just two layered linear-gradient backgrounds (pink horizontals, cyan verticals) tiled at 44px, the same graph-paper trick used for any CSS grid, here viewed in 3D.

Making it race forward

Animating the plane toward the viewer is a one-line keyframe: rgRun shifts background-position down by exactly one tile (44px) over 1.6 seconds and loops. Because the grid pattern repeats every 44px, moving by one full cell lands on an identical pattern, so the loop is seamless — the lines appear to stream continuously toward you with no visible jump. The plane is oversized (inset: -60% at the top) so the scrolling lines fill the perspective without revealing an edge near the horizon.

The retro sun

The sun is a circle filled with a vertical yellow-to-pink gradient and a soft glowing box-shadow. Its iconic horizontal slats come from an ::after pseudo-element: a repeating-linear-gradient of background-colored bars, masked so the stripes only appear across the lower half (mask: linear-gradient(transparent 55%, #000 55%)). That mask is what gives the classic synthwave sun its half-banded look without drawing each stripe by hand.

The color story

A vertical background gradient runs from deep indigo at the top through magenta to near-black at the bottom, so the sky glows behind the sun and darkens toward the grid. The headline uses a top-down background-clip: text gradient with a soft text-shadow glow, and the tag and copy use neon cyan and violet — all the hallmarks of the outrun palette. Everything is CSS, so recoloring the whole scene is a handful of values.

The optional script

The animation is entirely CSS, but two small JavaScript conveniences are included: a visibilitychange listener pauses the grid when the tab is hidden to spare the GPU, and a tiny window.retroGrid.speed(seconds) helper lets you retune the run speed at runtime (for example, to accelerate on a button press). Neither is required for the effect to work.

Customizing it

Change the perspective and rotateX to steepen or flatten the floor, adjust the 44px tile size for a denser or wider grid, retime rgRun for a faster or slower race, recolor the line gradients and sun, or move the horizon by resizing the grid container. Pair it with an aurora text headline or a pulse button for a complete retro hero.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA neon grid floor and a striped sun fill the hero.
  2. 2
    Watch it raceThe grid lines stream endlessly toward the horizon.
  3. 3
    Note the sunHorizontal slats band its lower half, synthwave style.
  4. 4
    Switch tabsThe grid pauses while hidden to save the GPU.
  5. 5
    Retune the speedCall window.retroGrid.speed(seconds) at runtime.
  6. 6
    Recolor the sceneEdit the gradient and sun colors.

Real-world uses

Common Use Cases

Synthwave landing pages
Pair with an aurora text headline.
Game and arcade sites
Set the mood behind a pulse button CTA.
Music and DJ pages
A retro backdrop for an app hero.
Event microsites
Frame a shiny text announcement.
Retro portfolios
An 80s alternative to a minimal hero.
CSS perspective demos
A reference for animated receding grids.

Got questions?

Frequently Asked Questions

The grid container has perspective: 240px and its child plane is rotated with rotateX(72deg) and transform-origin: bottom. The low perspective value plus the steep rotation tips the plane nearly flat and exaggerates the foreshortening, so the gridlines compress toward a vanishing point — the classic receding-floor look, all in CSS.

The rgRun keyframe shifts the plane background-position down by exactly one 44px tile and loops. Because the grid pattern repeats every 44px, moving by one full cell lands on an identical pattern, so the restart is invisible and the lines appear to stream continuously toward the viewer.

The sun is a circle with a vertical yellow-to-pink gradient and a glowing box-shadow. Its horizontal slats come from an ::after repeating-linear-gradient of background-colored bars, masked with a linear-gradient so the stripes only show across the lower half. The mask gives the iconic half-banded sun without drawing each stripe manually.

Not very — it animates only background-position on one element, which the compositor handles efficiently. A visibilitychange listener also pauses it when the tab is hidden to spare the GPU. For very low-end targets you can slow the keyframe or enlarge the tile size to reduce the number of lines.

The scene is pure CSS, so drop the markup into a component and keep the classes. Add the visibilitychange listener in a mount effect with cleanup, and expose the speed control as a prop that sets the animation-duration via a ref or inline style instead of the global helper. In Tailwind, build the plane with a bg-[linear-gradient(...)] arbitrary value and define the run keyframe in the config.

Retro Grid — Export as HTML, React, Vue, Angular & Tailwind

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Retro Grid</title>
  <style>
    *{box-sizing:border-box;margin:0;padding:0}
    body{font-family:system-ui,-apple-system,sans-serif;background:#0a0420;color:#fff}
    
    .rg-hero{position:relative;min-height:100vh;overflow:hidden;display:flex;align-items:center;justify-content:center;text-align:center;background:linear-gradient(180deg,#1a0b3a 0%,#2d0b4e 45%,#0a0420 75%)}
    
    .rg-grid{position:absolute;left:0;right:0;bottom:0;height:55%;perspective:240px;overflow:hidden}
    .rg-plane{position:absolute;inset:-60% 0 0 0;background-image:linear-gradient(rgba(236,72,153,.55) 1px,transparent 1px),linear-gradient(90deg,rgba(34,211,238,.55) 1px,transparent 1px);background-size:44px 44px;transform:rotateX(72deg);transform-origin:bottom;animation:rgRun 1.6s linear infinite}
    @keyframes rgRun{to{background-position:0 44px}}
    
    .rg-sun{position:absolute;top:24%;left:50%;width:260px;height:260px;border-radius:50%;transform:translate(-50%,-50%);background:linear-gradient(180deg,#fde047,#ec4899);box-shadow:0 0 90px 20px rgba(236,72,153,.45)}
    .rg-sun::after{content:'';position:absolute;inset:0;border-radius:50%;background:repeating-linear-gradient(180deg,transparent 0 14px,#0a0420 14px 18px);-webkit-mask:linear-gradient(180deg,transparent 55%,#000 55%);mask:linear-gradient(180deg,transparent 55%,#000 55%)}
    
    .rg-content{position:relative;z-index:1;padding:0 20px;max-width:600px}
    .rg-tag{display:inline-block;font-size:12px;font-weight:800;letter-spacing:.2em;color:#22d3ee;margin-bottom:16px;text-shadow:0 0 12px rgba(34,211,238,.7)}
    .rg-content h1{font-size:clamp(38px,9vw,84px);font-weight:900;letter-spacing:-.02em;text-transform:uppercase;background:linear-gradient(180deg,#fff,#f0abfc);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 0 40px rgba(240,171,252,.4)}
    .rg-content p{margin-top:14px;font-size:16px;color:#c4b5fd}
  </style>
</head>
<body>
  <section class="rg-hero">
    <div class="rg-grid" aria-hidden="true"><div class="rg-plane"></div></div>
    <div class="rg-sun" aria-hidden="true"></div>
    <div class="rg-content">
      <span class="rg-tag">★ SYNTHWAVE</span>
      <h1>Outrun the night</h1>
      <p>An animated neon grid floor racing toward the horizon — pure CSS perspective.</p>
    </div>
  </section>
  <script>
    // The grid is 100% CSS. This optional script lets you change the scroll speed
    // and pause it when the tab is hidden to save the GPU.
    var plane = document.querySelector('.rg-plane');
    
    document.addEventListener('visibilitychange', function () {
      plane.style.animationPlayState = document.hidden ? 'paused' : 'running';
    });
    
    // Expose a tiny API: window.retroGrid.speed(seconds) to retune the run speed.
    window.retroGrid = {
      speed: function (s) { plane.style.animationDuration = s + 's'; }
    };
  </script>
</body>
</html>
Tailwind
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Retro Grid</title>
  <!-- Tailwind CSS v3+ — arbitrary value classes (e.g. bg-[#0f172a]) are valid -->
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    @keyframes rgRun{to{background-position:0 44px}}

    * {
      box-sizing:border-box;margin:0;padding:0
    }

    body {
      font-family:system-ui,-apple-system,sans-serif;background:#0a0420;color:#fff
    }

    .rg-sun::after {
      content:'';position:absolute;inset:0;border-radius:50%;background:repeating-linear-gradient(180deg,transparent 0 14px,#0a0420 14px 18px);-webkit-mask:linear-gradient(180deg,transparent 55%,#000 55%);mask:linear-gradient(180deg,transparent 55%,#000 55%)
    }

    .rg-content h1 {
      font-size:clamp(38px,9vw,84px);font-weight:900;letter-spacing:-.02em;text-transform:uppercase;background:linear-gradient(180deg,#fff,#f0abfc);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 0 40px rgba(240,171,252,.4)
    }

    .rg-content p {
      margin-top:14px;font-size:16px;color:#c4b5fd
    }
  </style>
</head>
<body>
  <section class="relative min-h-screen overflow-hidden flex items-center justify-center text-center [background:linear-gradient(180deg,#1a0b3a_0%,#2d0b4e_45%,#0a0420_75%)]">
    <div class="absolute left-0 right-0 bottom-0 h-[55%] [perspective:240px] overflow-hidden" aria-hidden="true"><div class="rg-plane absolute inset-[-60% 0 0] [background-image:linear-gradient(rgba(236,72,153,.55)_1px,transparent_1px),linear-gradient(90deg,rgba(34,211,238,.55)_1px,transparent_1px)] bg-[size:44px_44px] [transform:rotateX(72deg)] [transform-origin:bottom] [animation:rgRun_1.6s_linear_infinite]"></div></div>
    <div class="rg-sun absolute top-[24%] left-1/2 w-[260px] h-[260px] rounded-full [transform:translate(-50%,-50%)] [background:linear-gradient(180deg,#fde047,#ec4899)] shadow-[0_0_90px_20px_rgba(236,72,153,.45)]" aria-hidden="true"></div>
    <div class="rg-content relative z-[1] py-0 px-5 max-w-[600px]">
      <span class="inline-block text-xs font-extrabold tracking-[.2em] text-[#22d3ee] mb-4 [text-shadow:0_0_12px_rgba(34,211,238,.7)]">★ SYNTHWAVE</span>
      <h1>Outrun the night</h1>
      <p>An animated neon grid floor racing toward the horizon — pure CSS perspective.</p>
    </div>
  </section>
  <script>
    // The grid is 100% CSS. This optional script lets you change the scroll speed
    // and pause it when the tab is hidden to save the GPU.
    var plane = document.querySelector('.rg-plane');
    
    document.addEventListener('visibilitychange', function () {
      plane.style.animationPlayState = document.hidden ? 'paused' : 'running';
    });
    
    // Expose a tiny API: window.retroGrid.speed(seconds) to retune the run speed.
    window.retroGrid = {
      speed: function (s) { plane.style.animationDuration = s + 's'; }
    };
  </script>
</body>
</html>
React
import React, { useEffect } from 'react';

// CSS — optionally move to RetroGrid.module.css
const css = `
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:system-ui,-apple-system,sans-serif;background:#0a0420;color:#fff}

.rg-hero{position:relative;min-height:100vh;overflow:hidden;display:flex;align-items:center;justify-content:center;text-align:center;background:linear-gradient(180deg,#1a0b3a 0%,#2d0b4e 45%,#0a0420 75%)}

.rg-grid{position:absolute;left:0;right:0;bottom:0;height:55%;perspective:240px;overflow:hidden}
.rg-plane{position:absolute;inset:-60% 0 0 0;background-image:linear-gradient(rgba(236,72,153,.55) 1px,transparent 1px),linear-gradient(90deg,rgba(34,211,238,.55) 1px,transparent 1px);background-size:44px 44px;transform:rotateX(72deg);transform-origin:bottom;animation:rgRun 1.6s linear infinite}
@keyframes rgRun{to{background-position:0 44px}}

.rg-sun{position:absolute;top:24%;left:50%;width:260px;height:260px;border-radius:50%;transform:translate(-50%,-50%);background:linear-gradient(180deg,#fde047,#ec4899);box-shadow:0 0 90px 20px rgba(236,72,153,.45)}
.rg-sun::after{content:'';position:absolute;inset:0;border-radius:50%;background:repeating-linear-gradient(180deg,transparent 0 14px,#0a0420 14px 18px);-webkit-mask:linear-gradient(180deg,transparent 55%,#000 55%);mask:linear-gradient(180deg,transparent 55%,#000 55%)}

.rg-content{position:relative;z-index:1;padding:0 20px;max-width:600px}
.rg-tag{display:inline-block;font-size:12px;font-weight:800;letter-spacing:.2em;color:#22d3ee;margin-bottom:16px;text-shadow:0 0 12px rgba(34,211,238,.7)}
.rg-content h1{font-size:clamp(38px,9vw,84px);font-weight:900;letter-spacing:-.02em;text-transform:uppercase;background:linear-gradient(180deg,#fff,#f0abfc);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 0 40px rgba(240,171,252,.4)}
.rg-content p{margin-top:14px;font-size:16px;color:#c4b5fd}
`;

export default function RetroGrid() {
  // Auto-generated escape hatch: the original snippet's vanilla JS runs once
  // after mount and queries the rendered DOM. For idiomatic React, lift this
  // into state + handlers.
  useEffect(() => {
    const _listeners = [];
    const _originalAddEventListener = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function(type, listener, options) {
      _listeners.push({ target: this, type, listener, options });
      return _originalAddEventListener.call(this, type, listener, options);
    };
    // The grid is 100% CSS. This optional script lets you change the scroll speed
    // and pause it when the tab is hidden to save the GPU.
    var plane = document.querySelector('.rg-plane');
    
    document.addEventListener('visibilitychange', function () {
      plane.style.animationPlayState = document.hidden ? 'paused' : 'running';
    });
    
    // Expose a tiny API: window.retroGrid.speed(seconds) to retune the run speed.
    window.retroGrid = {
      speed: function (s) { plane.style.animationDuration = s + 's'; }
    };
    // Cleanup: restore addEventListener and remove all listeners
    return () => {
      EventTarget.prototype.addEventListener = _originalAddEventListener;
      for (const { target, type, listener, options } of _listeners) {
        target.removeEventListener(type, listener, options);
      }
    };
  }, []);

  return (
    <>
      <style>{css}</style>
      <section className="rg-hero">
        <div className="rg-grid" aria-hidden="true"><div className="rg-plane"></div></div>
        <div className="rg-sun" aria-hidden="true"></div>
        <div className="rg-content">
          <span className="rg-tag">★ SYNTHWAVE</span>
          <h1>Outrun the night</h1>
          <p>An animated neon grid floor racing toward the horizon — pure CSS perspective.</p>
        </div>
      </section>
    </>
  );
}
React + Tailwind
import React, { useEffect } from 'react';
// Requires Tailwind CSS v3+ — https://tailwindcss.com/docs/installation
// Arbitrary value classes (e.g. bg-[#0f172a]) are valid Tailwind v3+

export default function RetroGrid() {
  // Auto-generated escape hatch: the original snippet's vanilla JS runs once
  // after mount and queries the rendered DOM. For idiomatic React, lift this
  // into state + handlers.
  useEffect(() => {
    const _listeners = [];
    const _originalAddEventListener = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function(type, listener, options) {
      _listeners.push({ target: this, type, listener, options });
      return _originalAddEventListener.call(this, type, listener, options);
    };
    // The grid is 100% CSS. This optional script lets you change the scroll speed
    // and pause it when the tab is hidden to save the GPU.
    var plane = document.querySelector('.rg-plane');
    
    document.addEventListener('visibilitychange', function () {
      plane.style.animationPlayState = document.hidden ? 'paused' : 'running';
    });
    
    // Expose a tiny API: window.retroGrid.speed(seconds) to retune the run speed.
    window.retroGrid = {
      speed: function (s) { plane.style.animationDuration = s + 's'; }
    };
    // Cleanup: restore addEventListener and remove all listeners
    return () => {
      EventTarget.prototype.addEventListener = _originalAddEventListener;
      for (const { target, type, listener, options } of _listeners) {
        target.removeEventListener(type, listener, options);
      }
    };
  }, []);

  return (
    <>
      <style>{`
@keyframes rgRun{to{background-position:0 44px}}

* {
  box-sizing:border-box;margin:0;padding:0
}

body {
  font-family:system-ui,-apple-system,sans-serif;background:#0a0420;color:#fff
}

.rg-sun::after {
  content:'';position:absolute;inset:0;border-radius:50%;background:repeating-linear-gradient(180deg,transparent 0 14px,#0a0420 14px 18px);-webkit-mask:linear-gradient(180deg,transparent 55%,#000 55%);mask:linear-gradient(180deg,transparent 55%,#000 55%)
}

.rg-content h1 {
  font-size:clamp(38px,9vw,84px);font-weight:900;letter-spacing:-.02em;text-transform:uppercase;background:linear-gradient(180deg,#fff,#f0abfc);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 0 40px rgba(240,171,252,.4)
}

.rg-content p {
  margin-top:14px;font-size:16px;color:#c4b5fd
}
      `}</style>
      <section className="relative min-h-screen overflow-hidden flex items-center justify-center text-center [background:linear-gradient(180deg,#1a0b3a_0%,#2d0b4e_45%,#0a0420_75%)]">
        <div className="absolute left-0 right-0 bottom-0 h-[55%] [perspective:240px] overflow-hidden" aria-hidden="true"><div className="rg-plane absolute inset-[-60% 0 0] [background-image:linear-gradient(rgba(236,72,153,.55)_1px,transparent_1px),linear-gradient(90deg,rgba(34,211,238,.55)_1px,transparent_1px)] bg-[size:44px_44px] [transform:rotateX(72deg)] [transform-origin:bottom] [animation:rgRun_1.6s_linear_infinite]"></div></div>
        <div className="rg-sun absolute top-[24%] left-1/2 w-[260px] h-[260px] rounded-full [transform:translate(-50%,-50%)] [background:linear-gradient(180deg,#fde047,#ec4899)] shadow-[0_0_90px_20px_rgba(236,72,153,.45)]" aria-hidden="true"></div>
        <div className="rg-content relative z-[1] py-0 px-5 max-w-[600px]">
          <span className="inline-block text-xs font-extrabold tracking-[.2em] text-[#22d3ee] mb-4 [text-shadow:0_0_12px_rgba(34,211,238,.7)]">★ SYNTHWAVE</span>
          <h1>Outrun the night</h1>
          <p>An animated neon grid floor racing toward the horizon — pure CSS perspective.</p>
        </div>
      </section>
    </>
  );
}
Vue
<template>
  <section class="rg-hero">
    <div class="rg-grid" aria-hidden="true"><div class="rg-plane"></div></div>
    <div class="rg-sun" aria-hidden="true"></div>
    <div class="rg-content">
      <span class="rg-tag">★ SYNTHWAVE</span>
      <h1>Outrun the night</h1>
      <p>An animated neon grid floor racing toward the horizon — pure CSS perspective.</p>
    </div>
  </section>
</template>

<script setup>
import { onMounted } from 'vue';

let plane;

onMounted(() => {
  plane = document.querySelector('.rg-plane');
  document.addEventListener('visibilitychange', function () {
    plane.style.animationPlayState = document.hidden ? 'paused' : 'running';
  });
  // Expose a tiny API: window.retroGrid.speed(seconds) to retune the run speed.
  window.retroGrid = {
    speed: function (s) { plane.style.animationDuration = s + 's'; }
  };
});
</script>

<style scoped>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:system-ui,-apple-system,sans-serif;background:#0a0420;color:#fff}

.rg-hero{position:relative;min-height:100vh;overflow:hidden;display:flex;align-items:center;justify-content:center;text-align:center;background:linear-gradient(180deg,#1a0b3a 0%,#2d0b4e 45%,#0a0420 75%)}

.rg-grid{position:absolute;left:0;right:0;bottom:0;height:55%;perspective:240px;overflow:hidden}
.rg-plane{position:absolute;inset:-60% 0 0 0;background-image:linear-gradient(rgba(236,72,153,.55) 1px,transparent 1px),linear-gradient(90deg,rgba(34,211,238,.55) 1px,transparent 1px);background-size:44px 44px;transform:rotateX(72deg);transform-origin:bottom;animation:rgRun 1.6s linear infinite}
@keyframes rgRun{to{background-position:0 44px}}

.rg-sun{position:absolute;top:24%;left:50%;width:260px;height:260px;border-radius:50%;transform:translate(-50%,-50%);background:linear-gradient(180deg,#fde047,#ec4899);box-shadow:0 0 90px 20px rgba(236,72,153,.45)}
.rg-sun::after{content:'';position:absolute;inset:0;border-radius:50%;background:repeating-linear-gradient(180deg,transparent 0 14px,#0a0420 14px 18px);-webkit-mask:linear-gradient(180deg,transparent 55%,#000 55%);mask:linear-gradient(180deg,transparent 55%,#000 55%)}

.rg-content{position:relative;z-index:1;padding:0 20px;max-width:600px}
.rg-tag{display:inline-block;font-size:12px;font-weight:800;letter-spacing:.2em;color:#22d3ee;margin-bottom:16px;text-shadow:0 0 12px rgba(34,211,238,.7)}
.rg-content h1{font-size:clamp(38px,9vw,84px);font-weight:900;letter-spacing:-.02em;text-transform:uppercase;background:linear-gradient(180deg,#fff,#f0abfc);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 0 40px rgba(240,171,252,.4)}
.rg-content p{margin-top:14px;font-size:16px;color:#c4b5fd}
</style>
Angular
// @ts-nocheck
// Note: vanilla JS DOM manipulation is preserved as-is inside ngAfterViewInit().
// For idiomatic Angular, replace document.getElementById() with @ViewChild() refs
// and move state into component properties with two-way binding.
import { Component, AfterViewInit, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-retro-grid',
  standalone: true,
  imports: [CommonModule],
  encapsulation: ViewEncapsulation.None,
  template: `
    <section class="rg-hero">
      <div class="rg-grid" aria-hidden="true"><div class="rg-plane"></div></div>
      <div class="rg-sun" aria-hidden="true"></div>
      <div class="rg-content">
        <span class="rg-tag">★ SYNTHWAVE</span>
        <h1>Outrun the night</h1>
        <p>An animated neon grid floor racing toward the horizon — pure CSS perspective.</p>
      </div>
    </section>
  `,
  styles: [`
    *{box-sizing:border-box;margin:0;padding:0}
    body{font-family:system-ui,-apple-system,sans-serif;background:#0a0420;color:#fff}
    
    .rg-hero{position:relative;min-height:100vh;overflow:hidden;display:flex;align-items:center;justify-content:center;text-align:center;background:linear-gradient(180deg,#1a0b3a 0%,#2d0b4e 45%,#0a0420 75%)}
    
    .rg-grid{position:absolute;left:0;right:0;bottom:0;height:55%;perspective:240px;overflow:hidden}
    .rg-plane{position:absolute;inset:-60% 0 0 0;background-image:linear-gradient(rgba(236,72,153,.55) 1px,transparent 1px),linear-gradient(90deg,rgba(34,211,238,.55) 1px,transparent 1px);background-size:44px 44px;transform:rotateX(72deg);transform-origin:bottom;animation:rgRun 1.6s linear infinite}
    @keyframes rgRun{to{background-position:0 44px}}
    
    .rg-sun{position:absolute;top:24%;left:50%;width:260px;height:260px;border-radius:50%;transform:translate(-50%,-50%);background:linear-gradient(180deg,#fde047,#ec4899);box-shadow:0 0 90px 20px rgba(236,72,153,.45)}
    .rg-sun::after{content:'';position:absolute;inset:0;border-radius:50%;background:repeating-linear-gradient(180deg,transparent 0 14px,#0a0420 14px 18px);-webkit-mask:linear-gradient(180deg,transparent 55%,#000 55%);mask:linear-gradient(180deg,transparent 55%,#000 55%)}
    
    .rg-content{position:relative;z-index:1;padding:0 20px;max-width:600px}
    .rg-tag{display:inline-block;font-size:12px;font-weight:800;letter-spacing:.2em;color:#22d3ee;margin-bottom:16px;text-shadow:0 0 12px rgba(34,211,238,.7)}
    .rg-content h1{font-size:clamp(38px,9vw,84px);font-weight:900;letter-spacing:-.02em;text-transform:uppercase;background:linear-gradient(180deg,#fff,#f0abfc);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 0 40px rgba(240,171,252,.4)}
    .rg-content p{margin-top:14px;font-size:16px;color:#c4b5fd}
  `]
})
export class RetroGridComponent implements AfterViewInit {
  ngAfterViewInit(): void {
    // The grid is 100% CSS. This optional script lets you change the scroll speed
    // and pause it when the tab is hidden to save the GPU.
    var plane = document.querySelector('.rg-plane');
    
    document.addEventListener('visibilitychange', function () {
      plane.style.animationPlayState = document.hidden ? 'paused' : 'running';
    });
    
    // Expose a tiny API: window.retroGrid.speed(seconds) to retune the run speed.
    window.retroGrid = {
      speed: function (s) { plane.style.animationDuration = s + 's'; }
    };
  }
}