| | import { useState, useEffect, useRef } from "react"; |
| |
|
| | const FONT_URL = "https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&display=swap"; |
| |
|
| | const TERMINAL_LINES = [ |
| | "INIT SEQUENCE 0x4F2A...", |
| | "AUTH TOKEN: ββββββββββββββ", |
| | "SCAN FREQ 847.221 MHz", |
| | "SECTOR [CLASSIFIED]", |
| | "NODE_ID NX-9912-DELTA", |
| | "TIMESTAMP 2025.03.06", |
| | "CLEARANCE LEVEL-OMEGA", |
| | "STATUS AUTHORIZED", |
| | "PAYLOAD ENCRYPTED", |
| | "UPLINK ACTIVE", |
| | "SIGNAL ββββββββ 61%", |
| | "VERIFY SHA256:c0d3f", |
| | "MATRIX 7Γ7 LATTICE", |
| | "HASH 0xDEADBEEF", |
| | "PING 12.4ms OK", |
| | "TRACE DISABLED", |
| | "VAULT SEALED", |
| | "PROTOCOL OMEGA-9", |
| | "ENTROPY HIGH", |
| | "FRAME #00441", |
| | "BUFFER FLUSHED", |
| | "CIPHER AES-256", |
| | "RELAY PROXIED", |
| | "ECHO SILENT", |
| | "LOCK ENGAGED", |
| | "GRID REF 44.0N 76.2W", |
| | "KERNEL 3.14.159", |
| | "DAEMON RUNNING", |
| | "WATCHDOG ARMED", |
| | "ROUTE OBFUSCATED", |
| | ]; |
| |
|
| | |
| | function GrainOverlay({ strength = 0.18 }) { |
| | const canvasRef = useRef(); |
| | const tick = useRef(0); |
| |
|
| | useEffect(() => { |
| | const canvas = canvasRef.current; |
| | if (!canvas) return; |
| | const ctx = canvas.getContext("2d"); |
| | let raf; |
| |
|
| | const draw = () => { |
| | tick.current++; |
| | if (tick.current % 2 !== 0) { raf = requestAnimationFrame(draw); return; } |
| | const { width, height } = canvas; |
| | const img = ctx.createImageData(width, height); |
| | const d = img.data; |
| | for (let i = 0; i < d.length; i += 4) { |
| | const px = i / 4; |
| | const x = px % width; |
| | const y = Math.floor(px / width); |
| | const cx = x / width - 0.5, cy = y / height - 0.5; |
| | const dist = Math.sqrt(cx * cx + cy * cy); |
| | const vignette = Math.min(1, dist * 2.2); |
| | const noise = (Math.random() - 0.5) * 255 * (strength + vignette * 0.18); |
| | d[i] = d[i + 1] = d[i + 2] = 128 + noise; |
| | d[i + 3] = Math.floor(18 + vignette * 30); |
| | } |
| | ctx.putImageData(img, 0, 0); |
| | raf = requestAnimationFrame(draw); |
| | }; |
| |
|
| | const resize = () => { |
| | canvas.width = canvas.offsetWidth; |
| | canvas.height = canvas.offsetHeight; |
| | }; |
| | resize(); |
| | draw(); |
| | window.addEventListener("resize", resize); |
| | return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", resize); }; |
| | }, [strength]); |
| |
|
| | return ( |
| | <canvas |
| | ref={canvasRef} |
| | style={{ |
| | position: "absolute", inset: 0, width: "100%", height: "100%", |
| | pointerEvents: "none", mixBlendMode: "overlay", zIndex: 10, |
| | }} |
| | /> |
| | ); |
| | } |
| |
|
| | |
| | function GeometricOverlay() { |
| | return ( |
| | <svg |
| | viewBox="0 0 480 860" |
| | style={{ |
| | position: "absolute", inset: 0, width: "100%", height: "100%", |
| | pointerEvents: "none", zIndex: 5, opacity: 0.08, |
| | }} |
| | preserveAspectRatio="none" |
| | > |
| | <polygon points="0,0 72,0 0,72" fill="none" stroke="white" strokeWidth="0.8" /> |
| | <polygon points="480,0 408,0 480,72" fill="none" stroke="white" strokeWidth="0.8" /> |
| | <polygon points="0,860 72,860 0,788" fill="none" stroke="white" strokeWidth="0.8" /> |
| | <polygon points="480,860 408,860 480,788" fill="none" stroke="white" strokeWidth="0.8" /> |
| | {[0.2, 0.4, 0.6, 0.8].map((t) => ( |
| | <line key={t} x1={480 * t} y1="0" x2={480 * t} y2="860" stroke="white" strokeWidth="0.4" /> |
| | ))} |
| | {[0.25, 0.5, 0.75].map((t) => ( |
| | <line key={t} x1="0" y1={860 * t} x2="480" y2={860 * t} stroke="white" strokeWidth="0.4" /> |
| | ))} |
| | <line x1="240" y1="430" x2="0" y2="0" stroke="white" strokeWidth="0.3" /> |
| | <line x1="240" y1="430" x2="480" y2="0" stroke="white" strokeWidth="0.3" /> |
| | <line x1="240" y1="430" x2="0" y2="860" stroke="white" strokeWidth="0.3" /> |
| | <line x1="240" y1="430" x2="480" y2="860" stroke="white" strokeWidth="0.3" /> |
| | <circle cx="240" cy="430" r="200" fill="none" stroke="white" strokeWidth="0.5" /> |
| | </svg> |
| | ); |
| | } |
| |
|
| | |
| | function TerminalMask() { |
| | const [offset, setOffset] = useState(0); |
| | const [glitch, setGlitch] = useState({ row: -1, px: 0 }); |
| |
|
| | useEffect(() => { |
| | const iv = setInterval(() => { |
| | setOffset((o) => (o + 1) % TERMINAL_LINES.length); |
| | }, 120); |
| | const gv = setInterval(() => { |
| | setGlitch({ row: Math.floor(Math.random() * 18), px: (Math.random() - 0.5) * 8 }); |
| | setTimeout(() => setGlitch({ row: -1, px: 0 }), 80); |
| | }, 900); |
| | return () => { clearInterval(iv); clearInterval(gv); }; |
| | }, []); |
| |
|
| | const visible = Array.from({ length: 20 }, (_, i) => |
| | TERMINAL_LINES[(offset + i) % TERMINAL_LINES.length] |
| | ); |
| |
|
| | return ( |
| | <div style={{ |
| | width: "100%", height: "100%", |
| | background: "#000", |
| | borderRadius: "50%", |
| | overflow: "hidden", |
| | display: "flex", |
| | flexDirection: "column", |
| | justifyContent: "center", |
| | padding: "18px 14px", |
| | gap: 0, |
| | position: "relative", |
| | }}> |
| | <div style={{ |
| | position: "absolute", inset: 0, borderRadius: "50%", |
| | background: "radial-gradient(ellipse at center, transparent 30%, rgba(0,0,0,0.72) 100%)", |
| | zIndex: 2, pointerEvents: "none", |
| | }} /> |
| | {visible.map((line, i) => ( |
| | <div key={i} style={{ |
| | fontFamily: "'IBM Plex Mono', monospace", |
| | fontSize: "9.5px", |
| | fontWeight: i === 0 ? 700 : 400, |
| | letterSpacing: "0.08em", |
| | color: i === 0 ? "#FFFFFF" : i < 3 ? "#D8D8D8" : "#888", |
| | lineHeight: "1.55", |
| | opacity: i === 0 ? 1 : Math.max(0.18, 1 - i * 0.045), |
| | transform: glitch.row === i ? `translateX(${glitch.px}px)` : "none", |
| | whiteSpace: "nowrap", |
| | overflow: "hidden", |
| | textOverflow: "ellipsis", |
| | transition: "transform 0.04s", |
| | position: "relative", |
| | zIndex: 3, |
| | }}> |
| | {i === 0 ? "βΆ " : " "}{line} |
| | </div> |
| | ))} |
| | </div> |
| | ); |
| | } |
| |
|
| | |
| | function Barcode() { |
| | const bars = Array.from({ length: 60 }, (_, i) => { |
| | const w = [1, 1, 2, 1, 3, 1, 2, 1, 1, 2][i % 10]; |
| | return { w, gap: [2, 1, 2, 3, 1, 2, 1, 2, 3, 1][i % 10] }; |
| | }); |
| | return ( |
| | <svg width="160" height="36" viewBox="0 0 160 36"> |
| | {bars.reduce((acc, bar, i) => { |
| | const x = acc.x; |
| | acc.elements.push( |
| | <rect key={i} x={x} y={2} width={bar.w} height={28} fill="white" /> |
| | ); |
| | acc.x += bar.w + bar.gap; |
| | return acc; |
| | }, { x: 2, elements: [] }).elements} |
| | </svg> |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | function TicketShell({ children, stubHeight = 120 }) { |
| | const W = 460; |
| | const H = 820; |
| | const R = 14; |
| | const PR = 9; |
| | const SR = 11; |
| | const tearY = H - stubHeight; |
| |
|
| | |
| | const zigzagLR = (x0, x1, y, dir) => { |
| | const count = Math.floor((x1 - x0) / (PR * 2.2)); |
| | const step = (x1 - x0) / count; |
| | let d = ""; |
| | for (let i = 0; i < count; i++) { |
| | const mx = x0 + i * step + step / 2; |
| | const ex = x0 + (i + 1) * step; |
| | d += ` L ${mx} ${y + dir * PR} L ${ex} ${y}`; |
| | } |
| | return d; |
| | }; |
| |
|
| | |
| | const zigzagRL = (x0, x1, y, dir) => { |
| | const count = Math.floor((x1 - x0) / (PR * 2.2)); |
| | const step = (x1 - x0) / count; |
| | let d = ""; |
| | for (let i = count - 1; i >= 0; i--) { |
| | const mx = x0 + i * step + step / 2; |
| | const ex = x0 + i * step; |
| | d += ` L ${mx} ${y + dir * PR} L ${ex} ${y}`; |
| | } |
| | return d; |
| | }; |
| |
|
| | const pad = 2; |
| | const x0 = pad + R, x1 = W - pad - R; |
| | const y0 = pad, y1 = H - pad; |
| |
|
| | |
| | |
| | const rightX = W - pad; |
| | const leftX = pad; |
| |
|
| | |
| | const path = [ |
| | `M ${x0} ${y0}`, |
| | |
| | zigzagLR(x0, x1, y0, -1), |
| | |
| | `L ${W - pad - R} ${y0}`, |
| | `Q ${W - pad} ${y0} ${W - pad} ${y0 + R}`, |
| | |
| | `L ${rightX} ${tearY - SR}`, |
| | |
| | `L ${rightX - SR} ${tearY}`, |
| | `L ${rightX} ${tearY + SR}`, |
| | |
| | `L ${rightX} ${y1 - R}`, |
| | |
| | `Q ${rightX} ${y1} ${x1} ${y1}`, |
| | |
| | `L ${x1} ${y1}`, |
| | zigzagRL(x0, x1, y1, 1), |
| | |
| | `L ${x0} ${y1}`, |
| | `Q ${leftX} ${y1} ${leftX} ${y1 - R}`, |
| | |
| | `L ${leftX} ${tearY + SR}`, |
| | |
| | `L ${leftX + SR} ${tearY}`, |
| | `L ${leftX} ${tearY - SR}`, |
| | |
| | `L ${leftX} ${y0 + R}`, |
| | |
| | `Q ${leftX} ${y0} ${x0} ${y0}`, |
| | `Z`, |
| | ].join(" "); |
| |
|
| | const clipId = "ticket-clip"; |
| | const innerId = "ticket-inner"; |
| |
|
| | return ( |
| | <div style={{ position: "relative", width: "100%", maxWidth: 460 }}> |
| | {/* SVG defs for clip path */} |
| | <svg width="0" height="0" style={{ position: "absolute" }}> |
| | <defs> |
| | <clipPath id={clipId} clipPathUnits="userSpaceOnUse"> |
| | <path d={path} /> |
| | </clipPath> |
| | </defs> |
| | </svg> |
| | |
| | {/* Outer shadow/glow layer */} |
| | <div style={{ |
| | position: "absolute", |
| | inset: -2, |
| | borderRadius: 18, |
| | boxShadow: "0 40px 100px rgba(0,0,0,0.95), 0 0 0 1px #1a1a1a", |
| | pointerEvents: "none", |
| | zIndex: 0, |
| | }} /> |
| | |
| | {/* The actual ticket content clipped to shape */} |
| | <div |
| | style={{ |
| | position: "relative", |
| | width: "100%", |
| | clipPath: `url(#${clipId})`, |
| | // Fallback border for browsers without clipPath |
| | }} |
| | > |
| | {/* SVG border drawn on top of content */} |
| | <svg |
| | viewBox={`0 0 ${W} ${H}`} |
| | width="100%" |
| | style={{ |
| | position: "absolute", inset: 0, width: "100%", height: "100%", |
| | pointerEvents: "none", zIndex: 50, |
| | }} |
| | preserveAspectRatio="none" |
| | > |
| | {/* Outer border */} |
| | <path |
| | d={path} |
| | fill="none" |
| | stroke="#2e2e2e" |
| | strokeWidth="1.2" |
| | /> |
| | {/* Inner inset border */} |
| | <path |
| | d={path} |
| | fill="none" |
| | stroke="#1e1e1e" |
| | strokeWidth="3" |
| | strokeDasharray="4 3" |
| | opacity="0.5" |
| | /> |
| | |
| | {/* Tear-line dashed rule */} |
| | <line |
| | x1={pad + SR + 4} y1={tearY} |
| | x2={W - pad - SR - 4} y2={tearY} |
| | stroke="#2a2a2a" |
| | strokeWidth="1" |
| | strokeDasharray="5 4" |
| | /> |
| | {/* Tear scissors icon hint */} |
| | <text x={W / 2 - 10} y={tearY - 5} fill="#333" fontSize="9" fontFamily="monospace" textAnchor="middle">β TEAR</text> |
| | |
| | {/* Corner punch holes β diamond arrowhead shapes */} |
| | {[ |
| | [pad + 28, pad + 28], |
| | [W - pad - 28, pad + 28], |
| | [pad + 28, H - pad - 28], |
| | [W - pad - 28, H - pad - 28], |
| | ].map(([cx, cy], i) => { |
| | const ro = 9; |
| | const ri = 4.5; |
| | return ( |
| | <g key={i}> |
| | <polygon |
| | points={`${cx},${cy - ro} ${cx + ro},${cy} ${cx},${cy + ro} ${cx - ro},${cy}`} |
| | fill="#0A0A0A" stroke="#2e2e2e" strokeWidth="1" |
| | /> |
| | <polygon |
| | points={`${cx},${cy - ri} ${cx + ri},${cy} ${cx},${cy + ri} ${cx - ri},${cy}`} |
| | fill="none" stroke="#252525" strokeWidth="0.8" |
| | /> |
| | </g> |
| | ); |
| | })} |
| | |
| | {/* Perforation diamond dots along tear line */} |
| | {Array.from({ length: 18 }, (_, i) => { |
| | const spacing = (W - pad * 2 - SR * 2 - 20) / 17; |
| | const x = pad + SR + 10 + i * spacing; |
| | const r = 2.2; |
| | return ( |
| | <polygon |
| | key={i} |
| | points={`${x},${tearY - r} ${x + r},${tearY} ${x},${tearY + r} ${x - r},${tearY}`} |
| | fill="#252525" |
| | /> |
| | ); |
| | })} |
| | </svg> |
| | |
| | {children} |
| | </div> |
| | </div> |
| | ); |
| | } |
| |
|
| | |
| | export default function CyberTicket() { |
| | const [pulse, setPulse] = useState(false); |
| |
|
| | useEffect(() => { |
| | if (!document.getElementById("ibm-plex-mono")) { |
| | const link = document.createElement("link"); |
| | link.id = "ibm-plex-mono"; |
| | link.rel = "stylesheet"; |
| | link.href = FONT_URL; |
| | document.head.appendChild(link); |
| | } |
| | const iv = setInterval(() => setPulse((p) => !p), 1400); |
| | return () => clearInterval(iv); |
| | }, []); |
| |
|
| | const STUB_H = 130; |
| |
|
| | return ( |
| | <div |
| | style={{ |
| | minHeight: "100vh", |
| | background: "#060606", |
| | display: "flex", |
| | alignItems: "center", |
| | justifyContent: "center", |
| | padding: "60px 16px", |
| | fontFamily: "'IBM Plex Mono', monospace", |
| | position: "relative", |
| | overflow: "hidden", |
| | }} |
| | > |
| | {/* ambient radial glow */} |
| | <div style={{ |
| | position: "absolute", |
| | width: 600, height: 600, |
| | background: "radial-gradient(circle, rgba(255,255,255,0.015) 0%, transparent 70%)", |
| | left: "50%", top: "50%", |
| | transform: "translate(-50%,-50%)", |
| | pointerEvents: "none", |
| | }} /> |
| | <GrainOverlay strength={0.13} /> |
| | |
| | <TicketShell stubHeight={130}> |
| | {/* ββ background fill */} |
| | <div style={{ |
| | background: "#0A0A0A", |
| | minHeight: 820, |
| | position: "relative", |
| | overflow: "hidden", |
| | }}> |
| | <GrainOverlay strength={0.2} /> |
| | <GeometricOverlay /> |
| | |
| | {/* 1 ββ TOP HEADER BAR */} |
| | <div style={{ |
| | background: "#0f0f0f", |
| | borderBottom: "1px solid #1e1e1e", |
| | padding: "16px 28px", |
| | display: "flex", |
| | alignItems: "center", |
| | justifyContent: "space-between", |
| | position: "relative", |
| | zIndex: 20, |
| | marginTop: 14, // clear top scallop |
| | }}> |
| | <div> |
| | <div style={{ |
| | fontSize: 9, fontWeight: 700, letterSpacing: "0.32em", |
| | color: "#FFF", textTransform: "uppercase", |
| | }}>NEXUS PROTOCOL</div> |
| | <div style={{ fontSize: 7.5, color: "#555", letterSpacing: "0.18em", marginTop: 1 }}> |
| | CLASSIFIED ACCESS DOCUMENT |
| | </div> |
| | </div> |
| | <div style={{ textAlign: "right" }}> |
| | <div style={{ fontSize: 9, color: "#555", letterSpacing: "0.1em" }}>Ξ©-09</div> |
| | <div style={{ fontSize: 7, color: "#333", marginTop: 1 }}>Β© 2025</div> |
| | </div> |
| | </div> |
| | |
| | {/* 2 ββ BRANDING BLOCK */} |
| | <div style={{ padding: "22px 32px 14px", position: "relative", zIndex: 20 }}> |
| | <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 6 }}> |
| | <svg width="28" height="28" viewBox="0 0 28 28" fill="none"> |
| | <circle cx="14" cy="14" r="13" stroke="white" strokeWidth="1" /> |
| | <path d="M4 14 Q7 8 10 14 Q13 20 16 14 Q19 8 22 14 Q24 18 24 14" |
| | stroke="white" strokeWidth="1.2" fill="none" strokeLinecap="round" /> |
| | <circle cx="14" cy="14" r="2" fill="white" /> |
| | </svg> |
| | <div> |
| | <div style={{ |
| | fontSize: 22, fontWeight: 700, letterSpacing: "0.18em", |
| | color: "#FFF", textTransform: "uppercase", lineHeight: 1, |
| | }}>NEURAL</div> |
| | <div style={{ |
| | fontSize: 22, fontWeight: 400, letterSpacing: "0.34em", |
| | color: "#666", textTransform: "uppercase", lineHeight: 1, marginTop: 2, |
| | }}>ACCESS</div> |
| | </div> |
| | </div> |
| | <div style={{ |
| | fontSize: 7.5, color: "#383838", letterSpacing: "0.22em", textTransform: "uppercase", |
| | }}> |
| | HIGH-CLEARANCE ADMISSION β SERIES 9 β OMEGA TIER |
| | </div> |
| | </div> |
| | |
| | {/* 3 ββ TERMINAL CIRCLE */} |
| | <div style={{ |
| | padding: "0 28px", position: "relative", zIndex: 20, |
| | display: "flex", justifyContent: "center", |
| | }}> |
| | <div style={{ |
| | width: 250, height: 250, |
| | borderRadius: "50%", |
| | border: "1px solid #2a2a2a", |
| | overflow: "hidden", |
| | position: "relative", |
| | boxShadow: "0 0 0 6px #0e0e0e, 0 0 0 7px #1e1e1e", |
| | }}> |
| | <TerminalMask /> |
| | <GrainOverlay strength={0.26} /> |
| | </div> |
| | </div> |
| | |
| | {/* scan status pill */} |
| | <div style={{ |
| | display: "flex", justifyContent: "center", marginTop: 12, |
| | position: "relative", zIndex: 20, |
| | }}> |
| | <div style={{ |
| | display: "flex", alignItems: "center", gap: 6, |
| | border: "1px solid #222", borderRadius: 999, |
| | padding: "4px 14px", |
| | background: "#0d0d0d", |
| | }}> |
| | <div style={{ |
| | width: 5, height: 5, borderRadius: "50%", |
| | background: pulse ? "#FFF" : "#333", |
| | transition: "background 0.4s", |
| | }} /> |
| | <span style={{ fontSize: 7.5, letterSpacing: "0.2em", color: "#666", textTransform: "uppercase" }}> |
| | SIGNAL {pulse ? "ACTIVE" : "PINGING"} |
| | </span> |
| | </div> |
| | </div> |
| | |
| | {/* 4 ββ INFO GRID */} |
| | <div style={{ |
| | padding: "24px 32px 0", |
| | position: "relative", zIndex: 20, |
| | display: "grid", gridTemplateColumns: "1fr 1fr", gap: "16px 12px", |
| | }}> |
| | {[ |
| | { label: "BEARER", value: "AGENT_NX-44" }, |
| | { label: "ISSUED", value: "2025.03.06" }, |
| | { label: "CLEARANCE", value: "OMEGA / Ξ©" }, |
| | { label: "EXPIRES", value: "2025.12.31" }, |
| | { label: "SECTOR", value: "DELTA-9" }, |
| | { label: "NODE", value: "0xDEADΒ·BF9" }, |
| | ].map(({ label, value }) => ( |
| | <div key={label}> |
| | <div style={{ |
| | fontSize: 7, color: "#3a3a3a", letterSpacing: "0.28em", |
| | textTransform: "uppercase", marginBottom: 3, |
| | }}>{label}</div> |
| | <div style={{ |
| | fontSize: 11, color: "#CDCDCD", letterSpacing: "0.1em", |
| | fontWeight: 600, |
| | }}>{value}</div> |
| | </div> |
| | ))} |
| | </div> |
| | |
| | {/* subtle divider */} |
| | <div style={{ padding: "22px 32px 0", position: "relative", zIndex: 20 }}> |
| | <div style={{ display: "flex", gap: 6, alignItems: "center" }}> |
| | {Array.from({ length: 3 }).map((_, i) => ( |
| | <div key={i} style={{ flex: 1, height: "1px", background: i === 1 ? "#222" : "#161616" }} /> |
| | ))} |
| | <svg width="10" height="10" viewBox="0 0 10 10" fill="none" style={{ opacity: 0.3 }}> |
| | <polygon points="5,0 10,10 0,10" stroke="white" strokeWidth="1" fill="none" /> |
| | </svg> |
| | {Array.from({ length: 3 }).map((_, i) => ( |
| | <div key={i} style={{ flex: 1, height: "1px", background: i === 1 ? "#222" : "#161616" }} /> |
| | ))} |
| | </div> |
| | </div> |
| | |
| | {/* ββ STUB SECTION (below tear line) ββ */} |
| | {/* Spacer to push stub below the scalloped tear cutout */} |
| | <div style={{ height: 36 }} /> |
| | |
| | <div style={{ |
| | padding: "4px 32px 32px", |
| | position: "relative", zIndex: 20, |
| | display: "flex", alignItems: "center", justifyContent: "space-between", |
| | }}> |
| | {/* Barcode */} |
| | <div> |
| | <Barcode /> |
| | <div style={{ fontSize: 7, color: "#2e2e2e", letterSpacing: "0.16em", marginTop: 3 }}> |
| | NX-9912-DELTA-44-0x2F |
| | </div> |
| | </div> |
| | {/* Stamp area */} |
| | <div style={{ textAlign: "right" }}> |
| | <div style={{ display: "flex", gap: 6, justifyContent: "flex-end", marginBottom: 6 }}> |
| | {["β
", "β", "β²"].map((icon, i) => ( |
| | <span key={i} style={{ |
| | fontSize: i === 0 ? 11 : 9, color: "#3a3a3a", fontFamily: "monospace", |
| | }}>{icon}</span> |
| | ))} |
| | </div> |
| | <div style={{ |
| | fontSize: 7, color: "#333", letterSpacing: "0.22em", |
| | textTransform: "uppercase", lineHeight: 1.7, |
| | }}> |
| | ADMIT<br />ONE |
| | </div> |
| | </div> |
| | </div> |
| | |
| | {/* bottom vignette */} |
| | <div style={{ |
| | position: "absolute", bottom: 0, left: 0, right: 0, height: 80, |
| | background: "linear-gradient(to top, rgba(0,0,0,0.6), transparent)", |
| | pointerEvents: "none", zIndex: 8, |
| | }} /> |
| | </div> |
| | </TicketShell> |
| | |
| | {/* ambient page label */} |
| | <div style={{ |
| | position: "absolute", bottom: 18, left: "50%", transform: "translateX(-50%)", |
| | fontSize: 7.5, letterSpacing: "0.3em", color: "#222", |
| | fontFamily: "'IBM Plex Mono', monospace", textTransform: "uppercase", |
| | zIndex: 20, whiteSpace: "nowrap", |
| | }}> |
| | NEXUS PROTOCOL β DOCUMENT RENDER v9.1 β CLASSIFIED |
| | </div> |
| | </div> |
| | ); |
| | } |