From 0744893e7b82fe8ab6fb349cb7dde4fa60b09f0c Mon Sep 17 00:00:00 2001 From: Tim McCarthy Date: Fri, 12 Jun 2026 06:50:00 -0700 Subject: [PATCH] Re-theme the app: token-based CSS and a full face lift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- TODO.md | 4 +- frontend/index.html | 2 +- frontend/package-lock.json | 30 ++ frontend/package.json | 3 + frontend/public/favicon.svg | 5 +- frontend/src/app.css | 12 +- frontend/src/assets/css/admin.css | 94 +++- frontend/src/assets/css/base.css | 208 ++++++++ frontend/src/assets/css/card.css | 140 ++--- frontend/src/assets/css/character.css | 216 ++++---- frontend/src/assets/css/components.css | 486 ++++++++++++------ frontend/src/assets/css/core.css | 237 --------- frontend/src/assets/css/lobby.css | 75 +-- frontend/src/assets/css/scene-play.css | 213 ++++---- frontend/src/assets/css/scene-setup.css | 90 ++-- frontend/src/assets/css/style.css | 18 - frontend/src/assets/css/theme.css | 81 +++ frontend/src/assets/css/upkeep.css | 93 ++-- frontend/src/assets/css/welcome.css | 117 +++-- .../components/CharacterCreationPhase.svelte | 24 +- frontend/src/components/CornerMenu.svelte | 20 +- frontend/src/components/EventLog.svelte | 64 +-- frontend/src/components/GameOverPhase.svelte | 20 +- frontend/src/components/LobbyPhase.svelte | 2 +- frontend/src/components/ScenePhase.svelte | 52 +- .../src/components/SceneSetupPhase.svelte | 24 +- frontend/src/components/UpkeepPhase.svelte | 72 +-- .../components/scene/ChallengePanel.svelte | 20 +- .../components/scene/CharacterSheet.svelte | 24 +- .../components/scene/DeepControlPanel.svelte | 16 +- .../src/components/scene/ObstacleBoard.svelte | 13 +- frontend/src/main.js | 9 + frontend/src/pages/Admin.svelte | 50 +- frontend/src/pages/Home.svelte | 37 +- frontend/src/pages/Join.svelte | 13 +- src/pirats/rules.html | 43 +- 36 files changed, 1442 insertions(+), 1185 deletions(-) create mode 100644 frontend/src/assets/css/base.css delete mode 100644 frontend/src/assets/css/core.css delete mode 100644 frontend/src/assets/css/style.css create mode 100644 frontend/src/assets/css/theme.css diff --git a/TODO.md b/TODO.md index a8f37da..e918d0b 100644 --- a/TODO.md +++ b/TODO.md @@ -10,8 +10,8 @@ ## Cosmetic -- [ ] **Refactor the CSS.** Make it easy to re-theme by keeping the definitions of primary/background/highlight/etc colors confined to a few specific styles. If this requires adopting some kind of CSS framework/preprocessing, so be it. -- [ ] **Re-styling**. The entire app could use a face lift, but in particular the splash page is ugly. +- [x] **Refactor the CSS.** All colors/fonts/radii/shadows now live as tokens in `frontend/src/assets/css/theme.css`; everything else derives translucent variants via `color-mix()`. Re-theming the app = editing that one file (plus the mirrored token block at the top of `src/pirats/rules.html`). +- [x] **Re-styling**. New "Lantern & Brine" theme: brass/parchment on lantern-lit ink-navy, Pirata One wordmark, Alegreya SC/Sans (self-hosted via fontsource), parchment-faced playing cards, rebuilt splash page. ## Worth Double-Checking / Minor diff --git a/frontend/index.html b/frontend/index.html index 2b56de4..b43ccda 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ - frontend + Rats with Gats
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index de8c438..33e4263 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,9 @@ "name": "frontend", "version": "0.0.0", "dependencies": { + "@fontsource/alegreya-sans": "^5.2.8", + "@fontsource/alegreya-sc": "^5.2.8", + "@fontsource/pirata-one": "^5.2.8", "svelte-spa-router": "^5.1.0" }, "devDependencies": { @@ -50,6 +53,33 @@ "tslib": "^2.4.0" } }, + "node_modules/@fontsource/alegreya-sans": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/alegreya-sans/-/alegreya-sans-5.2.8.tgz", + "integrity": "sha512-kXUTR1S6dsWa7rBxaDJ3P05HodmYmxfY20aQtQ4SYVmrEYrWtaw5A1n+h+wcCF0nAMwf+CQ4M435dNuWD1YfMg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/alegreya-sc": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/alegreya-sc/-/alegreya-sc-5.2.8.tgz", + "integrity": "sha512-28ZMhxJ/bx7f9S2oTTPeXvKchAu5VxPbEG95RI+EI9l3/1YyomEXzUqX0lCdCQb5fDXhdmVwHSD07P0BL4ueQA==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/pirata-one": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/pirata-one/-/pirata-one-5.2.8.tgz", + "integrity": "sha512-hl3Zqt6mgP+jstHnv2qYc2xQdYM1DSYrpSU9bpS1fYExoGFgJJNbXTPBQ9XivNk9RCKkibhou3iqoOZQOXM48w==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6c4b248..396790f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,9 @@ "vite": "^8.0.12" }, "dependencies": { + "@fontsource/alegreya-sans": "^5.2.8", + "@fontsource/alegreya-sc": "^5.2.8", + "@fontsource/pirata-one": "^5.2.8", "svelte-spa-router": "^5.1.0" } } diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg index 6893eb1..41a7012 100644 --- a/frontend/public/favicon.svg +++ b/frontend/public/favicon.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + ๐Ÿ€ + diff --git a/frontend/src/app.css b/frontend/src/app.css index 1e0e604..714aa0f 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -1,11 +1,17 @@ -@import './assets/css/style.css'; -@import './assets/css/core.css'; +/* ========================================================================== + RATS WITH GATS โ€” STYLESHEET INDEX + theme.css holds every color/font/shape token (edit it to re-theme). + base.css holds the reset, typography, and utility classes. + The rest are component- and phase-specific styles built on those tokens. + ========================================================================== */ +@import './assets/css/theme.css'; +@import './assets/css/base.css'; @import './assets/css/components.css'; +@import './assets/css/card.css'; @import './assets/css/welcome.css'; @import './assets/css/lobby.css'; @import './assets/css/character.css'; @import './assets/css/scene-setup.css'; @import './assets/css/scene-play.css'; -@import './assets/css/card.css'; @import './assets/css/upkeep.css'; @import './assets/css/admin.css'; diff --git a/frontend/src/assets/css/admin.css b/frontend/src/assets/css/admin.css index b5a9568..6f82269 100644 --- a/frontend/src/assets/css/admin.css +++ b/frontend/src/assets/css/admin.css @@ -1,22 +1,46 @@ -/* --- Admin Panel --- */ -.admin-players-list { - display: flex; - flex-direction: column; - gap: 1rem; +/* --- Admin panel --- */ +.admin-page { + max-width: 56rem; + margin: 0 auto; + padding: 2rem 1rem; +} + +.admin-page h1 { + font-family: var(--font-display); + font-weight: 400; + font-size: 2.2rem; + color: var(--accent); + margin-bottom: 1.5rem; + letter-spacing: 1px; +} + +.admin-key-chip { + background: var(--well); + border: 1px solid var(--edge); + border-radius: 4px; + padding: 0.15rem 0.5rem; + font-family: ui-monospace, monospace; + font-size: 0.875rem; +} + +.admin-table { + width: 100%; + text-align: left; + background: var(--well); + border: 1px solid var(--edge); + border-radius: var(--radius-sm); + border-collapse: collapse; margin-top: 1rem; } -.admin-player-row { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem; - gap: 1rem; - flex-wrap: wrap; +.admin-table th, .admin-table td { + padding: 0.75rem; + border-bottom: 1px solid var(--edge-soft); } -.player-info-basic { - font-size: 1.05rem; +.admin-table th { + font-family: var(--font-heading); + color: var(--accent); } .link-copy-action { @@ -26,3 +50,45 @@ flex: 1; max-width: 500px; } + +/* --- Game over --- */ +.gameover-container { + max-width: 800px; + margin: 0 auto; + padding: 2rem; +} + +.gameover-card { + text-align: center; +} + +.gameover-card h1 { + font-family: var(--font-display); + font-weight: 400; + font-size: 2.6rem; + color: var(--accent); + letter-spacing: 1px; + margin-bottom: 0.75rem; +} + +.gameover-card .sheet-group { + text-align: left; + margin-top: 1.5rem; +} + +.crew-epitaph-row { + background: var(--well); + padding: 0.75rem; + border-radius: var(--radius-sm); + margin-bottom: 0.5rem; + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 0.5rem; +} + +.crew-epitaph-row .objectives-summary { + font-size: 0.85rem; + color: var(--text-muted); +} diff --git a/frontend/src/assets/css/base.css b/frontend/src/assets/css/base.css new file mode 100644 index 0000000..f213bc1 --- /dev/null +++ b/frontend/src/assets/css/base.css @@ -0,0 +1,208 @@ +/* --- Reset & page setup --- */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background: + radial-gradient(ellipse at 50% -20%, color-mix(in srgb, var(--accent) 7%, transparent) 0%, transparent 55%), + radial-gradient(circle at 50% 60%, var(--bg) 0%, var(--bg-deep) 100%); + background-attachment: fixed; + color: var(--text); + font-family: var(--font-body); + font-size: 16px; + line-height: 1.6; + min-height: 100vh; + display: flex; + flex-direction: column; + overflow-x: hidden; +} + +h1, h2, h3, h4, h5 { + font-family: var(--font-heading); + font-weight: 700; + line-height: 1.25; +} + +a { + color: var(--deep); +} + +::selection { + background: color-mix(in srgb, var(--accent) 35%, transparent); +} + +input[type="checkbox"] { + accent-color: var(--accent); +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 8px; +} +::-webkit-scrollbar-track { + background: var(--bg-deep); +} +::-webkit-scrollbar-thumb { + background: color-mix(in srgb, var(--accent) 50%, var(--bg-deep)); + border-radius: 4px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--accent); +} + +/* --- App layout --- */ +.app-main { + flex: 1; + padding: 2rem; + max-width: 1400px; + width: 100%; + margin: 0 auto; +} + +/* Top padding clears the fixed corner menu */ +.dashboard-container { + padding: 3.5rem 2rem 4rem; + max-width: 1400px; + width: 100%; + margin: 0 auto; +} + +@media (max-width: 600px) { + .dashboard-container { + padding: 3.5rem 1rem 4rem; + } +} + +.view-header { + margin-bottom: 1.5rem; +} + +.view-header h2, +.lobby-view h2, +.scene-setup-view h2, +.between-scenes-view h2 { + font-size: 2.1rem; + color: var(--accent); + margin-bottom: 0.5rem; + letter-spacing: 0.5px; +} + +.description { + color: var(--text-muted); + max-width: 720px; + margin: 0 auto 1.5rem; +} + +/* --- Loader / spinner widgets --- */ +.loader-container { + padding: 4rem; +} + +.spinner { + width: 50px; + height: 50px; + border: 3px solid var(--edge-soft); + border-radius: 50%; + border-top-color: var(--accent); + animation: spin 1s ease-in-out infinite; + margin: 0 auto 1.5rem; +} + +.spinner-small { + width: 20px; + height: 20px; + border: 2px solid var(--edge-soft); + border-radius: 50%; + border-top-color: var(--accent); + animation: spin 1s ease-in-out infinite; + display: inline-block; + flex-shrink: 0; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* --- Text utilities --- */ +.text-center { text-align: center; } +.text-left { text-align: left; } +.text-sm { font-size: 0.875rem; } +.italic { font-style: italic; } +.font-bold { font-weight: 700; } +.font-mono { font-family: ui-monospace, monospace; } +.underline { text-decoration: underline; } + +.text-muted { color: var(--text-muted); } +.text-accent, .gold-text { color: var(--accent); } +.text-danger { color: var(--danger); } +.text-success, .success-text { color: var(--success); font-weight: 600; } +.text-warning { color: var(--warning); } +.text-deep, .deep-text { color: var(--deep); } + +.info-text { + font-size: 0.9rem; + color: var(--text-muted); + margin-bottom: 0.5rem; +} + +.section-desc { + font-size: 0.9rem; + color: var(--text-muted); + margin-bottom: 1rem; +} + +.empty-text { + color: var(--text-muted); + font-style: italic; + font-size: 0.9rem; +} + +.footnote, .footnote-desc { + font-size: 0.8rem; + color: var(--text-muted); +} + +.footnote-desc { + margin-top: 0.15rem; + margin-left: 1.5rem; +} + +/* --- Spacing & layout utilities --- */ +.mt-2 { margin-top: 0.5rem; } +.mt-4 { margin-top: 1rem; } +.mt-6 { margin-top: 1.5rem; } +.mt-8 { margin-top: 2rem; } +.mb-4 { margin-bottom: 1rem; } +.mb-6 { margin-bottom: 1.5rem; } +.p-3 { padding: 0.75rem; } +.p-4 { padding: 1rem; } +.p-6 { padding: 1.5rem; } +.mx-auto { margin-left: auto; margin-right: auto; } +.margin-top { margin-top: 1.5rem; } +.margin-top-small { margin-top: 0.5rem; } + +.flex { display: flex; } +.flex-grow { flex: 1; } +.items-center { align-items: center; } +.justify-center { justify-content: center; } +.justify-between { justify-content: space-between; } +.gap-2 { gap: 0.5rem; } +.gap-4 { gap: 1rem; } +.w-full { width: 100%; } +.max-w-4xl { max-width: 56rem; } +.max-w-5xl { max-width: 64rem; } +.space-y-2 > * + * { margin-top: 0.5rem; } +.space-y-6 > * + * { margin-top: 1.5rem; } + +.center-block { margin: 1rem auto; max-width: 500px; } +.inline-form { display: flex; gap: 0.5rem; width: 100%; } +.inline-group { display: flex; gap: 0.5rem; width: 100%; } + +/* --- Ghost World --- */ +.ghost-world { + filter: grayscale(95%) brightness(0.85) sepia(15%) contrast(1.05); + transition: filter 1.2s ease-in-out; +} diff --git a/frontend/src/assets/css/card.css b/frontend/src/assets/css/card.css index 4eb3161..63ff5f6 100644 --- a/frontend/src/assets/css/card.css +++ b/frontend/src/assets/css/card.css @@ -1,22 +1,44 @@ -/* Card Widget (Mini) */ +/* ============================================================ + Playing-card widgets (Card.svelte: mini / medium / large) + Light parchment faces on the dark table for contrast. + ============================================================ */ + +/* Shared face */ +.card-mini, .card-medium, .card-large { + background: linear-gradient(150deg, var(--card-face) 0%, var(--card-face-shade) 100%); + border: 1px solid color-mix(in srgb, var(--card-ink-black) 35%, var(--card-face-shade)); + color: var(--card-ink-black); +} + +.card-mini.suit-h, .card-mini.suit-d, +.card-medium.suit-h .val, .card-medium.suit-h .suit, .card-medium.suit-h .card-center, +.card-medium.suit-d .val, .card-medium.suit-d .suit, .card-medium.suit-d .card-center, +.card-large.suit-h .val, .card-large.suit-h .suit, .card-large.suit-h .card-center, +.card-large.suit-d .val, .card-large.suit-d .suit, .card-large.suit-d .card-center { + color: var(--card-ink-red); +} + +.card-medium.joker-card, .card-large.joker-card { + background: linear-gradient(150deg, color-mix(in srgb, var(--accent) 30%, var(--card-face)) 0%, var(--card-face-shade) 100%); + border-color: var(--accent-dark); +} + +/* --- Mini (played-card columns) --- */ .card-mini { width: 32px; height: 48px; border-radius: 4px; - border: 1px solid var(--text-muted); - background: var(--bg-dark); display: flex; flex-direction: column; justify-content: space-between; padding: 2px 4px; font-size: 0.7rem; font-weight: 900; + position: relative; } .card-mini.base-card { - border-color: var(--gold); - color: var(--gold); - background: rgba(212,175,55,0.1); + box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent); } .card-mini.rotated { @@ -25,13 +47,11 @@ } .card-mini.success { - border-color: var(--neon-emerald); - color: var(--neon-emerald); + box-shadow: 0 0 0 2px var(--success); } .card-mini.failure { - border-color: var(--red-suit); - color: var(--red-suit); + box-shadow: 0 0 0 2px var(--danger); } .card-mini .val { @@ -48,17 +68,15 @@ position: absolute; bottom: -1px; left: 1px; - color: var(--text-muted); + color: color-mix(in srgb, var(--card-ink-black) 60%, var(--card-face)); } -/* Card Widget (Medium) */ +/* --- Medium (obstacle display) --- */ .card-medium { width: 75px; height: 112px; - border-radius: 6px; - border: 1.5px solid var(--glass-border); - background: linear-gradient(135deg, var(--bg-ocean-light) 0%, var(--bg-dark) 100%); - box-shadow: 0 3px 10px rgba(0,0,0,0.4); + border-radius: var(--radius-sm); + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4); display: flex; flex-direction: column; justify-content: space-between; @@ -83,29 +101,6 @@ font-size: 0.75rem; } -.card-medium.suit-c, .card-medium.suit-s { - border-color: rgba(226, 232, 240, 0.15); -} - -.card-medium.suit-h, .card-medium.suit-d { - border-color: rgba(255, 42, 95, 0.15); -} - -.card-medium.joker-card { - border-color: var(--gold); - background: linear-gradient(135deg, #1d1b10 0%, var(--bg-dark) 100%); -} - -.card-medium.suit-c .val, .card-medium.suit-c .suit, -.card-medium.suit-s .val, .card-medium.suit-s .suit { - color: var(--black-suit); -} - -.card-medium.suit-h .val, .card-medium.suit-h .suit, -.card-medium.suit-d .val, .card-medium.suit-d .suit { - color: var(--red-suit); -} - .card-medium .card-center { font-size: 1.8rem; text-align: center; @@ -113,17 +108,13 @@ margin: auto 0; } -.card-medium.suit-c .card-center, .card-medium.suit-s .card-center { color: var(--black-suit); } -.card-medium.suit-h .card-center, .card-medium.suit-d .card-center { color: var(--red-suit); } - -/* Card Widget (Large) */ +/* --- Large (the player's hand) --- */ .card-large { width: 110px; height: 165px; - border-radius: 8px; - border: 2px solid var(--glass-border); - background: linear-gradient(135deg, var(--bg-ocean-light) 0%, var(--bg-dark) 100%); - box-shadow: 0 4px 15px rgba(0,0,0,0.5); + border-radius: var(--radius-md); + border-width: 2px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5); display: flex; flex-direction: column; justify-content: space-between; @@ -134,29 +125,7 @@ .card-large:hover { transform: translateY(-8px) scale(1.05); - border-color: var(--gold); - box-shadow: 0 10px 25px rgba(212, 175, 55, 0.2); -} - -.card-large.suit-c, .card-large.suit-s { - border-color: rgba(226, 232, 240, 0.15); -} -.card-large.suit-c:hover, .card-large.suit-s:hover { - border-color: var(--black-suit); - box-shadow: 0 10px 25px var(--black-glow); -} - -.card-large.suit-h, .card-large.suit-d { - border-color: rgba(255, 42, 95, 0.15); -} -.card-large.suit-h:hover, .card-large.suit-d:hover { - border-color: var(--red-suit); - box-shadow: 0 10px 25px var(--red-glow); -} - -.card-large.joker-card { - border-color: var(--gold); - background: linear-gradient(135deg, #1d1b10 0%, var(--bg-dark) 100%); + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.55), 0 0 14px color-mix(in srgb, var(--accent) 30%, transparent); } .card-large .card-corner { @@ -175,16 +144,6 @@ font-size: 1rem; } -.card-large.suit-c .val, .card-large.suit-c .suit, -.card-large.suit-s .val, .card-large.suit-s .suit { - color: var(--black-suit); -} - -.card-large.suit-h .val, .card-large.suit-h .suit, -.card-large.suit-d .val, .card-large.suit-d .suit { - color: var(--red-suit); -} - .card-large .card-center { font-size: 2.8rem; text-align: center; @@ -192,9 +151,6 @@ margin: auto 0; } -.card-large.suit-c .card-center, .card-large.suit-s .card-center { color: var(--black-suit); } -.card-large.suit-h .card-center, .card-large.suit-d .card-center { color: var(--red-suit); } - .card-large .card-tech-overlay { position: absolute; bottom: 0.5rem; @@ -203,10 +159,10 @@ text-align: center; } -.tech-tag { - background: rgba(0, 0, 0, 0.7); - border: 1px solid var(--gold); - color: var(--gold); +.card-large .tech-tag { + background: color-mix(in srgb, var(--surface) 92%, transparent); + border: 1px solid var(--accent); + color: var(--accent-bright); font-size: 0.65rem; padding: 0.15rem 0.3rem; border-radius: 4px; @@ -220,7 +176,7 @@ gap: 2px; } -/* Drag and Drop Interface Styles */ +/* --- Drag & drop --- */ .card-large[draggable="true"] { cursor: grab; } @@ -236,9 +192,9 @@ } .obstacle-item.drag-over { - border-color: var(--gold) !important; - background: rgba(212, 175, 55, 0.1) !important; - box-shadow: 0 0 20px rgba(212, 175, 55, 0.2) !important; + border-color: var(--accent) !important; + background: color-mix(in srgb, var(--accent) 9%, transparent) !important; + box-shadow: 0 0 20px color-mix(in srgb, var(--accent) 20%, transparent) !important; transform: translateY(-2px) scale(1.01); - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + transition: var(--transition-smooth); } diff --git a/frontend/src/assets/css/character.css b/frontend/src/assets/css/character.css index 13ea2f4..17a0e4f 100644 --- a/frontend/src/assets/css/character.css +++ b/frontend/src/assets/css/character.css @@ -1,4 +1,4 @@ -/* --- Character Creation & Sheet Grid --- */ +/* --- Character creation & sheet --- */ .creation-grid { display: grid; grid-template-columns: 1fr 1fr; @@ -10,20 +10,18 @@ .creation-grid { grid-template-columns: 1fr; } -} -.section-desc { - font-size: 0.9rem; - color: var(--text-muted); - margin-bottom: 1rem; + .creation-grid > .card { + grid-column: span 1 !important; + } } .record-line { - background: rgba(0,0,0,0.2); + background: var(--well); padding: 0.75rem 1rem; - border-radius: 6px; + border-radius: var(--radius-sm); margin-bottom: 0.75rem; - border-left: 3px solid var(--gold); + border-left: 3px solid var(--accent); } .delegation-box { @@ -33,14 +31,15 @@ } .delegation-box h4 { + font-family: var(--font-body); font-size: 0.95rem; - color: var(--text-primary); + color: var(--text); margin-bottom: 0.5rem; } .answer-box { font-style: italic; - color: var(--neon-cyan); + color: var(--accent-bright); font-size: 1.05rem; } @@ -50,14 +49,6 @@ font-style: normal; } -.waiting-box { - font-size: 0.9rem; - color: var(--gold); - display: flex; - align-items: center; - gap: 0.5rem; -} - .inbox-list:has(.inbox-item) .inbox-empty-message { display: none; } @@ -65,8 +56,8 @@ .inbox-item { padding: 1rem; margin-bottom: 0.75rem; - border-left: 3px solid var(--neon-cyan); - background: rgba(0, 242, 254, 0.02); + border-left: 3px solid var(--deep); + background: color-mix(in srgb, var(--deep) 4%, transparent); } .inbox-item label { @@ -76,26 +67,22 @@ } .submitted-techniques .tech-chip { - background: rgba(212,175,55,0.05); - border: 1px solid var(--gold); - color: var(--gold); - padding: 0.5rem; - border-radius: 6px; + background: color-mix(in srgb, var(--accent) 6%, transparent); + border: 1px solid var(--accent); + color: var(--accent); + padding: 0.6rem 1rem; + font-size: 0.95rem; + border-radius: var(--radius-sm); margin-bottom: 0.5rem; font-family: var(--font-heading); } -.tech-chip { - padding: 0.6rem 1rem; - font-size: 0.95rem; -} - .tech-assignment-pill { - background: rgba(0, 242, 254, 0.05); - border: 1px solid var(--neon-cyan); - color: var(--text-primary); + background: color-mix(in srgb, var(--deep) 6%, transparent); + border: 1px solid var(--deep); + color: var(--text); padding: 0.6rem 1rem; - border-radius: 6px; + border-radius: var(--radius-sm); margin-bottom: 0.5rem; text-align: left; display: flex; @@ -104,8 +91,8 @@ } .card-rank { - background: var(--neon-cyan); - color: var(--bg-dark); + background: var(--accent); + color: var(--text-inverse); font-weight: 900; width: 24px; height: 24px; @@ -114,33 +101,30 @@ justify-content: center; border-radius: 50%; font-size: 0.85rem; + flex-shrink: 0; } -/* --- Character Sheet layout --- */ +/* Crew creation progress rows */ +.status-row { + background: var(--well); + border-left: 4px solid var(--edge); + border-radius: var(--radius-sm); + padding: 0.75rem; + display: flex; + justify-content: space-between; + align-items: center; + list-style: none; +} + +.status-row.is-ready { + border-left-color: var(--success); +} + +/* --- Character sheet layout --- */ .character-sheet-details { text-align: left; } -.sheet-group { - background: rgba(0,0,0,0.15); - padding: 1rem; - border-radius: 8px; - border-left: 2px solid var(--gold-dark); -} - -.sheet-group h4 { - color: var(--gold); - font-size: 0.95rem; - margin-bottom: 0.5rem; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.footnote { - font-size: 0.8rem; - color: var(--text-muted); -} - .techniques-list-sheet { list-style: none; } @@ -150,37 +134,23 @@ font-size: 0.95rem; } -.footnote-desc { - font-size: 0.8rem; - color: var(--text-muted); - margin-top: 0.15rem; - margin-left: 1.5rem; -} - -.margin-top-small { - margin-top: 0.5rem; -} - -/* --- Visual & Tactile Technique Assignment --- */ +/* --- Face-card technique assignment (drag & drop) --- */ .face-tech-drag-form { margin-top: 1.5rem; } .available-techniques-container { - background: rgba(255, 255, 255, 0.02); - border: 1px dashed var(--glass-border); - border-radius: 12px; + background: var(--well); + border: 1px dashed var(--edge); + border-radius: var(--radius-lg); padding: 1.25rem; margin-bottom: 2rem; - box-shadow: inset 0 0 15px rgba(0,0,0,0.2); } .available-techniques-container h4 { - font-family: var(--font-heading); - color: var(--gold); + color: var(--accent); font-size: 1.1rem; margin-bottom: 0.25rem; - text-transform: uppercase; letter-spacing: 0.5px; } @@ -200,18 +170,17 @@ } .draggable-tech-chip { - background: linear-gradient(135deg, rgba(22, 36, 59, 0.9) 0%, rgba(13, 23, 38, 0.9) 100%); - border: 1px solid var(--gold); - color: var(--text-primary); + background: var(--surface-raised); + border: 1px solid var(--accent); + color: var(--text); padding: 0.6rem 1rem; - border-radius: 8px; + border-radius: var(--radius-sm); cursor: grab; user-select: none; - font-family: var(--font-body); font-size: 0.95rem; font-weight: 500; transition: var(--transition-smooth); - box-shadow: 0 4px 10px rgba(0,0,0,0.3), 0 0 5px rgba(212, 175, 55, 0.1); + box-shadow: var(--shadow-soft); display: flex; align-items: center; gap: 0.5rem; @@ -219,8 +188,7 @@ .draggable-tech-chip:hover { transform: translateY(-2px); - border-color: var(--neon-cyan); - box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4), 0 0 10px rgba(0, 242, 254, 0.3); + border-color: var(--accent-bright); } .draggable-tech-chip:active { @@ -232,26 +200,20 @@ border-style: dashed; } -.draggable-tech-chip.selected { - border-color: var(--neon-cyan); - box-shadow: 0 0 15px rgba(0, 242, 254, 0.5); - background: rgba(0, 242, 254, 0.1); -} - .draggable-tech-chip.assigned-hidden { opacity: 0.2; pointer-events: none; cursor: not-allowed; - border-color: var(--text-muted); + border-color: var(--edge); } .drag-icon { - color: var(--gold); + color: var(--accent); font-size: 0.8rem; opacity: 0.7; } -/* Slots Grid */ +/* Face-card slots */ .face-cards-slots-grid { display: grid; grid-template-columns: repeat(3, 1fr); @@ -276,9 +238,9 @@ max-width: 220px; aspect-ratio: 2 / 3; min-height: 280px; - background: linear-gradient(135deg, rgba(13, 23, 38, 0.8) 0%, rgba(7, 11, 18, 0.9) 100%); - border: 2px dashed rgba(212, 175, 55, 0.3); - border-radius: 12px; + background: var(--well); + border: 2px dashed var(--edge-accent); + border-radius: var(--radius-lg); padding: 1rem; display: flex; flex-direction: column; @@ -286,27 +248,25 @@ transition: var(--transition-smooth); overflow: hidden; cursor: pointer; - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4); + box-shadow: var(--shadow-soft); } .face-card-slot:hover { - border-color: rgba(212, 175, 55, 0.7); - box-shadow: 0 12px 30px rgba(212, 175, 55, 0.15); + border-color: var(--accent); transform: translateY(-4px); } .face-card-slot.drag-over { - border-color: var(--neon-cyan); + border-color: var(--accent-bright); border-style: solid; - background: rgba(0, 242, 254, 0.05); - box-shadow: 0 0 20px rgba(0, 242, 254, 0.2); + background: color-mix(in srgb, var(--accent) 7%, transparent); transform: scale(1.02); } .face-card-slot.has-assignment { border-style: solid; - border-color: var(--gold); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5), 0 0 15px rgba(212, 175, 55, 0.15); + border-color: var(--accent); + background: color-mix(in srgb, var(--accent) 5%, var(--well)); } .card-bg-letter { @@ -314,10 +274,9 @@ top: 50%; left: 50%; transform: translate(-50%, -50%); - font-family: var(--font-heading); - font-size: 8rem; - font-weight: 900; - color: rgba(255, 255, 255, 0.025); + font-family: var(--font-display); + font-size: 9rem; + color: color-mix(in srgb, var(--text) 4%, transparent); line-height: 1; pointer-events: none; user-select: none; @@ -325,7 +284,7 @@ } .face-card-slot.has-assignment .card-bg-letter { - color: rgba(212, 175, 55, 0.04); + color: color-mix(in srgb, var(--accent) 8%, transparent); } .card-slot-header, .card-slot-footer { @@ -342,7 +301,7 @@ .face-card-slot.has-assignment .card-slot-header, .face-card-slot.has-assignment .card-slot-footer { - color: var(--gold); + color: var(--accent); } .card-slot-body { @@ -360,29 +319,29 @@ font-family: var(--font-heading); font-size: 1.2rem; font-weight: 700; - color: var(--text-primary); + color: var(--text); margin-bottom: 0.75rem; pointer-events: none; } .face-card-slot.has-assignment .card-title { - color: var(--gold); + color: var(--accent); } .drop-zone-placeholder { font-size: 0.8rem; color: var(--text-muted); - border: 1px dashed rgba(255, 255, 255, 0.1); - background: rgba(0, 0, 0, 0.2); - border-radius: 6px; + border: 1px dashed var(--edge); + background: var(--well); + border-radius: var(--radius-sm); padding: 0.5rem 0.75rem; transition: var(--transition-smooth); pointer-events: none; } .face-card-slot:hover .drop-zone-placeholder { - color: var(--text-primary); - border-color: rgba(255, 255, 255, 0.2); + color: var(--text); + border-color: var(--edge-accent); } .assigned-tech-content { @@ -399,14 +358,14 @@ } .assigned-tech-chip { - background: rgba(212, 175, 55, 0.08); - border: 1px solid var(--gold); - color: var(--text-primary); + background: color-mix(in srgb, var(--accent) 9%, transparent); + border: 1px solid var(--accent); + color: var(--text); padding: 0.5rem; - border-radius: 8px; + border-radius: var(--radius-sm); font-size: 0.85rem; position: relative; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); + box-shadow: var(--shadow-soft); word-break: break-word; animation: fadeIn 0.3s ease; } @@ -418,22 +377,21 @@ width: 18px; height: 18px; border-radius: 50%; - background: #c0392b; - border: 1px solid #e74c3c; - color: white; + background: var(--danger); + border: 1px solid color-mix(in srgb, var(--danger) 70%, var(--text)); + color: var(--text-inverse); font-size: 10px; font-weight: 900; display: flex; align-items: center; justify-content: center; cursor: pointer; - box-shadow: 0 2px 5px rgba(0,0,0,0.5); + box-shadow: var(--shadow-soft); transition: var(--transition-smooth); } .remove-tech-btn:hover { - background: #e74c3c; - transform: scale(1.1); + transform: scale(1.15); } @keyframes fadeIn { diff --git a/frontend/src/assets/css/components.css b/frontend/src/assets/css/components.css index e3abba0..c66cb37 100644 --- a/frontend/src/assets/css/components.css +++ b/frontend/src/assets/css/components.css @@ -1,39 +1,108 @@ -/* --- UI Panels & Glassmorphism --- */ +/* --- Panels --- */ .glass-panel { - background: var(--glass-bg); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid var(--glass-border); - border-radius: 12px; + background: color-mix(in srgb, var(--surface) 88%, transparent); + border: 1px solid var(--edge); + border-radius: var(--radius-lg); padding: 2rem; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); + box-shadow: var(--shadow-soft); transition: var(--transition-smooth); } .glass-panel:hover { - border-color: rgba(212, 175, 55, 0.35); - box-shadow: 0 8px 32px rgba(212, 175, 55, 0.05); + border-color: var(--edge-accent); } .card { - background: var(--bg-ocean-light); - border: 1px solid var(--glass-border); - border-radius: 12px; + background: var(--surface); + border: 1px solid var(--edge); + border-radius: var(--radius-lg); padding: 1.5rem; margin-bottom: 1.5rem; - box-shadow: 0 4px 15px rgba(0,0,0,0.3); - transition: var(--transition-smooth); + box-shadow: var(--shadow-soft); } .card h3 { - font-family: var(--font-heading); - color: var(--gold); + color: var(--accent); + font-size: 1.35rem; margin-bottom: 1rem; - border-bottom: 1px solid rgba(212, 175, 55, 0.2); + border-bottom: 1px solid var(--edge-accent); padding-bottom: 0.5rem; } -/* --- Forms & Controls --- */ +/* Sunken sub-section inside a panel (character sheet groups, ledgers...) */ +.sheet-group { + background: var(--well); + padding: 1rem; + border-radius: var(--radius-sm); + border-left: 2px solid var(--accent-dark); +} + +.sheet-group h4 { + color: var(--accent); + font-size: 1.05rem; + margin-bottom: 0.5rem; + letter-spacing: 0.5px; +} + +/* Notice banners (first-scene framing, over-limit warnings...) */ +.notice-banner { + border: 1px dashed var(--edge); + border-radius: var(--radius-md); + padding: 1rem 1.5rem; + margin: 0 auto 1.5rem; + max-width: 700px; + text-align: left; +} + +.notice-banner h4 { + margin-bottom: 0.5rem; +} + +.notice-banner.accent { + border-color: var(--accent); + background: color-mix(in srgb, var(--accent) 9%, transparent); +} +.notice-banner.accent h4 { color: var(--accent); } + +.notice-banner.danger { + border-color: var(--danger); + background: color-mix(in srgb, var(--danger) 9%, transparent); +} +.notice-banner.danger h4 { color: var(--danger); } + +/* Prompt boxes (character-sheet callouts: death, ghost, name...) */ +.prompt-box { + border: 1px dashed var(--edge); + border-left: 2px solid var(--edge); + padding: 1rem; + border-radius: var(--radius-md); + margin-bottom: 1rem; + background: var(--well); +} + +.prompt-box h4 { + margin-bottom: 0.5rem; +} + +.prompt-box.accent { + border-color: var(--accent); + background: color-mix(in srgb, var(--accent) 10%, transparent); +} +.prompt-box.accent h4 { color: var(--accent); } + +.prompt-box.danger { + border-color: var(--danger); + background: color-mix(in srgb, var(--danger) 9%, transparent); +} +.prompt-box.danger h4 { color: var(--danger); } + +.prompt-box.ghostly { + border-color: var(--ghost); + background: color-mix(in srgb, var(--ghost) 10%, transparent); +} +.prompt-box.ghostly h4 { color: var(--ghost); } + +/* --- Forms & controls --- */ .form-group { margin-bottom: 1.25rem; text-align: left; @@ -47,40 +116,35 @@ font-weight: 500; } -.input-field { +.input-field, .form-control, .select-field, .copy-input { width: 100%; - padding: 0.75rem 1rem; - background: rgba(7, 11, 18, 0.8); - border: 1px solid var(--glass-border); - border-radius: 8px; - color: var(--text-primary); + padding: 0.7rem 1rem; + background: var(--well); + border: 1px solid var(--edge); + border-radius: var(--radius-sm); + color: var(--text); font-family: var(--font-body); font-size: 1rem; transition: var(--transition-smooth); } -.input-field:focus { +.input-field::placeholder, .form-control::placeholder { + color: color-mix(in srgb, var(--text-muted) 70%, transparent); +} + +.input-field:focus, .form-control:focus, .select-field:focus { outline: none; - border-color: var(--neon-cyan); - box-shadow: 0 0 10px rgba(0, 242, 254, 0.2); + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent); } .select-field { - width: 100%; - padding: 0.75rem 1rem; - background: rgba(7, 11, 18, 0.8); - border: 1px solid var(--glass-border); - border-radius: 8px; - color: var(--text-primary); - font-family: var(--font-body); - font-size: 1rem; - transition: var(--transition-smooth); cursor: pointer; } -.select-field:focus { - outline: none; - border-color: var(--neon-cyan); +.input-large { + padding: 0.9rem 1.1rem; + font-size: 1.1rem; } .input-row { @@ -92,96 +156,112 @@ flex: 1; } +.select-small { padding: 0.5rem; font-size: 0.9rem; flex: 1; } +.select-xsmall { padding: 0.4rem 0.5rem; font-size: 0.85rem; width: 140px; } + +.checkbox-label { + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + font-size: 0.95rem; +} + +.objectives-checklist { + display: flex; + flex-direction: column; + gap: 0.35rem; +} + /* --- Buttons --- */ .btn { display: inline-block; - padding: 0.75rem 1.5rem; - font-family: var(--font-body); + padding: 0.7rem 1.5rem; + font-family: var(--font-heading); font-weight: 700; font-size: 1rem; - text-transform: uppercase; letter-spacing: 1px; - border: none; - border-radius: 8px; + border: 1px solid transparent; + border-radius: var(--radius-sm); cursor: pointer; transition: var(--transition-smooth); text-decoration: none; } .btn-primary { - background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%); - color: var(--text-dark); - box-shadow: 0 4px 15px var(--gold-glow); + background: linear-gradient(160deg, var(--accent-bright) 0%, var(--accent) 45%, var(--accent-dark) 100%); + border-color: var(--accent-dark); + color: var(--text-inverse); + box-shadow: var(--shadow-soft); } .btn-primary:hover:not(:disabled) { transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(212, 175, 55, 0.6); + box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 35%, transparent); } .btn-secondary { - background: rgba(255,255,255,0.08); - border: 1px solid rgba(255,255,255,0.15); - color: var(--text-primary); + background: color-mix(in srgb, var(--text) 8%, transparent); + border-color: var(--edge); + color: var(--text); } .btn-secondary:hover:not(:disabled) { - background: rgba(255,255,255,0.15); + background: color-mix(in srgb, var(--text) 15%, transparent); transform: translateY(-2px); } .btn-deep { - background: linear-gradient(135deg, #152238 0%, #0d1726 100%); - border: 1px solid var(--neon-cyan); - color: var(--neon-cyan); - box-shadow: 0 4px 15px rgba(0, 242, 254, 0.1); + background: color-mix(in srgb, var(--deep) 10%, var(--surface)); + border-color: var(--deep); + color: var(--deep); } .btn-deep:hover:not(:disabled) { - background: var(--neon-cyan); - color: var(--text-dark); - box-shadow: 0 4px 20px rgba(0, 242, 254, 0.4); + background: var(--deep); + color: var(--text-inverse); transform: translateY(-2px); } .btn-danger { - background: linear-gradient(135deg, #7a1c1c 0%, #c0392b 100%); - color: var(--text-primary); - box-shadow: 0 4px 15px rgba(192, 57, 43, 0.2); + background: color-mix(in srgb, var(--danger) 18%, var(--surface)); + border-color: var(--danger); + color: color-mix(in srgb, var(--danger) 70%, var(--text)); } .btn-danger:hover:not(:disabled) { + background: var(--danger); + color: var(--text-inverse); transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(192, 57, 43, 0.5); +} + +.btn-success { + background: color-mix(in srgb, var(--success) 18%, var(--surface)); + border-color: var(--success); + color: color-mix(in srgb, var(--success) 70%, var(--text)); +} + +.btn-success:hover:not(:disabled) { + background: var(--success); + color: var(--text-inverse); } .btn-gold { background: transparent; - border: 2px solid var(--gold); - color: var(--gold); - box-shadow: 0 0 10px rgba(212,175,55,0.1); + border: 2px solid var(--accent); + color: var(--accent); } .btn-gold:hover:not(:disabled) { - background: var(--gold); - color: var(--bg-dark); - box-shadow: 0 0 20px var(--gold-glow); + background: var(--accent); + color: var(--text-inverse); + box-shadow: 0 0 20px color-mix(in srgb, var(--accent) 40%, transparent); transform: translateY(-2px); } -.btn-full { - width: 100%; -} - -.btn-small { - padding: 0.4rem 0.8rem; - font-size: 0.8rem; -} - -.btn-large { - padding: 1rem 2rem; - font-size: 1.1rem; -} +.btn-full, .btn-block { width: 100%; } +.btn-small { padding: 0.4rem 0.8rem; font-size: 0.85rem; } +.btn-large { padding: 0.9rem 2rem; font-size: 1.15rem; } .btn:disabled { opacity: 0.5; @@ -191,111 +271,183 @@ } .glow-effect:hover { - filter: brightness(1.2); + filter: brightness(1.15); } -/* --- Event Log --- */ -.event-log-fab { - position: fixed; - bottom: 20px; - right: 20px; - width: 60px; - height: 60px; - border-radius: 50%; - background: var(--glass-bg); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - border: 1px solid var(--gold); - color: var(--gold); - font-size: 1.5rem; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5), 0 0 10px rgba(212, 175, 55, 0.2); +/* --- Alerts --- */ +.alert { + padding: 0.75rem 1.25rem; + margin-bottom: 1.5rem; + border-radius: var(--radius-sm); + text-align: center; + font-weight: 500; +} + +.alert-danger { + background: color-mix(in srgb, var(--danger) 14%, transparent); + border: 1px solid var(--danger); + color: color-mix(in srgb, var(--danger) 75%, var(--text)); +} + +/* --- Player chips --- */ +.player-chips { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + justify-content: center; + margin-top: 1rem; +} + +.player-chip { + background: color-mix(in srgb, var(--text) 6%, transparent); + border: 1px solid var(--edge); + padding: 0.5rem 1.25rem; + border-radius: 30px; display: flex; align-items: center; - justify-content: center; - cursor: pointer; - z-index: 1000; + gap: 0.5rem; transition: var(--transition-smooth); } -.event-log-fab:hover { - transform: scale(1.1); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.6), 0 0 15px rgba(212, 175, 55, 0.4); +.player-chip.current-user { + background: color-mix(in srgb, var(--accent) 14%, transparent); + border-color: var(--accent); } -.event-log-panel { - position: fixed; - bottom: 90px; - right: 20px; - width: 350px; - max-width: calc(100vw - 40px); - height: 400px; - max-height: calc(100vh - 120px); - background: var(--glass-bg); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid var(--glass-border); - border-radius: 12px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6); - display: flex; - flex-direction: column; - z-index: 999; - transition: transform 0.3s ease, opacity 0.3s ease; +.player-chip.voted-chip { + border-color: var(--success); + background-color: color-mix(in srgb, var(--success) 6%, transparent); } -.event-log-panel.hidden { - transform: translateY(20px) scale(0.95); - opacity: 0; - pointer-events: none; +.player-chip.not-voted-chip { + border-color: var(--edge); } -.event-log-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); +.list-chips { + justify-content: flex-start; } -.event-log-header h3 { - margin: 0; +.list-chips .player-chip { + padding: 0.4rem 1rem; + font-size: 0.9rem; +} + +.deep-chip { + border-color: var(--deep); + background: color-mix(in srgb, var(--deep) 5%, transparent); +} + +.pirat-chip { + border-color: var(--pirat); + background: color-mix(in srgb, var(--pirat) 5%, transparent); +} + +.player-chip.is-ghost { + border-color: var(--ghost); + color: var(--ghost); + background: color-mix(in srgb, var(--ghost) 10%, transparent); +} + +.player-chip.is-dead { + border-color: var(--danger); + color: var(--danger); + background: color-mix(in srgb, var(--danger) 10%, transparent); +} + +.player-chip.is-captain { + border-color: var(--accent); + color: var(--accent); + background: color-mix(in srgb, var(--accent) 10%, transparent); +} + +/* --- Badges --- */ +.creator-badge { + background: var(--accent); + color: var(--text-inverse); + font-size: 0.7rem; + font-weight: 700; + padding: 0.1rem 0.4rem; + border-radius: 4px; + text-transform: uppercase; +} + +.deep-badge, .pirat-badge, .ghost-badge { + padding: 0.1rem 0.45rem; + font-size: 0.75rem; + font-weight: 700; + border-radius: 4px; + margin-left: 0.35rem; + white-space: nowrap; +} + +.deep-badge { + background: color-mix(in srgb, var(--deep) 14%, transparent); + border: 1px solid var(--deep); + color: var(--deep); +} + +.pirat-badge { + background: color-mix(in srgb, var(--pirat) 14%, transparent); + border: 1px solid var(--pirat); + color: var(--pirat); +} + +.ghost-badge { + background: color-mix(in srgb, var(--ghost) 14%, transparent); + border: 1px solid var(--ghost); + color: var(--ghost); +} + +.captain-badge { + background: color-mix(in srgb, var(--accent) 14%, transparent); + border: 1px solid var(--accent); + color: var(--accent); + padding: 0.4rem 1rem; + border-radius: 20px; + font-size: 1rem; + font-weight: 700; font-family: var(--font-heading); - font-size: 1.1rem; - color: var(--gold); -} - -.event-log-container { - flex: 1; - overflow-y: auto; - padding: 1rem; - display: flex; - flex-direction: column; + display: inline-flex; + align-items: center; gap: 0.5rem; } -.event-list { - list-style: none; - padding: 0; - margin: 0; - display: flex; - flex-direction: column; - gap: 0.8rem; -} - -.event-item { - font-size: 0.9rem; - background: rgba(0, 0, 0, 0.3); - padding: 0.75rem; - border-radius: 8px; - border-left: 3px solid var(--neon-cyan); -} - -.event-time { - display: block; - font-size: 0.75rem; +.captain-badge.vacant { + background: color-mix(in srgb, var(--text) 4%, transparent); + border: 1px dashed var(--edge); color: var(--text-muted); - margin-bottom: 0.25rem; } -.event-msg { - color: var(--text-primary); +/* --- Waiting indicator --- */ +.waiting-box, .waiting-indicator { + font-size: 0.95rem; + color: var(--accent); + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; +} + +/* --- Dev mode --- */ +.dev-toggle { + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; + font-size: 0.85rem; + color: var(--text-muted); + margin-top: 0.5rem; +} + +.dev-banner { + background: var(--well); + border: 1px solid var(--accent); + border-radius: var(--radius-md); + padding: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + margin: 0 auto 1.5rem; + max-width: 56rem; } diff --git a/frontend/src/assets/css/core.css b/frontend/src/assets/css/core.css deleted file mode 100644 index b5bce89..0000000 --- a/frontend/src/assets/css/core.css +++ /dev/null @@ -1,237 +0,0 @@ -/* --- Variables & Tokens --- */ -:root { - --bg-dark: #070b12; - --bg-ocean: #0d1726; - --bg-ocean-light: #16243b; - - --gold: #d4af37; - --gold-glow: rgba(212, 175, 55, 0.4); - --gold-dark: #aa841c; - - --neon-cyan: #00f2fe; - --neon-emerald: #00ff87; - - --red-suit: #ff2a5f; - --red-glow: rgba(255, 42, 95, 0.3); - --black-suit: #e2e8f0; - --black-glow: rgba(226, 232, 240, 0.2); - - --glass-bg: rgba(13, 23, 38, 0.7); - --glass-bg-hover: rgba(22, 36, 59, 0.85); - --glass-border: rgba(212, 175, 55, 0.2); - --glass-border-focus: rgba(0, 242, 254, 0.4); - - --text-primary: #f1f5f9; - --text-muted: #94a3b8; - --text-dark: #0f172a; - - --font-heading: 'Cinzel', serif; - --font-body: 'Outfit', sans-serif; - - --transition-smooth: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -/* --- Base Reset & Setup --- */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - background: radial-gradient(circle at 50% 50%, var(--bg-ocean) 0%, var(--bg-dark) 100%); - color: var(--text-primary); - font-family: var(--font-body); - font-size: 16px; - line-height: 1.6; - min-height: 100vh; - display: flex; - flex-direction: column; - overflow-x: hidden; -} - -/* Custom Scrollbar */ -::-webkit-scrollbar { - width: 8px; -} -::-webkit-scrollbar-track { - background: var(--bg-dark); -} -::-webkit-scrollbar-thumb { - background: var(--gold-dark); - border-radius: 4px; -} -::-webkit-scrollbar-thumb:hover { - background: var(--gold); -} - -/* --- Layout Components --- */ -.app-header { - background: rgba(7, 11, 18, 0.95); - border-bottom: 2px solid var(--gold); - box-shadow: 0 4px 20px rgba(0,0,0,0.5); - padding: 1rem 2rem; - display: flex; - justify-content: space-between; - align-items: center; - position: sticky; - top: 0; - z-index: 100; -} - -.logo-container { - display: flex; - align-items: center; - gap: 0.75rem; -} - -.logo-container h1 { - font-family: var(--font-heading); - font-size: 1.8rem; - font-weight: 900; - letter-spacing: 2px; - background: linear-gradient(135deg, var(--gold) 30%, #fff 70%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - text-shadow: 0 0 10px var(--gold-glow); -} - -.math-magic { - font-family: var(--font-heading); - font-size: 2.2rem; - color: var(--neon-cyan); - text-shadow: 0 0 10px var(--neon-cyan), 0 0 20px var(--neon-cyan); - animation: pulse-glow 3s infinite ease-in-out; -} - -.header-status { - display: flex; - align-items: center; - gap: 1rem; -} - -.player-pill { - background: rgba(0, 242, 254, 0.1); - border: 1px solid var(--neon-cyan); - padding: 0.25rem 0.75rem; - border-radius: 20px; - font-size: 0.9rem; - font-weight: 700; - display: flex; - align-items: center; - gap: 0.5rem; -} - -.player-pill .bullet { - width: 8px; - height: 8px; - background-color: var(--neon-emerald); - border-radius: 50%; - box-shadow: 0 0 8px var(--neon-emerald); -} - -.phase-pill { - background: rgba(212, 175, 55, 0.1); - border: 1px solid var(--gold); - color: var(--gold); - padding: 0.25rem 0.75rem; - border-radius: 20px; - font-size: 0.9rem; - font-weight: 700; - letter-spacing: 1px; -} - -.app-main { - flex: 1; - padding: 2rem; - max-width: 1400px; - width: 100%; - margin: 0 auto; -} - -.app-footer { - background: var(--bg-dark); - padding: 1.5rem; - text-align: center; - border-top: 1px solid rgba(255,255,255,0.05); - font-size: 0.85rem; - color: var(--text-muted); -} - -/* --- Loader / Spinner widgets --- */ -.loader-container { - padding: 4rem; -} - -.spinner { - width: 50px; - height: 50px; - border: 3px solid rgba(0, 242, 254, 0.1); - border-radius: 50%; - border-top-color: var(--neon-cyan); - animation: spin 1s ease-in-out infinite; - margin: 0 auto 1.5rem; -} - -.spinner-small { - width: 20px; - height: 20px; - border: 2px solid rgba(255,255,255,0.1); - border-radius: 50%; - border-top-color: var(--gold); - animation: spin 1s ease-in-out infinite; - display: inline-block; -} - -/* --- Alert styles --- */ -.alert { - padding: 0.75rem 1.25rem; - margin-bottom: 1.5rem; - border-radius: 8px; - text-align: center; - font-weight: 500; -} - -.alert-danger { - background: rgba(192, 57, 43, 0.2); - border: 1px solid #c0392b; - color: #e74c3c; -} - -/* --- Animation keyframes --- */ -@keyframes spin { - to { transform: rotate(360deg); } -} - -@keyframes pulse-glow { - 0% { - text-shadow: 0 0 10px var(--neon-cyan), 0 0 20px var(--neon-cyan); - transform: scale(1); - } - 50% { - text-shadow: 0 0 15px var(--neon-cyan), 0 0 30px var(--neon-cyan), 0 0 40px var(--neon-cyan); - transform: scale(1.05); - } - 100% { - text-shadow: 0 0 10px var(--neon-cyan), 0 0 20px var(--neon-cyan); - transform: scale(1); - } -} - -/* --- Utilities --- */ -.text-center { text-align: center; } -.text-left { text-align: left; } -.margin-top { margin-top: 1.5rem; } -.gold-text { color: var(--gold); } -.center-block { margin: 1rem auto; max-width: 500px; } -.inline-form { display: flex; gap: 0.5rem; width: 100%; } -.inline-group { display: flex; gap: 0.5rem; width: 100%; } -.select-small { padding: 0.5rem; font-size: 0.9rem; flex: 1; } -.select-xsmall { padding: 0.4rem; font-size: 0.85rem; } -.btn-small { padding: 0.4rem 0.8rem; font-size: 0.85rem; } - -/* --- Ghost World Styles --- */ -.ghost-world { - filter: grayscale(95%) brightness(0.85) sepia(15%) contrast(1.05); - transition: filter 1.2s ease-in-out; -} diff --git a/frontend/src/assets/css/lobby.css b/frontend/src/assets/css/lobby.css index 9b48fe1..8ec4a30 100644 --- a/frontend/src/assets/css/lobby.css +++ b/frontend/src/assets/css/lobby.css @@ -1,64 +1,13 @@ -/* --- Lobby / Hold View --- */ +/* --- Lobby / Ship's Hold --- */ .lobby-view { max-width: 700px; margin: 2rem auto; } -.lobby-view h2 { - font-family: var(--font-heading); - font-size: 2.2rem; - color: var(--gold); - margin-bottom: 0.5rem; -} - .lobby-status-box { margin: 2rem 0; } -.player-chips { - display: flex; - flex-wrap: wrap; - gap: 0.75rem; - justify-content: center; - margin-top: 1rem; -} - -.player-chip { - background: rgba(255,255,255,0.06); - border: 1px solid rgba(255,255,255,0.1); - padding: 0.5rem 1.25rem; - border-radius: 30px; - display: flex; - align-items: center; - gap: 0.5rem; - transition: var(--transition-smooth); -} - -.player-chip.current-user { - background: rgba(0, 242, 254, 0.15); - border-color: var(--neon-cyan); - box-shadow: 0 0 10px rgba(0,242,254,0.15); -} - -.player-chip.voted-chip { - border-color: var(--neon-emerald); - background-color: rgba(0,255,135,0.05); -} - -.player-chip.not-voted-chip { - border-color: rgba(255,255,255,0.1); -} - -.creator-badge { - background: var(--gold); - color: var(--text-dark); - font-size: 0.7rem; - font-weight: 700; - padding: 0.1rem 0.4rem; - border-radius: 4px; - text-transform: uppercase; -} - .links-box { text-align: left; margin-bottom: 2rem; @@ -69,7 +18,7 @@ } .link-item h4 { - color: var(--text-primary); + color: var(--text); margin-bottom: 0.5rem; } @@ -80,27 +29,17 @@ .copy-input { flex: 1; - background: #05080e; - border: 1px solid var(--glass-border); - color: var(--text-primary); - padding: 0.5rem 1rem; - border-radius: 8px; - font-family: var(--font-body); + background: var(--bg-deep); font-size: 0.95rem; + padding: 0.5rem 1rem; } .copy-input.admin-input { - border-color: var(--gold-dark); - color: var(--gold); + border-color: var(--edge-accent); + color: var(--accent); } .admin-link-item { - border-top: 1px dashed rgba(212, 175, 55, 0.3); + border-top: 1px dashed var(--edge-accent); padding-top: 1.5rem; } - -.info-text { - font-size: 0.9rem; - color: var(--text-muted); - margin-bottom: 0.5rem; -} diff --git a/frontend/src/assets/css/scene-play.css b/frontend/src/assets/css/scene-play.css index c0a969f..56df859 100644 --- a/frontend/src/assets/css/scene-play.css +++ b/frontend/src/assets/css/scene-play.css @@ -1,4 +1,4 @@ -/* --- Scene Play Board Layout --- */ +/* --- Scene board layout --- */ .scene-view-layout { display: grid; grid-template-columns: 1.4fr 1fr; @@ -15,7 +15,7 @@ display: flex; justify-content: space-between; align-items: center; - border-bottom: 1px solid rgba(212, 175, 55, 0.2); + border-bottom: 1px solid var(--edge-accent); padding-bottom: 0.5rem; margin-bottom: 1rem; } @@ -28,11 +28,49 @@ .deck-counter { font-size: 0.85rem; - color: var(--gold); + color: var(--accent); font-weight: 700; } -/* --- Active Obstacle Item Display --- */ +/* Scene status banner (captain + roster) */ +.scene-status-banner { + margin-bottom: 1.5rem; + padding: 1rem; + background: var(--well); + border: 1px solid var(--edge); + border-radius: var(--radius-md); + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 1rem; +} + +.roster-chips { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + align-items: center; +} + +.roster-chips .roster-label { + font-size: 0.85rem; + color: var(--text-muted); + font-family: var(--font-heading); + margin-right: 0.25rem; +} + +.roster-chips .player-chip { + font-size: 0.8rem; + padding: 0.25rem 0.6rem; + border-radius: 12px; + margin: 0; + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +/* --- Obstacles --- */ .obstacles-container { display: flex; flex-direction: column; @@ -40,10 +78,10 @@ } .obstacle-item { - border: 1px solid var(--glass-border); - border-radius: 10px; + border: 1px solid var(--edge); + border-radius: var(--radius-md); padding: 1.25rem; - background: rgba(7, 11, 18, 0.4); + background: var(--well); display: grid; grid-template-columns: 0.8fr 2fr 1fr 1fr; gap: 1rem; @@ -51,6 +89,10 @@ overflow: hidden; } +.obstacle-item.in-challenge { + box-shadow: 0 0 0 2px var(--danger); +} + @media (max-width: 768px) { .obstacle-item { grid-template-columns: 0.8fr 2fr 1.5fr; @@ -63,20 +105,14 @@ } } -/* Color theme mappings for suits */ -.suit-c { border-left: 4px solid var(--black-suit); } -.suit-s { border-left: 4px solid var(--black-suit); } -.suit-h { border-left: 4px solid var(--red-suit); } -.suit-d { border-left: 4px solid var(--red-suit); } +/* Suit accent stripes */ +.suit-c, .suit-s { border-left: 4px solid var(--suit-black); } +.suit-h, .suit-d { border-left: 4px solid var(--suit-red); } -.obstacle-meta { +.obstacle-card-wrapper { display: flex; - flex-direction: column; justify-content: center; align-items: center; - background: rgba(0,0,0,0.3); - border-radius: 6px; - padding: 0.5rem; } .suit-badge { @@ -84,8 +120,8 @@ font-size: 1.1rem; } -.suit-c .suit-badge, .suit-s .suit-badge { color: var(--black-suit); } -.suit-h .suit-badge, .suit-d .suit-badge { color: var(--red-suit); } +.suit-c .suit-badge, .suit-s .suit-badge { color: var(--suit-black); } +.suit-h .suit-badge, .suit-d .suit-badge { color: var(--suit-red); } .card-code { font-size: 0.8rem; @@ -94,10 +130,14 @@ } .obstacle-details h4 { - font-family: var(--font-heading); - color: var(--text-primary); + color: var(--text); margin-bottom: 0.25rem; - font-size: 1.1rem; + font-size: 1.15rem; +} + +.obstacle-details .in-challenge-tag { + color: var(--danger); + font-size: 0.8rem; } .obstacle-details .desc { @@ -110,9 +150,9 @@ flex-direction: column; justify-content: center; align-items: center; - background: rgba(212, 175, 55, 0.04); - border: 1px dashed var(--glass-border); - border-radius: 6px; + background: color-mix(in srgb, var(--accent) 5%, transparent); + border: 1px dashed var(--edge-accent); + border-radius: var(--radius-sm); padding: 0.5rem; } @@ -121,14 +161,15 @@ flex-direction: column; justify-content: center; align-items: center; - background: rgba(0, 255, 135, 0.04); - border: 1px dashed rgba(0, 255, 135, 0.25); - border-radius: 6px; + background: color-mix(in srgb, var(--success) 5%, transparent); + border: 1px dashed color-mix(in srgb, var(--success) 30%, transparent); + border-radius: var(--radius-sm); padding: 0.5rem; } .obstacle-successes-display .val-number { - color: var(--neon-emerald); + color: var(--success); + font-size: 1.5rem; } .val-label { @@ -141,22 +182,16 @@ font-size: 1.8rem; font-family: var(--font-heading); font-weight: 900; - color: var(--gold); + color: var(--accent); } .played-column { - grid-column: span 4; - border-top: 1px solid rgba(255,255,255,0.05); + grid-column: 1 / -1; + border-top: 1px solid var(--edge-soft); padding-top: 0.75rem; margin-top: 0.5rem; } -@media (max-width: 600px) { - .played-column { - grid-column: span 1; - } -} - .played-column h5 { font-size: 0.8rem; color: var(--text-muted); @@ -170,82 +205,64 @@ gap: 0.75rem; } -/* --- Challenges Section --- */ -.challenges-container { - display: flex; - flex-direction: column; - gap: 1.25rem; +.clear-obstacle-row { + grid-column: 1 / -1; } +/* --- Challenges --- */ .challenge-item { - background: rgba(255,255,255,0.02); - border: 1px solid var(--glass-border); - border-radius: 8px; - padding: 1.25rem; + background: color-mix(in srgb, var(--danger) 5%, transparent); + border: 1px solid var(--danger); + border-radius: var(--radius-md); + padding: 1rem 1.25rem; + margin-bottom: 1rem; text-align: left; } .challenge-item h4 { - font-family: var(--font-heading); - color: var(--neon-cyan); - font-size: 1.2rem; - margin-bottom: 0.25rem; + color: var(--danger); + font-size: 1.15rem; + margin: 0; } -.challenge-item .desc { - font-size: 0.9rem; - color: var(--text-muted); - margin-bottom: 1rem; -} - -.applied-obstacles h5 { - font-size: 0.85rem; - color: var(--text-muted); - margin-bottom: 0.5rem; -} - -.applied-obs-row { - padding: 0.75rem 1rem; - margin-bottom: 0.5rem; +.challenge-head { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; - gap: 0.75rem; -} - -.obs-info { - display: flex; - align-items: center; gap: 0.5rem; } -.obs-info .symbol { - font-size: 1.2rem; -} - -.play-card-form { +.challenge-actions { display: flex; gap: 0.5rem; + flex-wrap: wrap; align-items: center; } -.select-xsmall { - padding: 0.25rem 0.5rem; - font-size: 0.8rem; - width: 140px; - background: var(--bg-dark); +.tax-callout { + margin-top: 0.75rem; + padding: 0.75rem; + border: 1px dashed var(--accent); + border-radius: var(--radius-sm); + background: color-mix(in srgb, var(--accent) 6%, transparent); } -/* --- Deep Control panel --- */ -.deep-text { - color: var(--neon-cyan) !important; +.tax-callout p { + margin: 0 0 0.5rem 0; +} + +/* --- Deep control panel --- */ +.deep-panel-card { + max-height: 80vh; + overflow-y: auto; + border-color: color-mix(in srgb, var(--deep) 40%, transparent); } .deep-divider { border: 0; height: 1px; - background: linear-gradient(to right, rgba(0, 242, 254, 0), rgba(0, 242, 254, 0.4), rgba(0, 242, 254, 0)); + background: linear-gradient(to right, transparent, color-mix(in srgb, var(--deep) 40%, transparent), transparent); margin: 2rem 0; } @@ -253,22 +270,28 @@ display: flex; flex-direction: column; gap: 0.5rem; - background: rgba(0,0,0,0.2); + background: var(--well); padding: 1rem; - border-radius: 8px; + border-radius: var(--radius-sm); max-height: 150px; overflow-y: auto; - border: 1px solid var(--glass-border); + border: 1px solid var(--edge); } -.checkbox-label { - display: flex; - align-items: center; - gap: 0.5rem; - cursor: pointer; - font-size: 0.95rem; +.objective-player-block { + background: var(--well); + padding: 0.5rem 0.75rem; + border-radius: var(--radius-sm); + margin-bottom: 0.5rem; } +.scene-upkeep-controls { + margin-top: 1rem; + border-top: 1px solid var(--edge-soft); + padding-top: 1rem; +} + +/* --- Hand --- */ .hand-flex { display: flex; flex-wrap: wrap; diff --git a/frontend/src/assets/css/scene-setup.css b/frontend/src/assets/css/scene-setup.css index cc8d232..ade35be 100644 --- a/frontend/src/assets/css/scene-setup.css +++ b/frontend/src/assets/css/scene-setup.css @@ -1,4 +1,4 @@ -/* --- Scene Setup / Role Choose --- */ +/* --- Scene setup / role choice --- */ .setup-grid { display: grid; grid-template-columns: 1.2fr 1fr; @@ -22,62 +22,60 @@ .role-btn { padding: 1.5rem; font-size: 1.2rem; - background: rgba(255,255,255,0.03); - border: 2px solid rgba(255,255,255,0.1); + background: var(--well); + border: 2px solid var(--edge); color: var(--text-muted); } -.role-btn.pirat-btn:hover, .role-btn.pirat-btn.active { - border-color: var(--neon-emerald); - color: var(--text-primary); - background-color: rgba(0,255,135,0.06); - box-shadow: 0 0 15px rgba(0,255,135,0.15); +.role-btn.pirat-btn:hover:not(:disabled), .role-btn.pirat-btn.active { + border-color: var(--pirat); + color: var(--text); + background-color: color-mix(in srgb, var(--pirat) 8%, transparent); } -.role-btn.deep-btn:hover, .role-btn.deep-btn.active { - border-color: var(--neon-cyan); - color: var(--text-primary); - background-color: rgba(0,242,254,0.06); - box-shadow: 0 0 15px rgba(0,242,254,0.15); +.role-btn.deep-btn:hover:not(:disabled), .role-btn.deep-btn.active { + border-color: var(--deep); + color: var(--text); + background-color: color-mix(in srgb, var(--deep) 8%, transparent); } -.large-badge { - padding: 0.5rem 2rem; - font-size: 1.5rem; - border-radius: 8px; +.role-badge { + padding: 0.15rem 0.75rem; + border-radius: var(--radius-sm); font-family: var(--font-heading); - margin-top: 0.5rem; -} - -.role-badge.deep { - background: rgba(0, 242, 254, 0.15); - border: 2px solid var(--neon-cyan); - color: var(--neon-cyan); - box-shadow: 0 0 15px rgba(0,242,254,0.1); -} - -.role-badge.pirat { - background: rgba(0, 255, 135, 0.15); - border: 2px solid var(--neon-emerald); - color: var(--neon-emerald); - box-shadow: 0 0 15px rgba(0,255,135,0.1); -} - -.list-chips { - justify-content: flex-start; -} - -.list-chips .player-chip { - padding: 0.4rem 1rem; font-size: 0.9rem; } -.deep-chip { - border-color: var(--neon-cyan); - background: rgba(0, 242, 254, 0.03); +.role-badge.deep { + background: color-mix(in srgb, var(--deep) 14%, transparent); + border: 1px solid var(--deep); + color: var(--deep); } -.pirat-chip { - border-color: var(--neon-emerald); - background: rgba(0, 255, 135, 0.03); +.role-badge.pirat { + background: color-mix(in srgb, var(--pirat) 14%, transparent); + border: 1px solid var(--pirat); + color: var(--pirat); +} + +.role-badge.unassigned { + background: var(--well); + border: 1px dashed var(--edge); + color: var(--text-muted); +} + +.roster-list { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.roster-item { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.75rem; + background: var(--well); + border-radius: var(--radius-sm); + padding: 0.6rem 0.9rem; } diff --git a/frontend/src/assets/css/style.css b/frontend/src/assets/css/style.css deleted file mode 100644 index 2a5d954..0000000 --- a/frontend/src/assets/css/style.css +++ /dev/null @@ -1,18 +0,0 @@ -/* ========================================================================== - RATS WITH GATS DESIGN SYSTEM & STYLESHEET - A weathered math-magic pirate aesthetic: deep-ocean dark mode, glassmorphism, - neon math runes, gold accents, and animated card widgets. - - This file imports modular stylesheets divided by page phase and components. - ========================================================================== */ - -@import url("core.css"); -@import url("components.css"); -@import url("card.css"); -@import url("welcome.css"); -@import url("lobby.css"); -@import url("character.css"); -@import url("scene-setup.css"); -@import url("scene-play.css"); -@import url("upkeep.css"); -@import url("admin.css"); diff --git a/frontend/src/assets/css/theme.css b/frontend/src/assets/css/theme.css new file mode 100644 index 0000000..8c7ca5c --- /dev/null +++ b/frontend/src/assets/css/theme.css @@ -0,0 +1,81 @@ +/* ============================================================ + RATS WITH GATS โ€” THEME TOKENS + "Lantern & Brine": a lantern-lit pirate ship at night. + + This file is the ONLY place colors, fonts, radii, and shadows + are defined. Every other stylesheet derives translucent + variants with color-mix(), so re-theming the app means + editing this file and nothing else. + (Font files are bundled via @fontsource imports in main.js.) + ============================================================ */ + +:root { + /* --- Raw palette ---------------------------------------- */ + --ink-deep: #0a0d13; /* darkest: page edges, sunken wells */ + --ink: #131822; /* page background */ + --hull: #1b212e; /* panel surface */ + --hull-light: #262e3f; /* raised surface */ + + --parchment: #efe7d3; /* primary text */ + --driftwood: #a89e8a; /* muted text */ + + --brass: #d9a23c; /* primary accent */ + --brass-bright: #f3c365; + --brass-dark: #93701f; + + --tide: #41c9bd; /* the Deep */ + --kelp: #6cc983; /* Pi-Rats, success */ + --coral: #e8606e; /* danger, red suits */ + --bone: #dfe6ef; /* black suits */ + --ember: #f0954c; /* warnings, jokers */ + --mystic: #a08cd8; /* votes, objectives, misc arcana */ + --ghost: #8fa3b8; /* dead & ghostly things */ + + /* Playing-card faces (light parchment cards on a dark table) */ + --card-face: #f2e9d2; + --card-face-shade: #ddcfa9; + --card-ink-red: #b03546; + --card-ink-black: #2a3040; + + /* --- Semantic assignments -------------------------------- */ + --bg: var(--ink); + --bg-deep: var(--ink-deep); + --surface: var(--hull); + --surface-raised: var(--hull-light); + --well: color-mix(in srgb, var(--ink-deep) 55%, transparent); + + --text: var(--parchment); + --text-muted: var(--driftwood); + --text-inverse: #1c1508; + + --accent: var(--brass); + --accent-bright: var(--brass-bright); + --accent-dark: var(--brass-dark); + + --deep: var(--tide); + --pirat: var(--kelp); + --success: var(--kelp); + --danger: var(--coral); + --warning: var(--ember); + + --suit-red: var(--coral); + --suit-black: var(--bone); + + /* Borders */ + --edge: color-mix(in srgb, var(--parchment) 14%, transparent); + --edge-soft: color-mix(in srgb, var(--parchment) 8%, transparent); + --edge-accent: color-mix(in srgb, var(--accent) 35%, transparent); + + /* --- Type ------------------------------------------------ */ + --font-display: 'Pirata One', 'Alegreya SC', serif; + --font-heading: 'Alegreya SC', serif; + --font-body: 'Alegreya Sans', sans-serif; + + /* --- Shape & motion -------------------------------------- */ + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; + --shadow-soft: 0 4px 14px rgba(0, 0, 0, 0.35); + --shadow-deep: 0 10px 30px rgba(0, 0, 0, 0.5); + --transition-smooth: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); +} diff --git a/frontend/src/assets/css/upkeep.css b/frontend/src/assets/css/upkeep.css index 5a949a8..8e14e1d 100644 --- a/frontend/src/assets/css/upkeep.css +++ b/frontend/src/assets/css/upkeep.css @@ -1,4 +1,4 @@ -/* --- Between Scenes Upkeep --- */ +/* --- Between-scenes upkeep --- */ .between-grid { display: grid; grid-template-columns: 1fr 1fr; @@ -19,12 +19,7 @@ .voted-confirmation-box { padding: 1.5rem; text-align: center; - border: 1px solid var(--neon-emerald); -} - -.success-text { - color: var(--neon-emerald); - font-weight: 700; + border: 1px solid var(--success); } .ranks-ledger { @@ -33,30 +28,66 @@ .ranks-ledger li { padding: 0.5rem; - border-bottom: 1px solid rgba(255,255,255,0.05); + border-bottom: 1px solid var(--edge-soft); display: flex; justify-content: space-between; } -.deep-badge { - background: rgba(0, 242, 254, 0.15); - border: 1px solid var(--neon-cyan); - color: var(--neon-cyan); - padding: 0.1rem 0.4rem; - font-size: 0.75rem; - border-radius: 4px; +/* --- Death fate panel --- */ +.death-fate-card { + border: 2px solid var(--danger); + background: color-mix(in srgb, var(--danger) 5%, var(--surface)); + padding: 2.5rem; + margin: 2rem auto; + max-width: 650px; + text-align: center; } -.pirat-badge { - background: rgba(0, 255, 135, 0.15); - border: 1px solid var(--neon-emerald); - color: var(--neon-emerald); - padding: 0.1rem 0.4rem; - font-size: 0.75rem; - border-radius: 4px; +.death-fate-card > h2 { + color: var(--danger); + font-size: 2rem; + margin-bottom: 1rem; } -/* --- Deep Upkeep Hand Refresh Drag & Drop --- */ +.death-fate-card .description { + font-size: 1.15rem; + color: var(--text); + margin-bottom: 2rem; +} + +.fate-choices { + display: flex; + gap: 1.5rem; + justify-content: center; + flex-wrap: wrap; +} + +.creation-form-wrapper { + text-align: left; + background: var(--well); + padding: 1.5rem; + border-radius: var(--radius-md); + border: 1px solid var(--edge-soft); +} + +.creation-form-wrapper h3 { + color: var(--accent); + margin-bottom: 1.5rem; + border-bottom: 1px solid var(--edge-accent); + padding-bottom: 0.5rem; +} + +.form-actions { + display: flex; + gap: 1rem; + margin-top: 1.5rem; +} + +.form-actions .btn { + flex: 1; +} + +/* --- Deep hand refresh drag & drop --- */ .upkeep-drag-container { display: grid; grid-template-columns: 1fr 1fr; @@ -76,9 +107,9 @@ flex-direction: column; } -.upkeep-box h3 { +.upkeep-box h4 { margin-bottom: 1rem; - font-family: var(--font-heading); + font-size: 1.1rem; } .upkeep-flex { @@ -87,14 +118,16 @@ flex-wrap: wrap; gap: 1rem; padding: 1.5rem; - background: rgba(0, 0, 0, 0.3); - border: 1px dashed var(--glass-border); - border-radius: 8px; + background: var(--well); + border: 1px dashed var(--edge); + border-radius: var(--radius-md); align-content: flex-start; min-height: 300px; transition: var(--transition-smooth); } -.upkeep-box[ondragover]:hover .upkeep-flex { - border-color: var(--neon-cyan); +.end-story-box { + margin-top: 1.5rem; + border-top: 1px solid var(--edge-soft); + padding-top: 1rem; } diff --git a/frontend/src/assets/css/welcome.css b/frontend/src/assets/css/welcome.css index a06e78e..18efd33 100644 --- a/frontend/src/assets/css/welcome.css +++ b/frontend/src/assets/css/welcome.css @@ -1,50 +1,89 @@ -/* --- Welcome / Main Menu Screen --- */ +/* --- Welcome / splash & join screens --- */ .welcome-container { - max-width: 900px; - margin: 4rem auto; + max-width: 560px; + margin: 0 auto; + padding: 4rem 1.5rem 3rem; + text-align: center; } -.welcome-hero h2 { +.welcome-hero { + margin-bottom: 2.5rem; +} + +.hero-overline { font-family: var(--font-heading); - font-size: 2.5rem; - color: var(--text-primary); - margin-bottom: 1rem; -} - -.welcome-hero .subtitle { - font-size: 1.2rem; + font-size: 0.95rem; + letter-spacing: 4px; + text-transform: uppercase; color: var(--text-muted); - margin-bottom: 3rem; + margin-bottom: 0.5rem; } -.welcome-actions { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2rem; -} - -@media (max-width: 768px) { - .welcome-actions { - grid-template-columns: 1fr; - } -} - -.action-card { - padding: 2.5rem 1.5rem; - display: flex; - flex-direction: column; - justify-content: space-between; - height: 300px; -} - -.action-card h3 { - font-family: var(--font-heading); - color: var(--gold); - font-size: 1.5rem; +.wordmark { + font-family: var(--font-display); + font-weight: 400; + font-size: clamp(3.2rem, 10vw, 5rem); + line-height: 1; + letter-spacing: 2px; + background: linear-gradient(175deg, var(--accent-bright) 20%, var(--accent) 55%, var(--accent-dark) 100%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + filter: drop-shadow(0 3px 12px color-mix(in srgb, var(--accent) 30%, transparent)); margin-bottom: 0.75rem; } -.action-card p { - color: var(--text-muted); - margin-bottom: 2rem; +.wordmark .amp { + font-size: 0.45em; + vertical-align: 0.45em; + letter-spacing: 1px; +} + +.welcome-hero .subtitle { + font-size: 1.15rem; + color: var(--text-muted); + max-width: 420px; + margin: 0 auto; +} + +/* Anchor divider: โ€”โ€”โ€” โš“ โ€”โ€”โ€” */ +.hero-flourish { + display: flex; + align-items: center; + gap: 1rem; + color: var(--accent); + font-size: 1.2rem; + margin: 1.75rem auto 0; + max-width: 320px; +} + +.hero-flourish::before, +.hero-flourish::after { + content: ''; + flex: 1; + height: 1px; + background: linear-gradient(to right, transparent, var(--edge-accent), transparent); +} + +.creation-card { + text-align: left; +} + +.creation-card h2 { + color: var(--accent); + font-size: 1.5rem; + margin-bottom: 1.25rem; + text-align: center; +} + +.join-hint { + font-size: 0.85rem; + color: var(--text-muted); + text-align: center; + margin-top: 1.25rem; + margin-bottom: 0; +} + +.welcome-links { + margin-top: 1.75rem; } diff --git a/frontend/src/components/CharacterCreationPhase.svelte b/frontend/src/components/CharacterCreationPhase.svelte index 09d7202..f328619 100644 --- a/frontend/src/components/CharacterCreationPhase.svelte +++ b/frontend/src/components/CharacterCreationPhase.svelte @@ -171,15 +171,15 @@

Character Sheet Creation

Fill in your Rat Records, delegate questions to your crew, and prepare your Math Magic Techniques.

-
- +
+
{#if devMode} -
- ๐Ÿ›  Dev Mode Tools +
+ ๐Ÿ›  Dev Mode Tools
{:else} -

Assigning crewmates to write your relationships...

+

Assigning crewmates to write your relationships...

{/if}
@@ -295,7 +295,7 @@ {/if} {/each} {#if state.players.filter(p => (p.other_like_from_player_id === state.player.id && !p.other_like) || (p.other_hate_from_player_id === state.player.id && !p.other_hate)).length === 0} -

No pending tasks! Wait for other players to assign you tasks.

+

No pending tasks! Wait for other players to assign you tasks.

{/if} @@ -346,7 +346,7 @@ {:else if !techniquesComplete} {#if swappedTechniques.length === 3}
-

Drag and drop your assigned techniques onto your Face Cards:

+

Drag and drop your assigned techniques onto your Face Cards:

{#if faceError}
{faceError}
@@ -488,7 +488,7 @@
{:else} -
+
Waiting for all players to submit techniques so they can be shuffled...
{/if} @@ -512,15 +512,15 @@
    {#each state.players as p} -
  • +
  • {displayName(p)} {#if p.tech_jack} - Ready + Ready {:else if p.created_techniques && JSON.parse(p.created_techniques).length === 3} - Assigning Face Cards + Assigning Face Cards {:else} - Writing Sheet + Writing Sheet {/if}
  • diff --git a/frontend/src/components/CornerMenu.svelte b/frontend/src/components/CornerMenu.svelte index 9bcd496..13ad122 100644 --- a/frontend/src/components/CornerMenu.svelte +++ b/frontend/src/components/CornerMenu.svelte @@ -48,29 +48,29 @@ .menu-toggle { padding: 6px 14px; border-radius: 16px; - background: rgba(10, 15, 25, 0.9); - border: 1px solid var(--glass-border-focus); - color: var(--neon-cyan); + background: color-mix(in srgb, var(--bg-deep) 92%, transparent); + border: 1px solid var(--edge-accent); + color: var(--accent); font-size: 0.85rem; font-weight: 700; font-family: var(--font-heading); cursor: pointer; } .menu-toggle:hover, .menu-toggle.open { - background: rgba(0, 242, 254, 0.1); + background: color-mix(in srgb, var(--accent) 12%, var(--bg-deep)); } .menu-dropdown { margin-top: 6px; display: flex; flex-direction: column; - background: rgba(10, 15, 25, 0.95); - border: 1px solid var(--glass-border-focus); - border-radius: 12px; + background: color-mix(in srgb, var(--bg-deep) 96%, transparent); + border: 1px solid var(--edge-accent); + border-radius: var(--radius-md); overflow: hidden; } .menu-dropdown a { padding: 8px 16px; - color: var(--neon-cyan); + color: var(--accent); font-size: 0.85rem; font-weight: 700; text-decoration: none; @@ -79,9 +79,9 @@ white-space: nowrap; } .menu-dropdown a:hover { - background: rgba(0, 242, 254, 0.1); + background: color-mix(in srgb, var(--accent) 12%, transparent); } .menu-dropdown a + a { - border-top: 1px solid rgba(0, 242, 254, 0.15); + border-top: 1px solid var(--edge-soft); } diff --git a/frontend/src/components/EventLog.svelte b/frontend/src/components/EventLog.svelte index 170c2ee..e3ae454 100644 --- a/frontend/src/components/EventLog.svelte +++ b/frontend/src/components/EventLog.svelte @@ -150,10 +150,10 @@ bottom: 20px; right: 20px; width: 380px; - background: rgba(10, 15, 25, 0.95); - border: 1px solid var(--glass-border, rgba(255, 255, 255, 0.1)); - border-radius: 8px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); + background: color-mix(in srgb, var(--bg-deep) 95%, transparent); + border: 1px solid var(--edge); + border-radius: var(--radius-md); + box-shadow: var(--shadow-deep); z-index: 1000; display: flex; flex-direction: column; @@ -164,19 +164,19 @@ width: auto; } .toggle-log-btn { - background: var(--dark-bg, #1a1a2e); - color: white; + background: transparent; + color: var(--text); border: none; padding: 10px; text-align: center; cursor: pointer; font-weight: bold; - border-radius: 8px; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-md); + border-bottom: 1px solid var(--edge-soft); font-family: var(--font-heading); } .toggle-log-btn:hover { - background: rgba(255, 255, 255, 0.1); + background: color-mix(in srgb, var(--text) 10%, transparent); } .log-content { overflow-y: auto; @@ -193,21 +193,21 @@ } .log-top-note { font-size: 0.75rem; - color: var(--text-muted, #94a3b8); + color: var(--text-muted); font-style: italic; } .load-older-btn { - background: rgba(255, 255, 255, 0.06); - border: 1px solid rgba(255, 255, 255, 0.12); - color: var(--text-muted, #94a3b8); + background: color-mix(in srgb, var(--text) 6%, transparent); + border: 1px solid var(--edge); + color: var(--text-muted); font-size: 0.75rem; padding: 4px 12px; border-radius: 12px; cursor: pointer; } .load-older-btn:hover { - background: rgba(255, 255, 255, 0.12); - color: var(--text-primary, #f1f5f9); + background: color-mix(in srgb, var(--text) 12%, transparent); + color: var(--text); } .log-entry { display: grid; @@ -215,12 +215,12 @@ gap: 8px; align-items: baseline; padding: 6px 8px; - background: rgba(255, 255, 255, 0.03); - border-left: 3px solid rgba(255, 255, 255, 0.15); + background: color-mix(in srgb, var(--text) 3%, transparent); + border-left: 3px solid var(--edge); border-radius: 0 6px 6px 0; font-size: 0.85rem; line-height: 1.35; - color: #c3cede; + color: color-mix(in srgb, var(--text) 85%, var(--text-muted)); } .log-icon { font-size: 0.9rem; @@ -230,13 +230,13 @@ } .log-time { font-size: 0.7rem; - color: var(--text-muted, #94a3b8); + color: var(--text-muted); white-space: nowrap; opacity: 0.8; } .log-empty { padding: 10px; - color: var(--text-muted, #94a3b8); + color: var(--text-muted); font-style: italic; } .jump-to-bottom { @@ -244,37 +244,37 @@ bottom: 12px; left: 50%; transform: translateX(-50%); - background: var(--gold, #d4af37); - color: var(--text-dark, #0f172a); + background: var(--accent); + color: var(--text-inverse); border: none; border-radius: 16px; padding: 5px 14px; font-size: 0.8rem; font-weight: 700; cursor: pointer; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-soft); } .jump-to-bottom:hover { filter: brightness(1.1); } /* Accent colors by event kind */ - .log-kind-challenge { border-left-color: var(--red-suit, #ff2a5f); } - .log-kind-card { border-left-color: var(--neon-cyan, #00f2fe); } + .log-kind-challenge { border-left-color: var(--danger); } + .log-kind-card { border-left-color: var(--deep); } .log-kind-captain, .log-kind-tax, .log-kind-rank, - .log-kind-victory { border-left-color: var(--gold, #d4af37); } + .log-kind-victory { border-left-color: var(--accent); } .log-kind-scene, - .log-kind-phase { border-left-color: var(--neon-emerald, #00ff87); } + .log-kind-phase { border-left-color: var(--pirat); } .log-kind-joker, - .log-kind-warning { border-left-color: #ff9f43; } - .log-kind-obstacle { border-left-color: #4aa3df; } + .log-kind-warning { border-left-color: var(--warning); } + .log-kind-obstacle { border-left-color: var(--deep); } .log-kind-join, .log-kind-vote, - .log-kind-objective { border-left-color: #9b8cff; } + .log-kind-objective { border-left-color: var(--mystic); } .log-kind-victory { - background: rgba(212, 175, 55, 0.08); - color: var(--gold, #d4af37); + background: color-mix(in srgb, var(--accent) 9%, transparent); + color: var(--accent); } diff --git a/frontend/src/components/GameOverPhase.svelte b/frontend/src/components/GameOverPhase.svelte index 9fbc896..1b600aa 100644 --- a/frontend/src/components/GameOverPhase.svelte +++ b/frontend/src/components/GameOverPhase.svelte @@ -7,16 +7,16 @@ $: crewDone = state.game.completed_crew_1 && state.game.completed_crew_2 && state.game.completed_crew_3; -
    -
    -

    ๐ŸŽ‰ The Story Has Ended!

    +
    +
    +

    ๐ŸŽ‰ The Story Has Ended!

    The Pi-Rats of {state.game.crew_name || 'the crew'} party til they pass out in a pile. Tell one last tale of how your Pi-Rat is remembered!

    -
    -

    Crew Objectives

    +
    +

    Crew Objectives

    @@ -29,16 +29,16 @@ {/if}
    -
    -

    The Crew

    +
    +

    The Crew

    {#each pirats as p} -
    +
    {#if p.is_ghost}๐Ÿ‘ป{:else if p.is_dead}๐Ÿ’€{:else}๐Ÿ€{/if} {displayName(p)} (Rank {p.rank}) - {#if p.id === state.game.captain_player_id} โญ Captain{/if} + {#if p.id === state.game.captain_player_id} โญ Captain{/if} - + {p.completed_personal_1 ? '๐Ÿ”ซ Gat' : 'โ€” no gat'} ยท {p.completed_personal_2 ? '๐Ÿ“› Named' : 'โ€” nameless'} ยท {p.completed_personal_3 ? 'โšฐ๏ธ Story complete' : 'โ›ต Still sailing'} diff --git a/frontend/src/components/LobbyPhase.svelte b/frontend/src/components/LobbyPhase.svelte index 584523d..e1e4243 100644 --- a/frontend/src/components/LobbyPhase.svelte +++ b/frontend/src/components/LobbyPhase.svelte @@ -65,7 +65,7 @@
    {/if} diff --git a/frontend/src/components/ScenePhase.svelte b/frontend/src/components/ScenePhase.svelte index 24541b2..9f86a00 100644 --- a/frontend/src/components/ScenePhase.svelte +++ b/frontend/src/components/ScenePhase.svelte @@ -27,36 +27,34 @@
    -
    -
    - -
    - {#if captain} - - ๐Ÿดโ€โ˜ ๏ธ Captain: {displayName(captain)} (Rank {captain.rank}){isCaptain ? ' โ€” You!' : ''} +
    + +
    + {#if captain} + + ๐Ÿดโ€โ˜ ๏ธ Captain: {displayName(captain)} (Rank {captain.rank}){isCaptain ? ' โ€” You!' : ''} + + {:else} + + ๐Ÿดโ€โ˜ ๏ธ Captain: None{state.game.completed_crew_1 ? '' : ' (steal a ship first!)'} + + {/if} +
    + + +
    + Active Roster: + {#each state.players as p} + {#if p.role === 'deep'} + + ๐ŸŒŠ {displayName(p)} (Deep) - {:else} - - ๐Ÿดโ€โ˜ ๏ธ Captain: None{state.game.completed_crew_1 ? '' : ' (steal a ship first!)'} + {:else if p.role === 'pirat'} + + {#if p.is_ghost}๐Ÿ‘ป{:else if p.is_dead}๐Ÿ’€{:else}๐Ÿ€{/if} {displayName(p)} (Rank {p.rank}){p.id === state.game.captain_player_id ? ' โญ' : ''} {/if} -
    - - -
    - Active Roster: - {#each state.players as p} - {#if p.role === 'deep'} - - ๐ŸŒŠ {displayName(p)} (Deep) - - {:else if p.role === 'pirat'} - - {#if p.is_ghost}๐Ÿ‘ป{:else if p.is_dead}๐Ÿ’€{:else}๐Ÿ€{/if} {displayName(p)} (Rank {p.rank}){p.id === state.game.captain_player_id ? ' โญ' : ''} - - {/if} - {/each} -
    + {/each}
    diff --git a/frontend/src/components/SceneSetupPhase.svelte b/frontend/src/components/SceneSetupPhase.svelte index 9a3a98f..185965f 100644 --- a/frontend/src/components/SceneSetupPhase.svelte +++ b/frontend/src/components/SceneSetupPhase.svelte @@ -52,12 +52,12 @@

    Select your role for the upcoming scene. There must be at least one Pi-Rat and one Deep player. If you played the Deep in the last scene, you must play a Pi-Rat this scene!

    {#if state.game.current_scene_number === 1} -
    -

    ๐Ÿšข First Scene Framing

    +
    +

    ๐Ÿšข First Scene Framing

    The first scene must establish that the Pi-Rats are on a ship they can steal (or have an immediate opportunity to steal one). Don't start far from water! {#if state.player.role === 'deep'} -
    You're playing the Deep โ€” once the scene starts, describe where the crew is and what ship is ripe for the taking before calling any Challenges. +
    You're playing the Deep โ€” once the scene starts, describe where the crew is and what ship is ripe for the taking before calling any Challenges. {/if}

    @@ -85,16 +85,16 @@
    {#if !allowedRoles.includes('pirat')} {#if state.game.current_scene_number === 1} -

    You start at Rank 3, so you must play The Deep for the first scene!

    +

    You start at Rank 3, so you must play The Deep for the first scene!

    {:else} -

    You are the only eligible player for The Deep this scene!

    +

    You are the only eligible player for The Deep this scene!

    {/if} {/if} {#if !allowedRoles.includes('deep')} {#if state.game.current_scene_number === 1} -

    You start at Rank 1, so you must play your Pi-Rat for the first scene!

    +

    You start at Rank 1, so you must play your Pi-Rat for the first scene!

    {:else} -

    You played The Deep last scene, so you must play a Pi-Rat!

    +

    You played The Deep last scene, so you must play a Pi-Rat!

    {/if} {/if}
    @@ -106,7 +106,7 @@
    {#each state.players as p}
    - {displayName(p)} (Rank {p.rank}) + {displayName(p)} (Rank {p.rank}) {#if p.role === 'pirat'} Pi-Rat {:else if p.role === 'deep'} @@ -132,13 +132,13 @@ {starting ? 'Starting Scene...' : 'Confirm Roles & Shuffle Deck'} {:else if !allRolesAssigned} -

    Waiting for all players to choose a role...

    +

    Waiting for all players to choose a role...

    {:else if !deepPlayer} -

    Someone must play as The Deep!

    +

    Someone must play as The Deep!

    {:else if !piratPlayer} -

    Someone must play as a Pi-Rat!

    +

    Someone must play as a Pi-Rat!

    {:else} -

    Waiting for The Deep or Creator to start the scene...

    +

    Waiting for The Deep or Creator to start the scene...

    {/if}
    diff --git a/frontend/src/components/UpkeepPhase.svelte b/frontend/src/components/UpkeepPhase.svelte index 0d3acb9..0dfb433 100644 --- a/frontend/src/components/UpkeepPhase.svelte +++ b/frontend/src/components/UpkeepPhase.svelte @@ -184,67 +184,67 @@ {#if state.player.is_dead && !state.player.is_ghost} -
    -

    ๐Ÿ’€ Your Pi-Rat Has Died!

    -

    +

    +

    ๐Ÿ’€ Your Pi-Rat Has Died!

    +

    Your story arc is complete! You went out in a blaze of glory (or retired honorably). You must now choose how your journey continues:

    {#if !isRolling} -
    - -
    -

    +

    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.

    {:else} -
    -

    Create Your New Recruit

    +
    +

    Create Your New Recruit

    {#if rollingError}
    {rollingError}
    {/if} -
    - -
    - - +
    + +
    + +
    -
    - -
    - - +
    + +
    + +
    -
    - -
    - - +
    + +
    + +
    -
    - -
    - - +
    + +
    + +
    -
    - - +
    + +
    {/if} @@ -350,8 +350,8 @@
    {#if isOverLimit} -
    -

    โš ๏ธ 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).

    +
    +

    โš ๏ธ 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).

    {/if} @@ -374,7 +374,7 @@ {#each state.players as p}
  • {displayName(p)}: Rank {p.rank} - {#if p.role === 'deep'}Deep{:else if p.is_ghost}Ghost{:else}Pi-Rat{/if} + {#if p.role === 'deep'}Deep{:else if p.is_ghost}Ghost{:else}Pi-Rat{/if}
  • {/each}
@@ -414,7 +414,7 @@ {/if} {#if state.player.is_creator && state.game.phase === 'between_scenes'} -
+

All good stories end. When the crew agrees the legend is complete:

diff --git a/frontend/src/components/scene/ChallengePanel.svelte b/frontend/src/components/scene/ChallengePanel.svelte index ab8c579..c31b95c 100644 --- a/frontend/src/components/scene/ChallengePanel.svelte +++ b/frontend/src/components/scene/ChallengePanel.svelte @@ -62,9 +62,9 @@ {#each openChallenges as ch} {@const chPlays = JSON.parse(ch.plays || '[]')} {@const chObstacleIds = JSON.parse(ch.obstacle_ids || '[]')} -
-
-

+
+
+

{#if ch.challenge_type === 'pvp'} โš”๏ธ Duel: {playerName(ch.challenger_player_id)} vs {playerName(ch.target_player_id)} {:else} @@ -72,7 +72,7 @@ {/if}

{#if state.player.role === 'deep' && ch.challenge_type === 'deep'} -
+
@@ -101,10 +101,10 @@ {#if ch.tax_state === 'requested'} {#if myTaxRequest && myTaxRequest.id === ch.id} -
-

{playerName(ch.target_player_id)} calls a {ch.tax_type === 'gat' ? 'Gat' : 'Name'} Tax on you: take this Challenge for them!

+
+

{playerName(ch.target_player_id)} calls a {ch.tax_type === 'gat' ? 'Gat' : 'Name'} Tax on you: take this Challenge for them!

Accept: you get one random card from their hand and attempt the Challenge. Refuse: you hand over your {ch.tax_type === 'gat' ? 'Gat' : 'Name'} โ€” they keep it if they succeed!

-
+
@@ -116,8 +116,8 @@ {#if ch.challenge_type === 'deep' && ch.acting_player_id === state.player.id && !ch.tax_state && !state.player.tax_banned && taxType(state.player) && eligibleTaxTargets().length > 0} -
- No {taxType(state.player)}? Make it someone else's problem: +
+ No {taxType(state.player)}? Make it someone else's problem: +
+
{/if} {#if state.player.tax_banned} -
+

๐Ÿšซ You failed a refused Tax โ€” no more Gat/Name Taxes for you this scene.

{/if} @@ -104,7 +104,7 @@ {#if !state.player.is_dead && duelTargets.length > 0}
-

โš”๏ธ Duel a Pi-Rat

+

โš”๏ธ Duel a Pi-Rat

Challenge a crewmate (e.g. for the Captaincy)! Your card becomes a temporary Obstacle they must beat. Both cards are discarded afterwards.

@@ -141,7 +141,7 @@
-

Personal Objectives

+

Personal Objectives