/* MeshBay Web Client — Phase 9.6 */ /* ── Theme variables ──────────────────────────────────────────────────────── */ :root, .theme-light { --bg-base: #f8fafc; --bg-surface: #ffffff; --bg-raised: #f1f5f9; --text: #0f172a; --text-secondary: #475569; --text-dim: #94a3b8; --border: #e2e8f0; --border-focus: #0ea5e9; --accent: #0ea5e9; --accent-hover: #0284c7; --accent-text: #ffffff; --error: #ef4444; --error-bg: #fef2f2; --success: #22c55e; --nav-bg: #0f172a; --nav-text: #e2e8f0; --nav-brand: #38bdf8; --sidebar-bg: #f1f5f9; --sidebar-hover: #e2e8f0; --shadow: 0 1px 3px rgba(0, 0, 0, 0.08); --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.1); } .theme-dark { --bg-base: #0f172a; --bg-surface: #1e293b; --bg-raised: #334155; --text: #f1f5f9; --text-secondary: #94a3b8; --text-dim: #64748b; --border: #334155; --error-bg: #450a0a; --nav-bg: #020617; --sidebar-bg: #1e293b; --sidebar-hover: #334155; --shadow: 0 1px 3px rgba(0, 0, 0, 0.3); --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.3); } /* ── Reset ────────────────────────────────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: system-ui, -apple-system, sans-serif; background: var(--bg-base); color: var(--text); line-height: 1.6; min-height: 100vh; } a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } .search-synced { font-size: 0.72em; color: var(--text-dim); margin-top: 3px; } /* ── Icons ────────────────────────────────────────────────────────────────── */ /* Sized in em and stroked in currentColor, so an icon inherits the size and colour of whatever it sits next to and needs no rule of its own. Only the places that want a fixed size say so below. */ .icon { width: 1em; height: 1em; vertical-align: -0.14em; flex-shrink: 0; } .icon.flip { transform: rotate(180deg); } /* ── Navigation ───────────────────────────────────────────────────────────── */ .nav { background: var(--nav-bg); color: var(--nav-text); padding: 0 16px; height: 52px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 100; } .nav-left, .nav-right { display: flex; align-items: center; gap: 12px; } .nav-brand { color: var(--nav-brand); font-weight: 700; font-size: 1.15em; text-decoration: none; } .nav-brand:hover { text-decoration: none; } .nav-hamburger { display: none; background: none; border: none; color: var(--nav-text); font-size: 1.4em; cursor: pointer; padding: 4px 8px; line-height: 1; } .nav-user { color: var(--text-dim); font-size: 0.9em; } /* ── User Menu ──────────────────────────────────────────────────────────── */ .user-menu-wrap { position: relative; } .user-menu-trigger { display: flex; align-items: center; gap: 8px; background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.12); color: var(--nav-text); padding: 4px 10px 4px 4px; border-radius: 20px; cursor: pointer; font-size: 0.85em; transition: background 0.12s; } .user-menu-trigger:hover { background: rgba(255, 255, 255, 0.15); } .user-menu-avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.8em; flex-shrink: 0; } .user-menu-avatar.lg { width: 36px; height: 36px; font-size: 0.95em; } .user-menu-name { max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .user-menu-caret { font-size: 0.7em; color: rgba(255,255,255,0.5); } .user-menu-dropdown { position: absolute; right: 0; top: calc(100% + 6px); background: var(--bg-surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow-lg); min-width: 220px; z-index: 120; /* The language submenu expands to ten entries inside this dropdown, which overruns a short viewport. Clip horizontally as before, scroll vertically rather than hiding the last languages where nothing can reach them. */ max-height: calc(100vh - 72px); overflow-x: hidden; overflow-y: auto; padding: 4px 0; } .user-menu-header { display: flex; align-items: center; gap: 10px; padding: 12px 14px 8px; } .user-menu-uname { font-weight: 600; font-size: 0.9em; color: var(--text); } .user-menu-role { font-size: 0.75em; color: var(--text-dim); text-transform: capitalize; } .user-menu-divider { height: 1px; background: var(--border); margin: 4px 0; } .user-menu-section-label { padding: 6px 14px 2px; font-size: 0.7em; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); font-weight: 600; } .user-menu-item { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 14px; background: none; border: none; border-radius: 0; color: var(--text); font-size: 0.85em; cursor: pointer; text-align: left; } .user-menu-item:hover { background: var(--bg-raised); } .user-menu-logout { color: var(--error); } .umi-icon { width: 17px; height: 17px; flex-shrink: 0; color: var(--text-secondary); } .umi-arrow { margin-left: auto; width: 13px; height: 13px; color: var(--text-dim); } .umi-check { margin-left: auto; width: 14px; height: 14px; color: var(--accent); } .user-menu-caret { width: 13px; height: 13px; color: var(--nav-text); opacity: 0.8; } .user-menu-sub { padding-left: 32px; } .nav-btn { background: rgba(255, 255, 255, 0.1); color: var(--nav-text); border: none; padding: 6px 14px; border-radius: 6px; font-size: 0.85em; cursor: pointer; text-decoration: none; } .nav-btn:hover { background: rgba(255, 255, 255, 0.18); text-decoration: none; } /* ── Layout ───────────────────────────────────────────────────────────────── */ .layout { display: flex; min-height: calc(100vh - 52px); } /* ── Sidebar ──────────────────────────────────────────────────────────────── */ .sidebar { width: 240px; background: var(--sidebar-bg); border-right: 1px solid var(--border); padding: 16px 0; flex-shrink: 0; overflow-y: auto; } .sidebar-section { padding: 0 12px; margin-bottom: 24px; } .sidebar-heading { font-size: 0.7em; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); padding: 4px 8px; margin-bottom: 4px; font-weight: 600; } .sidebar-item { display: flex; align-items: center; gap: 8px; padding: 7px 12px; border-radius: 6px; color: var(--text); text-decoration: none; font-size: 0.9em; transition: background 0.12s; } .sidebar-item:hover { background: var(--sidebar-hover); text-decoration: none; } .sidebar-item.active { background: var(--accent); color: var(--accent-text); } .sidebar-empty { padding: 8px 12px; color: var(--text-dim); font-size: 0.85em; font-style: italic; } /* ── Main content ─────────────────────────────────────────────────────────── */ .main { flex: 1; padding: 24px 32px; max-width: 960px; min-width: 0; } .main h2 { font-size: 1.25em; margin-bottom: 16px; } .page-message { color: var(--text-secondary); margin-bottom: 24px; } /* ── Page center (login / register) ───────────────────────────────────────── */ .page-center { display: flex; align-items: center; justify-content: center; min-height: calc(100vh - 52px); padding: 24px; } /* A centring page already reserves the whole viewport below the header, so the main column's own padding is added on top of it and the page overflows by exactly that much — 48px, and a scrollbar on sign-in at every window size. Measured, not deduced: `.page-center` ended at 795 and `main` at 819. The page brings its own 24px, so dropping main's here changes nothing visible and removes the duplicated arithmetic rather than adding more. */ .main:has(> .page-center) { padding: 0; } /* ── Cards ────────────────────────────────────────────────────────────────── */ .card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; padding: 24px; box-shadow: var(--shadow); } .login-card { width: 100%; max-width: 380px; } .login-card h2 { text-align: center; margin-bottom: 20px; } .login-card form { display: flex; flex-direction: column; gap: 12px; } .login-footer { text-align: center; margin-top: 16px; font-size: 0.85em; color: var(--text-dim); } /* ── Form elements ────────────────────────────────────────────────────────── */ input[type="text"], input[type="password"], input[type="email"] { padding: 10px 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-base); color: var(--text); font-size: 0.95em; width: 100%; transition: border-color 0.15s; } input:focus { outline: none; border-color: var(--border-focus); } button { padding: 10px 20px; background: var(--accent); color: var(--accent-text); border: none; border-radius: 6px; font-size: 0.95em; cursor: pointer; transition: background 0.15s; } button:hover { background: var(--accent-hover); } button:disabled { opacity: 0.5; cursor: not-allowed; } /* ── Alerts ───────────────────────────────────────────────────────────────── */ .error-msg { background: var(--error-bg); color: var(--error); border: 1px solid var(--error); border-radius: 6px; padding: 8px 12px; font-size: 0.85em; } .success-msg { background: #16a34a20; color: var(--success); border: 1px solid var(--success); border-radius: 6px; padding: 8px 12px; font-size: 0.85em; } .settings-hint { font-size: 0.85em; color: var(--text-dim); margin-bottom: 8px; } /* ── Group cards (9.7 prep) ───────────────────────────────────────────────── */ .group-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; } .group-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px; cursor: pointer; transition: border-color 0.12s, box-shadow 0.12s; text-decoration: none; color: var(--text); display: block; } .group-card:hover { border-color: var(--accent); box-shadow: var(--shadow-lg); text-decoration: none; } .group-card h3 { font-size: 1em; margin-bottom: 4px; } .badge { display: inline-block; background: var(--bg-raised); color: var(--text-secondary); padding: 2px 8px; border-radius: 12px; font-size: 0.75em; } .badge-ok { background: #16a34a20; color: var(--success); } .badge-err { background: var(--error-bg); color: var(--error); } /* ── Group page header ───────────────────────────────────────────────────── */ .group-header { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; } .group-header h2 { margin-bottom: 0; } .status-badge { display: inline-block; padding: 3px 10px; border-radius: 12px; font-size: 0.75em; font-weight: 500; } .status-ok { background: #16a34a20; color: var(--success); } .status-err { background: var(--error-bg); color: var(--error); } .status-busy { background: var(--bg-raised); color: var(--text-secondary); } /* ── Group tabs ──────────────────────────────────────────────────────────── */ .group-tabs { display: flex; gap: 0; margin-bottom: 16px; border-bottom: 2px solid var(--border); } .group-tab { background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -2px; padding: 8px 20px; color: var(--text-secondary); font-size: 0.9em; font-weight: 500; cursor: pointer; border-radius: 0; transition: color 0.12s, border-color 0.12s; } .group-tab:hover { color: var(--text); background: none; } .group-tab.active { color: var(--accent); border-bottom-color: var(--accent); } /* ── Chat panel ──────────────────────────────────────────────────────────── */ .chat-panel { position: relative; display: flex; flex-direction: column; /* Overwritten from JS with the space actually left below the group header, which varies with the description and the buttons. These two are the value used for the first paint and the fallback if that never runs. `dvh` rather than `vh` so a phone's collapsing URL bar does not add a scrollbar. */ height: calc(100dvh - 260px); min-height: 240px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; } .chat-messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 4px; } .chat-empty { text-align: center; color: var(--text-dim); font-style: italic; padding: 40px 16px; } .chat-msg { display: flex; flex-direction: column; align-items: flex-start; max-width: 75%; } .chat-msg-own { align-self: flex-end; align-items: flex-end; } .chat-sender { font-size: 0.72em; color: var(--text-dim); margin-bottom: 2px; padding-left: 10px; font-weight: 600; } .chat-bubble { background: var(--bg-raised); padding: 8px 12px; border-radius: 12px 12px 12px 4px; font-size: 0.9em; line-height: 1.45; word-break: break-word; display: inline-flex; align-items: baseline; gap: 8px; flex-wrap: wrap; } .chat-bubble-own { background: var(--accent); color: var(--accent-text); border-radius: 12px 12px 4px 12px; } .chat-text { white-space: pre-wrap; } .chat-time { font-size: 0.65em; color: var(--text-dim); white-space: nowrap; flex-shrink: 0; } .chat-bubble-own .chat-time { color: rgba(255, 255, 255, 0.6); } .chat-input-row { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--border); background: var(--bg-base); } .chat-input { flex: 1; resize: none; padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-surface); color: var(--text); font-size: 0.9em; font-family: inherit; line-height: 1.4; min-height: 38px; max-height: 100px; } .chat-input:focus { outline: none; border-color: var(--border-focus); } .chat-send { align-self: flex-end; padding: 8px 16px; font-size: 0.85em; border-radius: 8px; white-space: nowrap; } /* ── File toolbar ────────────────────────────────────────────────────────── */ /* One bar, three groups: what you can add on the left, where you are in the middle, what you can do with what is here on the right. It used to be four controls of three different heights sitting in a row. */ .file-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; padding: 8px; background: var(--bg-raised); border: 1px solid var(--border); border-radius: 8px; flex-wrap: wrap; } .toolbar-group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; } .toolbar-group.right { margin-left: auto; } .tb-btn { display: inline-flex; align-items: center; gap: 6px; /* the icon and the word are not the same word */ height: 32px; padding: 0 11px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-surface); color: var(--text); font-size: 0.83em; white-space: nowrap; cursor: pointer; transition: border-color 0.12s, color 0.12s, background 0.12s; } .tb-btn:hover { border-color: var(--accent); color: var(--accent); } .tb-btn:disabled { opacity: 0.45; cursor: not-allowed; } .tb-btn:disabled:hover { border-color: var(--border); color: var(--text); } .tb-btn .icon { width: 15px; height: 15px; } .tb-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); } .tb-btn.primary:hover { background: var(--accent-hover); color: var(--accent-text); } .tb-btn.active { background: color-mix(in srgb, var(--accent) 12%, var(--bg-surface)); border-color: var(--accent); color: var(--accent); } /* The filter is a field, not a button, and should not pretend otherwise. */ .tb-search { display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-surface); color: var(--text-dim); /* A flex item defaults to min-width:auto and refuses to shrink below its content — which is how a 150px field pushed the toolbar off a phone. */ min-width: 0; } .tb-search:focus-within { border-color: var(--border-focus); } .tb-search .icon { width: 14px; height: 14px; flex-shrink: 0; } .tb-search input { border: none; background: none; outline: none; padding: 0; width: 150px; min-width: 0; font-size: 0.83em; color: var(--text); } .breadcrumbs { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; min-width: 0; font-size: 0.85em; min-width: 0; flex-wrap: wrap; } .crumb { display: inline-flex; align-items: center; cursor: pointer; color: var(--accent); padding: 2px 4px; border-radius: 4px; } .crumb:hover { background: var(--bg-raised); text-decoration: none; } .crumb-sep { color: var(--text-dim); } /* ── File table ──────────────────────────────────────────────────────────── */ .file-table { width: 100%; border-collapse: collapse; font-size: 0.9em; } .file-table th { text-align: left; padding: 8px 12px; border-bottom: 2px solid var(--border); color: var(--text-secondary); font-size: 0.8em; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap; user-select: none; } .file-table th.sortable { cursor: pointer; } .file-table th.sortable:hover { color: var(--text); } .file-row td { padding: 8px 12px; border-bottom: 1px solid var(--border); vertical-align: middle; } .file-row:hover { background: var(--bg-raised); } .dir-row { cursor: pointer; } .dir-row td { font-weight: 500; } .file-name { word-break: break-word; min-width: 0; } .file-size { white-space: nowrap; color: var(--text-secondary); } .file-type { color: var(--text-dim); } .file-date { white-space: nowrap; color: var(--text-dim); } .file-empty { text-align: center; padding: 24px 12px !important; color: var(--text-dim); font-style: italic; } /* ── Spinner ─────────────────────────────────────────────────────────────── */ .spinner { display: inline-block; width: 14px; height: 14px; border: 2px solid var(--border); border-top: 2px solid var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; vertical-align: middle; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* ── File action menu ───────────────────────────────────────────────────── */ .file-actions-cell { position: relative; width: 40px; } .file-menu-btn { background: none; border: 1px solid var(--border); color: var(--text-secondary); width: 30px; height: 30px; border-radius: 6px; font-size: 1.1em; padding: 0; display: flex; align-items: center; justify-content: center; cursor: pointer; line-height: 1; } .file-menu-btn:hover { background: var(--bg-raised); border-color: var(--accent); color: var(--accent); } .file-menu { position: absolute; right: 0; top: 100%; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow-lg); z-index: 30; min-width: 130px; padding: 4px 0; overflow: hidden; } .file-menu button { display: block; width: 100%; padding: 8px 14px; background: none; border: none; color: var(--text); font-size: 0.85em; text-align: left; cursor: pointer; border-radius: 0; } .file-menu button:hover { background: var(--bg-raised); } /* ── File link (clickable name) ─────────────────────────────────────────── */ .file-link { color: var(--accent); cursor: pointer; text-decoration: none; } .file-link:hover { text-decoration: underline; } /* ── File preview overlay ───────────────────────────────────────────────── */ .preview-image-wrap { display: flex; align-items: center; justify-content: center; max-width: 90vw; max-height: calc(100vh - 100px); padding: 40px 20px 20px; } .preview-image { max-width: 100%; max-height: calc(100vh - 120px); object-fit: contain; border-radius: 4px; } .preview-text-wrap { width: min(90vw, 900px); max-height: calc(100vh - 100px); overflow: auto; padding: 60px 20px 20px; } .preview-text { background: var(--bg-surface); color: var(--text); padding: 20px; border-radius: 8px; font-size: 0.85em; line-height: 1.6; white-space: pre-wrap; word-break: break-word; overflow-x: auto; margin: 0; font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; tab-size: 4; } /* ── Chat attachment ────────────────────────────────────────────────────── */ .chat-attach { display: flex; align-items: center; justify-content: center; width: 38px; height: 38px; font-size: 1.2em; cursor: pointer; border-radius: 8px; flex-shrink: 0; color: var(--text-secondary); } .chat-attach:hover { background: var(--bg-raised); color: var(--accent); } .chat-attachment { display: flex; flex-direction: column; gap: 2px; } .chat-att-img, .chat-att-file { font-weight: 500; font-size: 0.88em; } .chat-att-thumb { max-width: 200px; max-height: 200px; border-radius: 6px; object-fit: contain; display: block; cursor: pointer; } .chat-att-size { font-size: 0.75em; color: var(--text-dim); } .chat-bubble-own .chat-att-size { color: rgba(255, 255, 255, 0.6); } .file-menu button { display: flex; align-items: center; gap: 8px; } .file-menu button.danger { color: var(--error); } .file-menu button.danger:hover { background: var(--error-bg); } .fmi { font-size: 0.9em; width: 16px; text-align: center; flex-shrink: 0; } /* ── Download button + progress ──────────────────────────────────────────── */ .dl-btn { background: none; border: 1px solid var(--border); color: var(--accent); width: 30px; height: 30px; border-radius: 6px; font-size: 0.9em; padding: 0; display: flex; align-items: center; justify-content: center; cursor: pointer; } .dl-btn:hover { background: var(--bg-raised); border-color: var(--accent); } .dl-btn:disabled { opacity: 0.3; cursor: not-allowed; } .dl-progress { flex: 1; height: 6px; background: var(--bg-raised); border-radius: 3px; overflow: hidden; } .dl-fill { height: 100%; background: var(--accent); border-radius: 3px; transition: width 0.2s; } /* ── Settings page ───────────────────────────────────────────────────────── */ .settings-section { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px 20px; margin-bottom: 16px; } .settings-heading { font-size: 0.8em; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); font-weight: 600; margin-bottom: 12px; } .settings-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 8px 0; } .settings-row + .settings-row { border-top: 1px solid var(--border); } .settings-label { font-size: 0.9em; color: var(--text); } .settings-value { font-size: 0.9em; color: var(--text-secondary); } .settings-select { padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-base); color: var(--text); font-size: 0.9em; cursor: pointer; min-width: 120px; } .settings-select:focus { outline: none; border-color: var(--border-focus); } /* ── Video player overlay ─────────────────────────────────────────────────── */ .video-overlay { position: fixed; inset: 0; z-index: 200; background: rgba(0, 0, 0, 0.92); display: flex; flex-direction: column; align-items: center; justify-content: center; } .video-top-bar { position: absolute; top: 0; left: 0; right: 0; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 12px 20px; z-index: 210; } .video-title { color: #e2e8f0; font-size: 0.9em; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; } .video-close { background: rgba(255, 255, 255, 0.12); border: none; color: #e2e8f0; width: 36px; height: 36px; border-radius: 50%; font-size: 1.2em; cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .video-close:hover { background: rgba(255, 255, 255, 0.25); } .video-container { width: 100%; max-width: min(90vw, 1280px); max-height: calc(100vh - 120px); display: flex; align-items: center; justify-content: center; } .video-container video { width: 100%; max-height: calc(100vh - 120px); border-radius: 4px; outline: none; } /* Where the film was picked up again. Sits over the picture rather than pushing it down, and clears itself once the viewer is watching. */ .video-container { position: relative; } .video-resumed { position: absolute; left: 12px; top: 12px; display: flex; gap: 10px; align-items: center; padding: 6px 12px; border-radius: 999px; background: rgba(15, 23, 42, 0.82); color: #e2e8f0; font-size: 0.85rem; pointer-events: auto; animation: video-resumed-fade 6s forwards; } @keyframes video-resumed-fade { 0%, 70% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } } .video-resumed .linklike { background: none; border: 0; padding: 0; color: #7dd3fc; cursor: pointer; font: inherit; text-decoration: underline; } .video-loading { text-align: center; color: #94a3b8; } .video-loading-label { margin-bottom: 16px; font-size: 0.95em; } .video-progress-bar { width: min(400px, 80vw); height: 6px; background: rgba(255, 255, 255, 0.1); border-radius: 3px; overflow: hidden; margin-bottom: 8px; } .video-progress-fill { height: 100%; background: var(--accent); border-radius: 3px; transition: width 0.15s; } .video-progress-text { font-size: 0.8em; color: #64748b; } .video-error { color: var(--error); font-size: 0.9em; text-align: center; max-width: 400px; } .play-btn { background: none; border: 1px solid var(--border); color: var(--success); width: 30px; height: 30px; border-radius: 6px; font-size: 0.85em; padding: 0; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; margin-right: 4px; } .play-btn:hover { background: var(--bg-raised); border-color: var(--success); } .play-btn:disabled { opacity: 0.3; cursor: not-allowed; } /* ── Admin panel ─────────────────────────────────────────────────────────── */ .admin-tabs { display: flex; gap: 4px; margin-bottom: 20px; border-bottom: 2px solid var(--border); flex-wrap: wrap; } .admin-tab { padding: 8px 16px; border: none; background: none; color: var(--text-secondary); font-size: 0.9em; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -2px; transition: color 0.15s, border-color 0.15s; } .admin-tab:hover { color: var(--text); } .admin-tab.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; } .admin-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; margin-bottom: 20px; } .stat-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; padding: 20px; text-align: center; } .stat-card .stat-value { font-size: 2rem; font-weight: 700; color: var(--accent); } .stat-card .stat-label { font-size: 0.8em; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); margin-top: 4px; } .admin-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; } .admin-search { flex: 1; min-width: 180px; max-width: 300px; padding: 7px 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-base); color: var(--text); font-size: 0.9em; } .admin-search:focus { outline: none; border-color: var(--border-focus); } .admin-select { padding: 7px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-base); color: var(--text); font-size: 0.85em; cursor: pointer; } .admin-table { width: 100%; border-collapse: collapse; font-size: 0.88em; } .admin-table th { text-align: left; padding: 8px 10px; border-bottom: 2px solid var(--border); color: var(--text-secondary); font-size: 0.8em; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap; } .admin-table td { padding: 8px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; } .admin-table tr:hover { background: var(--bg-raised); } .admin-table .admin-empty { text-align: center; padding: 24px; color: var(--text-dim); font-style: italic; } /* Two things this cell has to do: hold a row of buttons, and stay as tall as the rest of its row even when it is empty — the group owner cannot be removed, and neither can your own account in the admin table. `display: flex` did the second one and broke the first. **A flex