diff --git a/index.html b/index.html index 27140c0..9c968f6 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ name="description" content="amerc is an agent mercenary layer for embedding, bringing, and hosting agents across vertical software boundaries." /> - + diff --git a/package.json b/package.json index e92c04e..3727b6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "amerc-site", - "version": "0.22.1-tavern", + "version": "0.23.0-hero", "private": true, "type": "module", "scripts": { diff --git a/public/scene2d/tavern-hero.jpg b/public/scene2d/tavern-hero.jpg new file mode 100644 index 0000000..e28edf1 Binary files /dev/null and b/public/scene2d/tavern-hero.jpg differ diff --git a/public/scene2d/tavern-hero.png b/public/scene2d/tavern-hero.png new file mode 100644 index 0000000..3ca0a43 Binary files /dev/null and b/public/scene2d/tavern-hero.png differ diff --git a/src/Scene2D.jsx b/src/Scene2D.jsx index d2f045b..2b89a5e 100644 --- a/src/Scene2D.jsx +++ b/src/Scene2D.jsx @@ -2,10 +2,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Menu, X } from 'lucide-react'; import { useAuth, AuthPanel, AdminConsole } from './Auth.jsx'; import { AgentBrowse, BoothDashboard } from './AgentPlatform.jsx'; -import TopDownTavern from './TopDownTavern.jsx'; import { api } from './api.js'; -const RELEASE = '0.22.1-tavern'; +const RELEASE = '0.23.0-hero'; const NAV = [ { id: 'home', label: 'Tavern' }, @@ -64,36 +63,38 @@ function PixelTopbar({ route, setRoute, auth }) { ); } -function StatsStrip() { - const [s, setS] = useState(null); - useEffect(() => { api('/agents/stats').then(setS).catch(() => {}); }, []); - const items = [ - ['classes', 'agent classes'], ['instances', 'instances'], ['online', 'online now'], - ['sessions', 'live sessions'], ['owners', 'publishers'], - ]; - return ( -
- {items.map(([k, label]) => ( -
{s ? s[k] : '—'}{label}
- ))} -
+function Home({ setRoute, auth }) { + const [stats, setStats] = useState(null); + useEffect(() => { api('/agents/stats').then(setStats).catch(() => {}); }, []); + const Hot = ({ s, to, title, glow }) => ( + - +
+
+ amerc — hire agents like mercenaries + {/* top nav, over the painted bar */} + + + + + + + {/* big interactive zones */} + + + + {/* live platform stat chips (subtle, bottom-left — keeps the art clean) */} + {stats && ( +
+ {stats.classes} classes + {stats.online} online + {stats.sessions} sessions
-
- + )} + {auth?.user + ?
{auth.user.handle}{auth.user.role === 'admin' ? ' · admin' : ''} ·
+ : null}
); @@ -102,7 +103,7 @@ function Home({ setRoute }) { function Page({ children }) { return
{children}
; } function Scene({ route, setRoute, auth }) { - if (route === 'home') return ; + if (route === 'home') return ; if (route === 'agents') return ; if (route === 'booth') return ; if (route === 'signin') return
@@ -122,7 +123,7 @@ export default function Scene2DApp() { return (

amerc agent mercenary tavern

- + {route !== 'home' && }
); diff --git a/src/TopDownTavern.jsx b/src/TopDownTavern.jsx deleted file mode 100644 index 22a3335..0000000 --- a/src/TopDownTavern.jsx +++ /dev/null @@ -1,159 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react'; - -// Painterly 3/4 top-down RPG tavern — smooth high-res canvas, warm lighting, -// cohesive with the painted character sprites. -const W = 1200, H = 760; -const rnd = (s) => { let x = Math.sin(s * 127.1) * 43758.5453; return x - Math.floor(x); }; - -function roundRect(ctx, x, y, w, h, r) { ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); } -function ellipse(ctx, x, y, rx, ry, c) { ctx.fillStyle = c; ctx.beginPath(); ctx.ellipse(x, y, rx, ry, 0, 0, 7); ctx.fill(); } - -function buildScene(buf) { - const ctx = buf.getContext('2d'); - // ---- floor: warm wood with radial light + planks ---- - const fg = ctx.createLinearGradient(0, 180, 0, H); - fg.addColorStop(0, '#5a3a20'); fg.addColorStop(0.5, '#6e4727'); fg.addColorStop(1, '#4a2e18'); - ctx.fillStyle = fg; ctx.fillRect(0, 180, W, H - 180); - for (let y = 200; y < H; y += 46) { // plank seams (perspective: wider toward bottom) - ctx.strokeStyle = 'rgba(40,24,12,0.55)'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke(); - ctx.strokeStyle = 'rgba(150,100,60,0.10)'; ctx.beginPath(); ctx.moveTo(0, y + 2); ctx.lineTo(W, y + 2); ctx.stroke(); - for (let x = 0; x < W; x += 150) { ctx.strokeStyle = 'rgba(40,24,12,0.4)'; ctx.beginPath(); ctx.moveTo(x + rnd(x + y) * 60, y); ctx.lineTo(x + rnd(x + y) * 60, y + 46); ctx.stroke(); } - } - // ---- rug (center, patterned) ---- - const cx = W / 2, ry = 470; - for (const [rw, rh, col] of [[420, 220, '#5a1a24'], [400, 205, '#7a2330'], [300, 150, '#5a1a24']]) { ctx.fillStyle = col; ctx.beginPath(); ctx.ellipse(cx, ry, rw / 2, rh / 2, 0, 0, 7); ctx.fill(); } - ctx.strokeStyle = '#d6a846'; ctx.lineWidth = 4; ctx.beginPath(); ctx.ellipse(cx, ry, 195, 98, 0, 0, 7); ctx.stroke(); - ctx.lineWidth = 3; ctx.beginPath(); ctx.moveTo(cx, ry - 70); ctx.lineTo(cx + 150, ry); ctx.lineTo(cx, ry + 70); ctx.lineTo(cx - 150, ry); ctx.closePath(); ctx.stroke(); - // ---- back wall (top) stone with gradient + rail ---- - const wg = ctx.createLinearGradient(0, 0, 0, 200); - wg.addColorStop(0, '#241c30'); wg.addColorStop(1, '#3a2f48'); - ctx.fillStyle = wg; ctx.fillRect(0, 0, W, 190); - for (let y = 0; y < 180; y += 36) for (let x = (Math.floor(y / 36) % 2 ? 0 : -40); x < W; x += 80) { ctx.strokeStyle = 'rgba(18,12,26,0.7)'; ctx.lineWidth = 2; ctx.strokeRect(x, y, 80, 36); ctx.strokeStyle = 'rgba(120,108,140,0.15)'; ctx.beginPath(); ctx.moveTo(x + 2, y + 2); ctx.lineTo(x + 78, y + 2); ctx.stroke(); } - // wainscot rail - const rg = ctx.createLinearGradient(0, 175, 0, 200); rg.addColorStop(0, '#8a5a2e'); rg.addColorStop(1, '#5a3a1c'); - ctx.fillStyle = rg; ctx.fillRect(0, 175, W, 22); ctx.fillStyle = 'rgba(180,130,80,0.5)'; ctx.fillRect(0, 175, W, 3); - ctx.fillStyle = 'rgba(0,0,0,0.35)'; ctx.fillRect(0, 197, W, 8); // shadow below rail - // windows (night sky) - for (const wx of [150, W - 230]) { - ctx.fillStyle = '#5a3a1c'; roundRect(ctx, wx - 6, 30, 92, 110, 8); ctx.fill(); - const sg = ctx.createLinearGradient(0, 36, 0, 132); sg.addColorStop(0, '#16243f'); sg.addColorStop(1, '#0c1428'); - ctx.fillStyle = sg; ctx.fillRect(wx, 36, 80, 98); - ctx.fillStyle = '#cfe0ff'; for (let i = 0; i < 9; i++) ctx.fillRect(wx + rnd(i + wx) * 76, 38 + rnd(i * 3) * 92, 2, 2); - ctx.fillStyle = '#5a3a1c'; ctx.fillRect(wx + 38, 36, 4, 98); ctx.fillRect(wx, 82, 80, 4); - } - // hearth (center back) - const hx = cx - 110; - ctx.fillStyle = '#2a2333'; roundRect(ctx, hx, 8, 220, 188, 10); ctx.fill(); - ctx.fillStyle = '#1a1422'; roundRect(ctx, hx + 24, 50, 172, 130, 8); ctx.fill(); - ctx.fillStyle = '#120a08'; roundRect(ctx, hx + 36, 66, 148, 110, 6); ctx.fill(); // fire cavity (fire animated) - const mg = ctx.createLinearGradient(0, 188, 0, 210); mg.addColorStop(0, '#9a6a36'); mg.addColorStop(1, '#5a3a1c'); - ctx.fillStyle = mg; ctx.fillRect(hx - 14, 188, 248, 18); - // back-bar shelf with bottles (under rail, sides of hearth) - for (const sx of [40, hx + 250]) { - ctx.fillStyle = '#4a3018'; ctx.fillRect(sx, 150, 230, 30); - ctx.fillStyle = 'rgba(0,0,0,0.4)'; ctx.fillRect(sx, 176, 230, 5); - const cols = ['#4a9a64', '#b46a52', '#6a82c8', '#caa54a', '#8a5ab0']; - for (let i = 0; i < 11; i++) { const bx = sx + 8 + i * 20, bc = cols[i % 5]; ctx.fillStyle = bc; roundRect(ctx, bx, 124, 9, 30, 3); ctx.fill(); ctx.fillStyle = 'rgba(255,255,255,0.25)'; ctx.fillRect(bx + 1, 126, 2, 22); } - } - // ---- bar counter (front of bartender) ---- - const barY = 360, barW = 520, barX = cx - barW / 2; - ctx.fillStyle = 'rgba(0,0,0,0.4)'; ctx.beginPath(); ctx.ellipse(cx, barY + 70, barW / 2 + 10, 30, 0, 0, 7); ctx.fill(); - const bg = ctx.createLinearGradient(0, barY, 0, barY + 64); bg.addColorStop(0, '#a06a38'); bg.addColorStop(0.18, '#7a4a24'); bg.addColorStop(1, '#5a3418'); - ctx.fillStyle = bg; roundRect(ctx, barX, barY, barW, 64, 10); ctx.fill(); - ctx.fillStyle = 'rgba(200,150,90,0.6)'; roundRect(ctx, barX + 6, barY + 4, barW - 12, 8, 4); ctx.fill(); // top sheen - for (let i = 1; i < 7; i++) { ctx.strokeStyle = 'rgba(40,24,12,0.5)'; ctx.beginPath(); ctx.moveTo(barX + i * barW / 7, barY + 16); ctx.lineTo(barX + i * barW / 7, barY + 60); ctx.stroke(); } - for (const mx of [barX + 70, barX + barW - 90]) { ctx.fillStyle = '#caa54a'; roundRect(ctx, mx, barY + 14, 22, 26, 4); ctx.fill(); ctx.fillStyle = '#e8dca0'; roundRect(ctx, mx + 2, barY + 10, 18, 8, 3); ctx.fill(); } - // ---- tables + stools (sides) ---- - for (const [tx, ty] of [[230, 600], [W - 230, 600]]) { - ctx.fillStyle = 'rgba(0,0,0,0.4)'; ellipse(ctx, tx, ty + 22, 70, 24, 'rgba(0,0,0,0.4)'); - ellipse(ctx, tx, ty, 64, 40, '#5a3418'); ellipse(ctx, tx, ty - 4, 60, 36, '#7a4a24'); ellipse(ctx, tx - 12, ty - 10, 30, 16, '#9a6a3a'); - ctx.fillStyle = '#e8dca0'; ctx.fillRect(tx - 4, ty - 14, 8, 14); // candle - } - // ---- barrels (left) + crates (right) ---- - for (const [bx, by] of [[70, 580], [120, 612], [92, 660]]) { - ellipse(ctx, bx + 22, by + 50, 26, 8, 'rgba(0,0,0,0.4)'); - const bgr = ctx.createLinearGradient(bx, 0, bx + 44, 0); bgr.addColorStop(0, '#6a4422'); bgr.addColorStop(0.5, '#8a5a30'); bgr.addColorStop(1, '#5a3618'); - ctx.fillStyle = bgr; roundRect(ctx, bx, by, 44, 54, 8); ctx.fill(); - ctx.fillStyle = '#c8a040'; ctx.fillRect(bx, by + 10, 44, 5); ctx.fillRect(bx, by + 38, 44, 5); - ellipse(ctx, bx + 22, by + 4, 22, 7, '#9a6a3a'); - } - for (const [cx2, cy2] of [[W - 130, 600], [W - 78, 632]]) { - ellipse(ctx, cx2 + 26, cy2 + 52, 30, 8, 'rgba(0,0,0,0.4)'); - ctx.fillStyle = '#7a4a24'; roundRect(ctx, cx2, cy2, 52, 50, 4); ctx.fill(); - ctx.fillStyle = 'rgba(180,130,80,0.5)'; ctx.fillRect(cx2 + 3, cy2 + 3, 46, 4); - ctx.strokeStyle = '#5a3418'; ctx.lineWidth = 3; ctx.strokeRect(cx2 + 3, cy2 + 3, 46, 44); ctx.beginPath(); ctx.moveTo(cx2 + 4, cy2 + 4); ctx.lineTo(cx2 + 48, cy2 + 46); ctx.stroke(); - } - // banners - for (const [bx, col] of [[60, '#3cc8f0'], [W - 96, '#d6a846']]) { - ctx.fillStyle = col; ctx.globalAlpha = 0.9; ctx.beginPath(); ctx.moveTo(bx, 6); ctx.lineTo(bx + 36, 6); ctx.lineTo(bx + 36, 110); ctx.lineTo(bx + 18, 124); ctx.lineTo(bx, 110); ctx.closePath(); ctx.fill(); ctx.globalAlpha = 1; - ctx.fillStyle = 'rgba(0,0,0,0.25)'; ctx.fillRect(bx + 24, 6, 12, 104); - ctx.fillStyle = '#d6a846'; roundRect(ctx, bx + 12, 48, 12, 12, 2); ctx.fill(); - } -} - -const LIGHTS = [[W / 2, 90, 150, 0.55, '255,170,90'], [W / 2, 360, 220, 0.22, '255,180,100'], [150, 60, 80, 0.3, '255,200,120'], [W - 190, 60, 80, 0.3, '255,200,120'], [230, 586, 70, 0.32, '255,190,110'], [W - 230, 586, 70, 0.32, '255,190,110']]; - -export default function TopDownTavern({ onHotspot }) { - const canvasRef = useRef(null); - useEffect(() => { - const buf = document.createElement('canvas'); buf.width = W; buf.height = H; buildScene(buf); - const ctx = canvasRef.current.getContext('2d'); - let raf, f = 0; - const render = () => { - f++; - ctx.drawImage(buf, 0, 0); - // hearth fire - const hx = W / 2 - 74; - for (let i = 0; i < 6; i++) { - const fl = 0.55 + 0.45 * Math.sin(f * 0.16 + i * 1.3), bx = hx + 8 + i * 22; - const fgr = ctx.createLinearGradient(0, 176, 0, 100); fgr.addColorStop(0, '#ff8a2a'); fgr.addColorStop(1, 'rgba(255,210,90,0)'); - ctx.fillStyle = fgr; ctx.beginPath(); ctx.moveTo(bx, 178); ctx.quadraticCurveTo(bx + 8, 150 - fl * 30, bx + 11, 120 - fl * 26); ctx.quadraticCurveTo(bx + 14, 150 - fl * 30, bx + 22, 178); ctx.fill(); - } - // warm lighting - ctx.globalCompositeOperation = 'lighter'; - for (const [lx, ly, lr, la, rgb] of LIGHTS) { - const a = la * (0.85 + 0.15 * Math.sin(f * 0.09 + lx)); - const g = ctx.createRadialGradient(lx, ly, 0, lx, ly, lr); g.addColorStop(0, `rgba(${rgb},${a})`); g.addColorStop(1, `rgba(${rgb},0)`); - ctx.fillStyle = g; ctx.beginPath(); ctx.arc(lx, ly, lr, 0, 7); ctx.fill(); - } - ctx.globalCompositeOperation = 'source-over'; - // vignette - const vg = ctx.createRadialGradient(W / 2, H * 0.5, H * 0.28, W / 2, H * 0.5, H * 0.82); - vg.addColorStop(0, 'rgba(0,0,0,0)'); vg.addColorStop(1, 'rgba(8,4,12,0.7)'); - ctx.fillStyle = vg; ctx.fillRect(0, 0, W, H); - // dust - ctx.fillStyle = 'rgba(255,220,160,0.45)'; - for (let i = 0; i < 22; i++) { const dx = (i * 67 + f * 0.35) % W, dy = (i * 53 + Math.sin(f * 0.018 + i) * 24 + 220) % H; ctx.fillRect(dx, dy, 2, 2); } - raf = requestAnimationFrame(render); - }; - render(); - return () => cancelAnimationFrame(raf); - }, []); - - return ( -
- -
- onHotspot?.('agents')} /> - onHotspot?.('booth')} /> - onHotspot?.('agents')} /> - - -
-
- ); -} - -function Npc({ sprite, x, y, h, flip, label, say, onClick }) { - const [hover, setHover] = useState(false); - return ( - - ); -} diff --git a/src/styles.css b/src/styles.css index 10053cc..6e707db 100644 --- a/src/styles.css +++ b/src/styles.css @@ -489,7 +489,7 @@ button { inset: 0; display: flex; flex-direction: column; - font-family: "Press Start 2P", ui-monospace, "Courier New", monospace; + font-family: Georgia, "Times New Roman", serif; background: #07060c; overflow: hidden; } @@ -778,7 +778,7 @@ button { .cs-app { position: fixed; inset: 0; display: flex; flex-direction: column; background: #0a0e17; color: #dce6f5; font-family: Inter, ui-sans-serif, system-ui, sans-serif; --accent: #27d8ff; } .cs-loading { margin: auto; color: #6c7b96; font-family: ui-monospace, monospace; } -.cs-brand { display: flex; align-items: center; gap: 8px; font-family: "Press Start 2P", monospace; font-size: 15px; color: #fff; } +.cs-brand { display: flex; align-items: center; gap: 8px; font-family: Georgia, "Times New Roman", serif; font-size: 15px; color: #fff; } .cs-brand small { font-family: Inter, sans-serif; font-size: 11px; color: var(--accent); letter-spacing: 1px; } .cs-gem { width: 12px; height: 12px; background: var(--accent); transform: rotate(45deg); box-shadow: 0 0 0 2px #07273a; } @@ -796,7 +796,7 @@ button { .cs-login { display: flex; flex-direction: column; gap: 12px; width: 330px; padding: 26px 24px; color: #fff0d7; background: linear-gradient(180deg, #2a1608, #160a04); border: 3px solid #000; border-radius: 4px; box-shadow: inset 0 0 0 2px #6b3a1c, inset 0 0 26px rgba(0,0,0,0.7), 6px 6px 0 #000, 0 24px 60px rgba(0,0,0,0.6); - font-family: "Press Start 2P", ui-monospace, monospace; } + font-family: Georgia, "Times New Roman", serif; } .cs-login .cs-brand { justify-content: center; margin-bottom: 8px; color: #f7bc5d; } .cs-login .cs-gem { background: #27d8ff; } .cs-tabs { display: flex; gap: 6px; } @@ -935,20 +935,20 @@ button { .td-say { position: absolute; bottom: 102%; left: 50%; transform: translateX(-50%); width: max-content; max-width: 180px; padding: 6px 8px; font-size: 8px; line-height: 1.6; color: #1c1206; background: var(--cream); border: 2px solid #000; box-shadow: 2px 2px 0 #000; text-align: center; z-index: 6; } .td-say strong { color: #7a3d0c; } .td-say em { display: block; font-style: normal; color: #3a2a14; margin-top: 2px; } -.td-hot { position: absolute; transform: translate(-50%, -50%); font-family: "Press Start 2P", monospace; cursor: pointer; z-index: 4; } +.td-hot { position: absolute; transform: translate(-50%, -50%); font-family: Georgia, "Times New Roman", serif; cursor: pointer; z-index: 4; } .td-hot-board { display: flex; flex-direction: column; gap: 4px; align-items: center; padding: 8px 14px; color: #cdeaff; background: rgba(8,20,36,0.82); border: 2px solid #27d8ff; box-shadow: 0 0 18px rgba(39,216,255,0.4), 3px 3px 0 #000; font-size: 11px; } .td-hot-board .td-hot-tag { font-size: 6px; letter-spacing: 2px; color: #27d8ff; } .td-hot-board:hover { background: rgba(12,30,52,0.92); } .td-hot-door { padding: 8px 14px; font-size: 10px; color: #36f0b0; background: rgba(8,24,18,0.82); border: 2px solid #36f0b0; box-shadow: 0 0 16px rgba(54,240,176,0.35), 3px 3px 0 #000; } .td-hot-door:hover { background: rgba(12,34,26,0.92); } -.td-hero { position: absolute; left: 2.5%; top: 6%; width: min(40%, 380px); z-index: 4; font-family: "Press Start 2P", monospace; +.td-hero { position: absolute; left: 2.5%; top: 6%; width: min(40%, 380px); z-index: 4; font-family: Georgia, "Times New Roman", serif; padding: 16px 18px; background: linear-gradient(180deg, rgba(12,6,18,0.72), rgba(12,6,18,0.45)); border-radius: 10px; backdrop-filter: blur(2px); } .td-hero h1 { font-size: clamp(13px, 2.1vw, 22px); line-height: 1.5; color: #fff; text-shadow: 2px 2px 0 #000, 0 0 18px rgba(0,0,0,0.8); margin: 0 0 10px; } .td-hero p { font-family: Inter, sans-serif; font-size: clamp(10px, 1.3vw, 13px); line-height: 1.7; color: #e7d4b6; text-shadow: 1px 1px 2px #000; margin: 0 0 12px; } .td-hero-cta { display: flex; gap: 8px; flex-wrap: wrap; } .td-stats { position: absolute; left: 50%; bottom: 3%; transform: translateX(-50%); display: flex; gap: 6px; z-index: 4; } -.td-stat { display: flex; flex-direction: column; align-items: center; padding: 6px 10px; background: rgba(8,12,22,0.8); border: 2px solid #000; box-shadow: 2px 2px 0 #000; font-family: "Press Start 2P", monospace; } +.td-stat { display: flex; flex-direction: column; align-items: center; padding: 6px 10px; background: rgba(8,12,22,0.8); border: 2px solid #000; box-shadow: 2px 2px 0 #000; font-family: Georgia, "Times New Roman", serif; } .td-stat b { font-size: 14px; color: #27d8ff; } .td-stat span { font-size: 6px; color: #9fb0d0; margin-top: 3px; letter-spacing: 1px; } .td-page { flex: 1; overflow: auto; background: #0a0710 radial-gradient(circle at 50% -10%, #1a0f22, #0a0710 60%); } @@ -957,7 +957,7 @@ button { /* agent platform */ .ap { max-width: 1080px; margin: 0 auto; padding: 24px 20px 60px; color: #e7d4b6; font-family: Inter, sans-serif; } .ap-head { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; } -.ap-head h2 { font-family: "Press Start 2P", monospace; font-size: 18px; color: #fff; margin: 0; } +.ap-head h2 { font-family: Georgia, "Times New Roman", serif; font-size: 18px; color: #fff; margin: 0; } .ap-by { color: #9a86b8; font-size: 13px; } .ap-search { margin-left: auto; padding: 9px 12px; border-radius: 8px; background: #140d1e; border: 1px solid #2e2440; color: #eaf2ff; font-family: inherit; } .ap-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 18px; } @@ -975,7 +975,7 @@ button { .ap-card-foot { display: flex; justify-content: space-between; font-size: 11px; color: #8a7aa8; margin-top: auto; } .ap-online { display: flex; align-items: center; gap: 5px; } .ap-online i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; } .ap-hint { color: #8a7aa8; font-size: 12px; line-height: 1.6; } -.ap-h4 { font-family: "Press Start 2P", monospace; font-size: 10px; color: #27d8ff; margin: 16px 0 8px; } +.ap-h4 { font-family: Georgia, "Times New Roman", serif; font-size: 10px; color: #27d8ff; margin: 16px 0 8px; } .ap-modal { position: fixed; inset: 0; background: rgba(4,6,14,0.75); display: flex; align-items: center; justify-content: center; z-index: 200; padding: 16px; } .ap-modal-box { width: min(640px, 96vw); max-height: 88vh; overflow: auto; background: #120c1e; border: 2px solid #2e2440; border-radius: 14px; padding: 18px; } @@ -1010,3 +1010,19 @@ button { .td-stage { width: 96vw; } .td-stats { position: static; transform: none; flex-wrap: wrap; justify-content: center; margin-top: 10px; } .td-home { flex-direction: column; } .ap-booth-grid { grid-template-columns: 1fr; } } + +/* ===================================================================== */ +/* 0.23 — concept-art hero frontpage (interactive layers) */ +/* ===================================================================== */ +.hero-wrap { position: relative; flex: 1; display: flex; align-items: center; justify-content: center; background: radial-gradient(circle at 50% 40%, #14100c, #000); overflow: hidden; } +.hero-stage { position: relative; width: min(100vw, calc((100vh - 0px) * 1.777)); aspect-ratio: 1672 / 941; box-shadow: 0 0 80px rgba(0,0,0,0.8); } +.hero-img { width: 100%; height: 100%; display: block; object-fit: cover; } +.hero-hot { position: absolute; background: transparent; border: 0; padding: 0; cursor: pointer; border-radius: 10px; transition: box-shadow .14s ease, background .14s ease; } +.hero-hot:hover { background: rgba(70,200,255,0.10); box-shadow: 0 0 0 2px rgba(80,205,255,0.55), 0 0 26px rgba(70,200,255,0.45); } +.hero-glow:hover { background: rgba(70,200,255,0.07); box-shadow: 0 0 34px rgba(70,200,255,0.4); } +.hero-live { position: absolute; left: 2.5%; bottom: 3.5%; display: flex; gap: 10px; font-family: Georgia, serif; } +.hero-live span { font-size: clamp(10px, 1.05vw, 14px); color: #cfe0ff; background: rgba(8,16,30,0.66); border: 1px solid rgba(80,200,255,0.35); border-radius: 8px; padding: 6px 11px; backdrop-filter: blur(2px); } +.hero-live b { color: #5fe0ff; font-size: 1.18em; } +.hero-acct { position: absolute; right: 2.5%; bottom: 3.5%; font-family: Georgia, serif; font-size: clamp(10px, 1vw, 13px); color: #dfe8ff; background: rgba(8,16,30,0.66); border: 1px solid rgba(120,150,200,0.35); border-radius: 8px; padding: 6px 11px; } +.hero-acct button { color: #5fe0ff; background: none; cursor: pointer; font-family: inherit; font-size: inherit; text-decoration: underline; } +@media (max-width: 640px) { .hero-live span:nth-child(3) { display: none; } }