Files
gibbz/public/style.css
T
matsandClaude Sonnet 5 5ecf415f64
Build and Publish / Metadata (push) Successful in 1s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 23s
Clarify mic mute state, center spatial map on you, show talking/muted on shares
- Mic button now swaps glyph (mic vs muted) and syncs immediately on
  join/leave/load instead of relying on a subtle CSS underline.
- Spatial minimap camera now follows the local user, matching how the
  audio panning is already centered on them, instead of plotting
  absolute room coordinates stretched across whatever width the
  screen happens to be.
- Screen-share tiles now show a speaking glow and muted badge, kept in
  sync on the existing audio-meter tick without tearing down <video>
  elements.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 11:07:34 +02:00

369 lines
13 KiB
CSS

/* Discord-ish dark theme (POC) */
:root {
--bg-0: #1e1f22; /* rail */
--bg-1: #2b2d31; /* sidebar */
--bg-2: #313338; /* main */
--bg-3: #383a40; /* hover */
--bg-4: #404249;
--text-0: #f2f3f5;
--text-1: #b5bac1;
--text-2: #80848e;
--brand: #5865f2;
--green: #23a55a;
--red: #f23f43;
--yellow: #f0b232;
--radius: 8px;
}
* { box-sizing: border-box; margin: 0; }
html, body { height: 100%; }
body {
font: 14px/1.4 "gg sans", "Segoe UI", system-ui, -apple-system, sans-serif;
background: var(--bg-2);
color: var(--text-0);
overflow: hidden;
}
#app { display: flex; height: 100vh; }
/* rail */
#rail {
width: 68px; background: var(--bg-0); padding: 12px 0;
display: flex; flex-direction: column; align-items: center; gap: 8px; flex-shrink: 0;
}
.rail-icon {
width: 44px; height: 44px; border-radius: 50%; background: var(--bg-3);
display: grid; place-items: center; font-weight: 700; color: var(--text-1);
cursor: pointer; transition: border-radius .15s, background .15s;
}
.rail-icon:hover, .rail-icon.home { border-radius: 16px; background: var(--brand); color: #fff; }
.rail-sep { width: 28px; height: 2px; background: var(--bg-3); border-radius: 1px; }
/* sidebar */
#sidebar {
width: 250px; background: var(--bg-1); display: flex; flex-direction: column; flex-shrink: 0;
position: relative; z-index: 10;
}
#server-name {
padding: 14px 16px; font-weight: 700; font-size: 15px;
border-bottom: 1px solid rgba(0,0,0,.25); box-shadow: 0 1px 0 rgba(0,0,0,.06);
}
.poc-tag {
font-size: 10px; background: var(--yellow); color: #000; border-radius: 4px;
padding: 1px 5px; vertical-align: 2px; margin-left: 6px; font-weight: 800;
}
.channel-group-label {
padding: 18px 8px 4px 16px; font-size: 11px; font-weight: 700;
letter-spacing: .4px; color: var(--text-2); text-transform: uppercase;
}
.channel {
margin: 1px 8px; padding: 7px 8px; border-radius: 6px; color: var(--text-1);
cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.channel:hover { background: var(--bg-3); color: var(--text-0); }
.channel.text { color: var(--text-2); }
.channel.text .hint { font-size: 10px; margin-left: 4px; }
.channel.voice.active { background: rgba(88,101,242,.25); color: var(--text-0); }
.channel .count { float: right; color: var(--text-2); font-size: 12px; }
#user-panel {
margin-top: auto; background: var(--bg-0); padding: 8px;
display: flex; align-items: center; justify-content: space-between; gap: 6px;
min-height: 52px;
}
.me { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
.me-meta { display: flex; flex-direction: column; min-width: 0; flex: 1; overflow: hidden; }
#nick {
background: transparent; border: none; color: var(--text-0); font: inherit;
font-weight: 600; font-size: 13px; width: 100%; padding: 0; outline: none; border-bottom: 1px dashed transparent;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#nick:hover, #nick:focus { border-bottom-color: var(--text-2); }
.status-row {
display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text-2);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.2;
}
.status-indicator {
width: 7px; height: 7px; border-radius: 50%; background: var(--text-2); flex-shrink: 0;
}
.status-indicator.online { background: var(--green); }
.status-indicator.connecting { background: var(--yellow); }
.status-indicator.error { background: var(--red); }
#voice-status {
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.user-buttons { display: flex; gap: 2px; flex-shrink: 0; }
.ctl {
background: transparent; border: none; color: var(--text-1); font-size: 15px;
width: 28px; height: 28px; border-radius: 6px; cursor: pointer; position: relative;
display: grid; place-items: center; padding: 0;
}
.ctl:hover { background: var(--bg-3); color: var(--text-0); }
.ctl.off { color: var(--red); }
.ctl.off::after {
content: ""; position: absolute; left: 5px; top: 13px; width: 18px; height: 2px;
background: var(--red); transform: rotate(-40deg); border-radius: 1px;
}
.ctl:disabled { opacity: .35; cursor: not-allowed; }
.ctl.active { color: var(--green); }
/* main */
#main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
#stage {
flex: 1; display: flex; flex-direction: column; padding: 16px; gap: 16px;
overflow: auto; position: relative;
}
#stage-empty {
position: absolute; inset: 0; display: grid; place-content: center;
text-align: center; gap: 8px; color: var(--text-1); padding: 24px;
}
#stage-empty .big-icon { font-size: 56px; }
#stage-empty h2 { font-size: 20px; color: var(--text-0); }
#stage-empty p { max-width: 420px; color: var(--text-2); }
#stage.empty #stage-empty { display: grid; }
#stage:not(.empty) #stage-empty { display: none; }
#screens { display: flex; gap: 12px; flex-wrap: wrap; flex: 1; min-height: 0; align-items: stretch; }
#screens.multi { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); align-content: stretch; }
#screens.multi .screen-card { flex: none; }
.screen-card.popped {
min-height: 120px; display: grid; place-items: center;
background: var(--bg-0); box-shadow: none; border: 1px dashed var(--bg-4);
}
.pop-btn {
position: absolute; right: 8px; top: 8px; z-index: 2;
background: rgba(0,0,0,.65); color: var(--text-0); border: none; cursor: pointer;
border-radius: 5px; padding: 3px 8px; font-size: 13px; font-weight: 600;
}
.pop-btn:hover { background: var(--brand); }
.screen-card {
position: relative; background: #000; border-radius: var(--radius); overflow: hidden;
flex: 1 1 480px; max-width: 100%; box-shadow: 0 8px 24px rgba(0,0,0,.4);
}
.screen-card video { width: 100%; height: 100%; display: block; max-height: 100%; object-fit: contain; }
.screen-card .label {
position: absolute; left: 8px; bottom: 8px; background: rgba(0,0,0,.65);
padding: 3px 8px; border-radius: 5px; font-size: 12px; font-weight: 600;
}
.screen-card .label .live { color: var(--red); font-weight: 800; margin-right: 5px; }
.screen-card.speaking { box-shadow: 0 0 0 3px var(--green), 0 8px 24px rgba(0,0,0,.4); }
.tile-mic-badge { margin-left: 6px; }
.tile-mic-badge.muted::before { content: "\1F507"; } /* 🔇 */
.tile-mic-badge:not(.muted)::before { content: ""; }
/* channel user lines */
.channel-users {
margin: 2px 8px 8px 16px;
display: flex;
flex-direction: column;
gap: 2px;
}
.channel-user-item {
position: relative;
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
border-radius: 4px;
color: var(--text-1);
font-size: 13px;
cursor: default;
}
.channel-user-item:hover {
background: var(--bg-3);
color: var(--text-0);
}
.channel-user-item.speaking .user-line-avatar {
box-shadow: 0 0 0 2px var(--green);
}
.user-line-avatar {
width: 22px;
height: 22px;
font-size: 11px;
}
.user-line-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.user-line-badges {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
}
.badge-conn {
color: var(--yellow);
font-weight: bold;
}
.badge-mute {
font-size: 11px;
}
.badge-share {
font-size: 11px;
}
/* hover volume popup */
.volume-popup {
position: absolute;
left: calc(100% + 6px);
top: 50%;
transform: translateY(-50%);
background: var(--bg-0);
border: 1px solid var(--bg-4);
border-radius: var(--radius);
padding: 8px 12px;
width: 150px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
display: none;
z-index: 100;
pointer-events: auto;
}
.channel-user-item:hover .volume-popup {
display: flex;
flex-direction: column;
gap: 6px;
}
.volume-popup .vol-title {
font-size: 11px;
font-weight: 600;
color: var(--text-1);
white-space: nowrap;
}
.volume-popup input[type=range] {
width: 100%;
accent-color: var(--brand);
}
.avatar {
width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center;
font-weight: 700; color: #fff; flex-shrink: 0; user-select: none;
}
/* spatial plane */
#spatial-wrap {
height: 34vh; min-height: 220px; background: var(--bg-1);
border-top: 1px solid rgba(0,0,0,.35); display: flex; flex-direction: column;
}
.spatial-label {
padding: 8px 16px 0; font-size: 11px; font-weight: 700; color: var(--text-2);
letter-spacing: .5px; display: flex; gap: 16px;
}
.spatial-label .hint { font-weight: 400; letter-spacing: 0; text-transform: none; }
#spatial { flex: 1; width: 100%; cursor: grab; touch-action: none; }
#spatial.dragging { cursor: grabbing; }
/* modal */
#modal-backdrop {
position: fixed; inset: 0; background: rgba(0,0,0,.7); display: grid;
place-items: center; z-index: 50;
}
#modal-backdrop.hidden { display: none; }
#settings-modal {
width: min(620px, 92vw); max-height: 90vh; overflow: auto;
background: var(--bg-1); border-radius: 8px; padding: 20px;
box-shadow: 0 12px 40px rgba(0,0,0,.6);
}
#settings-modal h2 { font-size: 18px; margin-bottom: 6px; }
#settings-modal h3 { font-size: 13px; margin: 16px 0 4px; color: var(--text-1); }
#settings-modal p { margin-bottom: 10px; }
#ice-json {
width: 100%; background: var(--bg-0); color: var(--text-0); border: 1px solid var(--bg-4);
border-radius: 6px; padding: 10px; font: 12px/1.5 ui-monospace, "Cascadia Code", monospace;
resize: vertical;
}
#ice-json:focus { outline: none; border-color: var(--brand); }
#ice-server-default {
background: var(--bg-0); padding: 8px 10px; border-radius: 6px;
font: 11px/1.5 ui-monospace, monospace; white-space: pre-wrap;
}
.toggle-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; cursor: pointer; }
.toggle-row input { accent-color: var(--brand); width: 16px; height: 16px; }
.modal-actions { display: flex; gap: 8px; margin-top: 12px; align-items: center; }
.modal-actions .spacer { flex: 1; }
.modal-actions button {
padding: 8px 16px; border-radius: 6px; border: none; cursor: pointer;
font-weight: 600; font-size: 13px;
}
.modal-actions button:not(.ghost) { background: var(--brand); color: #fff; }
.modal-actions button.ghost { background: transparent; color: var(--text-1); }
.modal-actions button.ghost:hover { text-decoration: underline; }
/* matrix text chat panel */
#mx-panel {
position: fixed; top: 0; right: 0; bottom: 0; width: 340px; max-width: 90vw;
background: var(--bg-1); border-left: 1px solid rgba(0,0,0,.35);
display: flex; flex-direction: column; z-index: 40;
box-shadow: -8px 0 24px rgba(0,0,0,.45);
}
#mx-panel.hidden { display: none; }
.mx-header {
padding: 12px 14px; font-weight: 700; font-size: 14px;
display: flex; align-items: center; justify-content: space-between;
border-bottom: 1px solid rgba(0,0,0,.25); flex-shrink: 0;
}
.mx-header button.ghost {
background: transparent; border: none; color: var(--text-1);
font-size: 20px; line-height: 1; cursor: pointer; padding: 0 4px;
}
.mx-header button.ghost:hover { color: var(--text-0); }
#mx-messages { flex: 1; overflow: auto; padding: 10px 14px; display: flex; flex-direction: column; gap: 8px; }
.mx-msg { font-size: 13px; line-height: 1.4; }
.mx-sender { font-weight: 700; color: var(--text-0); margin-right: 6px; }
.mx-body { color: var(--text-1); white-space: pre-wrap; overflow-wrap: anywhere; }
.mx-composer {
display: flex; gap: 8px; padding: 10px 14px; border-top: 1px solid rgba(0,0,0,.25); flex-shrink: 0;
}
.mx-composer textarea {
flex: 1; resize: none; background: var(--bg-0); border: 1px solid var(--bg-4);
border-radius: 6px; color: var(--text-0); padding: 8px 10px; font: inherit; max-height: 100px;
}
.mx-composer textarea:focus { outline: none; border-color: var(--brand); }
.mx-composer button {
background: var(--brand); border: none; color: #fff; border-radius: 6px;
padding: 0 14px; font-weight: 600; cursor: pointer;
}
/* reconnect banner */
#reconnect-banner {
position: fixed; top: 16px; left: 50%; transform: translateX(-50%);
z-index: 70; display: flex; align-items: center; gap: 12px;
background: var(--bg-0); border: 1px solid var(--red);
box-shadow: 0 8px 28px rgba(0,0,0,.55), 0 0 0 1px rgba(242,63,67,.15);
border-radius: 10px; padding: 10px 14px; font-size: 13px;
animation: banner-in .2s ease-out;
}
#reconnect-banner.hidden { display: none; }
#reconnect-banner #reconnect-text { color: var(--text-0); font-weight: 600; white-space: nowrap; }
.reconnect-spinner {
width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0;
border: 2px solid rgba(242,63,67,.25); border-top-color: var(--red);
animation: spin .8s linear infinite;
}
.reconnect-actions { display: flex; gap: 6px; margin-left: 4px; }
.reconnect-actions button {
padding: 5px 10px; border-radius: 6px; border: none; cursor: pointer;
font-weight: 600; font-size: 12px; background: var(--red); color: #fff;
}
.reconnect-actions button.ghost { background: transparent; color: var(--text-1); }
.reconnect-actions button.ghost:hover { color: var(--text-0); text-decoration: underline; }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes banner-in { from { transform: translate(-50%, -12px); opacity: 0; } }
/* toasts */
#toasts {
position: fixed; bottom: 16px; right: 16px; display: flex; flex-direction: column;
gap: 8px; z-index: 60; max-width: 380px;
}
.toast {
background: var(--bg-0); border-left: 3px solid var(--brand); border-radius: 6px;
padding: 10px 14px; box-shadow: 0 8px 20px rgba(0,0,0,.5); font-size: 13px;
animation: slide-in .18s ease-out;
}
.toast.error { border-left-color: var(--red); }
.toast.warn { border-left-color: var(--yellow); }
.toast.ok { border-left-color: var(--green); }
@keyframes slide-in { from { transform: translateX(30px); opacity: 0; } }
.hint { color: var(--text-2); font-size: 12px; }
code { font-family: ui-monospace, monospace; font-size: 12px; }