Files
netdesk/server/web/app.css
T

1303 lines
60 KiB
CSS

/* ================================================================
NetDesk design system — enterprise dark, RustDesk/TeamViewer-style
================================================================ */
:root {
--bg: #0b0e14;
--bg2: #11151f;
--bg3: #171d2a;
--bg4: #1d2536;
--fg: #e8edf6;
--muted: #8b95a9;
--faint: #5d6777;
--accent: #3d7eff;
--accent-h: #5c93ff;
--accent-dim: rgba(61, 126, 255, .14);
--ok: #2fbf71;
--warn: #f5a524;
--danger: #e5484d;
--danger-h: #f2666b;
--border: #222b3d;
--border-soft: #1a2233;
--shadow: 0 12px 40px rgba(0, 0, 0, .5);
--r-sm: 6px;
--r-md: 10px;
--r-lg: 14px;
}
/* light (corporate) theme - TeamViewer-style */
:root[data-theme="light"] {
--bg: #eef1f6;
--bg2: #ffffff;
--bg3: #f0f3f8;
--bg4: #e4e9f2;
--fg: #17202f;
--muted: #5b6577;
--faint: #98a1b3;
--border: #d9e0ea;
--border-soft: #e7ebf2;
--accent-dim: rgba(61, 126, 255, .10);
--shadow: 0 12px 40px rgba(23, 32, 47, .12);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
font-family: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, "Inter", sans-serif;
background: var(--bg);
color: var(--fg);
font-size: 13.5px;
line-height: 1.45;
-webkit-font-smoothing: antialiased;
}
svg.ic { width: 16px; height: 16px; display: block; }
/* ================= connect screen : split layout ================= */
#screenConnect { min-height: 100vh; }
.brand-pane {
flex: 1.1;
min-width: 0;
display: flex;
flex-direction: column;
justify-content: center;
padding: 48px 56px;
background:
radial-gradient(900px 500px at -10% -10%, rgba(61, 126, 255, .16), transparent 60%),
radial-gradient(700px 500px at 110% 115%, rgba(47, 191, 113, .10), transparent 60%),
var(--bg2);
border-right: 1px solid var(--border-soft);
}
.brand-logo { display: flex; align-items: center; gap: 14px; margin-bottom: 26px; }
.brand-logo h1 { font-size: 26px; font-weight: 600; letter-spacing: .2px; }
.brand-tag { font-size: 22px; font-weight: 600; line-height: 1.3; max-width: 460px; margin-bottom: 10px; }
.brand-sub { color: var(--muted); max-width: 440px; margin-bottom: 30px; }
.brand-feats { display: flex; flex-direction: column; gap: 12px; }
.feat { display: flex; gap: 12px; align-items: flex-start; color: var(--muted); max-width: 440px; }
.feat .fic {
flex-shrink: 0;
width: 30px; height: 30px;
border-radius: 8px;
background: var(--accent-dim);
color: var(--accent-h);
display: flex; align-items: center; justify-content: center;
}
.feat b { color: var(--fg); font-weight: 600; display: block; font-size: 13.5px; }
.feat span { font-size: 12.5px; }
.brand-foot { margin-top: 40px; color: var(--faint); font-size: 12px; }
.form-pane {
flex: 1;
min-width: 400px;
display: flex;
align-items: center;
justify-content: center;
padding: 32px;
overflow-y: auto;
}
.card {
width: 400px;
max-width: 96vw;
background: var(--bg2);
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: 26px;
box-shadow: var(--shadow);
}
.card .logo { display: none; }
.card h2 { font-size: 17px; font-weight: 600; margin-bottom: 2px; }
.card .sub { color: var(--muted); margin-bottom: 18px; font-size: 13px; }
label { display: block; margin: 12px 0 6px; color: var(--muted); font-size: 11.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .7px; }
input[type=text], input[type=password], input:not([type]) {
width: 100%;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--border);
border-radius: var(--r-sm);
padding: 9px 12px;
font-size: 14px;
outline: none;
transition: border-color .12s, box-shadow .12s;
}
input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
input::placeholder { color: var(--faint); }
.pw-wrap { display: flex; gap: 6px; }
.pw-wrap input { flex: 1; }
.row { display: flex; gap: 10px; }
.grow { flex: 1; }
#inId { font-size: 17px; letter-spacing: 2px; font-variant-numeric: tabular-nums; font-weight: 600; }
.chk {
display: flex; align-items: center; gap: 8px;
color: var(--muted); text-transform: none; letter-spacing: 0;
font-size: 13px; font-weight: 400; margin: 10px 0; cursor: pointer; user-select: none;
}
.chk input { accent-color: var(--accent); width: 14px; height: 14px; }
button.primary {
width: 100%;
margin-top: 12px;
background: linear-gradient(180deg, #4b88ff, #2f6ef2);
color: #fff;
border: 0;
border-radius: var(--r-sm);
padding: 11px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 14px rgba(61, 126, 255, .35);
transition: background .12s, filter .12s, transform .06s;
}
button.primary:hover { filter: brightness(1.07); }
button.primary:active { transform: translateY(1px); }
button.primary:disabled { opacity: .55; cursor: wait; }
.ghost {
background: var(--bg3);
color: var(--muted);
border: 1px solid var(--border);
border-radius: var(--r-sm);
padding: 8px 10px;
cursor: pointer;
display: flex; align-items: center; justify-content: center;
}
.ghost:hover { color: var(--fg); border-color: var(--accent); }
.error {
margin-top: 12px;
background: rgba(229, 72, 77, .10);
border: 1px solid rgba(229, 72, 77, .45);
color: #f6a9ac;
padding: 9px 12px;
border-radius: var(--r-sm);
font-size: 12.5px;
}
.hint { margin-top: 16px; color: var(--faint); font-size: 12px; line-height: 1.55; }
.hint code { background: var(--bg3); padding: 1px 5px; border-radius: 4px; }
.foot { color: var(--faint); font-size: 12px; }
.form-foot { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border-soft); display: flex; justify-content: space-between; align-items: center; }
.theme-toggle {
background: transparent; border: 1px solid var(--border); color: var(--muted);
border-radius: var(--r-sm); padding: 4px 8px; cursor: pointer; font-size: 12px;
display: inline-flex; align-items: center; gap: 6px;
}
.theme-toggle:hover { color: var(--fg); border-color: var(--accent); }
body, .card, #toolbar, .panel { transition: background-color .18s, border-color .18s, color .18s; }
#toolbar { background: var(--bg2); }
/* address book */
#abookWrap { margin-top: 16px; border-top: 1px solid var(--border-soft); padding-top: 12px; }
.ab-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; color: var(--muted); font-size: 11.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .7px; }
.ab-row {
display: flex; align-items: center; gap: 10px;
padding: 7px 8px; border-radius: var(--r-sm); cursor: pointer;
}
.ab-row:hover { background: var(--bg3); }
.ab-ava {
width: 28px; height: 28px; border-radius: 7px; flex-shrink: 0;
background: var(--accent-dim); color: var(--accent-h);
display: flex; align-items: center; justify-content: center;
font-weight: 600; font-size: 13px;
}
.ab-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ab-id { color: var(--muted); font-variant-numeric: tabular-nums; font-size: 12px; }
.ab-shared { display: inline-block; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; padding: 1px 6px; border-radius: 999px; background: rgba(77,139,255,.16); color: #9cc0ff; vertical-align: 1px; }
.ab-row .tb { padding: 3px 7px; }
/* ================= session screen ================= */
#screenSession { height: 100vh; display: flex; flex-direction: column; }
#toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
flex-wrap: wrap;
background: linear-gradient(180deg, #151a26, #10141d);
border-bottom: 1px solid var(--border);
padding: 6px 10px;
min-height: 46px;
z-index: 30;
}
.tb-group { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; flex-shrink: 0; }
.tb-title { font-weight: 600; margin-right: 4px; font-size: 13.5px; }
.state { color: var(--muted); font-size: 12px; display: flex; align-items: center; gap: 6px; }
.state::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--faint); }
.state.ok::before { background: var(--ok); box-shadow: 0 0 6px var(--ok); }
.state.warn::before { background: var(--warn); }
.state.err::before { background: var(--danger); }
.tb {
height: 30px;
display: inline-flex;
align-items: center;
gap: 6px;
background: transparent;
color: var(--fg);
border: 1px solid transparent;
border-radius: var(--r-sm);
padding: 0 9px;
font-size: 13px;
font-family: inherit;
cursor: pointer;
transition: background .1s, border-color .1s, color .1s;
white-space: nowrap;
}
.tb:hover { background: var(--bg3); border-color: var(--border); }
.tb:active { background: var(--bg4); }
.tb.active { background: var(--accent-dim); color: var(--accent-h); border-color: rgba(61, 126, 255, .45); }
.tb.danger:hover { background: rgba(229, 72, 77, .12); color: var(--danger-h); border-color: rgba(229, 72, 77, .4); }
.tb.rec-on { color: var(--danger-h); }
.tb.rec-on:hover { background: rgba(229, 72, 77, .12); }
select {
height: 30px;
background: var(--bg3);
color: var(--fg);
border: 1px solid var(--border);
border-radius: var(--r-sm);
padding: 0 8px;
font-size: 12.5px;
font-family: inherit;
outline: none;
cursor: pointer;
}
select:hover { border-color: var(--accent); }
.stats { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
#tbStats { background: var(--bg3); border: 1px solid var(--border-soft); border-radius: var(--r-sm); padding: 4px 10px; }
:root[data-theme="light"] .brand-pane {
background:
radial-gradient(900px 500px at -10% -10%, rgba(61, 126, 255, .12), transparent 60%),
radial-gradient(700px 500px at 110% 115%, rgba(47, 191, 113, .08), transparent 60%),
var(--bg2);
}
:root[data-theme="light"] #stage { background: #10141d; }
#stage { position: relative; flex: 1; overflow: hidden; background: #05070c; }
#canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
outline: none;
cursor: none;
}
#canvas.viewonly { cursor: default; }
.banner {
position: absolute;
top: 12px;
left: 50%;
transform: translateX(-50%);
background: rgba(229, 72, 77, .14);
border: 1px solid rgba(229, 72, 77, .5);
color: #fecaca;
padding: 8px 16px;
border-radius: var(--r-md);
font-size: 13px;
z-index: 20;
max-width: 80%;
backdrop-filter: blur(6px);
}
.banner.info { background: rgba(61, 126, 255, .14); border-color: rgba(61, 126, 255, .5); color: #cfe1ff; }
#dropHint {
position: absolute;
inset: 14px;
border: 2px dashed var(--accent);
border-radius: var(--r-lg);
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: var(--accent-h);
background: rgba(61, 126, 255, .08);
z-index: 25;
pointer-events: none;
}
/* ================= panels ================= */
.panel {
position: absolute;
top: 54px;
right: 12px;
width: 470px;
max-width: calc(100vw - 24px);
max-height: calc(100% - 70px);
background: var(--bg2);
border: 1px solid var(--border);
border-radius: var(--r-md);
display: flex;
flex-direction: column;
box-shadow: var(--shadow);
z-index: 40;
overflow: hidden;
}
.panel-head {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 12px;
border-bottom: 1px solid var(--border);
font-weight: 600;
font-size: 13.5px;
}
.file-path { display: flex; gap: 6px; padding: 8px 10px; border-bottom: 1px solid var(--border-soft); }
.file-path input { flex: 1; font-size: 12.5px; }
.file-list { flex: 1; overflow-y: auto; padding: 4px 0; }
.file-row {
display: flex;
align-items: center;
gap: 10px;
padding: 6px 12px;
cursor: pointer;
font-size: 13px;
}
.file-row:hover { background: var(--bg3); }
.file-row .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-row .meta { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.file-row .acts { display: none; gap: 2px; }
.file-row:hover .acts { display: flex; }
.file-row .acts button { background: none; border: 0; color: var(--muted); cursor: pointer; font-size: 13px; padding: 2px 5px; border-radius: 4px; }
.file-row .acts button:hover { color: var(--fg); background: var(--bg4); }
.panel-foot { display: flex; gap: 8px; padding: 8px 10px; border-top: 1px solid var(--border-soft); align-items: center; }
.panel-foot input { flex: 1; min-width: 0; font-size: 12.5px; }
#fileStatus { white-space: nowrap; }
.chat-log { flex: 1; overflow-y: auto; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; min-height: 220px; }
.chat-msg {
max-width: 85%;
background: var(--bg3);
border-radius: 10px 10px 10px 3px;
padding: 7px 11px;
font-size: 13px;
word-wrap: break-word;
}
.chat-msg.me { align-self: flex-end; background: var(--accent-dim); border-radius: 10px 10px 3px 10px; }
.chat-msg .who { font-size: 10.5px; color: var(--muted); margin-bottom: 2px; text-transform: uppercase; letter-spacing: .5px; }
.chat-input { display: flex; gap: 8px; padding: 8px 10px; border-top: 1px solid var(--border-soft); }
.sys-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 12px; }
.sys-grid .tb { background: var(--bg3); border-color: var(--border); height: 36px; justify-content: center; }
.sys-grid .tb:hover { border-color: var(--accent); }
.proc-head { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px 4px; color: var(--muted); font-size: 11.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .7px; border-top: 1px solid var(--border-soft); margin-top: 4px; }
#procList { max-height: 200px; }
/* collapsible panel sections (TeamViewer-style) */
details.sec { border-top: 1px solid var(--border-soft); }
details.sec:first-of-type { border-top: 0; }
details.sec > summary {
list-style: none;
display: flex;
align-items: center;
gap: 8px;
padding: 9px 12px;
cursor: pointer;
user-select: none;
color: var(--muted);
font-size: 11.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .7px;
transition: color .12s, background .12s;
}
details.sec > summary::-webkit-details-marker { display: none; }
details.sec > summary:hover { color: var(--fg); background: var(--bg3); }
details.sec[open] > summary { color: var(--accent-h); }
details.sec .chev { margin-left: auto; transition: transform .15s; color: var(--faint); }
details.sec[open] .chev { transform: rotate(180deg); }
details.sec summary .tb { padding: 2px 8px; font-size: 12px; }
#sysPanel { width: 380px; }
.panel-head { cursor: grab; }
.panel-head:active { cursor: grabbing; }
/* ================= portal ================= */
body.portal { min-height: 100vh; }
body.console { display: flex; min-height: 100vh; }
.side {
width: 230px;
flex-shrink: 0;
background: var(--bg2);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
padding: 16px 12px;
position: sticky;
top: 0;
height: 100vh;
}
.side-brand { display: flex; align-items: center; gap: 10px; padding: 4px 8px 18px; }
.side-sub { color: var(--muted); font-size: 11px; }
.side-nav { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.nav-it {
display: flex; align-items: center; gap: 10px;
padding: 9px 12px; border-radius: var(--r-sm);
color: var(--muted); text-decoration: none; font-size: 13.5px;
transition: background .1s, color .1s; border: 0; background: transparent;
font-family: inherit; cursor: pointer; text-align: left; width: 100%;
}
.nav-it:hover { background: var(--bg3); color: var(--fg); }
.nav-it.on { background: var(--accent-dim); color: var(--accent-h); }
.side-foot { display: flex; flex-direction: column; gap: 2px; border-top: 1px solid var(--border-soft); padding-top: 10px; }
.mainc { flex: 1; min-width: 0; padding: 22px 24px 48px; max-width: 1100px; }
.keyrow { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border-soft); }
.keyrow:last-child { border-bottom: 0; }
.key-l { color: var(--muted); font-size: 12px; margin-bottom: 2px; }
.key-v { font-size: 13px; word-break: break-all; }
@media (max-width: 900px) { .side { display: none; } }
.portal-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 22px;
background: var(--bg2);
border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
z-index: 10;
}
.portal-main { max-width: 1060px; margin: 0 auto; padding: 22px 16px 48px; }
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 12px; margin-bottom: 20px; }
.stat { background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-md); padding: 14px; text-align: center; }
.stat-n { font-size: 24px; font-weight: 600; font-variant-numeric: tabular-nums; }
.stat-l { color: var(--muted); font-size: 11.5px; margin-top: 2px; text-transform: uppercase; letter-spacing: .6px; }
.p-card { background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-md); padding: 16px; margin-bottom: 20px; }
.p-card h2 { font-size: 12.5px; margin-bottom: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .7px; }
.p-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 800px) {
.p-cols { grid-template-columns: 1fr; }
.brand-pane { display: none; }
.form-pane { min-width: 0; }
}
.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.tbl th { text-align: left; color: var(--muted); font-weight: 500; padding: 7px 8px; border-bottom: 1px solid var(--border); font-size: 11.5px; text-transform: uppercase; letter-spacing: .5px; }
.tbl td { padding: 9px 8px; border-bottom: 1px solid var(--border-soft); }
.tbl tr:hover td { background: var(--bg3); }
.mono { font-variant-numeric: tabular-nums; letter-spacing: .5px; }
.dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 8px; }
.dot.on { background: var(--ok); box-shadow: 0 0 6px var(--ok); }
.dot.off { background: var(--faint); }
a.connect { text-decoration: none; color: var(--accent-h); border: 1px solid rgba(61, 126, 255, .45); background: var(--accent-dim); }
a.tb { color: var(--fg); text-decoration: none; }
.feed { max-height: 300px; overflow-y: auto; display: flex; flex-direction: column; gap: 6px; }
.feed-row { display: flex; gap: 10px; font-size: 13px; }
.feed-row .stats { flex-shrink: 0; }
.feed-row.kind-auth-fail, .feed-row.kind-deny { color: #f6a9ac; }
.feed-row.kind-session { color: #a9c9ff; }
.dl-row { display: flex; gap: 12px; align-items: center; padding: 8px; border-radius: var(--r-sm); color: var(--fg); text-decoration: none; }
.dl-row:hover { background: var(--bg3); }
.dl-row .name { flex: 1; }
.muted { color: var(--muted); font-size: 13px; line-height: 1.5; }
.muted code { background: var(--bg3); padding: 1px 5px; border-radius: 4px; }
/* ================= scrollbars ================= */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 5px; border: 2px solid var(--bg2); }
::-webkit-scrollbar-thumb:hover { background: var(--border); }
::-webkit-scrollbar-track { background: transparent; }
@media (max-width: 760px) {
#screenConnect { flex-direction: column; }
.brand-pane { display: none; }
.form-pane { padding: 16px; }
}
/* auth modal + account chip + fullscreen pill */
.modal-wrap { position: fixed; inset: 0; background: rgba(5,7,12,.7); backdrop-filter: blur(4px);
z-index: 100; display: flex; align-items: center; justify-content: center; }
.modal-wrap[hidden] { display: none; }
.modal-card { width: 360px; max-width: 94vw; background: var(--bg2); border: 1px solid var(--border);
border-radius: var(--r-lg); padding: 22px; position: relative; box-shadow: var(--shadow); }
.modal-x { position: absolute; top: 10px; right: 12px; background: none; border: 0;
color: var(--muted); font-size: 15px; cursor: pointer; }
.auth-tabs { display: flex; gap: 4px; margin-bottom: 14px; }
.atab { flex: 1; background: var(--bg3); border: 1px solid var(--border); color: var(--muted);
padding: 8px 4px; border-radius: var(--r-sm); cursor: pointer; font-size: 12.5px; font-family: inherit; }
.atab.on { background: var(--accent-dim); color: var(--accent-h); border-color: rgba(61,126,255,.45); }
.apane { display: flex; flex-direction: column; gap: 10px; }
.apane[hidden] { display: none; }
.apane .primary { margin-top: 2px; }
.auok { margin-top: 12px; background: rgba(47,191,113,.12); border: 1px solid rgba(47,191,113,.45);
color: #8fe6bd; padding: 9px 12px; border-radius: var(--r-sm); font-size: 12.5px; }
#authChip { display: inline-flex; align-items: center; gap: 6px; }
#authChip .tb { padding: 2px 8px; font-size: 11.5px; }
.fs-pill { position: absolute; top: 60px; left: 50%; transform: translateX(-50%); z-index: 45;
background: var(--accent); color: #fff; border: 0; border-radius: 999px; padding: 12px 26px;
font-size: 15px; font-weight: 600; cursor: pointer; box-shadow: 0 8px 30px rgba(0,0,0,.5);
font-family: inherit; }
#toolbar.autohide { transform: translateY(-110%); transition: transform .25s ease; }
#toolbar { transition: transform .25s ease; }
.plan-strip { display: flex; gap: 8px; align-items: center; justify-content: center;
margin-top: 12px; font-size: 12px; color: var(--muted); flex-wrap: wrap; }
.dotsep { color: var(--faint); }
.linkbtn { background: none; border: 0; color: var(--accent-h); cursor: pointer;
font-size: 12px; padding: 0; text-decoration: underline; font-family: inherit; }
#tbStats.limit-warn { color: #f6a9ac; }
/* ================= RustDesk-style landing ================= */
.topnote { background: #eaf2ff; color: #1e3a6e; text-align: center;
padding: 9px 16px; font-size: 13.5px; border-bottom: 1px solid #d6e4ff; }
:root[data-theme="dark"] .topnote, body[data-theme="dark"] .topnote { background: #16233d; color: #b9d2ff; border-color: #1d3054; }
.nav { display: flex; align-items: center; justify-content: space-between;
padding: 14px 5vw; background: var(--bg2); border-bottom: 1px solid var(--border); }
.nav-brand { display: flex; align-items: center; gap: 9px; font-size: 20px; }
.nav-links { display: flex; align-items: center; gap: 22px; }
.nav-links a { color: var(--fg); text-decoration: none; font-size: 14.5px; opacity: .85; }
.nav-links a:hover { opacity: 1; color: var(--accent-h); }
.hero { display: flex; gap: 40px; align-items: center; justify-content: center;
padding: 64px 5vw 48px; flex-wrap: wrap;
background:
radial-gradient(900px 500px at 8% 0%, rgba(61,126,255,.10), transparent 55%),
radial-gradient(700px 500px at 95% 100%, rgba(61,126,255,.07), transparent 55%);
}
.hero-copy h1 { font-size: 52px; line-height: 1.08; letter-spacing: -1.2px; font-weight: 800; }
.hero-sub { font-size: 17px; color: var(--muted); max-width: 560px; margin: 18px 0 26px; line-height: 1.6; }
.hero-cta { display: flex; gap: 14px; }
.btn-big { display: inline-flex; align-items: center; gap: 8px; padding: 13px 28px;
border-radius: 999px; font-size: 15.5px; font-weight: 600; text-decoration: none;
transition: transform .08s, filter .15s, background .15s; }
.btn-blue { background: var(--accent); color: #fff; box-shadow: 0 6px 22px rgba(61,126,255,.4); }
.btn-blue:hover { filter: brightness(1.08); transform: translateY(-1px); }
.btn-ghost { border: 1.5px solid var(--border); color: var(--fg); background: var(--bg2); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent-h); }
.dl-ic { font-size: 13px; }
.hero-card { width: 400px; max-width: 94vw; }
.hero-card .card { padding: 22px; }
.feat-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
gap: 18px; padding: 30px 5vw 40px; max-width: 1250px; margin: 0 auto; }
.dl-band { display: flex; align-items: center; justify-content: space-between; gap: 24px;
flex-wrap: wrap; background: var(--bg2); border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border); padding: 34px 5vw; }
.dl-band h2 { font-size: 24px; margin-bottom: 6px; }
.dl-band p { color: var(--muted); max-width: 560px; }
.foot-band { display: flex; align-items: center; justify-content: space-between;
gap: 16px; flex-wrap: wrap; padding: 18px 5vw; color: var(--muted); font-size: 12.5px;
border-top: 1px solid var(--border); }
:root[data-theme="dark"] .hero { background:
radial-gradient(900px 500px at 8% 0%, rgba(61,126,255,.16), transparent 55%),
radial-gradient(700px 500px at 95% 100%, rgba(61,126,255,.08), transparent 55%); }
:root[data-theme="light"] .hero { background:
radial-gradient(900px 500px at 8% 0%, rgba(61,126,255,.10), transparent 55%),
radial-gradient(700px 500px at 95% 100%, rgba(61,126,255,.05), transparent 55%); }
/* docked (minimized to right edge) panels */
.panel.docked { width: 42px !important; min-height: 170px; cursor: pointer; }
.panel.docked > *:not(.panel-head) { display: none !important; }
.panel.docked .panel-head { padding: 12px 0; justify-content: center; cursor: pointer; }
.panel.docked .panel-head span { display: none; }
.panel.docked .panel-head button { display: none; }
.panel.docked::after {
content: attr(data-title);
writing-mode: vertical-rl;
color: var(--accent-h);
font-size: 12.5px;
font-weight: 600;
position: absolute;
top: 44px;
left: 50%;
transform: translateX(-50%);
letter-spacing: 1px;
}
.panel.docked .panel-head .dock-arrow { display: block; color: var(--accent-h); }
/* session tab: landing fully hidden, pure dark stage */
body.nw #screenConnect { display: none !important; }
body.nw { background: #05070c; }
#screenConnect.launched { opacity: .35; pointer-events: none; filter: saturate(.4); }
#screenConnect { transition: opacity .3s, filter .3s; }
.nav-auth-btn { background: var(--accent); color: #fff; border: 0; border-radius: 999px;
padding: 8px 18px; font-size: 13.5px; font-weight: 600; cursor: pointer; font-family: inherit; }
.nav-auth-btn:hover { filter: brightness(1.1); }
.nav-auth-email { color: var(--muted); font-size: 13px; }
/* ---- fixes: hidden must always win; letterboxed canvas with a visible cursor ---- */
[hidden] { display: none !important; }
#canvas { object-fit: contain; cursor: default; }
/* my computers (account device list) */
#myDevsWrap { margin-top: 16px; border-top: 1px solid var(--border-soft); padding-top: 12px; }
.dev-dot { width: 8px; height: 8px; border-radius: 50%; background: #8b95a5; flex-shrink: 0; }
.dev-dot.on { background: #2fbf71; box-shadow: 0 0 6px #2fbf71; }
.dev-dot.busy { background: #e0a53a; }
/* ================= premium polish (v21) ================= */
/* toolbar: soft depth + crisper separators */
#toolbar { box-shadow: 0 1px 0 rgba(255,255,255,.03) inset, 0 6px 20px rgba(0,0,0,.28); }
.tb { transition: background .12s, border-color .12s, color .12s, transform .06s, box-shadow .12s; }
.tb:hover { box-shadow: 0 2px 8px rgba(0,0,0,.25); }
.tb:active { transform: translateY(1px); }
.tb.active { box-shadow: 0 0 0 1px rgba(61,126,255,.25), 0 2px 10px rgba(61,126,255,.18); }
.tb svg.ic { transition: transform .12s; }
.tb:hover svg.ic { transform: scale(1.06); }
/* live connection-quality dot on the stats pill */
#tbStats { display: inline-flex; align-items: center; gap: 7px; font-weight: 500; }
#tbStats::before {
content: ""; width: 8px; height: 8px; border-radius: 50%;
background: var(--faint); flex-shrink: 0; transition: background .3s, box-shadow .3s;
}
#tbStats[data-q="good"]::before { background: var(--ok); box-shadow: 0 0 7px var(--ok); }
#tbStats[data-q="ok"]::before { background: var(--warn); box-shadow: 0 0 7px var(--warn); }
#tbStats[data-q="bad"]::before { background: var(--danger); box-shadow: 0 0 7px var(--danger); }
/* selects: match the premium button feel */
select { transition: border-color .12s, box-shadow .12s; }
select:hover, select:focus { box-shadow: 0 0 0 3px var(--accent-dim); }
/* floating panels: deeper, softer, glassy */
.panel {
box-shadow: 0 20px 60px rgba(0,0,0,.55), 0 0 0 1px var(--border);
border-radius: var(--r-lg);
backdrop-filter: blur(10px) saturate(120%);
}
:root[data-theme="light"] .panel { backdrop-filter: blur(10px) saturate(105%); }
.panel-head { border-top-left-radius: var(--r-lg); border-top-right-radius: var(--r-lg); }
/* connect card: subtle premium lift + accent top edge */
.hero-card .card, #connect {
box-shadow: 0 24px 70px rgba(0,0,0,.35), 0 0 0 1px var(--border);
position: relative; overflow: hidden;
}
.hero-card .card::before {
content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
background: linear-gradient(90deg, var(--accent), #7aa8ff 45%, var(--ok));
opacity: .9;
}
.primary {
background: linear-gradient(180deg, var(--accent-h), var(--accent));
box-shadow: 0 6px 18px rgba(61,126,255,.30);
transition: filter .12s, transform .06s, box-shadow .12s;
}
.primary:hover { filter: brightness(1.06); box-shadow: 0 8px 22px rgba(61,126,255,.38); }
.primary:active { transform: translateY(1px); }
/* state label: pill-ify while live for a pro look */
.state.ok { color: var(--ok); }
/* smooth canvas cursor feel */
#canvas { image-rendering: auto; }
/* remote cursor overlay (RustDesk-style: the real remote cursor shape) */
#remoteCursor {
position: absolute; pointer-events: none; z-index: 5;
image-rendering: auto; will-change: left, top;
}
#stage.remote-cursor #canvas { cursor: none; }
/* ================================================================
FIX: the live-session screen is ALWAYS dark (the toolbar bg is dark),
so pin every toolbar/panel control color explicitly. Before this, light
theme set --fg to a dark color -> dark icons on the dark toolbar =
"invisible buttons / no disconnect button".
================================================================ */
#screenSession { color-scheme: dark; }
#toolbar { color: #e8edf6; }
#toolbar .tb { color: #e8edf6; }
#toolbar .tb:hover { background: #1d2637; border-color: #2c3a55; color: #ffffff; }
#toolbar .tb.active { background: rgba(61,126,255,.16); color: #6aa1ff; border-color: rgba(61,126,255,.5); }
#toolbar .tb.danger { background: rgba(229,72,77,.14); border: 1px solid rgba(229,72,77,.45); color: #f2868b; }
#toolbar .tb.danger:hover { background: rgba(229,72,77,.26); color: #ffb3b6; }
#toolbar .tb-title { color: #e8edf6; }
#toolbar .state { color: #9aa4b9; }
#toolbar .sep { background: #26314a; }
#toolbar select { background: #171d2a; color: #e8edf6; border-color: #26314a; }
#toolbar #tbStats { background: #171d2a; border-color: #202a40; color: #aab4c8; }
#toolbar svg.ic { stroke: currentColor; }
/* app page responsiveness: stack the connect hero on narrow screens */
@media (max-width: 980px) {
.hero { flex-direction: column; gap: 22px; padding: 24px 16px; }
.hero-copy h1 { font-size: clamp(26px, 7vw, 40px); }
.hero-card, .hero-card .card { width: 100%; max-width: 520px; }
}
/* ===== RustDesk-style floating session toolbar (1.5) ===== */
#screenSession { position: relative; }
#toolbar {
position: absolute; top: 0; left: 50%; transform: translateX(-50%);
width: auto; max-width: calc(100vw - 20px);
border: 1px solid #26314a; border-top: none;
border-radius: 0 0 14px 14px;
background: rgba(13,17,26,.95);
backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
padding: 6px 12px; justify-content: center;
box-shadow: 0 10px 34px rgba(0,0,0,.5);
}
#toolbar.autohide { transform: translate(-50%, -110%); }
#toolbar.collapsed { transform: translate(-50%, -100%); }
#toolbar.collapsed.autohide { transform: translate(-50%, -110%); }
#stage { position: absolute; inset: 0; }
#tbTab {
position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
width: 52px; height: 17px; border: 1px solid #26314a; border-top: none;
border-radius: 0 0 11px 11px; background: rgba(13,17,26,.95);
color: #9aa4b9; cursor: pointer; font-size: 10px; line-height: 13px;
padding: 0; text-align: center;
}
#tbTab:hover { color: #fff; background: #1d2637; }
@media (max-width: 900px) { #toolbar { max-width: calc(100vw - 8px); padding: 5px 8px; } }
/* portal dashboard layout: sidebar + main side by side */
#viewDash { display: flex; flex: 1; min-width: 0; }
/* ===== TeamViewer-style session menus (1.5) ===== */
.menu-btn { font-weight: 600; }
.menu-btn.open { background: #1d2637; border-color: #2c3a55; }
.tmenu {
position: absolute; top: 100%; margin-top: 4px; z-index: 60;
min-width: 230px; max-height: 62vh; overflow-y: auto;
background: rgba(13,17,26,.98); border: 1px solid #26314a; border-radius: 10px;
padding: 6px; box-shadow: 0 16px 44px rgba(0,0,0,.55);
backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.tmenu .mi {
display: flex; width: 100%; align-items: center; justify-content: space-between;
gap: 14px; background: transparent; border: 0; border-radius: 7px;
color: #dbe3f0; font-size: 12.5px; padding: 7px 10px; cursor: pointer;
text-align: left; font-family: inherit;
}
.tmenu .mi:hover { background: #1d2637; color: #fff; }
.tmenu .mhead {
font-size: 10px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase;
color: #6b7891; padding: 8px 10px 4px;
}
.tmenu .msep { height: 1px; background: #222c42; margin: 5px 4px; }
.tmenu .mtick { visibility: hidden; color: #4ade80; font-weight: 700; }
.tmenu .mi.on .mtick { visibility: visible; }
/* Original (1:1) scaling: real pixels + scrollbars, like TeamViewer's "Original" */
#stage.orig { overflow: auto; }
#stage.orig #canvas { position: static; inset: auto; width: auto; height: auto; }
/* ===== premium account modal (1.5) ===== */
.auth-card.modal-card {
width: 408px; max-width: 94vw; padding: 26px 28px 18px; border-radius: 18px;
background: linear-gradient(180deg, #141b26, #0e131c);
border: 1px solid #27334a;
box-shadow: 0 40px 110px -20px rgba(0,0,0,.85), 0 0 0 1px rgba(255,255,255,.02) inset,
0 24px 60px -30px rgba(61,126,255,.35);
}
.auth-head { display: flex; align-items: center; gap: 11px; margin-bottom: 18px; }
.auth-logo {
width: 38px; height: 38px; border-radius: 10px; flex-shrink: 0;
background: linear-gradient(180deg, #25d386, #16a765);
display: inline-flex; align-items: center; justify-content: center;
box-shadow: 0 6px 18px rgba(37,211,134,.35);
}
.auth-brand { font-size: 18px; font-weight: 800; color: #e8edf6; letter-spacing: -.3px; }
.auth-brand i { font-style: normal; font-weight: 500; color: #64748b; }
.auth-card .auth-tabs {
display: flex; gap: 0; margin-bottom: 18px; background: #0b0f16;
border: 1px solid #202b3f; border-radius: 11px; padding: 4px;
}
.auth-card .atab {
flex: 1; background: transparent; border: 0; border-radius: 8px;
color: #8b96a6; font-size: 12.5px; font-weight: 600; padding: 8px 4px;
cursor: pointer; transition: color .15s, background .15s;
}
.auth-card .atab:hover { color: #cbd5e1; }
.auth-card .atab.on {
background: linear-gradient(180deg, #3d7eff, #2f66db); color: #fff;
box-shadow: 0 4px 14px rgba(61,126,255,.4);
}
.auth-title { font-size: 19px; font-weight: 750; color: #f1f5fb; margin: 0 0 4px; letter-spacing: -.3px; }
.auth-sub { font-size: 12.5px; color: #7d8a9d; margin: 0 0 12px; line-height: 1.55; }
.auth-lbl {
font-size: 10.5px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase;
color: #6b7891; margin: 2px 0 -3px;
}
.auth-card .apane input {
height: 43px; background: #0d1219; border: 1px solid #263241; border-radius: 10px;
color: #e8edf6; font-size: 13.5px; padding: 0 14px; outline: none;
transition: border-color .15s, box-shadow .15s; width: 100%;
}
.auth-card .apane input:focus {
border-color: #3d7eff; box-shadow: 0 0 0 3px rgba(61,126,255,.18);
}
/* Chrome autofill was painting the field WHITE - pin it to the dark theme */
.auth-card input:-webkit-autofill,
.auth-card input:-webkit-autofill:hover,
.auth-card input:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 60px #0d1219 inset !important;
-webkit-text-fill-color: #e8edf6 !important;
caret-color: #e8edf6;
border: 1px solid #263241;
}
.auth-card .auth-cta {
height: 43px; margin-top: 8px; border: 0; border-radius: 10px; cursor: pointer;
background: linear-gradient(180deg, #4d8dff, #2f6ae0); color: #fff;
font-size: 14px; font-weight: 700; letter-spacing: .2px;
box-shadow: 0 10px 26px -8px rgba(61,126,255,.55);
transition: transform .12s, box-shadow .15s, filter .15s;
}
.auth-card .auth-cta:hover { filter: brightness(1.08); transform: translateY(-1px);
box-shadow: 0 14px 30px -8px rgba(61,126,255,.65); }
.auth-card .auth-cta:active { transform: translateY(0); }
.auth-card .foot {
font-size: 11.5px; color: #6b7891; line-height: 1.55; margin-top: 10px;
background: rgba(61,126,255,.06); border: 1px solid rgba(61,126,255,.14);
border-radius: 9px; padding: 9px 12px;
}
.auth-secure {
margin-top: 16px; padding-top: 12px; border-top: 1px solid #1c2534;
font-size: 10.5px; color: #56637a; text-align: center; letter-spacing: .2px;
}
.auth-card .modal-x { top: 14px; right: 14px; width: 30px; height: 30px; border-radius: 8px;
color: #6b7891; font-size: 13px; transition: background .15s, color .15s; }
.auth-card .modal-x:hover { background: #1b2434; color: #fff; }
.auth-card .error, .auth-card .auok { margin-top: 12px; }
/* ===== docked slim menu-bar toolbar (TeamViewer style, 1.5.1) =====
The bar sits ABOVE the video in normal flow - it never covers the screen.
▲ collapses it to a tiny top-center tab; ▼ brings it back. */
#screenSession { display: flex; flex-direction: column; position: relative; }
#toolbar {
position: relative; top: auto; left: auto; transform: none;
width: 100%; max-width: none;
border: 0; border-bottom: 1px solid #232e45; border-radius: 0;
background: linear-gradient(180deg, #101623, #0c111b);
backdrop-filter: none; -webkit-backdrop-filter: none;
padding: 4px 10px; min-height: 42px;
flex-wrap: nowrap; justify-content: flex-start; gap: 6px;
box-shadow: 0 4px 18px rgba(0,0,0,.35);
}
#toolbar.autohide, #toolbar.collapsed.autohide { transform: none; }
#toolbar.collapsed { display: none; }
#stage { position: relative; inset: auto; flex: 1; min-height: 0; }
/* single-row discipline: groups never wrap; the stats text yields first */
#toolbar .tb-group { flex-wrap: nowrap; flex-shrink: 0; }
#toolbar .tb-group:last-of-type { flex-shrink: 1; min-width: 0; margin-left: auto; }
#tbStats { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 11px; }
.tb-title { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 12.5px; }
#toolbar .tb { height: 29px; padding: 0 8px; font-size: 12px; }
#toolbar select { height: 29px; font-size: 11.5px; max-width: 160px; }
#toolbar .menu-btn { padding: 0 10px; }
#toolbar .sep { height: 18px; margin: 0 2px; }
/* the ▲ collapse control lives IN the bar, far right */
#toolbar #tbTab {
position: static; top: auto; left: auto; transform: none;
width: 30px; height: 29px; flex-shrink: 0; margin-left: 2px;
border: 1px solid #26314a; border-radius: 7px;
background: transparent; color: #9aa4b9; font-size: 10px; line-height: 1;
}
#toolbar #tbTab:hover { background: #1d2637; color: #fff; }
/* tiny reopen tab when collapsed - hangs at top-center, TeamViewer style */
#tbShow {
position: absolute; top: 0; left: 50%; transform: translateX(-50%); z-index: 55;
height: 22px; padding: 0 14px; border: 1px solid #26314a; border-top: 0;
border-radius: 0 0 12px 12px; background: rgba(13,17,26,.94);
color: #9aa4b9; font-size: 11px; font-weight: 600; cursor: pointer;
box-shadow: 0 8px 22px rgba(0,0,0,.45);
}
#tbShow:hover { color: #fff; background: #1a2334; }
#tbShow[hidden] { display: none; }
/* progressive slimming on narrow windows - never a second row */
@media (max-width: 1300px) { #tbState { display: none; } }
@media (max-width: 1180px) { #selQuality { display: none; } .tb-title { max-width: 110px; } }
@media (max-width: 1020px) { #btnViewOnly span, #btnKbdLock span { display: none; }
#toolbar .menu-btn { padding: 0 7px; font-size: 11.5px; } }
@media (max-width: 880px) { #tbStats { display: none; } #selMonitor { max-width: 120px; } }
/* ===== touch / mobile support (1.5.1) ===== */
/* without touch-action:none the browser pans/zooms instead of sending
pointer events - THE reason touch "didn't work" on tablets/phones */
#canvas { touch-action: none; }
#stage { touch-action: none; }
.touch-only { display: none !important; }
@media (pointer: coarse) {
.touch-only { display: inline-flex !important; }
}
/* invisible input that summons the phone/tablet on-screen keyboard */
#oskInput {
position: fixed; bottom: 0; left: 0; width: 2px; height: 2px;
opacity: 0.01; border: 0; padding: 0; background: transparent; color: transparent;
pointer-events: none; z-index: -1;
}
/* ===== 3D polish for the docked control bar (1.5.2) ===== */
#toolbar {
min-height: 46px; padding: 6px 12px; gap: 8px;
background: linear-gradient(180deg, #1b2434 0%, #141b29 45%, #0e141f 100%);
border-bottom: 1px solid #05080f;
box-shadow: inset 0 1px 0 rgba(255,255,255,.07),
inset 0 -1px 0 rgba(255,255,255,.02),
0 8px 26px rgba(0,0,0,.55);
}
#toolbar .tb-group { gap: 6px; }
/* raised 3D buttons with a real pressed state */
#toolbar .tb {
height: 31px; padding: 0 10px; border-radius: 8px;
background: linear-gradient(180deg, #253044, #1a2333);
border: 1px solid #0b111d;
box-shadow: inset 0 1px 0 rgba(255,255,255,.09), 0 1px 3px rgba(0,0,0,.45);
color: #c9d4e3;
transition: background .12s, box-shadow .12s, transform .06s, color .12s;
}
#toolbar .tb:hover {
background: linear-gradient(180deg, #2d3a54, #222d42);
color: #fff; border-color: #0b111d;
box-shadow: inset 0 1px 0 rgba(255,255,255,.13), 0 3px 8px rgba(0,0,0,.5);
}
#toolbar .tb:active { transform: translateY(1px);
background: #18202f; box-shadow: inset 0 2px 6px rgba(0,0,0,.55); }
#toolbar .tb.active {
background: linear-gradient(180deg, #2d5290, #234070);
border-color: #142643; color: #d9e7ff;
box-shadow: inset 0 1px 0 rgba(255,255,255,.16), inset 0 0 12px rgba(61,126,255,.3);
}
#toolbar .tb.danger {
background: linear-gradient(180deg, #93323a, #701f26);
border-color: #400f13; color: #ffdcde;
box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 2px 10px rgba(229,72,77,.35);
}
#toolbar .tb.danger:hover {
background: linear-gradient(180deg, #aa3b45, #86262e); color: #fff;
}
/* Actions / View / Extras behave like real app menus: flat, raise on hover */
#toolbar .menu-btn {
background: transparent; border-color: transparent; box-shadow: none;
font-weight: 650; color: #d5dde9;
}
#toolbar .menu-btn:hover, #toolbar .menu-btn.open {
background: linear-gradient(180deg, #2b3852, #202b3f);
border-color: #0b111d;
box-shadow: inset 0 1px 0 rgba(255,255,255,.11), 0 2px 6px rgba(0,0,0,.45);
}
/* selects match the 3D buttons, custom chevron */
#toolbar select {
height: 31px; border-radius: 8px; padding: 0 26px 0 11px;
-webkit-appearance: none; appearance: none;
background: linear-gradient(180deg, #253044, #1a2333)
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238b96a6' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")
no-repeat right 9px center;
border: 1px solid #0b111d; color: #c9d4e3;
box-shadow: inset 0 1px 0 rgba(255,255,255,.09), 0 1px 3px rgba(0,0,0,.45);
cursor: pointer;
}
#toolbar select:hover { color: #fff;
background-image: linear-gradient(180deg, #2d3a54, #222d42),
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23cfd8e6' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); }
/* engraved separators */
#toolbar .sep {
width: 1px; height: 24px; margin: 0 3px; background:
linear-gradient(180deg, transparent, #05080f 25%, #05080f 75%, transparent);
box-shadow: 1px 0 0 rgba(255,255,255,.05);
}
/* title + live pill + inset stats chip */
#toolbar .tb-title { font-weight: 700; text-shadow: 0 1px 2px rgba(0,0,0,.6); }
#tbState {
background: #0c1320; border: 1px solid #080d17; border-radius: 999px;
padding: 3px 11px; box-shadow: inset 0 1px 3px rgba(0,0,0,.45), 0 1px 0 rgba(255,255,255,.04);
}
#tbStats {
background: #0b101b; border: 1px solid #070c15; border-radius: 8px;
padding: 6px 11px;
box-shadow: inset 0 1px 3px rgba(0,0,0,.5), 0 1px 0 rgba(255,255,255,.04);
}
/* dropdown menus + reopen tab share the depth */
.tmenu {
background: linear-gradient(180deg, #171f2f, #0f1522);
border-color: #0b111d;
box-shadow: 0 20px 54px rgba(0,0,0,.65), inset 0 1px 0 rgba(255,255,255,.06);
}
#tbShow {
background: linear-gradient(180deg, #1b2434, #10161f);
border-color: #0b111d;
box-shadow: 0 10px 26px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.08);
}
/* single-row overflow guards: Disconnect and the collapse tab must NEVER clip;
the stats chip yields first, then labels, then stats hides entirely */
#toolbar .tb-group:last-of-type > .tb, #toolbar #tbTab { flex-shrink: 0; }
#tbStats { flex: 0 1 auto; max-width: 300px; }
#toolbar .menu-btn { padding: 0 8px; }
#toolbar .tb-title { max-width: 128px; }
#toolbar select { max-width: 150px; }
@media (max-width: 1520px) {
#btnViewOnly span, #btnKbdLock span { display: none; }
}
@media (max-width: 1400px) { #tbStats { display: none; } }
@media (max-width: 1080px) { #btnDisconnect span { display: none; } #tbState { display: none; } }
/* ===== control bar: TeamViewer-grade flat premium (1.5.3, final pass) =====
Calm flat surface, ghost controls that light up on hover, one bold red
Disconnect pill. Overrides the heavier 3D pass above. */
#toolbar {
min-height: 50px; padding: 8px 14px; gap: 10px;
background: linear-gradient(180deg, #121926, #0d1219);
border-bottom: 1px solid rgba(255,255,255,.06);
box-shadow: 0 10px 30px rgba(0,0,0,.45);
}
#toolbar .tb-group { gap: 4px; }
/* ghost buttons: quiet until you need them */
#toolbar .tb {
height: 34px; min-width: 34px; padding: 0 11px; border-radius: 9px;
background: transparent; border: 1px solid transparent; box-shadow: none;
color: #b9c6d8; font-size: 12.5px; justify-content: center;
}
#toolbar .tb:hover {
background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.06);
color: #fff; box-shadow: none;
}
#toolbar .tb:active { transform: none; background: rgba(0,0,0,.35);
box-shadow: inset 0 2px 5px rgba(0,0,0,.45); }
#toolbar .tb.active {
background: rgba(61,126,255,.16); border-color: rgba(61,126,255,.4);
color: #7fb0ff; box-shadow: none;
}
#toolbar .menu-btn { font-weight: 650; color: #dbe3ee; padding: 0 12px;
background: transparent; border-color: transparent; box-shadow: none; }
#toolbar .menu-btn:hover, #toolbar .menu-btn.open {
background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.06); box-shadow: none; }
/* selects as quiet inset wells */
#toolbar select {
height: 34px; border-radius: 9px; padding: 0 28px 0 12px;
background-color: rgba(255,255,255,.05);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238b96a6' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
background-repeat: no-repeat; background-position: right 10px center;
border: 1px solid rgba(255,255,255,.09); color: #c6d2e2; box-shadow: none;
}
#toolbar select:hover { background-color: rgba(255,255,255,.09); color: #fff;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23cfd8e6' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); }
/* hairline separators */
#toolbar .sep { width: 1px; height: 22px; margin: 0 6px;
background: rgba(255,255,255,.08); box-shadow: none; }
/* identity cluster: bold name + breathing live dot, no boxes */
#toolbar .tb-title { font-size: 13px; font-weight: 700; color: #eef3fa; text-shadow: none; }
#tbState { background: transparent; border: 0; box-shadow: none; padding: 0 4px;
font-size: 12px; color: #8ea3bd; }
#tbState.ok::before { animation: livepulse 2.2s ease-in-out infinite; }
@keyframes livepulse { 0%,100% { box-shadow: 0 0 4px var(--ok); } 50% { box-shadow: 0 0 11px var(--ok); } }
/* stats: quiet telemetry text, no box */
#tbStats { background: transparent; border: 0; box-shadow: none; padding: 0 6px;
font-size: 11.5px; color: #7f93ad; letter-spacing: .2px; }
/* THE red pill - always fully visible, unmistakable */
#toolbar .tb.danger {
height: 34px; padding: 0 18px; border-radius: 999px; flex-shrink: 0;
background: linear-gradient(180deg, #ef5158, #d63a41);
border: 1px solid #b02a30; color: #fff; font-weight: 650;
box-shadow: 0 4px 16px rgba(229,72,77,.4), inset 0 1px 0 rgba(255,255,255,.22);
}
#toolbar .tb.danger:hover {
background: linear-gradient(180deg, #ff5f66, #e2444b);
box-shadow: 0 6px 20px rgba(229,72,77,.55), inset 0 1px 0 rgba(255,255,255,.25);
color: #fff;
}
#toolbar #tbTab { width: 34px; height: 34px; border-radius: 9px;
border: 1px solid transparent; background: transparent; color: #8ea3bd; }
#toolbar #tbTab:hover { background: rgba(255,255,255,.08); color: #fff; }
/* stats only when there is truly room; never a crushed "1920×…" fragment */
@media (max-width: 1620px) { #tbStats { display: none; } }
#toolbar .tb-title { max-width: 175px; }
/* exact TeamViewer right-edge order: … [icons] | ▲ collapse | [red end button] */
#toolbar #tbTab { order: 8; margin-left: auto; }
#toolbar .tb-group:last-of-type { order: 9; margin-left: 0; }
#toolbar { padding-right: 10px; }
/* ===== TeamViewer light skin for the session bar (reference-matched) ===== */
#toolbar {
margin: 8px 10px 0; border-radius: 11px; width: auto;
min-height: 46px; padding: 5px 10px;
background: linear-gradient(180deg, #ffffff, #f2f4f7);
border: 1px solid #d8dde4; border-bottom: 1px solid #c9cfd8;
box-shadow: 0 1px 0 rgba(255,255,255,.9) inset,
0 10px 28px rgba(0,0,0,.45), 0 2px 6px rgba(0,0,0,.25);
}
#toolbar .tb {
color: #3d4756; background: transparent; border: 1px solid transparent;
height: 34px; border-radius: 8px;
}
#toolbar .tb:hover { background: #e8ecf1; border-color: #d6dbe2; color: #1d2530;
box-shadow: 0 1px 0 rgba(255,255,255,.8) inset; }
#toolbar .tb:active { background: #dde2e9; box-shadow: inset 0 2px 4px rgba(0,0,0,.12); }
#toolbar .tb.active { background: #e3edff; border-color: #bdd3f5; color: #1e64d8; box-shadow: none; }
#toolbar .menu-btn { color: #2c3644; font-weight: 600; }
#toolbar .menu-btn:hover, #toolbar .menu-btn.open {
background: #e8ecf1; border-color: #d6dbe2; box-shadow: none; }
#toolbar select {
background-color: #fbfcfd; color: #2c3644; border: 1px solid #ccd3dc;
box-shadow: inset 0 1px 2px rgba(0,0,0,.05);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235b6878' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
}
#toolbar select:hover { background-color: #fff; color: #10151d; border-color: #b9c2cd;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%232c3644' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); }
#toolbar .sep { background: #d8dde4; box-shadow: 1px 0 0 #ffffff; height: 24px; }
#toolbar .tb-title { color: #16202e; }
#tbState { color: #5b6878; }
#tbStats { color: #6a7686; }
/* the red end button: compact, filled, unmistakable - like the reference */
#toolbar .tb.danger {
padding: 0 12px; border-radius: 8px;
background: linear-gradient(180deg, #ee4048, #d92730);
border: 1px solid #b21e26; color: #fff;
box-shadow: 0 1px 0 rgba(255,255,255,.3) inset, 0 3px 10px rgba(217,39,48,.4);
}
#toolbar .tb.danger:hover { background: linear-gradient(180deg, #f9525a, #e63039); }
#toolbar #tbTab { color: #5b6878; }
#toolbar #tbTab:hover { background: #e8ecf1; color: #1d2530; }
/* dropdown menus + info panel go light to match */
.tmenu {
background: #ffffff; border: 1px solid #d8dde4;
box-shadow: 0 16px 44px rgba(0,0,0,.35), 0 2px 8px rgba(0,0,0,.15);
}
.tmenu .mi { color: #2c3644; }
.tmenu .mi:hover { background: #eef2f7; color: #10151d; }
.tmenu .mhead { color: #7c8898; }
.tmenu .msep { background: #e5e9ee; }
.tmenu .mtick { color: #1e64d8; }
/* reopen tab matches the light bar */
#tbShow {
background: linear-gradient(180deg, #ffffff, #eef1f5);
border: 1px solid #ccd3dc; border-top: 0; color: #3d4756;
box-shadow: 0 8px 22px rgba(0,0,0,.35);
}
#tbShow:hover { background: #fff; color: #10151d; }
/* ===== reference-exact: airy sparse bar, menus-first (v41) ===== */
/* identity + dropdown boxes leave the bar - like the reference image */
#toolbar .tb-title, #tbState, #selMonitor, #selQuality { display: none !important; }
/* icon-only everywhere */
#btnViewOnly span, #btnKbdLock span, #btnDisconnect span { display: none !important; }
/* generous breathing room between groups */
#toolbar { gap: 16px; padding: 6px 12px; }
#toolbar .tb-group { gap: 10px; }
#toolbar .sep { margin: 0 6px; }
#toolbar .menu-btn { padding: 0 13px; font-size: 13px; }
/* compact square-ish red end button, icon only */
#toolbar .tb.danger { padding: 0 12px; min-width: 40px; }
#toolbar .tb.danger svg { width: 15px; height: 15px; }
/* menus can hold the new Monitor / Quality sections comfortably */
.tmenu { min-width: 250px; }
/* monitor cycle label + disabled menu items (v44) */
#monCycleLbl { font-size: 11px; font-weight: 700; margin-left: 5px; letter-spacing: .3px; }
.tmenu .mi[disabled] { opacity: .45; cursor: default; }
.tmenu .mi[disabled]:hover { background: transparent; color: #2c3644; }
/* iOS: no long-press callout / text-selection bubbles over the session */
#stage, #canvas, #toolbar, .tmenu {
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
}
/* ===== mobile session layout (phones) ===== */
.tmenu { position: fixed; } /* JS sets top/left, clamped to the viewport */
@media (max-width: 700px) {
#toolbar {
min-height: 44px; margin: 6px 6px 0; padding: 5px 6px; gap: 5px;
border-radius: 10px;
overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
#toolbar::-webkit-scrollbar { display: none; }
#toolbar .tb { height: 36px; min-width: 36px; }
#toolbar .menu-btn { padding: 0 10px; font-size: 12.5px; }
/* secondary controls live inside the menus on phones - keep the bar clean */
#btnViewOnly, #btnKbdLock, #btnClipboard, #btnPrivacy, #btnRec,
#btnSys, #btnChat, #btnFiles, #toolbar .sep { display: none !important; }
.tmenu { max-height: 68vh; overflow-y: auto; min-width: 230px; max-width: 92vw; }
#tbShow { height: 26px; padding: 0 16px; font-size: 12px; }
}
/* phones: consolidate to the essentials - everything else stays in menus */
@media (max-width: 700px) {
.menu-btn[data-menu="mComm"] { display: none !important; } /* chat lives in Extras */
#btnFullscreen { display: none !important; } /* no Fullscreen API on iPhone */
#btnOsk span { display: none !important; }
#monCycleLbl { font-size: 10px; margin-left: 3px; }
#toolbar { gap: 3px; }
#toolbar .menu-btn { padding: 0 8px; font-size: 12px; }
#toolbar .tb.danger { min-width: 38px; padding: 0 10px; }
}
/* inside the desktop app's viewer window: no website chrome */
body.embed .nav-links, body.embed a.btn-ghost[href="/portal"] { display: none !important; }
/* =========================================================================
ELEVATION LAYER v2 — glass, gradient accents, refined depth. Matches the
marketing site's elevation pass. Component-scoped overrides only; the base
design above is untouched so behaviour/layout stay identical.
====================================================================== */
:root{
--accent-grad: linear-gradient(135deg,#4d8bff,#6aa1ff 44%,#34d399);
--glass: rgba(18,24,36,.72);
--hair: rgba(255,255,255,.07);
--hair-strong: rgba(255,255,255,.13);
--shadow-lg: 0 24px 70px -18px rgba(0,0,0,.72);
--ring: 0 0 0 3px rgba(77,139,255,.26);
}
:root[data-theme="light"]{
--glass: rgba(255,255,255,.76);
--hair: rgba(16,22,34,.08);
--hair-strong: rgba(16,22,34,.14);
--shadow-lg: 0 24px 70px -22px rgba(23,32,47,.22);
--ring: 0 0 0 3px rgba(61,126,255,.18);
}
/* primary buttons: gradient fill + sheen sweep (sheen sits behind the text) */
button.primary, .btn-blue{
position:relative; overflow:hidden; z-index:0;
background:var(--accent-grad) !important; background-size:160% 160% !important;
box-shadow:0 8px 22px -6px rgba(61,126,255,.5), inset 0 1px 0 rgba(255,255,255,.22) !important;
}
button.primary::before, .btn-blue::before{
content:""; position:absolute; inset:0; z-index:-1; border-radius:inherit;
background:linear-gradient(100deg,transparent 22%,rgba(255,255,255,.4) 50%,transparent 78%);
transform:translateX(-120%); transition:transform .6s ease;
}
button.primary:hover::before, .btn-blue:hover::before{ transform:translateX(120%); }
button.primary:hover, .btn-blue:hover{ filter:brightness(1.05); transform:translateY(-1px); }
/* toolbar: frosted glass + a gradient hairline underline */
#toolbar{
position:relative;
background:var(--glass) !important;
backdrop-filter:blur(16px) saturate(1.3); -webkit-backdrop-filter:blur(16px) saturate(1.3);
border-bottom:1px solid var(--hair) !important;
box-shadow:0 1px 0 var(--hair) inset, 0 10px 26px -14px rgba(0,0,0,.55) !important;
}
#toolbar::after{
content:""; position:absolute; left:0; right:0; bottom:-1px; height:1px; pointer-events:none;
background:linear-gradient(90deg,transparent,rgba(77,139,255,.55),rgba(52,211,153,.4),transparent);
opacity:.75;
}
/* connect card + modals: gradient hairline border + deeper shadow */
.card, .modal-card{ position:relative; border-color:var(--hair-strong) !important; box-shadow:var(--shadow-lg) !important; }
.card::before, .modal-card::before{
content:""; position:absolute; inset:0; border-radius:inherit; padding:1px; pointer-events:none; opacity:.85;
background:linear-gradient(135deg,rgba(77,139,255,.5),transparent 42%,transparent 58%,rgba(52,211,153,.32));
-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
-webkit-mask-composite:xor; mask-composite:exclude;
}
.modal-wrap{ background:rgba(5,7,12,.62) !important; backdrop-filter:blur(9px) saturate(1.2) !important; -webkit-backdrop-filter:blur(9px) saturate(1.2) !important; }
/* inputs: softer gradient-tinted focus ring */
input:focus{ box-shadow:var(--ring) !important; }
/* active states get the gradient tint */
.atab.on{ background:linear-gradient(135deg,rgba(77,139,255,.22),rgba(52,211,153,.12)) !important; border-color:rgba(77,139,255,.5) !important; color:#bcd4ff !important; }
#toolbar .tb.active{ background:linear-gradient(135deg,rgba(77,139,255,.24),rgba(52,211,153,.12)) !important; border-color:rgba(77,139,255,.5) !important; }
/* operator-console (portal) cards: refined hairline + depth */
.p-card{ border-color:var(--hair-strong) !important; box-shadow:0 1px 2px rgba(0,0,0,.22), 0 12px 30px -16px rgba(0,0,0,.55) !important; }
:root[data-theme="light"] .p-card{ box-shadow:0 1px 2px rgba(23,32,47,.06), 0 12px 30px -18px rgba(23,32,47,.18) !important; }