domma-cms 0.106.0 → 0.107.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/js/lib/effect-defs.js +1 -1
- package/admin/js/lib/effects-builder.js +2 -2
- package/admin/js/lib/shortcode-context-menu.js +2 -2
- package/admin/js/templates/docs/usage-tools.html +7 -0
- package/package.json +2 -2
- package/plugins/_lib/call/invite.js +172 -0
- package/plugins/_lib/call/rooms.js +19 -5
- package/plugins/_lib/call/routes.js +78 -3
- package/plugins/_lib/mail/render.js +14 -1
- package/plugins/_lib/public/call/call.css +1 -1
- package/plugins/_lib/public/call/call.js +287 -23
- package/plugins/booking/CLAUDE.md +18 -1
- package/plugins/booking/docs/guide.md +1 -0
- package/plugins/booking/lib/call.js +18 -2
- package/plugins/booking/lib/store.js +2 -0
- package/plugins/booking/plugin.js +59 -6
- package/plugins/booking/plugin.json +1 -1
- package/plugins/booking/plugin.public.js +4 -4
- package/plugins/booking/tests/api.test.js +114 -0
- package/plugins/free-tier.lock.json +10 -10
- package/public/js/celebrations/index.js +1 -1
- package/public/js/celebrations/themes/butterfly-drawing.js +1 -0
- package/public/js/celebrations/themes/halloween-drawing.js +1 -0
- package/public/js/celebrations/themes/halloween.js +1 -1
- package/public/js/celebrations/themes/valentines.js +1 -1
- package/public/js/celebrations/trait-data.mjs +1 -0
- package/public/js/effects.js +1 -1
- package/server/routes/api/calls.js +25 -3
- package/server/routes/call-public.js +4 -3
- package/server/services/callInvites.js +238 -0
- package/server/services/hooks.js +55 -0
- package/server/services/instantCalls.js +30 -3
- package/server/services/plugins.js +6 -1
- package/server/templates/page.html +1 -1
|
@@ -11,6 +11,16 @@
|
|
|
11
11
|
* POST {prefix}/:room/answer {who, yes} (host: let in / turn away)
|
|
12
12
|
* POST {prefix}/:room/recording {on} (host)
|
|
13
13
|
* POST {prefix}/:room/leave
|
|
14
|
+
* GET {prefix}/:room/people?q= (invite only) -> {people: [{kind, id, name, email?, canNotify, canMessage}]}
|
|
15
|
+
* POST {prefix}/:room/invite (invite only) {people: [{kind, id} | {name, email}], via: {email, notify, message}}
|
|
16
|
+
* -> {link, results: [{name, emailed, notified, messaged, error?}]}
|
|
17
|
+
*
|
|
18
|
+
* "Add people" (optional): a Tool passing `invite: {search, send}` lets the people
|
|
19
|
+
* its resolve() marks `mayInvite` (default: the host) search and invite others
|
|
20
|
+
* while the call runs - the join answers `canInvite`, and the call screen shows
|
|
21
|
+
* the button. Checked by the caller's X-Call-Id/X-Call-Secret: someone let in,
|
|
22
|
+
* allowed to invite. Limits: MAX_TARGETS a request, INVITES_PER_MINUTE a caller
|
|
23
|
+
* (invite.js). Without `invite` the two routes do not exist.
|
|
14
24
|
*
|
|
15
25
|
* After joining, every request carries `X-Call-Id` and `X-Call-Secret`
|
|
16
26
|
* (headers, so the secret never lands in an access log).
|
|
@@ -24,6 +34,7 @@
|
|
|
24
34
|
|
|
25
35
|
import {CallError, createRooms} from './rooms.js';
|
|
26
36
|
import {iceServers, readCallConfig} from './ice.js';
|
|
37
|
+
import {cleanInviteRequest, cleanPeople, cleanResults, createLimiter, inviteOptionsOf} from './invite.js';
|
|
27
38
|
|
|
28
39
|
const STATUS = {gone: 410, full: 409, waiting: 409, away: 403, 'not-host': 403, 'no-recording': 403};
|
|
29
40
|
const BUSY = {config: {rateLimit: {max: 1200, timeWindow: '1 minute'}}};
|
|
@@ -43,9 +54,15 @@ const BUSY = {config: {rateLimit: {max: 1200, timeWindow: '1 minute'}}};
|
|
|
43
54
|
* `save(room, item, {identity})` is handed every new item, user and system. `room` is the Tool's own room id (no
|
|
44
55
|
* namespace); `identity` is what the Tool's resolve() gave the person concerned ('' for none) - server side only.
|
|
45
56
|
* Failures (and a load slower than 5 s) are logged and otherwise ignored: a chat never breaks a call.
|
|
57
|
+
* @param {{search: (room: string, q: string, ctx: {identity: string, name: string, request: object}) => Promise<object[]>,
|
|
58
|
+
* send: (room: string, people: object[], ctx: {identity: string, name: string, via: object, request: object}) =>
|
|
59
|
+
* Promise<{link: string, results: object[]}>}} [opts.invite] - "Add people" (see above); resolve() may add
|
|
60
|
+
* `mayInvite: boolean` (default: `host`) and `inviteExternal: false` (team members only: no contacts, typed
|
|
61
|
+
* emails or Copy link - the join answers `inviteOptions: {external}`). `people` is cleanInviteRequest()'s list; an empty one asks for a link only.
|
|
46
62
|
* @returns {ReturnType<typeof createRooms>} the rooms, so the Tool can close() one or count() it
|
|
47
63
|
*/
|
|
48
|
-
export function mountCallRoutes(fastify, {prefix = '/call', ns, resolve, rooms = createRooms(), config = () => readCallConfig(), chat = null
|
|
64
|
+
export function mountCallRoutes(fastify, {prefix = '/call', ns, resolve, rooms = createRooms(), config = () => readCallConfig(), chat = null, invite = null,
|
|
65
|
+
limiter = createLimiter()}) {
|
|
49
66
|
if (!ns) throw new Error('mountCallRoutes needs a namespace');
|
|
50
67
|
const keyOf = (room) => `${ns}:${String(room || '').slice(0, 120)}`;
|
|
51
68
|
const roomOf = (key) => key.slice(ns.length + 1);
|
|
@@ -83,6 +100,7 @@ export function mountCallRoutes(fastify, {prefix = '/call', ns, resolve, rooms =
|
|
|
83
100
|
throw err;
|
|
84
101
|
};
|
|
85
102
|
|
|
103
|
+
const inviting = typeof invite?.search === 'function' && typeof invite?.send === 'function';
|
|
86
104
|
const sweeper = setInterval(() => rooms.sweep(), 5000);
|
|
87
105
|
sweeper.unref?.();
|
|
88
106
|
fastify.addHook('onClose', async () => { clearInterval(sweeper); stopListening?.(); });
|
|
@@ -98,9 +116,14 @@ export function mountCallRoutes(fastify, {prefix = '/call', ns, resolve, rooms =
|
|
|
98
116
|
// A room being created starts from its stored chat (a room reopened later, or after a restart).
|
|
99
117
|
const history = rooms.has(key) ? undefined : await load(roomOf(key));
|
|
100
118
|
try {
|
|
119
|
+
const canInvite = inviting && (typeof r.mayInvite === 'boolean' ? r.mayInvite : r.host === true);
|
|
120
|
+
const inviteOptions = canInvite ? inviteOptionsOf(r) : null;
|
|
101
121
|
const joined = rooms.join(key, {name: r.name || body.name, host: r.host, title: r.title, max: r.max,
|
|
102
|
-
recordingAllowed: r.recordingAllowed === true, autoAdmit: r.autoAdmit === true, identity: r.identity || '', history
|
|
103
|
-
|
|
122
|
+
recordingAllowed: r.recordingAllowed === true, autoAdmit: r.autoAdmit === true, identity: r.identity || '', history, canInvite,
|
|
123
|
+
inviteOptions, seeHistory: r.history !== false});
|
|
124
|
+
// What "Add people" offers this person: {search, typed, copyLink, external} (invite.js inviteOptionsOf).
|
|
125
|
+
return reply.send({...joined, iceServers: iceServers(config(), request.hostname), closesAt: r.closesAt || null,
|
|
126
|
+
...(inviteOptions ? {inviteOptions} : {})});
|
|
104
127
|
} catch (err) { return fail(reply, err); }
|
|
105
128
|
});
|
|
106
129
|
|
|
@@ -133,6 +156,58 @@ export function mountCallRoutes(fastify, {prefix = '/call', ns, resolve, rooms =
|
|
|
133
156
|
action('recording', (k, id, s, b) => rooms.recording(k, id, s, b.on === true));
|
|
134
157
|
action('leave', (k, id, s) => rooms.leave(k, id, s));
|
|
135
158
|
|
|
159
|
+
// ---- Add people (a Tool with `invite`) ---------------------------------------------------
|
|
160
|
+
if (inviting) {
|
|
161
|
+
/** The caller, in the call and allowed to invite - else the reply is already sent. */
|
|
162
|
+
const inviter = (request, reply) => {
|
|
163
|
+
const [id, secret] = who(request);
|
|
164
|
+
let m;
|
|
165
|
+
try { m = rooms.member(keyOf(request.params.room), id, secret); } catch (err) { fail(reply, err); return null; }
|
|
166
|
+
if (m.state !== 'in' || !m.canInvite) { reply.code(403).send({error: 'Only the host can add people to this call.', code: 'not-host'}); return null; }
|
|
167
|
+
return m;
|
|
168
|
+
};
|
|
169
|
+
const warn = (err, what) => log.warn?.({err: err?.message || String(err)}, `[call] ${what} failed`);
|
|
170
|
+
|
|
171
|
+
fastify.get(`${prefix}/:room/people`, {config: {rateLimit: {max: 120, timeWindow: '1 minute'}}}, async (request, reply) => {
|
|
172
|
+
const m = inviter(request, reply);
|
|
173
|
+
if (!m) return reply;
|
|
174
|
+
const q = String(request.query?.q || '').trim().slice(0, 100);
|
|
175
|
+
let people = [];
|
|
176
|
+
if (m.inviteOptions?.search === false) return reply.header('Cache-Control', 'no-store').send({people: []});
|
|
177
|
+
try { people = await invite.search(String(request.params.room), q, {identity: m.identity, name: m.name, request}); } catch (err) { warn(err, 'people search'); }
|
|
178
|
+
reply.header('Cache-Control', 'no-store');
|
|
179
|
+
return reply.send({people: cleanPeople(people)});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
fastify.post(`${prefix}/:room/invite`, {config: {rateLimit: {max: 30, timeWindow: '1 minute'}}}, async (request, reply) => {
|
|
183
|
+
const m = inviter(request, reply);
|
|
184
|
+
if (!m) return reply;
|
|
185
|
+
const req = cleanInviteRequest(request.body || {});
|
|
186
|
+
if (req.error) return reply.code(400).send({error: req.error});
|
|
187
|
+
// What this caller was offered is what they may do (the Tool checks again).
|
|
188
|
+
const o = m.inviteOptions || {};
|
|
189
|
+
if (!req.people.length && o.copyLink === false) return reply.code(409).send({error: 'There is no link to copy for this call.'});
|
|
190
|
+
const offered = (p) => (p.kind === 'email' ? o.typed !== false : p.kind === 'contact' ? o.typed !== false && o.search !== false : o.search !== false);
|
|
191
|
+
if (!req.people.every(offered)) {
|
|
192
|
+
return reply.code(400).send({error: o.search === false ? 'Copy the link and pass it on yourself.' : 'Only team members can be added to this call.'});
|
|
193
|
+
}
|
|
194
|
+
if (!limiter.take(`${ns}:${m.identity || m.id}`, Math.max(1, req.people.length))) {
|
|
195
|
+
return reply.code(429).send({error: 'That is a lot of people in a minute - wait a moment and try again.'});
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const out = await invite.send(String(request.params.room), req.people, {identity: m.identity, name: m.name, via: req.via, request});
|
|
199
|
+
// A link to copy, or (a Tool whose links are per person - Messages) the results alone.
|
|
200
|
+
if (!out || out.error || (!out.link && !(req.people.length && Array.isArray(out.results)))) {
|
|
201
|
+
return reply.code(409).send({error: out?.error || 'People cannot be added to this call now.'});
|
|
202
|
+
}
|
|
203
|
+
return reply.send({link: String(out.link || ''), results: cleanResults(out.results)});
|
|
204
|
+
} catch (err) {
|
|
205
|
+
warn(err, 'invite');
|
|
206
|
+
return reply.code(500).send({error: 'The invitations could not be sent.'});
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
136
211
|
return {...rooms, closeRoom: (room) => rooms.close(keyOf(room)), countRoom: (room) => rooms.count(keyOf(room)),
|
|
137
212
|
historyOfRoom: (room) => rooms.history(keyOf(room)),
|
|
138
213
|
kickFromRoom: (room, identity) => rooms.kick(keyOf(room), identity)};
|
|
@@ -99,7 +99,20 @@ function sanitiseBody(html, options) {
|
|
|
99
99
|
'border': [/^.*$/],
|
|
100
100
|
'border-collapse': [/^.*$/],
|
|
101
101
|
'width': [/^.*$/],
|
|
102
|
-
'max-width': [/^.*$/]
|
|
102
|
+
'max-width': [/^.*$/],
|
|
103
|
+
// Marketing mail hides its inbox preview text ("preheader")
|
|
104
|
+
// with these. Strip them and keep its width:0, and the hidden
|
|
105
|
+
// text renders one letter per line under a tall run of
|
|
106
|
+
// invisible padding characters. None of them can position,
|
|
107
|
+
// load or overlay anything.
|
|
108
|
+
'display': [/^(none|block|inline|inline-block|table|table-row|table-cell|list-item)$/i],
|
|
109
|
+
'visibility': [/^(hidden|visible)$/i],
|
|
110
|
+
'height': [/^.*$/],
|
|
111
|
+
'max-height': [/^.*$/],
|
|
112
|
+
'line-height': [/^.*$/],
|
|
113
|
+
'overflow': [/^(hidden|visible)$/i],
|
|
114
|
+
'opacity': [/^[0-9.]+$/],
|
|
115
|
+
'vertical-align': [/^.*$/]
|
|
103
116
|
}
|
|
104
117
|
},
|
|
105
118
|
allowedSchemes: ['http', 'https', 'mailto', 'tel'],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.dmc{--dmc-gap: .75rem;--dmc-stage-bg: #0f1114;--dmc-glass: rgba(32, 34, 38, .72);--dmc-glass-strong: rgba(28, 30, 34, .94);--dmc-ctl: rgba(255, 255, 255, .12);--dmc-ctl-hover: rgba(255, 255, 255, .2);--dmc-on-dark: #f1f3f4;--dmc-muted-dark: #9aa0a6;--dmc-red: #e5484d;--dmc-red-hover: #d13b40;--dmc-blue: #8ab4f8;--dmc-chat-bg: #0b141a;--dmc-chat-head: #202c33;--dmc-bubble-in: #202c33;--dmc-bubble-out: #005c4b;--dmc-chat-text: #e9edef;--dmc-chat-meta: rgba(233, 237, 239, .6);--dmc-chat-sys: #182229;--dmc-chat-sys-text: #8696a0;--dmc-green: #00a884;--dmc-offset: 5rem;display:flex;flex-direction:column;gap:1rem;color:var(--dm-text, inherit)}.dmc [hidden]{display:none!important}.dmc-head{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.dmc-title{font-size:1.5rem;margin:0;flex:1 1 auto;letter-spacing:-.01em}.dmc-btn{font:inherit;cursor:pointer;padding:.55rem 1rem;border-radius:.6rem;border:1px solid var(--dm-border, #ccc);background:var(--dm-surface, #fff);color:inherit;display:inline-flex;align-items:center;justify-content:center;gap:.45rem;position:relative;transition:background-color .15s,border-color .15s,color .15s,transform .1s}.dmc-btn:hover{border-color:var(--dm-primary, #555)}.dmc-btn:active{transform:scale(.97)}.dmc-btn:disabled{opacity:.55;cursor:default;transform:none}.dmc-btn:focus-visible,.dmc-compose:focus-visible{outline:2px solid var(--dmc-blue);outline-offset:2px}.dmc-i{display:inline-flex}.dmc-btn svg,.dmc-count svg,.dmc-note svg,.dmc-chip svg{width:18px;height:18px;flex:none}.dmc-btn.is-off{background:var(--dm-danger, #c62828);border-color:transparent;color:#fff}.dmc-btn--go{background:var(--dm-primary, #1f6feb);border-color:transparent;color:#fff;font-weight:600}.dmc-btn--go:hover{filter:brightness(1.08);border-color:transparent}.dmc-btn--small{padding:.35rem .7rem;font-size:.88rem}.dmc-panel{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:2rem;align-items:center}.dmc-panel--msg{display:flex;flex-direction:column;align-items:center;text-align:center;padding:4rem 1rem;gap:.25rem}.dmc-panel--msg h2{margin:.5rem 0 .25rem}.dmc-panel--msg p{color:var(--dm-text-muted, #666);margin:0 0 1rem}.dmc-pulse{width:72px;height:72px;border-radius:50%;display:grid;place-items:center;color:#fff;background:var(--dm-primary, #1f6feb);box-shadow:0 0 color-mix(in srgb,var(--dm-primary, #1f6feb) 45%,transparent);animation:dmc-pulse 2s infinite}.dmc-pulse svg{width:30px;height:30px}@keyframes dmc-pulse{70%{box-shadow:0 0 0 18px transparent}to{box-shadow:0 0 0 0 transparent}}.dmc-preview{position:relative;aspect-ratio:16 / 9;background:#16181c;border-radius:1rem;overflow:hidden;box-shadow:0 10px 30px #0000002e}.dmc-preview video,.dmc-tile video{width:100%;height:100%;object-fit:cover;display:block}.dmc-self,.dmc-self-preview{transform:scaleX(-1)}.dmc-nocam{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.6rem;color:#cfd3d8;margin:0}.dmc-avatar-dot{width:84px;height:84px;border-radius:50%;display:grid;place-items:center;background:#3c4043;color:#fff;font-size:2rem;font-weight:600}.dmc-preview-tools{position:absolute;left:0;right:0;bottom:1rem;display:flex;justify-content:center;gap:.75rem}.dmc-round{width:3rem;height:3rem;padding:0;border-radius:50%;border:1px solid rgba(255,255,255,.5);background:#00000059;color:#fff;backdrop-filter:blur(6px)}.dmc-round:hover{background:#00000080;border-color:#fff}.dmc-round.is-off{background:var(--dmc-red);border-color:transparent}.dmc-check h2{margin:0 0 .25rem;font-size:1.6rem}.dmc-label{display:grid;gap:.35rem;margin:1rem 0 .5rem;font-weight:600}.dmc-input{font:inherit;padding:.6rem .8rem;border:1px solid var(--dm-border, #ccc);border-radius:.6rem;background:var(--dm-surface, #fff);color:inherit;min-width:0}.dmc-row{display:flex;gap:.5rem;flex-wrap:wrap;margin:.75rem 0}.dmc-chipbtn{border-radius:999px;padding:.4rem .9rem;font-size:.9rem}.dmc-note{color:var(--dm-text-muted, #666)}.dmc-note--rec{display:flex;gap:.5rem;align-items:flex-start;font-size:.92rem}.dmc-note--rec svg{color:var(--dm-danger, #c62828);fill:currentColor;width:12px;height:12px;margin-top:.3rem}.dmc-error{color:var(--dm-danger, #c62828);font-weight:600}.dmc-check .dmc-btn--go{width:100%;padding:.8rem 1rem;border-radius:999px;font-size:1.05rem;margin-top:.5rem}.dmc-call{display:flex;gap:0;color:var(--dmc-on-dark);background:var(--dmc-stage-bg);border-radius:1rem;overflow:hidden;height:calc(100vh - var(--dmc-offset) - 1rem);height:calc(100dvh - var(--dmc-offset) - 1rem);min-height:26rem;box-shadow:0 12px 40px #00000040;color-scheme:dark}.dmc-stage{position:relative;flex:1 1 auto;min-width:0;container:dmc-stage / size;overflow:hidden}.dmc-top{position:absolute;top:0;left:0;right:0;z-index:3;display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.85rem 1.1rem 1.6rem;background:linear-gradient(rgba(0,0,0,.6),transparent);pointer-events:none}.dmc-top>*{pointer-events:auto}.dmc-top-l{display:flex;align-items:baseline;gap:.75rem;min-width:0}.dmc-top-title{margin:0;font-size:1rem;font-weight:600;color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-timer{font-size:.88rem;color:var(--dmc-muted-dark);font-variant-numeric:tabular-nums}.dmc-top-r{display:flex;align-items:center;gap:.5rem;flex:none}.dmc-rec{display:inline-flex;align-items:center;gap:.4rem;color:#fff;background:var(--dmc-red);border-radius:999px;padding:.22rem .7rem;font-size:.8rem;font-weight:600}.dmc-rec-dot{width:8px;height:8px;border-radius:50%;background:#fff;animation:dmc-blink 1.4s infinite}@keyframes dmc-blink{50%{opacity:.25}}.dmc-count{display:inline-flex;align-items:center;gap:.35rem;font-size:.85rem;color:#fff;background:#ffffff24;border-radius:999px;padding:.22rem .65rem}.dmc-count svg{width:15px;height:15px}.dmc-main{position:absolute;inset:0}.dmc-remote{position:absolute;inset:3.6rem 1rem 5.6rem;display:flex;flex-wrap:wrap;align-content:center;justify-content:center;gap:var(--dmc-gap);--cols: 1;--rows: 1}.dmc-cell{container-type:size;display:grid;place-items:center;min-width:0;width:calc((100% - (var(--cols) - 1) * var(--dmc-gap)) / var(--cols));height:calc((100% - (var(--rows) - 1) * var(--dmc-gap)) / var(--rows))}.dmc-main[data-tiles="2"] .dmc-remote{--cols: 2}.dmc-main[data-tiles="3"] .dmc-remote,.dmc-main[data-tiles="4"] .dmc-remote{--cols: 2;--rows: 2}.dmc-main[data-tiles="5"] .dmc-remote,.dmc-main[data-tiles="6"] .dmc-remote{--cols: 3;--rows: 2}.dmc-tile{position:relative;margin:0;background:#202124;border-radius:.9rem;overflow:hidden}.dmc-cell .dmc-tile{width:min(100cqw,100cqh * 16 / 9);aspect-ratio:16 / 9;box-shadow:0 4px 18px #00000059}.dmc-tile video{position:relative;z-index:1}.dmc-avatar{position:absolute;inset:0;display:grid;place-items:center;z-index:0}.dmc-avatar span{width:clamp(3rem,22%,6.5rem);aspect-ratio:1;border-radius:50%;display:grid;place-items:center;background:#3c4043;color:#fff;font-size:clamp(1.2rem,4cqw,2.6rem);font-weight:600}.dmc-tile--me .dmc-avatar{z-index:2;background:#202124}.dmc-chip{position:absolute;left:.6rem;bottom:.6rem;z-index:3;display:inline-flex;align-items:center;gap:.3rem;max-width:calc(100% - 1.2rem);padding:.2rem .55rem;border-radius:.45rem;background:#0000008c;backdrop-filter:blur(6px);color:#fff;font-size:.8rem;line-height:1.3}.dmc-chip>span:last-child{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-chip-mute{display:inline-flex;color:#fff;background:var(--dmc-red);border-radius:50%;padding:2px}.dmc-chip-mute svg{width:12px;height:12px}.dmc-tile--me{position:absolute;z-index:2;right:1rem;bottom:5.6rem;width:clamp(9.5rem,20%,16rem);aspect-ratio:16 / 9;box-shadow:0 6px 24px #00000080;outline:1px solid rgba(255,255,255,.14);transition:all .25s ease}.dmc-tile--me .dmc-chip{left:.4rem;bottom:.4rem;font-size:.72rem;padding:.12rem .45rem}.dmc-main:not([data-tiles="0"]):not([data-tiles="1"]) .dmc-tile--me{width:clamp(8.5rem,15%,13rem)}.dmc-main[data-tiles="0"] .dmc-tile--me{inset:0;width:auto;aspect-ratio:auto;border-radius:0;outline:0;box-shadow:none}.dmc-main[data-tiles="0"] .dmc-tile--me .dmc-chip{left:1rem;bottom:5.6rem;font-size:.8rem;padding:.2rem .55rem}.dmc-main[data-tiles="0"] .dmc-tile--me:after{content:"";position:absolute;inset:0;z-index:2;background:radial-gradient(ellipse at center,#00000040,#0009);pointer-events:none}.dmc-alone{position:absolute;inset:0;z-index:2;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:1rem;pointer-events:none}.dmc-alone-title{margin:0;font-size:clamp(1.1rem,2.4vw,1.5rem);font-weight:600;color:#fff;text-shadow:0 1px 8px rgba(0,0,0,.6)}.dmc-alone-sub{margin:.35rem 0 0;color:#dadce0;font-size:.92rem;text-shadow:0 1px 6px rgba(0,0,0,.6)}.dmc-waiting{position:absolute;z-index:4;top:3.4rem;right:1rem;width:min(21rem,calc(100% - 2rem));padding:.85rem;border-radius:.9rem;background:var(--dmc-glass-strong);backdrop-filter:blur(14px);box-shadow:0 10px 30px #00000073;border:1px solid rgba(255,255,255,.08);animation:dmc-drop .25s ease}@keyframes dmc-drop{0%{opacity:0;transform:translateY(-6px)}}.dmc-waiting h3{display:flex;align-items:center;gap:.5rem;margin:0 0 .6rem;font-size:.9rem;font-weight:600;color:#fff}.dmc-waiting-dot{width:8px;height:8px;border-radius:50%;background:#fbbc04;box-shadow:0 0 0 3px #fbbc0440}.dmc-waiting ul{list-style:none;margin:0;padding:0;display:grid;gap:.55rem;max-height:14rem;overflow-y:auto}.dmc-waiting li{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.35rem .6rem}.dmc-winitial{width:2rem;height:2rem;border-radius:50%;display:grid;place-items:center;background:#5f6368;color:#fff;font-weight:600;font-size:.9rem}.dmc-wname{font-weight:600;color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-wbtns{grid-column:2;display:flex;gap:.4rem}.dmc-waiting .dmc-btn{border-radius:999px}.dmc-waiting .dmc-btn svg{width:15px;height:15px}.dmc-waiting .dmc-btn--go{background:var(--dmc-blue);color:#202124}.dmc-btn--ghost{background:transparent;color:#e8eaed;border-color:#ffffff40}.dmc-btn--ghost:hover{background:#ffffff14;border-color:#fff6}.dmc-bar{position:absolute;z-index:4;left:50%;bottom:1rem;transform:translate(-50%);display:flex;align-items:center;gap:.6rem;padding:.55rem .7rem;border-radius:999px;background:var(--dmc-glass);backdrop-filter:blur(14px) saturate(1.3);box-shadow:0 8px 28px #0006;border:1px solid rgba(255,255,255,.08)}.dmc-tool{width:3rem;height:3rem;padding:0;border-radius:50%;border:0;background:var(--dmc-ctl);color:#fff;flex:none}.dmc-tool:hover{background:var(--dmc-ctl-hover)}.dmc-tool svg{width:20px;height:20px}.dmc-tool.is-off{background:var(--dmc-red)}.dmc-tool.is-off:hover{background:var(--dmc-red-hover)}.dmc-tool.is-on{background:var(--dmc-blue);color:#202124}.dmc-btn--rec svg{color:var(--dmc-red);fill:currentColor;width:16px;height:16px}.dmc-btn--rec.is-on{background:var(--dmc-red);color:#fff;animation:dmc-recglow 1.6s infinite}.dmc-btn--rec.is-on svg{color:#fff}@keyframes dmc-recglow{0%,to{box-shadow:0 0 #e5484d99}50%{box-shadow:0 0 0 6px #e5484d00}}.dmc-btn--leave{background:var(--dmc-red);width:4rem;border-radius:999px}.dmc-btn--leave:hover{background:var(--dmc-red-hover)}.dmc-lbl{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.dmc-tool:after{content:attr(aria-label);position:absolute;bottom:calc(100% + .7rem);left:50%;transform:translate(-50%,4px);padding:.3rem .55rem;border-radius:.4rem;background:#3c4043;color:#fff;font-size:.75rem;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .15s,transform .15s}.dmc-tool:hover:after,.dmc-tool:focus-visible:after{opacity:1;transform:translate(-50%)}.dmc-badge{position:absolute;top:-.2rem;right:-.2rem;min-width:1.2rem;height:1.2rem;padding:0 .3rem;border-radius:999px;background:var(--dmc-green);color:#fff;font-size:.7rem;font-weight:700;line-height:1.2rem;text-align:center;box-shadow:0 0 0 2px #2a2c30}@container dmc-stage (max-aspect-ratio: 1 / 1){.dmc-main[data-tiles="2"] .dmc-remote{--cols: 1;--rows: 2}.dmc-main[data-tiles="5"] .dmc-remote,.dmc-main[data-tiles="6"] .dmc-remote{--cols: 2;--rows: 3}.dmc-cell .dmc-tile{width:100%;height:100%;aspect-ratio:auto}.dmc-tile--me{width:clamp(6.5rem,28%,9rem);aspect-ratio:3 / 4}.dmc-main:not([data-tiles="0"]):not([data-tiles="1"]) .dmc-tile--me{width:clamp(5.5rem,22%,7rem)}}.dmc-chat{flex:none;width:0;display:flex;flex-direction:column;background:var(--dmc-chat-bg);color:var(--dmc-chat-text);overflow:hidden;transition:width .25s ease;border-left:1px solid rgba(255,255,255,.06)}.dmc-call.is-chat .dmc-chat{width:21.25rem}.dmc-chat>*{min-width:21.25rem}.dmc-chat-head{display:flex;align-items:center;gap:.5rem;padding:.7rem .75rem .7rem 1rem;background:var(--dmc-chat-head)}.dmc-chat-titles{flex:1;min-width:0;display:flex;flex-direction:column}.dmc-chat-titles h3{margin:0;font-size:1rem;font-weight:600;color:var(--dmc-chat-text)}.dmc-chat-titles span{font-size:.76rem;color:var(--dmc-chat-sys-text)}.dmc-chat-back,.dmc-chat-close{width:2.25rem;height:2.25rem;border:0;border-radius:50%;background:transparent;color:#aebac1;cursor:pointer;display:grid;place-items:center}.dmc-chat-back:hover,.dmc-chat-close:hover{background:#ffffff14;color:#fff}.dmc-chat-back svg,.dmc-chat-close svg{width:20px;height:20px}.dmc-chat-back{display:none}.dmc-chat-body{position:relative;flex:1;min-height:0;display:flex}.dmc-messages{list-style:none;margin:0;padding:.6rem .9rem 1rem;flex:1;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:#374045 transparent}.dmc-chat-empty{position:absolute;inset:auto 1.5rem 45%;margin:0;text-align:center;color:var(--dmc-chat-sys-text);font-size:.85rem}.dmc-msg{display:flex;flex-direction:column;margin-top:2px}.dmc-msg.is-first{margin-top:.6rem}.dmc-msg.is-mine{align-items:flex-end}.dmc-msg.is-other{align-items:flex-start}.dmc-msg.is-sys{align-items:center;margin-top:.6rem}.dmc-msg.is-sys+.dmc-msg.is-sys:not(.has-day){margin-top:.3rem}.dmc-day{align-self:center;margin:.5rem 0 .35rem}.dmc-day span,.dmc-sys span{display:inline-block;padding:.28rem .65rem;border-radius:.5rem;background:var(--dmc-chat-sys);color:var(--dmc-chat-sys-text);font-size:.74rem;box-shadow:0 1px .5px #00000021}.dmc-day span{text-transform:uppercase;letter-spacing:.03em;font-size:.7rem}.dmc-msg.has-day.is-first{margin-top:.2rem}.dmc-bubble{position:relative;max-width:85%;padding:.38rem .55rem .3rem .6rem;border-radius:.55rem;background:var(--dmc-bubble-in);color:var(--dmc-chat-text);font-size:.9rem;line-height:1.32;box-shadow:0 1px .5px #00000021;overflow-wrap:anywhere}.is-mine .dmc-bubble{background:var(--dmc-bubble-out)}.is-first.is-mine .dmc-bubble{border-top-right-radius:0}.is-first.is-other .dmc-bubble{border-top-left-radius:0}.is-first.is-mine .dmc-bubble:after{content:"";position:absolute;top:0;right:-8px;border-top:10px solid var(--dmc-bubble-out);border-right:8px solid transparent}.is-first.is-other .dmc-bubble:after{content:"";position:absolute;top:0;left:-8px;border-top:10px solid var(--dmc-bubble-in);border-left:8px solid transparent}.dmc-from{display:block;font-size:.8rem;font-weight:600;margin-bottom:.1rem;color:#53bdeb}.dmc-text{white-space:pre-wrap}.dmc-time{float:right;position:relative;top:.3rem;margin-left:.6rem;font-size:.68rem;line-height:1;color:var(--dmc-chat-meta);font-variant-numeric:tabular-nums}.dmc-msg[data-hue="1"] .dmc-from{color:#ffd279}.dmc-msg[data-hue="2"] .dmc-from{color:#ff72a1}.dmc-msg[data-hue="3"] .dmc-from{color:#a5b337}.dmc-msg[data-hue="4"] .dmc-from{color:#06cf9c}.dmc-msg[data-hue="5"] .dmc-from{color:#f79877}.dmc-msg[data-hue="6"] .dmc-from{color:#a791ff}.dmc-msg[data-hue="7"] .dmc-from{color:#7ee2ff}.dmc-newchip{position:absolute;left:50%;bottom:.75rem;transform:translate(-50%);display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;border:0;border-radius:999px;padding:.4rem .8rem;background:#2a3942;color:var(--dmc-chat-text);font:inherit;font-size:.8rem;box-shadow:0 2px 10px #0006}.dmc-newchip svg{width:15px;height:15px;color:var(--dmc-green)}.dmc-send{display:flex;align-items:flex-end;gap:.5rem;padding:.6rem .75rem;background:var(--dmc-chat-head)}.dmc-compose{flex:1;resize:none;border:0;border-radius:1.3rem;padding:.6rem 1rem;background:#2a3942;color:var(--dmc-chat-text);line-height:1.35rem;font-size:.92rem;overflow-y:hidden;max-height:calc(1.35rem * 4 + 1.2rem);display:block}.dmc-compose::placeholder{color:var(--dmc-chat-sys-text)}.dmc-compose:focus{outline:0;box-shadow:inset 0 0 0 1px #00a88499}.dmc-sendbtn{width:2.55rem;height:2.55rem;padding:0;border:0;border-radius:50%;background:var(--dmc-green);color:#fff;flex:none}.dmc-sendbtn:hover{background:#06cf9c}.dmc-sendbtn:disabled{opacity:1;background:#2a3942;color:var(--dmc-chat-sys-text)}.dmc-sendbtn svg{width:19px;height:19px;margin-left:-2px}@media(max-width:760px){.dmc-panel{grid-template-columns:1fr;gap:1.25rem}.dmc-title{font-size:1.25rem}.dmc-call{border-radius:.75rem;min-height:30rem}.dmc-top{padding:.7rem .8rem 1.4rem}.dmc-remote{inset:3.2rem .6rem 5.4rem}.dmc-tile--me{right:.75rem;bottom:5.4rem}.dmc-main[data-tiles="0"] .dmc-tile--me .dmc-chip{bottom:5.4rem}.dmc-waiting{top:3.1rem;left:.6rem;right:.6rem;width:auto}.dmc-bar{left:.5rem;right:.5rem;bottom:.5rem;transform:none;justify-content:space-around;gap:.25rem;border-radius:1.4rem;padding:.5rem .4rem calc(.5rem + env(safe-area-inset-bottom,0px))}.dmc-tool{width:3.1rem;height:3.1rem}.dmc-btn--leave{width:3.1rem}.dmc-tool:after{display:none}.dmc-chat{position:fixed;inset:0;z-index:1000;width:auto;border:0;transform:translateY(100%);transition:transform .25s ease,visibility 0s .25s;visibility:hidden}.dmc-call.is-chat .dmc-chat{width:auto;transform:none;visibility:visible;transition:transform .25s ease}.dmc-chat>*{min-width:0}.dmc-chat-back{display:grid}.dmc-chat-close{display:none}.dmc-send{padding-bottom:calc(.6rem + env(safe-area-inset-bottom,0px))}.dmc-bubble{max-width:88%}}@media(prefers-reduced-motion:reduce){.dmc *,.dmc *:after{animation:none!important;transition:none!important}}
|
|
1
|
+
.dmc{--dmc-accent: #4f7cff;--dmc-accent-solid: color-mix(in srgb, var(--dmc-accent) 84%, #000);--dmc-accent-soft: color-mix(in srgb, var(--dmc-accent) 18%, transparent);--dmc-accent-text: color-mix(in srgb, var(--dmc-accent) 55%, #fff);--dmc-gap: 8px;--dmc-base: #1b1d21;--dmc-panel: #25282d;--dmc-raised: #2f3338;--dmc-line: #363a40;--dmc-on-dark: #e8eaed;--dmc-muted-dark: #9aa0a8;--dmc-red: #d9453f;--dmc-red-hover: #c23a35;--dmc-page: #f3f4f6;--dmc-card: #fff;--dmc-ink: #1f2328;--dmc-ink-muted: #5b6470;--dmc-border: #dde0e4;--dmc-offset: 0px;--dmc-left: 0px;--dmc-right: 0px;display:flex;flex-direction:column;gap:1rem;color:var(--dmc-ink)}.dmc [hidden]{display:none!important}html.dmc-page,html.dmc-page body{overflow:hidden!important}.dmc.dmc--app{position:fixed;z-index:40;top:var(--dmc-offset);left:var(--dmc-left);right:var(--dmc-right);bottom:0;margin:0;background:var(--dmc-page);overflow-y:auto;overscroll-behavior:contain;padding:2.5rem 1rem;align-items:center;justify-content:safe center;gap:1rem}.dmc.dmc--app[data-stage=in]{padding:0;background:var(--dmc-base);overflow:hidden}.dmc.dmc--app>*{width:min(60rem,100%);flex:none}.dmc.dmc--app>.dmc-call{width:100%;flex:1 1 auto}.dmc-head{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.dmc.dmc--app:not([data-stage=check])>.dmc-head{width:min(28rem,100%);justify-content:center;text-align:center}.dmc-title{font-size:1.35rem;font-weight:600;margin:0;flex:1 1 auto;letter-spacing:-.01em;color:var(--dmc-ink)}.dmc-btn{font:inherit;font-size:.9rem;cursor:pointer;padding:.5rem .95rem;min-height:2.5rem;border-radius:8px;border:1px solid var(--dmc-border);background:var(--dmc-card);color:inherit;display:inline-flex;align-items:center;justify-content:center;gap:.45rem;position:relative;font-weight:500;transition:background-color .15s,border-color .15s,color .15s}.dmc-btn:hover{border-color:#b9bec5;background:#f7f8f9}.dmc-btn:disabled{opacity:.55;cursor:default}.dmc-btn:focus-visible,.dmc-compose:focus-visible,.dmc-input:focus-visible{outline:2px solid var(--dmc-accent);outline-offset:2px}.dmc-i{display:inline-flex}.dmc-btn svg,.dmc-count svg,.dmc-note svg,.dmc-chip svg{width:18px;height:18px;flex:none}.dmc-btn.is-off{background:#fdecec;border-color:#f3c4c2;color:#b3261e}.dmc-btn--go{background:var(--dmc-accent-solid);border-color:transparent;color:#fff;font-weight:600}.dmc-btn--go:hover{background:color-mix(in srgb,var(--dmc-accent) 74%,#000);border-color:transparent}.dmc-btn--small{padding:.3rem .65rem;min-height:2rem;font-size:.82rem}.dmc-panel{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:1.75rem;align-items:center;background:var(--dmc-card);border:1px solid var(--dmc-border);border-radius:12px;padding:1.5rem;box-shadow:0 1px 2px #1018280d,0 8px 24px #1018280f}.dmc-panel--msg{display:flex;flex-direction:column;align-items:center;text-align:center;padding:2.5rem 2rem;gap:.25rem;width:min(28rem,100%)!important;align-self:center}.dmc-panel--msg h2{margin:.75rem 0 .25rem;font-size:1.2rem;font-weight:600;color:var(--dmc-ink)}.dmc-panel--msg p{color:var(--dmc-ink-muted);margin:0 0 1.25rem;font-size:.92rem;line-height:1.5}.dmc-pulse{width:64px;height:64px;border-radius:50%;display:grid;place-items:center;color:var(--dmc-accent-solid);background:var(--dmc-accent-soft);box-shadow:0 0 color-mix(in srgb,var(--dmc-accent) 35%,transparent);animation:dmc-pulse 2.2s infinite}.dmc-pulse svg{width:26px;height:26px}@keyframes dmc-pulse{70%{box-shadow:0 0 0 16px transparent}to{box-shadow:0 0 0 0 transparent}}.dmc-preview{position:relative;aspect-ratio:16 / 9;background:var(--dmc-base);border-radius:10px;overflow:hidden}.dmc-preview video,.dmc-tile video{width:100%;height:100%;object-fit:cover;display:block}.dmc-self,.dmc-self-preview{transform:scaleX(-1)}.dmc-nocam{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.6rem;color:var(--dmc-muted-dark);margin:0;font-size:.9rem}.dmc-avatar-dot{width:76px;height:76px;border-radius:50%;display:grid;place-items:center;background:var(--dmc-raised);color:var(--dmc-on-dark);font-size:1.8rem;font-weight:600}.dmc-preview-tools{position:absolute;left:0;right:0;bottom:.75rem;display:flex;justify-content:center;gap:.5rem}.dmc-round{width:44px;height:44px;min-height:0;padding:0;border-radius:10px;border:1px solid rgba(255,255,255,.14);background:#1b1d21b8;color:#fff;backdrop-filter:blur(6px)}.dmc-round:hover{background:#2f3338e6;border-color:#ffffff4d}.dmc-round.is-off{background:var(--dmc-red);border-color:transparent;color:#fff}.dmc-check h2{margin:0 0 .35rem;font-size:1.25rem;font-weight:600;color:var(--dmc-ink)}.dmc-label{display:grid;gap:.35rem;margin:1rem 0 .25rem;font-weight:500;font-size:.88rem;color:var(--dmc-ink)}.dmc-input{font:inherit;font-size:.95rem;padding:.55rem .75rem;min-height:2.5rem;border:1px solid var(--dmc-border);border-radius:8px;background:#fff;color:var(--dmc-ink);min-width:0}.dmc-label .dmc-input:focus{outline:0;border-color:var(--dmc-accent);box-shadow:0 0 0 3px var(--dmc-accent-soft)}.dmc-row{display:flex;gap:.5rem;flex-wrap:wrap;margin:.9rem 0}.dmc-chipbtn{font-size:.86rem}.dmc-note{color:var(--dmc-ink-muted);font-size:.9rem;line-height:1.45;margin:0}.dmc-note--rec{display:flex;gap:.5rem;align-items:flex-start;font-size:.85rem;margin:.25rem 0 0}.dmc-note--rec svg{color:var(--dmc-red);fill:currentColor;width:10px;height:10px;margin-top:.35rem}.dmc-error{color:#b3261e;font-weight:500;font-size:.9rem;margin:.5rem 0 0}.dmc-check .dmc-btn--go{width:100%;min-height:2.75rem;margin-top:1rem;font-size:.95rem}.dmc-call{display:flex;color:var(--dmc-on-dark);background:var(--dmc-base);overflow:hidden;color-scheme:dark;min-height:0;font-size:14px}.dmc-stage{position:relative;flex:1 1 auto;min-width:0;display:flex;flex-direction:column}.dmc-top{order:-1;flex:none;display:flex;align-items:center;justify-content:space-between;gap:1rem;height:44px;padding:0 1rem;background:var(--dmc-panel);border-bottom:1px solid var(--dmc-line)}.dmc-top-l{display:flex;align-items:center;gap:.75rem;min-width:0}.dmc-top .dmc-top-title{margin:0;font-size:.92rem;line-height:1.3;font-weight:600;letter-spacing:0;color:var(--dmc-on-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-timer{flex:none;font-size:.82rem;color:var(--dmc-muted-dark);font-variant-numeric:tabular-nums;padding-left:.75rem;border-left:1px solid var(--dmc-line)}.dmc-top-r{display:flex;align-items:center;gap:.6rem;flex:none}.dmc-rec{display:inline-flex;align-items:center;gap:.4rem;color:#ff8a85;background:#d9453f29;border:1px solid rgba(217,69,63,.45);border-radius:6px;padding:.12rem .5rem;font-size:.74rem;font-weight:600;letter-spacing:.02em}.dmc-rec-dot{width:7px;height:7px;border-radius:50%;background:#ff5a52;animation:dmc-blink 1.4s infinite}@keyframes dmc-blink{50%{opacity:.3}}.dmc-count{display:inline-flex;align-items:center;gap:.35rem;font-size:.82rem;color:var(--dmc-muted-dark);font-variant-numeric:tabular-nums}.dmc-count svg{width:16px;height:16px}.dmc-main{position:relative;flex:1 1 auto;min-height:0}.dmc-remote{position:absolute;inset:var(--dmc-gap);display:flex;flex-wrap:wrap;align-content:center;justify-content:center;gap:var(--dmc-gap);--cols: 1;--rows: 1}.dmc-cell{min-width:0;min-height:0;display:flex;width:var(--tile-w, calc((100% - (var(--cols) - 1) * var(--dmc-gap)) / var(--cols)));height:var(--tile-h, calc((100% - (var(--rows) - 1) * var(--dmc-gap)) / var(--rows)))}.dmc-main[data-tiles="2"] .dmc-remote{--cols: 2}.dmc-main[data-tiles="3"] .dmc-remote,.dmc-main[data-tiles="4"] .dmc-remote{--cols: 2;--rows: 2}.dmc-main[data-tiles="5"] .dmc-remote,.dmc-main[data-tiles="6"] .dmc-remote{--cols: 3;--rows: 2}.dmc-tile{position:relative;margin:0;background:var(--dmc-panel);border-radius:8px;overflow:hidden}.dmc-cell .dmc-tile{flex:1 1 auto;width:100%;height:100%}.dmc-tile video{position:relative;z-index:1}.dmc-avatar{position:absolute;inset:0;display:grid;place-items:center;z-index:0}.dmc-avatar span{width:clamp(3rem,18%,6rem);aspect-ratio:1;border-radius:50%;display:grid;place-items:center;background:var(--dmc-raised);color:var(--dmc-on-dark);font-size:clamp(1.1rem,2.4vw,2.2rem);font-weight:600}.dmc-tile--me .dmc-avatar{z-index:2;background:var(--dmc-panel)}.dmc-chip{position:absolute;left:.5rem;bottom:.5rem;z-index:3;display:inline-flex;align-items:center;gap:.3rem;max-width:calc(100% - 1rem);padding:.18rem .5rem;border-radius:6px;background:#1b1d21c7;color:var(--dmc-on-dark);font-size:.78rem;font-weight:500;line-height:1.35}.dmc-chip>span:last-child{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-chip-mute{display:inline-flex;color:#ff8a85}.dmc-chip-mute svg{width:13px;height:13px}.dmc-tile--me{position:absolute;z-index:2;right:calc(var(--dmc-gap) * 2);bottom:calc(var(--dmc-gap) * 2);width:clamp(10rem,17%,15rem);aspect-ratio:16 / 9;box-shadow:0 6px 20px #00000073;outline:1px solid rgba(255,255,255,.14)}.dmc-tile--me .dmc-chip{left:.35rem;bottom:.35rem;font-size:.7rem;padding:.1rem .4rem}.dmc-main[data-tiles="0"] .dmc-tile--me{inset:0;width:auto;aspect-ratio:auto;border-radius:0;outline:0;box-shadow:none}.dmc-main[data-tiles="0"] .dmc-tile--me .dmc-chip{left:.75rem;bottom:.75rem;font-size:.78rem;padding:.18rem .5rem}.dmc-main[data-tiles="0"] .dmc-tile--me:after{content:"";position:absolute;inset:0;z-index:2;background:#1b1d218c;pointer-events:none}.dmc-alone{position:absolute;inset:0;z-index:2;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:1rem;pointer-events:none}.dmc-alone-title{margin:0;font-size:1.1rem;font-weight:600;color:#fff}.dmc-alone-sub{margin:.35rem 0 0;color:#c9cdd2;font-size:.88rem}.dmc-waiting{position:absolute;z-index:4;top:calc(44px + .75rem);right:.75rem;width:min(20rem,calc(100% - 1.5rem));padding:.85rem;border-radius:10px;background:var(--dmc-raised);box-shadow:0 12px 32px #00000073;border:1px solid #40454c;animation:dmc-drop .2s ease}@keyframes dmc-drop{0%{opacity:0;transform:translateY(-4px)}}.dmc-waiting h3{display:flex;align-items:center;gap:.5rem;margin:0 0 .7rem;font-size:.85rem;font-weight:600;color:var(--dmc-on-dark)}.dmc-waiting-dot{width:8px;height:8px;border-radius:50%;background:var(--dmc-accent);box-shadow:0 0 0 3px var(--dmc-accent-soft)}.dmc-waiting ul{list-style:none;margin:0;padding:0;display:grid;gap:.7rem;max-height:14rem;overflow-y:auto}.dmc-waiting li{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.4rem .6rem}.dmc-winitial{width:2rem;height:2rem;border-radius:50%;display:grid;place-items:center;background:#454a52;color:#fff;font-weight:600;font-size:.85rem}.dmc-wname{font-weight:500;color:var(--dmc-on-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-wbtns{grid-column:2;display:flex;gap:.4rem}.dmc-waiting .dmc-btn svg{width:15px;height:15px}.dmc-waiting .dmc-btn--go{background:var(--dmc-accent-solid);color:#fff}.dmc-btn--ghost{background:transparent;color:var(--dmc-on-dark);border-color:#4a4f57}.dmc-btn--ghost:hover{background:#ffffff0f;border-color:#626872}.dmc-bar{flex:none;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:.5rem;padding:.5rem 1rem;background:var(--dmc-panel);border-top:1px solid var(--dmc-line)}.dmc-bar-mid{display:flex;align-items:center;gap:.35rem}.dmc-bar-end{display:flex;justify-content:flex-end}.dmc-tool{flex-direction:column;gap:3px;min-width:4.25rem;height:3.5rem;min-height:0;padding:.3rem .6rem;border-radius:10px;border:1px solid transparent;background:transparent;color:var(--dmc-on-dark);flex:none;font-weight:400}.dmc-tool:hover{background:var(--dmc-raised);border-color:transparent}.dmc-tool svg{width:20px;height:20px}.dmc-lbl{font-size:.72rem;line-height:1;color:var(--dmc-muted-dark);white-space:nowrap}.dmc-tool:hover .dmc-lbl{color:var(--dmc-on-dark)}.dmc-tool.is-off{background:transparent;color:#ff8a85}.dmc-tool.is-off:hover{background:#d9453f24}.dmc-tool.is-off .dmc-lbl{color:#ff8a85}.dmc-tool.is-on{background:var(--dmc-accent-soft);color:var(--dmc-accent-text)}.dmc-tool.is-on .dmc-lbl{color:var(--dmc-accent-text)}.dmc-btn--rec svg{color:var(--dmc-red);fill:currentColor;width:16px;height:16px;margin:2px 0}.dmc-btn--rec.is-on{background:#d9453f2e;color:#ff8a85}.dmc-btn--rec.is-on .dmc-lbl{color:#ff8a85}.dmc-btn--rec.is-on svg{color:#ff5a52;animation:dmc-blink 1.4s infinite}.dmc-btn--leave{background:var(--dmc-red);color:#fff;flex-direction:row;gap:.45rem;height:2.75rem;min-width:0;padding:0 1.1rem;border-radius:10px;font-weight:600}.dmc-btn--leave:hover{background:var(--dmc-red-hover)}.dmc-btn--leave .dmc-lbl,.dmc-btn--leave:hover .dmc-lbl{color:#fff;font-size:.85rem}.dmc-btn--leave svg{width:18px;height:18px}.dmc-badge{position:absolute;top:2px;right:10px;min-width:1.1rem;height:1.1rem;padding:0 .28rem;border-radius:999px;background:var(--dmc-accent-solid);color:#fff;font-size:.66rem;font-weight:600;line-height:1.1rem;text-align:center;box-shadow:0 0 0 2px var(--dmc-panel)}.dmc-chat{flex:none;width:0;display:flex;flex-direction:column;background:var(--dmc-panel);color:var(--dmc-on-dark);overflow:hidden;transition:width .2s ease;border-left:1px solid var(--dmc-line);font-size:14px}.dmc-call:not(.is-chat) .dmc-chat{border-left-width:0}.dmc-call.is-chat .dmc-chat{width:20rem}.dmc-chat>*{min-width:20rem}.dmc-chat-head{flex:none;display:flex;align-items:center;gap:.5rem;height:44px;padding:0 .5rem 0 1rem;border-bottom:1px solid var(--dmc-line)}.dmc-chat-titles{flex:1;min-width:0;display:flex;align-items:baseline;gap:.6rem}.dmc-chat-titles h3{margin:0;font-size:.92rem;font-weight:600;color:var(--dmc-on-dark)}.dmc-chat-titles span{font-size:.75rem;color:var(--dmc-muted-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-chat-back,.dmc-chat-close{width:2rem;height:2rem;border:0;border-radius:8px;background:transparent;color:var(--dmc-muted-dark);cursor:pointer;display:grid;place-items:center}.dmc-chat-back:hover,.dmc-chat-close:hover{background:var(--dmc-raised);color:var(--dmc-on-dark)}.dmc-chat-back:focus-visible,.dmc-chat-close:focus-visible{outline:2px solid var(--dmc-accent);outline-offset:1px}.dmc-chat-back svg,.dmc-chat-close svg{width:18px;height:18px}.dmc-chat-back{display:none}.dmc-chat-body{position:relative;flex:1;min-height:0;display:flex}.dmc-messages{list-style:none;margin:0;padding:.5rem 1rem 1rem;flex:1;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:#43484f transparent}.dmc-chat-empty{position:absolute;inset:auto 1.5rem 45%;margin:0;text-align:center;color:var(--dmc-muted-dark);font-size:.85rem;line-height:1.5}.dmc-msg{display:flex;flex-direction:column;margin-top:3px}.dmc-msg.is-first{margin-top:.85rem}.dmc-msg.is-mine{align-items:flex-end}.dmc-msg.is-other{align-items:flex-start}.dmc-msg.is-sys{align-items:center;margin-top:.6rem}.dmc-msg.is-sys+.dmc-msg.is-sys:not(.has-day){margin-top:.2rem}.dmc-msg.has-day.is-first{margin-top:.35rem}.dmc-day{align-self:stretch;display:flex;align-items:center;gap:.75rem;margin:.5rem 0;color:var(--dmc-muted-dark);font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em}.dmc-day:before,.dmc-day:after{content:"";flex:1;height:1px;background:var(--dmc-line)}.dmc-sys{color:#80868e;font-size:.76rem;line-height:1.4;text-align:center}.dmc-meta{display:flex;align-items:baseline;gap:.5rem;margin:0 .15rem .2rem;max-width:88%}.dmc-from{font-size:.8rem;font-weight:500;color:#8fb0ff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-time{font-size:.7rem;color:#80868e;font-variant-numeric:tabular-nums;flex:none}.dmc-bubble{max-width:88%;padding:.45rem .7rem;border-radius:8px;background:var(--dmc-raised);color:var(--dmc-on-dark);line-height:1.42;overflow-wrap:anywhere}.is-mine .dmc-bubble{background:color-mix(in srgb,var(--dmc-accent) 20%,var(--dmc-panel));color:#f1f4ff}.dmc-text{white-space:pre-wrap}.dmc-msg[data-hue="1"] .dmc-from{color:#6fc2ad}.dmc-msg[data-hue="2"] .dmc-from{color:#d6ad72}.dmc-msg[data-hue="3"] .dmc-from{color:#bf9fdc}.dmc-msg[data-hue="4"] .dmc-from{color:#e0948e}.dmc-msg[data-hue="5"] .dmc-from{color:#9fcb8d}.dmc-msg[data-hue="6"] .dmc-from{color:#7fbad6}.dmc-msg[data-hue="7"] .dmc-from{color:#d49fba}.dmc-newchip{position:absolute;left:50%;bottom:.75rem;transform:translate(-50%);display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;border:1px solid #40454c;border-radius:8px;padding:.35rem .7rem;background:var(--dmc-raised);color:var(--dmc-on-dark);font:inherit;font-size:.78rem;box-shadow:0 4px 14px #0006}.dmc-newchip svg{width:14px;height:14px;color:var(--dmc-accent-text)}.dmc-send{flex:none;display:flex;align-items:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--dmc-line)}.dmc-compose{flex:1;resize:none;border:1px solid #40454c;border-radius:8px;padding:.5rem .7rem;min-height:0;background:var(--dmc-base);color:var(--dmc-on-dark);line-height:1.35rem;font-size:14px;overflow-y:hidden;max-height:calc(6.4rem + 2px);display:block}.dmc-compose::placeholder{color:#80868e}.dmc-compose:focus{outline:0;border-color:var(--dmc-accent);box-shadow:0 0 0 3px var(--dmc-accent-soft)}.dmc-sendbtn{width:2.4rem;height:2.4rem;min-height:0;padding:0;border:0;border-radius:8px;background:var(--dmc-accent-solid);color:#fff;flex:none}.dmc-sendbtn:hover{background:color-mix(in srgb,var(--dmc-accent) 74%,#000)}.dmc-sendbtn:disabled{opacity:1;background:var(--dmc-raised);color:#80868e}.dmc-sendbtn svg{width:17px;height:17px;margin-left:-2px}.dmc-invite{flex:none;width:0;display:flex;flex-direction:column;background:var(--dmc-panel);color:var(--dmc-on-dark);overflow:hidden;transition:width .2s ease;border-left:0 solid var(--dmc-line);font-size:14px}.dmc-invite.is-open{width:22rem;border-left-width:1px}.dmc-invite>*{min-width:22rem}.dmc .dmc-invite ul{margin:0;padding:0;list-style:none}.dmc .dmc-invite li{margin:0}.dmc-inv-body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:.85rem 1rem 1rem;scrollbar-width:thin;scrollbar-color:#43484f transparent}.dmc-inv-input{font:inherit;font-size:14px;width:100%;min-width:0;min-height:2.4rem;padding:.45rem .7rem;border:1px solid #40454c;border-radius:8px;background:var(--dmc-base);color:var(--dmc-on-dark)}.dmc-inv-input::placeholder{color:#80868e}.dmc-inv-input:focus{outline:0;border-color:var(--dmc-accent);box-shadow:0 0 0 3px var(--dmc-accent-soft)}.dmc-inv-search{position:relative;display:block}.dmc-inv-search .dmc-inv-input{padding-left:2.2rem}.dmc-inv-sico{position:absolute;left:.7rem;top:50%;transform:translateY(-50%);display:inline-flex;color:#80868e;pointer-events:none}.dmc-inv-sico svg{width:16px;height:16px}.dmc-inv-label{margin:1rem 0 .4rem;font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--dmc-muted-dark)}.dmc-inv-chips{margin-top:.75rem}.dmc-inv-chips ul{display:flex;flex-wrap:wrap;gap:.35rem}.dmc-inv-chip{display:inline-flex;align-items:center;gap:.35rem;max-width:100%;padding:.2rem .25rem .2rem .6rem;border-radius:6px;background:var(--dmc-accent-soft);color:var(--dmc-accent-text);font-size:.8rem}.dmc-inv-chipname{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#f1f4ff;font-weight:500}.dmc-inv-chipkind{font-size:.68rem;opacity:.85}.dmc-inv-chipx{display:grid;place-items:center;width:1.4rem;height:1.4rem;border:0;border-radius:4px;background:transparent;color:inherit;cursor:pointer;padding:0}.dmc-inv-chipx:hover{background:#ffffff1a}.dmc-inv-chipx:focus-visible{outline:2px solid var(--dmc-accent);outline-offset:1px}.dmc-inv-chipx svg{width:13px;height:13px}.dmc-inv-list{list-style:none;margin:0;padding:0;display:grid;gap:2px}.dmc-inv-row{width:100%;display:grid;grid-template-columns:auto 1fr auto auto;align-items:center;gap:.6rem;padding:.45rem .5rem;border:1px solid transparent;border-radius:8px;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.dmc-inv-row:hover{background:var(--dmc-raised)}.dmc-inv-row:focus-visible{outline:2px solid var(--dmc-accent);outline-offset:-2px}.dmc-inv-row.is-picked{background:var(--dmc-accent-soft)}.dmc-inv-av{width:2rem;height:2rem;border-radius:50%;display:grid;place-items:center;background:#454a52;color:#fff;font-weight:600;font-size:.82rem}.dmc-inv-who{min-width:0;display:flex;flex-direction:column}.dmc-inv-name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-inv-mail{font-size:.75rem;color:var(--dmc-muted-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dmc-inv-kind{font-size:.68rem;font-weight:600;padding:.1rem .4rem;border-radius:4px;border:1px solid #4a4f57;color:var(--dmc-muted-dark)}.dmc-inv-kind[data-kind=user]{border-color:transparent;background:#3a3f46;color:#c9cdd2}.dmc-inv-tick{width:1.25rem;height:1.25rem;border-radius:50%;display:grid;place-items:center;border:1.5px solid #5a6069;color:transparent}.dmc-inv-tick svg{width:12px;height:12px}.dmc-inv-row.is-picked .dmc-inv-tick{background:var(--dmc-accent-solid);border-color:transparent;color:#fff}.dmc-inv-only{margin:.25rem 0 0;color:var(--dmc-on-dark);font-size:.88rem;line-height:1.5}.dmc-inv-empty{margin:.5rem .25rem;color:var(--dmc-muted-dark);font-size:.85rem;line-height:1.45}.dmc-inv-pair{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.4fr) auto;gap:.4rem}.dmc-inv-add{width:2.4rem;min-height:2.4rem;padding:0;background:var(--dmc-raised);border-color:#40454c;color:var(--dmc-on-dark)}.dmc-inv-add:hover{background:#3a3f46;border-color:#5a6069}.dmc-inv-add svg{width:17px;height:17px}.dmc-inv-foot{flex:none;border-top:1px solid var(--dmc-line);padding:.75rem 1rem calc(.85rem + env(safe-area-inset-bottom,0px));display:grid;gap:.55rem}.dmc-inv-via{border:0;margin:0;padding:0;min-width:0;display:flex;flex-wrap:wrap;align-items:center;gap:.35rem 1rem}.dmc-inv-via legend{float:left;width:100%;margin:0 0 .1rem;padding:0;font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--dmc-muted-dark)}.dmc-inv-via label{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;font-size:.86rem}.dmc-inv-via input{width:16px;height:16px;margin:0;accent-color:var(--dmc-accent)}.dmc-inv-hint{margin:0;font-size:.75rem;line-height:1.45;color:#80868e}.dmc-inv-status{margin:0;font-size:.82rem;line-height:1.4;color:#9fcb8d}.dmc-inv-status.is-err{color:#ff8a85}.dmc-inv-results{list-style:none;margin:0;padding:0;display:grid;gap:.25rem;max-height:7.5rem;overflow-y:auto;font-size:.8rem}.dmc-inv-res{display:flex;gap:.4rem;line-height:1.35;color:var(--dmc-muted-dark)}.dmc-inv-res:before{content:"";flex:none;width:6px;height:6px;margin-top:.4em;border-radius:50%;background:#6fb56a}.dmc-inv-res.is-err:before{background:#e0605a}.dmc-inv-rname{color:var(--dmc-on-dark);font-weight:500;flex:none;max-width:45%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dmc-inv-link{font-size:.78rem;color:var(--dmc-muted-dark)}.dmc-inv-btns{display:flex;gap:.5rem}.dmc-inv-btns .dmc-btn{flex:1;min-height:2.5rem}.dmc-inv-copy svg,.dmc-inv-send svg{width:16px;height:16px}.dmc-inv-send:disabled{opacity:1;background:var(--dmc-raised);color:#80868e}.dmc-tool--invite svg{width:20px;height:20px}@media(max-width:760px){.dmc.dmc--app{padding:1rem .75rem}.dmc-panel{grid-template-columns:1fr;gap:1.1rem;padding:1rem}.dmc-panel--msg{padding:2rem 1.25rem}.dmc-title{font-size:1.15rem}.dmc-top{padding:0 .75rem}.dmc-waiting{left:.5rem;right:.5rem;top:calc(44px + .5rem);width:auto}.dmc-bar{display:flex;justify-content:space-around;gap:.25rem;padding:.45rem .4rem calc(.45rem + env(safe-area-inset-bottom,0px))}.dmc-bar-mid{display:contents}.dmc-tool{width:44px;height:44px;min-width:0;padding:0;background:var(--dmc-raised)}.dmc-tool.is-off{background:#d9453f33}.dmc-lbl{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%)}.dmc-bar-side:empty{display:none}.dmc-bar-end{display:contents}.dmc-btn--leave{width:52px;padding:0;background:var(--dmc-red)}.dmc-badge{top:-4px;right:-4px}.dmc-tile--me{right:.5rem;bottom:.5rem}.dmc.dmc--app:has(.dmc-call.is-chat){z-index:1000}.dmc-chat{position:fixed;inset:0;z-index:1000;width:auto;border:0;transform:translateY(100%);transition:transform .22s ease,visibility 0s .22s;visibility:hidden}.dmc-call.is-chat .dmc-chat{width:auto;transform:none;visibility:visible;transition:transform .22s ease}.dmc-chat>*{min-width:0}.dmc-chat-back{display:grid}.dmc-chat-close{display:none}.dmc-chat-head{padding:0 .75rem 0 .35rem}.dmc-send{padding-bottom:calc(.75rem + env(safe-area-inset-bottom,0px))}.dmc.dmc--app:has(.dmc-invite.is-open){z-index:1000}.dmc-invite{position:fixed;inset:0;z-index:1000;width:auto;border:0;transform:translateY(100%);transition:transform .22s ease,visibility 0s .22s;visibility:hidden}.dmc-invite.is-open{width:auto;border:0;transform:none;visibility:visible;transition:transform .22s ease}.dmc-invite>*{min-width:0}}@media(max-width:760px)and (orientation:portrait){.dmc-tile--me{width:clamp(6rem,26%,8.5rem);aspect-ratio:3 / 4}}@media(prefers-reduced-motion:reduce){.dmc *,.dmc *:after{animation:none!important;transition:none!important}}
|