diora-web/static/css/app.css

1914 lines
44 KiB
CSS
Raw Normal View History

2026-03-16 19:19:22 +01:00
/* =========================================================
diora dark radio player theme
========================================================= */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
overflow: hidden;
scrollbar-color: #333 #000;
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: #000; }
::-webkit-scrollbar-thumb { background: #333; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #555; }
2026-03-16 19:19:22 +01:00
:root {
--bg: #000;
--bg-card: transparent;
--bg-alt: transparent;
--bg-row: transparent;
--bg-row-alt: transparent;
--border: #2a2a2a;
--accent: #e63946;
--accent-hover: #ff4d58;
--green: #2ecc71;
--yellow: #f1c40f;
--font: 'Courier New', Courier, monospace;
--radius: 3px;
--nav-h: 48px;
--bar-h: 72px;
/* contrast scheme — default: white on dark */
--fg: #fff;
--fg-muted: #fff;
--outline: #000;
--text: var(--fg);
--text-muted: var(--fg);
}
/* inverted: black on white */
2026-03-16 19:19:22 +01:00
body.bright-bg {
--bg: #fff;
--bg-card: #f5f5f5;
--bg-alt: #f0f0f0;
--bg-row: #fafafa;
--bg-row-alt: #f5f5f5;
2026-03-16 19:19:22 +01:00
--fg: #000;
--fg-muted: #000;
--outline: #fff;
--border: #bbb;
}
html, body {
background: var(--bg);
color: var(--fg);
font-family: var(--font);
font-size: 14px;
font-weight: 600;
line-height: 1.5;
min-height: 100vh;
text-shadow:
-1px -1px 0 var(--outline),
1px -1px 0 var(--outline),
-1px 1px 0 var(--outline),
1px 1px 0 var(--outline);
}
/* Elements with their own coloured backgrounds — no outline, no override */
.btn-play,
.btn-amazon,
.btn-lastfm,
.btn-danger,
.btn-primary,
.navbar-brand {
text-shadow: none;
}
/* Accent colour stays red regardless of scheme */
.navbar-brand { color: var(--accent); }
.tab-btn.active { color: var(--accent); }
a {
color: var(--accent);
text-decoration: none;
}
a:hover {
color: var(--accent-hover);
text-decoration: underline;
}
/* =========================================================
NAVBAR
========================================================= */
.navbar {
position: sticky;
top: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
height: var(--nav-h);
padding: 0 1.5rem;
background: var(--bg);
2026-03-16 19:19:22 +01:00
border-bottom: 1px solid var(--border);
/* Window Controls Overlay: extend navbar into the titlebar area */
padding-left: max(1.5rem, env(titlebar-area-x, 1.5rem));
padding-top: env(titlebar-area-y, 0);
height: calc(var(--nav-h) + env(titlebar-area-y, 0px));
-webkit-app-region: drag;
}
.navbar a, .navbar button, .navbar input, .navbar form {
-webkit-app-region: no-drag;
2026-03-16 19:19:22 +01:00
}
.navbar-brand {
font-size: 1.4rem;
font-weight: bold;
letter-spacing: 0.05em;
color: var(--accent);
text-decoration: none;
}
.navbar-brand:hover {
color: var(--accent-hover);
text-decoration: none;
}
.navbar-links {
display: flex;
align-items: center;
gap: 1rem;
}
.navbar-user {
color: var(--text-muted);
font-size: 0.85rem;
}
/* =========================================================
MAIN CONTENT
========================================================= */
.main-content {
max-width: 1100px;
margin: 0 auto;
padding: calc(var(--nav-h) + 3rem) 1.5rem calc(var(--bar-h) + 2rem);
height: 100%;
overflow-y: auto;
2026-03-16 19:19:22 +01:00
}
/* =========================================================
MESSAGES
========================================================= */
.messages {
margin-bottom: 1rem;
}
.message {
padding: 0.6rem 1rem;
border-radius: var(--radius);
margin-bottom: 0.4rem;
background: var(--bg-alt);
border-left: 3px solid var(--text-muted);
}
.message-error { border-color: var(--accent); }
.message-success { border-color: var(--green); }
.message-warning { border-color: var(--yellow); }
/* =========================================================
NOW PLAYING BAR (fixed at bottom)
========================================================= */
.now-playing-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: var(--bar-h);
background: var(--bg);
2026-03-16 19:19:22 +01:00
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1.5rem;
z-index: 200;
gap: 1rem;
}
.now-playing-info {
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
overflow: hidden;
}
.now-playing-station {
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.now-playing-track {
font-size: 0.95rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--text);
}
.now-playing-controls {
display: flex;
align-items: center;
gap: 0.75rem;
flex-shrink: 0;
}
.volume-label {
display: flex;
align-items: center;
gap: 0.4rem;
color: var(--text-muted);
font-size: 0.75rem;
}
.volume-slider {
width: 80px;
accent-color: var(--accent);
cursor: pointer;
}
/* =========================================================
AFFILIATE SECTION
========================================================= */
.affiliate-section {
display: flex;
align-items: center;
gap: 1.25rem;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1rem;
margin-bottom: 1.5rem;
}
.affiliate-artwork {
width: 80px;
height: 80px;
object-fit: cover;
border-radius: var(--radius);
flex-shrink: 0;
background: var(--bg-alt);
}
.affiliate-info {
display: flex;
flex-direction: column;
gap: 0.2rem;
min-width: 0;
}
.affiliate-track {
font-size: 1rem;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.affiliate-artist {
font-size: 0.85rem;
color: var(--text-muted);
}
.affiliate-album {
font-size: 0.8rem;
color: var(--text-muted);
font-style: italic;
}
.btn-amazon {
display: inline-block;
margin-top: 0.5rem;
background: #ff9900;
color: #000;
padding: 0.3rem 0.8rem;
border-radius: var(--radius);
font-weight: bold;
font-size: 0.8rem;
}
.btn-amazon:hover {
background: #ffad33;
color: #000;
text-decoration: none;
}
/* =========================================================
TABS
========================================================= */
.tabs {
display: flex;
border-bottom: 1px solid var(--border);
margin-bottom: 1.25rem;
gap: 0;
}
/* Haupttab-Leiste: immer sichtbar unterhalb der Navbar */
#tabs {
position: fixed;
top: var(--nav-h);
left: 0;
right: 0;
z-index: 150;
background: var(--bg);
margin-bottom: 0;
padding: 0 0.5rem;
}
2026-03-16 19:19:22 +01:00
.tab-btn {
background: none;
border: none;
border-bottom: 2px solid transparent;
color: var(--text-muted);
cursor: pointer;
font-family: var(--font);
font-size: 0.9rem;
padding: 0.5rem 1.25rem;
transition: color 0.15s, border-color 0.15s;
}
.tab-btn:hover {
color: var(--text);
}
.tab-btn.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.tab-panel {
min-height: 200px;
}
.sub-tabs {
border-bottom-color: transparent;
margin-bottom: 1rem;
}
.sub-tabs .tab-btn {
font-size: 0.8rem;
padding: 0.3rem 1rem;
color: var(--text-muted);
}
.sub-tabs .tab-btn.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
2026-03-16 19:19:22 +01:00
/* =========================================================
SEARCH
========================================================= */
.search-bar {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
.search-input {
flex: 1;
background: transparent;
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text);
font-family: var(--font);
font-size: 0.9rem;
padding: 0.4rem 0.7rem;
outline: none;
}
.search-input:focus {
border-color: var(--accent);
}
.status-msg {
color: var(--text-muted);
font-size: 0.85rem;
min-height: 1.4em;
margin-bottom: 0.5rem;
}
/* =========================================================
TABLES
========================================================= */
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
.data-table th {
background: var(--bg-alt);
border-bottom: 1px solid var(--border);
color: var(--text-muted);
font-weight: normal;
padding: 0.45rem 0.7rem;
text-align: left;
}
.data-table td {
padding: 0.4rem 0.7rem;
border-bottom: 1px solid var(--border);
vertical-align: middle;
max-width: 220px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.data-table tbody tr:nth-child(odd) { background: transparent; }
.data-table tbody tr:nth-child(even) { background: transparent; }
.data-table tbody tr:hover { background: rgba(255, 255, 255, 0.05); }
.empty-msg {
color: var(--text-muted);
text-align: center;
padding: 1.5rem !important;
}
.history-time {
color: var(--text-muted);
font-size: 0.75rem;
white-space: nowrap;
}
/* =========================================================
BUTTONS
========================================================= */
.btn {
background: transparent;
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text);
cursor: pointer;
font-family: var(--font);
font-size: 0.85rem;
padding: 0.35rem 0.75rem;
transition: background 0.1s, border-color 0.1s;
white-space: nowrap;
}
.btn:hover {
background: rgba(255, 255, 255, 0.07);
border-color: #444;
}
.btn-play {
background: var(--accent);
border-color: var(--accent);
color: #fff;
font-size: 0.9rem;
padding: 0.4rem 1rem;
}
.btn-play:hover {
background: var(--accent-hover);
border-color: var(--accent-hover);
}
.btn-play.playing {
background: #333;
border-color: #555;
color: var(--text);
}
.btn-save {
color: var(--yellow);
border-color: #444;
}
.btn-save:hover {
background: #2a2a00;
border-color: var(--yellow);
}
.btn-sm {
font-size: 0.78rem;
padding: 0.25rem 0.5rem;
}
.btn-primary {
background: var(--accent);
border-color: var(--accent);
color: #fff;
}
.btn-primary:hover {
background: var(--accent-hover);
}
.btn-danger {
background: #300;
border-color: #700;
color: #faa;
}
.btn-danger:hover {
background: #500;
border-color: #a00;
color: #fff;
}
.btn-lastfm {
background: #d51007;
border-color: #d51007;
color: #fff;
display: inline-block;
padding: 0.4rem 1rem;
border-radius: var(--radius);
font-family: var(--font);
font-size: 0.9rem;
cursor: pointer;
border: 1px solid transparent;
}
.btn-lastfm:hover {
background: #ff1a0e;
color: #fff;
text-decoration: none;
}
.btn-full {
width: 100%;
padding: 0.55rem;
font-size: 0.95rem;
}
.btn-link {
background: none;
border: none;
color: var(--accent);
cursor: pointer;
font-family: var(--font);
font-size: 1rem;
padding: 0;
}
.btn-link:hover {
color: var(--accent-hover);
text-decoration: underline;
}
.btn-icon {
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
font-size: 1rem;
padding: 0;
line-height: 1;
}
.btn-icon.active {
color: var(--yellow);
}
.btn-icon:hover {
color: var(--yellow);
}
.inline-form {
display: inline;
}
/* =========================================================
AUTH FORMS
========================================================= */
.auth-container {
max-width: 400px;
margin: 3rem auto;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 2rem;
}
.auth-title {
font-size: 1.4rem;
margin-bottom: 1.5rem;
color: var(--text);
}
.auth-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.form-label {
font-size: 0.85rem;
color: var(--text-muted);
}
.auth-form input[type="text"],
.auth-form input[type="password"],
.auth-form input[type="email"] {
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text);
font-family: var(--font);
font-size: 0.9rem;
padding: 0.45rem 0.7rem;
outline: none;
width: 100%;
}
.auth-form input:focus {
border-color: var(--accent);
}
.field-errors {
list-style: none;
color: var(--accent);
font-size: 0.8rem;
}
.form-errors {
color: var(--accent);
font-size: 0.85rem;
background: #1a0000;
border: 1px solid #500;
border-radius: var(--radius);
padding: 0.5rem 0.75rem;
}
.field-help {
color: var(--text-muted);
font-size: 0.75rem;
}
.auth-switch {
margin-top: 1.25rem;
font-size: 0.85rem;
color: var(--text-muted);
text-align: center;
}
/* =========================================================
SETTINGS
========================================================= */
.settings-container {
max-width: 600px;
margin: 2rem auto;
}
.settings-title {
font-size: 1.4rem;
margin-bottom: 1.5rem;
}
.settings-section {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.25rem;
margin-bottom: 1.25rem;
}
.settings-section h2 {
font-size: 1rem;
color: var(--text-muted);
margin-bottom: 1rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.lastfm-description {
color: var(--text-muted);
font-size: 0.85rem;
margin-bottom: 0.75rem;
}
.connected-status {
margin-bottom: 0.75rem;
font-size: 0.9rem;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
font-size: 0.9rem;
}
.auth-prompt {
color: var(--text-muted);
padding: 1.5rem 0;
}
/* =========================================================
RESPONSIVE
========================================================= */
/* =========================================================
RECOMMENDATIONS
========================================================= */
.recommendations-section {
padding: 12px 16px 4px;
border-bottom: 1px solid #222;
}
.recommendations-context {
font-size: 0.75rem;
color: var(--fg);
margin: 0 0 8px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.recommendations-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.recommendations-list li {
display: flex;
align-items: center;
gap: 6px;
}
.muted {
color: var(--fg);
font-size: 0.8rem;
}
@media (max-width: 600px) {
.main-content {
padding: calc(var(--nav-h) + 3rem) 0.75rem calc(var(--bar-h) + 1.5rem);
}
#tabs {
padding: 0 0.25rem;
2026-03-16 19:19:22 +01:00
}
.now-playing-bar {
flex-direction: column;
height: auto;
padding: 0.5rem 0.75rem;
gap: 0.4rem;
}
.now-playing-info {
width: 100%;
}
.now-playing-controls {
width: 100%;
justify-content: space-between;
}
.volume-label,
.volume-slider,
.volume-num {
display: none;
2026-03-16 19:19:22 +01:00
}
.affiliate-section {
flex-direction: column;
align-items: flex-start;
}
.data-table th:nth-child(3),
.data-table td:nth-child(3),
.data-table th:nth-child(4),
.data-table td:nth-child(4) {
display: none;
}
.auth-container {
margin: 1rem;
padding: 1.25rem;
}
}
.import-bar {
padding: 8px 16px;
display: flex;
align-items: center;
gap: 10px;
border-bottom: 1px solid #1a1a1a;
}
/* =========================================================
TIMER WIDGET
========================================================= */
.timer-widget {
display: flex;
align-items: center;
gap: 6px;
font-variant-numeric: tabular-nums;
margin-left: 8px;
}
.timer-phase {
font-size: 0.7rem;
color: var(--fg);
text-transform: uppercase;
letter-spacing: 0.05em;
width: 36px;
text-align: right;
}
.timer-display {
font-size: 1rem;
font-weight: 600;
letter-spacing: 0.05em;
min-width: 48px;
}
/* =========================================================
DO NOT DISTURB / FOCUS MODE
========================================================= */
body.dnd-mode .navbar,
body.dnd-mode .tabs,
body.dnd-mode .tab-panel,
body.dnd-mode .affiliate-section {
display: none !important;
}
body.dnd-mode .now-playing-bar {
position: fixed;
inset: 0;
height: 100vh;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 24px;
background: transparent;
z-index: 9999;
}
body.dnd-mode.dnd-dark {
background: #000 !important;
background-image: none !important;
}
2026-03-16 19:19:22 +01:00
body.dnd-mode.dnd-dark .now-playing-bar {
background: #000;
}
.dnd-only {
display: none;
}
body.dnd-mode .dnd-only {
display: inline;
}
body.dnd-mode .now-playing-info {
text-align: center;
flex-direction: column;
gap: 12px;
}
body.dnd-mode .now-playing-station {
font-size: 1.6rem;
}
body.dnd-mode .now-playing-track {
font-size: 1rem;
color: var(--fg);
}
body.dnd-mode .timer-display {
font-size: 3.5rem;
}
/* =========================================================
MOOD CHIPS
========================================================= */
.mood-chips {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 8px 16px;
border-bottom: 1px solid #1a1a1a;
}
.mood-chip {
background: transparent;
border: 1px solid #333;
color: #ccc;
border-radius: 999px;
padding: 3px 12px;
font-size: 0.78rem;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.mood-chip:hover {
background: rgba(255, 255, 255, 0.05);
border-color: #555;
}
.focus-today {
font-size: 0.72rem;
color: var(--fg);
margin-left: 8px;
white-space: nowrap;
}
.curated-lists-container {
padding: 12px 16px 0;
}
.curated-section {
margin-bottom: 16px;
}
.curated-label {
font-size: 0.75rem;
color: var(--fg);
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 6px;
}
.curated-stations {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
.curated-stations li {
display: flex;
align-items: center;
gap: 8px;
}
.curated-name {
font-size: 0.85rem;
color: var(--fg);
}
.btn-delete-history {
background: none;
border: none;
color: var(--muted, #888);
cursor: pointer;
font-size: 0.75rem;
padding: 0 4px;
opacity: 0.5;
}
.btn-delete-history:hover { opacity: 1; color: #e55; }
#donation-hint {
position: fixed;
bottom: 24px;
right: 24px;
background: var(--surface, #1e1e2e);
border: 1px solid var(--border, #333);
border-radius: 8px;
padding: 12px 16px;
display: flex;
align-items: center;
gap: 12px;
font-size: 0.85rem;
box-shadow: 0 4px 16px rgba(0,0,0,0.4);
z-index: 999;
animation: hint-in 0.3s ease;
max-width: 320px;
}
#donation-hint.hiding {
animation: hint-out 0.4s ease forwards;
}
#donation-hint button {
background: none;
border: none;
cursor: pointer;
color: var(--muted, #888);
font-size: 0.8rem;
padding: 0;
flex-shrink: 0;
}
#donation-hint button:hover { color: var(--fg, #fff); }
@keyframes hint-in {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes hint-out {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(12px); }
}
.featured-section {
padding: 8px 0 12px;
border-bottom: 1px solid var(--border, #333);
margin-bottom: 12px;
}
.featured-label {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted, #888);
margin: 0 0 8px;
}
.featured-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 6px;
}
.featured-list li {
display: flex;
align-items: center;
gap: 8px;
}
.volume-num {
width: 44px;
background: var(--surface, #1e1e2e);
border: 1px solid var(--border, #333);
border-radius: 4px;
color: var(--fg, #fff);
font-size: 0.8rem;
padding: 2px 4px;
text-align: center;
}
.volume-num::-webkit-inner-spin-button,
.volume-num::-webkit-outer-spin-button { display: none; }
.volume-num { -moz-appearance: textfield; }
/* ===== PODCAST COMPONENTS ===== */
.podcast-seek-bar {
display: flex;
align-items: center;
gap: 6px;
padding: 0 12px;
flex: 1;
min-width: 0;
position: relative;
}
.skip-btn {
font-size: 0.72rem;
opacity: 0.8;
white-space: nowrap;
padding: 2px 4px;
}
.skip-btn:hover { opacity: 1; }
.speed-btns {
display: flex;
gap: 2px;
margin-left: 4px;
flex-shrink: 0;
}
.speed-btn {
background: none;
border: 1px solid var(--border, #444);
color: var(--fg, #fff);
border-radius: 3px;
font-size: 0.68rem;
padding: 1px 4px;
cursor: pointer;
opacity: 0.6;
white-space: nowrap;
}
.speed-btn:hover { opacity: 1; }
.speed-btn.active {
opacity: 1;
border-color: var(--accent, #e63946);
color: var(--accent, #e63946);
}
.seek-slider {
flex: 1;
accent-color: var(--accent, #e63946);
cursor: pointer;
height: 4px;
}
.seek-time {
font-size: 0.75rem;
color: var(--text-muted, #888);
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
.podcast-toolbar {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 8px 0 12px;
border-bottom: 1px solid var(--border, #333);
margin-bottom: 10px;
align-items: center;
}
.podcast-pane { }
.podcast-feed-list {
display: flex;
flex-direction: column;
gap: 6px;
}
.podcast-feed-item {
display: flex;
align-items: center;
gap: 10px;
padding: 6px 0;
border-bottom: 1px solid var(--border, #222);
}
.podcast-feed-info {
flex: 1;
min-width: 0;
}
.podcast-feed-title {
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.podcast-feed-actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
.podcast-thumb {
width: 48px;
height: 48px;
object-fit: cover;
border-radius: 4px;
flex-shrink: 0;
}
.podcast-thumb-lg {
width: 80px;
height: 80px;
object-fit: cover;
border-radius: 6px;
flex-shrink: 0;
}
.podcast-thumb-placeholder {
width: 48px;
height: 48px;
background: var(--surface, #1e1e2e);
border-radius: 4px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.podcast-unplayed-badge {
background: var(--accent, #e63946);
color: #fff;
border-radius: 99px;
padding: 1px 7px;
font-size: 0.7rem;
margin-left: 6px;
}
.episode-list {
display: flex;
flex-direction: column;
gap: 4px;
}
.episode-item {
display: flex;
align-items: center;
gap: 10px;
padding: 7px 0;
border-bottom: 1px solid var(--border, #222);
}
.episode-item.episode-played {
opacity: 0.5;
}
.episode-info {
flex: 1;
min-width: 0;
}
.episode-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.9rem;
}
.episode-actions {
display: flex;
gap: 4px;
flex-shrink: 0;
}
.podcast-search-list {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 10px;
}
.podcast-search-item {
display: flex;
align-items: center;
gap: 10px;
padding: 6px 0;
border-bottom: 1px solid var(--border, #222);
}
.podcast-search-info {
flex: 1;
min-width: 0;
}
.podcast-queue-ol {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
.podcast-feed-header {
margin-bottom: 12px;
}
.podcast-feed-header-inner {
display: flex;
align-items: center;
gap: 14px;
}
.feed-refresh-btn { margin-left: auto; flex-shrink: 0; }
/* Clickable episode title (episode list) */
.ep-clickable {
cursor: pointer;
}
.ep-clickable:hover {
color: var(--accent, #e63946);
text-decoration: underline;
}
/* Clickable episode title / feed name in the now-playing bar */
.podcast-track-link,
.podcast-station-link {
cursor: pointer;
}
.podcast-track-link:hover,
.podcast-station-link:hover {
color: var(--accent, #e63946);
text-decoration: underline;
}
/* ===== SIDEBAR ===== */
.sidebar-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 299;
}
.sidebar {
position: fixed;
top: 0;
right: 0;
width: 400px;
max-width: 100vw;
/* stop above the now-playing bar */
bottom: 72px;
background: var(--surface, #111);
border-left: 1px solid var(--border, #333);
z-index: 300;
display: flex;
flex-direction: column;
transform: translateX(100%);
transition: transform 0.22s ease;
overflow: hidden;
}
.sidebar.open {
transform: translateX(0);
}
.sidebar-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
padding: 14px 16px 10px;
border-bottom: 1px solid var(--border, #333);
flex-shrink: 0;
}
.sidebar-title {
font-weight: bold;
font-size: 0.95rem;
line-height: 1.3;
}
.sidebar-close {
flex-shrink: 0;
margin-top: -2px;
}
.sidebar-body {
flex: 1;
overflow-y: auto;
padding: 16px;
font-size: 0.88rem;
line-height: 1.6;
}
/* ===== MODAL DIALOG ===== */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.55);
z-index: 500;
}
.modal-dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--surface, #111);
border: 1px solid var(--border, #333);
border-radius: var(--radius);
padding: 20px;
width: 360px;
max-width: calc(100vw - 32px);
z-index: 501;
}
.modal-message {
margin: 0 0 16px;
white-space: pre-wrap;
line-height: 1.5;
}
.modal-input { width: 100%; margin-bottom: 16px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; }
/* Style links and basic HTML inside shownotes */
.sidebar-body a { color: var(--accent, #e63946); }
.sidebar-body p { margin: 0 0 10px; }
.sidebar-body ul, .sidebar-body ol { margin: 0 0 10px; padding-left: 20px; }
.sidebar-body h1, .sidebar-body h2, .sidebar-body h3 {
font-size: 0.9rem;
margin: 12px 0 4px;
}
/* Inbox toolbar + checkboxes */
.inbox-toolbar {
display: flex; align-items: center; gap: 8px;
padding: 0 0 8px; flex-wrap: wrap; min-height: 32px;
}
.inbox-select-all-label {
display: flex; align-items: center; gap: 4px;
font-size: 0.82rem; color: var(--text-muted, #888); cursor: pointer;
white-space: nowrap;
}
.inbox-bulk-actions {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.inbox-load-more {
display: flex; align-items: center; gap: 6px; margin-left: auto;
}
.inbox-checkbox-label {
display: flex; align-items: center; flex-shrink: 0;
padding-right: 4px; cursor: pointer;
}
.inbox-checkbox-label input[type="checkbox"] {
width: 15px; height: 15px; cursor: pointer; accent-color: var(--accent, #e63946);
}
.episode-item.inbox-selected { background: var(--surface-alt, #2a2a3e); }
/* Sleep timer */
.sleep-timer-btn {
font-size: 0.68rem; padding: 1px 5px; white-space: nowrap;
border: 1px solid var(--border, #444); border-radius: 3px; opacity: 0.7;
}
.sleep-timer-btn:hover { opacity: 1; }
.sleep-timer-menu {
position: absolute; background: var(--surface, #1e1e2e);
border: 1px solid var(--border, #444); border-radius: 6px; padding: 4px;
display: flex; flex-direction: column; gap: 2px; z-index: 200;
bottom: calc(100% + 4px); right: 0;
}
.sleep-timer-option {
background: none; border: none; color: var(--fg, #fff);
padding: 5px 12px; text-align: left; cursor: pointer;
font-size: 0.85rem; border-radius: 4px;
}
.sleep-timer-option:hover { background: var(--accent, #e63946); color: #fff; }
/* Episode filter */
.episode-search-bar { padding: 6px 0 8px; }
.episode-search-bar .search-input { width: 100%; box-sizing: border-box; }
/* Episode meta line */
.episode-meta {
display: flex; gap: 8px; font-size: 0.78rem;
color: var(--text-muted, #888); margin-top: 2px; flex-wrap: wrap;
}
.episode-date { font-weight: 500; color: var(--fg, #ccc); }
.episode-feed-link { cursor: pointer; }
.episode-feed-link:hover { text-decoration: underline; color: var(--accent, #e63946); }
.episode-dur { color: var(--text-muted, #888); }
/* Episode progress bar */
.episode-progress-bar {
height: 3px; background: var(--border, #333);
border-radius: 2px; margin-top: 5px; overflow: hidden;
}
.episode-progress-fill {
height: 100%; background: var(--accent, #e63946); border-radius: 2px;
}
/* Queue drag-and-drop */
.drag-handle { cursor: grab; color: var(--text-muted, #666); padding: 0 6px; user-select: none; }
.drag-handle:active { cursor: grabbing; }
#podcast-queue-ol li.dragging { opacity: 0.4; border: 1px dashed var(--accent, #e63946); }
/* Feed list toolbar */
.feed-list-toolbar {
display: flex; gap: 8px; align-items: center;
padding: 0 0 10px; flex-wrap: wrap;
}
.feed-list-toolbar .search-input { flex: 1; min-width: 140px; }
.feed-sort-select {
background: var(--surface, #1e1e2e); color: var(--fg, #fff);
border: 1px solid var(--border, #444); border-radius: 4px;
padding: 4px 6px; font-size: 0.82rem; cursor: pointer;
}
@media (max-width: 600px) {
.sidebar { width: 100vw; }
.podcast-seek-bar { padding: 0 6px; }
.podcast-thumb { width: 40px; height: 40px; }
.podcast-thumb-lg { width: 60px; height: 60px; }
.podcast-feed-actions { flex-direction: column; }
.episode-actions { flex-direction: column; }
/* Reader auf Mobile: Header kompakter, Fortschrittsfeld versteckt */
.reader-header { padding: 6px 8px; gap: 4px; }
.reader-title { font-size: 13px; }
.reader-header-actions { gap: 4px; }
.reader-progress-wrap { display: none; }
.reader-content { padding: 16px 10px; }
}
/* =========================================================
Ebook reader + book list + focus station
========================================================= */
/* --- Drop zone --- */
.book-drop-zone {
border: 2px dashed var(--border);
border-radius: var(--radius);
padding: 24px 16px;
text-align: center;
margin: 12px 0;
cursor: pointer;
transition: border-color 0.15s, background 0.15s;
display: flex;
flex-direction: column;
gap: 6px;
align-items: center;
}
.book-drop-zone:hover,
.book-drop-zone.drag-over {
border-color: var(--accent);
background: rgba(255,255,255,0.04);
}
.book-drop-zone label {
color: var(--accent);
cursor: pointer;
}
.enc-key-prompt {
padding: 24px 0 16px;
}
.offline-notice {
font-size: 13px;
color: var(--accent);
padding: 4px 0 8px;
}
.book-key-bar {
display: flex;
align-items: center;
gap: 8px;
margin-top: 1rem;
padding-top: 0.75rem;
border-top: 1px solid var(--border);
}
/* --- Book list --- */
.book-list {
display: flex;
flex-direction: column;
gap: 6px;
margin-top: 8px;
}
.book-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
border: 1px solid var(--border);
border-radius: var(--radius);
gap: 12px;
}
.book-item-info {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.book-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.book-author,
.book-progress {
font-size: 12px;
}
.book-item-actions {
display: flex;
gap: 6px;
flex-shrink: 0;
}
.book-read-badge {
font-size: 12px;
font-weight: normal;
}
.book-list-filter {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: var(--muted, #888);
margin-top: 10px;
cursor: pointer;
}
/* --- PDF pages --- */
.pdf-page-wrapper {
margin: 0 auto 1rem;
display: flex;
justify-content: center;
max-width: none;
}
.pdf-page {
display: block;
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}
/* --- Reader overlay --- */
.reader-overlay {
position: fixed;
top: var(--nav-h);
left: 0;
right: 0;
bottom: var(--bar-h);
background: var(--bg);
z-index: 200;
display: flex;
flex-direction: column;
Reader: Marker-Modus statt impliziter Auswahl, Notiz-Anker rein positional (SW v26) Vier vom Nutzer gemeldete Bugs behoben: - Markierter Text war kaum lesbar: der globale weiße Text-Outline (fürs Hintergrundbild-Feature gedacht) kollidierte mit der Highlight-Farbe. Reader sitzt immer auf eigenem, opakem Hintergrund — Outline dort komplett deaktiviert. - "Notiz zu Markierung hinzufügen" öffnete weiterhin die rechte Sidebar statt den Rand. Jeder Notiz-Eintragspunkt (Highlight+Notiz aus der Textauswahl, Edit-Note-Klick auf eine Markierung im Fließtext) läuft jetzt über _openMarginAndEditNote() — öffnet bei Bedarf den Rand und bearbeitet dort inline. openNoteEditor()/rechte Sidebar für Notizen komplett entfernt. - Kernursache für "Notiz verschwindet, Markierung heftet sich an falsche Notiz": Anker basierten auf XPath mit Sibling-Index unter den Textknoten eines Blocks — jede weitere Markierung im selben Block (surroundContents spaltet Textknoten) verschob diese Indizes und korrumpierte lautlos ALLE anderen Anker im selben Block. Anker adressieren jetzt stattdessen Block-Index + Zeichen-Offset innerhalb des Blocks (wie das bestehende Lesefortschritt-Ankersystem) — Wrapping/Unwrapping durch andere Markierungen ändert weder Blockreihenfolge noch Zeichenanzahl, ist also erschütterungsfrei für andere Anker im selben Block. - Löschen einer Markierung riss zuvor aus demselben Grund weiter unten liegende Notizen optisch mit raus (Daten blieben in der DB) — mit dem neuen Ankersystem behoben. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 13:28:19 +02:00
/* The global white text-outline (for readability over a custom background
image elsewhere in the app) is never needed here the reader always
sits on its own opaque background and it muddies highlighted text
badly when combined with a colored highlight background. */
text-shadow: none;
}
.reader-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
gap: 12px;
}
.reader-title {
font-weight: 700;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
}
.reader-header-actions {
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.reader-progress-wrap {
display: flex;
align-items: center;
gap: 4px;
}
.reader-content {
flex: 1;
overflow-y: scroll;
overflow-x: auto;
position: relative;
padding: 24px 16px;
line-height: 1.8;
font-family: Georgia, 'Times New Roman', serif;
font-size: 16px;
font-weight: 400;
}
.reader-content > * {
max-width: 65ch;
margin-left: auto;
margin-right: auto;
}
.reader-content p {
margin-bottom: 1em;
}
.reader-content h1, .reader-content h2, .reader-content h3 {
margin: 1.4em 0 0.6em;
font-family: var(--font);
}
/* --- Focus station sidebar --- */
/* --- Radio sidebar --- */
.rsb-nowplaying { margin-bottom: 12px; }
.rsb-station-name { font-weight: 600; }
.rsb-track { font-size: 0.85rem; margin-top: 2px; }
.rsb-controls { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.rsb-vol { display: flex; align-items: center; gap: 6px; font-size: 0.85rem; color: var(--muted, #888); }
.rsb-station-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
/* --- Table of contents sidebar --- */
.toc-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 2px;
}
.toc-entry {
display: block;
width: 100%;
text-align: left;
padding: 4px 0;
font-size: 13px;
white-space: normal;
word-break: break-word;
}
.toc-entry:hover {
color: var(--accent);
}
/* Focus station pending (playing interrupted) */
#focus-station-btn.focus-pending {
color: var(--accent);
animation: focus-pulse 1.4s ease-in-out infinite;
}
@keyframes focus-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
/* =========================================================
Reader feature additions
========================================================= */
/* Reader themes */
.reader-theme-sepia .reader-content { background:#f5e6c8; color:#3b2a1a; }
.reader-theme-bright .reader-content { background:#fff; color:#111; }
.reader-content > * { max-width:var(--reader-max-width,65ch); margin-left:auto; margin-right:auto; }
.reader-content > .pdf-page-wrapper { max-width: none; margin: 0 auto 1rem; }
/* Inline panels */
.reader-settings-panel, .reader-search-bar {
display:flex; align-items:center; gap:12px; padding:8px 16px;
border-bottom:1px solid var(--border); flex-shrink:0; flex-wrap:wrap; background:var(--bg);
}
.reader-settings-panel input[type="range"] { width:80px; }
/* PDF viewport wrapper — CSS zoom applied here for smooth zoom without re-render */
#pdf-viewport { transform-origin: top left; }
/* PDF inner container — shares origin with canvas so text layer aligns exactly */
.pdf-page-inner { position:relative; display:inline-block; line-height:0; }
/* PDF text layer — sits flush over the canvas inside pdf-page-inner */
.pdf-text-layer { position:absolute; top:0; left:0; width:100%; height:100%; overflow:hidden; pointer-events:none; }
.pdf-text-layer span { position:absolute; color:transparent !important; background:transparent; white-space:pre; cursor:text; pointer-events:auto; user-select:text; -webkit-user-select:text; line-height:1; }
.pdf-text-layer span::selection { background:rgba(0,120,255,0.3); }
.pdf-text-layer span.reader-search-match { background:rgba(241,196,15,.5); }
.pdf-text-layer span.reader-search-match.active { background:rgba(230,57,70,.6); }
/* PDF invert */
#reader-overlay.pdf-inverted .pdf-page { filter:invert(1); }
/* ---- Immersive reader mode ---- */
.navbar { transition: transform 0.35s ease; }
.now-playing-bar{ transition: transform 0.35s ease; }
.reader-overlay { transition: top 0.35s ease, bottom 0.35s ease; }
.reader-header { overflow: hidden; max-height: 60px;
transition: max-height 0.35s ease, padding-top 0.35s ease, padding-bottom 0.35s ease; }
body.reader-immersive .navbar { transform: translateY(-100%); }
body.reader-immersive .now-playing-bar { transform: translateY(100%); }
body.reader-immersive .reader-overlay { top: 0; bottom: 0; }
body.reader-immersive .reader-header { max-height: 0; padding-top: 0; padding-bottom: 0; }
body.reader-immersive.reader-show-top .navbar { transform: none; }
body.reader-immersive.reader-show-top .reader-overlay { top: var(--nav-h); }
body.reader-immersive.reader-show-top .reader-header { max-height: 60px; padding-top: 8px; padding-bottom: 8px; }
body.reader-immersive.reader-show-bottom .now-playing-bar { transform: none; }
body.reader-immersive.reader-show-bottom .reader-overlay { bottom: var(--bar-h); }
/* PDF paginated */
.reader-content.pdf-paginated { overflow:hidden !important; display:flex; align-items:center; justify-content:center; }
.pdf-paginated .pdf-page-wrapper { margin:0; }
/* PDF loading overlay */
.pdf-loading-overlay {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(20, 20, 20, 0.85);
z-index: 200;
}
.pdf-loading-spinner {
width: 36px;
height: 36px;
border: 3px solid #333;
border-top-color: var(--accent, #e63946);
border-radius: 50%;
animation: pdf-spin 0.7s linear infinite;
}
@keyframes pdf-spin { to { transform: rotate(360deg); } }
/* PDF two-page spread */
.pdf-spread-wrapper { display:flex; flex-direction:row; gap:8px; justify-content:center; margin-bottom:1rem; }
.pdf-spread-wrapper .pdf-page-wrapper { margin:0; }
.pdf-spread-cover { margin-bottom:1rem; }
/* Disable text selection during pinch */
#reader-content.pinch-active { user-select:none; -webkit-user-select:none; }
/* Highlight popover */
.highlight-popover { position:fixed; z-index:500; display:flex; gap:6px; background:var(--bg-card,#1a1a1a); border:1px solid var(--border); border-radius:var(--radius); padding:6px 8px; box-shadow:0 4px 16px rgba(0,0,0,.5); }
.hl-color-btn { width:24px; height:24px; border-radius:50%; border:2px solid transparent; cursor:pointer; font-weight:700; font-size:12px; color:#000; line-height:1; }
.hl-color-btn:hover { border-color:#fff; }
.hl-note-btn { background:none; border:1px solid var(--border); color:var(--fg); padding:2px 6px; border-radius:var(--radius); cursor:pointer; }
/* Footnote popover */
.footnote-popover { position:fixed; z-index:500; max-width:min(400px,90vw); max-height:220px; overflow-y:auto; background:#1a1a1a; color:#e8e8e8; border:1px solid #444; border-radius:var(--radius); padding:10px 28px 10px 12px; box-shadow:0 4px 20px rgba(0,0,0,.6); font-size:0.88em; line-height:1.55; pointer-events:auto; }
.footnote-popover.reader-theme-sepia { background:#ede0c4; color:#3b2a1a; border-color:#c8b89a; }
.footnote-popover.reader-theme-bright { background:#f0f0f0; color:#111; border-color:#bbb; }
.footnote-popover-close { position:absolute; top:4px; right:6px; background:none; border:none; color:inherit; opacity:0.5; cursor:pointer; font-size:14px; padding:2px 4px; line-height:1; }
/* Highlight marks */
.reader-no-bold * { font-weight: normal !important; }
.reader-content img { max-width: 100%; height: auto; display: block; }
/* color:inherit overrides the browser's UA-default `mark { color: black }`
without it, highlighted text abruptly flips to black regardless of the
reader theme's own text color (jarring on the default dark theme, whose
body text is white). Inheriting keeps highlighted text the same color as
the text around it in every theme; the background tones below are chosen
dark/saturated enough to stay readable specifically against white text. */
.epub-highlight { border-radius:2px; cursor:pointer; color:inherit; }
.epub-highlight[data-color="yellow"] { background:rgba(184,134,11,.55); }
.epub-highlight[data-color="green"] { background:rgba(30,140,90,.55); }
.epub-highlight[data-color="blue"] { background:rgba(41,110,180,.55); }
.epub-highlight[data-color="red"] { background:rgba(190,50,60,.55); }
/* Margin ("page margin") panel left of the reader content. Highlights without
a note show as a small color dot; anything with note text (freeform notes or
a highlight+note) shows as a readable little "post-it" card, positioned next
to the text height it belongs to. Click empty space to place a new freeform
note anchored to that line. Freeform notes have NO in-text mark the anchor
is purely positional, only ever visible here in the margin. */
.reader-body-row { display:flex; flex:1; min-height:0; }
.reader-margin {
width:0; flex-shrink:0; overflow:hidden;
display:flex; flex-direction:column;
border-right:1px solid var(--border); background:var(--bg);
transition:width 0.25s ease;
}
.reader-margin.open { width:220px; }
.reader-margin-header {
display:none; align-items:center; justify-content:space-between;
padding:6px 8px; border-bottom:1px solid var(--border); white-space:nowrap; flex-shrink:0;
}
.reader-margin.open .reader-margin-header { display:flex; }
.reader-margin-title { font-size:11px; text-transform:uppercase; letter-spacing:.04em; color:var(--muted,#888); }
.reader-margin-header-actions { display:flex; align-items:center; gap:6px; }
.reader-margin-markers { position:relative; flex:1; overflow-y:auto; overflow-x:hidden; cursor:crosshair; }
.margin-note { position:absolute; left:8px; right:8px; cursor:pointer; }
.margin-note-dot { left:8px; right:auto; width:12px; height:12px; border-radius:50%; }
.margin-note-dot[data-color="yellow"] { background:rgba(241,196,15,.85); }
.margin-note-dot[data-color="green"] { background:rgba(46,204,113,.85); }
.margin-note-dot[data-color="blue"] { background:rgba(52,152,219,.85); }
.margin-note-dot[data-color="red"] { background:rgba(230,57,70,.85); }
.margin-note-text {
font-size:11px; line-height:1.4; padding:5px 7px; border-radius:3px;
background:var(--bg-card,#1a1a1a); border-left:3px solid var(--muted,#888);
box-shadow:1px 2px 5px rgba(0,0,0,.3);
white-space:pre-wrap; word-break:break-word;
}
.margin-note-text[data-color="yellow"] { border-left-color:#f1c40f; }
.margin-note-text[data-color="green"] { border-left-color:#2ecc71; }
.margin-note-text[data-color="blue"] { border-left-color:#3498db; }
.margin-note-text[data-color="red"] { border-left-color:#e63946; }
/* Freeform notes get a paper-like tint, like a post-it note pinned to the text */
.margin-note-text.margin-note-freeform {
border-left-color:#e6c229; background:rgba(241,196,15,.13);
}
/* Inline note editor appears right where the note lives in the margin, so
setting/editing a note never means jumping to a separate panel */
.margin-note-editor { position:absolute; left:8px; right:8px; z-index:1; }
.margin-note-textarea {
width:100%; min-height:52px; font-size:11px; line-height:1.4; padding:5px 7px;
border-radius:3px; border:1px solid var(--accent,#e63946);
background:var(--bg-card,#1a1a1a); color:var(--fg,#eee);
box-shadow:1px 2px 5px rgba(0,0,0,.4); resize:vertical;
}
@media (max-width: 600px) {
.reader-margin.open { width:150px; }
.reader-margin-title { display:none; }
}
/* Search matches */
mark.reader-search-match { background:rgba(241,196,15,.6); color:inherit; border-radius:2px; }
mark.reader-search-match.active { background:rgba(230,57,70,.7); }
#rs-search-count { font-size:12px; min-width:50px; }
/* Bookmarks sidebar */
.bookmark-entry { display:flex; width:100%; padding:6px 0; font-size:13px; justify-content:space-between; border-bottom:1px solid var(--border); }
/* Toast */
.reader-toast { position:fixed; bottom:calc(var(--bar-h) + 16px); left:50%; transform:translateX(-50%); background:var(--fg); color:var(--bg); padding:6px 14px; border-radius:var(--radius); font-size:13px; z-index:600; animation:toast-fade 2s ease forwards; pointer-events:none; }
@keyframes toast-fade { 0%,70%{opacity:1} 100%{opacity:0} }
.reader-toast-action { display:flex; align-items:center; gap:10px; padding:8px 8px 8px 14px; animation:toast-slide-up 0.2s ease forwards; pointer-events:auto; }
.reader-toast-btn { background:var(--accent,#e63946); color:#fff; border:none; border-radius:calc(var(--radius) - 2px); padding:5px 12px; font-size:13px; font-weight:600; cursor:pointer; white-space:nowrap; }
.reader-toast-btn:hover { filter:brightness(1.1); }
@keyframes toast-slide-up { 0%{opacity:0; transform:translate(-50%, 8px);} 100%{opacity:1; transform:translate(-50%, 0);} }
.build-time {
position: fixed;
bottom: 4px;
right: 6px;
font-size: 0.65rem;
color: #444;
pointer-events: none;
z-index: 1;
}