diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000..4c2c6c78 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + semi: true, + trailingComma: "all", + singleQuote: true, + printWidth: 120, + tabWidth: 4 + }; \ No newline at end of file diff --git a/README.md b/README.md index bf6cae78..e7808daa 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ curl -X POST "http://localhost:3000/api/v1/meeting" -H "authorization: mirotalk_ curl -X POST "https://mirotalk.up.railway.app/api/v1/meeting" -H "authorization: mirotalk_default_secret" -H "Content-Type: application/json" curl -X POST "https://mirotalk.herokuapp.com/api/v1/meeting" -H "authorization: mirotalk_default_secret" -H "Content-Type: application/json" ``` + ## API Documentation The API documentation uses [swagger](https://swagger.io/) at http://localhost:3000/api/v1/docs. Or check it out on [railway](https://mirotalk.up.railway.app/api/v1/docs) & [heroku](https://mirotalk.herokuapp.com/api/v1/docs). diff --git a/api/README.md b/api/README.md index d20ed4f6..23ad8968 100644 --- a/api/README.md +++ b/api/README.md @@ -1,4 +1,5 @@ [![restAPI](restAPI.png)](https://mirotalk.up.railway.app/api/v1/docs) + ## Create a meeting Create a meeting with a `HTTP request` containing the `API_KEY` sent to MiroTalk’s server. The response contains a `meeting` URL that can be `embedded` in your client within an `iframe`. @@ -20,9 +21,9 @@ Embedding a meeting into a `service` or `app` requires using an `iframe` with th ```html ``` @@ -32,8 +33,8 @@ Develop your `website` or `application`, and bring `video meetings` in with a si ```html ``` diff --git a/api/meeting.js b/api/meeting.js index 213e3966..925adba2 100644 --- a/api/meeting.js +++ b/api/meeting.js @@ -1,22 +1,22 @@ -const fetch = require("node-fetch"); +const fetch = require('node-fetch'); -const API_KEY = "mirotalk_default_secret"; +const API_KEY = 'mirotalk_default_secret'; // const MIROTALK_URL = "http://localhost:3000/api/v1/meeting"; // const MIROTALK_URL = "https://mirotalk.herokuapp.com/api/v1/meeting"; -const MIROTALK_URL = "https://mirotalk.up.railway.app/api/v1/meeting"; +const MIROTALK_URL = 'https://mirotalk.up.railway.app/api/v1/meeting'; function getResponse() { - return fetch(MIROTALK_URL, { - method: "POST", - headers: { - authorization: API_KEY, - "Content-Type": "application/json", - }, - }); + return fetch(MIROTALK_URL, { + method: 'POST', + headers: { + authorization: API_KEY, + 'Content-Type': 'application/json', + }, + }); } getResponse().then(async (res) => { - console.log("Status code:", res.status); - const data = await res.json(); - console.log("meeting:", data.meeting); + console.log('Status code:', res.status); + const data = await res.json(); + console.log('meeting:', data.meeting); }); diff --git a/api/swagger.yaml b/api/swagger.yaml index 6f680cef..f59d4084 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -1,47 +1,47 @@ -swagger: "2.0" +swagger: '2.0' info: - title: MiroTalk API - description: API description for external applications that integrates with MiroTalk. - version: 1.0.0 + title: MiroTalk API + description: API description for external applications that integrates with MiroTalk. + version: 1.0.0 basePath: /api/v1 schemes: - - https - - http + - https + - http paths: - /meeting: - post: - tags: - - "meeting" - summary: "Create meeting" - description: "Create meeting" - consumes: - - "application/json" - produces: - - "application/json" - security: - - secretApiKey: [] - responses: - "200": - description: "Meeting created" - schema: - $ref: "#/definitions/MeetingResponse" - "403": - description: "Unauthorized!" + /meeting: + post: + tags: + - 'meeting' + summary: 'Create meeting' + description: 'Create meeting' + consumes: + - 'application/json' + produces: + - 'application/json' + security: + - secretApiKey: [] + responses: + '200': + description: 'Meeting created' + schema: + $ref: '#/definitions/MeetingResponse' + '403': + description: 'Unauthorized!' securityDefinitions: - secretApiKey: - type: "apiKey" - name: "authorization" - in: "header" - description: "Format like this: authorization: {API_KEY_SECRET}" + secretApiKey: + type: 'apiKey' + name: 'authorization' + in: 'header' + description: 'Format like this: authorization: {API_KEY_SECRET}' definitions: - MeetingResponse: - type: "object" - properties: - meeting: - type: "string" + MeetingResponse: + type: 'object' + properties: + meeting: + type: 'string' diff --git a/docker-compose.yml b/docker-compose.yml index dbfb6096..3c5541f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,18 @@ version: '3' services: - mirotalk: - image: mirotalk:latest - build: - context: . - dockerfile: Dockerfile - container_name: mirotalk - hostname: mirotalk - volumes: - - .env:/usr/src/app/.env:ro - restart: unless-stopped - ports: - - "3000:3000" + mirotalk: + image: mirotalk:latest + build: + context: . + dockerfile: Dockerfile + container_name: mirotalk + hostname: mirotalk + volumes: + - .env:/usr/src/app/.env:ro + restart: unless-stopped + ports: + - '3000:3000' # Uncomment below, remove "ports:" section above and configure labels as # needed for LetsEncrypt TLS certificates with Traefik. # See https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/ @@ -23,4 +23,4 @@ services: # - "traefik.http.routers.mirotalk.rule=Host(`mirotalk.example.com`)" # - "traefik.http.routers.mirotalk.entrypoints=websecure" # - "traefik.http.routers.mirotalk.tls.certresolver=myresolver" -# - "traefik.http.services.mirotalk.loadbalancer.server.port=3000" \ No newline at end of file +# - "traefik.http.services.mirotalk.loadbalancer.server.port=3000" diff --git a/package.json b/package.json index 8949411e..84078919 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,30 @@ { - "name": "mirotalk", - "version": "1.0.0", - "description": "A free WebRTC browser-based video call", - "main": "server.js", - "scripts": { - "start": "node server.js", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/miroslavpejic85/mirotalk" - }, - "author": "Miroslav Pejic", - "license": "AGPL-3.0", - "homepage": "https://github.com/miroslavpejic85/mirotalk", - "dependencies": { - "compression": "^1.7.4", - "dotenv": "^10.0.0", - "express": "^4.17.1", - "ngrok": "^4.0.1", - "socket.io": "^4.1.2", - "swagger-ui-express": "^4.1.6", - "yamljs": "^0.3.0" - }, - "devDependencies": { - "node-fetch": "^2.6.1" - } + "name": "mirotalk", + "version": "1.0.0", + "description": "A free WebRTC browser-based video call", + "main": "server.js", + "scripts": { + "start": "node server.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/miroslavpejic85/mirotalk" + }, + "author": "Miroslav Pejic", + "license": "AGPL-3.0", + "homepage": "https://github.com/miroslavpejic85/mirotalk", + "dependencies": { + "compression": "^1.7.4", + "dotenv": "^10.0.0", + "express": "^4.17.1", + "ngrok": "^4.0.1", + "socket.io": "^4.1.2", + "swagger-ui-express": "^4.1.6", + "yamljs": "^0.3.0" + }, + "devDependencies": { + "node-fetch": "^2.6.1", + "prettier": "2.3.2" + } } diff --git a/server.js b/server.js index e7c03542..916458af 100755 --- a/server.js +++ b/server.js @@ -8,13 +8,13 @@ http://patorjk.com/software/taag/#p=display&f=ANSI%20Regular&t=Server ███████ ███████ ██  ██   ████   ███████ ██  ██                                        dependencies: { - compression : https://www.npmjs.com/package/compression - dotenv : https://www.npmjs.com/package/dotenv - express : https://www.npmjs.com/package/express - ngrok : https://www.npmjs.com/package/ngrok - socket.io : https://www.npmjs.com/package/socket.io - swagger : https://www.npmjs.com/package/swagger-ui-express - yamljs : https://www.npmjs.com/package/yamljs + compression : https://www.npmjs.com/package/compression + dotenv : https://www.npmjs.com/package/dotenv + express : https://www.npmjs.com/package/express + ngrok : https://www.npmjs.com/package/ngrok + socket.io : https://www.npmjs.com/package/socket.io + swagger : https://www.npmjs.com/package/swagger-ui-express + yamljs : https://www.npmjs.com/package/yamljs } MiroTalk Signaling Server @@ -35,29 +35,29 @@ along with this program. If not, see . */ -"use strict"; // https://www.w3schools.com/js/js_strict.asp +'use strict'; // https://www.w3schools.com/js/js_strict.asp -require("dotenv").config(); +require('dotenv').config(); -const compression = require("compression"); -const express = require("express"); -const path = require("path"); +const compression = require('compression'); +const express = require('express'); +const path = require('path'); const app = express(); app.use(compression()); // Compress all HTTP responses GZip -const http = require("http"); +const http = require('http'); const server = http.createServer(app); -const { Server } = require("socket.io"); +const { Server } = require('socket.io'); const io = new Server().listen(server); -const ngrok = require("ngrok"); -const yamlJS = require("yamljs"); -const swaggerUi = require("swagger-ui-express"); -const swaggerDocument = yamlJS.load(__dirname + "/api/swagger.yaml"); -const apiBasePath = "/api/v1"; +const ngrok = require('ngrok'); +const yamlJS = require('yamljs'); +const swaggerUi = require('swagger-ui-express'); +const swaggerDocument = yamlJS.load(__dirname + '/api/swagger.yaml'); +const apiBasePath = '/api/v1'; -let API_KEY_SECRET = process.env.API_KEY_SECRET || "mirotalk_default_secret"; +let API_KEY_SECRET = process.env.API_KEY_SECRET || 'mirotalk_default_secret'; let PORT = process.env.PORT || 3000; // signalingServerPort -let localHost = "http://localhost:" + PORT; // http -let api_docs = localHost + apiBasePath + "/docs"; // api docs +let localHost = 'http://localhost:' + PORT; // http +let api_docs = localHost + apiBasePath + '/docs'; // api docs let channels = {}; // collect channels let sockets = {}; // collect sockets let peers = {}; // collect peers info grp by channels @@ -70,105 +70,101 @@ let turnUsername = process.env.TURN_USERNAME; let turnCredential = process.env.TURN_PASSWORD; // Use all static files from the www folder -app.use(express.static(path.join(__dirname, "www"))); +app.use(express.static(path.join(__dirname, 'www'))); // Api parse body data as json app.use(express.json()); // Remove trailing slashes in url handle bad requests app.use((err, req, res, next) => { - if (err instanceof SyntaxError && err.status === 400 && "body" in err) { - logme("Request Error", { - header: req.headers, - body: req.body, - error: err.message, - }); - return res.status(400).send({ status: 404, message: err.message }); // Bad request - } - if (req.path.substr(-1) === "/" && req.path.length > 1) { - let query = req.url.slice(req.path.length); - res.redirect(301, req.path.slice(0, -1) + query); - } else { - next(); - } + if (err instanceof SyntaxError && err.status === 400 && 'body' in err) { + logme('Request Error', { + header: req.headers, + body: req.body, + error: err.message, + }); + return res.status(400).send({ status: 404, message: err.message }); // Bad request + } + if (req.path.substr(-1) === '/' && req.path.length > 1) { + let query = req.url.slice(req.path.length); + res.redirect(301, req.path.slice(0, -1) + query); + } else { + next(); + } }); /* app.get(["/"], (req, res) => { - res.sendFile(path.join(__dirname, "www/client.html")) + res.sendFile(path.join(__dirname, "www/client.html")) }); */ // all start from here -app.get(["/"], (req, res) => { - res.sendFile(path.join(__dirname, "www/landing.html")); +app.get(['/'], (req, res) => { + res.sendFile(path.join(__dirname, 'www/landing.html')); }); // set new room name and join -app.get(["/newcall"], (req, res) => { - res.sendFile(path.join(__dirname, "www/newcall.html")); +app.get(['/newcall'], (req, res) => { + res.sendFile(path.join(__dirname, 'www/newcall.html')); }); // if not allow video/audio -app.get(["/permission"], (req, res) => { - res.sendFile(path.join(__dirname, "www/permission.html")); +app.get(['/permission'], (req, res) => { + res.sendFile(path.join(__dirname, 'www/permission.html')); }); // privacy policy -app.get(["/privacy"], (req, res) => { - res.sendFile(path.join(__dirname, "www/privacy.html")); +app.get(['/privacy'], (req, res) => { + res.sendFile(path.join(__dirname, 'www/privacy.html')); }); // no room name specified to join -app.get("/join/", (req, res) => { - res.redirect("/"); +app.get('/join/', (req, res) => { + res.redirect('/'); }); // join to room -app.get("/join/*", (req, res) => { - if (Object.keys(req.query).length > 0) { - logme("redirect:" + req.url + " to " + url.parse(req.url).pathname); - res.redirect(url.parse(req.url).pathname); - } else { - res.sendFile(path.join(__dirname, "www/client.html")); - } +app.get('/join/*', (req, res) => { + if (Object.keys(req.query).length > 0) { + logme('redirect:' + req.url + ' to ' + url.parse(req.url).pathname); + res.redirect(url.parse(req.url).pathname); + } else { + res.sendFile(path.join(__dirname, 'www/client.html')); + } }); /** - MiroTalk API v1 - The response will give you a entrypoint / Room URL for your meeting. - For api docs we use: https://swagger.io/ + MiroTalk API v1 + The response will give you a entrypoint / Room URL for your meeting. + For api docs we use: https://swagger.io/ */ // api docs -app.use( - apiBasePath + "/docs", - swaggerUi.serve, - swaggerUi.setup(swaggerDocument) -); +app.use(apiBasePath + '/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // request meeting room endpoint -app.post([apiBasePath + "/meeting"], (req, res) => { - // check if user was authorized for the api call - let authorization = req.headers.authorization; - if (authorization != API_KEY_SECRET) { - logme("MiroTalk get meeting - Unauthorized", { - header: req.headers, - body: req.body, - }); - return res.status(403).json({ error: "Unauthorized!" }); - } - // setup meeting URL - let host = req.headers.host; - let meetingURL = getMeetingURL(host) + "/join/" + makeId(15); - res.setHeader("Content-Type", "application/json"); - res.end(JSON.stringify({ meeting: meetingURL })); +app.post([apiBasePath + '/meeting'], (req, res) => { + // check if user was authorized for the api call + let authorization = req.headers.authorization; + if (authorization != API_KEY_SECRET) { + logme('MiroTalk get meeting - Unauthorized', { + header: req.headers, + body: req.body, + }); + return res.status(403).json({ error: 'Unauthorized!' }); + } + // setup meeting URL + let host = req.headers.host; + let meetingURL = getMeetingURL(host) + '/join/' + makeId(15); + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ meeting: meetingURL })); - // logme the output if all done - logme("MiroTalk get meeting - Authorized", { - header: req.headers, - body: req.body, - meeting: meetingURL, - }); + // logme the output if all done + logme('MiroTalk get meeting - Authorized', { + header: req.headers, + body: req.body, + meeting: meetingURL, + }); }); /** @@ -177,7 +173,7 @@ app.post([apiBasePath + "/meeting"], (req, res) => { * @returns meeting Room URL */ function getMeetingURL(host) { - return "http" + (host.includes("localhost") ? "" : "s") + "://" + host; + return 'http' + (host.includes('localhost') ? '' : 's') + '://' + host; } /** @@ -186,14 +182,13 @@ function getMeetingURL(host) { * @returns random id */ function makeId(length) { - let result = ""; - let characters = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; + let result = ''; + let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; } // end of MiroTalk API v1 @@ -208,14 +203,14 @@ function makeId(length) { * Check the functionality of STUN/TURN servers: * https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ */ -let iceServers = [{ urls: "stun:stun.l.google.com:19302" }]; +let iceServers = [{ urls: 'stun:stun.l.google.com:19302' }]; -if (turnEnabled == "true") { - iceServers.push({ - urls: turnUrls, - username: turnUsername, - credential: turnCredential, - }); +if (turnEnabled == 'true') { + iceServers.push({ + urls: turnUrls, + username: turnUsername, + credential: turnCredential, + }); } /** @@ -223,37 +218,37 @@ if (turnEnabled == "true") { * https://ngrok.com */ async function ngrokStart() { - try { - await ngrok.authtoken(ngrokAuthToken); - await ngrok.connect(PORT); - let api = ngrok.getApi(); - let data = await api.listTunnels(); - let pu0 = data.tunnels[0].public_url; - let pu1 = data.tunnels[1].public_url; - let tunnelHttps = pu0.startsWith("https") ? pu0 : pu1; - // server settings - logme("settings", { - http: localHost, - https: tunnelHttps, - api_docs: api_docs, - api_key_secret: API_KEY_SECRET, - iceServers: iceServers, - ngrok: { - ngrok_enabled: ngrokEnabled, - ngrok_token: ngrokAuthToken, - }, - }); - } catch (err) { - console.error("[Error] ngrokStart", err); - } + try { + await ngrok.authtoken(ngrokAuthToken); + await ngrok.connect(PORT); + let api = ngrok.getApi(); + let data = await api.listTunnels(); + let pu0 = data.tunnels[0].public_url; + let pu1 = data.tunnels[1].public_url; + let tunnelHttps = pu0.startsWith('https') ? pu0 : pu1; + // server settings + logme('settings', { + http: localHost, + https: tunnelHttps, + api_docs: api_docs, + api_key_secret: API_KEY_SECRET, + iceServers: iceServers, + ngrok: { + ngrok_enabled: ngrokEnabled, + ngrok_token: ngrokAuthToken, + }, + }); + } catch (err) { + console.error('[Error] ngrokStart', err); + } } /** * Start Local Server with ngrok https tunnel (optional) */ server.listen(PORT, null, () => { - logme( - `%c + logme( + `%c ███████╗██╗ ██████╗ ███╗ ██╗ ███████╗███████╗██████╗ ██╗ ██╗███████╗██████╗ ██╔════╝██║██╔════╝ ████╗ ██║ ██╔════╝██╔════╝██╔══██╗██║ ██║██╔════╝██╔══██╗ @@ -263,21 +258,21 @@ server.listen(PORT, null, () => { ╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ started... `, - "font-family:monospace" - ); + 'font-family:monospace', + ); - // https tunnel - if (ngrokEnabled == "true") { - ngrokStart(); - } else { - // server settings - logme("settings", { - http: localHost, - api_docs: api_docs, - api_key_secret: API_KEY_SECRET, - iceServers: iceServers, - }); - } + // https tunnel + if (ngrokEnabled == 'true') { + ngrokStart(); + } else { + // server settings + logme('settings', { + http: localHost, + api_docs: api_docs, + api_key_secret: API_KEY_SECRET, + iceServers: iceServers, + }); + } }); /** @@ -291,403 +286,365 @@ server.listen(PORT, null, () => { * the peer connection and will be in streaming audio/video between eachother. * On peer connected */ -io.sockets.on("connect", (socket) => { - logme("[" + socket.id + "] --> connection accepted"); +io.sockets.on('connect', (socket) => { + logme('[' + socket.id + '] --> connection accepted'); - socket.channels = {}; - sockets[socket.id] = socket; + socket.channels = {}; + sockets[socket.id] = socket; - /** - * On peer diconnected - */ - socket.on("disconnect", () => { - for (let channel in socket.channels) { - removePeerFrom(channel); - } - logme("[" + socket.id + "] <--> disconnected"); - delete sockets[socket.id]; - }); - - /** - * On peer join - */ - socket.on("join", (config) => { - logme("[" + socket.id + "] --> join ", config); - - let channel = config.channel; - let peer_name = config.peerName; - let peer_video = config.peerVideo; - let peer_audio = config.peerAudio; - let peer_hand = config.peerHand; - - if (channel in socket.channels) { - logme("[" + socket.id + "] [Warning] already joined", channel); - return; - } - // no channel aka room in channels init - if (!(channel in channels)) { - channels[channel] = {}; - } - - // no channel aka room in peers init - if (!(channel in peers)) { - peers[channel] = {}; - } - - // room locked by the participants can't join - if (peers[channel]["Locked"] === true) { - logme("[" + socket.id + "] [Warning] Room Is Locked", channel); - socket.emit("roomIsLocked"); - return; - } - - // collect peers info grp by channels - peers[channel][socket.id] = { - peer_name: peer_name, - peer_video: peer_video, - peer_audio: peer_audio, - peer_hand: peer_hand, - }; - logme("connected peers grp by roomId", peers); - - for (let id in channels[channel]) { - // offer false - channels[channel][id].emit("addPeer", { - peer_id: socket.id, - peers: peers[channel], - should_create_offer: false, - iceServers: iceServers, - }); - // offer true - socket.emit("addPeer", { - peer_id: id, - peers: peers[channel], - should_create_offer: true, - iceServers: iceServers, - }); - logme("[" + socket.id + "] emit addPeer [" + id + "]"); - } - - channels[channel][socket.id] = socket; - socket.channels[channel] = channel; - }); - - /** - * Remove peers from channel aka room - * @param {*} channel - */ - async function removePeerFrom(channel) { - if (!(channel in socket.channels)) { - logme("[" + socket.id + "] [Warning] not in ", channel); - return; - } - - delete socket.channels[channel]; - delete channels[channel][socket.id]; - delete peers[channel][socket.id]; - - switch (Object.keys(peers[channel]).length) { - case 0: - // last peer disconnected from the room without room status set, delete room data - delete peers[channel]; - break; - case 1: - // last peer disconnected from the room having room status set, delete room data - if ("Locked" in peers[channel]) delete peers[channel]; - break; - } - - for (let id in channels[channel]) { - await channels[channel][id].emit("removePeer", { peer_id: socket.id }); - await socket.emit("removePeer", { peer_id: id }); - logme("[" + socket.id + "] emit removePeer [" + id + "]"); - } - } - - /** - * Relay ICE to peers - */ - socket.on("relayICE", (config) => { - let peer_id = config.peer_id; - let ice_candidate = config.ice_candidate; - /* - logme( - "[" + socket.id + "] relay ICE-candidate to [" + peer_id + "] ", - { address: config.ice_candidate.address } - ); - */ - if (peer_id in sockets) { - sockets[peer_id].emit("iceCandidate", { - peer_id: socket.id, - ice_candidate: ice_candidate, - }); - } - }); - - /** - * Relay SDP to peers - */ - socket.on("relaySDP", (config) => { - let peer_id = config.peer_id; - let session_description = config.session_description; - - logme( - "[" + socket.id + "] relay SessionDescription to [" + peer_id + "] ", - { type: session_description.type } - ); - - if (peer_id in sockets) { - sockets[peer_id].emit("sessionDescription", { - peer_id: socket.id, - session_description: session_description, - }); - } - }); - - /** - * Refresh Room Status (Locked/Unlocked) - */ - socket.on("roomStatus", (config) => { - let peerConnections = config.peerConnections; - let room_id = config.room_id; - let room_locked = config.room_locked; - let peer_name = config.peer_name; - - peers[room_id]["Locked"] = room_locked; - - if (Object.keys(peerConnections).length != 0) { - logme( - "[" + - socket.id + - "] emit roomStatus" + - " to [room_id: " + - room_id + - " locked: " + - room_locked + - "]" - ); - for (let peer_id in peerConnections) { - if (sockets[peer_id]) { - sockets[peer_id].emit("roomStatus", { - peer_name: peer_name, - room_locked: room_locked, - }); + /** + * On peer diconnected + */ + socket.on('disconnect', () => { + for (let channel in socket.channels) { + removePeerFrom(channel); + } + logme('[' + socket.id + '] <--> disconnected'); + delete sockets[socket.id]; + }); + + /** + * On peer join + */ + socket.on('join', (config) => { + logme('[' + socket.id + '] --> join ', config); + + let channel = config.channel; + let peer_name = config.peerName; + let peer_video = config.peerVideo; + let peer_audio = config.peerAudio; + let peer_hand = config.peerHand; + + if (channel in socket.channels) { + logme('[' + socket.id + '] [Warning] already joined', channel); + return; + } + // no channel aka room in channels init + if (!(channel in channels)) { + channels[channel] = {}; + } + + // no channel aka room in peers init + if (!(channel in peers)) { + peers[channel] = {}; + } + + // room locked by the participants can't join + if (peers[channel]['Locked'] === true) { + logme('[' + socket.id + '] [Warning] Room Is Locked', channel); + socket.emit('roomIsLocked'); + return; + } + + // collect peers info grp by channels + peers[channel][socket.id] = { + peer_name: peer_name, + peer_video: peer_video, + peer_audio: peer_audio, + peer_hand: peer_hand, + }; + logme('connected peers grp by roomId', peers); + + for (let id in channels[channel]) { + // offer false + channels[channel][id].emit('addPeer', { + peer_id: socket.id, + peers: peers[channel], + should_create_offer: false, + iceServers: iceServers, + }); + // offer true + socket.emit('addPeer', { + peer_id: id, + peers: peers[channel], + should_create_offer: true, + iceServers: iceServers, + }); + logme('[' + socket.id + '] emit addPeer [' + id + ']'); + } + + channels[channel][socket.id] = socket; + socket.channels[channel] = channel; + }); + + /** + * Remove peers from channel aka room + * @param {*} channel + */ + async function removePeerFrom(channel) { + if (!(channel in socket.channels)) { + logme('[' + socket.id + '] [Warning] not in ', channel); + return; + } + + delete socket.channels[channel]; + delete channels[channel][socket.id]; + delete peers[channel][socket.id]; + + switch (Object.keys(peers[channel]).length) { + case 0: + // last peer disconnected from the room without room status set, delete room data + delete peers[channel]; + break; + case 1: + // last peer disconnected from the room having room status set, delete room data + if ('Locked' in peers[channel]) delete peers[channel]; + break; + } + + for (let id in channels[channel]) { + await channels[channel][id].emit('removePeer', { peer_id: socket.id }); + await socket.emit('removePeer', { peer_id: id }); + logme('[' + socket.id + '] emit removePeer [' + id + ']'); } - } } - }); - /** - * Relay NAME to peers - */ - socket.on("peerName", (config) => { - let peerConnections = config.peerConnections; - let room_id = config.room_id; - let peer_name_old = config.peer_name_old; - let peer_name_new = config.peer_name_new; - let peer_id_to_update = null; + /** + * Relay ICE to peers + */ + socket.on('relayICE', (config) => { + let peer_id = config.peer_id; + let ice_candidate = config.ice_candidate; - // update peers new name in the specified room - for (let peer_id in peers[room_id]) { - if (peers[room_id][peer_id]["peer_name"] == peer_name_old) { - peers[room_id][peer_id]["peer_name"] = peer_name_new; - peer_id_to_update = peer_id; - /* - logme("[" + socket.id + "] change peer name", { - room_id: room_id, - peer_id: peer_id, - peer_name_old: peer_name_old, - peer_name_new: peer_name_new, + // logme('[' + socket.id + '] relay ICE-candidate to [' + peer_id + '] ', { + // address: config.ice_candidate.address, + // }); + + if (peer_id in sockets) { + sockets[peer_id].emit('iceCandidate', { + peer_id: socket.id, + ice_candidate: ice_candidate, + }); + } + }); + + /** + * Relay SDP to peers + */ + socket.on('relaySDP', (config) => { + let peer_id = config.peer_id; + let session_description = config.session_description; + + logme('[' + socket.id + '] relay SessionDescription to [' + peer_id + '] ', { type: session_description.type }); + + if (peer_id in sockets) { + sockets[peer_id].emit('sessionDescription', { + peer_id: socket.id, + session_description: session_description, + }); + } + }); + + /** + * Refresh Room Status (Locked/Unlocked) + */ + socket.on('roomStatus', (config) => { + let peerConnections = config.peerConnections; + let room_id = config.room_id; + let room_locked = config.room_locked; + let peer_name = config.peer_name; + + peers[room_id]['Locked'] = room_locked; + + if (Object.keys(peerConnections).length != 0) { + logme('[' + socket.id + '] emit roomStatus' + ' to [room_id: ' + room_id + ' locked: ' + room_locked + ']'); + for (let peer_id in peerConnections) { + if (sockets[peer_id]) { + sockets[peer_id].emit('roomStatus', { + peer_name: peer_name, + room_locked: room_locked, + }); + } + } + } + }); + + /** + * Relay NAME to peers + */ + socket.on('peerName', (config) => { + let peerConnections = config.peerConnections; + let room_id = config.room_id; + let peer_name_old = config.peer_name_old; + let peer_name_new = config.peer_name_new; + let peer_id_to_update = null; + + // update peers new name in the specified room + for (let peer_id in peers[room_id]) { + if (peers[room_id][peer_id]['peer_name'] == peer_name_old) { + peers[room_id][peer_id]['peer_name'] = peer_name_new; + peer_id_to_update = peer_id; + + // logme('[' + socket.id + '] change peer name', { + // room_id: room_id, + // peer_id: peer_id, + // peer_name_old: peer_name_old, + // peer_name_new: peer_name_new, + // }); + } + } + + // refresh if found + if (peer_id_to_update && Object.keys(peerConnections).length != 0) { + logme('[' + socket.id + '] emit peerName to [room_id: ' + room_id + ']', { + peer_id: peer_id_to_update, + peer_name: peer_name_new, + }); + for (let peer_id in peerConnections) { + if (sockets[peer_id]) { + sockets[peer_id].emit('peerName', { + peer_id: peer_id_to_update, + peer_name: peer_name_new, + }); + } + } + } + }); + + /** + * Relay Audio Video Hand ... Status to peers + */ + socket.on('peerStatus', (config) => { + let peerConnections = config.peerConnections; + let room_id = config.room_id; + let peer_name = config.peer_name; + let element = config.element; + let status = config.status; + + // update peers video-audio status in the specified room + for (let peer_id in peers[room_id]) { + if (peers[room_id][peer_id]['peer_name'] == peer_name) { + switch (element) { + case 'video': + peers[room_id][peer_id]['peer_video'] = status; + break; + case 'audio': + peers[room_id][peer_id]['peer_audio'] = status; + break; + case 'hand': + peers[room_id][peer_id]['peer_hand'] = status; + break; + } + + // logme('[' + socket.id + '] change ' + element + ' status', { + // room_id: room_id, + // peer_name: peer_name, + // element: element, + // status: status, + // }); + } + } + + // socket.id aka peer that send this status + if (Object.keys(peerConnections).length != 0) { + logme('[' + socket.id + '] emit peerStatus to [room_id: ' + room_id + ']', { + peer_id: socket.id, + element: element, + status: status, + }); + for (let peer_id in peerConnections) { + if (sockets[peer_id]) { + sockets[peer_id].emit('peerStatus', { + peer_id: socket.id, + peer_name: peer_name, + element: element, + status: status, + }); + } + } + } + }); + + /** + * Relay actions to peers in the same room + */ + socket.on('peerAction', (config) => { + let peerConnections = config.peerConnections; + let room_id = config.room_id; + let peer_name = config.peer_name; + let peer_action = config.peer_action; + + // socket.id aka peer that send this status + if (Object.keys(peerConnections).length != 0) { + logme('[' + socket.id + '] emit peerAction to [room_id: ' + room_id + ']', { + peer_id: socket.id, + peer_name: peer_name, + peer_action: peer_action, + }); + for (let peer_id in peerConnections) { + if (sockets[peer_id]) { + sockets[peer_id].emit('peerAction', { + peer_name: peer_name, + peer_action: peer_action, + }); + } + } + } + }); + + /** + * Relay Kick out peer from room + */ + socket.on('kickOut', (config) => { + let room_id = config.room_id; + let peer_id = config.peer_id; + let peer_name = config.peer_name; + + logme('[' + socket.id + '] kick out peer [' + peer_id + '] from room_id [' + room_id + ']'); + + if (peer_id in sockets) { + sockets[peer_id].emit('kickOut', { + peer_name: peer_name, + }); + } + }); + + /** + * Relay File info + */ + socket.on('fileInfo', (config) => { + let peerConnections = config.peerConnections; + let room_id = config.room_id; + let peer_name = config.peer_name; + let file = config.file; + + logme('[' + socket.id + '] Peer [' + peer_name + '] send file to room_id [' + room_id + ']', { + fileName: file.fileName, + fileSize: bytesToSize(file.fileSize), + fileType: file.fileType, }); - */ - } - } - // refresh if found - if (peer_id_to_update && Object.keys(peerConnections).length != 0) { - logme("[" + socket.id + "] emit peerName to [room_id: " + room_id + "]", { - peer_id: peer_id_to_update, - peer_name: peer_name_new, - }); - for (let peer_id in peerConnections) { - if (sockets[peer_id]) { - sockets[peer_id].emit("peerName", { - peer_id: peer_id_to_update, - peer_name: peer_name_new, - }); + function bytesToSize(bytes) { + let sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + if (bytes == 0) return '0 Byte'; + let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; } - } - } - }); - /** - * Relay Audio Video Hand ... Status to peers - */ - socket.on("peerStatus", (config) => { - let peerConnections = config.peerConnections; - let room_id = config.room_id; - let peer_name = config.peer_name; - let element = config.element; - let status = config.status; - - // update peers video-audio status in the specified room - for (let peer_id in peers[room_id]) { - if (peers[room_id][peer_id]["peer_name"] == peer_name) { - switch (element) { - case "video": - peers[room_id][peer_id]["peer_video"] = status; - break; - case "audio": - peers[room_id][peer_id]["peer_audio"] = status; - break; - case "hand": - peers[room_id][peer_id]["peer_hand"] = status; - break; + if (Object.keys(peerConnections).length != 0) { + for (let peer_id in peerConnections) { + if (sockets[peer_id]) { + sockets[peer_id].emit('fileInfo', file); + } + } } - /* - logme("[" + socket.id + "] change " + element + " status", { - room_id: room_id, - peer_name: peer_name, - element: element, - status: status, - }); - */ - } - } + }); - // socket.id aka peer that send this status - if (Object.keys(peerConnections).length != 0) { - logme( - "[" + socket.id + "] emit peerStatus to [room_id: " + room_id + "]", - { - peer_id: socket.id, - element: element, - status: status, + /** + * Whiteboard actions for all user in the same room + */ + socket.on('wb', (config) => { + let peerConnections = config.peerConnections; + delete config.peerConnections; + if (Object.keys(peerConnections).length != 0) { + // logme("[" + socket.id + "] whiteboard config", config); + for (let peer_id in peerConnections) { + if (sockets[peer_id]) { + sockets[peer_id].emit('wb', config); + } + } } - ); - for (let peer_id in peerConnections) { - if (sockets[peer_id]) { - sockets[peer_id].emit("peerStatus", { - peer_id: socket.id, - peer_name: peer_name, - element: element, - status: status, - }); - } - } - } - }); - - /** - * Relay actions to peers in the same room - */ - socket.on("peerAction", (config) => { - let peerConnections = config.peerConnections; - let room_id = config.room_id; - let peer_name = config.peer_name; - let peer_action = config.peer_action; - - // socket.id aka peer that send this status - if (Object.keys(peerConnections).length != 0) { - logme( - "[" + socket.id + "] emit peerAction to [room_id: " + room_id + "]", - { - peer_id: socket.id, - peer_name: peer_name, - peer_action: peer_action, - } - ); - for (let peer_id in peerConnections) { - if (sockets[peer_id]) { - sockets[peer_id].emit("peerAction", { - peer_name: peer_name, - peer_action: peer_action, - }); - } - } - } - }); - - /** - * Relay Kick out peer from room - */ - socket.on("kickOut", (config) => { - let room_id = config.room_id; - let peer_id = config.peer_id; - let peer_name = config.peer_name; - - logme( - "[" + - socket.id + - "] kick out peer [" + - peer_id + - "] from room_id [" + - room_id + - "]" - ); - - if (peer_id in sockets) { - sockets[peer_id].emit("kickOut", { - peer_name: peer_name, - }); - } - }); - - /** - * Relay File info - */ - socket.on("fileInfo", (config) => { - let peerConnections = config.peerConnections; - let room_id = config.room_id; - let peer_name = config.peer_name; - let file = config.file; - - logme( - "[" + - socket.id + - "] Peer [" + - peer_name + - "] send file to room_id [" + - room_id + - "]", - { - fileName: file.fileName, - fileSize: bytesToSize(file.fileSize), - fileType: file.fileType, - } - ); - - function bytesToSize(bytes) { - let sizes = ["Bytes", "KB", "MB", "GB", "TB"]; - if (bytes == 0) return "0 Byte"; - let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); - return Math.round(bytes / Math.pow(1024, i), 2) + " " + sizes[i]; - } - - if (Object.keys(peerConnections).length != 0) { - for (let peer_id in peerConnections) { - if (sockets[peer_id]) { - sockets[peer_id].emit("fileInfo", file); - } - } - } - }); - - /** - * Whiteboard actions for all user in the same room - */ - socket.on("wb", (config) => { - let peerConnections = config.peerConnections; - delete config.peerConnections; - if (Object.keys(peerConnections).length != 0) { - // logme("[" + socket.id + "] whiteboard config", config); - for (let peer_id in peerConnections) { - if (sockets[peer_id]) { - sockets[peer_id].emit("wb", config); - } - } - } - }); + }); }); // end [sockets.on-connect] /** @@ -695,7 +652,7 @@ io.sockets.on("connect", (socket) => { * @param {*} msg message any * @param {*} op optional params */ -function logme(msg, op = "") { - let dataTime = new Date().toISOString().replace(/T/, " ").replace(/Z/, ""); - console.log("[" + dataTime + "] " + msg, op); +function logme(msg, op = '') { + let dataTime = new Date().toISOString().replace(/T/, ' ').replace(/Z/, ''); + console.log('[' + dataTime + '] ' + msg, op); } diff --git a/www/client.html b/www/client.html index 63953a89..c91f88ac 100755 --- a/www/client.html +++ b/www/client.html @@ -1,418 +1,376 @@ - - MiroTalk WebRTC Video call, Chat Room & Screen Sharing. - - - + - - - - - - - - - - - - - - - - - - - + gtag('config', 'G-3XM60XK9RQ'); + + MiroTalk WebRTC Video call, Chat Room & Screen Sharing. + + + + + + + + + + + + + + + + + + + - - -

WebRTC

+ + +

WebRTC

- -
-

Loading...

-
+        
+        
+

Loading...

+
 Please allow camera & microphone
 access to use this app.
-      
-
+
+
- -
- - - - - - - - - - - - - - -
- +
+ + + + + + + + + + + + + + +
+ - -
-
-
-
- Chat -
-
- - - - - -
-
+
+
+
+
Chat
+
+ + + + + +
+
- -
-
-
+ +
+
+
-
-
-
Friends Name
-
00:00:00
-
+
+
+
Friends Name
+
00:00:00
+
-
Public message example
-
-
+
Public message example
+
+
-
-
+
+
-
-
-
Your Name
-
00:00:00
-
+
+
+
Your Name
+
00:00:00
+
-
Public message example
-
-
+
Public message example
+
+
- -
-
+ +
+
-
-
-
Friends Name
-
00:00:00
-
+
+
+
Friends Name
+
00:00:00
+
-
Private message example
-
-
+
Private message example
+
+
-
-
+
+
-
-
-
Your Name
-
00:00:00
-
+
+
+
Your Name
+
00:00:00
+
-
Private message example
-
-
-
+
Private message example
+ + + -
- - - -
-
+
+ + + +
+
- -
-
-
-
- Send Private messages -
-
- -
-
-
-
- -
-
-
+ +
+
+
+
Send Private messages
+
+ +
+
+
+
+ +
+
+
+
+
+
-
- -
- + - -
-
- -
- - -
- +
+
+ +
+ + +
+ - -
-
- -
-
-
-
- - - - + +
+
+ +
+
+
+
+ + + + +
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+ +

+ +
+ +

+ +
+ +
+ +
+
+
+
+    + +
+
+
+
+    + +

+
+ +
+
+ +
+
+ +
+ +
+
+
+ + + +
+
+ + +
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+ + + + +
+
+ -
-
-
-
- -
-
-
-
- -
-
-
-
- -
+ +
+
+
+ +
+ -
-
- -
- -

- -
- -

- -
- -
+ + + + + + + + + + + + -
-
-
-
-    - -
-
-
-
-    - -

-
- -
-
- -
-
- -
- -
-
-
- - - -
-
- - -
- -
-
- -
-
-
-
-
-
-
-
-
-
- - - - -
- -
- - - -
-
-
- - -
- - - - - - - - - - - - - - - - + --> + diff --git a/www/css/client.css b/www/css/client.css index 28f6f3bd..ba27ac1a 100755 --- a/www/css/client.css +++ b/www/css/client.css @@ -3,30 +3,30 @@ --------------------------------------------------------------*/ @-webkit-keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } + from { + opacity: 0; + } + to { + opacity: 1; + } } @-moz-keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } + from { + opacity: 0; + } + to { + opacity: 1; + } } @keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } + from { + opacity: 0; + } + to { + opacity: 1; + } } /*-------------------------------------------------------------- @@ -34,39 +34,39 @@ --------------------------------------------------------------*/ :root { - /* common */ - --msger-top: 50%; - --msger-left: 50%; - --msger-height: 680px; - --msger-width: 420px; + /* common */ + --msger-top: 50%; + --msger-left: 50%; + --msger-height: 680px; + --msger-width: 420px; - /* whiteboard resize */ - --wb-width: 800px; - --wb-height: 600px; + /* whiteboard resize */ + --wb-width: 800px; + --wb-height: 600px; - /* my settings */ - --mySettings-select-w: 100%; + /* my settings */ + --mySettings-select-w: 100%; - /* btns hover scale 110% zoom */ - --btns-hover-scale: scale(1.1); + /* btns hover scale 110% zoom */ + --btns-hover-scale: scale(1.1); - /* neon theme default */ - --body-bg: black; - --msger-bg: black; - --msger-private-bg: black; - --left-msg-bg: #da05f3; - --private-msg-bg: #f77070; - --right-msg-bg: #579ffb; - --box-shadow: 3px 3px 6px #0500ff, -3px -3px 6px #da05f3; - --btn-bg: white; - --btn-color: black; - --btn-opc: 1; - --btns-left: 20px; - --wb-bg: #000000; - --wb-hbg: #000000; - --my-settings-label-color: limegreen; + /* neon theme default */ + --body-bg: black; + --msger-bg: black; + --msger-private-bg: black; + --left-msg-bg: #da05f3; + --private-msg-bg: #f77070; + --right-msg-bg: #579ffb; + --box-shadow: 3px 3px 6px #0500ff, -3px -3px 6px #da05f3; + --btn-bg: white; + --btn-color: black; + --btn-opc: 1; + --btns-left: 20px; + --wb-bg: #000000; + --wb-hbg: #000000; + --my-settings-label-color: limegreen; - /* dark theme + /* dark theme --body-bg: #16171b; --msger-bg: #16171b; --msger-private-bg: black; @@ -83,7 +83,7 @@ --my-settings-label-color: limegreen; */ - /* forest theme + /* forest theme --body-bg: black; --msger-bg: black; --msger-private-bg: black; @@ -100,7 +100,7 @@ --my-settings-label-color: limegreen; */ - /* sky theme + /* sky theme --body-bg: black; --msger-bg: black; --msger-private-bg: black; @@ -117,7 +117,7 @@ --my-settings-label-color: #03a5ce; */ - /* ghost theme + /* ghost theme --body-bg: #16171b; --msger-bg: transparent; --msger-private-bg: black; @@ -134,12 +134,12 @@ --my-settings-label-color: limegreen; */ - /* https://developer.mozilla.org/it/docs/Web/CSS/object-fit */ - --video-object-fit: cover; + /* https://developer.mozilla.org/it/docs/Web/CSS/object-fit */ + --video-object-fit: cover; } * { - outline: none; + outline: none; } /*-------------------------------------------------------------- @@ -147,29 +147,29 @@ --------------------------------------------------------------*/ body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, - Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; - background: var(--body-bg); - background-image: url("../images/illustration-section-01.svg"); - background-repeat: no-repeat; - background-attachment: fixed; - background-position: center; - margin: 0; - padding: 0; - justify-content: center; - align-items: center; - height: 100vh; - opacity: 0; /* make things invisible upon start */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 0.3s; - -moz-animation-duration: 0.3s; - animation-duration: 0.3s; - overflow: hidden; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + background: var(--body-bg); + background-image: url('../images/illustration-section-01.svg'); + background-repeat: no-repeat; + background-attachment: fixed; + background-position: center; + margin: 0; + padding: 0; + justify-content: center; + align-items: center; + height: 100vh; + opacity: 0; /* make things invisible upon start */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 0.3s; + -moz-animation-duration: 0.3s; + animation-duration: 0.3s; + overflow: hidden; } /*-------------------------------------------------------------- @@ -177,17 +177,17 @@ body { --------------------------------------------------------------*/ #loadingDiv { - position: relative; - color: white; - top: 40%; - left: 60%; - transform: translate(-50%, -50%); + position: relative; + color: white; + top: 40%; + left: 60%; + transform: translate(-50%, -50%); } #loadingDiv h1 { - font-size: 70px; + font-size: 70px; } #loadingDiv pre { - font-size: 15px; + font-size: 15px; } /*-------------------------------------------------------------- @@ -195,45 +195,45 @@ body { --------------------------------------------------------------*/ .pulsate { - animation: pulsate 3s ease-out; - animation-iteration-count: infinite; - -webkit-animation: pulsate 3s ease-out; - -webkit-animation-iteration-count: infinite; - opacity: 0.5; + animation: pulsate 3s ease-out; + animation-iteration-count: infinite; + -webkit-animation: pulsate 3s ease-out; + -webkit-animation-iteration-count: infinite; + opacity: 0.5; } @-webkit-keyframes pulsate { - 0% { - opacity: 0.5; - } - 50% { - opacity: 1; - } - 100% { - opacity: 0.5; - } + 0% { + opacity: 0.5; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.5; + } } @keyframes pulsate { - 0% { - opacity: 0.5; - } - 50% { - opacity: 1; - } - 100% { - opacity: 0.5; - } + 0% { + opacity: 0.5; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.5; + } } @-webkit-keyframes pulsate { - 0% { - opacity: 0.5; - } - 50% { - opacity: 1; - } - 100% { - opacity: 0.5; - } + 0% { + opacity: 0.5; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.5; + } } /*-------------------------------------------------------------- @@ -241,56 +241,56 @@ body { --------------------------------------------------------------*/ .statusMenu { - z-index: 7; - display: none; - position: absolute; - padding: 10px; - background-color: rgba(0, 0, 0, 0.7); - border-radius: 5px; - font-size: small; /* 4 mobile */ - font-weight: bold; - text-align: center; - width: 100%; - cursor: default; - /* center */ - top: 22px; - left: 50%; - transform: translate(-50%, -50%); - -webkit-transform: translate(-50%, -50%); - -moz-transform: translate(-50%, -50%); - /* fadeIn effect */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: hidden; + z-index: 7; + display: none; + position: absolute; + padding: 10px; + background-color: rgba(0, 0, 0, 0.7); + border-radius: 5px; + font-size: small; /* 4 mobile */ + font-weight: bold; + text-align: center; + width: 100%; + cursor: default; + /* center */ + top: 22px; + left: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + /* fadeIn effect */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: hidden; } .statusMenu i, .statusMenu p, .statusMenu h4 { - color: white; - display: inline; - border: none; - margin-right: 10px; + color: white; + display: inline; + border: none; + margin-right: 10px; } .statusMenu button { - float: right; - margin-right: 3px; - color: white; - background: transparent; - display: inline; - border: none; + float: right; + margin-right: 3px; + color: white; + background: transparent; + display: inline; + border: none; } .statusMenu p:hover, .statusMenu h4:hover, .statusMenu button:hover { - color: rgb(0, 255, 0); - transition: all 0.3s ease-in-out; + color: rgb(0, 255, 0); + transition: all 0.3s ease-in-out; } /*-------------------------------------------------------------- @@ -298,13 +298,13 @@ body { --------------------------------------------------------------*/ .videoAvatarImage { - z-index: 8; - position: absolute; - /*center*/ - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - display: none; + z-index: 8; + position: absolute; + /*center*/ + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: none; } /*-------------------------------------------------------------- @@ -312,58 +312,58 @@ body { --------------------------------------------------------------*/ #leftButtons { - z-index: 12; - display: none; - position: absolute; - left: var(--btns-left); - top: 50%; - -webkit-transform: translate(0%, -50%); - -ms-transform: translate(0%, -50%); - transform: translate(0%, -50%); - border-radius: 20px; - background: transparent; - box-shadow: var(--box-shadow); - padding: 15px; - flex-direction: column; - justify-content: space-around; - grid-gap: 0.3rem; - width: 40px; - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: hidden; + z-index: 12; + display: none; + position: absolute; + left: var(--btns-left); + top: 50%; + -webkit-transform: translate(0%, -50%); + -ms-transform: translate(0%, -50%); + transform: translate(0%, -50%); + border-radius: 20px; + background: transparent; + box-shadow: var(--box-shadow); + padding: 15px; + flex-direction: column; + justify-content: space-around; + grid-gap: 0.3rem; + width: 40px; + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: hidden; } #leftButtons button { - border: none; - font-size: 1.5rem; - transition: all 0.3s ease-in-out; - background: var(--btn-bg); - padding: 4px; - border-radius: 5px; - opacity: var(--btn-opc); + border: none; + font-size: 1.5rem; + transition: all 0.3s ease-in-out; + background: var(--btn-bg); + padding: 4px; + border-radius: 5px; + opacity: var(--btn-opc); } #leftButtons button:focus { - outline: none; + outline: none; } #initAudioBtn, #initVideoBtn { - border: none; - border-radius: 5px; - width: 40px; - background: white; - color: black; - font-size: 1.5rem; - padding: 4px; - transition: all 0.3s ease-in-out; + border: none; + border-radius: 5px; + width: 40px; + background: white; + color: black; + font-size: 1.5rem; + padding: 4px; + transition: all 0.3s ease-in-out; } #shareRoomBtn, @@ -380,7 +380,7 @@ body { #mySettingsBtn, #aboutBtn, #leaveRoomBtn { - color: var(--btn-color); + color: var(--btn-color); } #initAudioBtn:hover, @@ -398,17 +398,17 @@ body { #whiteboardBtn:hover, #mySettingsBtn:hover, #aboutBtn:hover { - color: rgb(8, 189, 89); - transform: var(--btns-hover-scale); + color: rgb(8, 189, 89); + transform: var(--btns-hover-scale); } #leaveRoomBtn:hover { - color: red; - transform: var(--btns-hover-scale); + color: red; + transform: var(--btns-hover-scale); } .fa-microphone-slash, .fa-video-slash { - color: #e74c3c !important; + color: #e74c3c !important; } /*-------------------------------------------------------------- @@ -416,41 +416,41 @@ body { --------------------------------------------------------------*/ .msger-draggable { - z-index: 10; - display: none; - position: absolute; - /* center screen */ - top: var(--msger-top); - left: var(--msger-left); - transform: translate(-50%, -50%); - /* end center screen */ - height: var(--msger-height); - width: var(--msger-width); - background: var(--msger-bg); - /* text-align: justify; */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: hidden; - border-radius: 5px; - box-shadow: var(--box-shadow); + z-index: 10; + display: none; + position: absolute; + /* center screen */ + top: var(--msger-top); + left: var(--msger-left); + transform: translate(-50%, -50%); + /* end center screen */ + height: var(--msger-height); + width: var(--msger-width); + background: var(--msger-bg); + /* text-align: justify; */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: hidden; + border-radius: 5px; + box-shadow: var(--box-shadow); } .msger { - display: flex; - flex-flow: column wrap; - justify-content: space-between; - top: var(--msger-top); - left: var(--msger-left); - height: var(--msger-height); - width: var(--msger-width); - background: var(--msger-bg); + display: flex; + flex-flow: column wrap; + justify-content: space-between; + top: var(--msger-top); + left: var(--msger-left); + height: var(--msger-height); + width: var(--msger-width); + background: var(--msger-bg); } /*-------------------------------------------------------------- @@ -458,35 +458,35 @@ body { --------------------------------------------------------------*/ .msger-header { - display: flex; - justify-content: space-between; - padding: 10px; - background: rgb(0, 0, 0); - color: #666; - cursor: move; + display: flex; + justify-content: space-between; + padding: 10px; + background: rgb(0, 0, 0); + color: #666; + cursor: move; } .msger-private-header { - display: flex; - justify-content: space-between; - padding: 10px; - background: rgb(0, 0, 0); - color: #666; + display: flex; + justify-content: space-between; + padding: 10px; + background: rgb(0, 0, 0); + color: #666; } .msger-header-options button { - border: none; - font-size: 1.2rem; - transition: all 0.3s ease-in-out; - background: rgb(0, 0, 0); - color: #fff; - border-radius: 5px; - transition: background 0.23s; + border: none; + font-size: 1.2rem; + transition: all 0.3s ease-in-out; + background: rgb(0, 0, 0); + color: #fff; + border-radius: 5px; + transition: background 0.23s; } .msger-header-options button:hover { - color: rgb(0, 180, 50); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } /*-------------------------------------------------------------- @@ -494,108 +494,108 @@ body { --------------------------------------------------------------*/ .msger-chat { - flex: 1; - overflow-y: auto; - padding: 10px; - background: var(--msger-bg); + flex: 1; + overflow-y: auto; + padding: 10px; + background: var(--msger-bg); } .msger-chat::-webkit-scrollbar { - width: 5px; + width: 5px; } .msger-chat::-webkit-scrollbar-track { - background: transparent; + background: transparent; } .msger-chat::-webkit-scrollbar-thumb { - background: black; + background: black; } .msg { - display: flex; - align-items: flex-end; - margin-bottom: 10px; + display: flex; + align-items: flex-end; + margin-bottom: 10px; } .msg:last-of-type { - margin: 0; + margin: 0; } /* left side */ .left-msg .msg-bubble { - background: var(--left-msg-bg); - border-bottom-left-radius: 0; - color: #fff; + background: var(--left-msg-bg); + border-bottom-left-radius: 0; + color: #fff; } .left-msg .private-msg-bubble { - background: var(--private-msg-bg); - border-bottom-left-radius: 0; - color: #fff; + background: var(--private-msg-bg); + border-bottom-left-radius: 0; + color: #fff; } /* right side */ .right-msg { - flex-direction: row-reverse; + flex-direction: row-reverse; } .right-msg .msg-bubble { - background: var(--right-msg-bg); - border-bottom-right-radius: 0; - color: #fff; + background: var(--right-msg-bg); + border-bottom-right-radius: 0; + color: #fff; } .right-msg .private-msg-bubble { - background: var(--private-msg-bg); - border-bottom-right-radius: 0; - color: #fff; + background: var(--private-msg-bg); + border-bottom-right-radius: 0; + color: #fff; } .right-msg .msg-img { - margin: 0 0 0 10px; + margin: 0 0 0 10px; } /* common */ .msg-img { - width: 50px; - height: 50px; - margin-right: 10px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - /* border-radius: 50%; */ + width: 50px; + height: 50px; + margin-right: 10px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + /* border-radius: 50%; */ } .private-msg-bubble, .msg-bubble { - max-width: 200px; - padding: 15px; - border-radius: 15px; + max-width: 200px; + padding: 15px; + border-radius: 15px; } .msg-info { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; } .msg-info-name { - margin-right: 10px; - font-weight: bold; + margin-right: 10px; + font-weight: bold; } .msg-info-time { - font-size: 0.85em; + font-size: 0.85em; } .msg-text { - /* https://css-tricks.com/almanac/properties/o/overflow-wrap/ */ - overflow-wrap: break-word; - word-wrap: break-word; - hyphens: auto; + /* https://css-tricks.com/almanac/properties/o/overflow-wrap/ */ + overflow-wrap: break-word; + word-wrap: break-word; + hyphens: auto; } #chat-msg-a { - color: white; + color: white; } /*-------------------------------------------------------------- @@ -603,36 +603,36 @@ body { --------------------------------------------------------------*/ .msger-inputarea { - display: flex; - padding: 10px; - background: var(--msger-bg); + display: flex; + padding: 10px; + background: var(--msger-bg); } .msger-inputarea * { - padding: 10px; - border: none; - border-radius: 3px; - font-size: 1em; - color: white; + padding: 10px; + border: none; + border-radius: 3px; + font-size: 1em; + color: white; } .msger-input { - flex: 1; - background: rgb(0, 0, 0); + flex: 1; + background: rgb(0, 0, 0); } #msgerEmojiBtn, #msgerSendBtn { - background: rgb(0, 0, 0); - color: #fff; - transition: background 0.23s; + background: rgb(0, 0, 0); + color: #fff; + transition: background 0.23s; } #msgerEmojiBtn:hover, #msgerSendBtn:hover { - color: rgb(0, 180, 50); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } /*-------------------------------------------------------------- @@ -640,69 +640,69 @@ body { --------------------------------------------------------------*/ #msgerCP { - z-index: 11; - display: none; - cursor: default; - top: var(--msger-top); - left: var(--msger-left); - height: var(--msger-height); - width: var(--msger-width); - background: var(--msger-private-bg); - /* center */ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - /* fade in */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: hidden; + z-index: 11; + display: none; + cursor: default; + top: var(--msger-top); + left: var(--msger-left); + height: var(--msger-height); + width: var(--msger-width); + background: var(--msger-private-bg); + /* center */ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + /* fade in */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: hidden; } #msgerCPList button { - border: none; - font-size: 1rem; - transition: all 0.3s ease-in-out; - background: rgb(0, 0, 0); - color: #fff; - border-radius: 5px; - transition: background 0.23s; + border: none; + font-size: 1rem; + transition: all 0.3s ease-in-out; + background: rgb(0, 0, 0); + color: #fff; + border-radius: 5px; + transition: background 0.23s; } #msgerCPList button:hover { - color: rgb(0, 180, 50); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } -#searchPeerBarName{ - width: 94%; - padding: 10px; - font-size: 1rem; - background-color: transparent; - color: #ffffff; - border: grey 1px solid; +#searchPeerBarName { + width: 94%; + padding: 10px; + font-size: 1rem; + background-color: transparent; + color: #ffffff; + border: grey 1px solid; } .msger-peer-inputarea { - display: flex; - padding: 10px; - background: var(--msger-bg); + display: flex; + padding: 10px; + background: var(--msger-bg); } .msger-peer-inputarea * { - padding: 10px; - border: none; - border-radius: 3px; - font-size: 1em; - color: white; + padding: 10px; + border: none; + border-radius: 3px; + font-size: 1em; + color: white; } /*-------------------------------------------------------------- @@ -710,107 +710,107 @@ body { --------------------------------------------------------------*/ #msgerEmojiPicker { - z-index: 13; - display: none; - box-shadow: var(--box-shadow); - /* center */ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - /* fade in */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: hidden; + z-index: 13; + display: none; + box-shadow: var(--box-shadow); + /* center */ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + /* fade in */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: hidden; } #msgerEmojiHeader { - background: rgb(0, 0, 0); - cursor: move; + background: rgb(0, 0, 0); + cursor: move; } #msgerCloseEmojiBtn { - display: flex; - justify-content: space-between; - padding: 10px; - background: rgb(0, 0, 0); - border: none; - color: #fff; - font-size: 1.2rem; - transition: all 0.3s ease-in-out; + display: flex; + justify-content: space-between; + padding: 10px; + background: rgb(0, 0, 0); + border: none; + color: #fff; + font-size: 1.2rem; + transition: all 0.3s ease-in-out; } #msgerCloseEmojiBtn:hover { - color: rgb(0, 180, 50); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } emoji-picker { - --num-columns: 9; - --emoji-size: 1.5rem; - --background: var(--msger-bg); + --num-columns: 9; + --emoji-size: 1.5rem; + --background: var(--msger-bg); } #myVideo.mirror { - -webkit-transform: rotateY(180deg); - -moz-transform: rotateY(180deg); - transform: rotateY(180deg); + -webkit-transform: rotateY(180deg); + -moz-transform: rotateY(180deg); + transform: rotateY(180deg); } video { - width: 100%; - height: 100%; - object-fit: var(--video-object-fit); - border: 5px solid transparent; + width: 100%; + height: 100%; + object-fit: var(--video-object-fit); + border: 5px solid transparent; } video:fullscreen { - object-fit: contain; + object-fit: contain; } .video { - float: left; - width: 25vw; - height: 50vh; - overflow: hidden; - position: relative; + float: left; + width: 25vw; + height: 50vh; + overflow: hidden; + position: relative; } .video.one { - width: 100vw; - height: 100vh; + width: 100vw; + height: 100vh; } .video.two { - width: 50vw; - height: 100vh; - --video-object-fit: cover; - /* --video-object-fit: contain; */ + width: 50vw; + height: 100vh; + --video-object-fit: cover; + /* --video-object-fit: contain; */ } .video.three { - /* width: 33.33vw; + /* width: 33.33vw; height: 100vh; */ - width: 50vw; - --video-object-fit: cover; + width: 50vw; + --video-object-fit: cover; } .video.four { - width: 50vw; - height: 50vh; - --video-object-fit: cover; + width: 50vw; + height: 50vh; + --video-object-fit: cover; } .video.five { - width: 33.33vw; - height: 50vh; - --video-object-fit: cover; + width: 33.33vw; + height: 50vh; + --video-object-fit: cover; } .video.six { - width: 33.33vw; - height: 50vh; - --video-object-fit: cover; + width: 33.33vw; + height: 50vh; + --video-object-fit: cover; } /*-------------------------------------------------------------- @@ -818,33 +818,33 @@ video:fullscreen { --------------------------------------------------------------*/ @media only screen and (max-width: 720px) { - /* 960px */ - .video { - float: left; - width: 50vw; - height: 25vh; - overflow: hidden; - } - .video.two { - width: 100vw; - height: 50vh; - --video-object-fit: cover; - } - .video.three { - width: 100vw; - height: 33.33vh; - --video-object-fit: cover; - } - .video.five { - width: 50vw; - height: 33.33vh; - --video-object-fit: cover; - } - .video.six { - width: 50vw; - height: 33.33vh; - --video-object-fit: cover; - } + /* 960px */ + .video { + float: left; + width: 50vw; + height: 25vh; + overflow: hidden; + } + .video.two { + width: 100vw; + height: 50vh; + --video-object-fit: cover; + } + .video.three { + width: 100vw; + height: 33.33vh; + --video-object-fit: cover; + } + .video.five { + width: 50vw; + height: 33.33vh; + --video-object-fit: cover; + } + .video.six { + width: 50vw; + height: 33.33vh; + --video-object-fit: cover; + } } /*-------------------------------------------------------------- @@ -852,9 +852,9 @@ video:fullscreen { --------------------------------------------------------------*/ #qrRoomContainer { - display: flex; - justify-content: center; - align-items: center; + display: flex; + justify-content: center; + align-items: center; } /*-------------------------------------------------------------- @@ -862,137 +862,137 @@ video:fullscreen { --------------------------------------------------------------*/ #mySettings { - display: none; - z-index: 15; - min-width: 320px; - /* center */ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - /* gui */ - background-color: rgba(0, 0, 0, 0.7); - border-radius: 5px; - margin: auto; - box-shadow: var(--box-shadow); - padding: 10px; - /* fade in */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: hidden; + display: none; + z-index: 15; + min-width: 320px; + /* center */ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + /* gui */ + background-color: rgba(0, 0, 0, 0.7); + border-radius: 5px; + margin: auto; + box-shadow: var(--box-shadow); + padding: 10px; + /* fade in */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: hidden; } #mySettingsHeader { - cursor: move; + cursor: move; } #mySettings label { - width: 7em; - display: flex; - color: var(--my-settings-label-color); + width: 7em; + display: flex; + color: var(--my-settings-label-color); } #mySettings select { - width: var(--mySettings-select-w); - height: 30px; - color: white; - background-color: #2b2b2b; - border-radius: 5px; + width: var(--mySettings-select-w); + height: 30px; + color: white; + background-color: #2b2b2b; + border-radius: 5px; } #mySettingsCloseBtn { - border: none; - font-size: 1.2rem; - background: transparent; - color: #fff; - transition: background 0.23s; + border: none; + font-size: 1.2rem; + background: transparent; + color: #fff; + transition: background 0.23s; } #mySettingsCloseBtn:hover { - color: rgb(0, 180, 50); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } #myPeerNameSet { - border: 1px solid white; - color: white; - background-color: #2b2b2b; + border: 1px solid white; + color: white; + background-color: #2b2b2b; } #myPeerNameSetBtn, #muteEveryoneBtn, #hideEveryoneBtn, #lockUnlockRoomBtn { - padding: 5px; - border-radius: 5px; - color: white; - background-color: transparent; + padding: 5px; + border-radius: 5px; + color: white; + background-color: transparent; } #myPeerNameSetBtn:hover, #lockUnlockRoomBtn:hover { - color: rgb(0, 180, 50); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } #muteEveryoneBtn:hover, #hideEveryoneBtn:hover { - color: rgb(255, 0, 0); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(255, 0, 0); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } /* Style the tab */ .tab { - overflow: hidden; - border: 1px solid rgb(0, 0, 0); - background-color: rgba(0, 0, 0, 0.7); + overflow: hidden; + border: 1px solid rgb(0, 0, 0); + background-color: rgba(0, 0, 0, 0.7); } /* Style the buttons inside the tab */ .tab button { - background-color: inherit; - float: left; - border: none; - outline: none; - cursor: pointer; - padding: 14px 16px; - transition: 0.3s; - color: white; + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + color: white; } /* Change background color of buttons on hover */ .tab button:hover { - background-color: transparent; - color: rgb(0, 180, 50); - transition: all 0.3s ease-in-out; + background-color: transparent; + color: rgb(0, 180, 50); + transition: all 0.3s ease-in-out; } /* Create an active/current tablink class */ .tab button.active { - background-color: rgba(0, 0, 0, 0.7); + background-color: rgba(0, 0, 0, 0.7); } /* Style the tab content */ .tabcontent { - display: none; - padding: 6px 12px; - border: 1px solid rgb(0, 0, 0); - border-top: none; + display: none; + padding: 6px 12px; + border: 1px solid rgb(0, 0, 0); + border-top: none; } /* on open display devices tab */ #tabDevices { - display: block; + display: block; } /*-------------------------------------------------------------- @@ -1003,17 +1003,17 @@ video:fullscreen { .swal2-title, .swal2-content, .swal2-input { - text-align: center; - color: white !important; - background-color: transparent !important; + text-align: center; + color: white !important; + background-color: transparent !important; } .swal2-file { - color: white !important; - background-color: transparent !important; + color: white !important; + background-color: transparent !important; } .swal2-html-container { - color: rgb(165, 165, 165) !important; - background-color: transparent !important; + color: rgb(165, 165, 165) !important; + background-color: transparent !important; } /* @@ -1022,9 +1022,9 @@ video:fullscreen { } */ .swal2-select { - background-color: black !important; - color: white !important; - border-radius: 6px !important; + background-color: black !important; + color: white !important; + border-radius: 6px !important; } /*-------------------------------------------------------------- @@ -1032,45 +1032,45 @@ video:fullscreen { --------------------------------------------------------------*/ .pulsate { - animation: pulsate 3s ease-out; - animation-iteration-count: infinite; - -webkit-animation: pulsate 3s ease-out; - -webkit-animation-iteration-count: infinite; - opacity: 0.5; + animation: pulsate 3s ease-out; + animation-iteration-count: infinite; + -webkit-animation: pulsate 3s ease-out; + -webkit-animation-iteration-count: infinite; + opacity: 0.5; } @-webkit-keyframes pulsate { - 0% { - opacity: 0.5; - } - 50% { - opacity: 1; - } - 100% { - opacity: 0.5; - } + 0% { + opacity: 0.5; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.5; + } } @keyframes pulsate { - 0% { - opacity: 0.5; - } - 50% { - opacity: 1; - } - 100% { - opacity: 0.5; - } + 0% { + opacity: 0.5; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.5; + } } @-webkit-keyframes pulsate { - 0% { - opacity: 0.5; - } - 50% { - opacity: 1; - } - 100% { - opacity: 0.5; - } + 0% { + opacity: 0.5; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.5; + } } /*-------------------------------------------------------------- @@ -1078,51 +1078,51 @@ video:fullscreen { --------------------------------------------------------------*/ #sendFileDiv { - z-index: 16; - display: none; - /* center */ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - /* gui */ - background-color: rgba(0, 0, 0, 0.7); - border-radius: 5px; - margin: auto; - box-shadow: var(--box-shadow); - padding: 10px; - color: white; - font-size: 1rem; - /* fade in */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: hidden; + z-index: 16; + display: none; + /* center */ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + /* gui */ + background-color: rgba(0, 0, 0, 0.7); + border-radius: 5px; + margin: auto; + box-shadow: var(--box-shadow); + padding: 10px; + color: white; + font-size: 1rem; + /* fade in */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: hidden; } #sendAbortBtn { - padding: 5px; - border-radius: 5px; - font-size: 1rem; - color: white; - background-color: transparent; - transition: background 0.23s; + padding: 5px; + border-radius: 5px; + font-size: 1rem; + color: white; + background-color: transparent; + transition: background 0.23s; } #sendAbortBtn:hover { - color: rgb(255, 0, 0); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(255, 0, 0); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } progress { - width: 0; - min-width: 100%; + width: 0; + min-width: 100%; } /*-------------------------------------------------------------- @@ -1130,40 +1130,40 @@ progress { --------------------------------------------------------------*/ #about { - cursor: default; - /*text-decoration: none;*/ + cursor: default; + /*text-decoration: none;*/ } #about b { - color: rgb(0, 180, 50); + color: rgb(0, 180, 50); } #author a { - color: white; - text-decoration: none; + color: white; + text-decoration: none; } #about img { - cursor: pointer; - border-radius: 10px; + cursor: pointer; + border-radius: 10px; } #author a:hover { - color: rgb(0, 180, 50); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transition: all 0.3s ease-in-out; } /* about Sponsor btn */ #sponsorBtn { - border: none; - width: 170px; - height: 40px; - font-size: 1.2rem; - background: linear-gradient(100deg, #376df9 0, #ff5fa0 75%, #ffc55a 100%); - box-shadow: 0 0 6px 0 rgb(251 255 0 / 82%); - color: #ffffff; - transition: background 0.23s; - cursor: pointer; + border: none; + width: 170px; + height: 40px; + font-size: 1.2rem; + background: linear-gradient(100deg, #376df9 0, #ff5fa0 75%, #ffc55a 100%); + box-shadow: 0 0 6px 0 rgb(251 255 0 / 82%); + color: #ffffff; + transition: background 0.23s; + cursor: pointer; } #sponsorBtn:hover { - font-weight: bold; + font-weight: bold; } /*-------------------------------------------------------------- @@ -1171,8 +1171,8 @@ progress { --------------------------------------------------------------*/ #webRTCSeo { - /* just for SEO */ - display: none; + /* just for SEO */ + display: none; } /* diff --git a/www/css/landing.css b/www/css/landing.css index e2a1fc3a..b73aad9e 100755 --- a/www/css/landing.css +++ b/www/css/landing.css @@ -1,13 +1,13 @@ -@import url("https://fonts.googleapis.com/css?family=Fira+Sans:600|Lato:400&display=swap"); +@import url('https://fonts.googleapis.com/css?family=Fira+Sans:600|Lato:400&display=swap'); html { - line-height: 1.15; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; + line-height: 1.15; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; } body { - margin: 0; + margin: 0; } article, @@ -16,109 +16,109 @@ footer, header, nav, section { - display: block; + display: block; } h1 { - font-size: 2em; - margin: 0.67em 0; + font-size: 2em; + margin: 0.67em 0; } figcaption, figure, main { - display: block; + display: block; } figure { - margin: 1em 40px; + margin: 1em 40px; } hr { - box-sizing: content-box; - height: 0; - overflow: visible; + box-sizing: content-box; + height: 0; + overflow: visible; } pre { - font-family: monospace, monospace; - font-size: 1em; + font-family: monospace, monospace; + font-size: 1em; } a { - background-color: transparent; - -webkit-text-decoration-skip: objects; + background-color: transparent; + -webkit-text-decoration-skip: objects; } abbr[title] { - border-bottom: none; - text-decoration: underline; - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; + border-bottom: none; + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; } b, strong { - font-weight: inherit; + font-weight: inherit; } b, strong { - font-weight: bolder; + font-weight: bolder; } code, kbd, samp { - font-family: monospace, monospace; - font-size: 1em; + font-family: monospace, monospace; + font-size: 1em; } dfn { - font-style: italic; + font-style: italic; } mark { - background-color: #ff0; - color: #000; + background-color: #ff0; + color: #000; } small { - font-size: 80%; + font-size: 80%; } sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } sub { - bottom: -0.25em; + bottom: -0.25em; } sup { - top: -0.5em; + top: -0.5em; } audio, video { - display: inline-block; + display: inline-block; } audio:not([controls]) { - display: none; - height: 0; + display: none; + height: 0; } img { - border-style: none; + border-style: none; } svg:not(:root) { - overflow: hidden; + overflow: hidden; } button, @@ -126,302 +126,301 @@ input, optgroup, select, textarea { - font-family: sans-serif; - font-size: 100%; - line-height: 1.15; - margin: 0; + font-family: sans-serif; + font-size: 100%; + line-height: 1.15; + margin: 0; } button, input { - overflow: visible; + overflow: visible; } button, select { - text-transform: none; + text-transform: none; } button, -html [type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; +html [type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; } button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; +[type='button']::-moz-focus-inner, +[type='reset']::-moz-focus-inner, +[type='submit']::-moz-focus-inner { + border-style: none; + padding: 0; } button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; +[type='button']:-moz-focusring, +[type='reset']:-moz-focusring, +[type='submit']:-moz-focusring { + outline: 1px dotted ButtonText; } fieldset { - padding: 0.35em 0.75em 0.625em; + padding: 0.35em 0.75em 0.625em; } legend { - box-sizing: border-box; - color: inherit; - display: table; - max-width: 100%; - padding: 0; - white-space: normal; + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal; } progress { - display: inline-block; - vertical-align: baseline; + display: inline-block; + vertical-align: baseline; } textarea { - overflow: auto; + overflow: auto; } -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; - padding: 0; +[type='checkbox'], +[type='radio'] { + box-sizing: border-box; + padding: 0; } -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; +[type='number']::-webkit-inner-spin-button, +[type='number']::-webkit-outer-spin-button { + height: auto; } -[type="search"] { - -webkit-appearance: textfield; - outline-offset: -2px; +[type='search'] { + -webkit-appearance: textfield; + outline-offset: -2px; } -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; +[type='search']::-webkit-search-cancel-button, +[type='search']::-webkit-search-decoration { + -webkit-appearance: none; } ::-webkit-file-upload-button { - -webkit-appearance: button; - font: inherit; + -webkit-appearance: button; + font: inherit; } details, menu { - display: block; + display: block; } summary { - display: list-item; + display: list-item; } canvas { - display: inline-block; + display: inline-block; } template { - display: none; + display: none; } [hidden] { - display: none; + display: none; } @media (min-width: 641px) { - .has-animations [class*="reveal-"] { - opacity: 0; - will-change: opacity, transform; - } + .has-animations [class*='reveal-'] { + opacity: 0; + will-change: opacity, transform; + } - .has-animations .reveal-from-top { - transform: translateY(-10px); - } + .has-animations .reveal-from-top { + transform: translateY(-10px); + } - .has-animations .reveal-from-bottom { - transform: translateY(10px); - } + .has-animations .reveal-from-bottom { + transform: translateY(10px); + } - .has-animations .reveal-from-left { - transform: translateX(-10px); - } + .has-animations .reveal-from-left { + transform: translateX(-10px); + } - .has-animations .reveal-from-right { - transform: translateX(10px); - } + .has-animations .reveal-from-right { + transform: translateX(10px); + } - .has-animations .reveal-scale-up { - transform: scale(0.95); - } + .has-animations .reveal-scale-up { + transform: scale(0.95); + } - .has-animations .reveal-scale-down { - transform: scale(1.05); - } + .has-animations .reveal-scale-down { + transform: scale(1.05); + } - .has-animations .reveal-rotate-from-left { - transform: perspective(1000px) rotateY(-45deg); - } + .has-animations .reveal-rotate-from-left { + transform: perspective(1000px) rotateY(-45deg); + } - .has-animations .reveal-rotate-from-right { - transform: perspective(1000px) rotateY(45deg); - } + .has-animations .reveal-rotate-from-right { + transform: perspective(1000px) rotateY(45deg); + } - .has-animations.is-loaded [class*="reveal-"] { - transition: opacity 1s cubic-bezier(0.39, 0.575, 0.565, 1), - transform 1s cubic-bezier(0.39, 0.575, 0.565, 1); - } + .has-animations.is-loaded [class*='reveal-'] { + transition: opacity 1s cubic-bezier(0.39, 0.575, 0.565, 1), transform 1s cubic-bezier(0.39, 0.575, 0.565, 1); + } - .has-animations.is-loaded [class*="reveal-"].is-revealed { - opacity: 1; - transform: translate(0); - } + .has-animations.is-loaded [class*='reveal-'].is-revealed { + opacity: 1; + transform: translate(0); + } } html { - box-sizing: border-box; + box-sizing: border-box; } *, *:before, *:after { - box-sizing: inherit; + box-sizing: inherit; } body { - background: #16171b; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; + background: #16171b; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; } hr { - border: 0; - display: block; - height: 1px; - background: #292b32; - margin-top: 24px; - margin-bottom: 24px; + border: 0; + display: block; + height: 1px; + background: #292b32; + margin-top: 24px; + margin-bottom: 24px; } ul, ol { - margin-top: 0; - padding-left: 24px; + margin-top: 0; + padding-left: 24px; } ul:not(:last-child), ol:not(:last-child) { - margin-bottom: 24px; + margin-bottom: 24px; } ul { - list-style: disc; + list-style: disc; } ol { - list-style: decimal; + list-style: decimal; } li:not(:last-child) { - margin-bottom: 12px; + margin-bottom: 12px; } li > ul, li > ol { - margin-top: 12px; - margin-bottom: 0; + margin-top: 12px; + margin-bottom: 0; } dl { - margin-top: 0; - margin-bottom: 24px; + margin-top: 0; + margin-bottom: 24px; } dt { - font-weight: 700; + font-weight: 700; } dd { - margin-left: 24px; - margin-bottom: 24px; + margin-left: 24px; + margin-bottom: 24px; } img { - border-radius: 2px; + border-radius: 2px; } img, svg, video { - display: block; - height: auto; - max-width: 100%; + display: block; + height: auto; + max-width: 100%; } figure { - margin: 48px 0; + margin: 48px 0; } figcaption { - padding: 8px 0; + padding: 8px 0; } table { - font-size: 16px; - line-height: 24px; - letter-spacing: -0.1px; - border-collapse: collapse; - margin-bottom: 24px; - width: 100%; + font-size: 16px; + line-height: 24px; + letter-spacing: -0.1px; + border-collapse: collapse; + margin-bottom: 24px; + width: 100%; } tr { - border-bottom: 1px solid #292b32; + border-bottom: 1px solid #292b32; } th { - font-weight: 700; - text-align: left; + font-weight: 700; + text-align: left; } th, td { - padding: 8px 16px; + padding: 8px 16px; } th:first-child, td:first-child { - padding-left: 0; + padding-left: 0; } th:last-child, td:last-child { - padding-right: 0; + padding-right: 0; } .invert-color hr { - display: block; - height: 1px; - background: #e5e9ff; + display: block; + height: 1px; + background: #e5e9ff; } .invert-color tr { - border-bottom: 1px solid #e5e9ff; + border-bottom: 1px solid #e5e9ff; } html { - font-size: 20px; - line-height: 32px; - letter-spacing: -0.1px; + font-size: 20px; + line-height: 32px; + letter-spacing: -0.1px; } body { - color: #959cb1; - font-size: 1rem; + color: #959cb1; + font-size: 1rem; } body, @@ -429,8 +428,8 @@ button, input, select, textarea { - font-family: "Lato", sans-serif; - font-weight: 400; + font-family: 'Lato', sans-serif; + font-weight: 400; } h1, @@ -445,116 +444,116 @@ h6, .h4, .h5, .h6 { - font-family: "Fira Sans", sans-serif; - font-weight: 600; - clear: both; - color: #f9faff; - word-wrap: break-word; - overflow-wrap: break-word; + font-family: 'Fira Sans', sans-serif; + font-weight: 600; + clear: both; + color: #f9faff; + word-wrap: break-word; + overflow-wrap: break-word; } h1, .h1 { - font-size: 38px; - line-height: 48px; + font-size: 38px; + line-height: 48px; } h2, .h2 { - font-size: 32px; - line-height: 42px; + font-size: 32px; + line-height: 42px; } h3, .h3 { - font-size: 24px; - line-height: 34px; - letter-spacing: -0.1px; + font-size: 24px; + line-height: 34px; + letter-spacing: -0.1px; } h4, .h4 { - font-size: 24px; - line-height: 34px; - letter-spacing: -0.1px; + font-size: 24px; + line-height: 34px; + letter-spacing: -0.1px; } h5, .h5 { - font-size: 20px; - line-height: 32px; - letter-spacing: -0.1px; + font-size: 20px; + line-height: 32px; + letter-spacing: -0.1px; } h6, .h6, small, .text-sm { - font-size: 18px; - line-height: 30px; - letter-spacing: -0.1px; + font-size: 18px; + line-height: 30px; + letter-spacing: -0.1px; } .text-xs { - font-size: 16px; - line-height: 24px; - letter-spacing: -0.1px; + font-size: 16px; + line-height: 24px; + letter-spacing: -0.1px; } .text-xxs { - font-size: 14px; - line-height: 22px; + font-size: 14px; + line-height: 22px; } figcaption { - font-size: 14px; - line-height: 22px; + font-size: 14px; + line-height: 22px; } a:not(.button) { - color: inherit; + color: inherit; } a:not(.button):hover, a:not(.button):active { - color: #f9faff; - outline: 0; + color: #f9faff; + outline: 0; } a.button-link { - color: #6a6f82; + color: #6a6f82; } a.button-link:hover, a.button-link:active { - color: #959cb1; + color: #959cb1; } a.func-link { - color: #376df9; + color: #376df9; } a.func-link:hover, a.func-link:active { - color: #6991fa; + color: #6991fa; } h1, .h1 { - margin-top: 48px; - margin-bottom: 32px; + margin-top: 48px; + margin-bottom: 32px; } h2, .h2 { - margin-top: 48px; - margin-bottom: 32px; + margin-top: 48px; + margin-bottom: 32px; } h3, .h3 { - margin-top: 36px; - margin-bottom: 24px; + margin-top: 36px; + margin-bottom: 24px; } h4, @@ -563,49 +562,49 @@ h6, .h4, .h5, .h6 { - margin-top: 24px; - margin-bottom: 24px; + margin-top: 24px; + margin-bottom: 24px; } p { - margin-top: 0; - margin-bottom: 24px; + margin-top: 0; + margin-bottom: 24px; } dfn, cite, em, i { - font-style: italic; + font-style: italic; } blockquote { - font-size: 20px; - line-height: 32px; - letter-spacing: -0.1px; - margin-top: 24px; - margin-bottom: 24px; - margin-left: 24px; + font-size: 20px; + line-height: 32px; + letter-spacing: -0.1px; + margin-top: 24px; + margin-bottom: 24px; + margin-left: 24px; } blockquote::before { - content: "\201C"; + content: '\201C'; } blockquote::after { - content: "\201D"; + content: '\201D'; } blockquote p { - display: inline; + display: inline; } address { - border-width: 1px 0; - border-style: solid; - border-color: #292b32; - padding: 24px 0; - margin: 0 0 24px; + border-width: 1px 0; + border-style: solid; + border-color: #292b32; + padding: 24px 0; + margin: 0 0 24px; } pre, @@ -621,7 +620,7 @@ pre .h3, pre .h4, pre .h5, pre .h6 { - font-family: "Courier 10 Pitch", Courier, monospace; + font-family: 'Courier 10 Pitch', Courier, monospace; } pre, @@ -629,64 +628,64 @@ code, kbd, tt, var { - background: #0d0d10; + background: #0d0d10; } pre { - font-size: 16px; - line-height: 24px; - letter-spacing: -0.1px; - max-width: 100%; - overflow: auto; - padding: 24px 24px; - margin-top: 24px; - margin-bottom: 24px; + font-size: 16px; + line-height: 24px; + letter-spacing: -0.1px; + max-width: 100%; + overflow: auto; + padding: 24px 24px; + margin-top: 24px; + margin-bottom: 24px; } code, kbd, tt, var { - font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; - font-size: 16px; - line-height: 24px; - letter-spacing: -0.1px; - padding: 2px 4px; + font-family: Monaco, Consolas, 'Andale Mono', 'DejaVu Sans Mono', monospace; + font-size: 16px; + line-height: 24px; + letter-spacing: -0.1px; + padding: 2px 4px; } abbr, acronym { - cursor: help; + cursor: help; } mark, ins { - text-decoration: none; + text-decoration: none; } b, strong { - font-weight: 700; + font-weight: 700; } .invert-color { - color: #6a6f82; + color: #6a6f82; } .invert-color a:not(.button):hover, .invert-color a:not(.button):active { - color: #1c1d22; - outline: 0; + color: #1c1d22; + outline: 0; } .invert-color a.button-link:hover, .invert-color a.button-link:active { - color: #376df9; + color: #376df9; } .invert-color a.func-link:hover, .invert-color a.func-link:active { - color: #6991fa; + color: #6991fa; } .invert-color h1, @@ -701,11 +700,11 @@ strong { .invert-color .h4, .invert-color .h5, .invert-color .h6 { - color: #16171b; + color: #16171b; } .invert-color address { - border-color: #e5e9ff; + border-color: #e5e9ff; } .invert-color pre, @@ -713,303 +712,303 @@ strong { .invert-color kbd, .invert-color tt, .invert-color var { - background: #0d0d10; + background: #0d0d10; } @media (max-width: 640px) { - .h1-mobile { - font-size: 38px; - line-height: 48px; - } + .h1-mobile { + font-size: 38px; + line-height: 48px; + } - .h2-mobile { - font-size: 32px; - line-height: 42px; - } + .h2-mobile { + font-size: 32px; + line-height: 42px; + } - .h3-mobile { - font-size: 24px; - line-height: 34px; - letter-spacing: -0.1px; - } + .h3-mobile { + font-size: 24px; + line-height: 34px; + letter-spacing: -0.1px; + } - .h4-mobile { - font-size: 24px; - line-height: 34px; - letter-spacing: -0.1px; - } + .h4-mobile { + font-size: 24px; + line-height: 34px; + letter-spacing: -0.1px; + } - .h5-mobile { - font-size: 20px; - line-height: 32px; - letter-spacing: -0.1px; - } + .h5-mobile { + font-size: 20px; + line-height: 32px; + letter-spacing: -0.1px; + } - .h6-mobile { - font-size: 18px; - line-height: 30px; - letter-spacing: -0.1px; - } + .h6-mobile { + font-size: 18px; + line-height: 30px; + letter-spacing: -0.1px; + } } @media (min-width: 641px) { - h1, - .h1 { - font-size: 44px; - line-height: 54px; - } + h1, + .h1 { + font-size: 44px; + line-height: 54px; + } - h2, - .h2 { - font-size: 38px; - line-height: 48px; - } + h2, + .h2 { + font-size: 38px; + line-height: 48px; + } - h3, - .h3 { - font-size: 32px; - line-height: 42px; - } + h3, + .h3 { + font-size: 32px; + line-height: 42px; + } } .container, .container-sm, .container-xs { - width: 100%; - margin: 0 auto; - padding-left: 16px; - padding-right: 16px; + width: 100%; + margin: 0 auto; + padding-left: 16px; + padding-right: 16px; } @media (min-width: 481px) { - .container, - .container-sm, - .container-xs { - padding-left: 24px; - padding-right: 24px; - } + .container, + .container-sm, + .container-xs { + padding-left: 24px; + padding-right: 24px; + } } .container { - max-width: 1128px; + max-width: 1128px; } .container-sm { - max-width: 944px; + max-width: 944px; } .container-xs { - max-width: 668px; + max-width: 668px; } -[class*="container"] [class*="container"] { - padding-left: 0; - padding-right: 0; +[class*='container'] [class*='container'] { + padding-left: 0; + padding-right: 0; } -[class*="container"] .container-sm { - max-width: 896px; +[class*='container'] .container-sm { + max-width: 896px; } -[class*="container"] .container-xs { - max-width: 620px; +[class*='container'] .container-xs { + max-width: 620px; } .button { - display: inline-flex; - font-size: 14px; - line-height: 22px; - font-weight: 700; - padding: 12px 31px; - height: 48px; - text-decoration: none !important; - text-transform: uppercase; - color: #6a6f82; - background-color: #f9faff; - border-width: 1px; - border-style: solid; - border-color: rgba(0, 0, 0, 0); - border-radius: 2px; - cursor: pointer; - justify-content: center; - text-align: center; - letter-spacing: inherit; - white-space: nowrap; - transition: background 0.15s ease; + display: inline-flex; + font-size: 14px; + line-height: 22px; + font-weight: 700; + padding: 12px 31px; + height: 48px; + text-decoration: none !important; + text-transform: uppercase; + color: #6a6f82; + background-color: #f9faff; + border-width: 1px; + border-style: solid; + border-color: rgba(0, 0, 0, 0); + border-radius: 2px; + cursor: pointer; + justify-content: center; + text-align: center; + letter-spacing: inherit; + white-space: nowrap; + transition: background 0.15s ease; } .button:active { - outline: 0; + outline: 0; } .button:hover { - background-color: #fff; + background-color: #fff; } .button.is-loading { - position: relative; - color: transparent !important; - pointer-events: none; + position: relative; + color: transparent !important; + pointer-events: none; } .button.is-loading::after { - content: ""; - display: block; - position: absolute; - width: 22px; - height: 22px; - margin-left: -11px; - margin-top: -11px; - top: 50%; - left: 50%; - border: 2px solid #6a6f82; - border-radius: 50%; - border-right-color: transparent !important; - border-top-color: transparent !important; - z-index: 1; - -webkit-animation: button-loading 0.6s infinite linear; - animation: button-loading 0.6s infinite linear; + content: ''; + display: block; + position: absolute; + width: 22px; + height: 22px; + margin-left: -11px; + margin-top: -11px; + top: 50%; + left: 50%; + border: 2px solid #6a6f82; + border-radius: 50%; + border-right-color: transparent !important; + border-top-color: transparent !important; + z-index: 1; + -webkit-animation: button-loading 0.6s infinite linear; + animation: button-loading 0.6s infinite linear; } .button[disabled] { - cursor: not-allowed; - color: #16171b; - background-color: #292b32 !important; + cursor: not-allowed; + color: #16171b; + background-color: #292b32 !important; } .button[disabled].is-loading::after { - border-color: #16171b; + border-color: #16171b; } .button-sm { - padding: 6px 23px; - height: 36px; + padding: 6px 23px; + height: 36px; } .button-dark { - color: #f9faff; - background-color: #292b32; + color: #f9faff; + background-color: #292b32; } .button-dark:hover { - background-color: #30323a; + background-color: #30323a; } .button-dark.is-loading::after { - border-color: #f9faff; + border-color: #f9faff; } .button-primary { - color: #f9faff; - background-color: #376df9; + color: #f9faff; + background-color: #376df9; } .button-primary:hover { - background-color: #4678f9; + background-color: #4678f9; } .button-primary.is-loading::after { - border-color: #f9faff; + border-color: #f9faff; } .button-secondary { - color: #f9faff; - background-color: #ff5fa0; + color: #f9faff; + background-color: #ff5fa0; } .button-secondary:hover { - background-color: #ff6ea9; + background-color: #ff6ea9; } .button-secondary.is-loading::after { - border-color: #f9faff; + border-color: #f9faff; } .button-block { - display: flex; - width: 100%; + display: flex; + width: 100%; } .button-group { - display: flex; - flex-wrap: wrap; - align-items: center; - margin-right: -8px; - margin-left: -8px; - margin-top: -8px; + display: flex; + flex-wrap: wrap; + align-items: center; + margin-right: -8px; + margin-left: -8px; + margin-top: -8px; } .button-group:last-of-type { - margin-bottom: -8px; + margin-bottom: -8px; } .button-group:not(:last-of-type) { - margin-bottom: 8px; + margin-bottom: 8px; } -.button-group > [class*="button"] { - margin: 8px; +.button-group > [class*='button'] { + margin: 8px; } @media (max-width: 640px) { - .button-wide-mobile { - width: 100%; - max-width: 280px; - } + .button-wide-mobile { + width: 100%; + max-width: 280px; + } } @-webkit-keyframes button-loading { - 0% { - transform: rotate(0); - } - 100% { - transform: rotate(360deg); - } + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(360deg); + } } @keyframes button-loading { - 0% { - transform: rotate(0); - } - 100% { - transform: rotate(360deg); - } + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(360deg); + } } fieldset { - padding: 0; - margin: 0; - border: 0; + padding: 0; + margin: 0; + border: 0; } .form-label, .form-switch { - color: #6a6f82; - font-weight: 500; + color: #6a6f82; + font-weight: 500; } .form-label { - font-size: 14px; - line-height: 22px; + font-size: 14px; + line-height: 22px; } .form-input, .form-select, .form-checkbox input, .form-radio input { - -moz-appearance: none; - -webkit-appearance: none; - background-color: #f9faff; - border-width: 1px; - border-style: solid; - border-color: #16171b; + -moz-appearance: none; + -webkit-appearance: none; + background-color: #f9faff; + border-width: 1px; + border-style: solid; + border-color: #16171b; } .form-input:hover, .form-select:hover, .form-checkbox input:hover, .form-radio input:hover { - border-color: #6a6f82; + border-color: #6a6f82; } .form-input:active, @@ -1020,271 +1019,271 @@ fieldset { .form-checkbox input:focus, .form-radio input:active, .form-radio input:focus { - outline: none; - border-color: #376df9; + outline: none; + border-color: #376df9; } .form-input[disabled], .form-select[disabled], .form-checkbox input[disabled], .form-radio input[disabled] { - cursor: not-allowed; - background-color: #292b32; - border-color: #1c1d22; + cursor: not-allowed; + background-color: #292b32; + border-color: #1c1d22; } .form-input.form-error, .form-select.form-error, .form-checkbox input.form-error, .form-radio input.form-error { - border-color: #ff5fa0; + border-color: #ff5fa0; } .form-input.form-warning, .form-select.form-warning, .form-checkbox input.form-warning, .form-radio input.form-warning { - border-color: #ffc55a; + border-color: #ffc55a; } .form-input.form-success, .form-select.form-success, .form-checkbox input.form-success, .form-radio input.form-success { - border-color: #1ec198; + border-color: #1ec198; } .form-input, .form-select { - display: block; - font-size: 16px; - line-height: 24px; - letter-spacing: -0.1px; - padding: 11px 15px; - height: 48px; - border-radius: 0; - color: #16171b; - box-shadow: none; - max-width: 100%; - width: 100%; + display: block; + font-size: 16px; + line-height: 24px; + letter-spacing: -0.1px; + padding: 11px 15px; + height: 48px; + border-radius: 0; + color: #16171b; + box-shadow: none; + max-width: 100%; + width: 100%; } .form-input::-webkit-input-placeholder { - color: #959cb1; + color: #959cb1; } .form-input::-moz-placeholder { - color: #959cb1; + color: #959cb1; } .form-input:-ms-input-placeholder { - color: #959cb1; + color: #959cb1; } .form-input::-ms-input-placeholder { - color: #959cb1; + color: #959cb1; } .form-input::placeholder { - color: #959cb1; + color: #959cb1; } .form-input::-ms-input-placeholder { - color: #959cb1; + color: #959cb1; } textarea.form-input { - height: auto; - resize: vertical; + height: auto; + resize: vertical; } .form-select { - padding-right: 46px; - background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%2011.4L2.6%206%204%204.6l4%204%204-4L13.4%206%208%2011.4z%22%20fill%3D%22%23F9FAFF%22%20fill-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E"); - background-position: right 15px center; - background-repeat: no-repeat; - background-size: 16px 16px; + padding-right: 46px; + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%2011.4L2.6%206%204%204.6l4%204%204-4L13.4%206%208%2011.4z%22%20fill%3D%22%23F9FAFF%22%20fill-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E'); + background-position: right 15px center; + background-repeat: no-repeat; + background-size: 16px 16px; } .form-select-sm { - padding-right: 38px; - background-position: right 11px center; + padding-right: 38px; + background-position: right 11px center; } .form-select-sm, .form-input-sm { - padding: 5px 11px; - height: 36px; + padding: 5px 11px; + height: 36px; } .has-icon-left, .has-icon-right { - position: relative; + position: relative; } .has-icon-left svg, .has-icon-right svg { - pointer-events: none; - position: absolute; - top: 50%; - transform: translateY(-50%); + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); } .has-icon-left .form-input { - padding-left: 46px; + padding-left: 46px; } .has-icon-left .form-input + svg { - left: 15px; + left: 15px; } .has-icon-left .form-input-sm { - padding-left: 38px; + padding-left: 38px; } .has-icon-left .form-input-sm + svg { - left: 11px; + left: 11px; } .has-icon-right .form-input { - padding-right: 46px; + padding-right: 46px; } .has-icon-right .form-input + svg { - right: 15px; + right: 15px; } .has-icon-right .form-input-sm { - padding-right: 38px; + padding-right: 38px; } .has-icon-right .form-input-sm + svg { - right: 11px; + right: 11px; } .form-checkbox, .form-radio, .form-switch { - font-size: 16px; - line-height: 24px; - letter-spacing: -0.1px; - cursor: pointer; + font-size: 16px; + line-height: 24px; + letter-spacing: -0.1px; + cursor: pointer; } .form-checkbox, .form-radio { - color: #959cb1; + color: #959cb1; } .form-checkbox, .form-radio { - position: relative; - padding-left: 24px; + position: relative; + padding-left: 24px; } .form-checkbox input, .form-radio input { - position: absolute; - left: 0; - top: 3px; - width: 16px; - height: 16px; - cursor: pointer; + position: absolute; + left: 0; + top: 3px; + width: 16px; + height: 16px; + cursor: pointer; } .form-checkbox input:checked, .form-radio input:checked { - background-color: #376df9 !important; - border-color: #376df9 !important; - background-position: 50%; + background-color: #376df9 !important; + border-color: #376df9 !important; + background-position: 50%; } .form-checkbox input { - border-radius: 2px; + border-radius: 2px; } .form-checkbox input:checked { - background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+IDxwYXRoIGQ9Ik0xMS40IDVMMTAgMy42bC00IDQtMi0yTDIuNiA3IDYgMTAuNHoiIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==); + background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+IDxwYXRoIGQ9Ik0xMS40IDVMMTAgMy42bC00IDQtMi0yTDIuNiA3IDYgMTAuNHoiIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==); } .form-radio input { - border-radius: 50%; + border-radius: 50%; } .form-radio input:checked { - background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBmaWxsPSIjRkZGIiBjeD0iNyIgY3k9IjciIHI9IjMiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==); + background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBmaWxsPSIjRkZGIiBjeD0iNyIgY3k9IjciIHI9IjMiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==); } .form-switch { - display: inline-flex; - align-items: center; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + display: inline-flex; + align-items: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .form-switch input { - clip: rect(0, 0, 0, 0); - height: 1px; - margin: -1px; - overflow: hidden; - position: absolute; - width: 1px; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + width: 1px; } .form-switch .form-switch-icon { - display: block; - position: relative; - min-width: 60px; - width: 60px; - height: 32px; - border-radius: 16px; - background: #292b32; + display: block; + position: relative; + min-width: 60px; + width: 60px; + height: 32px; + border-radius: 16px; + background: #292b32; } .form-switch .form-switch-icon::before { - content: ""; - display: block; - position: absolute; - top: 2px; - left: 2px; - width: 28px; - height: 28px; - border-radius: 14px; - background: #f9faff; - transition: all 0.15s ease-out; + content: ''; + display: block; + position: absolute; + top: 2px; + left: 2px; + width: 28px; + height: 28px; + border-radius: 14px; + background: #f9faff; + transition: all 0.15s ease-out; } .form-switch input:checked + .form-switch-icon { - background: #376df9; + background: #376df9; } .form-switch input:checked + .form-switch-icon::before { - left: 30px; + left: 30px; } .form-switch > span:not(.form-switch-icon) { - order: -1; - margin-right: 12px; + order: -1; + margin-right: 12px; } .form-switch > span:not(.form-switch-icon):last-child { - order: initial; - margin-left: 12px; - margin-right: 0; + order: initial; + margin-left: 12px; + margin-right: 0; } .invert-color .form-label, .invert-color .form-switch { - color: #292b32; + color: #292b32; } .invert-color .form-input, .invert-color .form-select, .invert-color .form-checkbox input, .invert-color .form-radio input { - border-color: #e5e9ff; + border-color: #e5e9ff; } .invert-color .form-input:active, @@ -1295,2215 +1294,2193 @@ textarea.form-input { .invert-color .form-checkbox input:focus, .invert-color .form-radio input:active, .invert-color .form-radio input:focus { - border-color: #376df9; + border-color: #376df9; } .invert-color .form-input[disabled], .invert-color .form-select[disabled], .invert-color .form-checkbox input[disabled], .invert-color .form-radio input[disabled] { - background-color: #e5e9ff; + background-color: #e5e9ff; } .invert-color .form-input, .invert-color .form-select { - color: #292b32; + color: #292b32; } .invert-color .form-select { - background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%2011.4L2.6%206%204%204.6l4%204%204-4L13.4%206%208%2011.4z%22%20fill%3D%22%23292B32%22%20fill-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E"); + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%2011.4L2.6%206%204%204.6l4%204%204-4L13.4%206%208%2011.4z%22%20fill%3D%22%23292B32%22%20fill-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E'); } .invert-color .form-checkbox, .invert-color .form-radio { - color: #292b32; + color: #292b32; } .invert-color .form-checkbox input:checked, .invert-color .form-radio input:checked { - /*background-color: !important;*/ - /*border-color: !important*/ + /*background-color: !important;*/ + /*border-color: !important*/ } .form-group { - display: flex; + display: flex; } .form-group .form-input { - flex-grow: 1; - flex-shrink: 1; - margin-right: 12px; -} - -.form-group .button { - padding-left: 24px; - padding-right: 24px; - flex-shrink: 0; -} - -.form-hint { - font-size: 14px; - line-height: 22px; - margin-top: 8px; -} - -@media (max-width: 640px) { - .form-group-desktop .form-input { - margin-bottom: 12px; - } - - .form-group-desktop .button { - width: 100%; - } -} - -@media (min-width: 641px) { - .form-group-desktop { - display: flex; - } - - .form-group-desktop .form-input { flex-grow: 1; flex-shrink: 1; margin-right: 12px; - } +} - .form-group-desktop .button { +.form-group .button { padding-left: 24px; padding-right: 24px; flex-shrink: 0; - } +} + +.form-hint { + font-size: 14px; + line-height: 22px; + margin-top: 8px; +} + +@media (max-width: 640px) { + .form-group-desktop .form-input { + margin-bottom: 12px; + } + + .form-group-desktop .button { + width: 100%; + } +} + +@media (min-width: 641px) { + .form-group-desktop { + display: flex; + } + + .form-group-desktop .form-input { + flex-grow: 1; + flex-shrink: 1; + margin-right: 12px; + } + + .form-group-desktop .button { + padding-left: 24px; + padding-right: 24px; + flex-shrink: 0; + } } .header-nav-toggle { - background: transparent; - border: 0; - outline: 0; - padding: 0; - cursor: pointer; + background: transparent; + border: 0; + outline: 0; + padding: 0; + cursor: pointer; } .hamburger, .hamburger-inner { - display: block; - pointer-events: none; + display: block; + pointer-events: none; } .hamburger { - position: relative; - width: 24px; - height: 24px; + position: relative; + width: 24px; + height: 24px; } .hamburger-inner, .hamburger-inner::before, .hamburger-inner::after { - width: 24px; - height: 2px; - position: absolute; - background: #959cb1; + width: 24px; + height: 2px; + position: absolute; + background: #959cb1; } .invert-color .hamburger-inner, .invert-color .hamburger-inner::before, .invert-color .hamburger-inner::after { - background: #1c1d22; + background: #1c1d22; } .hamburger-inner { - top: 50%; - margin-top: -1px; - transition-duration: 0.22s; - transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + top: 50%; + margin-top: -1px; + transition-duration: 0.22s; + transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } .hamburger-inner::before, .hamburger-inner::after { - content: ""; - display: block; + content: ''; + display: block; } .hamburger-inner::before { - top: -7px; - transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in; + top: -7px; + transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in; } .hamburger-inner::after { - bottom: -7px; - transition: bottom 0.1s 0.25s ease-in, - transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19), - width 0.1s 0.25s ease-in; + bottom: -7px; + transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19), + width 0.1s 0.25s ease-in; } .off-nav-is-active .hamburger-inner { - transform: rotate(225deg); - transition-delay: 0.12s; - transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + transform: rotate(225deg); + transition-delay: 0.12s; + transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } .off-nav-is-active .hamburger-inner::before { - top: 0; - opacity: 0; - transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out; + top: 0; + opacity: 0; + transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out; } .off-nav-is-active .hamburger-inner::after { - width: 24px; - bottom: 0; - transform: rotate(-90deg); - transition: bottom 0.1s ease-out, - transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1), - width 0.1s ease-out; + width: 24px; + bottom: 0; + transform: rotate(-90deg); + transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1), width 0.1s ease-out; } .accordion li { - position: relative; + position: relative; } .accordion li::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #292b32; + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #292b32; } .accordion li:last-of-type { - position: relative; + position: relative; } .accordion li:last-of-type::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #292b32; + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #292b32; } .invert-color .accordion li { - position: relative; + position: relative; } .invert-color .accordion li::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #e5e9ff; + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #e5e9ff; } .invert-color .accordion li:last-of-type { - position: relative; + position: relative; } .invert-color .accordion li:last-of-type::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #e5e9ff; + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #e5e9ff; } .accordion-header { - display: flex; - justify-content: space-between; - align-items: center; - padding-top: 24px; - padding-bottom: 24px; - cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + padding-top: 24px; + padding-bottom: 24px; + cursor: pointer; } .accordion-header span { - width: calc(100% - (16px * 2)); + width: calc(100% - (16px * 2)); } .accordion-content { - max-height: 0; - opacity: 0; - overflow: hidden; - transition: max-height 0.15s ease-in-out, opacity 0.15s; + max-height: 0; + opacity: 0; + overflow: hidden; + transition: max-height 0.15s ease-in-out, opacity 0.15s; } .is-active .accordion-content { - opacity: 1; + opacity: 1; } .accordion-content p:last-child { - margin-bottom: 24px; + margin-bottom: 24px; } .accordion-icon { - position: relative; - width: 16px; - height: 16px; + position: relative; + width: 16px; + height: 16px; } .accordion-icon::before, .accordion-icon::after { - content: ""; - position: absolute; - background: #376df9; - transition: transform 0.25s ease-out; + content: ''; + position: absolute; + background: #376df9; + transition: transform 0.25s ease-out; } .accordion-icon::before { - top: 0; - left: 50%; - width: 2px; - height: 100%; - margin-left: -1px; + top: 0; + left: 50%; + width: 2px; + height: 100%; + margin-left: -1px; } .accordion-icon::after { - top: 50%; - left: 0; - width: 100%; - height: 2px; - margin-top: -1px; + top: 50%; + left: 0; + width: 100%; + height: 2px; + margin-top: -1px; } .is-active .accordion-icon { - cursor: pointer; + cursor: pointer; } .is-active .accordion-icon::before { - transform: rotate(90deg); + transform: rotate(90deg); } .is-active .accordion-icon::after { - transform: rotate(180deg); + transform: rotate(180deg); } .modal, .modal::before { - bottom: 0; - left: 0; - right: 0; - top: 0; + bottom: 0; + left: 0; + right: 0; + top: 0; } .modal { - display: none; - align-items: center; - flex-direction: column; - justify-content: center; - overflow: hidden; - position: fixed; - z-index: 40; + display: none; + align-items: center; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; } .modal.modal-video .modal-inner { - padding: 0; - max-width: 1024px; + padding: 0; + max-width: 1024px; } .modal::before, .modal .modal-inner { - display: none; + display: none; } .modal::before { - content: ""; - position: absolute; - background-color: rgba(22, 23, 27, 0.88); + content: ''; + position: absolute; + background-color: rgba(22, 23, 27, 0.88); } .modal.is-active { - display: flex; + display: flex; } .modal.is-active::before, .modal.is-active .modal-inner { - display: block; + display: block; } .modal.is-active .modal-inner { - -webkit-animation: slideUpInModal 0.15s ease-in-out both; - animation: slideUpInModal 0.15s ease-in-out both; + -webkit-animation: slideUpInModal 0.15s ease-in-out both; + animation: slideUpInModal 0.15s ease-in-out both; } .modal.is-active::before { - -webkit-animation: slideUpInModalBg 0.15s ease-in-out both; - animation: slideUpInModalBg 0.15s ease-in-out both; + -webkit-animation: slideUpInModalBg 0.15s ease-in-out both; + animation: slideUpInModalBg 0.15s ease-in-out both; } .modal-inner { - max-height: calc(100vh - 16px * 2); - overflow: auto; - position: relative; - width: calc(100% - (16px * 2)); - max-width: 480px; - margin-left: 16px; - margin-right: 16px; - background: #292b32; + max-height: calc(100vh - 16px * 2); + overflow: auto; + position: relative; + width: calc(100% - (16px * 2)); + max-width: 480px; + margin-left: 16px; + margin-right: 16px; + background: #292b32; } .modal-content { - padding: 48px 16px; + padding: 48px 16px; } .modal-close { - background: transparent; - border: 0; - outline: 0; - padding: 0; - cursor: pointer; - position: absolute; - right: 24px; - top: 24px; - width: 16px; - height: 16px; + background: transparent; + border: 0; + outline: 0; + padding: 0; + cursor: pointer; + position: absolute; + right: 24px; + top: 24px; + width: 16px; + height: 16px; } .modal-close::before, .modal-close::after { - content: ""; - display: block; - position: absolute; - top: 50%; - left: 50%; - margin-top: -1px; - margin-left: -8px; - width: 16px; - height: 2px; - background: #6a6f82; + content: ''; + display: block; + position: absolute; + top: 50%; + left: 50%; + margin-top: -1px; + margin-left: -8px; + width: 16px; + height: 2px; + background: #6a6f82; } .modal-close::before { - transform: rotate(225deg); + transform: rotate(225deg); } .modal-close::after { - transform: rotate(-45deg); + transform: rotate(-45deg); } .modal-close:hover::before, .modal-close:hover::after { - background: #959cb1; + background: #959cb1; } @media (min-width: 641px) { - .modal-inner { - margin: 0 auto; - max-height: calc(100vh - 48px * 2); - } + .modal-inner { + margin: 0 auto; + max-height: calc(100vh - 48px * 2); + } - .modal-content { - padding-top: 48px; - padding-bottom: 48px; - padding-left: 32px; - padding-right: 32px; - } + .modal-content { + padding-top: 48px; + padding-bottom: 48px; + padding-left: 32px; + padding-right: 32px; + } } @-webkit-keyframes slideUpInModal { - 0% { - opacity: 0; - transform: translateY(-24px); - } - to { - opacity: 1; - transform: translateY(0); - } + 0% { + opacity: 0; + transform: translateY(-24px); + } + to { + opacity: 1; + transform: translateY(0); + } } @keyframes slideUpInModal { - 0% { - opacity: 0; - transform: translateY(-24px); - } - to { - opacity: 1; - transform: translateY(0); - } + 0% { + opacity: 0; + transform: translateY(-24px); + } + to { + opacity: 1; + transform: translateY(0); + } } @-webkit-keyframes slideUpInModalBg { - 0% { - opacity: 0; - } - to { - opacity: 1; - } + 0% { + opacity: 0; + } + to { + opacity: 1; + } } @keyframes slideUpInModalBg { - 0% { - opacity: 0; - } - to { - opacity: 1; - } + 0% { + opacity: 0; + } + to { + opacity: 1; + } } .carousel-item { - display: none; + display: none; } .carousel-item.is-loading:not(.is-active) { - display: block; - position: absolute; - visibility: hidden; - opacity: 0; + display: block; + position: absolute; + visibility: hidden; + opacity: 0; } .carousel-item.is-active { - display: block; + display: block; } .carousel-bullets { - display: inline-flex; + display: inline-flex; } .carousel-bullet { - display: block; - position: relative; - width: 20px; - height: 20px; - padding: 0; - cursor: pointer; - line-height: 0; - border: none; - background: transparent; + display: block; + position: relative; + width: 20px; + height: 20px; + padding: 0; + cursor: pointer; + line-height: 0; + border: none; + background: transparent; } .carousel-bullet::before { - content: ""; - position: absolute; - left: 6px; - top: 6px; - background: #292b32; - width: 8px; - height: 8px; - border-radius: 50%; - transition: background 0.25s ease; + content: ''; + position: absolute; + left: 6px; + top: 6px; + background: #292b32; + width: 8px; + height: 8px; + border-radius: 50%; + transition: background 0.25s ease; } .carousel-bullet:focus { - outline: none; + outline: none; } .carousel-bullet.is-active::before { - background: #6a6f82; + background: #6a6f82; } .carousel-bullet:hover::before { - background: #959cb1; + background: #959cb1; } .invert-color .carousel-bullet::before { - background: #6a6f82; + background: #6a6f82; } .invert-color .carousel-bullet.is-active::before { - background: #292b32; + background: #292b32; } .invert-color .carousel-bullet:hover::before { - background: #376df9; + background: #376df9; } .split-wrap { - margin-top: -24px; + margin-top: -24px; } .split-wrap:last-of-type { - margin-bottom: -24px; + margin-bottom: -24px; } .split-wrap:not(:last-of-type) { - margin-bottom: 24px; + margin-bottom: 24px; } .split-wrap .split-item { - padding-top: 24px; - padding-bottom: 24px; - display: flex; - flex-direction: column; + padding-top: 24px; + padding-bottom: 24px; + display: flex; + flex-direction: column; } .split-wrap .split-item .split-item-image { - position: relative; - width: 100%; + position: relative; + width: 100%; } .split-wrap .split-item .split-item-image img, .split-wrap .split-item .split-item-image svg, .split-wrap .split-item .split-item-image video { - width: auto; - height: auto; - max-width: 100%; - overflow: visible; + width: auto; + height: auto; + max-width: 100%; + overflow: visible; } .split-wrap .split-item .split-item-image.split-item-image-fill img, .split-wrap .split-item .split-item-image.split-item-image-fill svg, .split-wrap .split-item .split-item-image.split-item-image-fill video { - width: 100%; + width: 100%; } @media (max-width: 640px) { - .split-wrap .split-item .split-item-content { - margin-bottom: 32px; - } + .split-wrap .split-item .split-item-content { + margin-bottom: 32px; + } - .split-wrap.invert-mobile .split-item .split-item-content { - order: 1; - margin-bottom: 0 !important; - } + .split-wrap.invert-mobile .split-item .split-item-content { + order: 1; + margin-bottom: 0 !important; + } - .split-wrap.invert-mobile .split-item .split-item-image { - margin-bottom: 32px; - } + .split-wrap.invert-mobile .split-item .split-item-image { + margin-bottom: 32px; + } } @media (min-width: 641px) { - .split-wrap { - margin-top: -40px; - } + .split-wrap { + margin-top: -40px; + } - .split-wrap:last-of-type { - margin-bottom: -40px; - } + .split-wrap:last-of-type { + margin-bottom: -40px; + } - .split-wrap:not(:last-of-type) { - margin-bottom: 40px; - } + .split-wrap:not(:last-of-type) { + margin-bottom: 40px; + } - .split-wrap .split-item { - padding-top: 40px; - padding-bottom: 40px; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - justify-content: flex-start; - } + .split-wrap .split-item { + padding-top: 40px; + padding-bottom: 40px; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + justify-content: flex-start; + } - .split-wrap .split-item .split-item-content { - flex-shrink: 0; - width: 396px; - margin-bottom: 0; - margin-right: 64px; - } + .split-wrap .split-item .split-item-content { + flex-shrink: 0; + width: 396px; + margin-bottom: 0; + margin-right: 64px; + } - .split-wrap .split-item .split-item-image { - min-width: 436px; - } + .split-wrap .split-item .split-item-image { + min-width: 436px; + } - .split-wrap:not(.invert-desktop) .split-item:nth-child(even), - .split-wrap.invert-desktop .split-item:nth-child(odd) { - justify-content: flex-end; - } + .split-wrap:not(.invert-desktop) .split-item:nth-child(even), + .split-wrap.invert-desktop .split-item:nth-child(odd) { + justify-content: flex-end; + } - .split-wrap:not(.invert-desktop) - .split-item:nth-child(even) - .split-item-content, - .split-wrap.invert-desktop .split-item:nth-child(odd) .split-item-content { - order: 1; - margin-left: 64px; - margin-right: 0; - } + .split-wrap:not(.invert-desktop) .split-item:nth-child(even) .split-item-content, + .split-wrap.invert-desktop .split-item:nth-child(odd) .split-item-content { + order: 1; + margin-left: 64px; + margin-right: 0; + } - .split-wrap:not(.invert-desktop) - .split-item:nth-child(odd) - .split-item-image - img, - .split-wrap:not(.invert-desktop) - .split-item:nth-child(odd) - .split-item-image - svg, - .split-wrap:not(.invert-desktop) - .split-item:nth-child(odd) - .split-item-image - video, - .split-wrap.invert-desktop .split-item:nth-child(even) .split-item-image img, - .split-wrap.invert-desktop .split-item:nth-child(even) .split-item-image svg, - .split-wrap.invert-desktop - .split-item:nth-child(even) - .split-item-image - video { - margin-left: auto; - } + .split-wrap:not(.invert-desktop) .split-item:nth-child(odd) .split-item-image img, + .split-wrap:not(.invert-desktop) .split-item:nth-child(odd) .split-item-image svg, + .split-wrap:not(.invert-desktop) .split-item:nth-child(odd) .split-item-image video, + .split-wrap.invert-desktop .split-item:nth-child(even) .split-item-image img, + .split-wrap.invert-desktop .split-item:nth-child(even) .split-item-image svg, + .split-wrap.invert-desktop .split-item:nth-child(even) .split-item-image video { + margin-left: auto; + } - .split-wrap.align-top .split-item { - align-items: flex-start; - } + .split-wrap.align-top .split-item { + align-items: flex-start; + } } @media (min-width: 821px) { - .container .split-wrap .split-item .split-item-content { - width: 488px; - } + .container .split-wrap .split-item .split-item-content { + width: 488px; + } - .container .split-wrap .split-item .split-item-image { - min-width: 528px; - } + .container .split-wrap .split-item .split-item-image { + min-width: 528px; + } } .tiles-wrap { - display: flex; - flex-wrap: wrap; - justify-content: center; - margin-right: -12px; - margin-left: -12px; - margin-top: -12px; + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-right: -12px; + margin-left: -12px; + margin-top: -12px; } .tiles-wrap:last-of-type { - margin-bottom: -12px; + margin-bottom: -12px; } .tiles-wrap:not(:last-of-type) { - margin-bottom: 12px; + margin-bottom: 12px; } .tiles-wrap.push-left::after { - content: ""; - flex-basis: 330px; - max-width: 330px; - box-sizing: content-box; - padding-left: 12px; - padding-right: 12px; - height: 0; + content: ''; + flex-basis: 330px; + max-width: 330px; + box-sizing: content-box; + padding-left: 12px; + padding-right: 12px; + height: 0; } .tiles-item { - flex-basis: 330px; - max-width: 330px; - box-sizing: content-box; - padding: 12px; + flex-basis: 330px; + max-width: 330px; + box-sizing: content-box; + padding: 12px; } .tiles-item * { - box-sizing: border-box; + box-sizing: border-box; } .tiles-item-inner { - display: flex; - flex-wrap: wrap; - flex-direction: column; - height: 100%; - padding: 32px 24px; + display: flex; + flex-wrap: wrap; + flex-direction: column; + height: 100%; + padding: 32px 24px; } @media (max-width: 640px) { - .section:first-of-type { - min-height: calc(100vh - (80px / 2)); - } + .section:first-of-type { + min-height: calc(100vh - (80px / 2)); + } } .site-header { - position: absolute !important; - top: 0; - width: 100%; - z-index: 10 !important; + position: absolute !important; + top: 0; + width: 100%; + z-index: 10 !important; } .site-header + .site-content .section:first-of-type { - padding-top: 80px; + padding-top: 80px; } .site-header .brand { - margin-right: 32px; + margin-right: 32px; } .site-header-inner { - display: flex; - justify-content: space-between; - align-items: center; - height: 80px; + display: flex; + justify-content: space-between; + align-items: center; + height: 80px; } .header-nav { - flex-grow: 1; + flex-grow: 1; } .header-nav .header-nav-inner { - display: flex; - flex-grow: 1; + display: flex; + flex-grow: 1; } .header-nav ul { - display: flex; - align-items: center; - flex-grow: 1; - white-space: nowrap; - margin-bottom: 0; + display: flex; + align-items: center; + flex-grow: 1; + white-space: nowrap; + margin-bottom: 0; } .header-nav ul:first-of-type { - flex-wrap: wrap; + flex-wrap: wrap; } .header-nav li + .header-button { - margin-left: 32px; + margin-left: 32px; } .header-nav a:not(.button) { - display: block; - text-decoration: none; - font-weight: 500; - text-transform: uppercase; - padding: 0 32px; + display: block; + text-decoration: none; + font-weight: 500; + text-transform: uppercase; + padding: 0 32px; } .invert-color .header-nav a:not(.button) { - text-decoration: none; + text-decoration: none; } .header-nav a.button { - margin-left: 32px; + margin-left: 32px; } .header-nav-center:first-of-type { - flex-grow: 1; - justify-content: flex-end; + flex-grow: 1; + justify-content: flex-end; } .header-nav-right { - justify-content: flex-end; + justify-content: flex-end; } .header-nav-right + .header-nav-right { - flex-grow: 0; + flex-grow: 0; } .header-nav-toggle { - display: none; + display: none; } @media (max-width: 640px) { - .header-nav-toggle { - display: block; - } + .header-nav-toggle { + display: block; + } - .header-nav-toggle + .header-nav { - flex-direction: column; - position: absolute; - left: 0; - right: 0; - top: 100%; - z-index: 9999; - background: #292b32; - max-height: 0; - opacity: 0; - overflow: hidden; - transition: max-height 0.25s ease-in-out, opacity 0.15s; - } + .header-nav-toggle + .header-nav { + flex-direction: column; + position: absolute; + left: 0; + right: 0; + top: 100%; + z-index: 9999; + background: #292b32; + max-height: 0; + opacity: 0; + overflow: hidden; + transition: max-height 0.25s ease-in-out, opacity 0.15s; + } - .header-nav-toggle + .header-nav.is-active { - opacity: 1; - } + .header-nav-toggle + .header-nav.is-active { + opacity: 1; + } - .header-nav-toggle + .header-nav .header-nav-inner { - flex-direction: column; - padding: 24px; - } + .header-nav-toggle + .header-nav .header-nav-inner { + flex-direction: column; + padding: 24px; + } - .header-nav-toggle + .header-nav ul { - display: block; - text-align: center; - } + .header-nav-toggle + .header-nav ul { + display: block; + text-align: center; + } - .header-nav-toggle + .header-nav ul a:not(.button) { - display: inline-flex; - padding-top: 12px; - padding-bottom: 12px; - } + .header-nav-toggle + .header-nav ul a:not(.button) { + display: inline-flex; + padding-top: 12px; + padding-bottom: 12px; + } - .header-nav-toggle + .header-nav a.button { - margin-left: 0; - margin-top: 12px; - margin-bottom: 12px; - } + .header-nav-toggle + .header-nav a.button { + margin-left: 0; + margin-top: 12px; + margin-bottom: 12px; + } } .is-boxed { - background: #1b1c21; + background: #1b1c21; } .is-boxed .body-wrap { - max-width: 1440px; - margin: 0 auto; - box-shadow: 0 20px 48px rgba(22, 23, 27, 0.8); + max-width: 1440px; + margin: 0 auto; + box-shadow: 0 20px 48px rgba(22, 23, 27, 0.8); } .is-boxed .body-wrap::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: #16171b; - z-index: -10; + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #16171b; + z-index: -10; } .body-wrap { - position: relative; - overflow: hidden; - display: flex; - flex-direction: column; - min-height: 100vh; + position: relative; + overflow: hidden; + display: flex; + flex-direction: column; + min-height: 100vh; } .site-content { - flex: 1 0 auto; + flex: 1 0 auto; } .site-footer { - position: relative; + position: relative; } .site-footer::before { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - background: #16171b; - z-index: -3; + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + background: #16171b; + z-index: -3; } .site-footer-inner { - padding: 48px 0; + padding: 48px 0; } .footer-top { - padding-bottom: 12px; + padding-bottom: 12px; } .footer-bottom { - padding-top: 12px; + padding-top: 12px; } .footer-blocks { - display: flex; - flex-wrap: wrap; - margin-right: -24px; - margin-left: -24px; - margin-top: -12px; + display: flex; + flex-wrap: wrap; + margin-right: -24px; + margin-left: -24px; + margin-top: -12px; } .footer-blocks:last-of-type { - margin-bottom: 28px; + margin-bottom: 28px; } .footer-blocks:not(:last-of-type) { - margin-bottom: 12px; + margin-bottom: 12px; } .footer-block { - flex-grow: 1; - flex-basis: 160px; - box-sizing: content-box; - padding: 12px 24px; + flex-grow: 1; + flex-basis: 160px; + box-sizing: content-box; + padding: 12px 24px; } .footer-block * { - box-sizing: border-box; + box-sizing: border-box; } .footer-block ul li:not(:last-child) { - margin-bottom: 4px; + margin-bottom: 4px; } .footer-block a { - color: #6a6f82; - text-decoration: none; + color: #6a6f82; + text-decoration: none; } .footer-block a:hover, .footer-block a:active { - color: #959cb1; + color: #959cb1; } .invert-color .footer-block a { - text-decoration: none; + text-decoration: none; } .footer-block-title { - font-size: 14px; - line-height: 22px; - font-weight: 700; - color: #f9faff; - text-transform: uppercase; - margin-bottom: 8px; + font-size: 14px; + line-height: 22px; + font-weight: 700; + color: #f9faff; + text-transform: uppercase; + margin-bottom: 8px; } .invert-color .footer-block-title { - color: #16171b; + color: #16171b; } .footer-social a, .footer-nav a { - display: flex; + display: flex; } .footer-social ul, .footer-nav ul { - display: flex; - flex-wrap: wrap; - justify-content: center; - align-items: center; - white-space: nowrap; - margin-bottom: 0; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + white-space: nowrap; + margin-bottom: 0; } .footer-social ul { - margin-right: -16px; - margin-left: -16px; + margin-right: -16px; + margin-left: -16px; } .footer-social li { - padding: 0 8px; + padding: 0 8px; } .footer-social a { - padding: 8px; + padding: 8px; } .footer-social a svg { - fill: #376df9; - transition: fill 0.15s ease; + fill: #376df9; + transition: fill 0.15s ease; } .footer-social a:hover svg { - fill: #6991fa; + fill: #6991fa; } .footer-nav { - margin-right: -12px; - margin-left: -12px; + margin-right: -12px; + margin-left: -12px; } .footer-nav a { - color: #6a6f82; - text-decoration: none; - padding: 0 12px; + color: #6a6f82; + text-decoration: none; + padding: 0 12px; } .footer-nav a:hover, .footer-nav a:active { - color: #959cb1; + color: #959cb1; } .invert-color .footer-nav a { - text-decoration: none; + text-decoration: none; } @media (max-width: 640px) { - .footer-top > *:not(:last-child), - .footer-bottom > *:not(:last-child) { - margin-bottom: 24px; - } + .footer-top > *:not(:last-child), + .footer-bottom > *:not(:last-child) { + margin-bottom: 24px; + } } @media (min-width: 641px) { - .site-footer-inner { - padding: 64px 0; - } + .site-footer-inner { + padding: 64px 0; + } - .footer-top.space-between, - .footer-bottom.space-between { - display: flex; - justify-content: space-between; - align-items: center; - } + .footer-top.space-between, + .footer-bottom.space-between { + display: flex; + justify-content: space-between; + align-items: center; + } - .footer-top.invert-order-desktop > *:first-child, - .footer-bottom.invert-order-desktop > *:first-child { - order: 1; - } + .footer-top.invert-order-desktop > *:first-child, + .footer-bottom.invert-order-desktop > *:first-child { + order: 1; + } } .section-inner { - position: relative; - padding-top: 48px; - padding-bottom: 48px; + position: relative; + padding-top: 48px; + padding-bottom: 48px; } .section-header { - padding-bottom: 48px; + padding-bottom: 48px; } @media (min-width: 641px) { - .section-inner { - padding-top: 80px; - padding-bottom: 80px; - } + .section-inner { + padding-top: 80px; + padding-bottom: 80px; + } - .section-header { - padding-bottom: 80px; - } + .section-header { + padding-bottom: 80px; + } } .hero-inner > .hero-content + .hero-figure, .hero-inner > .hero-figure + .hero-content { - margin-top: 48px; + margin-top: 48px; } .hero-inner > .hero-figure > a { - display: inline-flex; - align-items: center; - vertical-align: top; + display: inline-flex; + align-items: center; + vertical-align: top; } @media (max-width: 640px) { - .hero .split-wrap .split-item .split-item-content { - margin-bottom: 48px; - } + .hero .split-wrap .split-item .split-item-content { + margin-bottom: 48px; + } - .hero .split-wrap.invert-mobile .split-item .split-item-image { - margin-bottom: 48px; - } + .hero .split-wrap.invert-mobile .split-item .split-item-image { + margin-bottom: 48px; + } } @media (min-width: 641px) { - .hero-inner > .hero-content + .hero-figure, - .hero-inner > .hero-figure + .hero-content { - margin-top: 64px; - } + .hero-inner > .hero-content + .hero-figure, + .hero-inner > .hero-figure + .hero-content { + margin-top: 64px; + } } @media (min-width: 641px) { - .features-split .section-header { - padding-bottom: 92px; - } + .features-split .section-header { + padding-bottom: 92px; + } } .features-tiles .tiles-wrap { - margin-right: -16px; - margin-left: -16px; - margin-top: -16px; + margin-right: -16px; + margin-left: -16px; + margin-top: -16px; } .features-tiles .tiles-wrap:last-of-type { - margin-bottom: -16px; + margin-bottom: -16px; } .features-tiles .tiles-wrap:not(:last-of-type) { - margin-bottom: 16px; + margin-bottom: 16px; } .features-tiles .tiles-wrap.push-left::after { - flex-basis: 360px; - max-width: 360px; - padding-left: 16px; - padding-right: 16px; + flex-basis: 360px; + max-width: 360px; + padding-left: 16px; + padding-right: 16px; } .features-tiles .tiles-item { - flex-basis: 360px; - max-width: 360px; - padding: 16px; + flex-basis: 360px; + max-width: 360px; + padding: 16px; } .features-tiles .tiles-item-inner { - padding-top: 0; - padding-bottom: 0; - padding-left: 0; - padding-right: 0; + padding-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; } @media (min-width: 641px) { - .features-tiles .tiles-wrap { - margin-right: -32px; - margin-left: -32px; - margin-top: -32px; - } + .features-tiles .tiles-wrap { + margin-right: -32px; + margin-left: -32px; + margin-top: -32px; + } - .features-tiles .tiles-wrap:last-of-type { - margin-bottom: -32px; - } + .features-tiles .tiles-wrap:last-of-type { + margin-bottom: -32px; + } - .features-tiles .tiles-wrap:not(:last-of-type) { - margin-bottom: 32px; - } + .features-tiles .tiles-wrap:not(:last-of-type) { + margin-bottom: 32px; + } - .features-tiles .tiles-wrap.push-left::after { - padding-left: 32px; - padding-right: 32px; - } + .features-tiles .tiles-wrap.push-left::after { + padding-left: 32px; + padding-right: 32px; + } - .features-tiles .tiles-item { - padding: 32px; - } + .features-tiles .tiles-item { + padding: 32px; + } } .pricing .tiles-wrap.push-left::after { - flex-basis: 344px; - max-width: 344px; + flex-basis: 344px; + max-width: 344px; } .pricing .tiles-item { - flex-basis: 344px; - max-width: 344px; + flex-basis: 344px; + max-width: 344px; } .pricing .tiles-item-inner { - padding-top: 24px; - padding-bottom: 24px; - padding-left: 24px; - padding-right: 24px; + padding-top: 24px; + padding-bottom: 24px; + padding-left: 24px; + padding-right: 24px; } .pricing-item-content { - flex-grow: 1; - width: 100%; + flex-grow: 1; + width: 100%; } ul.pricing-item-features-list li { - display: flex; - align-items: center; - margin-bottom: 12px; + display: flex; + align-items: center; + margin-bottom: 12px; } .pricing-switcher { - margin-bottom: 48px; + margin-bottom: 48px; } @media (min-width: 641px) { - .pricing-switcher { - margin-bottom: 64px; - } + .pricing-switcher { + margin-bottom: 64px; + } } .testimonial .tiles-wrap.push-left::after { - flex-basis: 344px; - max-width: 344px; + flex-basis: 344px; + max-width: 344px; } .testimonial .tiles-item { - flex-basis: 344px; - max-width: 344px; + flex-basis: 344px; + max-width: 344px; } .testimonial .tiles-item-inner { - padding-top: 20px; - padding-bottom: 20px; - padding-left: 24px; - padding-right: 24px; + padding-top: 20px; + padding-bottom: 20px; + padding-left: 24px; + padding-right: 24px; } .testimonial-item-content { - flex-grow: 1; + flex-grow: 1; } .testimonial-item-source { - display: inline-flex; - flex-wrap: wrap; - align-items: center; + display: inline-flex; + flex-wrap: wrap; + align-items: center; } .team .tiles-wrap { - margin-right: -16px; - margin-left: -16px; - margin-top: -16px; + margin-right: -16px; + margin-left: -16px; + margin-top: -16px; } .team .tiles-wrap:last-of-type { - margin-bottom: -16px; + margin-bottom: -16px; } .team .tiles-wrap:not(:last-of-type) { - margin-bottom: 16px; + margin-bottom: 16px; } .team .tiles-wrap.push-left::after { - flex-basis: 296px; - max-width: 296px; - padding-left: 16px; - padding-right: 16px; + flex-basis: 296px; + max-width: 296px; + padding-left: 16px; + padding-right: 16px; } .team .tiles-item { - flex-basis: 296px; - max-width: 296px; - padding: 16px; + flex-basis: 296px; + max-width: 296px; + padding: 16px; } .team .tiles-item-inner { - padding-top: 0; - padding-bottom: 0; - padding-left: 0; - padding-right: 0; + padding-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; } @media (min-width: 641px) { - .team .section-header { - padding-bottom: 80px; - } + .team .section-header { + padding-bottom: 80px; + } - .team .tiles-wrap { - margin-right: -32px; - margin-left: -32px; - margin-top: -32px; - } + .team .tiles-wrap { + margin-right: -32px; + margin-left: -32px; + margin-top: -32px; + } - .team .tiles-wrap:last-of-type { - margin-bottom: -32px; - } + .team .tiles-wrap:last-of-type { + margin-bottom: -32px; + } - .team .tiles-wrap:not(:last-of-type) { - margin-bottom: 32px; - } + .team .tiles-wrap:not(:last-of-type) { + margin-bottom: 32px; + } - .team .tiles-wrap.push-left::after { - padding-left: 32px; - padding-right: 32px; - } + .team .tiles-wrap.push-left::after { + padding-left: 32px; + padding-right: 32px; + } - .team .tiles-item { - padding: 32px; - } + .team .tiles-item { + padding: 32px; + } } .cta .section-inner { - padding-top: 48px; - padding-bottom: 48px; + padding-top: 48px; + padding-bottom: 48px; } .cta-slogan { - margin-bottom: 40px; + margin-bottom: 40px; } @media (min-width: 641px) { - .cta .section-inner { - padding-top: 64px; - padding-bottom: 64px; - } + .cta .section-inner { + padding-top: 64px; + padding-bottom: 64px; + } - .cta-split { - display: flex; - justify-content: space-between; - align-items: center; - } + .cta-split { + display: flex; + justify-content: space-between; + align-items: center; + } - .cta-split .cta-slogan { - margin-bottom: 0; - margin-right: 48px; - } + .cta-split .cta-slogan { + margin-bottom: 0; + margin-right: 48px; + } } .clients .section-inner { - padding-top: 26px; - padding-bottom: 26px; + padding-top: 26px; + padding-bottom: 26px; } .clients-inner ul { - display: flex; - flex-wrap: wrap; - flex-direction: column; - justify-content: center; - align-items: center; - margin: 0; + display: flex; + flex-wrap: wrap; + flex-direction: column; + justify-content: center; + align-items: center; + margin: 0; } .clients-inner li { - padding: 12px 28px; + padding: 12px 28px; } @media (min-width: 641px) { - .clients .clients-inner ul { - flex-direction: row; - } + .clients .clients-inner ul { + flex-direction: row; + } } .signin .section-header { - padding-bottom: 32px; + padding-bottom: 32px; } .signin .tiles-item-inner { - padding-top: 0; - padding-bottom: 0; - padding-left: 0; - padding-right: 0; + padding-top: 0; + padding-bottom: 0; + padding-left: 0; + padding-right: 0; } @media (min-width: 641px) { - .signin .section-header { - padding-bottom: 48px; - } + .signin .section-header { + padding-bottom: 48px; + } } .signin-footer { - display: flex; - flex-wrap: wrap; - justify-content: space-between; + display: flex; + flex-wrap: wrap; + justify-content: space-between; } -[class*="illustration-"] { - position: relative; +[class*='illustration-'] { + position: relative; } -[class*="illustration-"]::after { - pointer-events: none; +[class*='illustration-']::after { + pointer-events: none; } -[class*="illustration-element-"]::after { - z-index: -1; +[class*='illustration-element-']::after { + z-index: -1; } -[class*="illustration-section-"]::after { - z-index: -2; +[class*='illustration-section-']::after { + z-index: -2; } .illustration-section-01::after { - content: ""; - position: absolute; - width: 100%; - max-width: 100%; - height: 612px; - background-image: url(../images/illustration-section-01.svg); - background-repeat: no-repeat; - background-size: auto; - left: 50%; - top: 0; - background-position: center top; - transform: translate(-50%); + content: ''; + position: absolute; + width: 100%; + max-width: 100%; + height: 612px; + background-image: url(../images/illustration-section-01.svg); + background-repeat: no-repeat; + background-size: auto; + left: 50%; + top: 0; + background-position: center top; + transform: translate(-50%); } .illustration-section-02::after { - content: ""; - position: absolute; - width: 100%; - max-width: 100%; - height: 612px; - background-image: url(../images/illustration-section-02.svg); - background-repeat: no-repeat; - background-size: auto; - left: 50%; - top: 0; - background-position: center top; - transform: translate(-50%); + content: ''; + position: absolute; + width: 100%; + max-width: 100%; + height: 612px; + background-image: url(../images/illustration-section-02.svg); + background-repeat: no-repeat; + background-size: auto; + left: 50%; + top: 0; + background-position: center top; + transform: translate(-50%); } .site-footer { - color: #6a6f82; + color: #6a6f82; } .features-tiles-item-image { - display: inline-flex; - border-radius: 50%; - background: radial-gradient( - circle at bottom, - #376df9 0%, - #ff79af 50%, - #ff8d74 100% - ); + display: inline-flex; + border-radius: 50%; + background: radial-gradient(circle at bottom, #376df9 0%, #ff79af 50%, #ff8d74 100%); } .pricing .tiles-item-inner { - background: #292b32; + background: #292b32; } .pricing-item-header { - position: relative; + position: relative; } .pricing-item-header::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #292b32; + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #292b32; } .pricing-item-header::after { - background: rgba(106, 111, 130, 0.32); - max-width: 88px; + background: rgba(106, 111, 130, 0.32); + max-width: 88px; } .pricing-item-price-currency { - color: #959cb1; + color: #959cb1; } ul.pricing-item-features-list { - position: relative; + position: relative; } ul.pricing-item-features-list::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #292b32; + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #292b32; } ul.pricing-item-features-list::after { - background: rgba(106, 111, 130, 0.32); + background: rgba(106, 111, 130, 0.32); } ul.pricing-item-features-list li { - margin-bottom: 0; - padding: 14px 0; - position: relative; + margin-bottom: 0; + padding: 14px 0; + position: relative; } ul.pricing-item-features-list li::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #292b32; + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #292b32; } ul.pricing-item-features-list li::before { - background: rgba(106, 111, 130, 0.32); + background: rgba(106, 111, 130, 0.32); } ul.pricing-item-features-list li::after { - content: ""; - display: block; - width: 24px; - height: 24px; - margin-right: 12px; - background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%2011h14v2H5z%22%20fill%3D%22%236A6F82%22%20fill-rule%3D%22nonzero%22%2F%3E%3C%2Fsvg%3E"); - background-repeat: no-repeat; - order: -1; + content: ''; + display: block; + width: 24px; + height: 24px; + margin-right: 12px; + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%2011h14v2H5z%22%20fill%3D%22%236A6F82%22%20fill-rule%3D%22nonzero%22%2F%3E%3C%2Fsvg%3E'); + background-repeat: no-repeat; + order: -1; } ul.pricing-item-features-list li.is-checked::after { - background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cg%20fill-rule%3D%22nonzero%22%20fill%3D%22none%22%3E%3Ccircle%20fill%3D%22%231EC198%22%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2212%22%2F%3E%3Cpath%20fill%3D%22%23292B32%22%20d%3D%22M10.5%2012.267l-2.5-1.6-1%201.066L10.5%2016%2017%209.067%2016%208z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cg%20fill-rule%3D%22nonzero%22%20fill%3D%22none%22%3E%3Ccircle%20fill%3D%22%231EC198%22%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2212%22%2F%3E%3Cpath%20fill%3D%22%23292B32%22%20d%3D%22M10.5%2012.267l-2.5-1.6-1%201.066L10.5%2016%2017%209.067%2016%208z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E'); } .testimonial .tiles-item-inner { - background: #292b32; + background: #292b32; } .testimonial-item-content { - position: relative; + position: relative; } .testimonial-item-content::before { - content: ""; - display: block; - width: 24px; - height: 18px; - margin-top: 12px; - margin-bottom: 16px; - background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2224%22%20height%3D%2218%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M0%2013.481c0-2.34.611-4.761%201.833-7.263C3.056%203.716%204.733%201.643%206.865%200L11%202.689C9.726%204.382%208.777%206.093%208.152%207.824c-.624%201.73-.936%203.578-.936%205.545V18H0v-4.519zm13%200c0-2.34.611-4.761%201.833-7.263%201.223-2.502%202.9-4.575%205.032-6.218L24%202.689c-1.274%201.693-2.223%203.404-2.848%205.135-.624%201.73-.936%203.578-.936%205.545V18H13v-4.519z%22%20fill%3D%22%23FF5FA0%22%20fill-rule%3D%22nonzero%22%2F%3E%3C%2Fsvg%3E"); - background-repeat: no-repeat; + content: ''; + display: block; + width: 24px; + height: 18px; + margin-top: 12px; + margin-bottom: 16px; + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2224%22%20height%3D%2218%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M0%2013.481c0-2.34.611-4.761%201.833-7.263C3.056%203.716%204.733%201.643%206.865%200L11%202.689C9.726%204.382%208.777%206.093%208.152%207.824c-.624%201.73-.936%203.578-.936%205.545V18H0v-4.519zm13%200c0-2.34.611-4.761%201.833-7.263%201.223-2.502%202.9-4.575%205.032-6.218L24%202.689c-1.274%201.693-2.223%203.404-2.848%205.135-.624%201.73-.936%203.578-.936%205.545V18H13v-4.519z%22%20fill%3D%22%23FF5FA0%22%20fill-rule%3D%22nonzero%22%2F%3E%3C%2Fsvg%3E'); + background-repeat: no-repeat; } .testimonial-item-footer { - font-family: "Fira Sans", sans-serif; - font-weight: 600; - padding-top: 20px; + font-family: 'Fira Sans', sans-serif; + font-weight: 600; + padding-top: 20px; } .testimonial-item-footer.has-top-divider::before { - background: rgba(106, 111, 130, 0.32); + background: rgba(106, 111, 130, 0.32); } .testimonial-item-link { - color: #376df9; + color: #376df9; } .testimonial-item-link a { - color: #376df9; - text-decoration: none; + color: #376df9; + text-decoration: none; } .testimonial-item-link a:hover { - color: #6991fa; + color: #6991fa; } .cta .form-input { - border-color: transparent; - border-radius: 2px; + border-color: transparent; + border-radius: 2px; } .cta-inner { - padding-left: 16px; - padding-right: 16px; - background-color: #376df9; - background: linear-gradient(100deg, #376df9 0, #ff5fa0 75%, #ffc55a 100%); + padding-left: 16px; + padding-right: 16px; + background-color: #376df9; + background: linear-gradient(100deg, #376df9 0, #ff5fa0 75%, #ffc55a 100%); } @media (min-width: 641px) { - .cta .form-input { - min-width: 280px; - } + .cta .form-input { + min-width: 280px; + } - .cta-inner { - padding-left: 48px; - padding-right: 48px; - } + .cta-inner { + padding-left: 48px; + padding-right: 48px; + } } .screen-reader { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; } .list-reset { - list-style: none; - padding: 0; + list-style: none; + padding: 0; } .list-reset li { - margin: 0; + margin: 0; } .ta-l { - text-align: left; + text-align: left; } .ta-c { - text-align: center; + text-align: center; } .ta-r { - text-align: right; + text-align: right; } .fw-400 { - font-weight: 400; + font-weight: 400; } .fw-500 { - font-weight: 500; + font-weight: 500; } .fw-600 { - font-weight: 600; + font-weight: 600; } .fw-700 { - font-weight: 700; + font-weight: 700; } .text-color-high { - color: #f9faff; + color: #f9faff; } .text-color-mid { - color: #959cb1; + color: #959cb1; } .text-color-low { - color: #6a6f82; + color: #6a6f82; } .text-color-primary { - color: #376df9; + color: #376df9; } .text-color-secondary { - color: #ff5fa0; + color: #ff5fa0; } .text-color-error { - color: #ff5fa0; + color: #ff5fa0; } .text-color-warning { - color: #ffc55a; + color: #ffc55a; } .text-color-success { - color: #1ec198; + color: #1ec198; } .invert-color .text-color-high { - color: #16171b; + color: #16171b; } .invert-color .text-color-mid { - color: #1c1d22; + color: #1c1d22; } .invert-color .text-color-low { - color: #6a6f82; + color: #6a6f82; } .tt-u { - text-transform: uppercase; + text-transform: uppercase; } .image-full { - width: 100%; + width: 100%; } .image-larger { - position: relative; - left: 50%; - transform: translateX(-50%); - width: calc(100% + 96px); - max-width: 100vw; + position: relative; + left: 50%; + transform: translateX(-50%); + width: calc(100% + 96px); + max-width: 100vw; } .has-bg-color { - position: relative; - background-color: #fff; - z-index: 0; + position: relative; + background-color: #fff; + z-index: 0; } .has-shadow { - box-shadow: 0 24px 64px rgba(22, 23, 27, 0.64); + box-shadow: 0 24px 64px rgba(22, 23, 27, 0.64); } img.has-shadow { - border-radius: 2px; + border-radius: 2px; } .has-top-divider { - position: relative; + position: relative; } .has-top-divider::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #292b32; + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #292b32; } .has-bottom-divider { - position: relative; + position: relative; } .has-bottom-divider::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #292b32; + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #292b32; } .invert-color .has-top-divider { - position: relative; + position: relative; } .invert-color .has-top-divider::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #e5e9ff; + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #e5e9ff; } .invert-color .has-bottom-divider { - position: relative; + position: relative; } .invert-color .has-bottom-divider::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - display: block; - height: 1px; - background: #e5e9ff; + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + display: block; + height: 1px; + background: #e5e9ff; } .center-content { - text-align: center; + text-align: center; } .center-content img, .center-content svg, .center-content video { - margin-left: auto; - margin-right: auto; + margin-left: auto; + margin-right: auto; } .center-content .button-group { - justify-content: center; + justify-content: center; } .responsive-video { - position: relative; - padding-bottom: 56.25%; - height: 0; + position: relative; + padding-bottom: 56.25%; + height: 0; } .responsive-video.is-4-3 { - padding-bottom: 75%; + padding-bottom: 75%; } .responsive-video iframe { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; } .m-0 { - margin: 0; + margin: 0; } .mt-0 { - margin-top: 0; + margin-top: 0; } .mr-0 { - margin-right: 0; + margin-right: 0; } .mb-0 { - margin-bottom: 0; + margin-bottom: 0; } .ml-0 { - margin-left: 0; + margin-left: 0; } .m-4 { - margin: 4px; + margin: 4px; } .mt-4 { - margin-top: 4px; + margin-top: 4px; } .mr-4 { - margin-right: 4px; + margin-right: 4px; } .mb-4 { - margin-bottom: 4px; + margin-bottom: 4px; } .ml-4 { - margin-left: 4px; + margin-left: 4px; } .m-8 { - margin: 8px; + margin: 8px; } .mt-8 { - margin-top: 8px; + margin-top: 8px; } .mr-8 { - margin-right: 8px; + margin-right: 8px; } .mb-8 { - margin-bottom: 8px; + margin-bottom: 8px; } .ml-8 { - margin-left: 8px; + margin-left: 8px; } .m-12 { - margin: 12px; + margin: 12px; } .mt-12 { - margin-top: 12px; + margin-top: 12px; } .mr-12 { - margin-right: 12px; + margin-right: 12px; } .mb-12 { - margin-bottom: 12px; + margin-bottom: 12px; } .ml-12 { - margin-left: 12px; + margin-left: 12px; } .m-16 { - margin: 16px; + margin: 16px; } .mt-16 { - margin-top: 16px; + margin-top: 16px; } .mr-16 { - margin-right: 16px; + margin-right: 16px; } .mb-16 { - margin-bottom: 16px; + margin-bottom: 16px; } .ml-16 { - margin-left: 16px; + margin-left: 16px; } .m-24 { - margin: 24px; + margin: 24px; } .mt-24 { - margin-top: 24px; + margin-top: 24px; } .mr-24 { - margin-right: 24px; + margin-right: 24px; } .mb-24 { - margin-bottom: 24px; + margin-bottom: 24px; } .ml-24 { - margin-left: 24px; + margin-left: 24px; } .m-32 { - margin: 32px; + margin: 32px; } .mt-32 { - margin-top: 32px; + margin-top: 32px; } .mr-32 { - margin-right: 32px; + margin-right: 32px; } .mb-32 { - margin-bottom: 32px; + margin-bottom: 32px; } .ml-32 { - margin-left: 32px; + margin-left: 32px; } .p-0 { - padding: 0; + padding: 0; } .pt-0 { - padding-top: 0; + padding-top: 0; } .pr-0 { - padding-right: 0; + padding-right: 0; } .pb-0 { - padding-bottom: 0; + padding-bottom: 0; } .pl-0 { - padding-left: 0; + padding-left: 0; } .p-4 { - padding: 4px; + padding: 4px; } .pt-4 { - padding-top: 4px; + padding-top: 4px; } .pr-4 { - padding-right: 4px; + padding-right: 4px; } .pb-4 { - padding-bottom: 4px; + padding-bottom: 4px; } .pl-4 { - padding-left: 4px; + padding-left: 4px; } .p-8 { - padding: 8px; + padding: 8px; } .pt-8 { - padding-top: 8px; + padding-top: 8px; } .pr-8 { - padding-right: 8px; + padding-right: 8px; } .pb-8 { - padding-bottom: 8px; + padding-bottom: 8px; } .pl-8 { - padding-left: 8px; + padding-left: 8px; } .p-12 { - padding: 12px; + padding: 12px; } .pt-12 { - padding-top: 12px; + padding-top: 12px; } .pr-12 { - padding-right: 12px; + padding-right: 12px; } .pb-12 { - padding-bottom: 12px; + padding-bottom: 12px; } .pl-12 { - padding-left: 12px; + padding-left: 12px; } .p-16 { - padding: 16px; + padding: 16px; } .pt-16 { - padding-top: 16px; + padding-top: 16px; } .pr-16 { - padding-right: 16px; + padding-right: 16px; } .pb-16 { - padding-bottom: 16px; + padding-bottom: 16px; } .pl-16 { - padding-left: 16px; + padding-left: 16px; } .p-24 { - padding: 24px; + padding: 24px; } .pt-24 { - padding-top: 24px; + padding-top: 24px; } .pr-24 { - padding-right: 24px; + padding-right: 24px; } .pb-24 { - padding-bottom: 24px; + padding-bottom: 24px; } .pl-24 { - padding-left: 24px; + padding-left: 24px; } .p-32 { - padding: 32px; + padding: 32px; } .pt-32 { - padding-top: 32px; + padding-top: 32px; } .pr-32 { - padding-right: 32px; + padding-right: 32px; } .pb-32 { - padding-bottom: 32px; + padding-bottom: 32px; } .pl-32 { - padding-left: 32px; + padding-left: 32px; } .spacer-4 { - padding-top: 4px; + padding-top: 4px; } .spacer-8 { - padding-top: 8px; + padding-top: 8px; } .spacer-12 { - padding-top: 12px; + padding-top: 12px; } .spacer-16 { - padding-top: 16px; + padding-top: 16px; } .spacer-24 { - padding-top: 24px; + padding-top: 24px; } .spacer-32 { - padding-top: 32px; + padding-top: 32px; } .spacer-48 { - padding-top: 48px; + padding-top: 48px; } .spacer-64 { - padding-top: 64px; + padding-top: 64px; } @media (max-width: 640px) { - .ta-l-mobile { - text-align: left; - } + .ta-l-mobile { + text-align: left; + } - .ta-c-mobile { - text-align: center; - } + .ta-c-mobile { + text-align: center; + } - .ta-r-mobile { - text-align: right; - } + .ta-r-mobile { + text-align: right; + } - .center-content-mobile { - text-align: center; - } + .center-content-mobile { + text-align: center; + } - .center-content-mobile img, - .center-content-mobile svg, - .center-content-mobile video { - margin-left: auto; - margin-right: auto; - } + .center-content-mobile img, + .center-content-mobile svg, + .center-content-mobile video { + margin-left: auto; + margin-right: auto; + } - .center-content-mobile .button-group { - justify-content: center; - } + .center-content-mobile .button-group { + justify-content: center; + } - .spacer-4-mobile { - padding-top: 4px; - } + .spacer-4-mobile { + padding-top: 4px; + } - .spacer-8-mobile { - padding-top: 8px; - } + .spacer-8-mobile { + padding-top: 8px; + } - .spacer-12-mobile { - padding-top: 12px; - } + .spacer-12-mobile { + padding-top: 12px; + } - .spacer-16-mobile { - padding-top: 16px; - } + .spacer-16-mobile { + padding-top: 16px; + } - .spacer-24-mobile { - padding-top: 24px; - } + .spacer-24-mobile { + padding-top: 24px; + } - .spacer-32-mobile { - padding-top: 32px; - } + .spacer-32-mobile { + padding-top: 32px; + } - .spacer-48-mobile { - padding-top: 48px; - } + .spacer-48-mobile { + padding-top: 48px; + } - .spacer-64-mobile { - padding-top: 64px; - } + .spacer-64-mobile { + padding-top: 64px; + } } @media (min-width: 641px) { - .ta-l-desktop { - text-align: left; - } + .ta-l-desktop { + text-align: left; + } - .ta-c-desktop { - text-align: center; - } + .ta-c-desktop { + text-align: center; + } - .ta-r-desktop { - text-align: right; - } + .ta-r-desktop { + text-align: right; + } - .center-content-desktop { - text-align: center; - } + .center-content-desktop { + text-align: center; + } - .center-content-desktop img, - .center-content-desktop svg, - .center-content-desktop video { - margin-left: auto; - margin-right: auto; - } + .center-content-desktop img, + .center-content-desktop svg, + .center-content-desktop video { + margin-left: auto; + margin-right: auto; + } - .center-content-desktop .button-group { - justify-content: center; - } + .center-content-desktop .button-group { + justify-content: center; + } } /*Pulse Button*/ .pulse { - box-shadow: 0 0 0 rgba(120, 120, 120, 0.4); - animation: pulse 4s infinite; + box-shadow: 0 0 0 rgba(120, 120, 120, 0.4); + animation: pulse 4s infinite; } .pulse:hover { - animation: none; + animation: none; } @-webkit-keyframes pulse { - 0% { - -webkit-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0.4); - } - 70% { - -webkit-box-shadow: 0 0 0 15px rgba(120, 120, 120, 0); - } - 100% { - -webkit-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0); - } + 0% { + -webkit-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0.4); + } + 70% { + -webkit-box-shadow: 0 0 0 15px rgba(120, 120, 120, 0); + } + 100% { + -webkit-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0); + } } @keyframes pulse { - 0% { - -moz-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0.4); - box-shadow: 0 0 0 0 rgba(120, 120, 120, 0.4); - } - 70% { - -moz-box-shadow: 0 0 0 10px rgba(120, 120, 120, 0); - box-shadow: 0 0 0 15px rgba(120, 120, 120, 0); - } - 100% { - -moz-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0); - box-shadow: 0 0 0 0 rgba(120, 120, 120, 0); - } + 0% { + -moz-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0.4); + box-shadow: 0 0 0 0 rgba(120, 120, 120, 0.4); + } + 70% { + -moz-box-shadow: 0 0 0 10px rgba(120, 120, 120, 0); + box-shadow: 0 0 0 15px rgba(120, 120, 120, 0); + } + 100% { + -moz-box-shadow: 0 0 0 0 rgba(120, 120, 120, 0); + box-shadow: 0 0 0 0 rgba(120, 120, 120, 0); + } } /*Pulse Button*/ diff --git a/www/css/newcall.css b/www/css/newcall.css index d0b4901f..2603c9e0 100644 --- a/www/css/newcall.css +++ b/www/css/newcall.css @@ -1,27 +1,27 @@ @media (max-width: 640px) { - .section:first-of-type { - min-height: 0; - } + .section:first-of-type { + min-height: 0; + } - section:first-of-type .hero-inner { - padding-top: 1rem; - padding-bottom: 0; - } + section:first-of-type .hero-inner { + padding-top: 1rem; + padding-bottom: 0; + } - section:first-of-type .hero-inner .split-item { - padding: 0; - } + section:first-of-type .hero-inner .split-item { + padding: 0; + } - section:nth-of-type(2) { - margin-top: 2rem; - } + section:nth-of-type(2) { + margin-top: 2rem; + } - section:nth-of-type(2) .section-inner { - padding-top: 1rem; - padding-bottom: 0.5rem; - } + section:nth-of-type(2) .section-inner { + padding-top: 1rem; + padding-bottom: 0.5rem; + } - section:nth-of-type(2) .section-inner .cta-slogan { - margin-bottom: 1rem; - } + section:nth-of-type(2) .section-inner .cta-slogan { + margin-bottom: 1rem; + } } diff --git a/www/css/whiteboard.css b/www/css/whiteboard.css index 87ee8c5f..68d75c22 100644 --- a/www/css/whiteboard.css +++ b/www/css/whiteboard.css @@ -1,234 +1,233 @@ .whiteboard-cont { - z-index: 14; - display: none; - width: var(--wb-width); - height: var(--wb-height); - position: absolute; - /* center */ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - /* fade in */ - -webkit-animation: fadeIn ease-in 1; - -moz-animation: fadeIn ease-in 1; - animation: fadeIn ease-in 1; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - animation-duration: 1s; - overflow: none; - box-shadow: var(--box-shadow); - border-radius: 5px; + z-index: 14; + display: none; + width: var(--wb-width); + height: var(--wb-height); + position: absolute; + /* center */ + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + /* fade in */ + -webkit-animation: fadeIn ease-in 1; + -moz-animation: fadeIn ease-in 1; + animation: fadeIn ease-in 1; + -webkit-animation-fill-mode: forwards; + -moz-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + animation-duration: 1s; + overflow: none; + box-shadow: var(--box-shadow); + border-radius: 5px; } .whiteboard-cont #whiteboard { - z-index: 99; - background-color: var(--wb-bg); - border-radius: 5px; + z-index: 99; + background-color: var(--wb-bg); + border-radius: 5px; } .whiteboard-cont .colors-cont { - position: absolute; - display: flex; - left: 0px; - top: 0px; - width: 100%; - background: var(--wb-hbg); - cursor: move; - border-radius: 5px; + position: absolute; + display: flex; + left: 0px; + top: 0px; + width: 100%; + background: var(--wb-hbg); + cursor: move; + border-radius: 5px; } .whiteboard-cont .colors-cont .white { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #ffffff; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #ffffff; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .white:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .red { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #e74c3c; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #e74c3c; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .red:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .yellow { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #f1c40f; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #f1c40f; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .yellow:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .green { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #badc58; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #badc58; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .green:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .orange { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #e67e22; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #e67e22; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .orange:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .purple { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #9b59b6; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #9b59b6; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .purple:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .blue { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #3498db; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #3498db; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .blue:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .pink { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #fd79a8; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #fd79a8; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .pink:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .brown { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #834c32; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #834c32; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .brown:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont .colors-cont .grey { - height: 30px; - width: 30px; - border-radius: 50px; - background-color: #afadad; - margin-top: 10px; - margin-left: 10px; + height: 30px; + width: 30px; + border-radius: 50px; + background-color: #afadad; + margin-top: 10px; + margin-left: 10px; } .whiteboard-cont .colors-cont .grey:hover { - cursor: pointer; - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + cursor: pointer; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } .whiteboard-cont button { - height: 30px; - width: 30px; - font-size: 1.2rem; - margin-top: 10px; - margin-left: 10px; - border: none; - color: white; - background: transparent; + height: 30px; + width: 30px; + font-size: 1.2rem; + margin-top: 10px; + margin-left: 10px; + border: none; + color: white; + background: transparent; } .whiteboard-cont button:hover { - color: rgb(0, 180, 50); - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + color: rgb(0, 180, 50); + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } #whiteboardColorPicker { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - padding: 0; - border: none; - width: 30px; - height: 30px; - margin-top: 10px; - margin-left: 10px; - margin-right: 15px; - border-radius: 50px; - border: solid 0.5px #afadad38; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding: 0; + border: none; + width: 30px; + height: 30px; + margin-top: 10px; + margin-left: 10px; + margin-right: 15px; + border-radius: 50px; + border: solid 0.5px #afadad38; } #whiteboardColorPicker:hover { - transform: var(--btns-hover-scale); - transition: all 0.3s ease-in-out; + transform: var(--btns-hover-scale); + transition: all 0.3s ease-in-out; } #whiteboardColorPicker::-webkit-color-swatch { - border: none; - border-radius: 50px; - padding: 0; + border: none; + border-radius: 50px; + padding: 0; } #whiteboardColorPicker::-webkit-color-swatch-wrapper { - border: none; - border-radius: 50px; - padding: 0; + border: none; + border-radius: 50px; + padding: 0; } #whiteboardColorPicker::-moz-color-swatch { - border: none; - border-radius: 50px; - padding: 0; + border: none; + border-radius: 50px; + padding: 0; } #whiteboardColorPicker::-moz-color-swatch-wrapper { - border: none; - border-radius: 50px; - padding: 0; + border: none; + border-radius: 50px; + padding: 0; } #whiteboardColorPicker::color-swatch { - border: none; - border-radius: 50px; - padding: 0; + border: none; + border-radius: 50px; + padding: 0; } #whiteboardColorPicker::color-swatch-wrapper { - border: none; - border-radius: 50px; - padding: 0; + border: none; + border-radius: 50px; + padding: 0; } diff --git a/www/js/client.js b/www/js/client.js index de92ba3f..71e5b0c3 100644 --- a/www/js/client.js +++ b/www/js/client.js @@ -23,32 +23,32 @@ along with this program. If not, see . */ -"use strict"; // https://www.w3schools.com/js/js_strict.asp +'use strict'; // https://www.w3schools.com/js/js_strict.asp -const welcomeImg = "../images/image-placeholder.svg"; -const shareUrlImg = "../images/image-placeholder.svg"; -const leaveRoomImg = "../images/leave-room.png"; -const confirmImg = "../images/image-placeholder.svg"; -const fileSharingImg = "../images/image-placeholder.svg"; -const roomLockedImg = "../images/locked.png"; -const camOffImg = "../images/cam-off.png"; -const audioOffImg = "../images/audio-off.png"; -const kickedOutImg = "../images/leave-room.png"; -const aboutImg = "../images/about.png"; -const peerLoockupUrl = "https://extreme-ip-lookup.com/json/"; -const avatarApiUrl = "https://eu.ui-avatars.com/api"; +const welcomeImg = '../images/image-placeholder.svg'; +const shareUrlImg = '../images/image-placeholder.svg'; +const leaveRoomImg = '../images/leave-room.png'; +const confirmImg = '../images/image-placeholder.svg'; +const fileSharingImg = '../images/image-placeholder.svg'; +const roomLockedImg = '../images/locked.png'; +const camOffImg = '../images/cam-off.png'; +const audioOffImg = '../images/audio-off.png'; +const kickedOutImg = '../images/leave-room.png'; +const aboutImg = '../images/about.png'; +const peerLoockupUrl = 'https://extreme-ip-lookup.com/json/'; +const avatarApiUrl = 'https://eu.ui-avatars.com/api'; const notifyBySound = true; // turn on - off sound notifications -const notifyAddPeer = "../audio/addPeer.mp3"; -const notifyDownload = "../audio/download.mp3"; -const notifyKickedOut = "../audio/kickedOut.mp3"; -const notifyRemovePeer = "../audio/removePeer.mp3"; -const notifyNewMessage = "../audio/newMessage.mp3"; -const notifyChatMessage = "../audio/chatMessage.mp3"; -const notifyRecStart = "../audio/recStart.mp3"; -const notifyRecStop = "../audio/recStop.mp3"; -const notifyRaiseHand = "../audio/raiseHand.mp3"; -const notifyError = "../audio/error.mp3"; -const fileSharingInput = "*"; // allow all file extensions +const notifyAddPeer = '../audio/addPeer.mp3'; +const notifyDownload = '../audio/download.mp3'; +const notifyKickedOut = '../audio/kickedOut.mp3'; +const notifyRemovePeer = '../audio/removePeer.mp3'; +const notifyNewMessage = '../audio/newMessage.mp3'; +const notifyChatMessage = '../audio/chatMessage.mp3'; +const notifyRecStart = '../audio/recStart.mp3'; +const notifyRecStop = '../audio/recStop.mp3'; +const notifyRaiseHand = '../audio/raiseHand.mp3'; +const notifyError = '../audio/error.mp3'; +const fileSharingInput = '*'; // allow all file extensions // "image/*,.mp3,.doc,.docs,.txt,.pdf,.xls,.xlsx,.csv,.pcap,.xml,.json,.md,.html,.js,.css,.php,.py,.sh,.zip,.rar,.tar"; // "*" const isWebRTCSupported = DetectRTC.isWebRTCSupported; @@ -66,8 +66,8 @@ let callStartTime; let callElapsedTime; let recStartTime; let recElapsedTime; -let mirotalkTheme = "neon"; // neon - dark - forest - ghost ... -let swalBackground = "rgba(0, 0, 0, 0.7)"; // black - #16171b - transparent ... +let mirotalkTheme = 'neon'; // neon - dark - forest - ghost ... +let swalBackground = 'rgba(0, 0, 0, 0.7)'; // black - #16171b - transparent ... let signalingServerPort = 3000; // must be same of server PORT let signalingServer = getServerUrl(); let roomId = getRoomId(); @@ -77,7 +77,7 @@ let peerConnection; let myPeerName; let useAudio = true; let useVideo = true; -let camera = "user"; +let camera = 'user'; let roomLocked = false; let myVideoChange = false; let myHandStatus = false; @@ -100,19 +100,19 @@ let chatDataChannels = {}; // keep track of our peer chat data channels let fileDataChannels = {}; // keep track of our peer file sharing data channels let peerMediaElements = {}; // keep track of our peer