Re-theme the app: token-based CSS and a full face lift

CSS refactor: every color, font, radius, and shadow is now defined once
in theme.css; all other styles derive translucent variants with
color-mix(), so re-theming means editing one file. Removed the
duplicate core.css/style.css import chains, dead styles, and the
Bootstrap/Tailwind orphan classes that were silently unstyled
(the main reason the splash page looked broken).

New "Lantern & Brine" look: brass and parchment on a lantern-lit
ink-navy night, Pirata One wordmark with Alegreya SC/Sans body fonts
(self-hosted via fontsource — they were previously referenced but
never loaded), parchment-faced playing cards, and a rebuilt splash
page. Inline color styles in components were replaced with semantic
classes (prompt-box, notice-banner, status chips, etc.), the rulebook's
embedded palette was updated to match, and the leftover Vite favicon
and "frontend" page title were replaced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 06:50:00 -07:00
parent ba6bf35579
commit 0744893e7b
36 changed files with 1442 additions and 1185 deletions

View File

@@ -184,67 +184,67 @@
{#if state.player.is_dead && !state.player.is_ghost}
<!-- Death Fate Panel -->
<div class="card glass-panel death-fate-card" style="border: 2px solid var(--red-suit); background: rgba(255, 42, 95, 0.05); padding: 2.5rem; margin: 2rem auto; max-width: 650px; border-radius: 12px; box-shadow: 0 0 20px rgba(255,42,95,0.15); text-align: center;">
<h2 style="color: var(--red-suit); font-family: var(--font-heading); margin-bottom: 1rem; font-size: 2rem;">💀 Your Pi-Rat Has Died!</h2>
<p class="description" style="font-size: 1.15rem; color: var(--text-primary); margin-bottom: 2rem; line-height: 1.6;">
<div class="glass-panel death-fate-card">
<h2>💀 Your Pi-Rat Has Died!</h2>
<p class="description">
Your story arc is complete! You went out in a blaze of glory (or retired honorably). You must now choose how your journey continues:
</p>
{#if !isRolling}
<div style="display: flex; gap: 1.5rem; justify-content: center; flex-wrap: wrap;">
<button class="btn btn-secondary btn-large glow-effect" on:click={becomeGhost} style="border: 1px solid var(--text-muted); font-size: 1.1rem; padding: 0.8rem 2rem;">
<div class="fate-choices">
<button class="btn btn-secondary btn-large glow-effect" on:click={becomeGhost}>
👻 Remain as a Ghost
</button>
<button class="btn btn-primary btn-large glow-effect" on:click={() => isRolling = true} style="background: var(--gold); border: 1px solid var(--gold); color: black; font-size: 1.1rem; padding: 0.8rem 2rem;">
<button class="btn btn-primary btn-large glow-effect" on:click={() => isRolling = true}>
🐀 Roll a New Character
</button>
</div>
<p class="info-text" style="margin-top: 1.5rem; font-style: italic; color: var(--text-muted);">
<p class="info-text italic" style="margin-top: 1.5rem;">
Ghosts look back into the living world, watch over friends, and help their crew. New recruits start fresh at Rank 1 with surprise Secret Techniques and a name based on their smell.
</p>
{:else}
<div class="creation-form-wrapper" style="text-align: left; background: rgba(0,0,0,0.2); padding: 1.5rem; border-radius: 8px; border: 1px solid rgba(255,255,255,0.05);">
<h3 style="color: var(--gold); font-family: var(--font-heading); margin-bottom: 1.5rem; border-bottom: 1px solid rgba(212,175,55,0.2); padding-bottom: 0.5rem;">Create Your New Recruit</h3>
<div class="creation-form-wrapper">
<h3>Create Your New Recruit</h3>
{#if rollingError}
<div class="alert alert-danger" style="margin-bottom: 1.5rem;">{rollingError}</div>
{/if}
<div class="form-group" style="margin-bottom: 1.25rem;">
<label style="display: block; font-weight: bold; margin-bottom: 0.5rem; font-size: 0.9rem; color: var(--text-primary); font-family: var(--font-heading);">What does your Pi-Rat look like?</label>
<div class="input-row" style="display: flex; gap: 0.5rem;">
<input type="text" placeholder="e.g. Scruffy snout, wearing a tattered vest" bind:value={reRollDetails.avatar_look} required class="input-field" style="flex: 1; padding: 0.6rem; border-radius: 4px; border: 1px solid var(--glass-border); background: rgba(0,0,0,0.3); color: white;">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.avatar_look = getSuggestion('look')} style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">Suggest</button>
<div class="form-group">
<label>What does your Pi-Rat look like?</label>
<div class="input-row">
<input type="text" placeholder="e.g. Scruffy snout, wearing a tattered vest" bind:value={reRollDetails.avatar_look} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.avatar_look = getSuggestion('look')}>Suggest</button>
</div>
</div>
<div class="form-group" style="margin-bottom: 1.25rem;">
<label style="display: block; font-weight: bold; margin-bottom: 0.5rem; font-size: 0.9rem; color: var(--text-primary); font-family: var(--font-heading);">What does your Pi-Rat smell like? (Determines name)</label>
<div class="input-row" style="display: flex; gap: 0.5rem;">
<input type="text" placeholder="e.g. Spiced rum, salty cheese, gunpowder" bind:value={reRollDetails.avatar_smell} required class="input-field" style="flex: 1; padding: 0.6rem; border-radius: 4px; border: 1px solid var(--glass-border); background: rgba(0,0,0,0.3); color: white;">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.avatar_smell = getSuggestion('smell')} style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">Suggest</button>
<div class="form-group">
<label>What does your Pi-Rat smell like? (Determines name)</label>
<div class="input-row">
<input type="text" placeholder="e.g. Spiced rum, salty cheese, gunpowder" bind:value={reRollDetails.avatar_smell} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.avatar_smell = getSuggestion('smell')}>Suggest</button>
</div>
</div>
<div class="form-group" style="margin-bottom: 1.25rem;">
<label style="display: block; font-weight: bold; margin-bottom: 0.5rem; font-size: 0.9rem; color: var(--text-primary); font-family: var(--font-heading);">What were your first words after transforming?</label>
<div class="input-row" style="display: flex; gap: 0.5rem;">
<input type="text" placeholder="e.g. Shiver my decimals!" bind:value={reRollDetails.first_words} required class="input-field" style="flex: 1; padding: 0.6rem; border-radius: 4px; border: 1px solid var(--glass-border); background: rgba(0,0,0,0.3); color: white;">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.first_words = getSuggestion('first_words')} style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">Suggest</button>
<div class="form-group">
<label>What were your first words after transforming?</label>
<div class="input-row">
<input type="text" placeholder="e.g. Shiver my decimals!" bind:value={reRollDetails.first_words} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.first_words = getSuggestion('first_words')}>Suggest</button>
</div>
</div>
<div class="form-group" style="margin-bottom: 1.5rem;">
<label style="display: block; font-weight: bold; margin-bottom: 0.5rem; font-size: 0.9rem; color: var(--text-primary); font-family: var(--font-heading);">Is your Pi-Rat good at Math?</label>
<div class="input-row" style="display: flex; gap: 0.5rem;">
<input type="text" placeholder="e.g. Thinks Pi is a dessert" bind:value={reRollDetails.good_at_math} required class="input-field" style="flex: 1; padding: 0.6rem; border-radius: 4px; border: 1px solid var(--glass-border); background: rgba(0,0,0,0.3); color: white;">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.good_at_math = getSuggestion('good_at_math')} style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">Suggest</button>
<div class="form-group">
<label>Is your Pi-Rat good at Math?</label>
<div class="input-row">
<input type="text" placeholder="e.g. Thinks Pi is a dessert" bind:value={reRollDetails.good_at_math} required class="input-field">
<button type="button" class="btn btn-secondary btn-small" on:click={() => reRollDetails.good_at_math = getSuggestion('good_at_math')}>Suggest</button>
</div>
</div>
<div style="display: flex; gap: 1rem; margin-top: 1.5rem;">
<button class="btn btn-secondary" on:click={() => isRolling = false} style="flex: 1; padding: 0.75rem;">Cancel</button>
<button class="btn btn-primary" on:click={submitReRoll} style="flex: 2; padding: 0.75rem; background: var(--gold); border: 1px solid var(--gold); color: black;">Submit New Character</button>
<div class="form-actions">
<button class="btn btn-secondary" on:click={() => isRolling = false}>Cancel</button>
<button class="btn btn-primary" on:click={submitReRoll}>Submit New Character</button>
</div>
</div>
{/if}
@@ -350,8 +350,8 @@
</div>
{#if isOverLimit}
<div style="border: 1px solid var(--red-suit); border-radius: 4px; padding: 1rem; margin: 1rem 0; background: rgba(255, 42, 95, 0.1);">
<p style="color: var(--red-suit); font-weight: bold; margin: 0;">⚠️ Discard Required: You have selected {keepCards.length} cards to keep, which exceeds your maximum hand limit of {maxHandSize}. Please discard at least {keepCards.length - maxHandSize} card(s).</p>
<div class="notice-banner danger" style="margin: 1rem 0; max-width: none;">
<p class="text-danger font-bold" style="margin: 0;">⚠️ Discard Required: You have selected {keepCards.length} cards to keep, which exceeds your maximum hand limit of {maxHandSize}. Please discard at least {keepCards.length - maxHandSize} card(s).</p>
</div>
{/if}
@@ -374,7 +374,7 @@
{#each state.players as p}
<li>
<strong>{displayName(p)}:</strong> Rank {p.rank}
{#if p.role === 'deep'}<span class="deep-badge">Deep</span>{:else if p.is_ghost}<span class="ghost-badge" style="background: rgba(120, 150, 180, 0.15); border: 1px solid #7890a8; color: #a0b0c0; padding: 0.15rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 700; margin-left: 0.5rem; display: inline-block;">Ghost</span>{:else}<span class="pirat-badge">Pi-Rat</span>{/if}
{#if p.role === 'deep'}<span class="deep-badge">Deep</span>{:else if p.is_ghost}<span class="ghost-badge">Ghost</span>{:else}<span class="pirat-badge">Pi-Rat</span>{/if}
</li>
{/each}
</ul>
@@ -414,7 +414,7 @@
{/if}
{#if state.player.is_creator && state.game.phase === 'between_scenes'}
<div style="margin-top: 1.5rem; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 1rem;">
<div class="end-story-box">
<p class="info-text" style="font-size: 0.85rem;">All good stories end. When the crew agrees the legend is complete:</p>
<button on:click={finishGame} class="btn btn-danger">🏴‍☠️ End the Story</button>
</div>