/* ========================================================================== tui-pages website - animated ASCII art layer (chafa-rendered) Loaded AFTER site.css. Provides: - .tp-ascii-rain full-bleed body background, slow drifting pattern sourced from static/img/og-image-bg.svg All animations respect prefers-reduced-motion. ========================================================================== */ /* Body-wide ASCII art background ---------------------------------------- */ /* Fixed full-bleed layer behind all content. Renders a chafa output of the og-image-bg.svg (black background + "tui-pages" wordmark + headline + subtitle), drawn as ASCII glyphs in a single full-width tile. Two copies of the tile are stacked vertically and the whole track drifts slowly upward, looping seamlessly when the top copy exits the viewport. The hero is a static as designed - this file does NOT touch the hero. Regenerate the source tile with `make ascii` (uses chafa on static/img/og-image-bg.svg). The chafa output is in static/ascii/rain.txt and is 240 columns wide. */ .tp-ascii-rain { position: fixed; inset: 0; z-index: 0; /* sit above the page background, below the content */ pointer-events: none; opacity: 0.14; overflow: hidden; font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace; font-size: clamp(6px, 0.9vw, 9px); line-height: 1.05; color: #f4a26b; /* warm rust-orange tint, picks up the brand */ white-space: pre; text-shadow: 0 0 6px rgba(183, 65, 14, 0.25); /* faint phosphor glow */ will-change: transform; } /* The track holds two byte-identical copies of rain.txt stacked vertically. translateY(0 -> -50%) is a perfect seamless loop. */ .tp-ascii-rain-track { display: block; width: 100%; margin: 0; padding: 0; animation: tp-ascii-drift 90s linear infinite; will-change: transform; } .tp-ascii-rain-cell { display: block; white-space: pre; /* preserve the chafa line breaks */ } /* CRT scanlines overlay - a thin moving line every 2px. Faint so it doesn't fight the page content. */ .tp-ascii-rain::after { content: ""; position: absolute; inset: 0; background: repeating-linear-gradient( to bottom, transparent 0, transparent 2px, rgba(0, 0, 0, 0.18) 2px, rgba(0, 0, 0, 0.18) 3px ); pointer-events: none; animation: tp-ascii-scanline 8s linear infinite; } @keyframes tp-ascii-drift { 0% { transform: translateY(0); } 100% { transform: translateY(-50%); } } @keyframes tp-ascii-scanline { 0% { background-position: 0 0; } 100% { background-position: 0 6px; } } /* The hero text is high-contrast on its own (zinc-50 / accent), and the body ASCII rain is at 14% opacity. No overlay needed — the rain shows through everywhere. */ /* Light theme: invert to dark text on light, dimmer, no glow. */ :root[data-theme="light"] .tp-ascii-rain { opacity: 0.10; color: #1f1f23; text-shadow: none; mix-blend-mode: multiply; } :root[data-theme="light"] .tp-ascii-rain::after { background: repeating-linear-gradient( to bottom, transparent 0, transparent 2px, rgba(255, 255, 255, 0.12) 2px, rgba(255, 255, 255, 0.12) 3px ); } /* Reduced motion: pause the drift, keep the static background. */ @media (prefers-reduced-motion: reduce) { .tp-ascii-rain-track, .tp-ascii-rain::after { animation: none !important; transform: none !important; } }