mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-11-03 17:22:20 +01:00
console.html and logs.html are always-dark terminal pages that deliberately do not load theme.css, so the var(--text-secondary) the notice asked for resolved to nothing there and the text fell back to Bootstrap's near-black body colour — roughly 1:1 against the navy background, i.e. invisible. Fixed twice over. Every colour in the demo CSS now carries a fallback, so a page without theme.css degrades to a readable light notice instead of to nothing — that closes the whole class of bug rather than this one instance. And console.html restyles the notice in its own palette, alongside the other hardcoded colours it already owns. Measured contrast: console 12.22:1, light theme 7.76:1, dark theme 5.71:1 (WCAG AA for small text is 4.5:1). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2715 lines
60 KiB
CSS
2715 lines
60 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;
|
|
}
|
|
|
|
/* Same badge in the sidebar (wide) and the navbar dropdown (narrow) */
|
|
.channel-sidebar-item .sidebar-unread-badge,
|
|
.channel-selector-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;
|
|
}
|
|
|
|
/* =============================================================================
|
|
"New messages" divider (channel chat + DM)
|
|
============================================================================= */
|
|
|
|
/* Both message lists are flex columns whose children set their own align-self,
|
|
so without `stretch` the divider would shrink to the width of its label. */
|
|
.unread-divider {
|
|
align-self: stretch;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
margin: 0.25rem 0;
|
|
color: var(--unread-divider-color);
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
user-select: none;
|
|
}
|
|
|
|
.unread-divider::before,
|
|
.unread-divider::after {
|
|
content: '';
|
|
flex: 1;
|
|
height: 1px;
|
|
background: var(--unread-divider-color);
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* =============================================================================
|
|
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%;
|
|
}
|
|
|
|
/* Chat inputs stay at 16px on mobile - anything smaller makes iOS zoom the
|
|
whole page on focus. See "iOS auto-zoom guard" at the end of this file. */
|
|
#messageInput,
|
|
#dmMessageInput {
|
|
font-size: 16px;
|
|
}
|
|
|
|
/* 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 */
|
|
#channelSelectorButton {
|
|
min-width: 0 !important;
|
|
width: 100%;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* DM: Contact search input on mobile (16px - see iOS auto-zoom guard) */
|
|
#dmContactSearchInput {
|
|
min-width: 100px !important;
|
|
font-size: 16px;
|
|
}
|
|
|
|
/* 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,
|
|
.unread-divider.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 by contacts_base.html and its contacts-* pages)
|
|
============================================================================= */
|
|
|
|
.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-* pages)
|
|
============================================================================= */
|
|
|
|
.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;
|
|
}
|
|
|
|
/* =============================================================================
|
|
iOS auto-zoom guard - KEEP THIS BLOCK LAST
|
|
-----------------------------------------------------------------------------
|
|
iOS WebKit (Safari, and Chrome/Firefox on iOS, which are WebKit too) zooms the
|
|
entire page when a focused form control has a computed font-size below 16px.
|
|
Because our shell is `height: 100dvh; overflow: hidden`, WebKit has nothing to
|
|
scroll back and leaves the page scaled - the user has to pinch out manually.
|
|
|
|
So: every focusable control stays at >= 16px on touch devices. Make controls
|
|
compact with padding/rows, never with font-size.
|
|
|
|
Scoped to (pointer: coarse) rather than a width breakpoint on purpose: it also
|
|
covers landscape phones, which are wider than 768px but still zoom. Desktop
|
|
keeps Bootstrap's smaller sizing.
|
|
|
|
`!important` is deliberate. This is a hard floor, and it has to outrank rules
|
|
it cannot enumerate: page-local <style> blocks load after this file and reach
|
|
specificities like `.filter-sort-toolbar .form-select` (contacts_base.html) or
|
|
`.filter-select` (logs.html). Being hard to override is the point - a new page
|
|
that shrinks its inputs should not silently bring the zoom back.
|
|
|
|
Types that open a picker rather than a keyboard are excluded: they never
|
|
trigger the zoom, so there is no reason to change how they look.
|
|
============================================================================= */
|
|
@media (pointer: coarse) {
|
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="button"]):not([type="submit"]):not([type="reset"]),
|
|
select,
|
|
textarea {
|
|
font-size: 16px !important;
|
|
}
|
|
}
|
|
|
|
/* =============================================================================
|
|
Share Cards — contacts, channels and positions shared inside chat messages
|
|
Rendered by message-utils.js into .message-content / .dm-content, which are
|
|
`white-space: pre-wrap`; the card resets that so its own text wraps normally.
|
|
============================================================================= */
|
|
|
|
.share-card {
|
|
display: block;
|
|
white-space: normal;
|
|
background-color: var(--bg-body);
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 0.625rem;
|
|
padding: 0.5rem;
|
|
margin: 0.25rem 0;
|
|
/* A definite width, not just a max: message bubbles shrink-to-fit, and with
|
|
only a max-width the inner flex row resolves against whatever narrow
|
|
width the rest of the bubble happens to impose, wrapping labels like
|
|
"Hashtag Channel" mid-phrase. max-width still protects narrow screens. */
|
|
width: 17.5rem;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.share-card-main {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
min-width: 0;
|
|
}
|
|
|
|
.share-card-avatar {
|
|
flex: 0 0 auto;
|
|
width: 2.25rem;
|
|
height: 2.25rem;
|
|
border-radius: 50%;
|
|
background-color: var(--sender-color);
|
|
color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.share-card-info {
|
|
min-width: 0;
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
.share-card-title {
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
line-height: 1.3;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.share-card-sub {
|
|
font-size: 0.75rem;
|
|
color: var(--text-muted);
|
|
line-height: 1.35;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.share-card-key,
|
|
.share-card-coords {
|
|
font-family: var(--bs-font-monospace, monospace);
|
|
}
|
|
|
|
/* "Shared contact" / "Shared channel" marker on our own messages, which carry
|
|
no action button — we already have whatever we shared. Sits above the
|
|
identity block, the way the official app labels these. */
|
|
.share-card-own {
|
|
font-size: 0.7rem;
|
|
color: var(--text-muted);
|
|
font-style: italic;
|
|
margin-bottom: 0.375rem;
|
|
}
|
|
|
|
.share-card-note {
|
|
font-size: 0.7rem;
|
|
color: var(--text-muted);
|
|
margin-top: 0.375rem;
|
|
}
|
|
|
|
.share-card-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.share-card-btn {
|
|
border: 1px solid transparent;
|
|
border-radius: 0.5rem;
|
|
padding: 0.3rem 0.6rem;
|
|
font-size: 0.8125rem;
|
|
line-height: 1.3;
|
|
cursor: pointer;
|
|
flex: 1 1 auto;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.share-card-btn-primary {
|
|
background-color: var(--sender-color);
|
|
color: #fff;
|
|
}
|
|
|
|
.share-card-btn-secondary {
|
|
background-color: transparent;
|
|
border-color: var(--border-color);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.share-card-btn-secondary:hover {
|
|
background-color: var(--bg-hover);
|
|
}
|
|
|
|
/* Icon-only actions (copy, external maps) must not stretch. */
|
|
.share-card-btn-icon {
|
|
flex: 0 0 auto;
|
|
background-color: transparent;
|
|
border-color: var(--border-color);
|
|
color: var(--text-muted);
|
|
padding: 0.3rem 0.5rem;
|
|
}
|
|
|
|
.share-card-btn-icon:hover {
|
|
background-color: var(--bg-hover);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.share-card-btn:disabled,
|
|
.share-card-btn.loading {
|
|
opacity: 0.6;
|
|
cursor: default;
|
|
}
|
|
|
|
.share-card-ext {
|
|
flex: 0 0 auto;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 1.9rem;
|
|
height: 1.75rem;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 0.5rem;
|
|
color: var(--text-muted);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.share-card-ext:hover {
|
|
background-color: var(--bg-hover);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
/* Terminal states: nothing to click, so styled as a label rather than a button. */
|
|
.share-card-state {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
margin-top: 0.5rem;
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
.share-card-state-done {
|
|
color: var(--bs-success, #198754);
|
|
}
|
|
|
|
.share-card-state-warning {
|
|
color: var(--bs-warning-text-emphasis, #997404);
|
|
}
|
|
|
|
/* =============================================================================
|
|
Share Composer — the "+" button, its menu, the pickers and the live preview
|
|
============================================================================= */
|
|
|
|
.share-composer-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
/* Anchored to .emoji-picker-container, the same positioned ancestor the emoji
|
|
and mentions popups use. */
|
|
.share-menu-popup {
|
|
position: absolute;
|
|
bottom: calc(100% + 0.5rem);
|
|
right: 0;
|
|
z-index: 1060;
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-width: 13rem;
|
|
padding: 0.25rem;
|
|
background-color: var(--popup-bg);
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 0.625rem;
|
|
box-shadow: var(--popup-shadow);
|
|
}
|
|
|
|
.share-menu-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem 0.625rem;
|
|
background: transparent;
|
|
border: 0;
|
|
border-radius: 0.5rem;
|
|
color: var(--text-primary);
|
|
text-align: left;
|
|
font-size: 0.9375rem;
|
|
}
|
|
|
|
.share-menu-item:hover {
|
|
background-color: var(--bg-hover);
|
|
}
|
|
|
|
.share-menu-item i {
|
|
color: var(--sender-color);
|
|
font-size: 1.05rem;
|
|
width: 1.25rem;
|
|
text-align: center;
|
|
}
|
|
|
|
/* --- pickers --- */
|
|
|
|
.share-pick-list {
|
|
max-height: 55vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.share-pick-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.625rem;
|
|
}
|
|
|
|
.share-pick-icon {
|
|
flex: 0 0 auto;
|
|
width: 1.75rem;
|
|
height: 1.75rem;
|
|
border-radius: 50%;
|
|
background-color: var(--sender-color);
|
|
color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.share-pick-text {
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.share-pick-title {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.share-pick-sub {
|
|
font-size: 0.75rem;
|
|
color: var(--text-muted);
|
|
font-family: var(--bs-font-monospace, monospace);
|
|
}
|
|
|
|
.share-pick-badge {
|
|
flex: 0 0 auto;
|
|
font-size: 0.7rem;
|
|
color: var(--text-muted);
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 0.75rem;
|
|
padding: 0.05rem 0.4rem;
|
|
}
|
|
|
|
.share-pick-coords {
|
|
font-family: var(--bs-font-monospace, monospace);
|
|
font-size: 0.8125rem;
|
|
opacity: 0.85;
|
|
margin-left: 0.375rem;
|
|
}
|
|
|
|
/* --- live preview above the composer ---
|
|
Present only while the input holds a valid token; it disappears the moment
|
|
the token is edited into something that will not render as a card. */
|
|
.share-preview {
|
|
padding: 0.375rem 0.75rem 0;
|
|
}
|
|
|
|
.share-preview-label {
|
|
font-size: 0.7rem;
|
|
color: var(--text-muted);
|
|
margin-bottom: 0.125rem;
|
|
}
|
|
|
|
.share-preview-body .share-card {
|
|
margin: 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
Demo mode (MC_DEMO)
|
|
------------------------------------------------------------
|
|
Locked controls stay visible and stay laid out — the instance is shared to
|
|
show the interface off, so a control that vanished would just look like a
|
|
feature mc-webui does not have. Dimmed and struck out of reach instead.
|
|
============================================================ */
|
|
|
|
.demo-locked {
|
|
opacity: 0.5;
|
|
cursor: not-allowed !important;
|
|
filter: grayscale(1);
|
|
}
|
|
|
|
/* Bootstrap paints its own disabled state on form controls; keep ours from
|
|
fighting it, and keep the pointer honest over the whole locked block. */
|
|
.demo-locked-region {
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.demo-locked-region .form-check-input,
|
|
.demo-locked-region .form-control,
|
|
.demo-locked-region .form-select {
|
|
background-color: var(--bg-surface-alt, #f0f0f0);
|
|
}
|
|
|
|
/* The notice that explains the greying out. Sits at the top of a locked pane. */
|
|
/* Every colour carries a fallback: console.html and logs.html are always-dark
|
|
terminal pages that deliberately do not load theme.css, so an unguarded
|
|
var() resolves to nothing there and the text inherits Bootstrap's near-black
|
|
body colour — invisible on their navy background. The fallbacks are the
|
|
light-theme values, so a page without theme.css degrades to a readable light
|
|
notice rather than to nothing. console.html then restyles it to its own
|
|
palette below. */
|
|
.demo-notice {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem 0.75rem;
|
|
margin-bottom: 0.75rem;
|
|
border: 1px solid var(--border-color, #dee2e6);
|
|
border-left: 3px solid #ffc107;
|
|
border-radius: 0.375rem;
|
|
background: var(--bg-surface, #f8f9fa);
|
|
color: var(--text-secondary, #495057);
|
|
font-size: 0.8125rem;
|
|
line-height: 1.35;
|
|
}
|
|
|
|
.demo-notice i {
|
|
color: #ffc107;
|
|
margin-top: 0.1rem;
|
|
}
|
|
|
|
/* "Demo" marker in the navbar, so it is obvious which instance this is. */
|
|
.demo-badge {
|
|
font-size: 0.65rem;
|
|
letter-spacing: 0.05em;
|
|
text-transform: uppercase;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/* Operator unlock box at the foot of the Settings modal. */
|
|
.demo-unlock-box {
|
|
border-top: 1px solid var(--border-color, #dee2e6);
|
|
margin-top: 1rem;
|
|
padding-top: 0.75rem;
|
|
}
|