mirror of
https://github.com/ancsemi/Haven.git
synced 2026-10-26 16:45:16 +00:00
990 lines
26 KiB
CSS
990 lines
26 KiB
CSS
/* Haven core styles, part 10 of 16: the Settings layout, games, toggles and desktop app preferences. Loaded in order by style.css; the order matters. */
|
|
/* ── Settings Layout (Nav + Body) ─────────────────────── */
|
|
.settings-layout {
|
|
display: flex;
|
|
min-height: 0;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.settings-nav {
|
|
width: 10.75rem; /* 172px at Normal; scales so labels don't wrap when the font grows */
|
|
min-width: 10.75rem;
|
|
padding: 0.5rem 0 0.5rem 0.5rem;
|
|
overflow-y: auto;
|
|
border-right: 1px solid var(--border);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.settings-nav-group {
|
|
font-size: 0.625rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: var(--text-muted);
|
|
padding: 0.625rem 0.625rem 0.25rem;
|
|
user-select: none;
|
|
}
|
|
|
|
.settings-nav-item {
|
|
padding: 0.3125rem 0.625rem;
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
border-radius: var(--radius-sm);
|
|
cursor: pointer;
|
|
margin-bottom: 0.0625rem;
|
|
/* Wrap rather than truncate. The nav is a fixed width the user can't drag,
|
|
so an ellipsis here is unrecoverable: there is no way to reveal the rest
|
|
of the label. Two short lines beat "Activity & Conne…".
|
|
The hanging indent keeps a wrapped second line aligned with the text
|
|
instead of starting underneath the leading emoji. */
|
|
white-space: normal;
|
|
overflow-wrap: break-word;
|
|
line-height: 1.3;
|
|
padding-left: 1.625rem;
|
|
text-indent: -16px;
|
|
transition: background 0.15s, color 0.15s;
|
|
}
|
|
|
|
.settings-nav-item:hover {
|
|
background: var(--bg-tertiary);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
/* Section headers in the settings nav. Not clickable; they exist so ~20 flat
|
|
entries read as five short groups instead of one long list. */
|
|
.settings-nav-group-label {
|
|
font-size: 0.5625rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.07em;
|
|
color: var(--text-muted);
|
|
padding: 0.625rem 0.625rem 0.1875rem;
|
|
margin-top: 0.125rem;
|
|
user-select: none;
|
|
pointer-events: none;
|
|
}
|
|
.settings-nav-group-label:first-child { margin-top: 0; padding-top: 0.125rem; }
|
|
|
|
.settings-nav-item.active {
|
|
background: var(--accent);
|
|
color: var(--accent-text);
|
|
}
|
|
|
|
.settings-nav-group.settings-nav-admin {
|
|
margin-top: 0.25rem;
|
|
padding-top: 0.5rem;
|
|
border-top: 2px solid var(--accent);
|
|
color: var(--accent);
|
|
}
|
|
|
|
.settings-body {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 0;
|
|
min-width: 0;
|
|
}
|
|
|
|
.modal-settings {
|
|
/* Opens at the original 640px. `resize: both` gives a drag handle, but
|
|
max-width is what actually caps it. It used to be 640px too, so dragging
|
|
stopped dead at the default size. Raising only max-width keeps the
|
|
familiar default while letting the handle go somewhere. */
|
|
width: min(40rem, 92vw); /* 640px at Normal; scales with the font setting */
|
|
max-width: min(1200px, 95vw);
|
|
min-width: 26.25rem; /* 420px at Normal */
|
|
max-height: 85vh;
|
|
min-height: 20rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
padding: 0;
|
|
resize: both;
|
|
}
|
|
|
|
/* ── Activities / Games Launcher ──────────────────────── */
|
|
.modal-activities {
|
|
max-width: 32.5rem;
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
padding: 0;
|
|
}
|
|
.activities-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 1.25rem 1.5rem 0.75rem;
|
|
position: sticky;
|
|
top: 0;
|
|
background: var(--bg-card);
|
|
z-index: 10;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.activities-header h3 {
|
|
font-size: 1.125rem;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
margin: 0;
|
|
}
|
|
/* The injected expand button sits beside the close button, not in the
|
|
middle of the space-between header (#5718). */
|
|
.activities-header > .modal-expand-btn-inline { margin-left: auto; }
|
|
.activities-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
|
gap: 0.75rem;
|
|
padding: 1rem 1.5rem 1.5rem;
|
|
}
|
|
.activity-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 1rem 0.625rem;
|
|
border-radius: 0.5rem;
|
|
background: var(--bg-secondary);
|
|
border: 1px solid var(--border);
|
|
cursor: pointer;
|
|
transition: all 0.15s ease;
|
|
text-align: center;
|
|
}
|
|
.activity-card:hover {
|
|
background: var(--bg-hover);
|
|
border-color: var(--accent);
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
}
|
|
.activity-card-icon {
|
|
font-size: 2.25rem;
|
|
line-height: 1;
|
|
}
|
|
.activity-card-name {
|
|
font-size: 0.8125rem;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
}
|
|
.activity-card-desc {
|
|
font-size: 0.6875rem;
|
|
color: var(--text-muted);
|
|
line-height: 1.3;
|
|
}
|
|
.activity-card-disabled {
|
|
opacity: 0.45;
|
|
cursor: not-allowed;
|
|
pointer-events: none;
|
|
}
|
|
.flash-install-banner {
|
|
grid-column: 1 / -1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 0.75rem;
|
|
padding: 0.625rem 1rem;
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-md);
|
|
font-size: 0.8125rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
.flash-install-banner .btn-sm { pointer-events: auto; flex-shrink: 0; }
|
|
.flash-install-note { color: var(--text-muted); font-style: italic; flex-shrink: 0; }
|
|
|
|
/* ── Iframe Game Overlay ──────────────────────────────── */
|
|
.game-iframe-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 10000;
|
|
background: var(--bg-primary);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.game-iframe-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 1rem;
|
|
background: var(--bg-secondary);
|
|
border-bottom: 1px solid var(--border);
|
|
flex-shrink: 0;
|
|
}
|
|
.game-iframe-title {
|
|
font-size: 0.875rem;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
}
|
|
.game-iframe-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
.game-iframe {
|
|
flex: 1;
|
|
width: 100%;
|
|
border: none;
|
|
background: var(--bg-primary);
|
|
}
|
|
|
|
/* Win95 overrides for activities */
|
|
[data-theme="win95"] .modal-activities { background: #bfbfbf; border: 3px outset #fff; border-radius: 0; }
|
|
[data-theme="win95"] .activities-header { background: linear-gradient(90deg, #000080, #1084d0); padding: 0.25rem 0.5rem; border-bottom: none; }
|
|
[data-theme="win95"] .activities-header h3 { color: #fff; font-size: 0.75rem; font-weight: 700; margin: 0; background: none; font-family: "MS Sans Serif","Microsoft Sans Serif",Tahoma,Arial,sans-serif, var(--font-emoji); }
|
|
[data-theme="win95"] .activity-card { background: #bfbfbf; border: 3px outset #fff; border-radius: 0; }
|
|
[data-theme="win95"] .activity-card:hover { border: 3px inset #808080; transform: none; box-shadow: none; }
|
|
[data-theme="win95"] .game-iframe-header { background: linear-gradient(90deg, #000080, #1084d0); border-bottom: 2px solid #808080; }
|
|
[data-theme="win95"] .game-iframe-title { color: #fff; font-family: "MS Sans Serif","Microsoft Sans Serif",Tahoma,Arial,sans-serif, var(--font-emoji); font-size: 0.75rem; }
|
|
|
|
.settings-section {
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.settings-section:last-child { border-bottom: none; }
|
|
|
|
.settings-subsection { margin-top: 0.6rem; }
|
|
|
|
/* ── Admin section divider ── */
|
|
.admin-section-divider {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
margin: 0.5rem 0 1rem;
|
|
}
|
|
.admin-divider-line {
|
|
flex: 1;
|
|
height: 0.125rem;
|
|
background: linear-gradient(90deg, transparent, var(--accent), transparent);
|
|
}
|
|
.admin-divider-label {
|
|
font-size: 0.75rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1.5px;
|
|
color: var(--accent);
|
|
white-space: nowrap;
|
|
}
|
|
.admin-save-notice {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
background: rgba(var(--accent-rgb, 124,58,237), 0.12);
|
|
border: 1px solid rgba(var(--accent-rgb, 124,58,237), 0.3);
|
|
border-radius: 0.5rem;
|
|
padding: 0.5rem 0.875rem;
|
|
margin-bottom: 1rem;
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.settings-section-title {
|
|
font-size: 0.875rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 0.875rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 2px solid var(--border);
|
|
}
|
|
|
|
.settings-section-subtitle {
|
|
font-size: 0.8125rem;
|
|
font-weight: 600;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 0.625rem;
|
|
margin-top: 1rem;
|
|
padding-bottom: 0.375rem;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
/* ── Plugin & Theme Cards ── */
|
|
.plugin-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.375rem;
|
|
}
|
|
.plugin-card {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.625rem 0.75rem;
|
|
background: var(--bg-tertiary, rgba(255,255,255,0.04));
|
|
border: 1px solid var(--border, rgba(255,255,255,0.08));
|
|
border-radius: 0.5rem;
|
|
transition: background 0.15s;
|
|
}
|
|
.plugin-card:hover { background: var(--bg-hover, rgba(255,255,255,0.06)); }
|
|
.plugin-card-info { flex: 1; min-width: 0; }
|
|
.plugin-card-name {
|
|
font-weight: 600;
|
|
font-size: 0.8125rem;
|
|
color: var(--text-primary);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.plugin-card-desc {
|
|
font-size: 0.6875rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 0.125rem;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.plugin-card-meta {
|
|
font-size: 0.625rem;
|
|
color: var(--text-muted);
|
|
margin-top: 0.125rem;
|
|
}
|
|
#extension-update-results .plugin-card {
|
|
align-items: stretch;
|
|
flex-direction: column;
|
|
}
|
|
.extension-update-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: 0.375rem;
|
|
margin-top: 0.625rem;
|
|
}
|
|
.extension-update-actions .btn-sm {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
font-size: 0.75rem;
|
|
min-height: 2rem;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
}
|
|
@media (max-width: 600px) {
|
|
.extension-update-actions {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
}
|
|
#extension-update-results .extension-update-actions > .btn-sm {
|
|
justify-content: center;
|
|
min-width: 0;
|
|
width: 100%;
|
|
white-space: normal;
|
|
}
|
|
}
|
|
.plugin-empty {
|
|
font-size: 0.75rem;
|
|
color: var(--text-muted);
|
|
padding: 0.5rem 0;
|
|
}
|
|
.plugin-empty code {
|
|
background: var(--bg-tertiary);
|
|
padding: 0.0625rem 0.25rem;
|
|
border-radius: 0.1875rem;
|
|
font-size: 0.6875rem;
|
|
}
|
|
/* Plugin and theme on/off switch. Same size, colours and knob travel as
|
|
the settings switches in style-presence-connections.css, all in rem so the
|
|
knob stays inside the track at every interface scale. */
|
|
.plugin-toggle {
|
|
position: relative;
|
|
display: inline-block;
|
|
width: 2.125rem;
|
|
height: 1.25rem;
|
|
flex-shrink: 0;
|
|
margin-left: 0.75rem;
|
|
}
|
|
.plugin-toggle input {
|
|
position: absolute;
|
|
opacity: 0;
|
|
width: 0;
|
|
height: 0;
|
|
margin: 0;
|
|
}
|
|
.plugin-toggle-slider {
|
|
position: absolute;
|
|
cursor: pointer;
|
|
inset: 0;
|
|
background: var(--bg-tertiary);
|
|
box-shadow: inset 0 0 0 1px var(--border);
|
|
border-radius: 0.625rem;
|
|
transition: background 0.18s ease, box-shadow 0.18s ease;
|
|
}
|
|
.plugin-toggle-slider::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0.125rem;
|
|
left: 0.125rem;
|
|
width: 1rem;
|
|
height: 1rem;
|
|
background: var(--text-muted);
|
|
border-radius: 50%;
|
|
transition: left 0.18s ease, background 0.18s ease;
|
|
}
|
|
.plugin-toggle input:checked + .plugin-toggle-slider {
|
|
background: var(--accent);
|
|
box-shadow: inset 0 0 0 1px var(--accent);
|
|
}
|
|
.plugin-toggle input:checked + .plugin-toggle-slider::before {
|
|
left: 1rem;
|
|
background: #fff;
|
|
}
|
|
.plugin-toggle input:focus-visible + .plugin-toggle-slider {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 2px;
|
|
}
|
|
.plugin-toggle input:disabled + .plugin-toggle-slider {
|
|
opacity: 0.45;
|
|
cursor: not-allowed;
|
|
}
|
|
/* Classic checkboxes (Settings > Toggle style) and Win95 show a plain box
|
|
here too, like every other on/off setting. */
|
|
:root[data-toggle-style="box"] .plugin-toggle,
|
|
[data-theme="win95"] .plugin-toggle {
|
|
width: auto;
|
|
height: auto;
|
|
}
|
|
:root[data-toggle-style="box"] .plugin-toggle input,
|
|
[data-theme="win95"] .plugin-toggle input {
|
|
position: static;
|
|
opacity: 1;
|
|
width: 1rem;
|
|
height: 1rem;
|
|
cursor: pointer;
|
|
}
|
|
:root[data-toggle-style="box"] .plugin-toggle-slider,
|
|
[data-theme="win95"] .plugin-toggle-slider {
|
|
display: none;
|
|
}
|
|
|
|
/* One size for every number box in settings, with room for five digits
|
|
and the spin arrows, and a little space before the value. */
|
|
.settings-number-input {
|
|
box-sizing: border-box;
|
|
width: 5.5rem;
|
|
padding: 0.25rem 0.25rem 0.25rem 0.5rem;
|
|
background: var(--bg-input);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0.25rem;
|
|
color: var(--text-primary);
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.settings-number-input:focus { outline: none; border-color: var(--accent); }
|
|
|
|
.settings-hint {
|
|
color: var(--text-muted);
|
|
font-size: 0.625rem;
|
|
display: block;
|
|
/* Was -2px, which tucked the hint up into the row above. That was invisible
|
|
next to a 16px checkbox but collides with a 20px switch. */
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* A hint sits under its control row but spans the full panel width, so its
|
|
text used to run underneath the control on the right. Reserve that column so
|
|
the text wraps before reaching it instead of sliding under it. */
|
|
.toggle-row + .settings-hint,
|
|
.select-row + .settings-hint,
|
|
.checkbox-row + .settings-hint,
|
|
/* A slider's value, as a percent or in dB (app-master-volume.js). */
|
|
.vol-readout { flex: 0 0 4.2rem; text-align: right; font-size: 0.72rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
|
|
.volume-row:has(> .vol-readout) > input[type="range"] { margin-left: auto; }
|
|
.volume-row + .settings-hint {
|
|
padding-right: 2.75rem; /* 44px */
|
|
}
|
|
.settings-hint.error { color: #e94560; }
|
|
.settings-hint.success { color: #43b581; }
|
|
/* Invite Links closes out the Server Invite Code section, so it carries a
|
|
divider. For someone holding only invite_users the rest of that section is
|
|
hidden and the block stands alone, leaving a rule with nothing above it to
|
|
separate; .invite-links-flush drops it. (#5470) */
|
|
#invite-links-block {
|
|
margin-top: 18px;
|
|
padding-top: 12px;
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
#invite-links-block.invite-links-flush {
|
|
margin-top: 0;
|
|
padding-top: 0;
|
|
border-top: none;
|
|
}
|
|
#invite-new-expiry { width: 6.5rem }
|
|
|
|
/* Note on a setting that also has a value in the server's environment, so the
|
|
admin can see which of the two is actually live. (#5489) */
|
|
.settings-hint.env-setting-hint {
|
|
color: var(--text-secondary);
|
|
border-left: 2px solid var(--accent);
|
|
padding-left: 0.5rem;
|
|
margin-top: 0.25rem;
|
|
line-height: 1.5;
|
|
}
|
|
.settings-desc {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 0.875rem;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
/* ── Desktop Shortcuts table ──────────────────────────── */
|
|
.shortcut-table { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.625rem; }
|
|
.shortcut-row {
|
|
display: flex; align-items: center; gap: 0.625rem;
|
|
padding: 0.375rem 0.5rem; border-radius: var(--radius-sm);
|
|
background: var(--bg-tertiary); border: 1px solid var(--border-color);
|
|
}
|
|
.shortcut-row.recording {
|
|
border-color: var(--accent); background: rgba(107,79,219,.1);
|
|
}
|
|
.shortcut-label { flex: 1; font-size: 0.75rem; color: var(--text-primary); }
|
|
.shortcut-key {
|
|
min-width: 8.75rem; font-size: 0.6875rem; font-family: var(--font-mono, monospace);
|
|
background: var(--bg-secondary); border: 1px solid var(--border);
|
|
border-radius: 0.1875rem; padding: 0.125rem 0.5rem; color: var(--text-secondary);
|
|
text-align: center;
|
|
}
|
|
.shortcut-key.recording-label {
|
|
color: var(--accent); border-color: var(--accent); animation: shortcut-pulse 1s ease infinite;
|
|
}
|
|
@keyframes shortcut-pulse { 0%,100%{opacity:1} 50%{opacity:.5} }
|
|
.shortcut-btns { display: flex; gap: 0.25rem; }
|
|
.shortcut-label .shortcut-hint { display: block; margin: 0.125rem 0 0; font-size: 0.6875rem; }
|
|
|
|
/* ── Desktop App preference rows ─── */
|
|
.desktop-pref-row { margin-bottom: 0.75rem; }
|
|
.desktop-pref-row .toggle-row { justify-content: flex-start; gap: 0.625rem; font-size: 0.8125rem; color: var(--text-primary); cursor: pointer; }
|
|
.desktop-pref-row .settings-hint { margin: 0.125rem 0 0 1.625rem; font-size: 0.6875rem; }
|
|
|
|
.password-change-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
.password-change-form .form-group.compact {
|
|
margin: 0;
|
|
}
|
|
.password-change-form input {
|
|
width: 100%;
|
|
padding: 0.4375rem 0.625rem;
|
|
border-radius: var(--radius-sm);
|
|
border: 1px solid var(--border);
|
|
background: var(--bg-primary);
|
|
color: var(--text-primary);
|
|
font-size: 0.8125rem;
|
|
outline: none;
|
|
}
|
|
.password-change-form input:focus {
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
.sidebar-settings-panel,
|
|
.sidebar-invite-panel {
|
|
flex-shrink: 0;
|
|
border-top: 1px solid var(--border);
|
|
border-bottom: none;
|
|
padding: 0.625rem 1rem;
|
|
}
|
|
|
|
.btn-settings-popout,
|
|
.btn-invite-popout {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
width: 100%;
|
|
padding: 0.5rem 0.75rem;
|
|
background: var(--bg-tertiary);
|
|
color: var(--text-secondary);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
cursor: pointer;
|
|
font-size: 0.8125rem;
|
|
font-weight: 500;
|
|
transition: all 0.15s ease;
|
|
}
|
|
.btn-settings-popout:hover,
|
|
.btn-invite-popout:hover {
|
|
background: var(--bg-hover);
|
|
color: var(--text-primary);
|
|
border-color: var(--accent);
|
|
}
|
|
.btn-settings-popout svg,
|
|
.btn-invite-popout svg {
|
|
flex-shrink: 0;
|
|
opacity: 0.7;
|
|
}
|
|
.btn-settings-popout:hover svg,
|
|
.btn-invite-popout:hover svg {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
|
|
ADMIN MEMBER LIST
|
|
â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• */
|
|
|
|
.aml-member-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 0.625rem;
|
|
background: var(--bg-tertiary);
|
|
border-radius: var(--radius-sm);
|
|
gap: 0.625rem;
|
|
}
|
|
.aml-member-row:hover { background: var(--bg-hover); }
|
|
|
|
.aml-member-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.625rem;
|
|
min-width: 0;
|
|
flex: 1;
|
|
}
|
|
|
|
.aml-avatar-wrap {
|
|
position: relative;
|
|
flex-shrink: 0;
|
|
width: 2.125rem;
|
|
height: 2.125rem;
|
|
}
|
|
|
|
.aml-avatar {
|
|
width: 2.125rem;
|
|
height: 2.125rem;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.aml-avatar-default {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: var(--bg-secondary);
|
|
color: var(--text-secondary);
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.aml-status-dot {
|
|
position: absolute;
|
|
bottom: -1px;
|
|
right: -1px;
|
|
width: 0.625rem;
|
|
height: 0.625rem;
|
|
border-radius: 50%;
|
|
border: 2px solid var(--bg-tertiary);
|
|
}
|
|
.aml-status-dot.aml-online { background: var(--success); }
|
|
.aml-status-dot.aml-offline { background: var(--text-muted); }
|
|
.aml-status-dot.aml-away { background: #faa61a; }
|
|
.aml-status-dot.aml-dnd { background: var(--danger); }
|
|
/* Connected but invisible; only staff are shown this (see admin.js). */
|
|
.aml-status-dot.aml-invisible { background: var(--bg-tertiary); box-shadow: inset 0 0 0 2px var(--text-muted); }
|
|
|
|
.aml-member-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.1875rem;
|
|
min-width: 0;
|
|
}
|
|
|
|
.aml-member-name {
|
|
font-size: 0.8125rem;
|
|
font-weight: 500;
|
|
color: var(--text-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.3125rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.aml-login-name {
|
|
font-size: 0.6875rem;
|
|
color: var(--text-muted);
|
|
font-weight: 400;
|
|
}
|
|
|
|
.aml-admin-badge {
|
|
font-size: 0.625rem;
|
|
padding: 0.0625rem 0.3125rem;
|
|
border-radius: 0.1875rem;
|
|
background: var(--danger);
|
|
color: var(--danger-text);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.aml-banned-badge {
|
|
font-size: 0.625rem;
|
|
padding: 0.0625rem 0.3125rem;
|
|
border-radius: 0.1875rem;
|
|
background: var(--text-muted);
|
|
color: #fff;
|
|
font-weight: 500;
|
|
text-decoration: line-through;
|
|
}
|
|
|
|
.aml-new-badge {
|
|
font-size: 0.625rem;
|
|
padding: 0.0625rem 0.3125rem;
|
|
border-radius: 0.1875rem;
|
|
background: var(--accent);
|
|
color: var(--accent-text);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.aml-member-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
flex-wrap: wrap;
|
|
font-size: 0.6875rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.aml-role-badge {
|
|
font-size: 0.625rem;
|
|
padding: 0.0625rem 0.375rem;
|
|
border-radius: 0.5625rem;
|
|
border: 1px solid;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.aml-member-joined {
|
|
font-size: 0.625rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.aml-member-channels {
|
|
font-size: 0.625rem;
|
|
color: var(--text-muted);
|
|
opacity: 0.7;
|
|
}
|
|
|
|
/* Upload storage per member. Deliberately a touch stronger than the other
|
|
meta chips: it is the one number an admin scans this list looking for. */
|
|
.aml-member-storage {
|
|
font-size: 0.625rem;
|
|
color: var(--text-secondary, var(--text-muted));
|
|
opacity: 0.85;
|
|
white-space: nowrap;
|
|
cursor: help;
|
|
}
|
|
|
|
/* ── Channel Picker (Add/Remove user from channels) ── */
|
|
.aml-ch-picker {
|
|
max-width: 26.25rem;
|
|
width: 100%;
|
|
max-height: 70vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 1rem;
|
|
gap: 0.625rem;
|
|
}
|
|
.aml-ch-picker-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 0.75rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.06));
|
|
}
|
|
.aml-ch-picker-title {
|
|
margin: 0;
|
|
font-size: 0.9375rem;
|
|
font-weight: 600;
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.aml-ch-picker-selectall {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
font-size: 0.75rem;
|
|
color: var(--text-muted);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
white-space: nowrap;
|
|
}
|
|
.aml-ch-picker-selectall input[type="checkbox"] {
|
|
margin: 0;
|
|
cursor: pointer;
|
|
}
|
|
.aml-ch-picker-subtitle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
.aml-ch-picker-count {
|
|
font-size: 0.6875rem;
|
|
color: var(--text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
flex-shrink: 0;
|
|
}
|
|
.aml-ch-picker-search {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding: 0.375rem 0.625rem;
|
|
font-size: 0.75rem;
|
|
background: var(--bg-input, rgba(0,0,0,0.25));
|
|
border: 1px solid var(--border-color, rgba(255,255,255,0.08));
|
|
border-radius: var(--radius-sm, 0.375rem);
|
|
color: var(--text);
|
|
outline: none;
|
|
}
|
|
.aml-ch-picker-search:focus {
|
|
border-color: var(--accent, #5865f2);
|
|
}
|
|
.aml-channel-list {
|
|
overflow-y: auto;
|
|
flex: 1;
|
|
min-height: 5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.0625rem;
|
|
padding: 0.125rem;
|
|
margin: 0 -0.125rem;
|
|
}
|
|
.aml-channel-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.4375rem 0.625rem;
|
|
border-radius: var(--radius-sm, 0.375rem);
|
|
cursor: pointer;
|
|
transition: background 0.12s ease;
|
|
}
|
|
.aml-channel-row:hover {
|
|
background: var(--bg-hover, rgba(255,255,255,0.04));
|
|
}
|
|
.aml-channel-row input[type="checkbox"] {
|
|
margin: 0;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
}
|
|
.aml-ch-hash {
|
|
color: var(--text-muted);
|
|
font-size: 0.8125rem;
|
|
font-weight: 500;
|
|
}
|
|
.aml-ch-name {
|
|
font-size: 0.8125rem;
|
|
color: var(--text);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.aml-channel-row:has(input:checked) {
|
|
background: var(--bg-hover, rgba(88,101,242,0.10));
|
|
}
|
|
.aml-channel-row:has(input:checked) .aml-ch-name {
|
|
font-weight: 500;
|
|
}
|
|
.aml-ch-picker-actions {
|
|
margin-top: 0.25rem;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
/* ── Member List Action Buttons ── */
|
|
.aml-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.1875rem;
|
|
flex-shrink: 0;
|
|
opacity: 0;
|
|
transition: opacity 0.15s;
|
|
}
|
|
.aml-member-row:hover .aml-actions { opacity: 1; }
|
|
|
|
.aml-action-btn {
|
|
width: 1.75rem;
|
|
height: 1.75rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: none;
|
|
background: transparent;
|
|
border-radius: var(--radius-sm);
|
|
cursor: pointer;
|
|
font-size: 0.875rem;
|
|
padding: 0;
|
|
transition: background 0.12s;
|
|
}
|
|
.aml-action-btn:hover { background: var(--bg-hover); }
|
|
.aml-btn-ban:hover,
|
|
.aml-btn-delete:hover { background: rgba(244, 63, 94, 0.15); }
|
|
.aml-btn-unban:hover { background: rgba(74, 222, 128, 0.15); }
|
|
|
|
/* ── Channel Picker (add/remove) ── */
|
|
.aml-channel-row:hover {
|
|
background: var(--bg-hover);
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
|
|
.bans-list {
|
|
max-height: 18.75rem;
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.ban-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 0.625rem;
|
|
padding: 0.5rem 0.625rem;
|
|
background: var(--bg-tertiary);
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
|
|
.ban-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.125rem;
|
|
min-width: 0;
|
|
flex: 1;
|
|
}
|
|
|
|
.ban-info strong {
|
|
font-size: 0.8125rem;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.ban-reason {
|
|
font-size: 0.6875rem;
|
|
color: var(--text-secondary);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.ban-date {
|
|
font-size: 0.625rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.btn-unban {
|
|
flex-shrink: 0;
|
|
background: var(--success) !important;
|
|
color: var(--success-text) !important;
|
|
}
|
|
|
|
.btn-unban:hover { opacity: 0.85; }
|
|
|
|
.ban-actions {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
flex-shrink: 0;
|
|
align-items: center;
|
|
}
|
|
|
|
.btn-delete-user {
|
|
flex-shrink: 0;
|
|
background: var(--danger) !important;
|
|
color: var(--danger-text) !important;
|
|
font-size: 0.75rem;
|
|
padding: 0.25rem 0.5rem !important;
|
|
}
|
|
|
|
.btn-delete-user:hover { opacity: 0.85; }
|
|
|