MosswartOverlord/static/style.css

1454 lines
29 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* style.css - Core styles for Dereth Tracker Single-Page Application
*
* Defines CSS variables for theming, layout rules for sidebar and map,
* interactive element styling (buttons, inputs), and responsive considerations.
*/
/* CSS Custom Properties for theme colors and sizing */
:root {
--sidebar-width: 340px;
--bg-main: #111;
--bg-side: #1a1a1a;
--card: #222;
--card-hov:#333;
--text: #eee;
--accent: #88f;
}
/*
* style.css - Styling for Dereth Tracker SPA frontend.
* Defines layout, theming variables, and component styles (sidebar, map, controls).
*/
/* Placeholder text in chat input should be white */
.chat-input::placeholder {
color: #fff;
opacity: 0.7;
}
html {
margin: 0;
height: 100%;
width: 100%;
}
body {
margin: 0;
height: 100%;
display: flex;
overflow: hidden;
font-family: "Segoe UI", sans-serif;
background: var(--bg-main);
color: var(--text);
position: relative;
}
.sort-buttons {
/* Container for sorting controls; uses flex layout to distribute buttons equally */
display: flex;
gap: 2px;
margin: 12px 16px 8px;
}
.sort-buttons .btn {
/* Compact styling for sort buttons to fit 6 options */
flex: 1;
padding: 4px 6px;
background: #333;
color: #ccc;
border: 1px solid #666;
border-radius: 3px;
text-align: center;
cursor: pointer;
user-select: none;
font-size: 0.75rem;
font-weight: 500;
transition: all 0.15s;
min-width: 0;
white-space: nowrap;
overflow: hidden;
}
.sort-buttons .btn:hover {
background: #444;
color: #fff;
border-color: #777;
}
.sort-buttons .btn.active {
/* Active sort button highlighted with accent color */
background: var(--accent);
color: #111;
border-color: var(--accent);
position: relative;
}
.sort-buttons .btn.active:hover {
background: var(--accent);
color: #111;
}
/* Sort direction indicators */
.sort-buttons .btn.active::after {
content: '';
position: absolute;
top: 2px;
right: 2px;
width: 0;
height: 0;
border-left: 3px solid transparent;
border-right: 3px solid transparent;
}
/* Most sorts are descending (down arrow) */
.sort-buttons .btn.active::after {
border-top: 4px solid #111;
}
/* Name and KPR are ascending (up arrow) */
.sort-buttons .btn.active[data-value="name"]::after,
.sort-buttons .btn.active[data-value="kpr"]::after {
border-top: none;
border-bottom: 4px solid #111;
}
/* ---------- sidebar --------------------------------------------- */
#sidebar {
width: var(--sidebar-width);
scrollbar-width: none;
background: var(--bg-side);
border-right: 2px solid #333;
box-sizing: border-box;
padding: 18px 16px;
overflow-y: auto;
}
#sidebar h2 {
margin: 8px 0 12px;
font-size: 1.25rem;
color: var(--accent);
}
.total-rares-counter {
margin: 0 0 12px 0;
padding: 8px 12px;
background: linear-gradient(135deg, #2a2a2a, #1a1a1a);
border: 1px solid #444;
border-radius: 6px;
font-size: 0.95rem;
font-weight: 600;
color: #ffd700;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.total-rares-counter #totalRaresCount {
color: #fff;
margin-left: 4px;
}
.server-kph-counter {
margin: 0 0 12px 0;
padding: 9px 12px;
background: linear-gradient(135deg, #2a2a44, #1a1a33);
border: 2px solid #4466aa;
border-radius: 6px;
font-size: 1rem;
font-weight: 600;
color: #aaccff;
text-align: center;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
position: relative;
animation: kph-border-glow 4s ease-in-out infinite;
}
@keyframes kph-border-glow {
0%, 100% { border-color: #4466aa; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4); }
50% { border-color: #6688cc; box-shadow: 0 3px 12px rgba(102, 136, 204, 0.3); }
}
.server-kph-counter #serverKphCount {
color: #fff;
margin-left: 4px;
font-size: 1.1rem;
font-weight: 700;
text-shadow: 0 0 8px rgba(255, 255, 255, 0.3);
animation: kph-pulse 3s ease-in-out infinite;
}
@keyframes kph-pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.02); }
}
/* ULTRA MODE for KPH > 5000 */
.server-kph-counter.ultra-epic {
background: linear-gradient(135deg, #6644ff, #4422cc, #6644ff);
background-size: 200% 200%;
animation: kph-border-glow 4s ease-in-out infinite, ultra-background 3s ease-in-out infinite;
border-color: #8866ff;
color: #eeeeff;
box-shadow: 0 4px 12px rgba(102, 68, 255, 0.5);
}
@keyframes ultra-background {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.server-kph-counter.ultra-epic #serverKphCount {
font-size: 1.3rem;
color: #ffffff;
text-shadow: 0 0 12px rgba(255, 255, 255, 0.7);
animation: kph-pulse 3s ease-in-out infinite, ultra-glow 2s ease-in-out infinite alternate;
}
@keyframes ultra-glow {
from { text-shadow: 0 0 12px rgba(255, 255, 255, 0.7); }
to { text-shadow: 0 0 18px rgba(255, 255, 255, 0.9), 0 0 25px rgba(136, 102, 255, 0.5); }
}
/* Server Status Styling */
.server-status-container {
margin: 0 0 16px 0;
padding: 12px;
background: linear-gradient(135deg, #2a4a2a, #1a3a1a);
border: 2px solid #44aa44;
border-radius: 8px;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
}
.server-status-container h3 {
margin: 0 0 10px 0;
font-size: 1.1rem;
color: #aaffaa;
text-align: center;
font-weight: 600;
}
.status-indicator {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 8px;
font-weight: 600;
font-size: 1rem;
}
.status-dot {
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 8px;
box-shadow: 0 0 6px rgba(0, 0, 0, 0.3);
}
.status-dot.status-up {
background-color: #44ff44;
box-shadow: 0 0 8px rgba(68, 255, 68, 0.6);
animation: status-pulse-up 2s ease-in-out infinite;
}
.status-dot.status-down {
background-color: #ff4444;
box-shadow: 0 0 8px rgba(255, 68, 68, 0.6);
animation: status-pulse-down 2s ease-in-out infinite;
}
.status-dot.status-unknown,
.status-dot.status-error {
background-color: #ffaa44;
box-shadow: 0 0 8px rgba(255, 170, 68, 0.6);
}
@keyframes status-pulse-up {
0%, 100% {
box-shadow: 0 0 8px rgba(68, 255, 68, 0.6);
}
50% {
box-shadow: 0 0 16px rgba(68, 255, 68, 0.9);
}
}
@keyframes status-pulse-down {
0%, 100% {
box-shadow: 0 0 8px rgba(255, 68, 68, 0.6);
}
50% {
box-shadow: 0 0 16px rgba(255, 68, 68, 0.9);
}
}
.status-details {
font-size: 0.85rem;
color: #ccc;
line-height: 1.6;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px 16px;
}
.status-details div {
display: flex;
align-items: center;
white-space: nowrap;
}
.status-details span {
color: #fff;
font-weight: 500;
margin-left: 6px;
}
.total-kills-counter {
margin: 0 0 12px 0;
padding: 8px 12px;
background: linear-gradient(135deg, #2a2a2a, #1a1a1a);
border: 1px solid #555;
border-radius: 6px;
font-size: 0.95rem;
font-weight: 600;
color: #ff6666;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.total-kills-counter #totalKillsCount {
color: #fff;
margin-left: 4px;
}
#playerList {
list-style: none;
margin: 0;
padding: 0;
}
/* Filter input in sidebar for player list */
.player-filter {
width: 100%;
padding: 6px 8px;
margin-bottom: 12px;
background: var(--card);
color: var(--text);
border: 1px solid #555;
border-radius: 4px;
font-size: 0.9rem;
box-sizing: border-box;
}
#playerList li {
margin: 4px 0;
padding: 6px 8px;
background: var(--card);
border-left: 4px solid #555;
cursor: pointer;
}
#playerList li:hover {
background: var(--card-hov);
}
#playerList li.selected {
background: #454545;
}
/* ---------- map container --------------------------------------- */
#mapContainer {
flex: 1;
min-width: 0;
min-height: 0;
position: relative;
overflow: hidden;
background: #000;
cursor: grab;
}
#mapContainer.dragging {
cursor: grabbing;
}
#mapGroup {
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
}
#map {
display: block;
user-select: none;
pointer-events: none;
}
/* ---------- dots ------------------------------------------------ */
#dots {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
.dot {
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
border: 1px solid #000;
transform: translate(-50%, -50%);
/* enable events on each dot */
pointer-events: auto;
cursor: pointer;
}
.dot.highlight {
width: 10px;
height: 10px;
animation: blink 0.6s step-end infinite;
}
@keyframes blink {
50% { opacity: 0; }
}
/* ---------- tooltip --------------------------------------------- */
.tooltip {
position: absolute;
display: none;
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.8rem;
pointer-events: none;
white-space: nowrap;
z-index: 1000;
}
/* ---------- coordinate display ---------------------------------- */
.coordinates {
position: absolute;
display: none;
background: rgba(0, 50, 100, 0.9);
color: #fff;
padding: 3px 6px;
border-radius: 3px;
font-size: 0.75rem;
font-family: monospace;
pointer-events: none;
white-space: nowrap;
z-index: 999;
border: 1px solid rgba(100, 150, 200, 0.5);
}
/* make each row a flex container */
/* 2-column flex layout for each player row */
/* make each row a flex container */
/* make each row a vertical stack */
/* make each player row into a 3×2 grid */
#playerList li {
display: grid;
grid-template-columns: 1fr auto auto auto auto auto;
grid-template-rows: auto auto auto auto auto;
grid-template-areas:
"name name name name name name"
"vitals vitals vitals vitals vitals vitals"
"kills totalkills kph kph kph kph"
"rares kpr meta meta meta meta"
"onlinetime deaths tapers tapers tapers tapers";
gap: 4px 8px;
margin: 6px 0;
padding: 8px 10px;
background: var(--card);
border-left: 4px solid transparent;
transition: none;
font-size: 0.85rem;
}
/* assign each span into its grid cell */
.player-name { grid-area: name; font-weight: 600; color: var(--text); }
.coordinates-inline { font-size: 0.75rem; color: #aaa; font-weight: 400; margin-left: 8px; }
.stat.kills { grid-area: kills; }
.stat.total-kills { grid-area: totalkills; }
.stat.kph { grid-area: kph; }
.stat.rares { grid-area: rares; }
.stat.kpr { grid-area: kpr; }
.stat.meta { grid-area: meta; }
.stat.onlinetime { grid-area: onlinetime; }
.stat.deaths { grid-area: deaths; }
.stat.tapers { grid-area: tapers; }
.player-vitals { grid-area: vitals; }
/* pill styling */
#playerList li .stat {
background: rgba(255,255,255,0.1);
padding: 4px 8px;
border-radius: 12px;
display: inline-block;
font-size: 0.75rem;
white-space: nowrap;
color: var(--text);
}
/* icons & suffixes */
.stat.kills::before { content: "⚔️ "; }
.stat.total-kills::before { content: "🏆 "; }
.stat.kph::after { content: " KPH"; font-size:0.7em; color:#aaa; }
.stat.rares::before { content: "💎 "; }
.stat.rares::after { content: " Rares"; font-size:0.7em; color:#aaa; }
.stat.kpr::before { content: "📊 "; }
.stat.kpr::after { content: " KPR"; font-size:0.7em; color:#aaa; }
/* metastate pill colors are assigned dynamically: green for “good” states, red otherwise */
#playerList li .stat.meta {
/* fallback */
background: var(--accent);
color: #111;
}
#playerList li .stat.meta.green {
background: #2ecc71; /* pleasant green */
color: #111;
}
#playerList li .stat.meta.red {
background: #e74c3c; /* vivid red */
color: #fff;
}
/* ---------- chat window styling ------------------------------- */
.chat-btn, .stats-btn, .inventory-btn {
margin-top: 4px;
padding: 2px 6px;
background: var(--accent);
color: #111;
border: none;
border-radius: 3px;
font-size: 0.75rem;
cursor: pointer;
}
.chat-window, .stats-window, .inventory-window {
position: absolute;
top: 10px;
/* position window to start just right of the sidebar */
left: calc(var(--sidebar-width) + 10px);
/* increase default size for better usability */
width: 760px; /* increased width for larger terminal area */
height: 300px;
background: var(--card);
border: 1px solid #555;
display: flex;
flex-direction: column;
z-index: 10000;
}
.chat-header {
display: flex;
justify-content: space-between;
align-items: center;
background: var(--accent);
padding: 4px;
color: #111;
cursor: move; /* indicates the header is draggable */
}
.chat-close-btn {
background: transparent;
border: none;
font-size: 1.2rem;
line-height: 1;
cursor: pointer;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 4px;
font-size: 0.85rem;
color: #fff;
/* reserve space so messages aren't hidden behind the input */
padding-bottom: 40px;
}
.chat-form {
display: flex;
border-top: 1px solid #333;
/* fix input area to the bottom of the chat window */
position: absolute;
left: 0;
right: 0;
bottom: 0;
background: #333;
z-index: 10;
}
.chat-input {
flex: 1;
padding: 4px 6px;
border: none;
background: #333;
color: #fff;
outline: none;
}
/* Prevent text selection while dragging chat windows */
body.noselect, body.noselect * {
user-select: none !important;
}
.stat.onlinetime::before { content: "🕑 "}
.stat.deaths::before { content: "💀 "}
.stat.tapers::before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
background-image: url('prismatic-taper-icon.png');
background-size: contain;
background-repeat: no-repeat;
margin-right: 4px;
vertical-align: text-bottom;
}
/* hover & selected states */
#playerList li:hover { background: var(--card-hov); }
#playerList li.selected { background: #454545; }
/* trails paths */
#trails {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
.trail-path {
fill: none;
stroke-width: 2px;
stroke-opacity: 0.7;
stroke-linecap: round;
stroke-linejoin: round;
}
/* -------------------------------------------------------- */
/* Stats window: 2×2 iframe grid and flexible height */
.stats-window {
/* allow height to expand to fit two rows of panels */
height: auto;
}
.stats-window .chat-messages {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: auto;
gap: 10px;
padding: 10px;
overflow: visible;
background: #f7f7f7;
color: #000;
}
.stats-window iframe {
width: 350px;
height: 200px;
border: none;
}
/* ---------- stats window time controls --------------------------- */
.stats-controls {
display: flex;
gap: 8px;
padding: 10px 15px;
background: #333;
border-bottom: 1px solid #555;
}
.time-range-btn {
padding: 6px 12px;
background: #444;
color: #ccc;
border: 1px solid #666;
border-radius: 4px;
font-size: 0.85rem;
cursor: pointer;
transition: all 0.2s;
}
.time-range-btn:hover {
background: #555;
color: #fff;
}
.time-range-btn.active {
background: var(--accent);
color: #111;
border-color: var(--accent);
}
/* ---------- inventory window styling ----------------------------- */
.inventory-content {
flex: 1;
padding: 15px;
background: var(--card);
color: var(--text);
overflow-y: auto;
}
.inventory-placeholder {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 1.1rem;
color: #888;
font-style: italic;
}
/* Inventory window specific styles */
.inventory-window {
position: fixed;
top: 100px;
left: 400px;
width: 600px;
height: 500px;
background: var(--card);
border: 1px solid #555;
border-radius: 8px;
display: flex;
flex-direction: column;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
z-index: 1000;
}
.inventory-loading {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 1.1rem;
color: #888;
}
/* Inventory grid layout - matches AC original */
.inventory-grid {
display: grid;
grid-template-columns: repeat(8, 36px);
gap: 0px;
padding: 8px;
background:
linear-gradient(90deg, #333 1px, transparent 1px),
linear-gradient(180deg, #333 1px, transparent 1px),
#111;
background-size: 36px 36px;
max-height: 450px;
overflow-y: auto;
border: 1px solid #444;
}
/* Individual inventory slots - no borders like AC original */
.inventory-slot {
width: 36px;
height: 36px;
background: transparent;
border: none;
border-radius: 0;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background 0.1s ease;
padding: 0;
margin: 0;
}
.inventory-slot:hover {
background: rgba(136, 136, 255, 0.3);
}
.inventory-icon {
width: 36px;
height: 36px;
object-fit: contain;
image-rendering: pixelated;
/* Improve icon appearance - make background match slot */
border: none;
outline: none;
background: #1a1a1a;
border-radius: 2px;
}
/* Icon compositing for overlays/underlays - matches AC original */
.item-icon-composite {
position: relative;
width: 36px;
height: 36px;
display: block;
background: transparent;
padding: 0;
margin: 0;
}
.icon-underlay,
.icon-base,
.icon-overlay {
position: absolute;
top: 0;
left: 0;
width: 36px;
height: 36px;
border: none;
outline: none;
background: transparent;
padding: 0;
margin: 0;
}
.icon-underlay {
z-index: 1;
}
.icon-base {
z-index: 2;
}
.icon-overlay {
z-index: 3;
}
/* Item count */
.inventory-count {
text-align: center;
padding: 10px;
color: #888;
font-size: 0.9rem;
}
/* Inventory tooltip */
.inventory-tooltip {
position: fixed;
background: rgba(0, 0, 0, 0.95);
border: 1px solid #555;
border-radius: 4px;
padding: 10px;
pointer-events: none;
z-index: 20000;
display: none;
min-width: 200px;
max-width: 350px;
font-size: 0.9rem;
}
.tooltip-name {
font-weight: bold;
color: var(--accent);
margin-bottom: 8px;
font-size: 1rem;
}
.tooltip-section {
margin-bottom: 6px;
}
.tooltip-section-title {
font-weight: bold;
color: #ffd700;
margin-bottom: 3px;
font-size: 0.85rem;
text-transform: uppercase;
}
.tooltip-stats {
display: flex;
flex-direction: column;
gap: 3px;
font-size: 0.9rem;
}
.tooltip-stat,
.tooltip-requirement,
.tooltip-property {
color: #ddd;
font-size: 0.85rem;
margin-left: 8px;
}
.tooltip-requirement {
color: #ffaa00;
}
.tooltip-property {
color: #88ff88;
}
.tooltip-string {
color: #add8e6;
font-size: 0.8rem;
margin-left: 8px;
}
.tooltip-spell {
color: #dda0dd;
font-size: 0.8rem;
margin-left: 8px;
margin-bottom: 2px;
}
.spell-name {
color: #4a90e2;
font-weight: 500;
}
.spell-school {
font-size: 11px;
color: #888;
font-style: italic;
}
.tooltip-info {
color: #f0e68c;
font-size: 0.8rem;
margin-left: 8px;
}
.tooltip-description {
color: #ccc;
font-style: italic;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #444;
}
.tooltip-value {
color: #4CAF50;
}
.tooltip-burden {
color: #FFC107;
}
.tooltip-source {
font-size: 10px;
color: #888;
margin-top: 4px;
text-align: center;
}
/* ---------- inline vitals bars ---------------------------------- */
.player-vitals {
grid-column: 1 / -1;
margin: 2px 0 4px 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.vital-bar-inline {
height: 5px;
background: #222;
border-radius: 3px;
overflow: hidden;
position: relative;
}
.vitae-indicator {
font-size: 0.75rem;
color: #ff6666;
margin-left: 8px;
font-weight: 500;
}
.vital-fill {
height: 100%;
transition: width 0.3s ease-out;
border-radius: 2px;
}
.vital-fill.health {
background: linear-gradient(90deg, #ff4444, #ff6666);
}
.vital-fill.stamina {
background: linear-gradient(90deg, #ffaa00, #ffcc44);
}
.vital-fill.mana {
background: linear-gradient(90deg, #4488ff, #66aaff);
}
/* Pulsing effects for low vitals */
.vital-bar-inline.low-vital {
animation: pulse-bar-low 2s ease-in-out infinite;
}
.vital-bar-inline.critical-vital {
animation: pulse-bar-critical 1s ease-in-out infinite;
}
@keyframes pulse-bar-low {
0%, 100% { background: #222; }
50% { background: #332200; }
}
@keyframes pulse-bar-critical {
0%, 100% { background: #222; }
50% { background: #440000; }
}
/* ---------- epic rare notifications ------------------------------ */
.rare-notifications {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 10001;
pointer-events: none;
}
.rare-notification {
background: linear-gradient(135deg, #ffd700, #ffed4e, #ffd700);
border: 3px solid #ff6600;
border-radius: 12px;
padding: 20px 30px;
margin-bottom: 10px;
text-align: center;
box-shadow: 0 8px 32px rgba(255, 215, 0, 0.5);
animation: notification-slide-in 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55),
epic-glow 2s ease-in-out infinite;
position: relative;
overflow: hidden;
}
@keyframes notification-slide-in {
from {
transform: translateY(-100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes epic-glow {
0%, 100% {
box-shadow: 0 8px 32px rgba(255, 215, 0, 0.5);
}
50% {
box-shadow: 0 8px 48px rgba(255, 215, 0, 0.8);
}
}
.rare-notification-title {
font-size: 1.2rem;
font-weight: 800;
color: #ff0044;
text-transform: uppercase;
margin-bottom: 8px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
animation: epic-text-pulse 1s ease-in-out infinite;
}
@keyframes epic-text-pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.rare-notification-mob {
font-size: 1.5rem;
font-weight: 700;
color: #1a0033;
margin-bottom: 4px;
text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.5);
}
.rare-notification-finder {
font-size: 1rem;
color: #333;
font-style: italic;
margin-bottom: 4px;
}
.rare-notification-character {
font-size: 1.3rem;
font-weight: 700;
color: #ff0044;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
/* Shine effect overlay */
.rare-notification::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(45deg,
transparent 30%,
rgba(255, 255, 255, 0.5) 50%,
transparent 70%
);
transform: rotate(45deg);
animation: notification-shine 3s infinite;
}
@keyframes notification-shine {
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); }
100% { transform: translateX(100%) translateY(100%) rotate(45deg); }
}
/* ---------- fireworks particles ---------------------------------- */
.fireworks-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 9999;
}
.firework-particle {
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
pointer-events: none;
animation: firework-fly 2s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
}
@keyframes firework-fly {
0% {
transform: translate(0, 0) scale(1);
opacity: 1;
}
100% {
opacity: 0;
}
}
/* Different particle colors */
.particle-gold { background: #ffd700; box-shadow: 0 0 6px #ffd700; }
.particle-red { background: #ff4444; box-shadow: 0 0 6px #ff4444; }
.particle-orange { background: #ff8800; box-shadow: 0 0 6px #ff8800; }
.particle-purple { background: #cc00ff; box-shadow: 0 0 6px #cc00ff; }
.particle-blue { background: #00ccff; box-shadow: 0 0 6px #00ccff; }
/* Character glow effect in player list */
.player-item.rare-finder-glow {
animation: rare-finder-highlight 5s ease-in-out;
border-left-color: #ffd700 !important;
border-left-width: 6px !important;
}
@keyframes rare-finder-highlight {
0%, 100% {
background: var(--card);
box-shadow: none;
}
50% {
background: rgba(255, 215, 0, 0.2);
box-shadow: 0 0 20px rgba(255, 215, 0, 0.5);
}
}
/* ---------- milestone celebration overlay ------------------------ */
.milestone-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(ellipse at center, rgba(255, 215, 0, 0.3), rgba(0, 0, 0, 0.8));
z-index: 20000;
display: flex;
align-items: center;
justify-content: center;
animation: milestone-fade-in 0.5s ease-out;
}
@keyframes milestone-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.milestone-content {
text-align: center;
animation: milestone-zoom 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
@keyframes milestone-zoom {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}
.milestone-number {
font-size: 8rem;
font-weight: 900;
color: #ffd700;
text-shadow:
0 0 30px #ffd700,
0 0 60px #ff6600,
0 0 90px #ff0044,
0 0 120px #ff0044;
margin-bottom: 20px;
animation: milestone-pulse 1s ease-in-out infinite alternate;
}
@keyframes milestone-pulse {
from {
transform: scale(1);
text-shadow:
0 0 30px #ffd700,
0 0 60px #ff6600,
0 0 90px #ff0044,
0 0 120px #ff0044;
}
to {
transform: scale(1.1);
text-shadow:
0 0 40px #ffd700,
0 0 80px #ff6600,
0 0 120px #ff0044,
0 0 160px #ff0044;
}
}
.milestone-text {
font-size: 3rem;
font-weight: 700;
color: #fff;
text-transform: uppercase;
letter-spacing: 0.2em;
text-shadow: 0 0 20px rgba(255, 255, 255, 0.8);
animation: milestone-text-glow 2s ease-in-out infinite;
}
@keyframes milestone-text-glow {
0%, 100% {
opacity: 0.8;
}
50% {
opacity: 1;
}
}
.milestone-subtitle {
font-size: 1.5rem;
color: #ffcc00;
margin-top: 20px;
font-style: italic;
animation: milestone-subtitle-slide 1s ease-out;
}
@keyframes milestone-subtitle-slide {
from {
transform: translateY(50px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
/* Milestone firework burst - larger particles */
.milestone-particle {
position: absolute;
width: 12px;
height: 12px;
border-radius: 50%;
pointer-events: none;
background: #ffd700;
box-shadow: 0 0 12px #ffd700;
}
/* Screen shake effect */
@keyframes screen-shake {
0%, 100% { transform: translate(0, 0); }
10% { transform: translate(-5px, -5px); }
20% { transform: translate(5px, -5px); }
30% { transform: translate(-5px, 5px); }
40% { transform: translate(5px, 5px); }
50% { transform: translate(-3px, -3px); }
60% { transform: translate(3px, -3px); }
70% { transform: translate(-3px, 3px); }
80% { transform: translate(3px, 3px); }
90% { transform: translate(-1px, -1px); }
}
.screen-shake {
animation: screen-shake 0.5s ease-in-out;
}
/* ---------- Heat Map Canvas Layer ---------- */
#heatmapCanvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0.85;
mix-blend-mode: screen; /* Additive blending for nice heat map effect */
}
/* Trails and dots use default positioning - no changes needed for layering */
/* Heat map toggle styling */
.heatmap-toggle {
margin: 0 0 12px;
padding: 6px 12px;
background: var(--card);
border: 1px solid var(--accent);
border-radius: 4px;
font-size: 0.9rem;
}
.heatmap-toggle input {
margin-right: 8px;
cursor: pointer;
}
.heatmap-toggle label {
cursor: pointer;
user-select: none;
}
/* Inventory search link styling */
.inventory-search-link {
margin: 0 0 12px;
padding: 8px 12px;
background: var(--card);
border: 1px solid #4a9eff;
border-radius: 4px;
text-align: center;
}
.inventory-search-link a {
color: #4a9eff;
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
display: block;
cursor: pointer;
user-select: none;
transition: all 0.2s ease;
}
.inventory-search-link a:hover {
color: #fff;
background: rgba(74, 158, 255, 0.1);
border-radius: 2px;
padding: 2px 4px;
margin: -2px -4px;
}
.suitbuilder-link {
margin: 0 0 12px;
padding: 8px 12px;
background: var(--card);
border: 1px solid #ff6b4a;
border-radius: 4px;
text-align: center;
}
.suitbuilder-link a {
color: #ff6b4a;
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
display: block;
cursor: pointer;
user-select: none;
transition: all 0.2s ease;
}
.suitbuilder-link a:hover {
color: #fff;
background: rgba(255, 107, 74, 0.1);
border-radius: 2px;
padding: 2px 4px;
margin: -2px -4px;
}
.debug-link {
margin: 0 0 12px;
padding: 8px 12px;
background: var(--card);
border: 1px solid #4aff6b;
border-radius: 4px;
text-align: center;
}
.debug-link a {
color: #4aff6b;
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
display: block;
cursor: pointer;
user-select: none;
transition: all 0.2s ease;
}
.debug-link a:hover {
color: #fff;
background: rgba(74, 255, 107, 0.1);
border-radius: 2px;
padding: 2px 4px;
margin: -2px -4px;
}
/* Sortable column styles for inventory tables */
.sortable {
cursor: pointer;
user-select: none;
position: relative;
padding-right: 20px \!important;
}
.sortable:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.results-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.results-table th,
.results-table td {
padding: 8px 12px;
border-bottom: 1px solid #333;
text-align: left;
}
.results-table th {
background-color: #222;
font-weight: bold;
color: #eee;
}
.results-table tr:hover {
background-color: rgba(255, 255, 255, 0.05);
}
.text-right {
text-align: right \!important;
}
.results-info {
margin-bottom: 10px;
color: #ccc;
font-size: 14px;
}
/* Spell/Cantrip column styling */
.spells-cell {
font-size: 10px;
line-height: 1.2;
max-width: 200px;
word-wrap: break-word;
vertical-align: top;
}
.legendary-cantrip {
color: #ffd700;
font-weight: bold;
}
.regular-spell {
color: #88ccff;
}