diff --git a/src/core/persistence.js b/src/core/persistence.js index 58535a4..fcd1131 100644 --- a/src/core/persistence.js +++ b/src/core/persistence.js @@ -381,6 +381,14 @@ function migrateToTrackerConfig() { userStats: { customStats: [], showRPGAttributes: true, + rpgAttributes: [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ], statusSection: { enabled: true, showMoodEmoji: true, @@ -438,6 +446,47 @@ function migrateToTrackerConfig() { } } + // Migrate old showRPGAttributes boolean to rpgAttributes array + if (extensionSettings.trackerConfig.userStats.showRPGAttributes !== undefined) { + const shouldShow = extensionSettings.trackerConfig.userStats.showRPGAttributes; + extensionSettings.trackerConfig.userStats.rpgAttributes = [ + { id: 'str', name: 'STR', enabled: shouldShow }, + { id: 'dex', name: 'DEX', enabled: shouldShow }, + { id: 'con', name: 'CON', enabled: shouldShow }, + { id: 'int', name: 'INT', enabled: shouldShow }, + { id: 'wis', name: 'WIS', enabled: shouldShow }, + { id: 'cha', name: 'CHA', enabled: shouldShow } + ]; + delete extensionSettings.trackerConfig.userStats.showRPGAttributes; + console.log('[RPG Companion] Migrated showRPGAttributes to rpgAttributes array'); + } + + // Ensure rpgAttributes exists even if no migration was needed + if (!extensionSettings.trackerConfig.userStats.rpgAttributes) { + extensionSettings.trackerConfig.userStats.rpgAttributes = [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ]; + } + + // Ensure showRPGAttributes exists (defaults to true) + if (extensionSettings.trackerConfig.userStats.showRPGAttributes === undefined) { + extensionSettings.trackerConfig.userStats.showRPGAttributes = true; + } + + // Ensure all rpgAttributes have corresponding values in classicStats + if (extensionSettings.classicStats) { + for (const attr of extensionSettings.trackerConfig.userStats.rpgAttributes) { + if (extensionSettings.classicStats[attr.id] === undefined) { + extensionSettings.classicStats[attr.id] = 10; + } + } + } + // Migrate old presentCharacters structure to new format if (extensionSettings.trackerConfig.presentCharacters) { const pc = extensionSettings.trackerConfig.presentCharacters; diff --git a/src/core/state.js b/src/core/state.js index d0069c0..d3afd51 100644 --- a/src/core/state.js +++ b/src/core/state.js @@ -71,8 +71,16 @@ export let extensionSettings = { { id: 'hygiene', name: 'Hygiene', enabled: true }, { id: 'arousal', name: 'Arousal', enabled: true } ], - // RPG Attributes toggle + // RPG Attributes (customizable D&D-style attributes) showRPGAttributes: true, + rpgAttributes: [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ], // Status section config statusSection: { enabled: true, diff --git a/src/systems/generation/promptBuilder.js b/src/systems/generation/promptBuilder.js index 4049536..62be66c 100644 --- a/src/systems/generation/promptBuilder.js +++ b/src/systems/generation/promptBuilder.js @@ -56,6 +56,41 @@ export function buildInventorySummary(inventory) { return 'None'; } +/** + * Builds a dynamic attributes string based on configured RPG attributes. + * Uses custom attribute names and values from classicStats. + * + * @returns {string} Formatted attributes string (e.g., "STR 10, DEX 12, INT 15, LVL 5") + */ +function buildAttributesString() { + const trackerConfig = extensionSettings.trackerConfig; + const classicStats = extensionSettings.classicStats; + const userStatsConfig = trackerConfig?.userStats; + + // Get enabled attributes from config + const rpgAttributes = userStatsConfig?.rpgAttributes || [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ]; + + const enabledAttributes = rpgAttributes.filter(attr => attr && attr.enabled && attr.name && attr.id); + + // Build attributes string dynamically + const attributeParts = enabledAttributes.map(attr => { + const value = classicStats[attr.id] !== undefined ? classicStats[attr.id] : 10; + return `${attr.name} ${value}`; + }); + + // Add level at the end + attributeParts.push(`LVL ${extensionSettings.level}`); + + return attributeParts.join(', '); +} + /** * Generates an example block showing current tracker states in markdown code blocks. * Uses COMMITTED data (not displayed data) for generation context. @@ -170,7 +205,7 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon instructions += 'Weather: [Weather Emoji, Forecast]\n'; } if (widgets.temperature?.enabled) { - const unit = widgets.temperature.unit === 'fahrenheit' ? '°F' : '°C'; + const unit = widgets.temperature.unit === 'F' ? '°F' : '°C'; instructions += `Temperature: [Temperature in ${unit}]\n`; } if (widgets.time?.enabled) { @@ -250,7 +285,8 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon // Include attributes and dice roll only if there was a dice roll if (extensionSettings.lastDiceRoll) { const roll = extensionSettings.lastDiceRoll; - instructions += `${userName}'s attributes: STR ${classicStats.str}, DEX ${classicStats.dex}, CON ${classicStats.con}, INT ${classicStats.int}, WIS ${classicStats.wis}, CHA ${classicStats.cha}, LVL ${extensionSettings.level}\n`; + const attributesString = buildAttributesString(); + instructions += `${userName}'s attributes: ${attributesString}\n`; instructions += `${userName} rolled ${roll.total} on the last ${roll.formula} roll. Based on their attributes, decide whether they succeeded or failed the action they attempted.\n\n`; } } @@ -327,9 +363,9 @@ export function generateContextualSummary() { // Include attributes and dice roll only if there was a dice roll if (extensionSettings.lastDiceRoll) { - const classicStats = extensionSettings.classicStats; const roll = extensionSettings.lastDiceRoll; - summary += `${userName}'s attributes: STR ${classicStats.str}, DEX ${classicStats.dex}, CON ${classicStats.con}, INT ${classicStats.int}, WIS ${classicStats.wis}, CHA ${classicStats.cha}, LVL ${extensionSettings.level}\n`; + const attributesString = buildAttributesString(); + summary += `${userName}'s attributes: ${attributesString}\n`; summary += `${userName} rolled ${roll.total} on the last ${roll.formula} roll. Based on their attributes, decide whether they succeeded or failed the action they attempted.\n\n`; } diff --git a/src/systems/integration/sillytavern.js b/src/systems/integration/sillytavern.js index 53ac984..d429938 100644 --- a/src/systems/integration/sillytavern.js +++ b/src/systems/integration/sillytavern.js @@ -103,11 +103,11 @@ export async function onMessageReceived(data) { // console.log('[RPG Companion] Parsing together mode response:', responseText); const parsedData = parseResponse(responseText); - console.log('[RPG Companion] Parsed data results:', { - hasUserStats: !!parsedData.userStats, - hasInfoBox: !!parsedData.infoBox, - hasCharacterThoughts: !!parsedData.characterThoughts - }); + // console.log('[RPG Companion] Parsed data results:', { + // hasUserStats: !!parsedData.userStats, + // hasInfoBox: !!parsedData.infoBox, + // hasCharacterThoughts: !!parsedData.characterThoughts + // }); // Update stored data (both lastGeneratedData for old UI and extensionSettings for dashboard widgets) if (parsedData.userStats) { @@ -171,9 +171,7 @@ export async function onMessageReceived(data) { lastMessage.swipes[currentSwipeId] = cleanedMessage.trim(); } - // console.log('[RPG Companion] Cleaned message, removed tracker code blocks'); - - // Render the updated data (old panel UI) + // Render the updated data FIRST (before cleaning DOM) renderUserStats(); renderInfoBox(); renderThoughts(); @@ -183,6 +181,17 @@ export async function onMessageReceived(data) { // Refresh dashboard widgets (v2 dashboard) refreshDashboard(); + // Then update the DOM to reflect the cleaned message + const lastMessageElement = $('#chat').children('.mes').last(); + if (lastMessageElement.length) { + const messageText = lastMessageElement.find('.mes_text'); + if (messageText.length) { + messageText.html(substituteParams(cleanedMessage.trim())); + } + } + + // console.log('[RPG Companion] Cleaned message, removed tracker code blocks from DOM'); + // Save to chat metadata saveChatData(); } diff --git a/src/systems/rendering/infoBox.js b/src/systems/rendering/infoBox.js index 4a4a5e6..d223e84 100644 --- a/src/systems/rendering/infoBox.js +++ b/src/systems/rendering/infoBox.js @@ -329,18 +329,18 @@ export function renderInfoBox() { let tempValue = data.tempValue || 20; // Apply temperature unit conversion - const preferredUnit = config.widgets.temperature.unit || 'celsius'; + const preferredUnit = config.widgets.temperature.unit || 'C'; if (data.temperature) { // Detect current unit in the data const isCelsius = tempDisplay.includes('°C'); const isFahrenheit = tempDisplay.includes('°F'); - if (preferredUnit === 'fahrenheit' && isCelsius) { + if (preferredUnit === 'F' && isCelsius) { // Convert C to F const fahrenheit = Math.round((tempValue * 9/5) + 32); tempDisplay = `${fahrenheit}°F`; tempValue = fahrenheit; - } else if (preferredUnit === 'celsius' && isFahrenheit) { + } else if (preferredUnit === 'C' && isFahrenheit) { // Convert F to C const celsius = Math.round((tempValue - 32) * 5/9); tempDisplay = `${celsius}°C`; @@ -348,12 +348,14 @@ export function renderInfoBox() { } } else { // No data yet, use default for preferred unit - tempDisplay = preferredUnit === 'fahrenheit' ? '68°F' : '20°C'; - tempValue = preferredUnit === 'fahrenheit' ? 68 : 20; + tempDisplay = preferredUnit === 'F' ? '68°F' : '20°C'; + tempValue = preferredUnit === 'F' ? 68 : 20; } - const tempPercent = Math.min(100, Math.max(0, ((tempValue + 20) / 60) * 100)); - const tempColor = tempValue < 10 ? '#4a90e2' : tempValue < 25 ? '#67c23a' : '#e94560'; + // Calculate thermometer display (convert to Celsius for consistent thresholds) + const tempInCelsius = preferredUnit === 'F' ? Math.round((tempValue - 32) * 5/9) : tempValue; + const tempPercent = Math.min(100, Math.max(0, ((tempInCelsius + 20) / 60) * 100)); + const tempColor = tempInCelsius < 10 ? '#4a90e2' : tempInCelsius < 25 ? '#67c23a' : '#e94560'; row1Widgets.push(`
diff --git a/src/systems/rendering/thoughts.js b/src/systems/rendering/thoughts.js index fa1fbc0..d263ed1 100644 --- a/src/systems/rendering/thoughts.js +++ b/src/systems/rendering/thoughts.js @@ -396,7 +396,7 @@ export function renderThoughts() { const statColor = getStatColor(statValue, extensionSettings.statBarColorLow, extensionSettings.statBarColorHigh); html += `
- ${stat.name}: ${statValue}% + ${stat.name}: ${statValue}%
`; } @@ -431,6 +431,7 @@ export function renderThoughts() { const character = $(this).data('character'); const field = $(this).data('field'); const value = $(this).text().trim(); + console.log('[RPG Companion] Character stat edit:', { character, field, value }); updateCharacterField(character, field, value); }); @@ -492,10 +493,20 @@ export function updateCharacterField(characterName, field, value) { } if (characterFound) { - // Update the specific field within the character block + // Check if we're updating a character stat + const isStatField = enabledCharStats.findIndex(s => s.name === field) !== -1; + let statsLineExists = false; + let statsLineIndex = -1; + + // First pass: check if Stats line exists and update other fields for (let i = characterStartIndex; i < characterEndIndex; i++) { const line = lines[i].trim(); + if (line.startsWith('Stats:')) { + statsLineExists = true; + statsLineIndex = i; + } + if (field === 'name' && line.startsWith('- ')) { lines[i] = `- ${value}`; } @@ -519,20 +530,68 @@ export function updateCharacterField(characterName, field, value) { const relationshipValue = emojiToRelationship[value] || value; lines[i] = `Relationship: ${relationshipValue}`; } - else if (line.startsWith('Stats:')) { - const statIndex = enabledCharStats.findIndex(s => s.name === field); - if (statIndex !== -1) { - const statsContent = line.substring(line.indexOf(':') + 1).trim(); - const statParts = statsContent.split('|').map(p => p.trim()); + } - for (let j = 0; j < statParts.length; j++) { - if (statParts[j].startsWith(field + ':')) { - statParts[j] = `${field}: ${value}%`; - break; - } + // Handle stat updates + if (isStatField) { + // Clean the value: remove % if present, parse as integer, clamp 0-100 + let cleanValue = value.replace('%', '').trim(); + let numValue = parseInt(cleanValue); + if (isNaN(numValue)) { + numValue = 0; + } + numValue = Math.max(0, Math.min(100, numValue)); + + console.log('[RPG Companion] Updating stat:', { field, rawValue: value, cleanValue, numValue }); + + if (statsLineExists) { + // Update existing Stats line + const line = lines[statsLineIndex]; + const statsContent = line.substring(line.indexOf(':') + 1).trim(); + const statParts = statsContent.split('|').map(p => p.trim()); + + let statFound = false; + for (let j = 0; j < statParts.length; j++) { + if (statParts[j].startsWith(field + ':')) { + statParts[j] = `${field}: ${numValue}%`; + statFound = true; + console.log('[RPG Companion] Updated stat part:', statParts[j]); + break; } - lines[i] = `Stats: ${statParts.join(' | ')}`; } + + // If stat wasn't found in existing parts, add it + if (!statFound) { + statParts.push(`${field}: ${numValue}%`); + console.log('[RPG Companion] Added new stat to existing line:', `${field}: ${numValue}%`); + } + + lines[statsLineIndex] = `Stats: ${statParts.join(' | ')}`; + console.log('[RPG Companion] Updated stats line:', lines[statsLineIndex]); + } else { + // Create new Stats line with all enabled stats (defaulting to 0% except the one being edited) + const statsParts = enabledCharStats.map(s => { + if (s.name === field) { + return `${s.name}: ${numValue}%`; + } + return `${s.name}: 0%`; + }); + const newStatsLine = `Stats: ${statsParts.join(' | ')}`; + + // Insert before Thoughts line or at end of character block + let insertIndex = characterEndIndex; + for (let i = characterStartIndex; i < characterEndIndex; i++) { + const line = lines[i].trim(); + const thoughtsFieldName = presentCharsConfig?.thoughts?.name || 'Thoughts'; + if (line.startsWith(thoughtsFieldName + ':')) { + insertIndex = i; + break; + } + } + + lines.splice(insertIndex, 0, newStatsLine); + console.log('[RPG Companion] Created new stats line:', newStatsLine); + characterEndIndex++; // Adjust end index since we inserted a line } } } else { @@ -554,7 +613,19 @@ export function updateCharacterField(characterName, field, value) { } if (enabledCharStats.length > 0) { - const statsParts = enabledCharStats.map(s => `${s.name}: ${field === s.name ? value : '0'}%`); + const statsParts = enabledCharStats.map(s => { + if (field === s.name) { + // Clean the value: remove % if present, parse as integer, clamp 0-100 + let cleanValue = value.replace('%', '').trim(); + let numValue = parseInt(cleanValue); + if (isNaN(numValue)) { + numValue = 0; + } + numValue = Math.max(0, Math.min(100, numValue)); + return `${s.name}: ${numValue}%`; + } + return `${s.name}: 0%`; + }); newCharacterLines.push(`Stats: ${statsParts.join(' | ')}`); } @@ -565,6 +636,8 @@ export function updateCharacterField(characterName, field, value) { lastGeneratedData.characterThoughts = lines.join('\n'); committedTrackerData.characterThoughts = lines.join('\n'); + console.log('[RPG Companion] Updated characterThoughts data:', lastGeneratedData.characterThoughts); + const chat = getContext().chat; if (chat && chat.length > 0) { for (let i = chat.length - 1; i >= 0; i--) { diff --git a/src/systems/rendering/userStats.js b/src/systems/rendering/userStats.js index 12de415..97fad33 100644 --- a/src/systems/rendering/userStats.js +++ b/src/systems/rendering/userStats.js @@ -86,7 +86,14 @@ export function renderUserStats() { { id: 'hygiene', name: 'Hygiene', enabled: true }, { id: 'arousal', name: 'Arousal', enabled: true } ], - showRPGAttributes: true, + rpgAttributes: [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ], statusSection: { enabled: true, showMoodEmoji: true, customFields: ['Conditions'] }, skillsSection: { enabled: false, label: 'Skills' } }; @@ -171,64 +178,49 @@ export function renderUserStats() { html += '
'; // Close rpg-stats-left - // RPG Attributes section (conditionally rendered) - if (config.showRPGAttributes) { + // RPG Attributes section (dynamically generated from config) + // Check if RPG Attributes section is enabled + const showRPGAttributes = config.showRPGAttributes !== undefined ? config.showRPGAttributes : true; + + if (showRPGAttributes) { + // Use attributes from config, with fallback to defaults if not configured + const rpgAttributes = (config.rpgAttributes && config.rpgAttributes.length > 0) ? config.rpgAttributes : [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ]; + const enabledAttributes = rpgAttributes.filter(attr => attr && attr.enabled && attr.name && attr.id); + + if (enabledAttributes.length > 0) { html += `
-
- STR + `; + + enabledAttributes.forEach(attr => { + const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10; + html += ` +
+ ${attr.name}
- - ${extensionSettings.classicStats.str} - -
-
-
- DEX -
- - ${extensionSettings.classicStats.dex} - -
-
-
- CON -
- - ${extensionSettings.classicStats.con} - -
-
-
- INT -
- - ${extensionSettings.classicStats.int} - -
-
-
- WIS -
- - ${extensionSettings.classicStats.wis} - -
-
-
- CHA -
- - ${extensionSettings.classicStats.cha} - + + ${value} +
+ `; + }); + + html += `
`; + } } html += '
'; // Close rpg-stats-content diff --git a/src/systems/ui/trackerEditor.js b/src/systems/ui/trackerEditor.js index 4b96ef8..2d66f67 100644 --- a/src/systems/ui/trackerEditor.js +++ b/src/systems/ui/trackerEditor.js @@ -137,6 +137,14 @@ function resetToDefaults() { { id: 'arousal', name: 'Arousal', enabled: true } ], showRPGAttributes: true, + rpgAttributes: [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ], statusSection: { enabled: true, showMoodEmoji: true, @@ -221,12 +229,47 @@ function renderUserStatsTab() { html += '
'; html += ''; - // RPG Attributes toggle + // RPG Attributes section + html += '

RPG Attributes

'; + + // Enable/disable toggle for entire RPG Attributes section + const showRPGAttributes = config.showRPGAttributes !== undefined ? config.showRPGAttributes : true; html += '
'; - html += ``; - html += ''; + html += ``; + html += ''; html += '
'; + html += '
'; + + // Ensure rpgAttributes exists in the actual config (not just local fallback) + if (!config.rpgAttributes || config.rpgAttributes.length === 0) { + config.rpgAttributes = [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ]; + // Save the defaults back to the actual config + extensionSettings.trackerConfig.userStats.rpgAttributes = config.rpgAttributes; + } + + const rpgAttributes = config.rpgAttributes; + + rpgAttributes.forEach((attr, index) => { + html += ` +
+ + + +
+ `; + }); + + html += '
'; + html += ''; + // Status Section html += '

Status Section

'; html += '
'; @@ -296,7 +339,52 @@ function setupUserStatsListeners() { extensionSettings.trackerConfig.userStats.customStats[index].name = $(this).val(); }); - // RPG attributes toggle + // Add attribute + $('#rpg-add-attr').off('click').on('click', function() { + // Ensure rpgAttributes array exists with defaults if needed + if (!extensionSettings.trackerConfig.userStats.rpgAttributes || extensionSettings.trackerConfig.userStats.rpgAttributes.length === 0) { + extensionSettings.trackerConfig.userStats.rpgAttributes = [ + { id: 'str', name: 'STR', enabled: true }, + { id: 'dex', name: 'DEX', enabled: true }, + { id: 'con', name: 'CON', enabled: true }, + { id: 'int', name: 'INT', enabled: true }, + { id: 'wis', name: 'WIS', enabled: true }, + { id: 'cha', name: 'CHA', enabled: true } + ]; + } + const newId = 'attr_' + Date.now(); + extensionSettings.trackerConfig.userStats.rpgAttributes.push({ + id: newId, + name: 'NEW', + enabled: true + }); + // Initialize value in classicStats if doesn't exist + if (extensionSettings.classicStats[newId] === undefined) { + extensionSettings.classicStats[newId] = 10; + } + renderUserStatsTab(); + }); + + // Remove attribute + $('.rpg-attr-remove').off('click').on('click', function() { + const index = $(this).data('index'); + extensionSettings.trackerConfig.userStats.rpgAttributes.splice(index, 1); + renderUserStatsTab(); + }); + + // Toggle attribute + $('.rpg-attr-toggle').off('change').on('change', function() { + const index = $(this).data('index'); + extensionSettings.trackerConfig.userStats.rpgAttributes[index].enabled = $(this).is(':checked'); + }); + + // Rename attribute + $('.rpg-attr-name').off('blur').on('blur', function() { + const index = $(this).data('index'); + extensionSettings.trackerConfig.userStats.rpgAttributes[index].name = $(this).val(); + }); + + // Enable/disable RPG Attributes section toggle $('#rpg-show-rpg-attrs').off('change').on('change', function() { extensionSettings.trackerConfig.userStats.showRPGAttributes = $(this).is(':checked'); }); @@ -452,7 +540,7 @@ function renderPresentCharactersTab() { - +
`; } diff --git a/style.css b/style.css index 13d82f5..2c45c86 100644 --- a/style.css +++ b/style.css @@ -7981,3 +7981,67 @@ body:has(.rpg-panel.rpg-position-left) #sheld { .rpg-widget-empty-state a:hover { opacity: 0.8; } + +/* ======================================== + MOBILE FONT SIZE OVERRIDES (ALL SCREENS) + Apply to screens up to 1000px + ======================================== */ +@media (max-width: 1000px) { + /* Collapse toggle button */ + .rpg-collapse-toggle { + font-size: clamp(16px, 3vw, 20px) !important; + } + + /* Top position panel titles */ + .rpg-panel.rpg-position-top .rpg-stats-title { + font-size: clamp(12px, 2.6vw, 16px) !important; + } + + .rpg-panel.rpg-position-top .rpg-mood { + font-size: clamp(10px, 2vw, 13px) !important; + } + + .rpg-panel.rpg-position-top .rpg-classic-stats-title { + font-size: clamp(10px, 2vw, 13px) !important; + } + + .rpg-panel.rpg-position-top .rpg-classic-stat-label { + font-size: clamp(8px, 1.7vw, 11px) !important; + } + + .rpg-panel.rpg-position-top .rpg-classic-stat-value { + font-size: clamp(12px, 2.6vw, 16px) !important; + } + + .rpg-panel.rpg-position-top .rpg-classic-stat-btn { + font-size: clamp(10px, 2.2vw, 14px) !important; + } + + .rpg-panel.rpg-position-top .rpg-info-content, + .rpg-panel.rpg-position-top .rpg-thoughts-content { + font-size: clamp(10px, 2.2vw, 14px) !important; + } + + /* Panel header */ + .rpg-panel-header h3 { + font-size: clamp(14px, 3.4vw, 18px) !important; + } + + /* Loading indicator */ + .rpg-loading { + font-size: clamp(12px, 2.6vw, 16px) !important; + } + + /* Dice display */ + .rpg-dice-display { + font-size: clamp(10px, 2vw, 13px) !important; + } + + .rpg-dice-display i { + font-size: clamp(12px, 2.6vw, 16px) !important; + } + + .rpg-clear-dice-btn { + font-size: clamp(14px, 3vw, 18px) !important; + } +}