Add light/dark theme system with CSS variables, fix ProseMirror editors

Theme System:
- Add _theme-variables.scss with light (parchment) and dark color palettes
- Register theme options in system.json for Foundry v13 color scheme support
- Convert all SCSS color variables to CSS custom properties
- Update base, mixins, components, and sheet styles for theme support
- Add _applyThemeClass() to actor and item sheet classes

ProseMirror Editor Fix (v13 ApplicationV2):
- Replace {{editor}} helper with <prose-mirror> custom element
- Add TextEditor.enrichHTML() for rich text content preparation
- Update all 8 item templates (spell, weapon, armor, equipment, etc.)
- Fix toolbar hiding content by renaming wrapper to .editor-wrapper
- Style prose-mirror with sticky toolbar and proper flex layout

Roll Dialog & Chat Card Styling:
- Complete roll dialog styling with favor/hinder toggles, info panels
- Complete chat card styling with roll results, damage display, animations
- Mark tasks 5.7 and 5.8 complete in roadmap
- Add task 5.11 for deferred resizable editor feature

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2025-12-15 15:36:16 -06:00
parent 5ddd33c41c
commit 8b9daa1f36
30 changed files with 1905 additions and 801 deletions

Binary file not shown.

View File

@ -118,6 +118,10 @@ cd ~/.claude/skills/notediscovery && python client.py search "keyword"
Original PDF at: `/mnt/NV2/Development/claude-home/gaming/Vagabond_RPG_-_Pulp_Fantasy_Core_Rulebook_Interactive_PDF.pdf` Original PDF at: `/mnt/NV2/Development/claude-home/gaming/Vagabond_RPG_-_Pulp_Fantasy_Core_Rulebook_Interactive_PDF.pdf`
Character sheet reference: `/mnt/NV2/Development/claude-home/gaming/Vagabond_-_Hero_Record_Interactive_PDF.pdf` Character sheet reference: `/mnt/NV2/Development/claude-home/gaming/Vagabond_-_Hero_Record_Interactive_PDF.pdf`
## Reference Project Documentation
The D&D 5e Foundry system is very well documented here: https://deepwiki.com/foundryvtt/dnd5e/1-dnd5e-system-overview
## Project Roadmap ## Project Roadmap
See `PROJECT_ROADMAP.json` for complete task breakdown with dependencies. See `PROJECT_ROADMAP.json` for complete task breakdown with dependencies.

View File

@ -680,28 +680,31 @@
"id": "5.6", "id": "5.6",
"name": "Style Item sheets", "name": "Style Item sheets",
"description": "Consistent look across all item types, clear form layouts", "description": "Consistent look across all item types, clear form layouts",
"completed": false, "completed": true,
"tested": false, "tested": false,
"priority": "medium", "priority": "medium",
"dependencies": ["5.1", "5.2", "5.3", "4.1"] "dependencies": ["5.1", "5.2", "5.3", "4.1"],
"notes": "Styled all 8 item types with: header (image with hover effect, styled name input, color-coded type badges), tab navigation, form inputs (transitions, focus states, disabled states), fieldsets, properties grids, type-specific sections (traits, prerequisites, progression tables, features, relic sections, spell effects). Added .hidden utility for tab switching, custom scrollbar, flexbox layout for proper scrolling. ALSO IMPLEMENTED: Light/Dark theme system with CSS custom properties - registered themes in system.json, created _theme-variables.scss with light (parchment) and dark color palettes, converted all SCSS color variables to CSS custom properties across base, mixins, components, and sheet styles."
}, },
{ {
"id": "5.7", "id": "5.7",
"name": "Style roll dialogs", "name": "Style roll dialogs",
"description": "Favor/Hinder toggles, modifier inputs, clear roll button", "description": "Favor/Hinder toggles, modifier inputs, clear roll button",
"completed": false, "completed": true,
"tested": false, "tested": false,
"priority": "medium", "priority": "medium",
"dependencies": ["5.1", "5.2"] "dependencies": ["5.1", "5.2"],
"notes": "Comprehensive styling in _roll-dialog.scss (950 lines): ApplicationV2 dialogs with themed backgrounds, skill/weapon/save/spell selections, info panels with difficulty/crit display, favor/hinder toggles with active states, damage preview, mana display for spells, focus warnings, legacy dialog support, Favor/Hinder Debug Panel."
}, },
{ {
"id": "5.8", "id": "5.8",
"name": "Style chat cards", "name": "Style chat cards",
"description": "Roll results, spell casts, attack outcomes in themed chat messages", "description": "Roll results, spell casts, attack outcomes in themed chat messages",
"completed": false, "completed": true,
"tested": false, "tested": false,
"priority": "medium", "priority": "medium",
"dependencies": ["5.1", "5.2"] "dependencies": ["5.1", "5.2"],
"notes": "Comprehensive styling in _chat-cards.scss (577 lines): Card headers with icons and badges, roll results with success/failure/critical/fumble states, roll breakdown display, damage sections with critical highlighting, weapon properties, spell cards with mana cost and focus indicator, animations for crits and fumbles."
}, },
{ {
"id": "5.9", "id": "5.9",
@ -711,6 +714,26 @@
"tested": false, "tested": false,
"priority": "high", "priority": "high",
"dependencies": ["5.4", "5.5", "5.6"] "dependencies": ["5.4", "5.5", "5.6"]
},
{
"id": "5.10",
"name": "Investigate per-sheet theming in Foundry v13",
"description": "Per-sheet theme selection via Configure Sheet dialog doesn't work - Foundry v13 shows theme options but doesn't store selection in document flags or apply theme classes to ApplicationV2 sheets. Infrastructure exists (CSS variables, _applyThemeClass JS), need to find correct Foundry API for per-sheet theme storage. Global theme switching works via Settings > Color Scheme.",
"completed": false,
"tested": false,
"priority": "low",
"dependencies": ["5.6"],
"notes": "CSS infrastructure complete in _theme-variables.scss. JS _applyThemeClass() in base-actor-sheet.mjs and base-item-sheet.mjs applies theme class based on settings. Current workaround: use global Foundry color scheme (Settings > Configure Settings > Color Scheme > Applications). Per-sheet theme dropdown in Configure Sheet appears but selection not persisted to document.flags.core.sheetTheme."
},
{
"id": "5.11",
"name": "Add resizable editor containers",
"description": "Allow users to drag-resize ProseMirror editor text boxes on item sheets for viewing/editing longer content. CSS resize:vertical not working with Foundry's prose-mirror element structure.",
"completed": false,
"tested": false,
"priority": "low",
"dependencies": ["5.6"],
"notes": "Editors functional with prose-mirror element in v13 ApplicationV2. Resize handle not appearing despite CSS - may need JavaScript-based resize or different approach. Foundry's internal .editor-container conflicts with custom wrapper naming."
} }
] ]
}, },

View File

@ -2,6 +2,9 @@
"VAGABOND.SystemName": "Vagabond RPG", "VAGABOND.SystemName": "Vagabond RPG",
"VAGABOND.SystemDescription": "A Foundry VTT system for Vagabond RPG - Pulp Fantasy Roleplaying", "VAGABOND.SystemDescription": "A Foundry VTT system for Vagabond RPG - Pulp Fantasy Roleplaying",
"VAGABOND.ThemeLight": "Light (Parchment)",
"VAGABOND.ThemeDark": "Dark",
"VAGABOND.SheetCharacter": "Character Sheet", "VAGABOND.SheetCharacter": "Character Sheet",
"VAGABOND.SheetNPC": "NPC Sheet", "VAGABOND.SheetNPC": "NPC Sheet",
"VAGABOND.SheetItem": "Item Sheet", "VAGABOND.SheetItem": "Item Sheet",

View File

@ -44,7 +44,7 @@ export default class VagabondRollDialog extends HandlebarsApplicationMixin(Appli
/** @override */ /** @override */
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
id: "vagabond-roll-dialog", id: "vagabond-roll-dialog",
classes: ["vagabond", "roll-dialog"], classes: ["vagabond", "roll-dialog", "themed"],
tag: "form", tag: "form",
window: { window: {
title: "VAGABOND.RollDialog", title: "VAGABOND.RollDialog",
@ -143,6 +143,9 @@ export default class VagabondRollDialog extends HandlebarsApplicationMixin(Appli
_onRender(context, options) { _onRender(context, options) {
super._onRender(context, options); super._onRender(context, options);
// Apply theme class based on configured theme
this._applyThemeClass();
// Favor/Hinder toggle buttons // Favor/Hinder toggle buttons
const favorBtn = this.element.querySelector('[data-action="toggle-favor"]'); const favorBtn = this.element.querySelector('[data-action="toggle-favor"]');
const hinderBtn = this.element.querySelector('[data-action="toggle-hinder"]'); const hinderBtn = this.element.querySelector('[data-action="toggle-hinder"]');
@ -166,6 +169,40 @@ export default class VagabondRollDialog extends HandlebarsApplicationMixin(Appli
}); });
} }
/**
* Apply the configured theme class to the dialog element.
* Foundry v13 doesn't automatically add theme classes to ApplicationV2,
* so we handle it manually.
* @protected
*/
_applyThemeClass() {
if (!this.element) return;
// Remove any existing theme classes
this.element.classList.remove("theme-light", "theme-dark");
// Check global preference
let theme = null;
try {
const uiConfig = game.settings.get("core", "uiConfig");
const colorScheme = uiConfig?.colorScheme?.applications;
if (colorScheme === "dark") {
theme = "dark";
} else if (colorScheme === "light") {
theme = "light";
}
} catch {
// Settings not available, use default
}
// Apply the theme class
if (theme === "dark") {
this.element.classList.add("theme-dark");
} else if (theme === "light") {
this.element.classList.add("theme-light");
}
}
/** /**
* Toggle favor on/off. * Toggle favor on/off.
* @private * @private

View File

@ -26,7 +26,7 @@ export default class FavorHinderDebug extends HandlebarsApplicationMixin(Applica
/** @override */ /** @override */
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
id: "vagabond-favor-hinder-debug", id: "vagabond-favor-hinder-debug",
classes: ["vagabond", "favor-hinder-debug"], classes: ["vagabond", "favor-hinder-debug", "themed"],
tag: "div", tag: "div",
window: { window: {
title: "Favor/Hinder Debug", title: "Favor/Hinder Debug",
@ -174,6 +174,9 @@ export default class FavorHinderDebug extends HandlebarsApplicationMixin(Applica
_onRender(context, options) { _onRender(context, options) {
super._onRender(context, options); super._onRender(context, options);
// Apply theme class based on configured theme
this._applyThemeClass();
// Actor selection dropdown // Actor selection dropdown
const actorSelect = this.element.querySelector('[name="actorId"]'); const actorSelect = this.element.querySelector('[name="actorId"]');
actorSelect?.addEventListener("change", (event) => { actorSelect?.addEventListener("change", (event) => {
@ -319,6 +322,40 @@ export default class FavorHinderDebug extends HandlebarsApplicationMixin(Applica
SkillCheckDialog.prompt(this.actor); SkillCheckDialog.prompt(this.actor);
} }
/**
* Apply the configured theme class to the dialog element.
* Foundry v13 doesn't automatically add theme classes to ApplicationV2,
* so we handle it manually.
* @protected
*/
_applyThemeClass() {
if (!this.element) return;
// Remove any existing theme classes
this.element.classList.remove("theme-light", "theme-dark");
// Check global preference
let theme = null;
try {
const uiConfig = game.settings.get("core", "uiConfig");
const colorScheme = uiConfig?.colorScheme?.applications;
if (colorScheme === "dark") {
theme = "dark";
} else if (colorScheme === "light") {
theme = "light";
}
} catch {
// Settings not available, use default
}
// Apply the theme class
if (theme === "dark") {
this.element.classList.add("theme-dark");
} else if (theme === "light") {
this.element.classList.add("theme-light");
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Static Methods */ /* Static Methods */
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -38,7 +38,7 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
/** @override */ /** @override */
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
id: "vagabond-actor-sheet-{id}", id: "vagabond-actor-sheet-{id}",
classes: ["vagabond", "sheet", "actor"], classes: ["vagabond", "sheet", "actor", "themed"],
tag: "form", tag: "form",
window: { window: {
title: "VAGABOND.ActorSheet", title: "VAGABOND.ActorSheet",
@ -271,6 +271,9 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
_onRender(context, options) { _onRender(context, options) {
super._onRender(context, options); super._onRender(context, options);
// Apply theme class based on configured theme
this._applyThemeClass();
// Remove stale tab content (ApplicationV2 appends parts without removing old ones) // Remove stale tab content (ApplicationV2 appends parts without removing old ones)
this._cleanupInactiveTabs(); this._cleanupInactiveTabs();
@ -284,6 +287,49 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
this._initializeEditors(); this._initializeEditors();
} }
/**
* Apply the configured theme class to the sheet element.
* Foundry v13 doesn't automatically add theme classes to ApplicationV2 sheets,
* so we handle it manually.
* @protected
*/
_applyThemeClass() {
if (!this.element) return;
// Remove any existing theme classes
this.element.classList.remove("theme-light", "theme-dark");
// Get the configured theme for this sheet
// DocumentSheetConfig stores per-document and per-type theme preferences
const sheetConfig = this.document.getFlag("core", "sheetTheme");
const typeConfig = game.settings.get("core", "sheetClasses")?.[this.document.documentName]?.[
this.document.type
];
const defaultTheme = typeConfig?.defaultTheme;
// Determine which theme to apply: document-specific > type default > global
let theme = sheetConfig || defaultTheme;
// If no specific theme, check global preference
if (!theme) {
const uiConfig = game.settings.get("core", "uiConfig");
const colorScheme = uiConfig?.colorScheme?.applications;
if (colorScheme === "dark") {
theme = "dark";
} else if (colorScheme === "light") {
theme = "light";
}
}
// Apply the theme class
if (theme === "dark") {
this.element.classList.add("theme-dark");
} else if (theme === "light") {
this.element.classList.add("theme-light");
}
// If still no theme, it will use body.theme-dark/light via CSS
}
/** /**
* Remove tab content sections that don't match the active tab. * Remove tab content sections that don't match the active tab.
* ApplicationV2's parts rendering appends new parts without removing old ones, * ApplicationV2's parts rendering appends new parts without removing old ones,
@ -581,7 +627,7 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
const weaponId = target.dataset.weaponId; const weaponId = target.dataset.weaponId;
const { AttackRollDialog } = game.vagabond.applications; const { AttackRollDialog } = game.vagabond.applications;
await AttackRollDialog.prompt(this.actor, { weaponId }); await AttackRollDialog.prompt(this.actor, weaponId);
} }
/** /**
@ -594,11 +640,8 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
const spellId = target.dataset.spellId; const spellId = target.dataset.spellId;
if (!spellId) return; if (!spellId) return;
const spell = this.actor.items.get(spellId);
if (!spell) return;
const { SpellCastDialog } = game.vagabond.applications; const { SpellCastDialog } = game.vagabond.applications;
await SpellCastDialog.prompt(this.actor, { spell }); await SpellCastDialog.prompt(this.actor, spellId);
} }
/** /**

View File

@ -34,7 +34,7 @@ export default class VagabondItemSheet extends HandlebarsApplicationMixin(ItemSh
/** @override */ /** @override */
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
id: "vagabond-item-sheet-{id}", id: "vagabond-item-sheet-{id}",
classes: ["vagabond", "sheet", "item"], classes: ["vagabond", "sheet", "item", "themed"],
tag: "form", tag: "form",
window: { window: {
title: "VAGABOND.ItemSheet", title: "VAGABOND.ItemSheet",
@ -163,6 +163,39 @@ export default class VagabondItemSheet extends HandlebarsApplicationMixin(ItemSh
// Active Effects on this item // Active Effects on this item
context.effects = this._prepareEffects(); context.effects = this._prepareEffects();
// Enrich HTML content for ProseMirror editors
// ApplicationV2 requires enriched HTML to be prepared in context
const enrichOptions = {
secrets: this.item.isOwner,
rollData: context.rollData,
relativeTo: this.item,
};
const TextEditorImpl = foundry.applications.ux.TextEditor.implementation;
context.enrichedDescription = await TextEditorImpl.enrichHTML(
this.item.system.description ?? "",
enrichOptions
);
// Enrich spell-specific fields
if (this.item.type === "spell") {
context.enrichedEffect = await TextEditorImpl.enrichHTML(
this.item.system.effect ?? "",
enrichOptions
);
context.enrichedCritEffect = await TextEditorImpl.enrichHTML(
this.item.system.critEffect ?? "",
enrichOptions
);
}
// Enrich class-specific fields
if (this.item.type === "class") {
context.enrichedStartingPack = await TextEditorImpl.enrichHTML(
this.item.system.startingPack ?? "",
enrichOptions
);
}
// Type-specific context // Type-specific context
await this._prepareTypeContext(context, options); await this._prepareTypeContext(context, options);
@ -205,6 +238,9 @@ export default class VagabondItemSheet extends HandlebarsApplicationMixin(ItemSh
_onRender(context, options) { _onRender(context, options) {
super._onRender(context, options); super._onRender(context, options);
// Apply theme class based on configured theme
this._applyThemeClass();
// Clean up inactive tabs if using tabs // Clean up inactive tabs if using tabs
if (this.hasTabs) { if (this.hasTabs) {
this._cleanupInactiveTabs(); this._cleanupInactiveTabs();
@ -214,6 +250,46 @@ export default class VagabondItemSheet extends HandlebarsApplicationMixin(ItemSh
this._initializeEditors(); this._initializeEditors();
} }
/**
* Apply the configured theme class to the sheet element.
* Foundry v13 doesn't automatically add theme classes to ApplicationV2 sheets,
* so we handle it manually.
* @protected
*/
_applyThemeClass() {
if (!this.element) return;
// Remove any existing theme classes
this.element.classList.remove("theme-light", "theme-dark");
// Try to get per-sheet theme (location TBD - Foundry v13 storage unclear)
// TODO: Find correct API for per-sheet theme in Foundry v13
const sheetConfig = this.document.getFlag("core", "sheetTheme");
const sheetClasses = game.settings.get("core", "sheetClasses");
const typeConfig = sheetClasses?.[this.document.documentName]?.[this.document.type];
// Determine which theme to apply: document-specific > type default > global
let theme = sheetConfig || typeConfig?.defaultTheme;
// If no specific theme, check global preference
if (!theme) {
const uiConfig = game.settings.get("core", "uiConfig");
const colorScheme = uiConfig?.colorScheme?.applications;
if (colorScheme === "dark") {
theme = "dark";
} else if (colorScheme === "light") {
theme = "light";
}
}
// Apply the theme class
if (theme === "dark") {
this.element.classList.add("theme-dark");
} else if (theme === "light") {
this.element.classList.add("theme-light");
}
}
/** /**
* Remove tab content sections that don't match the active tab. * Remove tab content sections that don't match the active tab.
* ApplicationV2's parts rendering appends new parts without removing old ones. * ApplicationV2's parts rendering appends new parts without removing old ones.

View File

@ -7,7 +7,7 @@
font-family: $font-family-body; font-family: $font-family-body;
font-size: $font-size-base; font-size: $font-size-base;
line-height: $line-height-normal; line-height: $line-height-normal;
color: $color-text-primary; color: var(--color-text-primary);
// Box sizing // Box sizing
*, *,
@ -18,12 +18,12 @@
// Links // Links
a { a {
color: $color-accent-primary; color: var(--color-accent-primary);
text-decoration: none; text-decoration: none;
transition: color $transition-fast; transition: color $transition-fast;
&:hover { &:hover {
color: $color-accent-secondary; color: var(--color-accent-secondary);
text-decoration: underline; text-decoration: underline;
} }
@ -40,7 +40,7 @@
font-family: $font-family-header; font-family: $font-family-header;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
line-height: $line-height-tight; line-height: $line-height-tight;
color: $color-text-primary; color: var(--color-text-primary);
margin: 0 0 $spacing-2 0; margin: 0 0 $spacing-2 0;
} }
@ -100,18 +100,18 @@
td { td {
padding: $spacing-2 $spacing-3; padding: $spacing-2 $spacing-3;
text-align: left; text-align: left;
border-bottom: 1px solid $color-border-light; border-bottom: 1px solid var(--color-border-light);
} }
th { th {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
} }
// Horizontal rule // Horizontal rule
hr { hr {
border: none; border: none;
border-top: 1px solid $color-border; border-top: 1px solid var(--color-border);
margin: $spacing-4 0; margin: $spacing-4 0;
} }
@ -120,7 +120,7 @@
font-family: $font-family-mono; font-family: $font-family-mono;
font-size: $font-size-sm; font-size: $font-size-sm;
padding: $spacing-1 $spacing-2; padding: $spacing-1 $spacing-2;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-radius: $radius-sm; border-radius: $radius-sm;
} }
@ -128,48 +128,41 @@
blockquote { blockquote {
margin: 0 0 $spacing-4 0; margin: 0 0 $spacing-4 0;
padding: $spacing-3 $spacing-4; padding: $spacing-3 $spacing-4;
border-left: 3px solid $color-accent-primary; border-left: 3px solid var(--color-accent-primary);
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
font-style: italic; font-style: italic;
} }
// Selection // Selection
::selection { ::selection {
background-color: $color-accent-highlight; background-color: var(--color-accent-highlight);
color: $color-text-primary; color: var(--color-text-primary);
} }
} }
// Foundry sheet wrapper styles // Foundry sheet wrapper styles
.sheet.vagabond { .sheet.vagabond {
@include custom-scrollbar; @include custom-scrollbar;
background: $color-parchment; background: var(--color-bg-primary);
background-image: linear-gradient(
to bottom,
rgba($color-parchment-light, 0.3) 0%,
transparent 5%,
transparent 95%,
rgba($color-parchment-dark, 0.3) 100%
);
} }
// Window header customization // Window header customization
.window-app.vagabond { .window-app.vagabond {
.window-header { .window-header {
background: linear-gradient(to bottom, $color-parchment-dark, $color-parchment-darker); background: linear-gradient(to bottom, var(--color-bg-secondary), var(--color-bg-tertiary));
border-bottom: 2px solid $color-border-dark; border-bottom: 2px solid var(--color-border-dark);
.window-title { .window-title {
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-lg; font-size: $font-size-lg;
color: $color-text-primary; color: var(--color-text-primary);
} }
.header-button { .header-button {
color: $color-text-secondary; color: var(--color-text-secondary);
&:hover { &:hover {
color: $color-text-primary; color: var(--color-text-primary);
} }
} }
} }

View File

@ -32,7 +32,7 @@
font-size: $size; font-size: $size;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
line-height: $line-height-tight; line-height: $line-height-tight;
color: $color-text-primary; color: var(--color-text-primary);
} }
@mixin body-text($size: $font-size-base) { @mixin body-text($size: $font-size-base) {
@ -40,7 +40,7 @@
font-size: $size; font-size: $size;
font-weight: $font-weight-normal; font-weight: $font-weight-normal;
line-height: $line-height-normal; line-height: $line-height-normal;
color: $color-text-primary; color: var(--color-text-primary);
} }
// Buttons // Buttons
@ -60,7 +60,7 @@
transition: all $transition-fast; transition: all $transition-fast;
&:focus { &:focus {
outline: 2px solid $color-accent-primary; outline: 2px solid var(--color-accent-primary);
outline-offset: 2px; outline-offset: 2px;
} }
@ -72,23 +72,23 @@
@mixin button-primary { @mixin button-primary {
@include button-base; @include button-base;
background-color: $color-accent-primary; background-color: var(--color-accent-primary);
color: $color-text-inverse; color: var(--color-text-inverse);
border-color: $color-accent-secondary; border-color: var(--color-accent-secondary);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: $color-accent-secondary; background-color: var(--color-accent-secondary);
} }
} }
@mixin button-secondary { @mixin button-secondary {
@include button-base; @include button-base;
background-color: transparent; background-color: transparent;
color: $color-text-primary; color: var(--color-text-primary);
border-color: $color-border; border-color: var(--color-border);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
} }
} }
@ -100,7 +100,7 @@
height: 28px; height: 28px;
padding: 0; padding: 0;
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-secondary; color: var(--color-text-secondary);
background-color: transparent; background-color: transparent;
border: 1px solid transparent; border: 1px solid transparent;
border-radius: $radius-sm; border-radius: $radius-sm;
@ -108,13 +108,13 @@
transition: all $transition-fast; transition: all $transition-fast;
&:hover:not(:disabled) { &:hover:not(:disabled) {
color: $color-text-primary; color: var(--color-text-primary);
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-color: $color-border; border-color: var(--color-border);
} }
&:focus { &:focus {
outline: 2px solid $color-accent-primary; outline: 2px solid var(--color-accent-primary);
outline-offset: 2px; outline-offset: 2px;
} }
@ -129,41 +129,41 @@
padding: $spacing-2 $spacing-3; padding: $spacing-2 $spacing-3;
font-family: $font-family-body; font-family: $font-family-body;
font-size: $font-size-base; font-size: $font-size-base;
color: $color-text-primary; color: var(--color-text-primary);
background-color: $color-parchment-light; background-color: var(--color-bg-input);
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-md; border-radius: $radius-md;
transition: border-color $transition-fast; transition: border-color $transition-fast;
&:focus { &:focus {
outline: none; outline: none;
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
box-shadow: 0 0 0 2px rgba($color-accent-primary, 0.2); box-shadow: 0 0 0 2px rgba(139, 69, 19, 0.2); // Using fixed color for box-shadow
} }
&::placeholder { &::placeholder {
color: $color-text-muted; color: var(--color-text-muted);
} }
&:disabled { &:disabled {
background-color: $color-parchment-darker; background-color: var(--color-bg-tertiary);
cursor: not-allowed; cursor: not-allowed;
} }
} }
// Cards/Panels // Cards/Panels
@mixin panel { @mixin panel {
background-color: $color-parchment; background-color: var(--color-bg-primary);
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-md; border-radius: $radius-md;
box-shadow: 0 1px 3px $shadow-light; box-shadow: 0 1px 3px var(--shadow-light);
} }
@mixin panel-header { @mixin panel-header {
@include flex-between; @include flex-between;
padding: $spacing-3 $spacing-4; padding: $spacing-3 $spacing-4;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-bottom: 1px solid $color-border; border-bottom: 1px solid var(--color-border);
border-radius: $radius-md $radius-md 0 0; border-radius: $radius-md $radius-md 0 0;
} }
@ -175,16 +175,16 @@
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background: $color-parchment-dark; background: var(--color-bg-secondary);
border-radius: $radius-full; border-radius: $radius-full;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background: $color-border; background: var(--color-border);
border-radius: $radius-full; border-radius: $radius-full;
&:hover { &:hover {
background: $color-border-dark; background: var(--color-border-dark);
} }
} }
} }
@ -192,7 +192,7 @@
// Accessibility - focus visible // Accessibility - focus visible
@mixin focus-visible { @mixin focus-visible {
&:focus-visible { &:focus-visible {
outline: 2px solid $color-accent-primary; outline: 2px solid var(--color-accent-primary);
outline-offset: 2px; outline-offset: 2px;
} }
} }
@ -218,7 +218,7 @@
} }
// Stat badge (for the large stat numbers) // Stat badge (for the large stat numbers)
@mixin stat-badge($color: $color-text-primary) { @mixin stat-badge($color: var(--color-text-primary)) {
@include flex-center; @include flex-center;
width: 3rem; width: 3rem;
height: 3rem; height: 3rem;
@ -226,7 +226,7 @@
font-size: $font-size-3xl; font-size: $font-size-3xl;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: $color; color: $color;
background-color: $color-parchment-light; background-color: var(--color-bg-input);
border: 2px solid $color-border; border: 2px solid var(--color-border);
border-radius: $radius-md; border-radius: $radius-md;
} }

View File

@ -0,0 +1,146 @@
// Vagabond RPG - Theme Variables (CSS Custom Properties)
// ======================================================
// These CSS custom properties enable theme switching.
// The SCSS variables are kept for compile-time calculations (like mix()).
// Runtime theming uses the CSS custom properties.
// ==========================================
// LIGHT THEME (Default - Parchment)
// ==========================================
// This is the default theme, warm parchment colors
// WCAG AA compliant (4.5:1 contrast ratio minimum)
.vagabond {
// Background colors
--color-bg-primary: #{$color-parchment};
--color-bg-secondary: #{$color-parchment-dark};
--color-bg-tertiary: #{$color-parchment-darker};
--color-bg-input: #{$color-parchment-light};
--color-bg-highlight: #{$color-parchment-light};
// Text colors
--color-text-primary: #{$color-text-primary};
--color-text-secondary: #{$color-text-secondary};
--color-text-muted: #{$color-text-muted};
--color-text-inverse: #{$color-text-inverse};
// Accent colors
--color-accent-primary: #{$color-accent-primary};
--color-accent-secondary: #{$color-accent-secondary};
--color-accent-highlight: #{$color-accent-highlight};
// Semantic colors
--color-success: #{$color-success};
--color-danger: #{$color-danger};
--color-warning: #{$color-warning};
--color-info: #{$color-info};
// Stat colors (for visual distinction)
--color-might: #{$color-might};
--color-dexterity: #{$color-dexterity};
--color-awareness: #{$color-awareness};
--color-reason: #{$color-reason};
--color-presence: #{$color-presence};
--color-luck: #{$color-luck};
// Border colors
--color-border: #{$color-border};
--color-border-light: #{$color-border-light};
--color-border-dark: #{$color-border-dark};
// Shadows
--shadow-light: #{$shadow-light};
--shadow-medium: #{$shadow-medium};
--shadow-dark: #{$shadow-dark};
// Resource bar colors (HP, Mana)
--color-hp-fill: #{$color-danger};
--color-hp-bg: #{$color-parchment-darker};
--color-mana-fill: #{$color-reason};
--color-mana-bg: #{$color-parchment-darker};
--color-bar-values-bg: rgba(245, 240, 225, 0.85);
--color-bar-input-bg: rgba(255, 255, 255, 0.9);
// Type badge backgrounds (mixed with background)
--color-badge-weapon: #{mix($color-danger, $color-parchment, 15%)};
--color-badge-armor: #{mix($color-info, $color-parchment, 15%)};
--color-badge-spell: #{mix($color-reason, $color-parchment, 15%)};
--color-badge-perk: #{mix($color-success, $color-parchment, 15%)};
--color-badge-class: #{mix($color-warning, $color-parchment, 15%)};
--color-badge-feature: #{mix($color-presence, $color-parchment, 15%)};
--color-badge-ancestry: #{mix($color-luck, $color-parchment, 15%)};
--color-badge-equipment: #{mix($color-dexterity, $color-parchment, 15%)};
}
// ==========================================
// DARK THEME
// ==========================================
// Dark backgrounds with warm parchment-tinted text
// Maintains the fantasy aesthetic while being easier on eyes
//
// Two application methods:
// 1. Global: body.theme-dark .vagabond - when Foundry's global theme is dark
// 2. Per-sheet: .vagabond.theme-dark - when sheet has theme-dark class (applied by _applyThemeClass)
body.theme-dark .vagabond:not(.theme-light),
.vagabond.theme-dark {
// Dark background colors (warm-tinted darks)
--color-bg-primary: #1e1a16;
--color-bg-secondary: #2a2520;
--color-bg-tertiary: #36302a;
--color-bg-input: #252119;
--color-bg-highlight: #3d362e;
// Light text colors (parchment-tinted)
--color-text-primary: #e8dcc8;
--color-text-secondary: #c4b8a4;
--color-text-muted: #8a7e6e;
--color-text-inverse: #1e1a16;
// Accent colors (slightly brighter for dark bg)
--color-accent-primary: #c9682a;
--color-accent-secondary: #a85a24;
--color-accent-highlight: #e8a060;
// Semantic colors (adjusted for dark backgrounds)
--color-success: #4a9f42;
--color-danger: #c94444;
--color-warning: #d4a32c;
--color-info: #4a8080;
// Stat colors (brighter for dark bg)
--color-might: #e05050;
--color-dexterity: #50c050;
--color-awareness: #6090e0;
--color-reason: #b060e0;
--color-presence: #e0b030;
--color-luck: #40d0d0;
// Border colors (warm grays)
--color-border: #5c4a3a;
--color-border-light: #6d5a4a;
--color-border-dark: #4a3a2a;
// Shadows (more pronounced on dark)
--shadow-light: rgba(0, 0, 0, 0.2);
--shadow-medium: rgba(0, 0, 0, 0.35);
--shadow-dark: rgba(0, 0, 0, 0.5);
// Resource bar colors
--color-hp-fill: #c94444;
--color-hp-bg: #2a2520;
--color-mana-fill: #7050b0;
--color-mana-bg: #2a2520;
--color-bar-values-bg: rgba(30, 26, 22, 0.9);
--color-bar-input-bg: rgba(42, 37, 32, 0.95);
// Type badge backgrounds (for dark theme)
--color-badge-weapon: #3d2828;
--color-badge-armor: #283838;
--color-badge-spell: #382840;
--color-badge-perk: #283828;
--color-badge-class: #383828;
--color-badge-feature: #383028;
--color-badge-ancestry: #283838;
--color-badge-equipment: #283828;
}

View File

@ -1,36 +1,45 @@
// Vagabond RPG - Chat Card Styles // Vagabond RPG - Chat Card Styles
// ================================ // ================================
// Uses CSS custom properties for theme support.
// Base chat card // Base chat card
.vagabond.chat-card { .vagabond.chat-card {
@include panel; @include panel;
overflow: hidden; overflow: hidden;
background-color: var(--color-bg-primary);
// Card header // Card header
.card-header { .card-header {
@include flex-between; @include flex-between;
padding: $spacing-2 $spacing-3; padding: $spacing-2 $spacing-3;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-bottom: 1px solid $color-border; border-bottom: 1px solid var(--color-border);
.card-title, .card-title,
h3 { h3 {
@include flex-center;
gap: $spacing-2;
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-base; font-size: $font-size-base;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
margin: 0; margin: 0;
color: var(--color-text-primary);
i {
color: var(--color-accent-primary);
}
} }
.card-subtitle { .card-subtitle {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
} }
.trained-badge { .trained-badge {
font-size: $font-size-xs; font-size: $font-size-xs;
padding: $spacing-1 $spacing-2; padding: $spacing-1 $spacing-2;
background-color: rgba($color-success, 0.2); background-color: rgba(74, 159, 66, 0.2);
color: $color-success; color: var(--color-success);
border-radius: $radius-full; border-radius: $radius-full;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
} }
@ -46,17 +55,18 @@
@include flex-column; @include flex-column;
align-items: center; align-items: center;
gap: $spacing-2; gap: $spacing-2;
padding: $spacing-3; padding: $spacing-4;
margin: $spacing-2 0; margin: $spacing-3;
background-color: $color-parchment-light; background-color: var(--color-bg-secondary);
border-radius: $radius-md; border-radius: $radius-md;
border: 2px solid $color-border; border: 2px solid var(--color-border);
.roll-total { .roll-total {
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-4xl; font-size: $font-size-4xl;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
line-height: 1; line-height: 1;
color: var(--color-text-primary);
} }
.roll-status { .roll-status {
@ -71,45 +81,45 @@
} }
.success { .success {
background-color: rgba($color-success, 0.2); background-color: rgba(74, 159, 66, 0.2);
color: $color-success; color: var(--color-success);
} }
.failure { .failure {
background-color: rgba($color-danger, 0.2); background-color: rgba(201, 68, 68, 0.2);
color: $color-danger; color: var(--color-danger);
} }
.critical { .critical {
background-color: rgba($color-warning, 0.3); background-color: rgba(212, 163, 44, 0.3);
color: $color-warning; color: var(--color-warning);
animation: pulse 1s ease-in-out; animation: pulse 1s ease-in-out;
} }
.fumble { .fumble {
background-color: rgba($color-danger, 0.3); background-color: rgba(201, 68, 68, 0.3);
color: $color-danger; color: var(--color-danger);
animation: shake 0.5s ease-in-out; animation: shake 0.5s ease-in-out;
} }
} }
// Conditional styling based on result // Conditional styling based on result
&.success { &.success {
border-color: $color-success; border-color: var(--color-success);
} }
&.failure { &.failure {
border-color: $color-danger; border-color: var(--color-danger);
} }
&.critical { &.critical {
border-color: $color-warning; border-color: var(--color-warning);
background-color: rgba($color-warning, 0.1); background-color: rgba(212, 163, 44, 0.1);
} }
&.fumble { &.fumble {
border-color: $color-danger; border-color: var(--color-danger);
background-color: rgba($color-danger, 0.1); background-color: rgba(201, 68, 68, 0.1);
} }
} }
@ -117,8 +127,9 @@
.roll-details { .roll-details {
@include flex-column; @include flex-column;
gap: $spacing-2; gap: $spacing-2;
padding: $spacing-2; padding: $spacing-3;
background-color: $color-parchment-dark; margin: 0 $spacing-3 $spacing-3;
background-color: var(--color-bg-secondary);
border-radius: $radius-md; border-radius: $radius-md;
font-size: $font-size-sm; font-size: $font-size-sm;
@ -126,11 +137,12 @@
@include flex-between; @include flex-between;
.label { .label {
color: $color-text-muted; color: var(--color-text-muted);
} }
.value { .value {
font-family: $font-family-mono; font-family: $font-family-mono;
color: var(--color-text-primary);
} }
} }
@ -138,7 +150,7 @@
@include flex-center; @include flex-center;
gap: $spacing-3; gap: $spacing-3;
padding-top: $spacing-2; padding-top: $spacing-2;
border-top: 1px solid $color-border; border-top: 1px solid var(--color-border);
span { span {
@include flex-center; @include flex-center;
@ -148,32 +160,38 @@
.d20-result { .d20-result {
font-family: $font-family-mono; font-family: $font-family-mono;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: var(--color-text-primary);
} }
.favor-die { .favor-die {
font-family: $font-family-mono; font-family: $font-family-mono;
&.favor { &.favor {
color: $color-success; color: var(--color-success);
} }
&.hinder { &.hinder {
color: $color-danger; color: var(--color-danger);
} }
} }
.modifier { .modifier {
font-family: $font-family-mono; font-family: $font-family-mono;
color: $color-text-secondary; color: var(--color-text-secondary);
} }
} }
} }
// Target info (difficulty, crit threshold) // Info sections (save-info, skill-info, target-info)
.save-info,
.skill-info,
.target-info { .target-info {
@include grid(2, $spacing-2); @include flex-column;
margin-top: $spacing-2; gap: $spacing-1;
padding: $spacing-2; margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2 $spacing-3;
background-color: var(--color-bg-tertiary);
border-radius: $radius-md;
font-size: $font-size-sm; font-size: $font-size-sm;
> div { > div {
@ -181,11 +199,53 @@
} }
.label { .label {
color: $color-text-muted; color: var(--color-text-muted);
} }
.value { .value {
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: var(--color-text-primary);
}
.stat-abbr {
font-weight: $font-weight-bold;
color: var(--color-accent-primary);
}
}
// Defense info display
.defense-info-display {
@include flex-center;
gap: $spacing-2;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2 $spacing-3;
background-color: rgba(64, 144, 224, 0.1);
border: 1px solid var(--color-info);
border-radius: $radius-md;
font-size: $font-size-sm;
color: var(--color-info);
i {
font-size: $font-size-base;
}
}
// Defense badge
.defense-badge {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
border-radius: $radius-full;
font-weight: $font-weight-medium;
text-transform: uppercase;
&.block {
background-color: rgba(64, 144, 224, 0.2);
color: var(--color-info);
}
&.dodge {
background-color: rgba(74, 159, 66, 0.2);
color: var(--color-success);
} }
} }
@ -194,20 +254,20 @@
.hinder-sources { .hinder-sources {
@include flex-center; @include flex-center;
gap: $spacing-2; gap: $spacing-2;
margin-top: $spacing-2; margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2; padding: $spacing-2;
font-size: $font-size-sm; font-size: $font-size-sm;
border-radius: $radius-md; border-radius: $radius-md;
} }
.favor-sources { .favor-sources {
background-color: rgba($color-success, 0.1); background-color: rgba(74, 159, 66, 0.1);
color: $color-success; color: var(--color-success);
} }
.hinder-sources { .hinder-sources {
background-color: rgba($color-danger, 0.1); background-color: rgba(201, 68, 68, 0.1);
color: $color-danger; color: var(--color-danger);
} }
// Result status (legacy) // Result status (legacy)
@ -220,18 +280,18 @@
border-radius: $radius-md; border-radius: $radius-md;
&.success { &.success {
background-color: rgba($color-success, 0.2); background-color: rgba(74, 159, 66, 0.2);
color: $color-success; color: var(--color-success);
} }
&.failure { &.failure {
background-color: rgba($color-danger, 0.2); background-color: rgba(201, 68, 68, 0.2);
color: $color-danger; color: var(--color-danger);
} }
&.critical { &.critical {
background-color: rgba($color-warning, 0.2); background-color: rgba(212, 163, 44, 0.2);
color: $color-warning; color: var(--color-warning);
animation: pulse 1s ease-in-out; animation: pulse 1s ease-in-out;
} }
} }
@ -240,27 +300,27 @@
.damage-display { .damage-display {
@include flex-center; @include flex-center;
gap: $spacing-2; gap: $spacing-2;
margin-top: $spacing-3; margin: $spacing-3;
padding: $spacing-2; padding: $spacing-2;
background-color: rgba($color-danger, 0.1); background-color: rgba(201, 68, 68, 0.1);
border: 1px solid $color-danger; border: 1px solid var(--color-danger);
border-radius: $radius-md; border-radius: $radius-md;
.damage-label { .damage-label {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-secondary; color: var(--color-text-secondary);
} }
.damage-value { .damage-value {
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-xl; font-size: $font-size-xl;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: $color-danger; color: var(--color-danger);
} }
.damage-type { .damage-type {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
} }
} }
@ -269,7 +329,7 @@
display: flex; display: flex;
gap: $spacing-2; gap: $spacing-2;
padding: $spacing-3; padding: $spacing-3;
border-top: 1px solid $color-border; border-top: 1px solid var(--color-border);
button { button {
flex: 1; flex: 1;
@ -284,6 +344,13 @@
} }
} }
// Save roll card specific
.vagabond.chat-card.save-roll {
.save-name {
margin: 0;
}
}
// Attack roll card specific // Attack roll card specific
.vagabond.chat-card.attack-roll { .vagabond.chat-card.attack-roll {
.card-header { .card-header {
@ -295,7 +362,7 @@
width: 32px; width: 32px;
height: 32px; height: 32px;
border-radius: $radius-sm; border-radius: $radius-sm;
border: 1px solid $color-border; border: 1px solid var(--color-border);
} }
.header-text { .header-text {
@ -304,13 +371,14 @@
.weapon-name { .weapon-name {
margin: 0; margin: 0;
font-size: $font-size-base; font-size: $font-size-base;
color: var(--color-text-primary);
} }
.attack-type-badge { .attack-type-badge {
font-size: $font-size-xs; font-size: $font-size-xs;
padding: $spacing-1 $spacing-2; padding: $spacing-1 $spacing-2;
background-color: rgba($color-accent-primary, 0.2); background-color: rgba(139, 69, 19, 0.2);
color: $color-accent-primary; color: var(--color-accent-primary);
border-radius: $radius-full; border-radius: $radius-full;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
} }
@ -318,18 +386,18 @@
} }
.damage-section { .damage-section {
margin-top: $spacing-3; margin: $spacing-3;
padding: $spacing-3; padding: $spacing-3;
background-color: rgba($color-danger, 0.1); background-color: rgba(201, 68, 68, 0.1);
border: 1px solid rgba($color-danger, 0.3); border: 1px solid rgba(201, 68, 68, 0.3);
border-radius: $radius-md; border-radius: $radius-md;
&.critical { &.critical {
background-color: rgba($color-warning, 0.15); background-color: rgba(212, 163, 44, 0.15);
border-color: $color-warning; border-color: var(--color-warning);
.damage-total { .damage-total {
color: $color-warning; color: var(--color-warning);
} }
} }
@ -338,13 +406,14 @@
gap: $spacing-2; gap: $spacing-2;
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
margin-bottom: $spacing-2; margin-bottom: $spacing-2;
color: var(--color-text-primary);
i { i {
color: $color-danger; color: var(--color-danger);
} }
.crit-label { .crit-label {
color: $color-warning; color: var(--color-warning);
font-size: $font-size-sm; font-size: $font-size-sm;
} }
} }
@ -357,13 +426,13 @@
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-3xl; font-size: $font-size-3xl;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: $color-danger; color: var(--color-danger);
line-height: 1; line-height: 1;
} }
.damage-type { .damage-type {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-secondary; color: var(--color-text-secondary);
text-transform: capitalize; text-transform: capitalize;
} }
} }
@ -374,10 +443,10 @@
margin-top: $spacing-2; margin-top: $spacing-2;
font-family: $font-family-mono; font-family: $font-family-mono;
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
.grip-indicator { .grip-indicator {
color: $color-text-secondary; color: var(--color-text-secondary);
} }
} }
} }
@ -386,32 +455,54 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: $spacing-1; gap: $spacing-1;
margin-top: $spacing-2; margin: $spacing-2 $spacing-3;
padding: $spacing-2; padding: $spacing-2;
.property-tag { .property-tag {
font-size: $font-size-xs; font-size: $font-size-xs;
padding: $spacing-1 $spacing-2; padding: $spacing-1 $spacing-2;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-radius: $radius-full; border-radius: $radius-full;
color: $color-text-secondary; color: var(--color-text-secondary);
text-transform: capitalize; text-transform: capitalize;
} }
} }
} }
// Spell card specific // Spell card specific
.vagabond.chat-card.spell-card { .vagabond.chat-card.spell-card,
.vagabond.chat-card.spell-cast {
.card-header {
.spell-name {
margin: 0;
}
.mana-cost-badge {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: rgba(112, 80, 176, 0.2);
color: var(--color-reason);
border-radius: $radius-full;
font-weight: $font-weight-medium;
i {
margin-right: $spacing-1;
}
}
}
.spell-effect { .spell-effect {
padding: $spacing-3; padding: $spacing-3;
font-style: italic; font-style: italic;
border-left: 3px solid $color-accent-primary; border-left: 3px solid var(--color-accent-primary);
background-color: $color-parchment-light; background-color: var(--color-bg-secondary);
margin: $spacing-3 0; margin: $spacing-3;
color: var(--color-text-secondary);
} }
.spell-meta { .spell-meta {
@include grid(2, $spacing-2); @include grid(2, $spacing-2);
margin: 0 $spacing-3 $spacing-3;
font-size: $font-size-sm; font-size: $font-size-sm;
.meta-item { .meta-item {
@ -419,10 +510,45 @@
padding: $spacing-1; padding: $spacing-1;
.meta-label { .meta-label {
color: $color-text-muted; color: var(--color-text-muted);
}
.meta-value {
font-weight: $font-weight-medium;
color: var(--color-text-primary);
} }
} }
} }
// Mana spent display
.mana-spent {
@include flex-center;
gap: $spacing-2;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2;
background-color: rgba(112, 80, 176, 0.1);
border: 1px solid rgba(112, 80, 176, 0.3);
border-radius: $radius-md;
font-size: $font-size-sm;
color: var(--color-reason);
i {
font-size: $font-size-base;
}
}
// Focus indicator
.focus-indicator {
@include flex-center;
gap: $spacing-2;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2;
background-color: rgba(212, 163, 44, 0.1);
border: 1px solid var(--color-warning);
border-radius: $radius-md;
font-size: $font-size-sm;
color: var(--color-warning);
}
} }
// Animations // Animations

View File

@ -33,11 +33,11 @@
padding: 0; padding: 0;
background-color: transparent; background-color: transparent;
border-color: transparent; border-color: transparent;
color: $color-text-primary; color: var(--color-text-primary);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
color: $color-accent-primary; color: var(--color-accent-primary);
} }
i { i {
@ -52,14 +52,14 @@
width: 24px; width: 24px;
height: 24px; height: 24px;
padding: 0; padding: 0;
background-color: $color-parchment; background-color: var(--color-bg-primary);
border: 1px solid $color-border; border: 1px solid var(--color-border);
color: $color-text-primary; color: var(--color-text-primary);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
color: $color-accent-primary; color: var(--color-accent-primary);
} }
i { i {
@ -71,13 +71,13 @@
// Rollable button (for dice rolls) // Rollable button (for dice rolls)
.btn-roll { .btn-roll {
@include button-base; @include button-base;
background-color: $color-parchment-light; background-color: var(--color-bg-input);
color: $color-text-primary; color: var(--color-text-primary);
border-color: $color-border; border-color: var(--color-border);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: $color-accent-highlight; background-color: var(--color-accent-highlight);
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
} }
i { i {
@ -88,24 +88,24 @@
// Danger button // Danger button
.btn-danger { .btn-danger {
@include button-base; @include button-base;
background-color: $color-danger; background-color: var(--color-danger);
color: $color-text-inverse; color: var(--color-text-inverse);
border-color: darken($color-danger, 10%); border-color: var(--color-danger);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: darken($color-danger, 10%); filter: brightness(0.85);
} }
} }
// Success button // Success button
.btn-success { .btn-success {
@include button-base; @include button-base;
background-color: $color-success; background-color: var(--color-success);
color: $color-text-inverse; color: var(--color-text-inverse);
border-color: darken($color-success, 10%); border-color: var(--color-success);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: darken($color-success, 10%); filter: brightness(0.85);
} }
} }

View File

@ -41,8 +41,8 @@
padding: $spacing-2 $spacing-8 $spacing-2 $spacing-3; padding: $spacing-2 $spacing-8 $spacing-2 $spacing-3;
cursor: pointer; cursor: pointer;
appearance: none; appearance: none;
background-color: $color-parchment-light !important; background-color: var(--color-bg-input) !important;
color: $color-text-primary !important; color: var(--color-text-primary) !important;
font-size: $font-size-base; font-size: $font-size-base;
line-height: 1.5; line-height: 1.5;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%232c2416' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%232c2416' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
@ -50,13 +50,18 @@
background-position: right $spacing-3 center; background-position: right $spacing-3 center;
} }
// Dark theme select arrow override (per-sheet, following D&D5e pattern)
&.themed.theme-dark select {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23e8dcc8' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}
// Checkbox // Checkbox
input[type="checkbox"] { input[type="checkbox"] {
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
margin: 0; margin: 0;
cursor: pointer; cursor: pointer;
accent-color: $color-accent-primary; accent-color: var(--color-accent-primary);
@include focus-visible; @include focus-visible;
} }
@ -78,7 +83,7 @@
height: 1rem; height: 1rem;
margin: 0; margin: 0;
cursor: pointer; cursor: pointer;
accent-color: $color-accent-primary; accent-color: var(--color-accent-primary);
@include focus-visible; @include focus-visible;
} }
@ -91,7 +96,7 @@
display: block; display: block;
margin-bottom: $spacing-1; margin-bottom: $spacing-1;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: $color-text-secondary; color: var(--color-text-secondary);
} }
&.inline { &.inline {
@ -134,6 +139,7 @@
text-align: center; text-align: center;
background: transparent; background: transparent;
border: none; border: none;
color: inherit;
&:focus { &:focus {
outline: none; outline: none;
@ -153,7 +159,7 @@
} }
.separator { .separator {
color: $color-text-muted; color: var(--color-text-muted);
} }
} }
@ -166,12 +172,12 @@
transition: all $transition-fast; transition: all $transition-fast;
&:hover { &:hover {
border-color: $color-border-light; border-color: var(--color-border-light);
} }
&:focus { &:focus {
background: $color-parchment-light; background: var(--color-bg-input);
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
outline: none; outline: none;
} }
} }
@ -179,9 +185,14 @@
// Readonly display (looks like text, not input) // Readonly display (looks like text, not input)
.readonly-value { .readonly-value {
padding: $spacing-2 $spacing-3; padding: $spacing-2 $spacing-3;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border: 1px solid $color-border-light; border: 1px solid var(--color-border-light);
border-radius: $radius-md; border-radius: $radius-md;
color: $color-text-secondary; color: var(--color-text-secondary);
} }
} }
// Global dark theme select arrow override (when body has theme-dark)
body.theme-dark .vagabond select {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23e8dcc8' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}

View File

@ -9,8 +9,8 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
border-bottom: 2px solid $color-border; border-bottom: 2px solid var(--color-border);
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
.item { .item {
margin: 0; margin: 0;
@ -18,7 +18,7 @@
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-base; font-size: $font-size-base;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: $color-text-secondary; color: var(--color-text-secondary);
background-color: transparent; background-color: transparent;
border: none; border: none;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
@ -27,14 +27,14 @@
transition: all $transition-fast; transition: all $transition-fast;
&:hover { &:hover {
color: $color-text-primary; color: var(--color-text-primary);
background-color: $color-parchment; background-color: var(--color-bg-primary);
} }
&.active { &.active {
color: $color-text-primary; color: var(--color-text-primary);
background-color: $color-parchment; background-color: var(--color-bg-primary);
border-bottom-color: $color-accent-primary; border-bottom-color: var(--color-accent-primary);
} }
@include focus-visible; @include focus-visible;
@ -64,7 +64,7 @@
.sheet-tabs.vertical { .sheet-tabs.vertical {
flex-direction: column; flex-direction: column;
border-bottom: none; border-bottom: none;
border-right: 2px solid $color-border; border-right: 2px solid var(--color-border);
.item { .item {
border-bottom: none; border-bottom: none;
@ -73,7 +73,7 @@
margin-right: -2px; margin-right: -2px;
&.active { &.active {
border-right-color: $color-accent-primary; border-right-color: var(--color-accent-primary);
} }
} }
} }
@ -84,12 +84,12 @@
gap: $spacing-2; gap: $spacing-2;
margin-bottom: $spacing-4; margin-bottom: $spacing-4;
padding-bottom: $spacing-2; padding-bottom: $spacing-2;
border-bottom: 1px solid $color-border-light; border-bottom: 1px solid var(--color-border-light);
.sub-tab { .sub-tab {
padding: $spacing-1 $spacing-3; padding: $spacing-1 $spacing-3;
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
background-color: transparent; background-color: transparent;
border: 1px solid transparent; border: 1px solid transparent;
border-radius: $radius-md; border-radius: $radius-md;
@ -97,14 +97,14 @@
transition: all $transition-fast; transition: all $transition-fast;
&:hover { &:hover {
color: $color-text-primary; color: var(--color-text-primary);
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
} }
&.active { &.active {
color: $color-text-primary; color: var(--color-text-primary);
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-color: $color-border; border-color: var(--color-border);
} }
} }
} }

View File

@ -1,18 +1,21 @@
// Vagabond RPG - Roll Dialog Styles // Vagabond RPG - Roll Dialog Styles
// ================================== // ==================================
// All roll dialogs use CSS custom properties for theme support.
// ApplicationV2 Roll Dialog Base // ApplicationV2 Roll Dialog Base
.vagabond.roll-dialog { .vagabond.roll-dialog {
// Force light background on the entire window // Use themed class for proper theme support
background-color: $color-parchment; &.themed {
color: $color-text-primary; background-color: var(--color-bg-primary);
color: var(--color-text-primary);
}
.roll-dialog-content { .roll-dialog-content {
@include flex-column; @include flex-column;
gap: $spacing-3; gap: $spacing-3;
padding: $spacing-4; padding: $spacing-4;
background-color: $color-parchment; background-color: var(--color-bg-primary);
color: $color-text-primary; color: var(--color-text-primary);
} }
// Automatic favor/hinder from Active Effects // Automatic favor/hinder from Active Effects
@ -28,30 +31,60 @@
} }
&.favor { &.favor {
background-color: rgba($color-success, 0.15); background-color: rgba(74, 159, 66, 0.15);
color: $color-success; color: var(--color-success);
border: 1px solid $color-success; border: 1px solid var(--color-success);
} }
&.hinder { &.hinder {
background-color: rgba($color-danger, 0.15); background-color: rgba(201, 68, 68, 0.15);
color: $color-danger; color: var(--color-danger);
border: 1px solid $color-danger; border: 1px solid var(--color-danger);
} }
} }
// Skill selection // Common selection dropdowns
.skill-selection { .skill-selection,
.weapon-selection,
.save-selection,
.spell-selection {
@include flex-column; @include flex-column;
gap: $spacing-2; gap: $spacing-2;
label { label {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
color: var(--color-text-primary);
}
select {
@include input-base;
width: 100%;
cursor: pointer;
}
.no-weapons-message,
.no-spells-warning {
@include flex-center;
gap: $spacing-2;
padding: $spacing-3;
text-align: center;
color: var(--color-text-muted);
font-style: italic;
background-color: var(--color-bg-secondary);
border-radius: $radius-md;
i {
color: var(--color-warning);
}
} }
} }
// Skill info panel // Info panels (skill-info, attack-info, save-info, spell-info)
.skill-info { .skill-info,
.attack-info,
.save-info,
.spell-info,
.casting-skill {
@include panel; @include panel;
@include grid(2, $spacing-2); @include grid(2, $spacing-2);
padding: $spacing-3; padding: $spacing-3;
@ -62,28 +95,113 @@
.label { .label {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
} }
.value { .value {
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: var(--color-text-primary);
&.trained { &.trained {
color: $color-success; color: var(--color-success);
} }
&.untrained { &.untrained {
color: $color-text-muted; color: var(--color-text-muted);
} }
&.difficulty { &.difficulty {
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-lg; font-size: $font-size-lg;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: var(--color-accent-primary);
} }
&.crit { &.crit {
color: $color-warning; color: var(--color-warning);
}
}
.stat-name {
font-weight: $font-weight-medium;
}
}
// Single-column info (for spell dialog)
.spell-info {
@include flex-column;
gap: $spacing-2;
> div {
@include flex-between;
}
}
// Damage preview panel
.damage-preview {
@include panel;
padding: $spacing-3;
background-color: rgba(201, 68, 68, 0.08);
border-color: rgba(201, 68, 68, 0.3);
.damage-formula {
@include flex-center;
gap: $spacing-2;
.label {
font-size: $font-size-sm;
color: var(--color-text-muted);
}
.value {
font-family: $font-family-mono;
font-weight: $font-weight-bold;
font-size: $font-size-lg;
color: var(--color-danger);
}
.damage-type {
font-size: $font-size-sm;
color: var(--color-text-secondary);
}
}
.weapon-properties {
display: flex;
flex-wrap: wrap;
gap: $spacing-1;
margin-top: $spacing-2;
justify-content: center;
.property-tag {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: var(--color-bg-secondary);
border-radius: $radius-full;
color: var(--color-text-secondary);
text-transform: uppercase;
}
}
}
// Versatile weapon toggle
.versatile-toggle {
@include flex-center;
padding: $spacing-2;
.checkbox-label {
@include flex-center;
gap: $spacing-2;
cursor: pointer;
input[type="checkbox"] {
width: 1.25rem;
height: 1.25rem;
accent-color: var(--color-accent-primary);
}
span {
color: var(--color-text-primary);
} }
} }
} }
@ -95,6 +213,7 @@
> label { > label {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
color: var(--color-text-primary);
} }
.favor-hinder-toggles { .favor-hinder-toggles {
@ -109,18 +228,18 @@
&.favor-btn { &.favor-btn {
&.active, &.active,
&:hover { &:hover {
background-color: rgba($color-success, 0.15); background-color: rgba(74, 159, 66, 0.15);
border-color: $color-success; border-color: var(--color-success);
color: $color-success; color: var(--color-success);
} }
} }
&.hinder-btn { &.hinder-btn {
&.active, &.active,
&:hover { &:hover {
background-color: rgba($color-danger, 0.15); background-color: rgba(201, 68, 68, 0.15);
border-color: $color-danger; border-color: var(--color-danger);
color: $color-danger; color: var(--color-danger);
} }
} }
} }
@ -128,19 +247,24 @@
.net-favor-hinder { .net-favor-hinder {
@include flex-center; @include flex-center;
padding: $spacing-1 $spacing-2; gap: $spacing-2;
padding: $spacing-2 $spacing-3;
font-size: $font-size-sm; font-size: $font-size-sm;
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
border-radius: $radius-md; border-radius: $radius-md;
i {
font-size: $font-size-base;
}
&.favor { &.favor {
background-color: rgba($color-success, 0.15); background-color: rgba(74, 159, 66, 0.15);
color: $color-success; color: var(--color-success);
} }
&.hinder { &.hinder {
background-color: rgba($color-danger, 0.15); background-color: rgba(201, 68, 68, 0.15);
color: $color-danger; color: var(--color-danger);
} }
} }
} }
@ -152,6 +276,7 @@
> label { > label {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
color: var(--color-text-primary);
} }
.modifier-presets { .modifier-presets {
@ -166,7 +291,7 @@
font-size: $font-size-sm; font-size: $font-size-sm;
&:hover { &:hover {
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
} }
} }
} }
@ -196,129 +321,310 @@
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;
} }
.insufficient-mana-label {
font-size: $font-size-sm;
opacity: 0.8;
}
} }
} }
} }
// Skill check dialog specific // ===========================================
.vagabond.skill-check-dialog { // Save Roll Dialog Specific Styles
// Additional skill-specific styles if needed // ===========================================
} .vagabond.roll-dialog {
// Defense options (Block/Dodge for Reflex saves)
// Attack roll dialog specific .defense-options {
.vagabond.attack-roll-dialog {
.weapon-selection {
@include flex-column; @include flex-column;
gap: $spacing-2; gap: $spacing-2;
margin-top: $spacing-2;
label { > label {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
color: var(--color-text-primary);
} }
.no-weapons-message { .defense-buttons {
padding: $spacing-3; display: flex;
text-align: center; gap: $spacing-2;
color: $color-text-muted;
font-style: italic;
}
}
.attack-info { .defense-btn {
@include panel; @include button-secondary;
@include grid(2, $spacing-2); flex: 1;
gap: $spacing-2;
padding: $spacing-3; padding: $spacing-3;
> div { i {
@include flex-between;
}
.label {
font-size: $font-size-sm;
color: $color-text-muted;
}
.value {
font-weight: $font-weight-medium;
&.difficulty {
font-family: $font-family-header;
font-size: $font-size-lg; font-size: $font-size-lg;
font-weight: $font-weight-bold;
} }
&.crit { &.dodge-btn {
color: $color-warning; &.active,
&:hover:not(:disabled) {
background-color: rgba(74, 159, 66, 0.15);
border-color: var(--color-success);
color: var(--color-success);
}
}
&.block-btn {
&.active,
&:hover:not(:disabled) {
background-color: rgba(64, 144, 224, 0.15);
border-color: var(--color-info);
color: var(--color-info);
}
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
&:hover {
background-color: transparent;
border-color: var(--color-border);
color: var(--color-text-muted);
}
} }
} }
} }
.damage-preview { .defense-info {
@include flex-center;
gap: $spacing-2;
padding: $spacing-2 $spacing-3;
font-size: $font-size-sm;
color: var(--color-text-secondary);
background-color: var(--color-bg-secondary);
border-radius: $radius-md;
i {
color: var(--color-info);
}
}
}
}
// ===========================================
// Spell Cast Dialog Specific Styles
// ===========================================
.vagabond.roll-dialog {
// Mana display
.mana-display {
@include panel; @include panel;
@include flex-between;
padding: $spacing-3; padding: $spacing-3;
background-color: rgba($color-danger, 0.1); background: linear-gradient(135deg, rgba(112, 80, 176, 0.1), rgba(112, 80, 176, 0.05));
border-color: rgba($color-danger, 0.3); border-color: rgba(112, 80, 176, 0.3);
.damage-formula { .mana-current,
.mana-cost {
@include flex-center; @include flex-center;
gap: $spacing-2; gap: $spacing-2;
.label { .label {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
} }
.value { .value {
font-family: $font-family-mono; font-family: $font-family-header;
font-size: $font-size-xl;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
font-size: $font-size-lg; color: var(--color-reason);
}
.damage-type { &.insufficient {
font-size: $font-size-sm; color: var(--color-danger);
color: $color-text-secondary;
} }
} }
.weapon-properties {
display: flex;
flex-wrap: wrap;
gap: $spacing-1;
margin-top: $spacing-2;
justify-content: center;
.property-tag {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: $color-parchment-dark;
border-radius: $radius-full;
color: $color-text-secondary;
text-transform: uppercase;
}
} }
} }
.versatile-toggle { // Spell effect section
@include flex-center; .spell-effect {
padding: $spacing-2; @include panel;
padding: $spacing-3;
.checkbox-label { background-color: var(--color-bg-secondary);
.effect-header {
margin-bottom: $spacing-2;
.include-effect-toggle {
@include flex-center; @include flex-center;
justify-content: flex-start;
gap: $spacing-2; gap: $spacing-2;
cursor: pointer; cursor: pointer;
input[type="checkbox"] { input[type="checkbox"] {
width: 1.25rem; width: 1.25rem;
height: 1.25rem; height: 1.25rem;
accent-color: $color-accent-primary; accent-color: var(--color-accent-primary);
}
span {
font-weight: $font-weight-semibold;
color: var(--color-text-primary);
}
}
}
.effect-text {
font-size: $font-size-sm;
color: var(--color-text-secondary);
padding: $spacing-2;
background-color: var(--color-bg-primary);
border-radius: $radius-sm;
border-left: 3px solid var(--color-accent-primary);
}
}
// Damage configuration (dice slider)
.damage-config {
@include flex-column;
gap: $spacing-2;
> label {
font-weight: $font-weight-semibold;
color: var(--color-text-primary);
}
.damage-dice-input {
@include flex-center;
gap: $spacing-3;
input[type="range"] {
flex: 1;
height: 8px;
border-radius: $radius-full;
background: var(--color-bg-tertiary);
outline: none;
cursor: pointer;
&::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--color-danger);
cursor: pointer;
border: 2px solid var(--color-bg-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
&::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--color-danger);
cursor: pointer;
border: 2px solid var(--color-bg-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
}
.dice-count {
font-family: $font-family-mono;
font-size: $font-size-lg;
font-weight: $font-weight-bold;
color: var(--color-danger);
min-width: 4rem;
text-align: center;
}
}
.damage-preview {
@include flex-center;
gap: $spacing-2;
padding: $spacing-2;
background-color: rgba(201, 68, 68, 0.08);
border-radius: $radius-md;
.label {
font-size: $font-size-sm;
color: var(--color-text-muted);
}
.value {
font-family: $font-family-mono;
font-weight: $font-weight-bold;
color: var(--color-danger);
}
.damage-type {
font-size: $font-size-sm;
color: var(--color-text-secondary);
}
}
}
// Delivery and Duration selection
.delivery-selection,
.duration-selection {
@include flex-column;
gap: $spacing-2;
> label {
font-weight: $font-weight-semibold;
color: var(--color-text-primary);
}
select {
@include input-base;
width: 100%;
cursor: pointer;
}
}
// Focus warning
.focus-warning {
@include panel;
@include flex-column;
gap: $spacing-2;
padding: $spacing-3;
background-color: rgba(212, 163, 44, 0.1);
border-color: var(--color-warning);
> i {
color: var(--color-warning);
}
> span {
font-size: $font-size-sm;
color: var(--color-text-secondary);
}
.current-focus {
font-size: $font-size-sm;
color: var(--color-text-muted);
font-style: italic;
}
.focus-limit-warning {
@include flex-center;
gap: $spacing-2;
padding: $spacing-2;
font-size: $font-size-sm;
font-weight: $font-weight-medium;
color: var(--color-danger);
background-color: rgba(201, 68, 68, 0.1);
border-radius: $radius-md;
i {
color: var(--color-danger);
} }
} }
} }
} }
// ===========================================
// Legacy dialog styles (for backward compatibility) // Legacy dialog styles (for backward compatibility)
// ===========================================
.vagabond.dialog.roll-dialog { .vagabond.dialog.roll-dialog {
.dialog-content { .dialog-content {
padding: $spacing-4; padding: $spacing-4;
background-color: var(--color-bg-primary);
color: var(--color-text-primary);
} }
// Roll info section // Roll info section
@ -335,14 +641,15 @@
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-3xl; font-size: $font-size-3xl;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: var(--color-accent-primary);
} }
.crit-threshold { .crit-threshold {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
.crit-value { .crit-value {
color: $color-accent-primary; color: var(--color-warning);
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
} }
} }
@ -361,14 +668,15 @@
label { label {
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: var(--color-text-primary);
} }
&.favor .toggle-active { &.favor .toggle-active {
color: $color-success; color: var(--color-success);
} }
&.hinder .toggle-active { &.hinder .toggle-active {
color: $color-danger; color: var(--color-danger);
} }
} }
} }
@ -398,7 +706,7 @@
} }
} }
// Spell cast dialog specific // Legacy spell cast dialog
.vagabond.dialog.spell-cast-dialog { .vagabond.dialog.spell-cast-dialog {
.mana-cost { .mana-cost {
@include panel; @include panel;
@ -408,20 +716,21 @@
.cost-label { .cost-label {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
color: var(--color-text-primary);
} }
.cost-value { .cost-value {
font-family: $font-family-header; font-family: $font-family-header;
font-size: $font-size-xl; font-size: $font-size-xl;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
color: $color-accent-primary; color: var(--color-reason);
} }
&.insufficient { &.insufficient {
border-color: $color-danger; border-color: var(--color-danger);
.cost-value { .cost-value {
color: $color-danger; color: var(--color-danger);
} }
} }
} }
@ -434,6 +743,7 @@
.selection-label { .selection-label {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
margin-bottom: $spacing-2; margin-bottom: $spacing-2;
color: var(--color-text-primary);
} }
.selection-grid { .selection-grid {
@ -447,35 +757,34 @@
transition: all $transition-fast; transition: all $transition-fast;
&:hover { &:hover {
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
} }
&.selected { &.selected {
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
} }
.option-name { .option-name {
font-weight: $font-weight-medium; font-weight: $font-weight-medium;
color: var(--color-text-primary);
} }
.option-cost { .option-cost {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-muted; color: var(--color-text-muted);
} }
} }
} }
} }
// ===========================================
// Favor/Hinder Debug Panel // Favor/Hinder Debug Panel
// ===========================================
.vagabond.favor-hinder-debug { .vagabond.favor-hinder-debug {
// Force light background on the entire window content &.themed {
// Using !important to override Foundry's dark theme styles background-color: var(--color-bg-primary);
background-color: $color-parchment !important; color: var(--color-text-primary);
color: $color-text-primary !important;
* {
color: $color-text-primary;
} }
// Enable scrolling on the window content // Enable scrolling on the window content
@ -489,7 +798,7 @@
@include flex-column; @include flex-column;
gap: $spacing-4; gap: $spacing-4;
padding: $spacing-4; padding: $spacing-4;
background-color: $color-parchment !important; background-color: var(--color-bg-primary);
} }
.actor-selection { .actor-selection {
@ -498,7 +807,7 @@
label { label {
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
color: $color-text-primary; color: var(--color-text-primary);
} }
} }
@ -510,7 +819,7 @@
.debug-panel { .debug-panel {
@include panel; @include panel;
padding: $spacing-3; padding: $spacing-3;
background-color: $color-parchment-light; background-color: var(--color-bg-secondary);
h3 { h3 {
@include flex-center; @include flex-center;
@ -518,12 +827,12 @@
gap: $spacing-2; gap: $spacing-2;
margin: 0 0 $spacing-3 0; margin: 0 0 $spacing-3 0;
padding-bottom: $spacing-2; padding-bottom: $spacing-2;
border-bottom: 1px solid $color-border; border-bottom: 1px solid var(--color-border);
font-size: $font-size-base; font-size: $font-size-base;
color: $color-text-primary; color: var(--color-text-primary);
i { i {
color: $color-accent-primary; color: var(--color-accent-primary);
} }
} }
} }
@ -531,21 +840,21 @@
.flag-table { .flag-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
background-color: $color-parchment-light; background-color: var(--color-bg-secondary);
th, th,
td { td {
padding: $spacing-2; padding: $spacing-2;
text-align: left; text-align: left;
border-bottom: 1px solid $color-border-light; border-bottom: 1px solid var(--color-border-light);
color: $color-text-primary; color: var(--color-text-primary);
} }
th { th {
font-size: $font-size-sm; font-size: $font-size-sm;
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
color: $color-text-secondary; color: var(--color-text-secondary);
background-color: $color-parchment-dark; background-color: var(--color-bg-tertiary);
&.center { &.center {
text-align: center; text-align: center;
@ -553,7 +862,7 @@
} }
td { td {
background-color: $color-parchment-light !important; background-color: var(--color-bg-secondary);
&.center { &.center {
text-align: center; text-align: center;
@ -564,17 +873,16 @@
} }
} }
// Alternating row colors with good contrast
tbody tr:nth-child(even) td { tbody tr:nth-child(even) td {
background-color: $color-parchment !important; background-color: var(--color-bg-primary);
} }
.stat-tag { .stat-tag {
font-size: $font-size-xs; font-size: $font-size-xs;
padding: $spacing-1 $spacing-2; padding: $spacing-1 $spacing-2;
background-color: $color-parchment-dark; background-color: var(--color-bg-tertiary);
border-radius: $radius-full; border-radius: $radius-full;
color: $color-text-secondary; color: var(--color-text-secondary);
text-transform: uppercase; text-transform: uppercase;
} }
@ -582,11 +890,11 @@
width: 1.25rem; width: 1.25rem;
height: 1.25rem; height: 1.25rem;
cursor: pointer; cursor: pointer;
accent-color: $color-accent-primary; accent-color: var(--color-accent-primary);
} }
tbody tr:hover td { tbody tr:hover td {
background-color: $color-parchment-dark; background-color: var(--color-bg-tertiary);
} }
} }
@ -594,7 +902,7 @@
display: flex; display: flex;
gap: $spacing-3; gap: $spacing-3;
padding-top: $spacing-3; padding-top: $spacing-3;
border-top: 1px solid $color-border; border-top: 1px solid var(--color-border);
button { button {
@include button-base; @include button-base;
@ -608,11 +916,11 @@
.clear-btn { .clear-btn {
@include button-secondary; @include button-secondary;
color: $color-danger; color: var(--color-danger);
border-color: $color-danger; border-color: var(--color-danger);
&:hover:not(:disabled) { &:hover:not(:disabled) {
background-color: rgba($color-danger, 0.1); background-color: rgba(201, 68, 68, 0.1);
} }
} }
} }
@ -623,7 +931,7 @@
gap: $spacing-3; gap: $spacing-3;
padding: $spacing-6; padding: $spacing-6;
text-align: center; text-align: center;
color: $color-text-muted; color: var(--color-text-muted);
i { i {
font-size: $font-size-4xl; font-size: $font-size-4xl;

File diff suppressed because it is too large Load Diff

View File

@ -4,25 +4,36 @@
.vagabond.sheet.item { .vagabond.sheet.item {
min-width: 500px; min-width: 500px;
min-height: 400px; min-height: 400px;
display: flex;
flex-direction: column;
// Utility class for hiding inactive tabs
.hidden {
display: none !important;
}
// Header styling // Header styling
.sheet-header.item-header { .sheet-header.item-header {
@include flex-between; @include flex-between;
padding: $spacing-4; padding: $spacing-4;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
border-bottom: 2px solid $color-border; border-bottom: 2px solid var(--color-border);
gap: $spacing-4; gap: $spacing-4;
.item-img { .item-img {
width: 64px; width: 64px;
height: 64px; height: 64px;
object-fit: cover; object-fit: cover;
border: 2px solid $color-border; border: 2px solid var(--color-border);
border-radius: $radius-md; border-radius: $radius-md;
cursor: pointer; cursor: pointer;
transition: all $transition-fast;
box-shadow: 0 1px 3px var(--shadow-light);
&:hover { &:hover {
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
box-shadow: 0 2px 6px var(--shadow-medium);
transform: scale(1.02);
} }
} }
@ -37,14 +48,23 @@
input { input {
width: 100%; width: 100%;
font-size: $font-size-lg; font-family: $font-family-header;
font-weight: bold; font-size: $font-size-xl;
font-weight: $font-weight-bold;
color: var(--color-text-primary);
border: none; border: none;
background: transparent; background: transparent;
border-bottom: 1px solid transparent; border-bottom: 1px solid transparent;
padding: $spacing-1 0;
transition: border-color $transition-fast;
&:hover {
border-bottom-color: var(--color-border-light);
}
&:focus { &:focus {
border-bottom-color: $color-accent-primary; border-bottom-color: var(--color-accent-primary);
outline: none;
} }
} }
} }
@ -56,35 +76,64 @@
font-size: $font-size-sm; font-size: $font-size-sm;
font-weight: 500; font-weight: 500;
text-transform: capitalize; text-transform: capitalize;
background-color: $color-parchment; background-color: var(--color-bg-primary);
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-full; border-radius: $radius-full;
&.weapon { &.weapon {
background-color: mix($color-danger, $color-parchment, 15%); background-color: var(--color-badge-weapon);
} }
&.armor { &.armor {
background-color: mix($color-info, $color-parchment, 15%); background-color: var(--color-badge-armor);
} }
&.spell { &.spell {
background-color: mix($color-reason, $color-parchment, 15%); background-color: var(--color-badge-spell);
} }
&.perk { &.perk {
background-color: mix($color-success, $color-parchment, 15%); background-color: var(--color-badge-perk);
} }
&.class { &.class {
background-color: mix($color-warning, $color-parchment, 15%); background-color: var(--color-badge-class);
}
&.feature {
background-color: var(--color-badge-feature);
}
&.ancestry {
background-color: var(--color-badge-ancestry);
}
&.equipment {
background-color: var(--color-badge-equipment);
} }
} }
} }
} }
} }
// Sheet body // Tab content areas (both .sheet-body and .tab-content)
.sheet-body { .sheet-body,
.tab-content {
padding: $spacing-4; padding: $spacing-4;
overflow-y: auto; overflow-y: auto;
max-height: calc(100% - 80px); background-color: var(--color-bg-primary);
@include custom-scrollbar;
// When used as standalone body (no tabs)
&.sheet-body {
flex: 1;
min-height: 0; // Important for flexbox scrolling
}
}
// Details tab specific
.details-tab {
&.sheet-body {
// Combined class - body that's also the details tab
}
}
// Effects tab has its own padding defined in .effects-tab
.effects-tab.tab-content {
padding: 0; // Remove duplicate padding, .effects-tab handles it
} }
// Item content container // Item content container
@ -120,9 +169,11 @@
} }
label { label {
font-size: $font-size-sm; font-size: $font-size-xs;
font-weight: 500; font-weight: $font-weight-semibold;
color: $color-text-secondary; color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.03em;
} }
input[type="text"], input[type="text"],
@ -130,17 +181,29 @@
select, select,
textarea { textarea {
padding: $spacing-2; padding: $spacing-2;
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-sm; border-radius: $radius-sm;
background-color: $color-parchment-light; background-color: var(--color-bg-input);
font-family: $font-family-body;
font-size: $font-size-sm;
color: var(--color-text-primary);
transition:
border-color $transition-fast,
box-shadow $transition-fast;
&:hover:not(:disabled) {
border-color: var(--color-border-dark);
}
&:focus { &:focus {
border-color: $color-accent-primary; border-color: var(--color-accent-primary);
box-shadow: 0 0 0 2px rgba(139, 69, 19, 0.15);
outline: none; outline: none;
} }
&:disabled { &:disabled {
background-color: $color-parchment; background-color: var(--color-bg-primary);
color: var(--color-text-muted);
cursor: not-allowed; cursor: not-allowed;
} }
} }
@ -150,6 +213,12 @@
height: 18px; height: 18px;
margin: 0; margin: 0;
cursor: pointer; cursor: pointer;
accent-color: var(--color-accent-primary);
&:disabled {
cursor: not-allowed;
opacity: 0.6;
}
} }
input[type="number"] { input[type="number"] {
@ -168,7 +237,7 @@
.units { .units {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-secondary; color: var(--color-text-secondary);
} }
textarea { textarea {
@ -180,11 +249,11 @@
// Fieldset styling // Fieldset styling
fieldset { fieldset {
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-md; border-radius: $radius-md;
padding: $spacing-3; padding: $spacing-3;
margin: 0; margin: 0;
background-color: rgba($color-parchment-dark, 0.3); background-color: var(--color-bg-highlight);
legend { legend {
padding: 0 $spacing-2; padding: 0 $spacing-2;
@ -254,15 +323,55 @@
font-weight: 600; font-weight: 600;
} }
.editor-container { .editor-wrapper {
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-sm; border-radius: $radius-sm;
overflow: hidden; background-color: var(--color-bg-input);
.editor {
min-height: 120px; min-height: 120px;
max-height: 400px;
overflow: auto;
resize: vertical;
// Static content display (non-editable)
> .editor-content {
min-height: 100px;
padding: $spacing-2; padding: $spacing-2;
background-color: $color-parchment-light; }
// ProseMirror custom element styling
prose-mirror {
display: flex;
flex-direction: column;
min-height: 100px;
// The menu bar that appears when editing
> menu.editor-menu {
flex: 0 0 auto;
position: sticky;
top: 0;
z-index: 1;
background-color: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
}
// Foundry's inner editor-container
> .editor-container {
flex: 1 1 auto;
display: flex;
flex-direction: column;
min-height: 80px;
// The actual editable content area
> .editor-content {
flex: 1 1 auto;
padding: $spacing-2;
}
}
// Toggle button
> button.toggle {
display: none; // Hide since we use toggled="false"
}
} }
} }
} }
@ -275,9 +384,9 @@
.trait-entry { .trait-entry {
padding: $spacing-3; padding: $spacing-3;
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-sm; border-radius: $radius-sm;
background-color: $color-parchment-light; background-color: var(--color-bg-input);
.trait-header { .trait-header {
display: flex; display: flex;
@ -291,7 +400,7 @@
button { button {
@include button-icon; @include button-icon;
color: $color-danger; color: var(--color-danger);
} }
} }
@ -302,7 +411,7 @@
} }
.no-traits { .no-traits {
color: $color-text-secondary; color: var(--color-text-secondary);
font-style: italic; font-style: italic;
text-align: center; text-align: center;
padding: $spacing-4; padding: $spacing-4;
@ -330,7 +439,7 @@
label { label {
font-size: $font-size-xs; font-size: $font-size-xs;
font-weight: 600; font-weight: 600;
color: $color-text-secondary; color: var(--color-text-secondary);
} }
input { input {
@ -364,7 +473,7 @@
.hint { .hint {
font-size: $font-size-xs; font-size: $font-size-xs;
color: $color-text-secondary; color: var(--color-text-secondary);
font-style: italic; font-style: italic;
} }
} }
@ -380,7 +489,7 @@
grid-template-columns: 50px 60px 80px 80px 1fr 40px; grid-template-columns: 50px 60px 80px 80px 1fr 40px;
gap: $spacing-2; gap: $spacing-2;
padding: $spacing-2; padding: $spacing-2;
background-color: $color-parchment-dark; background-color: var(--color-bg-secondary);
font-size: $font-size-xs; font-size: $font-size-xs;
font-weight: 600; font-weight: 600;
border-radius: $radius-sm $radius-sm 0 0; border-radius: $radius-sm $radius-sm 0 0;
@ -391,8 +500,8 @@
grid-template-columns: 50px 60px 80px 80px 1fr 40px; grid-template-columns: 50px 60px 80px 80px 1fr 40px;
gap: $spacing-2; gap: $spacing-2;
padding: $spacing-2; padding: $spacing-2;
border-bottom: 1px solid $color-border; border-bottom: 1px solid var(--color-border);
background-color: $color-parchment-light; background-color: var(--color-bg-input);
&:last-child { &:last-child {
border-radius: 0 0 $radius-sm $radius-sm; border-radius: 0 0 $radius-sm $radius-sm;
@ -406,14 +515,14 @@
button { button {
@include button-icon; @include button-icon;
color: $color-danger; color: var(--color-danger);
} }
} }
.no-progression { .no-progression {
padding: $spacing-4; padding: $spacing-4;
text-align: center; text-align: center;
color: $color-text-secondary; color: var(--color-text-secondary);
font-style: italic; font-style: italic;
} }
} }
@ -429,9 +538,9 @@
.feature-entry { .feature-entry {
padding: $spacing-3; padding: $spacing-3;
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-sm; border-radius: $radius-sm;
background-color: $color-parchment-light; background-color: var(--color-bg-input);
.feature-header { .feature-header {
display: flex; display: flex;
@ -458,7 +567,7 @@
button { button {
@include button-icon; @include button-icon;
color: $color-danger; color: var(--color-danger);
} }
} }
@ -471,7 +580,7 @@
.no-features { .no-features {
padding: $spacing-4; padding: $spacing-4;
text-align: center; text-align: center;
color: $color-text-secondary; color: var(--color-text-secondary);
font-style: italic; font-style: italic;
} }
} }
@ -488,14 +597,55 @@
font-weight: 600; font-weight: 600;
} }
.editor-container { .editor-wrapper {
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-sm; border-radius: $radius-sm;
background-color: var(--color-bg-input);
.editor {
min-height: 80px; min-height: 80px;
max-height: 300px;
overflow: auto;
resize: vertical;
// Static content display (non-editable)
> .editor-content {
min-height: 60px;
padding: $spacing-2; padding: $spacing-2;
background-color: $color-parchment-light; }
// ProseMirror custom element styling
prose-mirror {
display: flex;
flex-direction: column;
min-height: 60px;
// The menu bar that appears when editing
> menu.editor-menu {
flex: 0 0 auto;
position: sticky;
top: 0;
z-index: 1;
background-color: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
}
// Foundry's inner editor-container
> .editor-container {
flex: 1 1 auto;
display: flex;
flex-direction: column;
min-height: 40px;
// The actual editable content area
> .editor-content {
flex: 1 1 auto;
padding: $spacing-2;
}
}
// Toggle button
> button.toggle {
display: none;
}
} }
} }
} }
@ -515,6 +665,94 @@
} }
} }
// Requirements section (feature)
.requirements-section {
display: flex;
flex-direction: column;
gap: $spacing-2;
> label {
font-size: $font-size-xs;
font-weight: $font-weight-semibold;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.03em;
}
input {
padding: $spacing-2;
border: 1px solid var(--color-border);
border-radius: $radius-sm;
background-color: var(--color-bg-input);
font-family: $font-family-body;
font-size: $font-size-sm;
color: var(--color-text-primary);
transition:
border-color $transition-fast,
box-shadow $transition-fast;
&:hover:not(:disabled) {
border-color: var(--color-border-dark);
}
&:focus {
border-color: var(--color-accent-primary);
box-shadow: 0 0 0 2px rgba(139, 69, 19, 0.15);
outline: none;
}
&:disabled {
background-color: var(--color-bg-primary);
color: var(--color-text-muted);
cursor: not-allowed;
}
}
}
// Ritual components (perk)
.ritual-components {
display: flex;
flex-direction: column;
gap: $spacing-2;
> label {
font-size: $font-size-xs;
font-weight: $font-weight-semibold;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.03em;
}
input {
padding: $spacing-2;
border: 1px solid var(--color-border);
border-radius: $radius-sm;
background-color: var(--color-bg-input);
font-family: $font-family-body;
font-size: $font-size-sm;
color: var(--color-text-primary);
transition:
border-color $transition-fast,
box-shadow $transition-fast;
&:hover:not(:disabled) {
border-color: var(--color-border-dark);
}
&:focus {
border-color: var(--color-accent-primary);
box-shadow: 0 0 0 2px rgba(139, 69, 19, 0.15);
outline: none;
}
&:disabled {
background-color: var(--color-bg-primary);
color: var(--color-text-muted);
cursor: not-allowed;
}
}
}
// Effects tab // Effects tab
.effects-tab { .effects-tab {
padding: $spacing-4; padding: $spacing-4;
@ -561,8 +799,8 @@
align-items: center; align-items: center;
gap: $spacing-2; gap: $spacing-2;
padding: $spacing-2; padding: $spacing-2;
background-color: $color-parchment-light; background-color: var(--color-bg-input);
border: 1px solid $color-border; border: 1px solid var(--color-border);
border-radius: $radius-sm; border-radius: $radius-sm;
&.disabled { &.disabled {
@ -587,7 +825,7 @@
width: 24px; width: 24px;
height: 24px; height: 24px;
border-radius: $radius-sm; border-radius: $radius-sm;
border: 1px solid $color-border; border: 1px solid var(--color-border);
} }
.effect-name { .effect-name {
@ -603,10 +841,10 @@
@include button-icon; @include button-icon;
&.delete { &.delete {
color: $color-danger; color: var(--color-danger);
&:hover { &:hover {
background-color: rgba($color-danger, 0.1); background-color: rgba(201, 68, 68, 0.1);
} }
} }
} }
@ -614,7 +852,7 @@
} }
.no-effects { .no-effects {
color: $color-text-secondary; color: var(--color-text-secondary);
font-style: italic; font-style: italic;
text-align: center; text-align: center;
padding: $spacing-4; padding: $spacing-4;
@ -622,7 +860,7 @@
.effects-hint { .effects-hint {
font-size: $font-size-sm; font-size: $font-size-sm;
color: $color-text-secondary; color: var(--color-text-secondary);
margin-top: $spacing-2; margin-top: $spacing-2;
i { i {

View File

@ -5,6 +5,9 @@
@import "variables"; @import "variables";
@import "mixins"; @import "mixins";
// Theme system (CSS custom properties)
@import "theme-variables";
// Base styles // Base styles
@import "base"; @import "base";

View File

@ -16,6 +16,17 @@
], ],
"esmodules": ["module/vagabond.mjs"], "esmodules": ["module/vagabond.mjs"],
"styles": ["styles/vagabond.css"], "styles": ["styles/vagabond.css"],
"themes": [
{
"name": "light",
"label": "VAGABOND.ThemeLight",
"default": true
},
{
"name": "dark",
"label": "VAGABOND.ThemeDark"
}
],
"languages": [ "languages": [
{ {
"lang": "en", "lang": "en",

View File

@ -64,8 +64,12 @@
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -128,8 +128,12 @@
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -56,8 +56,12 @@
{{!-- Starting Pack --}} {{!-- Starting Pack --}}
<div class="starting-pack-section"> <div class="starting-pack-section">
<label>{{localize "VAGABOND.StartingPack"}}</label> <label>{{localize "VAGABOND.StartingPack"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.startingPack target="system.startingPack" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.startingPack" toggled="false">{{{enrichedStartingPack}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedStartingPack}}}</div>
{{/if}}
</div> </div>
</div> </div>
@ -156,8 +160,12 @@
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -162,8 +162,12 @@
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -76,8 +76,12 @@
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -133,8 +133,12 @@
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -111,24 +111,36 @@
{{!-- Effect --}} {{!-- Effect --}}
<div class="spell-effect"> <div class="spell-effect">
<label>{{localize "VAGABOND.Effect"}}</label> <label>{{localize "VAGABOND.Effect"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.effect target="system.effect" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.effect" toggled="false">{{{enrichedEffect}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedEffect}}}</div>
{{/if}}
</div> </div>
</div> </div>
{{!-- Crit Effect --}} {{!-- Crit Effect --}}
<div class="spell-crit-effect"> <div class="spell-crit-effect">
<label>{{localize "VAGABOND.CritEffect"}}</label> <label>{{localize "VAGABOND.CritEffect"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.critEffect target="system.critEffect" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.critEffect" toggled="false">{{{enrichedCritEffect}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedCritEffect}}}</div>
{{/if}}
</div> </div>
</div> </div>
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -228,8 +228,12 @@
{{!-- Description --}} {{!-- Description --}}
<div class="item-description"> <div class="item-description">
<label>{{localize "VAGABOND.Description"}}</label> <label>{{localize "VAGABOND.Description"}}</label>
<div class="editor-container"> <div class="editor-wrapper">
{{editor system.description target="system.description" button=true editable=editable engine="prosemirror"}} {{#if editable}}
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
{{else}}
<div class="editor-content">{{{enrichedDescription}}}</div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>