- Add CSS minification support to build script (--minify flag)
- Pure JS minifier: removes comments, whitespace, redundant chars
- Reports size reduction percentage
- Preserves CSS custom properties, data URIs, strings
- Refactor _08_themes.css: extend CSS custom properties pattern
- Define theme-specific properties per theme (--rpg-content-bg,
--rpg-content-box-shadow, --rpg-header-text-shadow, etc.)
- Replace triple-theme selector duplication with single [data-theme]
selectors — children inherit variables automatically
- Reduces themes.css from 379 to ~220 lines
- Reduces style.css from 305KB to 294KB (3.8% reduction)
- Add build:css:min npm script for production builds
- Add 9 tests for CSS build: minification, size reduction, CSS
variable preservation, data URI preservation, theme refactoring
277 lines
9.4 KiB
CSS
277 lines
9.4 KiB
CSS
/* ============================================
|
|
THEME VARIATIONS
|
|
============================================ */
|
|
|
|
/* Sci-Fi / Synthwave Theme */
|
|
.rpg-panel[data-theme="sci-fi"] {
|
|
--rpg-bg: #0a0e27;
|
|
--rpg-accent: #1a1f3a;
|
|
--rpg-text: #00fff9;
|
|
--rpg-highlight: #ff006e;
|
|
--rpg-border: #8b00ff;
|
|
--rpg-shadow: rgba(139, 0, 255, 0.5);
|
|
--rpg-content-bg: linear-gradient(135deg, #1a1f3a 0%, #0a0e27 100%);
|
|
--rpg-content-box-shadow: 0 0 40px rgba(139, 0, 255, 0.4), inset 0 0 30px rgba(0, 0, 0, 0.5);
|
|
--rpg-content-border: 2px solid #8b00ff;
|
|
--rpg-header-text-shadow: 0 0 20px #ff006e, 0 0 40px #8b00ff;
|
|
--rpg-divider-bg: linear-gradient(to right, transparent, #8b00ff, #ff006e, #8b00ff, transparent);
|
|
--rpg-thoughts-bg: linear-gradient(135deg, rgba(10, 14, 39, 0.9) 0%, rgba(26, 31, 58, 0.8) 50%, rgba(10, 14, 39, 0.9) 100%);
|
|
}
|
|
|
|
/* Apply sci-fi theme to thought panel */
|
|
#rpg-thought-panel[data-theme="sci-fi"],
|
|
#rpg-thought-icon[data-theme="sci-fi"],
|
|
#rpg-alt-present-characters[data-theme="sci-fi"],
|
|
.rpg-mobile-toggle[data-theme="sci-fi"] {
|
|
--rpg-bg: #0a0e27;
|
|
--rpg-accent: #1a1f3a;
|
|
--rpg-text: #00fff9;
|
|
--rpg-highlight: #ff006e;
|
|
--rpg-border: #8b00ff;
|
|
--rpg-shadow: rgba(139, 0, 255, 0.5);
|
|
}
|
|
|
|
/* Fantasy / Rustic Parchment Theme */
|
|
.rpg-panel[data-theme="fantasy"] {
|
|
--rpg-bg: #2b1810;
|
|
--rpg-accent: #3d2414;
|
|
--rpg-text: #f4e8d0;
|
|
--rpg-highlight: #d4af37;
|
|
--rpg-border: #8b6914;
|
|
--rpg-shadow: rgba(0, 0, 0, 0.7);
|
|
--rpg-bg-image: linear-gradient(rgba(43, 24, 16, 0.9), rgba(43, 24, 16, 0.9)), url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><filter id="noise"><feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="4" /></filter><rect width="100" height="100" filter="url(%23noise)" opacity="0.1"/></svg>');
|
|
--rpg-content-bg: linear-gradient(135deg, #3d2414 0%, #2b1810 100%);
|
|
--rpg-content-box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8), inset 0 0 40px rgba(139, 105, 20, 0.2);
|
|
--rpg-content-border: 3px solid #8b6914;
|
|
--rpg-content-border-style: ridge;
|
|
--rpg-header-font-family: 'Georgia', serif;
|
|
--rpg-header-text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
|
--rpg-divider-content: '❦';
|
|
--rpg-divider-font-size: clamp(1rem, 1.5vw, 1.5rem);
|
|
--rpg-thoughts-bg: linear-gradient(135deg, rgba(43, 24, 16, 0.92) 0%, rgba(61, 36, 20, 0.88) 50%, rgba(43, 24, 16, 0.92) 100%);
|
|
}
|
|
|
|
/* Apply fantasy theme to thought panel */
|
|
#rpg-thought-panel[data-theme="fantasy"],
|
|
#rpg-thought-icon[data-theme="fantasy"],
|
|
#rpg-alt-present-characters[data-theme="fantasy"],
|
|
.rpg-mobile-toggle[data-theme="fantasy"] {
|
|
--rpg-bg: #2b1810;
|
|
--rpg-accent: #3d2414;
|
|
--rpg-text: #f4e8d0;
|
|
--rpg-highlight: #d4af37;
|
|
--rpg-border: #8b6914;
|
|
--rpg-shadow: rgba(0, 0, 0, 0.7);
|
|
}
|
|
|
|
/* Cyberpunk / Neon Grid Theme */
|
|
.rpg-panel[data-theme="cyberpunk"] {
|
|
--rpg-bg: #000000;
|
|
--rpg-accent: #0d0d0d;
|
|
--rpg-text: #00ff41;
|
|
--rpg-highlight: #ff2a6d;
|
|
--rpg-border: #05d9e8;
|
|
--rpg-shadow: rgba(5, 217, 232, 0.5);
|
|
--rpg-bg-image: linear-gradient(rgba(0, 0, 0, 0.95), rgba(0, 0, 0, 0.95)), repeating-linear-gradient(0deg, rgba(5, 217, 232, 0.1) 0px, transparent 1px, transparent 2px, rgba(5, 217, 232, 0.1) 3px), repeating-linear-gradient(90deg, rgba(5, 217, 232, 0.1) 0px, transparent 1px, transparent 2px, rgba(5, 217, 232, 0.1) 3px);
|
|
--rpg-bg-size: 100% 100%, 30px 30px, 30px 30px;
|
|
--rpg-content-bg: linear-gradient(135deg, rgba(13, 13, 13, 0.9) 0%, rgba(0, 0, 0, 0.9) 100%);
|
|
--rpg-content-box-shadow: 0 0 40px rgba(255, 42, 109, 0.4), inset 0 0 30px rgba(5, 217, 232, 0.2);
|
|
--rpg-content-border: 2px solid #05d9e8;
|
|
--rpg-header-font-family: 'Courier New', monospace;
|
|
--rpg-header-letter-spacing: 0.125em;
|
|
--rpg-header-text-shadow: 0 0 10px #ff2a6d, 0 0 20px #05d9e8, 0 0 30px #ff2a6d;
|
|
--rpg-divider-bg: linear-gradient(to right, transparent, #05d9e8, #ff2a6d, #05d9e8, transparent);
|
|
--rpg-divider-height: 0.188rem;
|
|
--rpg-thoughts-bg: linear-gradient(135deg, rgba(0, 0, 0, 0.92) 0%, rgba(13, 13, 13, 0.85) 50%, rgba(0, 0, 0, 0.92) 100%);
|
|
}
|
|
|
|
/* Apply cyberpunk theme to thought panel */
|
|
#rpg-thought-panel[data-theme="cyberpunk"],
|
|
#rpg-thought-icon[data-theme="cyberpunk"],
|
|
#rpg-alt-present-characters[data-theme="cyberpunk"],
|
|
.rpg-mobile-toggle[data-theme="cyberpunk"] {
|
|
--rpg-bg: #000000;
|
|
--rpg-accent: #0d0d0d;
|
|
--rpg-text: #00ff41;
|
|
--rpg-highlight: #ff2a6d;
|
|
--rpg-border: #05d9e8;
|
|
--rpg-shadow: rgba(5, 217, 232, 0.5);
|
|
}
|
|
|
|
/* ============================================
|
|
THEME SUPPORT FOR ALL PANEL ELEMENTS
|
|
Uses CSS custom properties defined above — no selector duplication needed.
|
|
Any element inside .rpg-panel inherits the theme variables automatically.
|
|
============================================ */
|
|
|
|
/* Apply theme background image if defined */
|
|
.rpg-panel[data-theme] {
|
|
background-image: var(--rpg-bg-image, none);
|
|
background-size: var(--rpg-bg-size, auto);
|
|
}
|
|
|
|
/* Content box theming via custom properties */
|
|
.rpg-panel[data-theme] .rpg-content-box {
|
|
background: var(--rpg-content-bg);
|
|
box-shadow: var(--rpg-content-box-shadow);
|
|
border: var(--rpg-content-border);
|
|
border-style: var(--rpg-content-border-style, solid);
|
|
}
|
|
|
|
/* Header theming */
|
|
.rpg-panel[data-theme] .rpg-panel-header h3,
|
|
.rpg-panel[data-theme] .rpg-stats-title,
|
|
.rpg-panel[data-theme] .rpg-info-header,
|
|
.rpg-panel[data-theme] .rpg-thoughts-header {
|
|
font-family: var(--rpg-header-font-family, inherit);
|
|
text-shadow: var(--rpg-header-text-shadow, none);
|
|
letter-spacing: var(--rpg-header-letter-spacing, normal);
|
|
}
|
|
|
|
/* Divider theming */
|
|
.rpg-panel[data-theme] .rpg-divider {
|
|
background: var(--rpg-divider-bg);
|
|
height: var(--rpg-divider-height, auto);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-divider::after {
|
|
content: var(--rpg-divider-content, none);
|
|
font-size: var(--rpg-divider-font-size, inherit);
|
|
}
|
|
|
|
/* Thoughts content theming */
|
|
.rpg-panel[data-theme] .rpg-thoughts-content::before {
|
|
background: var(--rpg-thoughts-bg);
|
|
}
|
|
|
|
/* Tabs navigation theming */
|
|
.rpg-panel[data-theme] .rpg-tabs-nav {
|
|
border-bottom-color: var(--rpg-border);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-tab-btn {
|
|
background: var(--rpg-accent);
|
|
border-color: var(--rpg-border);
|
|
color: var(--rpg-text);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-tab-btn:hover {
|
|
background: var(--rpg-highlight);
|
|
border-color: var(--rpg-highlight);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-tab-btn.active {
|
|
background: var(--rpg-highlight);
|
|
border-color: var(--rpg-highlight);
|
|
color: var(--rpg-bg);
|
|
}
|
|
|
|
/* Inventory subtabs theming */
|
|
.rpg-panel[data-theme] .rpg-inventory-subtabs {
|
|
border-bottom-color: var(--rpg-border);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-inventory-subtab {
|
|
border-color: var(--rpg-border);
|
|
color: var(--rpg-text);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-inventory-subtab:hover {
|
|
border-color: var(--rpg-highlight);
|
|
color: var(--rpg-highlight);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-inventory-subtab.active {
|
|
border-color: var(--rpg-highlight);
|
|
color: var(--rpg-highlight);
|
|
}
|
|
|
|
/* Quests subtabs theming */
|
|
.rpg-panel[data-theme] .rpg-quests-subtabs {
|
|
border-bottom-color: var(--rpg-border);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-quests-subtab {
|
|
border-color: var(--rpg-border);
|
|
color: var(--rpg-text);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-quests-subtab:hover {
|
|
border-color: var(--rpg-highlight);
|
|
color: var(--rpg-highlight);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-quests-subtab.active {
|
|
border-color: var(--rpg-highlight);
|
|
color: var(--rpg-highlight);
|
|
}
|
|
|
|
/* Storage locations theming */
|
|
.rpg-panel[data-theme] .rpg-storage-location {
|
|
border-color: var(--rpg-border);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-storage-header {
|
|
background: var(--rpg-highlight);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-storage-content {
|
|
background: var(--rpg-accent);
|
|
}
|
|
|
|
/* Button theming */
|
|
.rpg-panel[data-theme] .rpg-inventory-edit-btn,
|
|
.rpg-panel[data-theme] .rpg-inventory-add-btn,
|
|
.rpg-panel[data-theme] .rpg-inventory-remove-btn,
|
|
.rpg-panel[data-theme] .rpg-quest-edit,
|
|
.rpg-panel[data-theme] .rpg-quest-remove,
|
|
.rpg-panel[data-theme] .rpg-add-quest-btn {
|
|
background: var(--rpg-accent);
|
|
border-color: var(--rpg-border);
|
|
color: var(--rpg-text);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-inventory-add-btn,
|
|
.rpg-panel[data-theme] .rpg-add-quest-btn {
|
|
background: transparent;
|
|
border-color: var(--rpg-highlight);
|
|
color: var(--rpg-highlight);
|
|
}
|
|
|
|
/* Inventory/quest items theming */
|
|
.rpg-panel[data-theme] .rpg-inventory-text,
|
|
.rpg-panel[data-theme] .rpg-quest-item,
|
|
.rpg-panel[data-theme] .rpg-main-quest-display {
|
|
background: var(--rpg-accent);
|
|
border-color: var(--rpg-border);
|
|
color: var(--rpg-text);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-quest-item:hover {
|
|
border-color: var(--rpg-highlight);
|
|
}
|
|
|
|
/* Hints and empty states theming */
|
|
.rpg-panel[data-theme] .rpg-inventory-hint,
|
|
.rpg-panel[data-theme] .rpg-quest-hint,
|
|
.rpg-panel[data-theme] .rpg-inventory-empty,
|
|
.rpg-panel[data-theme] .rpg-quest-empty {
|
|
border-color: var(--rpg-highlight);
|
|
color: var(--rpg-text);
|
|
}
|
|
|
|
/* Input fields theming */
|
|
.rpg-panel[data-theme] .rpg-inline-input,
|
|
.rpg-panel[data-theme] .rpg-quest-edit-form input,
|
|
.rpg-panel[data-theme] .rpg-quest-edit-form textarea {
|
|
background: var(--rpg-bg);
|
|
border-color: var(--rpg-border);
|
|
color: var(--rpg-text);
|
|
}
|
|
|
|
.rpg-panel[data-theme] .rpg-inline-input:focus,
|
|
.rpg-panel[data-theme] .rpg-quest-edit-form input:focus,
|
|
.rpg-panel[data-theme] .rpg-quest-edit-form textarea:focus {
|
|
border-color: var(--rpg-highlight);
|
|
}
|