:root { color-scheme: dark; --bg: #0a0b0e; --panel: #111318; --panel-2: #181b22; --panel-3: #20242d; --line: rgba(255, 255, 255, 0.07); --line-strong: rgba(255, 255, 255, 0.14); --text: #e9eaee; --muted: #8a8f9e; --live: #ff4d4d; --blue: #5b9cff; --gold: #f5c84c; --green: #3ecf8e; --amber: #f0a441; --accent: var(--blue); --radius: 10px; --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; } * { box-sizing: border-box; } html, body { margin: 0; height: 100%; } body { font-family: var(--font); font-size: 13px; line-height: 1.45; background: var(--bg); color: var(--text); -webkit-font-smoothing: antialiased; font-feature-settings: "tnum"; } body.is-overlay { background: transparent; overflow: hidden; } a { color: inherit; text-decoration: none; } button, input, select { font: inherit; color: inherit; } h1, h2, p { margin: 0; } .muted { color: var(--muted); } /* Buttons */ .btn { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 11px; border-radius: 8px; border: 1px solid var(--line-strong); background: var(--panel-2); font-size: 12.5px; font-weight: 500; cursor: pointer; white-space: nowrap; transition: background 120ms ease, border-color 120ms ease, color 120ms ease; } .btn:hover { background: var(--panel-3); } .btn:disabled { opacity: 0.5; cursor: default; } .btn--icon { width: 32px; padding: 0; justify-content: center; } .btn--sm { height: 26px; padding: 0 8px; font-size: 12px; } .btn--primary { background: var(--live); border-color: transparent; color: #fff; } .btn--primary:hover { background: #ff6363; } .btn--danger:hover { color: var(--live); border-color: rgba(255, 77, 77, 0.5); } .btn--active { color: var(--amber); border-color: rgba(240, 164, 65, 0.6); } /* Landing */ .landing { min-height: 100vh; display: grid; place-items: center; padding: 24px; } .landing__card { width: min(100%, 460px); padding: 32px; border: 1px solid var(--line); border-radius: 16px; background: var(--panel); } .landing__card h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; } .landing__card p { margin-top: 8px; color: var(--muted); font-size: 14px; } .landing__links { display: flex; gap: 8px; margin-top: 20px; } /* Connect */ .connect { min-height: 100vh; display: grid; place-items: center; padding: 24px; } .connect__card { width: min(100%, 440px); display: flex; flex-direction: column; gap: 10px; padding: 28px; border: 1px solid var(--line); border-radius: 16px; background: var(--panel); } .connect__icon { width: 40px; height: 40px; display: grid; place-items: center; border-radius: 12px; background: rgba(255, 77, 77, 0.14); color: var(--live); margin-bottom: 6px; } .connect__card h1 { font-size: 18px; font-weight: 650; } .connect__card p { color: var(--muted); } .connect__card input { margin-top: 8px; } .connect__error { color: var(--live) !important; } .connect__card .btn { height: 38px; justify-content: center; margin-top: 4px; } input, select { height: 34px; padding: 0 10px; border-radius: 8px; border: 1px solid var(--line-strong); background: var(--bg); outline: none; transition: border-color 120ms ease; } input:focus, select:focus { border-color: var(--blue); } /* Dashboard shell */ .dash { height: 100vh; display: grid; /* minmax(0, 1fr) so a long single-line "on air" message cannot widen the page past the viewport. */ grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr); } .topbar { display: flex; align-items: center; gap: 14px; min-width: 0; height: 48px; padding: 0 12px; border-bottom: 1px solid var(--line); background: var(--panel); } .topbar__stream { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 0 1 auto; } .topbar__title { font-weight: 600; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 34vw; } .topbar__stats { display: flex; gap: 12px; margin-left: auto; color: var(--muted); font-size: 12px; white-space: nowrap; } .topbar__actions { display: flex; gap: 6px; } .search { display: flex; align-items: center; gap: 8px; flex: 0 1 380px; min-width: 160px; height: 32px; padding: 0 10px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--bg); color: var(--muted); } .search:focus-within { border-color: var(--blue); } .search input { flex: 1; height: 100%; border: 0; padding: 0; background: transparent; color: var(--text); } .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); flex: none; } .dot--live { background: var(--live); box-shadow: 0 0 0 0 rgba(255, 77, 77, 0.6); animation: pulse 1.8s ease-out infinite; } .dot--warn { background: var(--amber); } .dot--danger { background: var(--live); } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 77, 77, 0.55); } 100% { box-shadow: 0 0 0 8px rgba(255, 77, 77, 0); } } .chip { display: inline-flex; align-items: center; gap: 4px; height: 20px; padding: 0 7px; border-radius: 999px; font-size: 11px; font-weight: 600; letter-spacing: 0.02em; background: var(--panel-3); color: var(--muted); white-space: nowrap; } .chip--live { background: rgba(255, 77, 77, 0.16); color: var(--live); } .chip--warn { background: rgba(240, 164, 65, 0.16); color: var(--amber); } .chip--danger { background: rgba(255, 77, 77, 0.16); color: var(--live); } .chip--poll { background: rgba(91, 156, 255, 0.16); color: var(--blue); } /* On air strip */ .onair { display: flex; align-items: center; gap: 10px; min-width: 0; overflow: hidden; min-height: 40px; padding: 6px 12px; border-bottom: 1px solid var(--line); background: var(--panel); } .onair--live { background: linear-gradient(90deg, rgba(255, 77, 77, 0.12), var(--panel) 45%); } .onair__label { font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); flex: none; } .onair--live .onair__label { color: var(--live); } .onair__author { font-weight: 600; flex: none; } .onair__text { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .onair__hint { color: var(--muted); } /* Panels */ .grid { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: 1px; background: var(--line); min-height: 0; } .side { display: grid; grid-template-rows: minmax(0, 1fr) minmax(0, 1fr); gap: 1px; min-height: 0; min-width: 0; } .panel { display: flex; flex-direction: column; min-height: 0; min-width: 0; background: var(--bg); } .panel__head { display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 12px; font-size: 11px; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--line); flex: none; } .panel__note { margin-left: auto; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--blue); } .list { position: relative; flex: 1; min-height: 0; } .list__scroll { height: 100%; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: var(--panel-3) transparent; } .list__empty { padding: 32px 16px; text-align: center; color: var(--muted); } .list__jump, .list__paused { position: absolute; left: 50%; transform: translateX(-50%); display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 10px; border-radius: 999px; font-size: 12px; font-weight: 600; border: 1px solid var(--line-strong); background: var(--panel-3); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4); } .list__jump { bottom: 10px; cursor: pointer; color: var(--text); } .list__paused { top: 8px; color: var(--amber); } /* Message cards */ .card { display: block; width: 100%; min-width: 0; overflow: hidden; padding: 7px 12px 7px 9px; border: 0; border-left: 3px solid transparent; background: transparent; text-align: left; cursor: pointer; transition: background 100ms ease, opacity 150ms ease; } .card:hover { background: var(--panel); } .card + .card { border-top: 1px solid var(--line); } .card--selected { background: rgba(255, 77, 77, 0.1); border-left-color: var(--live); } .card--selected:hover { background: rgba(255, 77, 77, 0.14); } .card--seen { opacity: 0.5; } .card--seen:hover { opacity: 0.85; } .card--super { border-left-color: var(--accent); } .card--member { border-left-color: var(--gold); } .card__head { display: flex; align-items: center; gap: 6px; min-width: 0; } .card__author { min-width: 0; flex: 0 1 auto; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .card--super .card__author { color: #fff; } .card__time { margin-left: auto; color: var(--muted); font-size: 11px; flex: none; } .card__text { margin: 3px 0 0 30px; font-size: 13.5px; overflow-wrap: anywhere; } .card__amount { display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 6px; background: var(--accent); color: #fff; font-weight: 700; font-size: 12px; white-space: nowrap; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); } .card__level { display: inline-flex; align-items: center; gap: 4px; color: var(--gold); font-size: 12px; font-weight: 600; white-space: nowrap; } .avatar { width: 24px; height: 24px; border-radius: 50%; flex: none; object-fit: cover; background: var(--panel-3); } .avatar--sm { width: 20px; height: 20px; } .avatar--empty { display: grid; place-items: center; font-size: 11px; font-weight: 700; color: var(--muted); } .emoji { height: 1.35em; width: auto; vertical-align: -0.3em; margin: 0 1px; } .sticker { display: block; max-width: 120px; max-height: 120px; margin: 6px 0 0 30px; } .link { color: var(--blue); text-decoration: underline; text-decoration-color: rgba(91, 156, 255, 0.4); text-underline-offset: 2px; overflow-wrap: anywhere; } .badge { display: inline-flex; align-items: center; gap: 2px; height: 16px; min-width: 16px; padding: 0 3px; border-radius: 4px; font-size: 10.5px; font-weight: 700; flex: none; } .badge--image { width: 16px; height: 16px; padding: 0; border-radius: 3px; object-fit: contain; } .badge--moderator { background: rgba(91, 156, 255, 0.18); color: var(--blue); } .badge--member { background: rgba(62, 207, 142, 0.18); color: var(--green); } .badge--verified { background: rgba(255, 255, 255, 0.12); color: var(--text); } .badge--owner { background: rgba(245, 200, 76, 0.2); color: var(--gold); } .badge--rank { background: rgba(245, 200, 76, 0.18); color: var(--gold); } /* Modal */ .modal { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: 24px; background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(2px); } .modal__card { width: min(100%, 440px); display: flex; flex-direction: column; gap: 12px; padding: 20px; border: 1px solid var(--line-strong); border-radius: 14px; background: var(--panel); box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5); } .modal__card--wide { width: min(100%, 600px); } .modal__card h2 { font-size: 16px; font-weight: 650; } .modal__head { display: flex; align-items: center; justify-content: space-between; } .modal__url { padding: 10px; border-radius: 8px; background: var(--bg); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; overflow-wrap: anywhere; } .modal__actions { display: flex; justify-content: flex-end; gap: 8px; } .fields { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } .field { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); } .urlbox { display: flex; gap: 6px; } .urlbox input { flex: 1; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; } /* Toasts */ .toasts { position: fixed; right: 16px; bottom: 16px; z-index: 60; display: flex; flex-direction: column; gap: 8px; } .toast { padding: 10px 14px; border-radius: 10px; border: 1px solid rgba(255, 77, 77, 0.4); background: var(--panel-2); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45); font-size: 12.5px; } @media (max-width: 960px) { .dash { height: auto; min-height: 100vh; } .topbar { flex-wrap: wrap; height: auto; padding: 8px 12px; } .topbar__stats { margin-left: 0; } .grid { grid-template-columns: 1fr; } .grid > .panel { height: 60vh; } .side { grid-template-rows: 40vh 40vh; } .fields { grid-template-columns: 1fr; } } /* OBS overlay */ /* Sized for a 1080p canvas and scaled with the source width, so a 4K browser source looks the same as a 1080p one. */ .ov { position: fixed; inset: 0; display: flex; padding: 1.5vw; pointer-events: none; --unit: calc(100vw / 1920); --w: 640; --fs: calc(20 * var(--unit)); } .ov--size-s { --fs: calc(16 * var(--unit)); } .ov--size-l { --fs: calc(26 * var(--unit)); } .ov--size-xl { --fs: calc(34 * var(--unit)); } .ov--bl { align-items: flex-end; justify-content: flex-start; } .ov--bc { align-items: flex-end; justify-content: center; } .ov--br { align-items: flex-end; justify-content: flex-end; } .ov--tl { align-items: flex-start; justify-content: flex-start; } .ov--tc { align-items: flex-start; justify-content: center; } .ov--tr { align-items: flex-start; justify-content: flex-end; } .ov__card { max-width: min(calc(var(--w) * var(--unit)), 100%); padding: 0.7em 0.9em 0.8em; border-radius: 0.7em; font-size: var(--fs); line-height: 1.35; overflow: hidden; --card-bg: rgba(12, 13, 17, 0.92); --card-fg: #fff; --card-muted: rgba(255, 255, 255, 0.65); --card-line: rgba(255, 255, 255, 0.1); background: var(--card-bg); color: var(--card-fg); border: 1px solid var(--card-line); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45); } .ov--light .ov__card { --card-bg: rgba(255, 255, 255, 0.96); --card-fg: #15171c; --card-muted: rgba(0, 0, 0, 0.55); --card-line: rgba(0, 0, 0, 0.08); } /* Light card tuned for the blueprint paper background: navy ink, drafting-blue rule, paper white. */ .ov--blueprint .ov__card { --card-bg: rgba(247, 249, 253, 0.97); --card-fg: #1b2940; --card-muted: #5f7392; --card-line: #5b7fb8; border-width: 2px; box-shadow: 0 0.35em 1.2em rgba(27, 41, 64, 0.18); } .ov--blueprint .ov__author { color: #2f4d80; } .ov--blueprint .ov__card--super { box-shadow: 0 0 0 2px var(--accent), 0 0.35em 1.2em rgba(27, 41, 64, 0.18); } .ov--blueprint .ov__level { color: #8a6a12; } .ov--blueprint .badge--rank, .ov--blueprint .badge--owner { background: rgba(138, 106, 18, 0.15); color: #8a6a12; } .ov--blueprint .badge--verified { background: rgba(27, 41, 64, 0.1); color: #1b2940; } .ov--glass .ov__card { --card-bg: rgba(18, 19, 26, 0.55); --card-line: rgba(255, 255, 255, 0.2); backdrop-filter: blur(16px) saturate(1.4); } .ov--youtube .ov__card { --card-bg: linear-gradient(135deg, #e62117, #b31217); --card-line: rgba(255, 255, 255, 0.18); } .ov__card--super { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent), 0 12px 40px rgba(0, 0, 0, 0.45); } .ov__card--member { border-color: var(--gold); } .ov__head { display: flex; align-items: center; gap: 0.4em; font-size: 0.85em; } .ov__avatar { width: 1.7em; height: 1.7em; border-radius: 50%; object-fit: cover; } .ov__author { font-weight: 700; } .ov__head .badge { height: 1.25em; min-width: 1.25em; padding: 0 0.25em; gap: 0.15em; border-radius: 0.25em; font-size: 0.8em; } /* Lucide icons carry a pixel size attribute; in the overlay they must follow the font size. */ .ov__head .badge svg { width: 1em; height: 1em; } .ov__head .badge--image { width: 1.25em; height: 1.25em; padding: 0; } .ov__amount { margin-left: auto; padding: 0.1em 0.5em; border-radius: 0.35em; background: var(--accent); color: #fff; font-weight: 800; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); } .ov__level { margin-left: auto; color: var(--gold); font-weight: 600; } .ov__text { margin-top: 0.3em; font-weight: 500; overflow-wrap: anywhere; } .ov__text .emoji { height: 1.3em; } .ov__text .link { color: inherit; text-decoration: none; } .ov__sticker { display: block; max-width: 6em; max-height: 6em; margin-top: 0.4em; } .ov--anim-fade .ov__card { animation: ov-fade-in 240ms ease-out; } .ov--anim-fade .ov__card--leaving { animation: ov-fade-out 220ms ease-in forwards; } .ov--anim-slide .ov__card { animation: ov-slide-in 280ms cubic-bezier(0.2, 0.8, 0.2, 1); } .ov--anim-slide .ov__card--leaving { animation: ov-slide-out 220ms ease-in forwards; } .ov--tl.ov--anim-slide, .ov--tc.ov--anim-slide, .ov--tr.ov--anim-slide { --slide: -24px; } .ov--bl.ov--anim-slide, .ov--bc.ov--anim-slide, .ov--br.ov--anim-slide { --slide: 24px; } @keyframes ov-fade-in { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: scale(1); } } @keyframes ov-fade-out { to { opacity: 0; transform: scale(0.97); } } @keyframes ov-slide-in { from { opacity: 0; transform: translateY(var(--slide)); } to { opacity: 1; transform: translateY(0); } } @keyframes ov-slide-out { to { opacity: 0; transform: translateY(var(--slide)); } }