Files
mc-webui/app/static/css/style.css
T
MarekWo d8d3427dc9 feat(pathanalyzer): chat route click opens the analyzer map deep-linked
Clicking a route in the chat path popup now opens Path Analyzer on the
Map view with that message selected and that exact echo path drawn,
instead of copying the route to the clipboard. Copy stays available as
a small per-route clipboard icon in the popup.

Deep link flow: popup click stores {packet_hash, path hex} in
window.paDeepLink; the modal show handler builds the iframe URL with
?hash=&path=; the analyzer resolves the message after load (widening
the time range once to 7 days if needed), matches the echo by raw path
hex (fallback: shortest), and switches to the map. A plain menu open
still loads the analyzer without any deep link.

Verified live via Playwright: clicked the 3rd (non-shortest) route of a
multi-route message - the map opened with exactly that echo selected,
including the 3-to-7-day widening retry (message was 4 days old).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 07:10:31 +02:00

2279 lines
48 KiB
CSS

/* mc-webui Custom Styles */
/* Colors are defined as CSS custom properties in theme.css */
/* Page Layout */
html, body {
height: 100vh; /* Fallback for older browsers */
height: 100dvh; /* Dynamic viewport height (mobile-friendly) */
margin: 0;
overflow: hidden;
}
body {
display: flex;
flex-direction: column;
background-color: var(--bg-body);
color: var(--text-primary);
}
main {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 0; /* Important for flex children */
}
/* =============================================================================
Channel Sidebar (Group Chat) - visible on lg+ screens
============================================================================= */
.channel-sidebar {
display: none;
width: 250px;
flex-shrink: 0;
border-right: 1px solid var(--border-color);
background: var(--bg-surface);
flex-direction: column;
}
.channel-sidebar-header {
padding: 0.6rem 0.75rem;
font-weight: 600;
font-size: 0.85rem;
border-bottom: 1px solid var(--border-color);
color: var(--text-secondary);
background: var(--bg-surface-alt);
}
.channel-sidebar-list {
overflow-y: auto;
flex: 1;
}
.channel-sidebar-item {
padding: 0.45rem 0.75rem;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 0;
border-bottom: 1px solid var(--border-light);
font-size: 0.85rem;
transition: background-color 0.15s;
color: var(--text-primary);
}
/* Top row: name + time + unread badge */
.channel-item-top {
display: flex;
align-items: center;
gap: 0.35rem;
min-width: 0;
}
.channel-last-time {
font-size: 0.72rem;
color: var(--text-muted);
white-space: nowrap;
flex-shrink: 0;
}
.channel-item-preview {
font-size: 0.72rem;
color: var(--text-muted);
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-height: 1.3;
margin-top: 0.1rem;
word-break: break-word;
}
.channel-selector-item .channel-item-preview {
-webkit-line-clamp: 1;
}
.channel-sidebar-item:hover {
background-color: var(--bg-hover);
}
.channel-sidebar-item.active {
background-color: var(--bg-active);
border-left: 3px solid var(--sender-color);
padding-left: calc(0.75rem - 3px);
font-weight: 500;
color: var(--sender-color);
}
.channel-sidebar-item.muted {
opacity: 0.5;
}
.channel-sidebar-item .channel-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.channel-sidebar-item .sidebar-unread-badge {
background-color: var(--sender-color);
color: white;
border-radius: 10px;
padding: 1px 6px;
font-size: 0.7rem;
font-weight: bold;
min-width: 18px;
text-align: center;
flex-shrink: 0;
}
/* Show sidebar and hide dropdown on wide screens (toggled by JS via .layout-wide on <html>) */
.layout-wide .channel-sidebar {
display: flex;
}
.layout-wide #channelSelectorWrapper {
display: none !important;
}
/* Channel Selector Dropdown (base.html navbar, narrow screens) */
.channel-selector-dropdown {
position: absolute;
top: 100%;
right: 0;
min-width: 200px;
z-index: 1050;
max-height: 60vh;
overflow-y: auto;
background: var(--dropdown-bg);
border: 1px solid var(--border-color);
border-radius: 0.375rem;
box-shadow: var(--popup-shadow);
}
.channel-selector-item {
padding: 0.45rem 0.75rem;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 0;
border-bottom: 1px solid var(--border-light);
font-size: 0.88rem;
font-weight: 400;
}
.channel-selector-item:hover,
.channel-selector-item.active {
background-color: var(--dropdown-item-hover);
}
.channel-selector-item.muted {
opacity: 0.5;
}
.channel-selector-item .channel-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* =============================================================================
DM Sidebar (Direct Messages) - visible on lg+ screens
============================================================================= */
.dm-sidebar {
display: none;
width: 280px;
flex-shrink: 0;
border-right: 1px solid var(--border-color);
background: var(--bg-surface);
flex-direction: column;
}
.dm-sidebar-header {
padding: 0.5rem;
border-bottom: 1px solid var(--border-color);
background: var(--bg-surface-alt);
}
.dm-sidebar-list {
overflow-y: auto;
flex: 1;
}
.dm-sidebar-separator {
padding: 0.25rem 0.75rem;
font-size: 0.7rem;
color: var(--text-muted);
background: var(--bg-surface-alt);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
}
.dm-sidebar-item {
padding: 0.5rem 0.75rem;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid var(--border-light);
font-size: 0.85rem;
transition: background-color 0.15s;
}
.dm-sidebar-item:hover {
background-color: var(--bg-hover);
}
.dm-sidebar-item.active {
background-color: #e7f5ee;
border-left: 3px solid #198754;
padding-left: calc(0.75rem - 3px);
font-weight: 500;
}
[data-theme="dark"] .dm-sidebar-item.active {
background-color: rgba(16, 185, 129, 0.15);
border-left-color: #10b981;
}
.dm-sidebar-item .contact-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.88rem;
font-weight: 400;
}
.dm-sidebar-item .sidebar-unread-dot {
width: 8px;
height: 8px;
background-color: var(--sender-color);
border-radius: 50%;
flex-shrink: 0;
}
.dm-sidebar-item .badge {
font-size: 0.65rem;
flex-shrink: 0;
}
/* Show DM sidebar and hide mobile selector on wide screens (toggled by JS via .layout-wide on <html>) */
.layout-wide .dm-sidebar {
display: flex;
}
.layout-wide .dm-mobile-selector {
display: none !important;
}
.layout-wide .dm-desktop-header {
display: block !important;
}
.dm-desktop-header {
display: none;
}
/* Messages Container */
.messages-container {
background-color: var(--bg-messages);
padding-left: 0.25rem !important;
padding-right: 0.25rem !important;
}
#messagesList {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
/* =============================================================================
Message Wrapper - New Layout with Avatar
============================================================================= */
/* Message wrapper - contains avatar + message container */
.message-wrapper {
display: flex;
align-items: flex-start;
gap: 0.5rem;
max-width: 85%;
animation: fadeIn 0.3s ease-in;
}
.message-wrapper.own {
align-self: flex-end;
flex-direction: row-reverse;
}
.message-wrapper.other {
align-self: flex-start;
}
/* Avatar circle */
.message-avatar {
flex-shrink: 0;
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.85rem;
font-weight: 600;
color: white;
text-transform: uppercase;
margin-top: 0.1rem;
}
.message-avatar.emoji {
font-size: 1.25rem;
background-color: transparent !important;
border: 1.5px solid;
line-height: 1;
padding-bottom: 1px;
}
/* Message container - holds sender row + bubble + actions */
.message-container {
display: flex;
flex-direction: column;
min-width: 0; /* Allow text truncation */
}
/* Sender row - name and time above bubble */
.message-sender-row {
display: flex;
align-items: baseline;
gap: 0.5rem;
margin-bottom: 0.25rem;
padding-left: 0.25rem;
}
.message-sender {
font-weight: 600;
font-size: 0.875rem;
color: var(--sender-color);
}
.message-sender-row .message-time {
font-size: 0.7rem;
color: var(--text-muted);
}
/* Message footer for own messages (name + time above bubble) */
.message-footer {
display: flex;
align-items: baseline;
padding-right: 0.5rem;
margin-bottom: 0.25rem;
}
.message-footer.own {
justify-content: flex-end;
}
.message-footer .message-time {
font-size: 0.7rem;
color: var(--text-muted);
}
.message-footer .message-sender.own {
font-weight: 600;
font-size: 0.875rem;
color: var(--sender-own-color);
margin-right: 0.5rem;
}
/* Message action buttons container */
.message-actions {
display: flex;
gap: 0.25rem;
margin-top: 0.5rem;
}
/* Message Bubbles */
.message {
padding: 0.75rem 1rem;
border-radius: 1rem;
border: 1px solid var(--msg-border);
word-wrap: break-word;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* Own Messages (right-aligned) */
.message.own {
background-color: var(--msg-own-bg);
border-color: var(--msg-own-border);
}
/* Other Messages (left-aligned) */
.message.other {
background-color: var(--msg-other-bg);
}
.message-time {
font-size: 0.75rem;
color: var(--text-muted);
}
/* Message Content */
.message-content {
margin: 0;
white-space: pre-wrap;
line-height: 1.4;
}
/* Message Metadata */
.message-meta {
font-size: 0.7rem;
color: var(--text-meta);
margin-top: 0.25rem;
}
/* Reply Button */
.btn-reply {
font-size: 0.7rem;
padding: 0.1rem 0.4rem;
margin-top: 0.25rem;
}
/* Send Form */
#messageInput,
#dmMessageInput {
resize: none;
border-radius: 0.5rem 0 0 0.5rem;
}
#sendBtn,
#dmSendBtn {
border-radius: 0 0.5rem 0.5rem 0;
}
/* Status Indicators */
.status-connected {
color: #198754 !important;
}
.status-disconnected {
color: #dc3545 !important;
}
.status-connecting {
color: #ffc107 !important;
}
/* Scrollbar Styling */
.messages-container::-webkit-scrollbar {
width: 8px;
}
.messages-container::-webkit-scrollbar-track {
background: var(--scrollbar-track);
}
.messages-container::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb);
border-radius: 4px;
}
.messages-container::-webkit-scrollbar-thumb:hover {
background: var(--scrollbar-thumb-hover);
}
/* Date selector - larger font size */
#dateSelector {
font-size: 1rem;
}
/* Navbar touch targets - larger for mobile */
.navbar-touch-btn {
min-width: 40px;
min-height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 1.1rem;
padding: 0.35rem 0.6rem;
}
.navbar-touch-select {
min-height: 40px;
font-size: 1rem;
padding: 0.35rem 1.5rem 0.35rem 0.5rem;
}
/* Offcanvas menu styling */
.offcanvas {
width: 300px !important;
}
.offcanvas-body .list-group-item {
padding: 1rem 0.75rem;
border: none;
border-bottom: 1px solid var(--offcanvas-item-border);
font-size: 1rem;
}
.offcanvas-body .list-group-item:hover {
background-color: var(--offcanvas-item-hover);
}
.offcanvas-body .list-group-item i {
color: var(--offcanvas-icon-color);
min-width: 1.5rem;
}
.offcanvas-body .list-group-item span {
font-weight: 500;
}
.offcanvas-body .list-group-item .form-select {
font-size: 1rem;
}
/* Responsive Design */
@media (max-width: 768px) {
.message-wrapper {
max-width: 90%;
}
.message-avatar {
width: 32px;
height: 32px;
font-size: 0.75rem;
}
.message-avatar.emoji {
font-size: 1.1rem;
}
.message-sender {
font-size: 0.8rem;
}
.dm-message-wrapper {
max-width: 85%;
}
#messageInput,
#dmMessageInput {
font-size: 0.9rem;
}
/* Reduce padding on mobile to save vertical space */
#sendMessageForm,
#dmSendForm {
padding: 0.5rem !important;
}
/* Make status bar more compact */
.row.border-top .p-2 {
padding: 0.3rem !important;
font-size: 0.7rem;
}
/* Navbar: Reduce gap between elements */
.navbar .d-flex {
gap: 0.25rem !important;
}
/* Navbar: Force one-row layout (Bootstrap default is flex-wrap: wrap) */
.navbar,
.navbar > .container-fluid {
flex-wrap: nowrap !important;
}
/* Navbar: Shrink brand title and let it truncate if needed */
.navbar-brand.h1 {
font-size: 1rem;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 0.5rem;
}
/* Navbar: Channel selector on mobile */
#channelSelectorInput {
min-width: 0 !important;
width: 100%;
font-size: 0.9rem;
}
/* DM: Contact search input on mobile */
#dmContactSearchInput {
min-width: 100px !important;
font-size: 0.9rem;
}
/* Navbar: Smaller buttons */
.navbar .btn-sm {
padding: 0.25rem 0.4rem;
font-size: 0.875rem;
}
/* Modal: Better mobile layout */
.modal-dialog {
margin: 0.5rem;
}
.modal-body {
padding: 0.75rem;
}
/* Modal: Compact channel list */
.modal .list-group-item {
padding: 0.5rem;
}
}
/* Small phone screens: icon-only buttons in contact cards */
@media (max-width: 428px) {
.pending-contact-card .btn-label,
.existing-contact-card .btn-label {
display: none;
}
.pending-contact-card .d-flex.gap-2,
.existing-contact-card .d-flex.gap-2 {
flex-wrap: wrap;
}
}
/* Loading State */
.loading-spinner {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
/* Spin animation for update check button */
.spin {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Empty State */
.empty-state {
text-align: center;
padding: 3rem 1rem;
color: var(--text-muted);
}
.empty-state i {
font-size: 3rem;
margin-bottom: 1rem;
opacity: 0.5;
}
/* Notification Bell Badge */
.notification-badge {
position: absolute;
top: -8px;
right: -8px;
background-color: #dc3545;
color: white;
border-radius: 10px;
padding: 2px 6px;
font-size: 0.65rem;
font-weight: bold;
line-height: 1;
min-width: 18px;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
z-index: 10;
}
/* Bell Ring Animation */
@keyframes bell-ring {
0% { transform: rotate(0deg); }
10% { transform: rotate(14deg); }
20% { transform: rotate(-8deg); }
30% { transform: rotate(14deg); }
40% { transform: rotate(-4deg); }
50% { transform: rotate(10deg); }
60% { transform: rotate(0deg); }
100% { transform: rotate(0deg); }
}
.bell-ring {
animation: bell-ring 1s ease-in-out;
transform-origin: 50% 4px;
}
/* Notification Bell Container */
#notificationBell {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
}
#notificationBell:hover .notification-badge {
transform: scale(1.1);
transition: transform 0.2s ease;
}
/* =============================================================================
Direct Messages (DM) Styles
============================================================================= */
/* DM Badge on notification bell (secondary badge, bottom-right, green) */
.notification-badge-dm {
position: absolute;
bottom: -6px;
right: -6px;
background-color: #198754;
color: white;
border-radius: 8px;
padding: 1px 4px;
font-size: 0.6rem;
font-weight: bold;
min-width: 14px;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
z-index: 10;
}
/* DM Messages Container */
.dm-messages-container {
height: 50vh;
overflow-y: auto;
padding: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
background-color: var(--bg-dm-messages);
}
/* DM Messages List (flex container for message alignment) */
#dmMessagesList {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
@media (max-width: 576px) {
.dm-messages-container {
height: calc(100vh - 200px);
}
}
/* DM Message Wrapper - timestamp + bubble */
.dm-message-wrapper {
max-width: 70%;
display: flex;
flex-direction: column;
animation: fadeIn 0.3s ease-in;
}
.dm-message-wrapper.own {
align-self: flex-end;
}
.dm-message-wrapper.other {
align-self: flex-start;
}
/* DM Time Row - above bubble */
.dm-time-row {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.7rem;
color: var(--text-muted);
margin-bottom: 0.2rem;
padding: 0 0.25rem;
}
.dm-message-wrapper.own .dm-time-row {
justify-content: flex-end;
}
/* DM Message Bubbles */
.dm-message {
padding: 0.75rem 1rem;
border-radius: 1rem;
word-wrap: break-word;
}
.dm-message.own {
background-color: var(--msg-own-bg);
border: 1px solid var(--msg-own-border);
}
.dm-message.other {
background-color: var(--msg-other-bg);
border: 1px solid var(--msg-border);
}
.dm-content {
margin: 0;
white-space: pre-wrap;
line-height: 1.4;
}
/* DM Message Metadata */
.dm-meta {
font-size: 0.75rem;
color: var(--dm-meta-color);
margin-top: 0.25rem;
}
/* DM Status Indicators */
.dm-status {
font-size: 0.7rem;
margin-left: 0.25rem;
}
.dm-status.pending {
color: #ffc107;
}
.dm-status.delivered {
color: #198754;
}
.dm-status.timeout {
color: #dc3545;
}
.dm-status.unknown {
color: var(--text-meta);
}
.dm-status-unknown {
cursor: pointer;
position: relative;
}
.dm-retry-info:empty {
display: none;
}
.dm-delivery-meta {
font-size: 0.75rem;
color: var(--dm-meta-color);
margin-top: 0.1rem;
}
.dm-route-link {
cursor: pointer;
text-decoration: underline;
text-decoration-style: dotted;
position: relative;
}
.dm-delivery-popup {
position: absolute;
bottom: 100%;
right: 0;
background-color: #333;
color: #fff;
padding: 0.35rem 0.6rem;
border-radius: 0.375rem;
font-size: 0.7rem;
white-space: nowrap;
z-index: 1000;
pointer-events: none;
margin-bottom: 0.25rem;
}
/* DM Action Buttons */
.dm-actions {
display: flex;
justify-content: flex-end;
margin-top: 0.25rem;
}
.dm-action-btn {
padding: 0.15rem 0.4rem;
font-size: 0.75rem;
line-height: 1;
}
/* DM Conversation List Item */
.dm-conversation-item {
padding: 0.75rem;
border-bottom: 1px solid var(--conversation-border);
cursor: pointer;
transition: background-color 0.15s ease;
}
.dm-conversation-item:hover {
background-color: var(--conversation-hover);
}
.dm-conversation-item.unread {
background-color: var(--conversation-unread);
}
.dm-conversation-item:last-child {
border-bottom: none;
}
/* DM Preview Text */
.dm-preview {
font-size: 0.85rem;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
/* DM Button on channel messages - uses same class as Reply (.btn-reply) */
/* DM Empty State */
.dm-empty-state {
text-align: center;
padding: 2rem 1rem;
color: var(--text-muted);
}
.dm-empty-state i {
font-size: 2.5rem;
margin-bottom: 0.75rem;
opacity: 0.5;
}
/* DM Scrollbar */
.dm-messages-container::-webkit-scrollbar {
width: 6px;
}
.dm-messages-container::-webkit-scrollbar-track {
background: var(--scrollbar-track);
}
.dm-messages-container::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb-light);
border-radius: 3px;
}
.dm-messages-container::-webkit-scrollbar-thumb:hover {
background: var(--scrollbar-thumb-light-hover);
}
/* =============================================================================
Message Content Enhancements (Mentions, Links, Images)
============================================================================= */
/* Mention Badge (similar to Android Meshcore app) */
.mention-badge {
display: inline-block;
background-color: var(--mention-bg);
color: white;
padding: 0.15rem 0.5rem;
border-radius: 0.75rem;
font-size: 0.85em;
font-weight: 500;
margin: 0 0.1rem;
white-space: nowrap;
}
.message.own .mention-badge {
background-color: var(--mention-own-bg);
}
/* Channel Links (#channelname) */
.channel-link {
display: inline-block;
background-color: var(--channel-link-bg);
color: white;
padding: 0.15rem 0.5rem;
border-radius: 0.75rem;
font-size: 0.85em;
font-weight: 500;
margin: 0 0.1rem;
white-space: nowrap;
text-decoration: none;
cursor: pointer;
transition: background-color 0.15s ease;
}
.channel-link:hover {
background-color: var(--channel-link-hover);
color: white;
text-decoration: none;
}
.message.own .channel-link {
background-color: var(--channel-link-own-bg);
}
.message.own .channel-link:hover {
background-color: var(--channel-link-own-hover);
}
.channel-link.loading {
opacity: 0.7;
pointer-events: none;
}
.channel-link.loading::after {
content: '...';
}
/* Quoted Text */
.quote-text {
font-style: italic;
color: var(--quote-color);
background-color: var(--quote-bg);
padding: 0.1rem 0.3rem;
border-radius: 0.25rem;
border-left: 2px solid var(--quote-border);
}
.message.own .quote-text {
color: var(--quote-own-color);
background-color: var(--quote-own-bg);
border-left-color: var(--quote-own-border);
}
/* Large Emoji for emoji-only messages */
.emoji-large {
font-size: 2.5rem;
line-height: 1.2;
}
/* Clickable Links in Messages */
.message-link {
color: var(--link-color);
text-decoration: underline;
word-break: break-all;
}
.message-link:hover {
color: var(--link-hover);
text-decoration: underline;
}
.message.own .message-link {
color: var(--link-own-color);
}
.message.own .message-link:hover {
color: var(--link-own-hover);
}
/* Image Thumbnails in Messages */
.message-image-container {
margin-top: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.message-image-thumbnail {
max-width: 300px;
max-height: 200px;
border-radius: 0.5rem;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
border: 1px solid var(--image-border);
}
.message-image-thumbnail:hover {
transform: scale(1.02);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.message-image-url {
font-size: 0.75rem;
word-break: break-all;
}
/* Responsive image sizes on mobile */
@media (max-width: 576px) {
.message-image-thumbnail {
max-width: 200px;
max-height: 150px;
}
}
/* Image Preview Modal */
#imagePreviewModal .modal-content {
background-color: rgba(0, 0, 0, 0.95);
}
#imagePreviewModal .modal-body {
padding: 1rem;
}
#imagePreviewImg {
border-radius: 0.5rem;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
}
/* =============================================================================
Floating Action Buttons (FAB)
============================================================================= */
.fab-container {
position: fixed;
right: 16px;
top: 80px;
z-index: 900; /* Lower than offcanvas (1045) but higher than content */
display: flex;
flex-direction: column;
gap: var(--fab-custom-gap, 12px);
touch-action: none; /* Prevent scroll during drag */
}
.fab {
position: relative; /* For badge positioning */
width: var(--fab-custom-size, 56px);
height: var(--fab-custom-size, 56px);
border-radius: 50%;
border: none;
display: flex;
align-items: center;
justify-content: center;
font-size: calc(var(--fab-custom-size, 56px) * 0.43);
cursor: pointer;
box-shadow: var(--fab-shadow);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.fab:hover {
transform: scale(1.1);
box-shadow: var(--fab-shadow-hover);
}
.fab:active {
transform: scale(0.95);
}
.fab-dm {
background: linear-gradient(135deg, #198754 0%, #157347 100%);
color: white;
}
.fab-contacts {
background: linear-gradient(135deg, #0d6efd 0%, #0a58ca 100%);
color: white;
}
/* FAB Badge (base style for all badges on FAB buttons) */
.fab-badge {
position: absolute;
top: -4px;
right: -4px;
min-width: 20px;
height: 20px;
border-radius: 10px;
padding: 2px 6px;
font-size: 0.65rem;
font-weight: bold;
line-height: 1.4;
text-align: center;
color: white;
display: none;
z-index: 1;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
/* FAB Badge for Pending Contacts (red for consistency and contrast) */
.fab-badge-pending {
background-color: #dc3545;
}
/* FAB Badge for Direct Messages (red for consistency and contrast) */
.fab-badge-dm {
background-color: #dc3545;
}
/* Animation on hover */
.fab:hover .fab-badge {
transform: scale(1.1);
transition: transform 0.2s ease;
}
/* FAB toggle button (smaller, semi-transparent) — not affected by custom size */
.fab-toggle {
width: 32px !important;
height: 32px !important;
background: rgba(108, 117, 125, 0.6);
color: white;
font-size: 0.85rem !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
cursor: grab;
}
.fab-toggle:active {
cursor: grabbing;
}
.fab-toggle:hover {
background: rgba(108, 117, 125, 0.9);
}
/* Collapsed state - hide all FABs except toggle */
.fab-container.collapsed .fab:not(.fab-toggle) {
opacity: 0;
pointer-events: none;
transform: scale(0);
height: 0;
width: 0;
margin: 0;
overflow: hidden;
}
.fab-container.collapsed {
gap: 0;
}
/* Smooth transitions for collapse */
.fab-container .fab:not(.fab-toggle) {
transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease, height 0.2s ease, width 0.2s ease;
}
.fab-toggle i {
transition: transform 0.2s ease;
}
.fab-container.collapsed .fab-toggle i {
transform: rotate(180deg);
}
/* Mobile optimization */
@media (max-width: 768px) {
.fab-container {
right: 12px;
top: 70px;
gap: var(--fab-custom-gap, 10px);
}
.fab {
width: var(--fab-custom-size, 48px);
height: var(--fab-custom-size, 48px);
font-size: calc(var(--fab-custom-size, 48px) * 0.43);
}
.fab-toggle {
width: 28px !important;
height: 28px !important;
font-size: 0.75rem !important;
}
}
/* =============================================================================
PWA Safe Area Handling
============================================================================= */
/* Ensure bottom UI is visible above system bars on mobile devices */
@supports (padding-bottom: env(safe-area-inset-bottom)) {
body {
padding-bottom: env(safe-area-inset-bottom);
}
}
/* =============================================================================
PWA Notifications
============================================================================= */
/* Notification toggle disabled state */
#notificationsToggle:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* =============================================================================
Leaflet Map Modal
============================================================================= */
#mapModal .modal-body {
min-height: 400px;
}
#leafletMap {
z-index: 1;
}
/* Fix Leaflet controls z-index in Bootstrap modal */
.leaflet-top,
.leaflet-bottom {
z-index: 1000;
}
/* =============================================================================
Message Action Buttons
============================================================================= */
/* Icon-only action buttons on message bubbles */
.btn-msg-action {
width: 28px;
height: 28px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.875rem;
}
/* =============================================================================
Map Filter Badges
============================================================================= */
/* Clickable map filter badges */
.map-filter-badge {
display: inline-block;
padding: 0.25rem 0.6rem;
font-size: 0.8rem;
font-weight: 600;
border-radius: 0.375rem;
cursor: pointer;
transition: all 0.15s ease-in-out;
user-select: none;
}
.map-filter-badge[data-type="1"] {
color: #2196F3;
background-color: var(--map-badge-inactive-bg);
border: 2px solid #2196F3;
}
.map-filter-badge[data-type="1"].active {
color: white;
background-color: #2196F3;
}
.map-filter-badge[data-type="2"] {
color: #4CAF50;
background-color: var(--map-badge-inactive-bg);
border: 2px solid #4CAF50;
}
.map-filter-badge[data-type="2"].active {
color: white;
background-color: #4CAF50;
}
.map-filter-badge[data-type="3"] {
color: #9C27B0;
background-color: var(--map-badge-inactive-bg);
border: 2px solid #9C27B0;
}
.map-filter-badge[data-type="3"].active {
color: white;
background-color: #9C27B0;
}
.map-filter-badge[data-type="4"] {
color: #FF9800;
background-color: var(--map-badge-inactive-bg);
border: 2px solid #FF9800;
}
.map-filter-badge[data-type="4"].active {
color: #212529;
background-color: #FF9800;
}
/* =============================================================================
Mentions Autocomplete Popup
============================================================================= */
.mentions-popup {
position: absolute;
bottom: 100%;
left: 0;
z-index: 1001;
margin-bottom: 0.5rem;
max-height: 200px;
width: 280px;
overflow-y: auto;
background-color: var(--popup-bg);
border: 1px solid var(--border-color);
border-radius: 0.5rem;
box-shadow: var(--popup-shadow);
}
.mentions-popup.hidden {
display: none;
}
.mentions-list {
list-style: none;
margin: 0;
padding: 0;
}
.mention-item {
padding: 0.5rem 0.75rem;
cursor: pointer;
border-bottom: 1px solid var(--mention-item-border);
font-size: 0.9rem;
transition: background-color 0.1s ease;
}
.mention-item:last-child {
border-bottom: none;
}
.mention-item:hover,
.mention-item.highlighted {
background-color: var(--mention-item-highlight);
}
.mention-item-name {
font-weight: 500;
}
.mentions-empty {
padding: 0.75rem;
text-align: center;
color: var(--text-muted);
font-size: 0.85rem;
}
/* Mobile responsive */
@media (max-width: 576px) {
.mentions-popup {
width: 100%;
max-width: none;
left: 0;
right: 0;
}
}
/* Mentions popup scrollbar */
.mentions-popup::-webkit-scrollbar {
width: 6px;
}
.mentions-popup::-webkit-scrollbar-track {
background: var(--scrollbar-track);
}
.mentions-popup::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb-light);
border-radius: 3px;
}
.mentions-popup::-webkit-scrollbar-thumb:hover {
background: var(--scrollbar-thumb-light-hover);
}
/* =============================================================================
Scroll to Bottom Button
============================================================================= */
.scroll-to-bottom-btn {
position: absolute;
bottom: 1rem;
right: 1.5rem;
width: 44px;
height: 44px;
border-radius: 50%;
border: none;
background-color: rgba(var(--bs-primary-rgb), 0.7);
color: white;
font-size: 1.25rem;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease, background-color 0.15s ease;
z-index: 100;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.scroll-to-bottom-btn.visible {
opacity: 1;
visibility: visible;
}
.scroll-to-bottom-btn:hover {
background-color: rgba(var(--bs-primary-rgb), 0.9);
}
.scroll-to-bottom-btn:active {
transform: scale(0.95);
}
/* =============================================================================
Echo Badge - "Heard X repeats" indicator for sent messages
============================================================================= */
.echo-badge {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.7rem;
color: var(--echo-color);
padding: 0.2rem 0.4rem;
margin-right: 0.25rem;
border-radius: 0.25rem;
background-color: var(--echo-bg);
}
.echo-badge i {
font-size: 0.65rem;
}
/* Path info in message meta (incoming messages) */
.path-info {
cursor: pointer;
border-bottom: 1px dotted currentColor;
position: relative;
}
/* Path popup (mobile-friendly, multi-path) */
.path-popup {
position: absolute;
bottom: 100%;
right: 0;
left: auto;
background-color: #333;
color: #fff;
padding: 0.4rem 0.6rem;
border-radius: 0.375rem;
font-size: 0.7rem;
white-space: normal;
z-index: 1000;
pointer-events: auto;
margin-bottom: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
min-width: 180px;
max-width: min(320px, calc(100vw - 1.5rem));
}
.path-popup .path-entry {
padding: 0.15rem 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
word-break: break-all;
cursor: pointer;
display: flex;
align-items: flex-start;
gap: 0.4rem;
}
.path-popup .path-route {
flex: 1 1 auto;
min-width: 0;
}
.path-popup .path-copy {
flex: 0 0 auto;
padding: 0.1rem 0.15rem;
opacity: 0.7;
cursor: pointer;
}
.path-popup .path-copy:hover {
opacity: 1;
}
.path-popup .path-entry:active {
opacity: 0.6;
}
.path-popup .path-entry:last-child {
border-bottom: none;
}
.path-popup .path-detail {
display: block;
opacity: 0.7;
font-size: 0.6rem;
}
/* =============================================================================
Chat Filter
============================================================================= */
/* Filter FAB button (gray gradient) */
.fab-filter {
background: linear-gradient(135deg, #6c757d 0%, #495057 100%);
color: white;
}
/* Search FAB button (muted teal) */
.fab-search {
background: linear-gradient(135deg, #5fa8a0 0%, #4a8f88 100%);
color: white;
}
/* Settings FAB button (warm orange) */
.fab-settings {
background: linear-gradient(135deg, #fd7e14 0%, #e06b0a 100%);
color: white;
}
/* Advert FAB button (muted teal) */
.fab-advert {
background: linear-gradient(135deg, #5fa8a0 0%, #4a8f88 100%);
color: white;
}
/* Flood Advert FAB button (warning yellow) */
.fab-floodadvert {
background: linear-gradient(135deg, #ffc107 0%, #d39e00 100%);
color: white;
}
/* Map FAB button (muted teal) */
.fab-map {
background: linear-gradient(135deg, #5fa8a0 0%, #4a8f88 100%);
color: white;
}
/* Console FAB button (blue) */
.fab-console {
background: linear-gradient(135deg, #0d6efd 0%, #0a58ca 100%);
color: white;
}
/* Device Info FAB button (muted teal) */
.fab-deviceinfo {
background: linear-gradient(135deg, #5fa8a0 0%, #4a8f88 100%);
color: white;
}
/* System Log FAB button (blue) */
.fab-syslog {
background: linear-gradient(135deg, #0d6efd 0%, #0a58ca 100%);
color: white;
}
/* My Repeaters FAB button (REP green) */
.fab-repeaters {
background: linear-gradient(135deg, #198754 0%, #146c43 100%);
color: white;
}
/* Path Analyzer FAB button + modal header (purple) */
.fab-pathanalyzer,
.pathanalyzer-header {
background: linear-gradient(135deg, #6f42c1 0%, #59359a 100%);
color: white;
}
/* Filter bar overlay - slides down from top of chat area */
.filter-bar {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 1002; /* Above mentions popup (1001) */
background-color: var(--filter-bg);
border-bottom: 1px solid var(--border-color);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
padding: 0.75rem;
transform: translateY(-100%);
opacity: 0;
visibility: hidden;
transition: transform 0.3s ease, opacity 0.3s ease, visibility 0.3s ease;
}
.filter-bar.visible {
transform: translateY(0);
opacity: 1;
visibility: visible;
}
/* Push messages container down when filter bar is visible */
.messages-container {
transition: padding-top 0.3s ease;
}
.filter-bar.visible ~ .messages-container {
padding-top: calc(1rem + 52px) !important; /* 52px ~ filter bar height */
}
/* Filter bar inner layout */
.filter-bar-inner {
display: flex;
align-items: center;
gap: 0.5rem;
}
.filter-bar-input {
border-radius: 0.375rem;
border: 1px solid var(--filter-input-border);
padding: 0.5rem 0.75rem;
font-size: 0.9rem;
background-color: var(--bg-body);
color: var(--text-primary);
}
.filter-bar-input:focus {
outline: none;
border-color: #86b7fe;
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
}
[data-theme="dark"] .filter-bar-input:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25);
}
/* Filter bar buttons */
.filter-bar-btn {
width: 36px;
height: 36px;
border-radius: 50%;
border: none;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.15s ease;
}
.filter-bar-btn-me {
background-color: var(--filter-btn-me-bg);
color: var(--filter-btn-me-color);
}
.filter-bar-btn-me:hover {
background-color: var(--filter-btn-me-hover);
}
.filter-bar-btn-clear {
background-color: var(--filter-btn-clear-bg);
color: var(--filter-btn-clear-color);
}
.filter-bar-btn-clear:hover {
background-color: var(--filter-btn-clear-hover);
}
.filter-bar-btn-close {
background-color: #dc3545;
color: white;
}
.filter-bar-btn-close:hover {
background-color: #bb2d3b;
}
/* Filter match count indicator */
.filter-match-count {
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
padding: 0 0.5rem;
}
/* Highlighted text in filtered messages */
.filter-highlight {
background-color: var(--filter-highlight);
border-radius: 0.2rem;
padding: 0 0.1rem;
}
/* Hidden messages when filtering */
.message-wrapper.filter-hidden,
.dm-message-wrapper.filter-hidden {
display: none !important;
}
/* No matches message */
.filter-no-matches {
text-align: center;
padding: 2rem;
color: var(--text-muted);
}
.filter-no-matches i {
font-size: 2rem;
margin-bottom: 0.5rem;
display: block;
}
/* Filter input wrapper for mentions popup positioning */
.filter-input-wrapper {
flex: 1;
position: relative;
}
.filter-input-wrapper .filter-bar-input {
width: 100%;
}
/* Filter mentions popup - appears below input (not above like message input) */
.filter-mentions-popup {
bottom: auto !important;
top: 100% !important;
margin-top: 0.25rem;
margin-bottom: 0;
}
/* Mobile responsive filter bar */
@media (max-width: 576px) {
.filter-bar {
padding: 0.5rem;
}
.filter-bar-input {
font-size: 0.85rem;
padding: 0.4rem 0.6rem;
}
.filter-bar-btn {
width: 32px;
height: 32px;
font-size: 0.9rem;
}
}
/* =============================================================================
Global Search
============================================================================= */
#searchResults {
max-height: 60vh;
overflow-y: auto;
}
#searchResults .list-group-item {
border-left: 3px solid transparent;
}
#searchResults .list-group-item:hover {
border-left-color: var(--bs-primary);
}
#searchResults mark {
background-color: var(--search-mark-bg);
padding: 0 2px;
border-radius: 2px;
}
/* Own device map marker */
.own-device-marker {
background: transparent;
border: none;
}
/* =============================================================================
Emoji Picker (shared between index.html and dm.html)
============================================================================= */
emoji-picker {
--emoji-size: 1.5rem;
--num-columns: 8;
}
.emoji-picker-container {
position: relative;
}
.emoji-picker-popup {
position: absolute;
bottom: 100%;
right: 0;
z-index: 1000;
margin-bottom: 0.5rem;
box-shadow: var(--popup-shadow);
border-radius: 0.5rem;
overflow: hidden;
}
.emoji-picker-popup.hidden {
display: none;
}
/* Mobile responsive adjustments */
@media (max-width: 576px) {
emoji-picker {
--emoji-size: 1.25rem;
--num-columns: 6;
}
.emoji-picker-popup {
right: auto;
left: 0;
width: 100%;
max-width: 100%;
}
}
/* Modal fullscreen - remove all margins and padding */
#dmModal .modal-dialog.modal-fullscreen,
#contactsModal .modal-dialog.modal-fullscreen,
#logsModal .modal-dialog.modal-fullscreen,
#consoleModal .modal-dialog.modal-fullscreen,
#repeatersModal .modal-dialog.modal-fullscreen,
#pathAnalyzerModal .modal-dialog.modal-fullscreen {
margin: 0 !important;
width: 100vw !important;
max-width: 100vw !important;
height: 100vh !important;
max-height: 100vh !important;
}
#dmModal .modal-content,
#contactsModal .modal-content,
#logsModal .modal-content,
#consoleModal .modal-content,
#repeatersModal .modal-content,
#pathAnalyzerModal .modal-content {
border: none !important;
border-radius: 0 !important;
height: 100vh !important;
}
#dmModal .modal-body,
#contactsModal .modal-body,
#logsModal .modal-body,
#consoleModal .modal-body,
#repeatersModal .modal-body,
#pathAnalyzerModal .modal-body {
overflow: hidden !important;
}
/* =============================================================================
Contact Management Styles (shared between contacts.html and contacts_base.html)
============================================================================= */
.compact-setting {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background-color: var(--bg-surface);
border-radius: 0.5rem;
margin-bottom: 1rem;
}
.info-icon {
color: var(--text-muted);
cursor: help;
font-size: 1.1rem;
}
.info-icon:hover {
color: var(--sender-color);
}
.pending-contact-card {
background-color: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 0.75rem;
box-shadow: var(--card-shadow);
}
.contact-name {
font-size: 1.1rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 0.1rem;
word-wrap: break-word;
}
.contact-key {
font-family: 'Courier New', monospace;
font-size: 0.85rem;
color: var(--text-muted);
word-break: break-all;
margin-bottom: 0.15rem;
}
.contact-key.clickable-key {
cursor: pointer;
transition: color 0.15s, background-color 0.15s;
padding: 0.15rem 0.3rem;
margin-left: -0.3rem;
border-radius: 0.25rem;
}
.contact-key.clickable-key:hover {
color: var(--key-hover-color);
background-color: var(--key-hover-bg);
}
.contact-key.clickable-key.copied {
color: var(--key-copied-color);
background-color: var(--key-copied-bg);
}
.btn-action {
min-height: 44px; /* Touch-friendly size */
font-size: 1rem;
}
.info-badge {
display: inline-block;
background-color: var(--info-badge-bg);
color: var(--info-badge-color);
padding: 0.5rem 1rem;
border-radius: 0.375rem;
font-size: 0.9rem;
margin-top: 0.5rem;
}
/* Existing Contacts Styles */
.existing-contact-card {
background-color: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 0.75rem;
box-shadow: var(--card-shadow);
transition: box-shadow 0.2s;
}
.existing-contact-card:hover {
box-shadow: var(--card-shadow-hover);
}
.type-badge {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
font-weight: 600;
}
/* =============================================================================
DM Contact Dropdown (dm.html)
============================================================================= */
.dm-contact-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 1050;
max-height: 300px;
overflow-y: auto;
background: var(--dropdown-bg);
border: 1px solid var(--border-color);
border-top: none;
border-radius: 0 0 0.375rem 0.375rem;
box-shadow: var(--popup-shadow);
}
.dm-contact-item {
padding: 0.5rem 0.75rem;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid var(--border-light);
font-size: 0.88rem;
font-weight: 400;
}
.dm-contact-item:hover,
.dm-contact-item.active {
background-color: var(--dropdown-item-hover);
}
.dm-contact-item .contact-name {
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.88rem;
font-weight: 400;
}
.dm-contact-item .badge {
font-size: 0.7rem;
}
.dm-dropdown-separator {
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
color: var(--text-muted);
background: var(--dropdown-separator-bg);
font-weight: 600;
}
/* =============================================================================
Path Management (dm.html)
============================================================================= */
.path-list-item {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.35rem 0.5rem;
border: 1px solid var(--path-item-border);
border-radius: 0.25rem;
margin-bottom: 0.25rem;
font-size: 0.8rem;
background: var(--path-item-bg);
}
.path-list-item.primary {
border-color: var(--path-item-primary-border);
background: var(--path-item-primary-bg);
}
.path-list-item .path-hex {
font-family: monospace;
font-size: 0.75rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.path-list-item .path-label {
color: var(--text-muted);
font-size: 0.7rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.path-list-item .path-actions {
margin-left: auto;
display: flex;
gap: 0.15rem;
flex-shrink: 0;
}
.path-list-item .path-actions .btn {
padding: 0 0.25rem;
font-size: 0.7rem;
line-height: 1.2;
}
.path-section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.path-section-header h6 {
font-size: 0.85rem;
margin: 0;
}
.repeater-picker-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.4rem 0.5rem;
cursor: pointer;
border-bottom: 1px solid var(--border-light);
font-size: 0.8rem;
}
.repeater-picker-item:hover {
background-color: var(--bg-hover);
}
.repeater-picker-item .badge {
font-family: monospace;
font-size: 0.7rem;
}
.path-uniqueness-warning {
color: #dc3545;
font-size: 0.75rem;
}
/* Leaflet z-index fix for Bootstrap modal (DM repeater map) */
#rptLeafletMap { z-index: 1; }
#rptLeafletMap .leaflet-top,
#rptLeafletMap .leaflet-bottom { z-index: 1000; }
/* =============================================================================
Contact Management - Page-specific Styles (contacts.html)
============================================================================= */
.contact-info-row {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
flex-wrap: wrap;
}
.counter-badge {
font-size: 1rem;
padding: 0.35rem 0.75rem;
}
.counter-ok {
background-color: #28a745;
}
.counter-warning {
background-color: #ffc107;
color: #212529;
}
.counter-alarm {
background-color: #dc3545;
animation: counterPulse 1.5s infinite;
}
@keyframes counterPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.search-toolbar {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.search-toolbar input,
.search-toolbar select {
flex: 1;
min-width: 150px;
}
/* Scrollable contacts lists - height managed by flexbox in contacts_base */
#pendingList,
#existingList {
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
}
#existingList::-webkit-scrollbar,
#pendingList::-webkit-scrollbar {
width: 8px;
}
#existingList::-webkit-scrollbar-track,
#pendingList::-webkit-scrollbar-track {
background: var(--scrollbar-track);
border-radius: 4px;
}
#existingList::-webkit-scrollbar-thumb,
#pendingList::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb);
border-radius: 4px;
}
#existingList::-webkit-scrollbar-thumb:hover,
#pendingList::-webkit-scrollbar-thumb:hover {
background: var(--scrollbar-thumb-hover);
}
.section-compact {
margin-bottom: 0.75rem;
}
/* Device settings sub-tabs */
#tabSettingsDevice .nav-pills .nav-link {
font-size: 0.8rem;
padding: 0.25rem 0.75rem;
}