638 lines
17 KiB
Vue
638 lines
17 KiB
Vue
<script setup lang="ts">
|
|
import { ref, onMounted, onUnmounted } from 'vue'
|
|
import { useGameStore } from '../stores/gameStore'
|
|
import { sound } from '../audio/synthAudio'
|
|
|
|
const store = useGameStore()
|
|
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
|
const showExpressIntro = ref(true)
|
|
let animId: number | null = null
|
|
|
|
let wagonX = 70
|
|
let wagonY = 325
|
|
let speed = 3.2
|
|
let distance = 0
|
|
const maxDistance = 2100
|
|
|
|
function startExpress() {
|
|
sound.playDialogueBlip()
|
|
showExpressIntro.value = false
|
|
}
|
|
|
|
interface Guest {
|
|
id: string
|
|
x: number
|
|
name: string
|
|
served: boolean
|
|
avatarColor: string
|
|
}
|
|
|
|
let guests: Guest[] = [
|
|
{ id: 'hansi', x: 300, name: 'Hansi 🧔', served: false, avatarColor: '#6366f1' },
|
|
{ id: 'viktor', x: 550, name: 'Viktor (Vampir) 🧛', served: false, avatarColor: '#881337' },
|
|
{ id: 'albin', x: 820, name: 'Albin (Fitness) 🏋️', served: false, avatarColor: '#0284c7' },
|
|
{ id: 'fabian', x: 1100, name: 'Fabian (Brauer) 🍺', served: false, avatarColor: '#d97706' },
|
|
{ id: 'maierflo', x: 1380, name: 'Maier Flo (DJ) 🎧', served: false, avatarColor: '#7c3aed' },
|
|
{ id: 'guate', x: 1650, name: 'Guatemalteke 🌋', served: false, avatarColor: '#059669' },
|
|
{ id: 'markus_nat', x: 1920, name: 'Markus & Nathalie 🥂', served: false, avatarColor: '#db2777' }
|
|
]
|
|
|
|
function throwBeer() {
|
|
sound.playGulp()
|
|
// Check if any guest is near the wagon
|
|
guests.forEach(g => {
|
|
if (!g.served && Math.abs(distance + wagonX - g.x) < 95) {
|
|
g.served = true
|
|
store.serveGuest()
|
|
}
|
|
})
|
|
}
|
|
|
|
function updateGame() {
|
|
if (showExpressIntro.value) return // Don't advance while reading intro!
|
|
|
|
distance += speed
|
|
|
|
if (distance >= maxDistance) {
|
|
store.setAct('finale')
|
|
return
|
|
}
|
|
}
|
|
|
|
function draw(ctx: CanvasRenderingContext2D, w: number, h: number) {
|
|
ctx.clearRect(0, 0, w, h)
|
|
|
|
// Sunset Party Sky Gradient
|
|
const grad = ctx.createLinearGradient(0, 0, 0, h)
|
|
grad.addColorStop(0, '#1e082b')
|
|
grad.addColorStop(0.4, '#4a154b')
|
|
grad.addColorStop(0.7, '#831843')
|
|
grad.addColorStop(0.9, '#c2410c')
|
|
grad.addColorStop(1, '#f59e0b')
|
|
ctx.fillStyle = grad
|
|
ctx.fillRect(0, 0, w, h)
|
|
|
|
// Sweeping Festival Lasers & Party Beams
|
|
const now = Date.now() * 0.003
|
|
ctx.save()
|
|
for (let b = 0; b < 3; b++) {
|
|
const angleOffset = b * (Math.PI / 3)
|
|
const targetX = w * 0.5 + Math.sin(now + angleOffset) * (w * 0.45)
|
|
ctx.strokeStyle = `hsla(${((now * 50) + b * 90) % 360}, 100%, 75%, 0.45)`
|
|
ctx.lineWidth = 3
|
|
ctx.beginPath()
|
|
ctx.moveTo(w * 0.5, 90)
|
|
ctx.lineTo(targetX, 350)
|
|
ctx.stroke()
|
|
}
|
|
ctx.restore()
|
|
|
|
// Medieval Castle silhouette on the horizon
|
|
ctx.fillStyle = '#170c14'
|
|
ctx.beginPath()
|
|
ctx.moveTo(0, 310)
|
|
ctx.lineTo(30, 290); ctx.lineTo(50, 290); ctx.lineTo(50, 310)
|
|
ctx.lineTo(110, 310); ctx.lineTo(130, 275); ctx.lineTo(160, 275); ctx.lineTo(170, 310)
|
|
ctx.lineTo(240, 310); ctx.lineTo(255, 295); ctx.lineTo(275, 295); ctx.lineTo(290, 310)
|
|
ctx.lineTo(w, 310); ctx.lineTo(w, 350); ctx.lineTo(0, 350)
|
|
ctx.fill()
|
|
|
|
// Cobblestone Highway
|
|
ctx.fillStyle = '#1c1917'
|
|
ctx.fillRect(0, 350, w, 130)
|
|
ctx.fillStyle = '#292524'
|
|
for (let r = 0; r < w + 40; r += 32) {
|
|
const rx = (r - (distance % 32))
|
|
ctx.fillRect(rx, 352, 26, 6)
|
|
ctx.fillRect(rx + 12, 362, 26, 6)
|
|
}
|
|
// Curbs / Grass edge
|
|
ctx.fillStyle = '#365314'
|
|
ctx.fillRect(0, 348, w, 3)
|
|
|
|
// Draw Guests along the road
|
|
guests.forEach(g => {
|
|
const screenX = g.x - distance
|
|
if (screenX > -70 && screenX < w + 70) {
|
|
// Guest shadow
|
|
ctx.fillStyle = 'rgba(0,0,0,0.4)'
|
|
ctx.beginPath()
|
|
ctx.ellipse(screenX + 10, 350, 14, 5, 0, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
if (g.id === 'viktor') {
|
|
// Red velvet vampire cape
|
|
ctx.fillStyle = '#4c0519'
|
|
ctx.fillRect(screenX - 5, 305, 30, 44)
|
|
}
|
|
|
|
// Guest body
|
|
ctx.fillStyle = g.avatarColor
|
|
ctx.fillRect(screenX, 305, 20, 45)
|
|
|
|
// Head
|
|
ctx.fillStyle = '#fed7aa'
|
|
ctx.beginPath()
|
|
ctx.arc(screenX + 10, 295, 10, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
// Character specifics
|
|
if (g.id === 'hansi') {
|
|
// Moustache
|
|
ctx.fillStyle = '#451a03'
|
|
ctx.fillRect(screenX + 6, 297, 8, 2.5)
|
|
} else if (g.id === 'viktor') {
|
|
// Sunglasses & fangs
|
|
ctx.fillStyle = '#0f172a'
|
|
ctx.fillRect(screenX + 6, 293, 8, 3)
|
|
} else if (g.id === 'albin') {
|
|
// Gym Headband
|
|
ctx.fillStyle = '#38bdf8'
|
|
ctx.fillRect(screenX + 2, 288, 16, 3)
|
|
} else if (g.id === 'fabian') {
|
|
// Beer mug in hand
|
|
ctx.fillStyle = '#f59e0b'
|
|
ctx.fillRect(screenX + 20, 312, 8, 10)
|
|
ctx.fillStyle = '#ffffff'
|
|
ctx.fillRect(screenX + 19, 309, 10, 3)
|
|
} else if (g.id === 'maierflo') {
|
|
// Headphones
|
|
ctx.strokeStyle = '#c084fc'
|
|
ctx.lineWidth = 2.5
|
|
ctx.beginPath()
|
|
ctx.arc(screenX + 10, 295, 12, Math.PI, 0)
|
|
ctx.stroke()
|
|
ctx.fillStyle = '#9333ea'
|
|
ctx.fillRect(screenX - 3, 293, 4, 6)
|
|
ctx.fillRect(screenX + 19, 293, 4, 6)
|
|
} else if (g.id === 'guate') {
|
|
// Bushy dark beard
|
|
ctx.fillStyle = '#1c1917'
|
|
ctx.fillRect(screenX + 4, 297, 12, 9)
|
|
} else if (g.id === 'markus_nat') {
|
|
// Second head for couple
|
|
ctx.fillStyle = '#fbcfe8'
|
|
ctx.beginPath()
|
|
ctx.arc(screenX + 24, 296, 9, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
ctx.fillStyle = '#db2777'
|
|
ctx.fillRect(screenX + 16, 307, 16, 43)
|
|
}
|
|
|
|
// Name & icon tag
|
|
ctx.fillStyle = '#fff'
|
|
ctx.font = 'bold 9px MedievalSharp, serif'
|
|
ctx.textAlign = 'center'
|
|
ctx.fillText(g.name, screenX + 10, 278)
|
|
|
|
if (g.served) {
|
|
ctx.fillStyle = '#22c55e'
|
|
ctx.font = 'bold 11px sans-serif'
|
|
ctx.fillText('🍻 PROST!', screenX + 10, 264)
|
|
} else {
|
|
ctx.fillStyle = '#fbbf24'
|
|
ctx.font = '8px "Press Start 2P", monospace'
|
|
ctx.fillText('DURST!', screenX + 10, 264)
|
|
}
|
|
}
|
|
})
|
|
|
|
// ================= REDESIGNED BOLLERWAGEN (RETRO PIXEL ART) =================
|
|
const wx = wagonX
|
|
const wy = wagonY
|
|
const bob = showExpressIntro.value ? 0 : Math.sin(Date.now() * 0.015) * 2.5
|
|
|
|
// 1. Shadow underneath the wagon
|
|
ctx.fillStyle = 'rgba(0,0,0,0.5)'
|
|
ctx.beginPath()
|
|
ctx.ellipse(wx + 30, wy + 32, 54, 8, 0, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
// 2. Heavy Rustic Oak Timber Bed with Iron Corner Brackets
|
|
ctx.fillStyle = '#451a03' // Dark wood outline
|
|
ctx.fillRect(wx - 26, wy + bob, 114, 26)
|
|
ctx.fillStyle = '#78350f' // Main oak plank
|
|
ctx.fillRect(wx - 24, wy + bob + 2, 110, 22)
|
|
ctx.fillStyle = '#92400e' // Highlight upper plank
|
|
ctx.fillRect(wx - 24, wy + bob + 4, 110, 8)
|
|
|
|
// Iron bands and golden rivets
|
|
ctx.fillStyle = '#1c1917'
|
|
ctx.fillRect(wx - 26, wy + bob, 6, 26)
|
|
ctx.fillRect(wx + 28, wy + bob, 5, 26)
|
|
ctx.fillRect(wx + 82, wy + bob, 6, 26)
|
|
ctx.fillStyle = '#ffd700'
|
|
;[wx - 23, wx + 30, wx + 85].forEach(rx => {
|
|
ctx.fillRect(rx, wy + bob + 4, 2, 2)
|
|
ctx.fillRect(rx, wy + bob + 14, 2, 2)
|
|
})
|
|
|
|
// 3. Side-Mounted Hopfen Beer Keg with Brass Faucet
|
|
ctx.fillStyle = '#292524'
|
|
ctx.fillRect(wx + 5, wy + bob - 12, 22, 14)
|
|
ctx.fillStyle = '#b45309'
|
|
ctx.fillRect(wx + 6, wy + bob - 11, 20, 12)
|
|
ctx.fillStyle = '#ffd700' // Faucet
|
|
ctx.fillRect(wx + 26, wy + bob - 6, 5, 3)
|
|
ctx.fillRect(wx + 29, wy + bob - 3, 2, 4)
|
|
|
|
// 4. Giant 135-BPM Bass Subwoofer on the rear
|
|
ctx.fillStyle = '#09090b'
|
|
ctx.fillRect(wx - 22, wy - 36 + bob, 26, 38)
|
|
ctx.strokeStyle = '#ffd700'
|
|
ctx.lineWidth = 1.5
|
|
ctx.strokeRect(wx - 22, wy - 36 + bob, 26, 38)
|
|
|
|
// Pulsing Bass Speaker Cone
|
|
const bassKick = Math.abs(Math.sin(Date.now() * 0.02) * 5)
|
|
ctx.fillStyle = '#e11d48'
|
|
ctx.beginPath()
|
|
ctx.arc(wx - 9, wy - 17 + bob, 8 + bassKick, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
ctx.strokeStyle = '#f43f5e'
|
|
ctx.lineWidth = 2
|
|
ctx.stroke()
|
|
// Speaker center cap
|
|
ctx.fillStyle = '#ffd700'
|
|
ctx.beginPath()
|
|
ctx.arc(wx - 9, wy - 17 + bob, 3, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
// 5. Hof-DJ Mixer Console & Turntable on the front
|
|
ctx.fillStyle = '#18181b'
|
|
ctx.fillRect(wx + 46, wy - 16 + bob, 34, 18)
|
|
ctx.strokeStyle = '#38bdf8'
|
|
ctx.lineWidth = 1
|
|
ctx.strokeRect(wx + 46, wy - 16 + bob, 34, 18)
|
|
|
|
// Vinyl Turntable with spinning vinyl
|
|
ctx.fillStyle = '#0a0a0a'
|
|
ctx.beginPath()
|
|
ctx.arc(wx + 60, wy - 7 + bob, 7, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
ctx.fillStyle = '#ef4444' // Center vinyl label
|
|
ctx.beginPath()
|
|
ctx.arc(wx + 60, wy - 7 + bob, 2.5, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
// Flashing Mixer LEDs
|
|
const ledFlash = Math.floor(Date.now() / 150) % 3
|
|
ctx.fillStyle = ledFlash === 0 ? '#22c55e' : '#15803d'
|
|
ctx.fillRect(wx + 72, wy - 12 + bob, 3, 3)
|
|
ctx.fillStyle = ledFlash === 1 ? '#eab308' : '#854d0e'
|
|
ctx.fillRect(wx + 72, wy - 8 + bob, 3, 3)
|
|
ctx.fillStyle = ledFlash === 2 ? '#ef4444' : '#7f1d1d'
|
|
ctx.fillRect(wx + 72, wy - 4 + bob, 3, 3)
|
|
|
|
// 6. KING SASCHA standing proud on the wagon
|
|
// Flowing Royal Red Velvet Cape
|
|
ctx.fillStyle = '#b91c1c'
|
|
ctx.fillRect(wx + 10, wy - 36 + bob, 24, 38)
|
|
|
|
// Royal Blue Tunic with Gold Trim
|
|
ctx.fillStyle = '#1d4ed8'
|
|
ctx.fillRect(wx + 15, wy - 32 + bob, 18, 24)
|
|
ctx.fillStyle = '#d4af37'
|
|
ctx.fillRect(wx + 22, wy - 32 + bob, 4, 24)
|
|
|
|
// Face & Beard
|
|
ctx.fillStyle = '#fed7aa'
|
|
ctx.fillRect(wx + 16, wy - 46 + bob, 16, 14)
|
|
// Short Blonde/Brown Hair (as requested)
|
|
ctx.fillStyle = '#b45309'
|
|
ctx.fillRect(wx + 15, wy - 50 + bob, 18, 5)
|
|
|
|
// Deep Black Royal Sunglasses
|
|
ctx.fillStyle = '#0f172a'
|
|
ctx.fillRect(wx + 18, wy - 43 + bob, 6, 4)
|
|
ctx.fillRect(wx + 25, wy - 43 + bob, 6, 4)
|
|
ctx.fillRect(wx + 23, wy - 42 + bob, 3, 2) // Bridge
|
|
|
|
// Golden Imperial Crown with Jewels
|
|
ctx.fillStyle = '#facc15'
|
|
ctx.fillRect(wx + 15, wy - 53 + bob, 18, 5)
|
|
ctx.beginPath()
|
|
ctx.moveTo(wx + 15, wy - 53 + bob); ctx.lineTo(wx + 15, wy - 58 + bob); ctx.lineTo(wx + 19, wy - 53 + bob)
|
|
ctx.lineTo(wx + 24, wy - 60 + bob); ctx.lineTo(wx + 29, wy - 53 + bob); ctx.lineTo(wx + 33, wy - 58 + bob)
|
|
ctx.lineTo(wx + 33, wy - 53 + bob)
|
|
ctx.fill()
|
|
// Crown jewels
|
|
ctx.fillStyle = '#dc2626'
|
|
ctx.fillRect(wx + 23, wy - 54 + bob, 2, 2)
|
|
|
|
// Raised Beer Stein in Right Hand (Prost!)
|
|
ctx.fillStyle = '#f59e0b' // Golden Beer
|
|
ctx.fillRect(wx + 35, wy - 44 + bob, 8, 12)
|
|
ctx.fillStyle = '#ffffff' // White froth/foam
|
|
ctx.fillRect(wx + 34, wy - 47 + bob, 10, 4)
|
|
ctx.fillStyle = '#cbd5e1' // Glass handle
|
|
ctx.fillRect(wx + 42, wy - 42 + bob, 3, 7)
|
|
|
|
// 7. Detailed Wooden Spoke Wheels with Golden Brass Caps
|
|
const wheelSpin = (distance * 0.08) % (Math.PI * 2)
|
|
;[-8, 68].forEach(wheelOffset => {
|
|
ctx.save()
|
|
ctx.translate(wx + wheelOffset, wy + 26)
|
|
ctx.rotate(wheelSpin)
|
|
|
|
// Outer dark tyre
|
|
ctx.fillStyle = '#1c1917'
|
|
ctx.beginPath()
|
|
ctx.arc(0, 0, 13, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
// Inner wooden rim
|
|
ctx.fillStyle = '#78350f'
|
|
ctx.beginPath()
|
|
ctx.arc(0, 0, 11, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
// Brass rim edge
|
|
ctx.strokeStyle = '#ffd700'
|
|
ctx.lineWidth = 1.5
|
|
ctx.stroke()
|
|
|
|
// 8 Spokes
|
|
ctx.strokeStyle = '#b45309'
|
|
ctx.lineWidth = 1.5
|
|
for (let s = 0; s < 4; s++) {
|
|
ctx.beginPath()
|
|
ctx.moveTo(-11 * Math.cos(s * Math.PI / 4), -11 * Math.sin(s * Math.PI / 4))
|
|
ctx.lineTo(11 * Math.cos(s * Math.PI / 4), 11 * Math.sin(s * Math.PI / 4))
|
|
ctx.stroke()
|
|
}
|
|
|
|
// Center brass axle cap
|
|
ctx.fillStyle = '#facc15'
|
|
ctx.beginPath()
|
|
ctx.arc(0, 0, 4, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
ctx.restore()
|
|
})
|
|
|
|
// Top Banner HUD
|
|
ctx.fillStyle = '#ffd700'
|
|
ctx.font = 'bold 8px "Press Start 2P", monospace'
|
|
ctx.textAlign = 'center'
|
|
ctx.fillText('AKT IV: DER 135-BPM-FEST-KONVOI', w / 2, 22)
|
|
|
|
// Progress Bar
|
|
const progress = Math.min(1, distance / maxDistance)
|
|
const barMargin = 20
|
|
const barWidth = w - barMargin * 2
|
|
ctx.fillStyle = 'rgba(0,0,0,0.7)'
|
|
ctx.fillRect(barMargin, 32, barWidth, 10)
|
|
ctx.strokeStyle = '#ffd700'
|
|
ctx.lineWidth = 1
|
|
ctx.strokeRect(barMargin, 32, barWidth, 10)
|
|
|
|
// Progress fill
|
|
ctx.fillStyle = '#22c55e'
|
|
ctx.fillRect(barMargin + 1, 33, (barWidth - 2) * progress, 8)
|
|
|
|
// Moving Keg Icon on the progress bar
|
|
const kegX = barMargin + (barWidth * progress)
|
|
ctx.font = '10px sans-serif'
|
|
ctx.fillText('🍺', kegX, 39)
|
|
}
|
|
|
|
function loop() {
|
|
updateGame()
|
|
if (canvasRef.value) {
|
|
const ctx = canvasRef.value.getContext('2d')
|
|
if (ctx) draw(ctx, canvasRef.value.width, canvasRef.value.height)
|
|
}
|
|
animId = requestAnimationFrame(loop)
|
|
}
|
|
|
|
onMounted(() => {
|
|
animId = requestAnimationFrame(loop)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
if (animId) cancelAnimationFrame(animId)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="express-container">
|
|
<canvas ref="canvasRef" width="360" height="480" class="game-canvas"></canvas>
|
|
|
|
<div class="express-controls">
|
|
<button class="throw-beer-btn" @click="throwBeer">
|
|
🍺 BIER AN DIE GÄSTE SCHENKEN!
|
|
</button>
|
|
<span class="express-hint">Tippe, wenn du an deinen Freunden vorbeifährst!</span>
|
|
</div>
|
|
|
|
<!-- Pre-Level Start Screen Modal -->
|
|
<div v-if="showExpressIntro" class="level-intro-modal">
|
|
<div class="intro-card">
|
|
<div class="intro-act-tag">👑 AKT IV: FAHRGESCHÄFT</div>
|
|
<h2 class="intro-card-title">DER 135-BPM-FEST-KONVOI</h2>
|
|
<p class="intro-card-story">
|
|
Der Hof-Bass wummert, der Bollerwagen ist poliert!<br />
|
|
König Sascha zieht mit der Reichs-Soundanlage über die Festmeile von Haumdaucher. Deine Freunde stehen durstig am Straßenrand!
|
|
</p>
|
|
<div class="mission-callout">
|
|
<span class="callout-icon">🎯</span>
|
|
<div class="callout-text">
|
|
<strong>KÖNIGLICHE MISSION:</strong><br />
|
|
Versorge Hansi, Viktor, Albin, Fabian, Flo Maier & das Gefolge mit kühlem Gerstensaft im Takt des Basses!
|
|
</div>
|
|
</div>
|
|
<div class="controls-overview">
|
|
<div class="ctrl-item">
|
|
<span class="ctrl-badge">🍺 BIER SCHENKEN</span>
|
|
<span class="ctrl-label">Tippe den Button, sobald du an einem Freund bist</span>
|
|
</div>
|
|
<div class="ctrl-item">
|
|
<span class="ctrl-badge">🏆 TIMING</span>
|
|
<span class="ctrl-label">Jedes glückliche Gefolge bringt fette Highscore-Punkte!</span>
|
|
</div>
|
|
</div>
|
|
<button class="start-act-btn" @click="startExpress">
|
|
🚀 PARTY-EXPRESS STARTEN!
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.express-container {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #000;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.game-canvas {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
image-rendering: pixelated;
|
|
image-rendering: crisp-edges;
|
|
}
|
|
|
|
.express-controls {
|
|
position: absolute;
|
|
bottom: 12px;
|
|
left: 0;
|
|
right: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 6px;
|
|
z-index: 20;
|
|
}
|
|
|
|
.throw-beer-btn {
|
|
background: #eab308;
|
|
color: #1a0f0a;
|
|
border: 2px solid #fff;
|
|
border-radius: 8px;
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 8.5px;
|
|
padding: 10px 14px;
|
|
cursor: pointer;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.7);
|
|
animation: pulse 1s infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% { transform: scale(1); }
|
|
50% { transform: scale(1.04); }
|
|
}
|
|
|
|
.express-hint {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 13px;
|
|
color: #fef08a;
|
|
text-shadow: 1px 1px 2px #000;
|
|
}
|
|
|
|
/* Pre-Level Start Screen Modal */
|
|
.level-intro-modal {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.88);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 12px;
|
|
z-index: 50;
|
|
backdrop-filter: blur(2px);
|
|
}
|
|
|
|
.intro-card {
|
|
background: #231209;
|
|
border: 3px double #d4af37;
|
|
border-radius: 10px;
|
|
padding: 16px 14px;
|
|
max-width: 320px;
|
|
width: 100%;
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.95);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.intro-act-tag {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 6.5px;
|
|
color: #f59e0b;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.intro-card-title {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 9.5px;
|
|
color: #ffd700;
|
|
margin: 0;
|
|
text-shadow: 1px 1px 0 #000;
|
|
}
|
|
|
|
.intro-card-story {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 13px;
|
|
color: #fef08a;
|
|
line-height: 1.35;
|
|
margin: 0;
|
|
}
|
|
|
|
.mission-callout {
|
|
background: #451a03;
|
|
border-left: 3px solid #22c55e;
|
|
border-radius: 4px;
|
|
padding: 8px 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
text-align: left;
|
|
}
|
|
|
|
.callout-icon {
|
|
font-size: 20px;
|
|
}
|
|
|
|
.callout-text {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 12.5px;
|
|
color: #bbf7d0;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.controls-overview {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 5px;
|
|
width: 100%;
|
|
background: #170c06;
|
|
border: 1px solid #78350f;
|
|
border-radius: 6px;
|
|
padding: 6px 10px;
|
|
text-align: left;
|
|
}
|
|
|
|
.ctrl-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
}
|
|
|
|
.ctrl-badge {
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 6.5px;
|
|
color: #ffd700;
|
|
}
|
|
|
|
.ctrl-label {
|
|
font-family: 'MedievalSharp', serif;
|
|
font-size: 11.5px;
|
|
color: #fed7aa;
|
|
}
|
|
|
|
.start-act-btn {
|
|
background: linear-gradient(180deg, #dc2626 0%, #991b1b 100%);
|
|
color: #fff;
|
|
border: 2px solid #ffd700;
|
|
border-radius: 8px;
|
|
padding: 10px 16px;
|
|
font-family: 'Press Start 2P', monospace;
|
|
font-size: 8px;
|
|
cursor: pointer;
|
|
margin-top: 4px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.7);
|
|
transition: transform 0.1s;
|
|
}
|
|
|
|
.start-act-btn:active {
|
|
transform: scale(0.96);
|
|
}
|
|
</style>
|