.navbar { display: grid; grid-template-rows: auto 1fr; height: 100%; min-height: 0; background: var(--background-secondary); overflow: hidden; user-select: none; -webkit-user-select: none; } .header { display: flex; align-items: center; gap: var(--spacing-1); width: 100%; min-height: var(--layout-header-height, 3.5rem); padding: 0 var(--spacing-4); font-weight: 600; font-size: 1rem; font-family: inherit; text-align: left; border: none; border-bottom: 1px solid var(--user-area-divider-color); background: var(--background-secondary); cursor: pointer; color: var(--text-primary); flex-shrink: 0; transition: background-color var(--transition-normal); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .header:hover { background-color: var(--background-modifier-hover); } .serverName { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.25rem; max-height: 1.25rem; } .headerCaret { margin-left: auto; flex-shrink: 0; height: 1rem; width: 1rem; transition: transform 0.15s ease; } .headerCaretOpen { transform: rotate(180deg); } .header { cursor: pointer; transition: background-color 0.15s ease; } .header:hover { background-color: color-mix(in srgb, var(--text-primary) 3%, transparent); } .headerOpen { background-color: color-mix(in srgb, var(--text-primary) 5%, transparent); } .channelList { flex: 1; overflow-y: auto; padding-right: var(--spacing-2); background-color: var(--background-secondary); /* Hide the scrollbar but keep scrolling. Firefox + IE first, then the WebKit pseudo-element so it disappears in Chrome / Safari / Edge / Electron without losing wheel + drag scroll. */ scrollbar-width: none; -ms-overflow-style: none; } .channelList::-webkit-scrollbar { display: none; } /* ── Categories ──────────────────────────────────────────────────────── */ .category { display: flex; flex-direction: column; gap: 1px; } .category + .category { margin-top: var(--spacing-1); } .categoryRow { display: flex; align-items: center; margin-left: 0.5rem; margin-right: 0; margin-top: 0.25rem; } .categoryHeader { position: relative; display: flex; align-items: center; gap: 0.25rem; flex: 1; min-width: 0; padding: 0.375rem 0.5rem; background: none; border: none; cursor: pointer; color: var(--text-tertiary-muted, var(--text-muted)); font-size: 0.875rem; font-weight: 600; line-height: 1.25rem; text-align: left; font-family: inherit; border-radius: 0.375rem; transition: color 0.15s ease; } .categoryHeader:hover { color: var(--text-primary); } .categoryAddButton { display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; margin-right: 0.5rem; background: none; border: none; border-radius: 4px; cursor: pointer; color: var(--text-tertiary-muted, var(--text-muted)); opacity: 0; transition: opacity 0.15s, color 0.15s, background-color 0.15s; } .categoryRow:hover .categoryAddButton { opacity: 1; } .categoryAddButton:hover { color: var(--text-primary); background-color: color-mix(in srgb, var(--text-primary) 10%, transparent); } .categoryName { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-height: 1.25rem; } .categoryChevron { height: 0.75rem; width: 0.75rem; flex-shrink: 0; transition: transform 0.2s ease; } .categoryCollapsed .categoryChevron, .categoryChevronCollapsed { transform: rotate(-90deg); } /* ── Channel Items ───────────────────────────────────────────────────── */ .channelItem { position: relative; margin-left: 0.5rem; margin-right: 0; display: flex; align-items: center; gap: 0.375rem; width: calc(100% - 0.5rem); padding: 0.375rem 0.5rem; border-radius: 0.375rem; background: none; border: none; cursor: pointer; color: var(--text-tertiary-muted, var(--text-muted)); font-size: 1rem; line-height: 1.25rem; text-align: left; font-family: inherit; transition: background-color 0.1s ease, color 0.1s ease; } .channelItem:hover { background-color: var(--background-modifier-hover); color: var(--text-chat, var(--text-secondary)); } .channelItem:hover .channelName { color: var(--text-chat, var(--text-secondary)); } .channelSelected { background-color: var(--background-modifier-selected) !important; color: var(--text-primary) !important; } .channelSelected .channelName, .channelSelected .channelIcon { color: var(--text-primary) !important; } .channelIcon { width: 1.25rem; height: 1.25rem; flex-shrink: 0; color: var(--text-tertiary-muted); } .channelName { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; font-size: 1rem; line-height: 1.25rem; max-height: 1.25rem; min-width: 0; } .channelUnread { color: var(--text-primary) !important; font-weight: 600; } /* ── Unread Indicators ───────────────────────────────────────────────── */ .channelItemUnread { position: relative; } .channelItemUnread::before { content: ""; position: absolute; left: -0.25rem; top: 50%; transform: translateY(-50%); height: 0.5rem; width: 0.5rem; border-radius: 0 9999px 9999px 0; background-color: var(--text-primary); } .unreadBadge { flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; background-color: var(--text-primary); margin-left: auto; } .mentionBadge { flex-shrink: 0; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background-color: var(--status-danger); color: #fff; font-size: 0.75rem; font-weight: 700; display: flex; align-items: center; justify-content: center; margin-left: auto; } /* ── Hover-reveal channel settings gear ────────────────────────────── The wrapper holds both the channel button and the gear button as siblings (nesting interactive elements inside a button is invalid HTML). The gear is absolute-positioned at the right edge of the row and hidden by default. Visibility rules, mirroring Fluxer's ChannelItem.module.css: - display: none by default - display: flex when the wrapper is hovered on desktop (hover: hover) - display: flex when the channel is selected (data-selected='true') On hover or select, the unread/mention badges are hidden so the gear takes their place — same pattern Discord uses. */ .channelItemWrapper { position: relative; min-width: 0; overflow: hidden; } .channelSettingsGear { display: none; position: absolute; right: 10px; top: 6px; width: 24px; height: 24px; align-items: center; justify-content: center; padding: 0; background: transparent; border: none; border-radius: 4px; color: var(--text-tertiary-muted, var(--text-muted)); cursor: pointer; transition: color 0.15s ease, background-color 0.15s ease; z-index: 2; } .channelSettingsGear:hover { color: var(--text-primary); background-color: color-mix(in srgb, var(--text-primary) 10%, transparent); } .channelItemWrapper[data-selected="true"] .channelSettingsGear { display: flex; color: var(--text-primary); } .channelItemWrapper[data-selected="true"] .channelItem { padding-right: 2.25rem; } @media (hover: hover) and (pointer: fine) { .channelItemWrapper:hover .channelSettingsGear { display: flex; } .channelItemWrapper:hover .channelItem { padding-right: 2.25rem; } .channelItemWrapper:hover .mentionBadge, .channelItemWrapper:hover .unreadBadge { display: none; } } .channelItemWrapper[data-selected="true"] .mentionBadge, .channelItemWrapper[data-selected="true"] .unreadBadge { display: none; } /* ── Voice Channel Styles ────────────────────────────────────────────── */ .voiceUsers { display: flex; flex-direction: column; gap: 1px; padding-left: 2rem; margin-top: 2px; } .voiceUser { display: flex; align-items: center; gap: 0.375rem; padding: 0.25rem 0.5rem; border-radius: 0.375rem; font-size: 0.875rem; font-weight: 500; line-height: 1.25rem; color: var(--text-primary-muted); cursor: pointer; transition: background-color 150ms, color 150ms; } .voiceUser:hover { background-color: var(--background-modifier-hover); color: var(--text-primary); } .voiceUserAvatar { width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0; } .voiceUserName { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ── Drag-and-drop: drop indicator + overlay ─────────────────── */ .dropIndicator { height: 2px; margin: 0 8px; border-radius: 1px; background: var(--brand-primary); position: relative; } .dropIndicator::before, .dropIndicator::after { content: ""; position: absolute; top: -3px; width: 8px; height: 8px; border-radius: 50%; background: var(--brand-primary); } .dropIndicator::before { left: -4px; } .dropIndicator::after { right: -4px; } .dragOverlay { display: flex; align-items: center; gap: 6px; padding: 6px 10px; border-radius: 6px; background: var(--background-secondary); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); color: var(--text-primary); font-size: 0.9375rem; font-weight: 500; pointer-events: none; white-space: nowrap; } /* ── Light theme overrides ──────────────────────────────────── In light theme every channel name and category name reads as --text-primary across default / hover / selected / unread so the sidebar labels stay high-contrast against the near-white background instead of fading to the muted tertiary shade. */ [data-theme="light"] .channelItem, [data-theme="light"] .channelItem:hover, [data-theme="light"] .channelItem:hover .channelName, [data-theme="light"] .channelItem .channelIcon, [data-theme="light"] .categoryHeader, [data-theme="light"] .categoryHeader .categoryChevron { color: var(--text-primary); }