FreeCall - Beautiful Video Calling Without Limits | Free Online Video Chat
Rated #1 Free Video Calling Platform
Beautiful Video Calling
For Everyone
Connect instantly with friends, family, and colleagues in crystal-clear video calls.
No downloads, no registration, just pure video calling magic powered by your browser.
Start Free Video Call
Join Meeting
2M+
Happy Users
15
Max Participants
100%
Free Forever
Instant Connection
Start video calls in seconds with no downloads required
Group Calling
Connect up to 15 people in crystal-clear video calls
Screen Sharing
Share your screen with beautiful transitions and controls
Private & Secure
End-to-end encrypted calls with no data storage
Mobile Friendly
Perfect experience on phones, tablets, and desktops
Real-time Chat
Send messages and emojis during your video calls
Loved by millions worldwide
"The most beautiful video calling app I've ever used!"
Sarah Chen
Remote Team Lead
"Finally, a video calling platform that's actually fun to use."
Marcus Johnson
Freelance Designer
Chat is ready. Send a message to start the conversation.
Share on Social Media
WhatsApp
Telegram
Facebook
LinkedIn
Step 1: Share Your Offer
Copy this offer and send it to the participant you want to connect with:
Copy Offer
Step 2: Paste Their Answer
Paste the answer you received from the other participant:
Connect
Alternative: Handle Incoming Offer
If someone sent you an offer, paste it here:
Generate Answer
Your Answer
Copy this answer and send it back:
Copy Answer
Setting up your beautiful video call...
Achievement Unlocked!
Awesome!
:root {
/* Primitive Color Tokens */
--color-white: rgba(255, 255, 255, 1);
--color-black: rgba(0, 0, 0, 1);
--color-cream-50: rgba(252, 252, 249, 1);
--color-cream-100: rgba(255, 255, 253, 1);
--color-gray-200: rgba(245, 245, 245, 1);
--color-gray-300: rgba(167, 169, 169, 1);
--color-gray-400: rgba(119, 124, 124, 1);
--color-slate-500: rgba(98, 108, 113, 1);
--color-brown-600: rgba(94, 82, 64, 1);
--color-charcoal-700: rgba(31, 33, 33, 1);
--color-charcoal-800: rgba(38, 40, 40, 1);
--color-slate-900: rgba(19, 52, 59, 1);
--color-teal-300: rgba(50, 184, 198, 1);
--color-teal-400: rgba(45, 166, 178, 1);
--color-teal-500: rgba(33, 128, 141, 1);
--color-teal-600: rgba(29, 116, 128, 1);
--color-teal-700: rgba(26, 104, 115, 1);
--color-teal-800: rgba(41, 150, 161, 1);
--color-red-400: rgba(255, 84, 89, 1);
--color-red-500: rgba(192, 21, 47, 1);
--color-orange-400: rgba(230, 129, 97, 1);
--color-orange-500: rgba(168, 75, 47, 1);
/* RGB versions for opacity control */
--color-brown-600-rgb: 94, 82, 64;
--color-teal-500-rgb: 33, 128, 141;
--color-slate-900-rgb: 19, 52, 59;
--color-slate-500-rgb: 98, 108, 113;
--color-red-500-rgb: 192, 21, 47;
--color-red-400-rgb: 255, 84, 89;
--color-orange-500-rgb: 168, 75, 47;
--color-orange-400-rgb: 230, 129, 97;
/* Background color tokens (Light Mode) */
--color-bg-1: rgba(59, 130, 246, 0.08); /* Light blue */
--color-bg-2: rgba(245, 158, 11, 0.08); /* Light yellow */
--color-bg-3: rgba(34, 197, 94, 0.08); /* Light green */
--color-bg-4: rgba(239, 68, 68, 0.08); /* Light red */
--color-bg-5: rgba(147, 51, 234, 0.08); /* Light purple */
--color-bg-6: rgba(249, 115, 22, 0.08); /* Light orange */
--color-bg-7: rgba(236, 72, 153, 0.08); /* Light pink */
--color-bg-8: rgba(6, 182, 212, 0.08); /* Light cyan */
/* Semantic Color Tokens (Light Mode) */
--color-background: var(--color-cream-50);
--color-surface: var(--color-cream-100);
--color-text: var(--color-slate-900);
--color-text-secondary: var(--color-slate-500);
--color-primary: var(--color-teal-500);
--color-primary-hover: var(--color-teal-600);
--color-primary-active: var(--color-teal-700);
--color-secondary: rgba(var(--color-brown-600-rgb), 0.12);
--color-secondary-hover: rgba(var(--color-brown-600-rgb), 0.2);
--color-secondary-active: rgba(var(--color-brown-600-rgb), 0.25);
--color-border: rgba(var(--color-brown-600-rgb), 0.2);
--color-btn-primary-text: var(--color-cream-50);
--color-card-border: rgba(var(--color-brown-600-rgb), 0.12);
--color-card-border-inner: rgba(var(--color-brown-600-rgb), 0.12);
--color-error: var(--color-red-500);
--color-success: var(--color-teal-500);
--color-warning: var(--color-orange-500);
--color-info: var(--color-slate-500);
--color-focus-ring: rgba(var(--color-teal-500-rgb), 0.4);
--color-select-caret: rgba(var(--color-slate-900-rgb), 0.8);
/* Common style patterns */
--focus-ring: 0 0 0 3px var(--color-focus-ring);
--focus-outline: 2px solid var(--color-primary);
--status-bg-opacity: 0.15;
--status-border-opacity: 0.25;
--select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
--select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
/* RGB versions for opacity control */
--color-success-rgb: 33, 128, 141;
--color-error-rgb: 192, 21, 47;
--color-warning-rgb: 168, 75, 47;
--color-info-rgb: 98, 108, 113;
/* Typography */
--font-family-base: "FKGroteskNeue", "Geist", "Inter", -apple-system,
BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-family-mono: "Berkeley Mono", ui-monospace, SFMono-Regular, Menlo,
Monaco, Consolas, monospace;
--font-size-xs: 11px;
--font-size-sm: 12px;
--font-size-base: 14px;
--font-size-md: 14px;
--font-size-lg: 16px;
--font-size-xl: 18px;
--font-size-2xl: 20px;
--font-size-3xl: 24px;
--font-size-4xl: 30px;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 550;
--font-weight-bold: 600;
--line-height-tight: 1.2;
--line-height-normal: 1.5;
--letter-spacing-tight: -0.01em;
/* Spacing */
--space-0: 0;
--space-1: 1px;
--space-2: 2px;
--space-4: 4px;
--space-6: 6px;
--space-8: 8px;
--space-10: 10px;
--space-12: 12px;
--space-16: 16px;
--space-20: 20px;
--space-24: 24px;
--space-32: 32px;
/* Border Radius */
--radius-sm: 6px;
--radius-base: 8px;
--radius-md: 10px;
--radius-lg: 12px;
--radius-full: 9999px;
/* Shadows */
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.02);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.02);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.04),
0 2px 4px -1px rgba(0, 0, 0, 0.02);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.04),
0 4px 6px -2px rgba(0, 0, 0, 0.02);
--shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.15),
inset 0 -1px 0 rgba(0, 0, 0, 0.03);
/* Animation */
--duration-fast: 150ms;
--duration-normal: 250ms;
--ease-standard: cubic-bezier(0.16, 1, 0.3, 1);
/* Layout */
--container-sm: 640px;
--container-md: 768px;
--container-lg: 1024px;
--container-xl: 1280px;
}
/* Dark mode colors */
@media (prefers-color-scheme: dark) {
:root {
/* RGB versions for opacity control (Dark Mode) */
--color-gray-400-rgb: 119, 124, 124;
--color-teal-300-rgb: 50, 184, 198;
--color-gray-300-rgb: 167, 169, 169;
--color-gray-200-rgb: 245, 245, 245;
/* Background color tokens (Dark Mode) */
--color-bg-1: rgba(29, 78, 216, 0.15); /* Dark blue */
--color-bg-2: rgba(180, 83, 9, 0.15); /* Dark yellow */
--color-bg-3: rgba(21, 128, 61, 0.15); /* Dark green */
--color-bg-4: rgba(185, 28, 28, 0.15); /* Dark red */
--color-bg-5: rgba(107, 33, 168, 0.15); /* Dark purple */
--color-bg-6: rgba(194, 65, 12, 0.15); /* Dark orange */
--color-bg-7: rgba(190, 24, 93, 0.15); /* Dark pink */
--color-bg-8: rgba(8, 145, 178, 0.15); /* Dark cyan */
/* Semantic Color Tokens (Dark Mode) */
--color-background: var(--color-charcoal-700);
--color-surface: var(--color-charcoal-800);
--color-text: var(--color-gray-200);
--color-text-secondary: rgba(var(--color-gray-300-rgb), 0.7);
--color-primary: var(--color-teal-300);
--color-primary-hover: var(--color-teal-400);
--color-primary-active: var(--color-teal-800);
--color-secondary: rgba(var(--color-gray-400-rgb), 0.15);
--color-secondary-hover: rgba(var(--color-gray-400-rgb), 0.25);
--color-secondary-active: rgba(var(--color-gray-400-rgb), 0.3);
--color-border: rgba(var(--color-gray-400-rgb), 0.3);
--color-error: var(--color-red-400);
--color-success: var(--color-teal-300);
--color-warning: var(--color-orange-400);
--color-info: var(--color-gray-300);
--color-focus-ring: rgba(var(--color-teal-300-rgb), 0.4);
--color-btn-primary-text: var(--color-slate-900);
--color-card-border: rgba(var(--color-gray-400-rgb), 0.2);
--color-card-border-inner: rgba(var(--color-gray-400-rgb), 0.15);
--shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.1),
inset 0 -1px 0 rgba(0, 0, 0, 0.15);
--button-border-secondary: rgba(var(--color-gray-400-rgb), 0.2);
--color-border-secondary: rgba(var(--color-gray-400-rgb), 0.2);
--color-select-caret: rgba(var(--color-gray-200-rgb), 0.8);
/* Common style patterns - updated for dark mode */
--focus-ring: 0 0 0 3px var(--color-focus-ring);
--focus-outline: 2px solid var(--color-primary);
--status-bg-opacity: 0.15;
--status-border-opacity: 0.25;
--select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
--select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
/* RGB versions for dark mode */
--color-success-rgb: var(--color-teal-300-rgb);
--color-error-rgb: var(--color-red-400-rgb);
--color-warning-rgb: var(--color-orange-400-rgb);
--color-info-rgb: var(--color-gray-300-rgb);
}
}
/* Data attribute for manual theme switching */
[data-color-scheme="dark"] {
/* RGB versions for opacity control (dark mode) */
--color-gray-400-rgb: 119, 124, 124;
--color-teal-300-rgb: 50, 184, 198;
--color-gray-300-rgb: 167, 169, 169;
--color-gray-200-rgb: 245, 245, 245;
/* Colorful background palette - Dark Mode */
--color-bg-1: rgba(29, 78, 216, 0.15); /* Dark blue */
--color-bg-2: rgba(180, 83, 9, 0.15); /* Dark yellow */
--color-bg-3: rgba(21, 128, 61, 0.15); /* Dark green */
--color-bg-4: rgba(185, 28, 28, 0.15); /* Dark red */
--color-bg-5: rgba(107, 33, 168, 0.15); /* Dark purple */
--color-bg-6: rgba(194, 65, 12, 0.15); /* Dark orange */
--color-bg-7: rgba(190, 24, 93, 0.15); /* Dark pink */
--color-bg-8: rgba(8, 145, 178, 0.15); /* Dark cyan */
/* Semantic Color Tokens (Dark Mode) */
--color-background: var(--color-charcoal-700);
--color-surface: var(--color-charcoal-800);
--color-text: var(--color-gray-200);
--color-text-secondary: rgba(var(--color-gray-300-rgb), 0.7);
--color-primary: var(--color-teal-300);
--color-primary-hover: var(--color-teal-400);
--color-primary-active: var(--color-teal-800);
--color-secondary: rgba(var(--color-gray-400-rgb), 0.15);
--color-secondary-hover: rgba(var(--color-gray-400-rgb), 0.25);
--color-secondary-active: rgba(var(--color-gray-400-rgb), 0.3);
--color-border: rgba(var(--color-gray-400-rgb), 0.3);
--color-error: var(--color-red-400);
--color-success: var(--color-teal-300);
--color-warning: var(--color-orange-400);
--color-info: var(--color-gray-300);
--color-focus-ring: rgba(var(--color-teal-300-rgb), 0.4);
--color-btn-primary-text: var(--color-slate-900);
--color-card-border: rgba(var(--color-gray-400-rgb), 0.15);
--color-card-border-inner: rgba(var(--color-gray-400-rgb), 0.15);
--shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.1),
inset 0 -1px 0 rgba(0, 0, 0, 0.15);
--color-border-secondary: rgba(var(--color-gray-400-rgb), 0.2);
--color-select-caret: rgba(var(--color-gray-200-rgb), 0.8);
/* Common style patterns - updated for dark mode */
--focus-ring: 0 0 0 3px var(--color-focus-ring);
--focus-outline: 2px solid var(--color-primary);
--status-bg-opacity: 0.15;
--status-border-opacity: 0.25;
--select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
--select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
/* RGB versions for dark mode */
--color-success-rgb: var(--color-teal-300-rgb);
--color-error-rgb: var(--color-red-400-rgb);
--color-warning-rgb: var(--color-orange-400-rgb);
--color-info-rgb: var(--color-gray-300-rgb);
}
[data-color-scheme="light"] {
/* RGB versions for opacity control (light mode) */
--color-brown-600-rgb: 94, 82, 64;
--color-teal-500-rgb: 33, 128, 141;
--color-slate-900-rgb: 19, 52, 59;
/* Semantic Color Tokens (Light Mode) */
--color-background: var(--color-cream-50);
--color-surface: var(--color-cream-100);
--color-text: var(--color-slate-900);
--color-text-secondary: var(--color-slate-500);
--color-primary: var(--color-teal-500);
--color-primary-hover: var(--color-teal-600);
--color-primary-active: var(--color-teal-700);
--color-secondary: rgba(var(--color-brown-600-rgb), 0.12);
--color-secondary-hover: rgba(var(--color-brown-600-rgb), 0.2);
--color-secondary-active: rgba(var(--color-brown-600-rgb), 0.25);
--color-border: rgba(var(--color-brown-600-rgb), 0.2);
--color-btn-primary-text: var(--color-cream-50);
--color-card-border: rgba(var(--color-brown-600-rgb), 0.12);
--color-card-border-inner: rgba(var(--color-brown-600-rgb), 0.12);
--color-error: var(--color-red-500);
--color-success: var(--color-teal-500);
--color-warning: var(--color-orange-500);
--color-info: var(--color-slate-500);
--color-focus-ring: rgba(var(--color-teal-500-rgb), 0.4);
/* RGB versions for light mode */
--color-success-rgb: var(--color-teal-500-rgb);
--color-error-rgb: var(--color-red-500-rgb);
--color-warning-rgb: var(--color-orange-500-rgb);
--color-info-rgb: var(--color-slate-500-rgb);
}
/* Base styles */
html {
font-size: var(--font-size-base);
font-family: var(--font-family-base);
line-height: var(--line-height-normal);
color: var(--color-text);
background-color: var(--color-background);
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
/* Typography */
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
font-weight: var(--font-weight-semibold);
line-height: var(--line-height-tight);
color: var(--color-text);
letter-spacing: var(--letter-spacing-tight);
}
h1 {
font-size: var(--font-size-4xl);
}
h2 {
font-size: var(--font-size-3xl);
}
h3 {
font-size: var(--font-size-2xl);
}
h4 {
font-size: var(--font-size-xl);
}
h5 {
font-size: var(--font-size-lg);
}
h6 {
font-size: var(--font-size-md);
}
p {
margin: 0 0 var(--space-16) 0;
}
a {
color: var(--color-primary);
text-decoration: none;
transition: color var(--duration-fast) var(--ease-standard);
}
a:hover {
color: var(--color-primary-hover);
}
code,
pre {
font-family: var(--font-family-mono);
font-size: calc(var(--font-size-base) * 0.95);
background-color: var(--color-secondary);
border-radius: var(--radius-sm);
}
code {
padding: var(--space-1) var(--space-4);
}
pre {
padding: var(--space-16);
margin: var(--space-16) 0;
overflow: auto;
border: 1px solid var(--color-border);
}
pre code {
background: none;
padding: 0;
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--space-8) var(--space-16);
border-radius: var(--radius-base);
font-size: var(--font-size-base);
font-weight: 500;
line-height: 1.5;
cursor: pointer;
transition: all var(--duration-normal) var(--ease-standard);
border: none;
text-decoration: none;
position: relative;
}
.btn:focus-visible {
outline: none;
box-shadow: var(--focus-ring);
}
.btn--primary {
background: var(--color-primary);
color: var(--color-btn-primary-text);
}
.btn--primary:hover {
background: var(--color-primary-hover);
}
.btn--primary:active {
background: var(--color-primary-active);
}
.btn--secondary {
background: var(--color-secondary);
color: var(--color-text);
}
.btn--secondary:hover {
background: var(--color-secondary-hover);
}
.btn--secondary:active {
background: var(--color-secondary-active);
}
.btn--outline {
background: transparent;
border: 1px solid var(--color-border);
color: var(--color-text);
}
.btn--outline:hover {
background: var(--color-secondary);
}
.btn--sm {
padding: var(--space-4) var(--space-12);
font-size: var(--font-size-sm);
border-radius: var(--radius-sm);
}
.btn--lg {
padding: var(--space-10) var(--space-20);
font-size: var(--font-size-lg);
border-radius: var(--radius-md);
}
.btn--full-width {
width: 100%;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Form elements */
.form-control {
display: block;
width: 100%;
padding: var(--space-8) var(--space-12);
font-size: var(--font-size-md);
line-height: 1.5;
color: var(--color-text);
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-base);
transition: border-color var(--duration-fast) var(--ease-standard),
box-shadow var(--duration-fast) var(--ease-standard);
}
textarea.form-control {
font-family: var(--font-family-base);
font-size: var(--font-size-base);
}
select.form-control {
padding: var(--space-8) var(--space-12);
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-image: var(--select-caret-light);
background-repeat: no-repeat;
background-position: right var(--space-12) center;
background-size: 16px;
padding-right: var(--space-32);
}
/* Add a dark mode specific caret */
@media (prefers-color-scheme: dark) {
select.form-control {
background-image: var(--select-caret-dark);
}
}
/* Also handle data-color-scheme */
[data-color-scheme="dark"] select.form-control {
background-image: var(--select-caret-dark);
}
[data-color-scheme="light"] select.form-control {
background-image: var(--select-caret-light);
}
.form-control:focus {
border-color: var(--color-primary);
outline: var(--focus-outline);
}
.form-label {
display: block;
margin-bottom: var(--space-8);
font-weight: var(--font-weight-medium);
font-size: var(--font-size-sm);
}
.form-group {
margin-bottom: var(--space-16);
}
/* Card component */
.card {
background-color: var(--color-surface);
border-radius: var(--radius-lg);
border: 1px solid var(--color-card-border);
box-shadow: var(--shadow-sm);
overflow: hidden;
transition: box-shadow var(--duration-normal) var(--ease-standard);
}
.card:hover {
box-shadow: var(--shadow-md);
}
.card__body {
padding: var(--space-16);
}
.card__header,
.card__footer {
padding: var(--space-16);
border-bottom: 1px solid var(--color-card-border-inner);
}
/* Status indicators - simplified with CSS variables */
.status {
display: inline-flex;
align-items: center;
padding: var(--space-6) var(--space-12);
border-radius: var(--radius-full);
font-weight: var(--font-weight-medium);
font-size: var(--font-size-sm);
}
.status--success {
background-color: rgba(
var(--color-success-rgb, 33, 128, 141),
var(--status-bg-opacity)
);
color: var(--color-success);
border: 1px solid
rgba(var(--color-success-rgb, 33, 128, 141), var(--status-border-opacity));
}
.status--error {
background-color: rgba(
var(--color-error-rgb, 192, 21, 47),
var(--status-bg-opacity)
);
color: var(--color-error);
border: 1px solid
rgba(var(--color-error-rgb, 192, 21, 47), var(--status-border-opacity));
}
.status--warning {
background-color: rgba(
var(--color-warning-rgb, 168, 75, 47),
var(--status-bg-opacity)
);
color: var(--color-warning);
border: 1px solid
rgba(var(--color-warning-rgb, 168, 75, 47), var(--status-border-opacity));
}
.status--info {
background-color: rgba(
var(--color-info-rgb, 98, 108, 113),
var(--status-bg-opacity)
);
color: var(--color-info);
border: 1px solid
rgba(var(--color-info-rgb, 98, 108, 113), var(--status-border-opacity));
}
/* Container layout */
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: var(--space-16);
padding-left: var(--space-16);
}
@media (min-width: 640px) {
.container {
max-width: var(--container-sm);
}
}
@media (min-width: 768px) {
.container {
max-width: var(--container-md);
}
}
@media (min-width: 1024px) {
.container {
max-width: var(--container-lg);
}
}
@media (min-width: 1280px) {
.container {
max-width: var(--container-xl);
}
}
/* Utility classes */
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.justify-between {
justify-content: space-between;
}
.gap-4 {
gap: var(--space-4);
}
.gap-8 {
gap: var(--space-8);
}
.gap-16 {
gap: var(--space-16);
}
.m-0 {
margin: 0;
}
.mt-8 {
margin-top: var(--space-8);
}
.mb-8 {
margin-bottom: var(--space-8);
}
.mx-8 {
margin-left: var(--space-8);
margin-right: var(--space-8);
}
.my-8 {
margin-top: var(--space-8);
margin-bottom: var(--space-8);
}
.p-0 {
padding: 0;
}
.py-8 {
padding-top: var(--space-8);
padding-bottom: var(--space-8);
}
.px-8 {
padding-left: var(--space-8);
padding-right: var(--space-8);
}
.py-16 {
padding-top: var(--space-16);
padding-bottom: var(--space-16);
}
.px-16 {
padding-left: var(--space-16);
padding-right: var(--space-16);
}
.block {
display: block;
}
.hidden {
display: none;
}
/* Accessibility */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
:focus-visible {
outline: var(--focus-outline);
outline-offset: 2px;
}
/* Dark mode specifics */
[data-color-scheme="dark"] .btn--outline {
border: 1px solid var(--color-border-secondary);
}
@font-face {
font-family: 'FKGroteskNeue';
src: url('https://r2cdn.perplexity.ai/fonts/FKGroteskNeue.woff2')
format('woff2');
}
/* END PERPLEXITY DESIGN SYSTEM */
/* Modern glassmorphism and beautiful video calling styles */
/* Reset and base styles */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* CSS Variables for the modern theme */
:root {
/* Modern gradient colors */
--gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--gradient-secondary: linear-gradient(135deg, #00D4FF 0%, #4ECDC4 100%);
--gradient-accent: linear-gradient(135deg, #FF6B6B 0%, #FFD93D 100%);
/* Glassmorphism colors */
--glass-bg: rgba(255, 255, 255, 0.1);
--glass-border: rgba(255, 255, 255, 0.2);
--glass-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
--glass-blur: blur(12px);
/* Accent colors */
--accent-cyan: #00D4FF;
--accent-coral: #FF6B6B;
--accent-mint: #4ECDC4;
--accent-purple: #A8E6CF;
--accent-gold: #FFD93D;
/* Animation variables */
--animation-fast: 0.2s;
--animation-normal: 0.3s;
--animation-slow: 0.5s;
--ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
--ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
/* Typography */
--font-primary: 'Poppins', system-ui, -apple-system, sans-serif;
/* Shadows */
--shadow-soft: 0 10px 40px rgba(0, 0, 0, 0.1);
--shadow-medium: 0 20px 60px rgba(0, 0, 0, 0.15);
--shadow-strong: 0 30px 80px rgba(0, 0, 0, 0.2);
/* Dark theme colors */
--dark-bg-primary: #0a0a0f;
--dark-bg-secondary: #1a1a24;
--dark-text-primary: #ffffff;
--dark-text-secondary: #a0a0a0;
}
body {
font-family: var(--font-primary);
background: var(--gradient-primary);
color: var(--color-text);
line-height: 1.6;
overflow-x: hidden;
min-height: 100vh;
position: relative;
}
body.dark-theme {
background: linear-gradient(135deg, var(--dark-bg-primary) 0%, var(--dark-bg-secondary) 100%);
color: var(--dark-text-primary);
}
/* Particle Background */
.particles-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
opacity: 0.6;
}
.particle {
position: absolute;
background: var(--accent-cyan);
border-radius: 50%;
animation: float 6s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0) rotate(0deg); opacity: 0.3; }
50% { transform: translateY(-20px) rotate(180deg); opacity: 0.8; }
}
/* Header */
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border-bottom: 1px solid var(--glass-border);
z-index: 1000;
transition: all var(--animation-normal) var(--ease-smooth);
}
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-16) 0;
max-width: 1200px;
margin: 0 auto;
padding-left: var(--space-20);
padding-right: var(--space-20);
}
.brand {
display: flex;
align-items: center;
gap: var(--space-16);
}
.brand-logo {
display: flex;
align-items: center;
gap: var(--space-12);
}
.brand-icon {
font-size: var(--font-size-2xl);
background: var(--gradient-secondary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
.brand-name {
font-size: var(--font-size-2xl);
font-weight: 800;
background: var(--gradient-primary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin: 0;
}
.brand-slogan {
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
margin: 0;
opacity: 0.8;
}
.nav {
display: flex;
align-items: center;
gap: var(--space-20);
}
.nav-toggle {
display: none;
background: none;
border: none;
font-size: var(--font-size-lg);
color: var(--color-text);
cursor: pointer;
padding: var(--space-8);
border-radius: var(--radius-base);
transition: all var(--animation-fast) var(--ease-smooth);
}
.nav-toggle:hover {
background: var(--glass-bg);
}
.nav-list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
gap: var(--space-8);
}
.nav-link {
padding: var(--space-12) var(--space-20);
border-radius: var(--radius-full);
transition: all var(--animation-normal) var(--ease-smooth);
font-weight: 500;
text-decoration: none;
color: var(--color-text);
position: relative;
overflow: hidden;
}
.nav-link::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: var(--gradient-secondary);
transition: left var(--animation-normal) var(--ease-smooth);
border-radius: var(--radius-full);
z-index: -1;
}
.nav-link:hover::before,
.nav-link.active::before {
left: 0;
}
.nav-link:hover,
.nav-link.active {
color: white;
transform: translateY(-2px);
}
.theme-toggle {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--radius-full);
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all var(--animation-normal) var(--ease-smooth);
color: var(--color-text);
}
.theme-toggle:hover {
background: var(--glass-border);
transform: scale(1.1);
}
/* Main content */
.main {
min-height: 100vh;
padding-top: 80px;
}
.page {
display: none;
min-height: calc(100vh - 80px);
animation: fadeIn var(--animation-normal) var(--ease-smooth);
}
.page.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 var(--space-20);
}
/* Hero section */
.hero {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-32);
align-items: center;
min-height: 80vh;
padding: var(--space-32) 0;
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: var(--space-8);
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
padding: var(--space-8) var(--space-16);
border-radius: var(--radius-full);
border: 1px solid var(--glass-border);
font-size: var(--font-size-sm);
font-weight: 500;
margin-bottom: var(--space-24);
color: var(--accent-gold);
animation: slideInLeft var(--animation-slow) var(--ease-bounce);
}
.hero-badge i {
animation: sparkle 1.5s ease-in-out infinite;
}
@keyframes sparkle {
0%, 100% { transform: scale(1) rotate(0deg); }
50% { transform: scale(1.2) rotate(180deg); }
}
.hero-title {
font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 800;
line-height: 1.1;
margin-bottom: var(--space-24);
animation: slideInLeft var(--animation-slow) var(--ease-bounce) 0.2s;
}
.gradient-text {
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-description {
font-size: var(--font-size-lg);
color: var(--color-text-secondary);
margin-bottom: var(--space-32);
line-height: 1.7;
animation: slideInLeft var(--animation-slow) var(--ease-bounce) 0.4s;
}
.hero-actions {
display: flex;
gap: var(--space-20);
margin-bottom: var(--space-32);
flex-wrap: wrap;
animation: slideInLeft var(--animation-slow) var(--ease-bounce) 0.6s;
}
.hero-stats {
display: flex;
gap: var(--space-32);
animation: slideInLeft var(--animation-slow) var(--ease-bounce) 0.8s;
}
.stat-item {
text-align: center;
}
.stat-number {
display: block;
font-size: var(--font-size-2xl);
font-weight: 800;
background: var(--gradient-secondary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.stat-label {
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
font-weight: 500;
}
/* Hero visual */
.hero-visual {
position: relative;
animation: slideInRight var(--animation-slow) var(--ease-bounce);
}
.hero-image {
position: relative;
height: 400px;
display: flex;
align-items: center;
justify-content: center;
}
.floating-card {
position: absolute;
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
padding: var(--space-16);
box-shadow: var(--shadow-soft);
animation: float 3s ease-in-out infinite;
min-width: 120px;
}
.floating-card.card-1 {
top: 20%;
left: 10%;
animation-delay: 0s;
}
.floating-card.card-2 {
top: 60%;
right: 20%;
animation-delay: 1s;
}
.floating-card.card-3 {
bottom: 20%;
left: 20%;
animation-delay: 2s;
}
.mock-video {
width: 80px;
height: 60px;
background: var(--gradient-primary);
border-radius: var(--radius-base);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: var(--font-size-lg);
margin-bottom: var(--space-8);
}
.participant-name {
font-size: var(--font-size-sm);
font-weight: 500;
text-align: center;
color: var(--color-text);
}
.floating-elements {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.floating-icon {
position: absolute;
width: 40px;
height: 40px;
background: var(--gradient-accent);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: var(--font-size-base);
animation: floatIcon 4s ease-in-out infinite;
}
.floating-icon.icon-1 {
top: 10%;
right: 10%;
animation-delay: 0.5s;
}
.floating-icon.icon-2 {
bottom: 30%;
right: 5%;
animation-delay: 1.5s;
}
.floating-icon.icon-3 {
top: 50%;
left: 5%;
animation-delay: 2.5s;
}
@keyframes floatIcon {
0%, 100% { transform: translateY(0) rotate(0deg) scale(1); }
25% { transform: translateY(-10px) rotate(90deg) scale(1.1); }
50% { transform: translateY(5px) rotate(180deg) scale(0.9); }
75% { transform: translateY(-5px) rotate(270deg) scale(1.1); }
}
@keyframes slideInLeft {
from { opacity: 0; transform: translateX(-50px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes slideInRight {
from { opacity: 0; transform: translateX(50px); }
to { opacity: 1; transform: translateX(0); }
}
/* Button styles */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-8);
padding: var(--space-12) var(--space-24);
border-radius: var(--radius-base);
font-size: var(--font-size-base);
font-weight: 600;
font-family: var(--font-primary);
cursor: pointer;
transition: all var(--animation-normal) var(--ease-smooth);
border: none;
text-decoration: none;
position: relative;
overflow: hidden;
user-select: none;
min-height: 44px;
}
.btn--animated {
position: relative;
overflow: hidden;
}
.btn-ripple {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: scale(0);
animation: ripple 0.6s linear;
pointer-events: none;
}
@keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
.btn--primary {
background: var(--gradient-secondary);
color: white;
border: none;
box-shadow: var(--shadow-soft);
}
.btn--primary:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-medium);
}
.btn--primary:active {
transform: translateY(-1px);
}
.btn--outline {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
color: var(--color-text);
backdrop-filter: var(--glass-blur);
}
.btn--outline:hover {
background: var(--glass-border);
border-color: var(--accent-cyan);
color: var(--accent-cyan);
transform: translateY(-2px);
}
.btn--lg {
padding: var(--space-16) var(--space-32);
font-size: var(--font-size-lg);
border-radius: var(--radius-lg);
min-height: 56px;
}
.btn--sm {
padding: var(--space-8) var(--space-16);
font-size: var(--font-size-sm);
min-height: 36px;
}
.btn--full-width {
width: 100%;
}
.cta-button {
background: var(--gradient-primary);
transform: translateY(0);
box-shadow: var(--shadow-medium);
}
.cta-button:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-strong);
}
/* Features section */
.features-section {
padding: var(--space-32) 0;
margin-top: var(--space-32);
}
.section-header {
text-align: center;
margin-bottom: var(--space-32);
}
.section-title {
font-size: var(--font-size-4xl);
font-weight: 800;
margin-bottom: var(--space-16);
background: var(--gradient-primary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.section-description {
font-size: var(--font-size-lg);
color: var(--color-text-secondary);
max-width: 600px;
margin: 0 auto;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: var(--space-24);
margin-top: var(--space-32);
}
.feature-card {
position: relative;
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
padding: var(--space-32);
text-align: center;
transition: all var(--animation-normal) var(--ease-smooth);
overflow: hidden;
}
.feature-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--gradient-secondary);
transform: scaleX(0);
transition: transform var(--animation-normal) var(--ease-smooth);
}
.feature-card:hover::before {
transform: scaleX(1);
}
.feature-card:hover {
transform: translateY(-8px);
box-shadow: var(--shadow-medium);
border-color: var(--accent-cyan);
}
.feature-icon {
width: 80px;
height: 80px;
margin: 0 auto var(--space-20);
background: var(--gradient-accent);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: var(--font-size-2xl);
color: white;
position: relative;
overflow: hidden;
}
.feature-icon::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: all var(--animation-normal) var(--ease-smooth);
}
.feature-card:hover .feature-icon::after {
width: 100%;
height: 100%;
}
.feature-title {
font-size: var(--font-size-xl);
font-weight: 700;
margin-bottom: var(--space-12);
color: var(--color-text);
}
.feature-description {
color: var(--color-text-secondary);
line-height: 1.6;
margin: 0;
}
.feature-glow {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 200px;
background: radial-gradient(circle, rgba(102, 126, 234, 0.1) 0%, transparent 70%);
border-radius: 50%;
transform: translate(-50%, -50%);
opacity: 0;
transition: opacity var(--animation-normal) var(--ease-smooth);
pointer-events: none;
}
.feature-card:hover .feature-glow {
opacity: 1;
}
/* Testimonials */
.testimonials-section {
padding: var(--space-32) 0;
text-align: center;
}
.testimonials-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: var(--space-24);
margin-top: var(--space-32);
}
.testimonial-card {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
padding: var(--space-32);
transition: all var(--animation-normal) var(--ease-smooth);
}
.testimonial-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-medium);
}
.testimonial-content p {
font-size: var(--font-size-lg);
font-style: italic;
color: var(--color-text);
margin-bottom: var(--space-24);
}
.testimonial-author {
display: flex;
align-items: center;
gap: var(--space-16);
margin-bottom: var(--space-16);
}
.author-avatar {
width: 50px;
height: 50px;
background: var(--gradient-primary);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: var(--font-size-lg);
}
.author-info {
text-align: left;
}
.author-name {
display: block;
font-weight: 600;
color: var(--color-text);
}
.author-role {
display: block;
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
}
.testimonial-rating {
color: var(--accent-gold);
}
/* Glass card styles */
.glass-card {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-soft);
}
/* Room setup */
.room-setup {
max-width: 600px;
margin: 0 auto;
padding: var(--space-32) 0;
}
.setup-content {
padding: var(--space-32);
animation: slideInUp var(--animation-slow) var(--ease-bounce);
}
@keyframes slideInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
.setup-header {
text-align: center;
margin-bottom: var(--space-32);
}
.setup-icon {
width: 80px;
height: 80px;
margin: 0 auto var(--space-20);
background: var(--gradient-secondary);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: var(--font-size-2xl);
color: white;
animation: bounce 2s ease-in-out infinite;
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-10px); }
60% { transform: translateY(-5px); }
}
.setup-header h2 {
font-size: var(--font-size-3xl);
font-weight: 700;
margin-bottom: var(--space-12);
color: var(--color-text);
}
.setup-header p {
color: var(--color-text-secondary);
font-size: var(--font-size-lg);
}
/* Form styles */
.form-group {
margin-bottom: var(--space-24);
}
.form-label {
display: flex;
align-items: center;
gap: var(--space-8);
margin-bottom: var(--space-8);
font-weight: 600;
color: var(--color-text);
font-size: var(--font-size-sm);
}
.form-control {
width: 100%;
padding: var(--space-16);
border: 1px solid var(--glass-border);
border-radius: var(--radius-base);
font-size: var(--font-size-base);
font-family: var(--font-primary);
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
color: var(--color-text);
transition: all var(--animation-fast) var(--ease-smooth);
}
.form-control:focus {
outline: none;
border-color: var(--accent-cyan);
box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.1);
background: var(--glass-border);
}
.form-control::placeholder {
color: var(--color-text-secondary);
}
.input-group {
display: flex;
gap: var(--space-12);
}
.input-group .form-control {
flex: 1;
}
/* Device preview */
.device-preview {
margin: var(--space-32) 0;
}
.device-preview h3 {
display: flex;
align-items: center;
gap: var(--space-8);
margin-bottom: var(--space-20);
text-align: center;
justify-content: center;
font-size: var(--font-size-lg);
color: var(--color-text);
}
.preview-container {
position: relative;
width: 100%;
height: 240px;
background: linear-gradient(135deg, var(--dark-bg-primary), var(--dark-bg-secondary));
border-radius: var(--radius-lg);
overflow: hidden;
border: 2px solid var(--glass-border);
box-shadow: var(--shadow-soft);
}
.preview-container video {
width: 100%;
height: 100%;
object-fit: cover;
}
.preview-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: white;
backdrop-filter: blur(10px);
}
.preview-overlay i {
font-size: var(--font-size-4xl);
margin-bottom: var(--space-16);
opacity: 0.6;
}
.preview-overlay p {
font-size: var(--font-size-lg);
margin: 0;
opacity: 0.8;
}
.preview-effects {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.effect-dot {
position: absolute;
width: 8px;
height: 8px;
background: var(--accent-cyan);
border-radius: 50%;
animation: pulse 2s ease-in-out infinite;
}
.effect-dot.dot-1 {
top: 20%;
left: 20%;
animation-delay: 0s;
}
.effect-dot.dot-2 {
top: 60%;
right: 30%;
animation-delay: 0.7s;
}
.effect-dot.dot-3 {
bottom: 30%;
left: 60%;
animation-delay: 1.4s;
}
.preview-controls {
display: flex;
gap: var(--space-16);
justify-content: center;
margin-top: var(--space-20);
}
.preview-control {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-base);
padding: var(--space-12) var(--space-20);
display: flex;
align-items: center;
gap: var(--space-8);
color: var(--color-text);
font-family: var(--font-primary);
font-weight: 500;
cursor: pointer;
transition: all var(--animation-normal) var(--ease-smooth);
}
.preview-control:hover {
background: var(--glass-border);
border-color: var(--accent-cyan);
color: var(--accent-cyan);
transform: translateY(-2px);
}
.preview-control.muted {
background: var(--accent-coral);
border-color: var(--accent-coral);
color: white;
}
/* Call interface */
.call-page {
padding: 0;
}
.call-interface {
height: 100vh;
display: flex;
flex-direction: column;
background: var(--dark-bg-primary);
color: var(--dark-text-primary);
}
.glass-header {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border-bottom: 1px solid var(--glass-border);
}
.call-header {
padding: var(--space-20) var(--space-24);
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.room-info h3 {
margin: 0 0 var(--space-8) 0;
font-size: var(--font-size-xl);
color: var(--dark-text-primary);
}
.call-status {
display: flex;
align-items: center;
gap: var(--space-12);
font-size: var(--font-size-sm);
color: var(--dark-text-secondary);
}
.timer {
font-family: var(--font-family-mono);
font-weight: 600;
color: var(--accent-cyan);
}
.participant-count {
color: var(--accent-mint);
}
.status {
display: flex;
align-items: center;
gap: var(--space-4);
font-weight: 500;
}
.status--success {
color: var(--accent-mint);
}
.status i {
animation: pulse 2s ease-in-out infinite;
}
.separator {
color: var(--dark-text-secondary);
opacity: 0.5;
}
.call-actions-top {
display: flex;
gap: var(--space-12);
}
/* Video container */
.video-container {
flex: 1;
position: relative;
background: var(--dark-bg-secondary);
overflow: hidden;
}
.video-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: var(--space-16);
padding: var(--space-20);
height: 100%;
align-content: center;
}
.video-tile {
position: relative;
background: var(--dark-bg-primary);
border-radius: var(--radius-lg);
overflow: hidden;
aspect-ratio: 16/9;
min-height: 200px;
transition: all var(--animation-normal) var(--ease-smooth);
}
.glass-video {
border: 1px solid var(--glass-border);
box-shadow: var(--shadow-soft);
}
.video-tile:hover {
transform: scale(1.02);
box-shadow: var(--shadow-medium);
}
.video-tile video {
width: 100%;
height: 100%;
object-fit: cover;
}
.video-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
padding: var(--space-16);
display: flex;
align-items: center;
justify-content: space-between;
backdrop-filter: blur(10px);
}
.video-overlay .participant-name {
color: white;
font-weight: 600;
font-size: var(--font-size-sm);
display: flex;
align-items: center;
gap: var(--space-8);
}
.video-controls-mini {
display: flex;
gap: var(--space-8);
}
.mute-indicator {
background: var(--accent-coral);
color: white;
padding: var(--space-6);
border-radius: var(--radius-sm);
font-size: var(--font-size-xs);
}
.video-effects {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.pulse-ring {
position: absolute;
top: 50%;
left: 50%;
width: 100px;
height: 100px;
border: 2px solid var(--accent-cyan);
border-radius: 50%;
transform: translate(-50%, -50%);
opacity: 0;
animation: pulseRing 3s ease-in-out infinite;
}
@keyframes pulseRing {
0% {
transform: translate(-50%, -50%) scale(0.5);
opacity: 1;
}
50% {
transform: translate(-50%, -50%) scale(1.2);
opacity: 0.3;
}
100% {
transform: translate(-50%, -50%) scale(1.5);
opacity: 0;
}
}
/* Call controls */
.glass-controls {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border-top: 1px solid var(--glass-border);
}
.call-controls {
padding: var(--space-24);
flex-shrink: 0;
}
.controls-group {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-20);
}
.control-btn {
width: 60px;
height: 60px;
border-radius: 50%;
border: none;
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
color: var(--dark-text-primary);
font-size: var(--font-size-lg);
cursor: pointer;
transition: all var(--animation-normal) var(--ease-smooth);
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.animated-btn {
position: relative;
overflow: hidden;
}
.control-btn:hover {
background: var(--glass-border);
transform: scale(1.1);
box-shadow: var(--shadow-soft);
}
.control-btn.active {
background: var(--accent-cyan);
color: white;
border-color: var(--accent-cyan);
}
.control-btn.muted {
background: var(--accent-coral);
color: white;
border-color: var(--accent-coral);
}
.control-btn.end-call {
background: var(--accent-coral);
color: white;
border-color: var(--accent-coral);
}
.control-btn.end-call:hover {
background: #ff5252;
transform: scale(1.1);
}
/* Reactions */
.reactions-container {
position: fixed;
top: 50%;
left: 50%;
width: 200px;
height: 200px;
transform: translate(-50%, -50%);
pointer-events: none;
z-index: 1000;
}
.reaction-emoji {
position: absolute;
font-size: var(--font-size-2xl);
animation: floatReaction 3s ease-out forwards;
pointer-events: none;
}
@keyframes floatReaction {
0% {
transform: scale(0) rotate(0deg);
opacity: 1;
}
20% {
transform: scale(1.5) rotate(180deg);
opacity: 1;
}
100% {
transform: scale(0.5) rotate(360deg) translateY(-100px);
opacity: 0;
}
}
/* Chat panel */
.glass-panel {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border-left: 1px solid var(--glass-border);
}
.chat-panel {
position: fixed;
top: 0;
right: -400px;
width: 400px;
height: 100vh;
display: flex;
flex-direction: column;
transition: right var(--animation-normal) var(--ease-smooth);
z-index: 1001;
box-shadow: var(--shadow-strong);
}
.chat-panel.active {
right: 0;
}
.chat-header {
padding: var(--space-20);
border-bottom: 1px solid var(--glass-border);
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.chat-header h3 {
margin: 0;
color: var(--dark-text-primary);
display: flex;
align-items: center;
gap: var(--space-8);
}
.chat-messages {
flex: 1;
padding: var(--space-20);
overflow-y: auto;
background: rgba(0, 0, 0, 0.2);
}
.system-message {
text-align: center;
color: var(--dark-text-secondary);
font-size: var(--font-size-sm);
margin-bottom: var(--space-20);
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-8);
background: var(--glass-bg);
padding: var(--space-12);
border-radius: var(--radius-base);
backdrop-filter: var(--glass-blur);
}
.chat-message {
margin-bottom: var(--space-16);
padding: var(--space-12) var(--space-16);
background: var(--glass-bg);
border-radius: var(--radius-base);
border-left: 3px solid var(--accent-cyan);
backdrop-filter: var(--glass-blur);
animation: slideInRight 0.3s var(--ease-smooth);
}
@keyframes slideInRight {
from { opacity: 0; transform: translateX(20px); }
to { opacity: 1; transform: translateX(0); }
}
.message-sender {
font-weight: 600;
font-size: var(--font-size-sm);
color: var(--accent-cyan);
margin-bottom: var(--space-4);
}
.message-content {
margin: 0;
color: var(--dark-text-primary);
line-height: 1.5;
}
.message-time {
font-size: var(--font-size-xs);
color: var(--dark-text-secondary);
margin-top: var(--space-8);
}
.chat-input {
padding: var(--space-20);
border-top: 1px solid var(--glass-border);
display: flex;
gap: var(--space-8);
flex-shrink: 0;
background: var(--glass-bg);
}
.chat-input input {
flex: 1;
background: rgba(0, 0, 0, 0.3);
border: 1px solid var(--glass-border);
color: var(--dark-text-primary);
}
.chat-input input::placeholder {
color: var(--dark-text-secondary);
}
.emoji-btn {
background: none;
border: none;
font-size: var(--font-size-lg);
cursor: pointer;
padding: var(--space-8);
border-radius: var(--radius-base);
transition: all var(--animation-fast) var(--ease-smooth);
}
.emoji-btn:hover {
background: var(--glass-bg);
transform: scale(1.1);
}
/* Modals */
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
padding: var(--space-20);
backdrop-filter: blur(10px);
animation: fadeIn var(--animation-normal) var(--ease-smooth);
}
.modal.hidden {
display: none;
}
.modal-content {
max-width: 600px;
width: 100%;
max-height: 80vh;
overflow-y: auto;
animation: scaleIn var(--animation-normal) var(--ease-bounce);
}
@keyframes scaleIn {
from { transform: scale(0.9); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
.modal-header {
padding: var(--space-24);
border-bottom: 1px solid var(--glass-border);
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-header h3 {
margin: 0;
color: var(--color-text);
display: flex;
align-items: center;
gap: var(--space-8);
}
.modal-body {
padding: var(--space-24);
}
/* Share modal */
.share-section {
margin-bottom: var(--space-32);
}
.share-section h4 {
margin-bottom: var(--space-16);
color: var(--color-text);
display: flex;
align-items: center;
gap: var(--space-8);
}
.share-link {
display: flex;
gap: var(--space-8);
}
.share-link input {
flex: 1;
}
.qr-container {
text-align: center;
}
.qr-code {
background: white;
padding: var(--space-16);
border-radius: var(--radius-base);
margin-bottom: var(--space-16);
box-shadow: var(--shadow-soft);
}
.social-buttons {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: var(--space-12);
}
.social-btn {
padding: var(--space-12) var(--space-16);
border: none;
border-radius: var(--radius-base);
color: white;
font-weight: 600;
cursor: pointer;
transition: all var(--animation-normal) var(--ease-smooth);
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-8);
font-family: var(--font-primary);
}
.social-btn:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-soft);
}
.social-btn.whatsapp { background: #25D366; }
.social-btn.telegram { background: #0088cc; }
.social-btn.twitter { background: #1DA1F2; }
.social-btn.facebook { background: #4267B2; }
.social-btn.linkedin { background: #0077b5; }
/* Signaling modal */
.signaling-step {
margin-bottom: var(--space-24);
padding: var(--space-24);
background: var(--glass-bg);
border-radius: var(--radius-base);
border: 1px solid var(--glass-border);
backdrop-filter: var(--glass-blur);
}
.signaling-step h4 {
margin: 0 0 var(--space-12) 0;
color: var(--accent-cyan);
display: flex;
align-items: center;
gap: var(--space-8);
}
.signaling-step p {
margin-bottom: var(--space-16);
color: var(--color-text-secondary);
line-height: 1.6;
}
.signaling-step textarea {
margin-bottom: var(--space-16);
min-height: 80px;
font-family: var(--font-family-mono);
font-size: var(--font-size-sm);
resize: vertical;
}
/* Loading overlay */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.9);
display: flex;
align-items: center;
justify-content: center;
z-index: 3000;
backdrop-filter: blur(10px);
}
.loading-overlay.hidden {
display: none;
}
.loading-spinner {
text-align: center;
color: white;
}
.spinner-ring {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
margin-bottom: var(--space-24);
}
.spinner-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 64px;
height: 64px;
margin: 8px;
border: 8px solid var(--accent-cyan);
border-radius: 50%;
animation: spin 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: var(--accent-cyan) transparent transparent transparent;
}
.spinner-ring div:nth-child(1) { animation-delay: -0.45s; }
.spinner-ring div:nth-child(2) { animation-delay: -0.3s; }
.spinner-ring div:nth-child(3) { animation-delay: -0.15s; }
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
margin: 0;
font-size: var(--font-size-lg);
font-weight: 500;
color: var(--accent-cyan);
}
/* Toast notifications */
.toast-container {
position: fixed;
top: var(--space-20);
right: var(--space-20);
z-index: 4000;
display: flex;
flex-direction: column;
gap: var(--space-8);
}
.toast {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-base);
padding: var(--space-16) var(--space-20);
color: white;
font-weight: 500;
box-shadow: var(--shadow-medium);
animation: slideInToast 0.3s var(--ease-bounce);
max-width: 300px;
position: relative;
overflow: hidden;
}
.toast::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: var(--gradient-secondary);
}
.toast.success::before { background: var(--accent-mint); }
.toast.error::before { background: var(--accent-coral); }
.toast.warning::before { background: var(--accent-gold); }
@keyframes slideInToast {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
/* Achievement modal */
.achievement-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 5000;
backdrop-filter: blur(10px);
animation: fadeIn var(--animation-normal) var(--ease-smooth);
}
.achievement-modal.hidden {
display: none;
}
.achievement-content {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
padding: var(--space-32);
text-align: center;
max-width: 400px;
animation: bounceIn 0.6s var(--ease-bounce);
position: relative;
overflow: hidden;
}
.achievement-content::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: conic-gradient(var(--accent-gold), var(--accent-cyan), var(--accent-coral), var(--accent-mint), var(--accent-gold));
animation: rotate 3s linear infinite;
z-index: -1;
}
.achievement-content::after {
content: '';
position: absolute;
top: 3px;
left: 3px;
right: 3px;
bottom: 3px;
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border-radius: calc(var(--radius-lg) - 3px);
z-index: -1;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes bounceIn {
0% { transform: scale(0); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.achievement-icon {
width: 80px;
height: 80px;
margin: 0 auto var(--space-20);
background: var(--gradient-accent);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: var(--font-size-2xl);
color: white;
animation: spin 1s ease-in-out;
}
.achievement-title {
font-size: var(--font-size-xl);
font-weight: 700;
margin-bottom: var(--space-12);
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.achievement-description {
color: var(--color-text-secondary);
margin-bottom: var(--space-24);
}
/* Responsive design */
@media (max-width: 1024px) {
.hero {
grid-template-columns: 1fr;
text-align: center;
gap: var(--space-24);
}
.features-grid {
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.testimonials-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.nav-toggle {
display: block;
}
.nav-list {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
border-top: 1px solid var(--glass-border);
flex-direction: column;
padding: var(--space-20);
gap: var(--space-8);
display: none;
box-shadow: var(--shadow-medium);
}
.nav-list.active {
display: flex;
}
.theme-toggle {
order: -1;
}
.hero-actions {
flex-direction: column;
align-items: center;
}
.hero-actions .btn {
width: 100%;
max-width: 300px;
}
.hero-stats {
flex-direction: column;
gap: var(--space-16);
}
.features-grid {
grid-template-columns: 1fr;
}
.setup-content {
margin: var(--space-16);
padding: var(--space-24);
}
.input-group {
flex-direction: column;
}
.call-header {
flex-direction: column;
gap: var(--space-16);
text-align: center;
}
.call-actions-top {
justify-content: center;
}
.video-grid {
grid-template-columns: 1fr;
gap: var(--space-12);
padding: var(--space-12);
}
.controls-group {
gap: var(--space-16);
flex-wrap: wrap;
justify-content: center;
}
.control-btn {
width: 52px;
height: 52px;
}
.chat-panel {
width: 100%;
right: -100%;
}
.modal-content {
margin: var(--space-16);
max-height: calc(100vh - 32px);
}
.social-buttons {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.container {
padding: 0 var(--space-16);
}
.hero {
padding: var(--space-20) 0;
min-height: 60vh;
}
.hero-title {
font-size: clamp(1.8rem, 8vw, 2.5rem);
}
.hero-actions .btn {
width: 100%;
}
.feature-card {
padding: var(--space-24);
}
.setup-content {
padding: var(--space-20);
}
.preview-container {
height: 180px;
}
.preview-controls {
flex-direction: column;
gap: var(--space-8);
}
.preview-control {
justify-content: center;
}
.video-tile {
min-height: 160px;
}
.controls-group {
gap: var(--space-12);
}
.control-btn {
width: 48px;
height: 48px;
font-size: var(--font-size-base);
}
.toast {
margin: var(--space-8);
max-width: calc(100% - var(--space-32));
}
.achievement-content {
margin: var(--space-16);
padding: var(--space-24);
}
}
/* Print styles */
@media print {
.header,
.call-controls,
.chat-panel,
.modal,
.loading-overlay,
.particles-container {
display: none !important;
}
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
*,
::before,
::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
// Enhanced FreeCall Video Calling App - Fixed Navigation & Functionality
class FreeCallApp {
constructor() {
this.localStream = null;
this.remoteStreams = new Map();
this.peerConnections = new Map();
this.dataChannels = new Map();
this.currentPage = 'home';
this.roomId = '';
this.participantName = '';
this.isAudioEnabled = true;
this.isVideoEnabled = true;
this.isScreenSharing = false;
this.isChatOpen = false;
this.callStartTime = null;
this.callTimer = null;
this.participants = new Set(['You']);
this.achievements = new Set();
this.isDarkTheme = false;
// Social sharing platforms
this.socialPlatforms = {
whatsapp: { url: 'https://wa.me/?text=', color: '#25D366' },
telegram: { url: 'https://t.me/share/url?url=', color: '#0088cc' },
twitter: { url: 'https://twitter.com/intent/tweet?text=', color: '#1DA1F2' },
facebook: { url: 'https://www.facebook.com/sharer/sharer.php?u=', color: '#4267B2' },
linkedin: { url: 'https://www.linkedin.com/sharing/share-offsite/?url=', color: '#0077b5' }
};
// Reaction emojis
this.reactions = ['❤️', '😂', '😮', '👏', '👍', '👎', '😢', '😡'];
console.log('🎥 FreeCall App initializing...');
this.init();
}
init() {
// Ensure DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.setupApp());
} else {
this.setupApp();
}
}
setupApp() {
console.log('📱 Setting up FreeCall application...');
// Generate initial room ID
this.generateRoomId();
// Setup core functionality
this.initParticles();
this.initTheme();
this.handleURLParams();
// Setup event listeners with explicit timing
setTimeout(() => {
this.setupAllEventListeners();
this.initScrollAnimations();
console.log('✅ FreeCall app ready!');
}, 100);
}
setupAllEventListeners() {
console.log('🔧 Setting up all event listeners...');
// Theme toggle
this.setupThemeToggle();
// Navigation - using more specific selectors
this.setupNavigation();
// Action buttons
this.setupActionButtons();
// Room functionality
this.setupRoomControls();
// Call controls
this.setupCallControls();
// Chat functionality
this.setupChatControls();
// Modal controls
this.setupModalControls();
// Sharing
this.setupSharingControls();
// Utility events
this.setupUtilityEvents();
console.log('✅ All event listeners configured');
}
setupThemeToggle() {
const themeToggle = document.getElementById('themeToggle');
if (themeToggle) {
themeToggle.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
this.toggleTheme();
console.log('🌓 Theme toggled');
});
console.log('✓ Theme toggle configured');
} else {
console.warn('⚠️ Theme toggle button not found');
}
}
setupNavigation() {
// Nav toggle for mobile
const navToggle = document.getElementById('navToggle');
if (navToggle) {
navToggle.addEventListener('click', (e) => {
e.preventDefault();
this.toggleMobileNav();
});
}
// Navigation links with explicit selection
const navLinks = document.querySelectorAll('a[data-page]');
console.log(`📍 Found ${navLinks.length} navigation links`);
navLinks.forEach((link, index) => {
const pageId = link.getAttribute('data-page');
console.log(`📌 Setting up nav link ${index}: ${pageId}`);
link.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log(`🔀 Navigation clicked: ${pageId}`);
this.navigateToPage(pageId);
});
});
}
setupActionButtons() {
// Main CTA buttons
const ctaButtons = document.querySelectorAll('.cta-button, button[data-page]');
console.log(`🎯 Found ${ctaButtons.length} action buttons`);
ctaButtons.forEach((button, index) => {
const pageId = button.getAttribute('data-page');
console.log(`🎯 Setting up action button ${index}: ${pageId}`);
button.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
console.log(`🚀 Action button clicked: ${pageId}`);
this.navigateToPage(pageId);
});
});
}
setupRoomControls() {
// Generate room ID
const generateBtn = document.getElementById('generateRoomBtn');
if (generateBtn) {
generateBtn.addEventListener('click', (e) => {
e.preventDefault();
this.generateRoomId();
this.showToast('New room ID generated!', 'success');
});
}
// Create room
const createBtn = document.getElementById('createRoomBtn');
if (createBtn) {
createBtn.addEventListener('click', (e) => {
e.preventDefault();
this.createRoom();
});
}
// Join room
const joinBtn = document.getElementById('joinRoomBtn');
if (joinBtn) {
joinBtn.addEventListener('click', (e) => {
e.preventDefault();
this.joinRoom();
});
}
// Preview controls
this.setupPreviewControls();
}
setupCallControls() {
const controlButtons = [
{ id: 'muteBtn', action: () => this.toggleMute() },
{ id: 'cameraBtn', action: () => this.toggleCamera() },
{ id: 'screenShareBtn', action: () => this.toggleScreenShare() },
{ id: 'chatBtn', action: () => this.toggleChat() },
{ id: 'reactionsBtn', action: () => this.showReactions() },
{ id: 'endCallBtn', action: () => this.endCall() },
{ id: 'copyLinkBtn', action: () => this.copyRoomLink() },
{ id: 'showSignalingBtn', action: () => this.showSignaling() }
];
controlButtons.forEach(({ id, action }) => {
const element = document.getElementById(id);
if (element) {
element.addEventListener('click', (e) => {
e.preventDefault();
action();
});
}
});
}
setupChatControls() {
const chatInput = document.getElementById('chatInput');
if (chatInput) {
chatInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.sendMessage();
}
});
}
const sendBtn = document.getElementById('sendMessageBtn');
if (sendBtn) {
sendBtn.addEventListener('click', (e) => {
e.preventDefault();
this.sendMessage();
});
}
const closeChatBtn = document.getElementById('closeChatBtn');
if (closeChatBtn) {
closeChatBtn.addEventListener('click', (e) => {
e.preventDefault();
this.toggleChat();
});
}
}
setupModalControls() {
// Share modal
const shareBtn = document.getElementById('shareBtn');
if (shareBtn) {
shareBtn.addEventListener('click', (e) => {
e.preventDefault();
this.showShareModal();
});
}
const closeShareBtn = document.getElementById('closeShareBtn');
if (closeShareBtn) {
closeShareBtn.addEventListener('click', (e) => {
e.preventDefault();
this.closeShareModal();
});
}
// Signaling modal
const signalingButtons = [
{ id: 'closeSignalingBtn', action: () => this.closeSignaling() },
{ id: 'copyOfferBtn', action: () => this.copyOffer() },
{ id: 'processAnswerBtn', action: () => this.processAnswer() },
{ id: 'processOfferBtn', action: () => this.processOffer() },
{ id: 'copyAnswerBtn', action: () => this.copyAnswer() }
];
signalingButtons.forEach(({ id, action }) => {
const element = document.getElementById(id);
if (element) {
element.addEventListener('click', (e) => {
e.preventDefault();
action();
});
}
});
}
setupSharingControls() {
// Social sharing buttons
document.addEventListener('click', (e) => {
if (e.target.closest('.social-btn')) {
e.preventDefault();
const btn = e.target.closest('.social-btn');
const platform = btn.getAttribute('data-platform');
if (platform) {
this.shareOnSocial(platform);
}
}
});
}
setupUtilityEvents() {
// Ripple effects
document.addEventListener('click', (e) => {
if (e.target.closest('.btn--animated')) {
const btn = e.target.closest('.btn--animated');
this.createRipple(e, btn);
}
});
// Modal close on outside click
document.addEventListener('click', (e) => {
if (e.target.classList.contains('modal')) {
e.target.classList.add('hidden');
}
});
// Window resize
window.addEventListener('resize', () => {
this.initParticles();
});
}
navigateToPage(pageId) {
if (!pageId) return;
console.log(`📄 Navigating to: ${pageId}`);
// Hide all pages
const allPages = document.querySelectorAll('.page');
allPages.forEach(page => {
page.classList.remove('active');
});
// Show target page
const targetPage = document.getElementById(pageId);
if (targetPage) {
targetPage.classList.add('active');
console.log(`✅ Showing page: ${pageId}`);
} else {
console.error(`❌ Page not found: ${pageId}`);
return;
}
// Update navigation state
document.querySelectorAll('.nav-link').forEach(link => {
link.classList.remove('active');
if (link.getAttribute('data-page') === pageId) {
link.classList.add('active');
}
});
// Close mobile nav
const navList = document.getElementById('navList');
if (navList) {
navList.classList.remove('active');
}
this.currentPage = pageId;
// Page-specific setup
if (pageId === 'create' && !this.roomId) {
this.generateRoomId();
}
// Update title
this.updatePageTitle(pageId);
// Show success message
this.showToast(`Navigated to ${pageId} page`, 'info');
}
updatePageTitle(pageId) {
const titles = {
home: 'FreeCall - Beautiful Video Calling Without Limits',
create: 'Create Room - FreeCall',
join: 'Join Meeting - FreeCall',
call: `Video Call - Room ${this.roomId} - FreeCall`
};
document.title = titles[pageId] || titles.home;
}
toggleTheme() {
this.isDarkTheme = !this.isDarkTheme;
document.body.classList.toggle('dark-theme', this.isDarkTheme);
const themeIcon = document.querySelector('#themeToggle i');
if (themeIcon) {
themeIcon.className = this.isDarkTheme ? 'fas fa-sun' : 'fas fa-moon';
}
localStorage.setItem('freecall-theme', this.isDarkTheme ? 'dark' : 'light');
this.updateParticles();
this.showToast(`Switched to ${this.isDarkTheme ? 'dark' : 'light'} theme`, 'success');
}
initTheme() {
const savedTheme = localStorage.getItem('freecall-theme');
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
this.isDarkTheme = true;
document.body.classList.add('dark-theme');
const themeIcon = document.querySelector('#themeToggle i');
if (themeIcon) {
themeIcon.className = 'fas fa-sun';
}
}
}
toggleMobileNav() {
const navList = document.getElementById('navList');
if (navList) {
navList.classList.toggle('active');
}
}
generateRoomId() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let result = '';
for (let i = 0; i < 8; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
this.roomId = result;
const roomIdInput = document.getElementById('roomId');
if (roomIdInput) {
roomIdInput.value = result;
}
console.log('🆔 Generated room ID:', result);
return result;
}
setupPreviewControls() {
const previewControls = [
{ id: 'togglePreviewCamera', type: 'video' },
{ id: 'togglePreviewMic', type: 'audio' },
{ id: 'toggleJoinPreviewCamera', type: 'video' },
{ id: 'toggleJoinPreviewMic', type: 'audio' }
];
previewControls.forEach(control => {
const element = document.getElementById(control.id);
if (element) {
element.addEventListener('click', (e) => {
e.preventDefault();
this.togglePreviewDevice(control.type, control.id);
});
}
});
}
async togglePreviewDevice(deviceType, buttonId) {
const button = document.getElementById(buttonId);
if (!button) return;
if (deviceType === 'video') {
this.isVideoEnabled = !this.isVideoEnabled;
} else {
this.isAudioEnabled = !this.isAudioEnabled;
}
this.updatePreviewButton(button, deviceType === 'video' ? this.isVideoEnabled : this.isAudioEnabled, deviceType);
this.showToast(`${deviceType === 'video' ? 'Camera' : 'Microphone'} ${deviceType === 'video' ? this.isVideoEnabled : this.isAudioEnabled ? 'on' : 'off'}`, 'info');
}
updatePreviewButton(button, isEnabled, type) {
const icons = {
video: { on: 'fas fa-video', off: 'fas fa-video-slash' },
audio: { on: 'fas fa-microphone', off: 'fas fa-microphone-slash' }
};
const icon = isEnabled ? icons[type].on : icons[type].off;
const text = type === 'video' ? 'Camera' : 'Microphone';
button.innerHTML = `
${text} `;
button.classList.toggle('muted', !isEnabled);
}
async createRoom() {
console.log('🚀 Creating room...');
this.showLoading(true, 'Creating your beautiful video room...');
const roomNameInput = document.getElementById('roomName');
const roomIdInput = document.getElementById('roomId');
const roomName = roomNameInput ? roomNameInput.value.trim() : '';
const roomId = roomIdInput ? roomIdInput.value.trim() : this.roomId;
if (!roomId) {
this.showToast('Please generate a room ID', 'error');
this.showLoading(false);
return;
}
this.roomId = roomId;
// Simulate room creation
await new Promise(resolve => setTimeout(resolve, 1500));
this.setupCallInterface(roomName, roomId);
this.showLoading(false);
this.navigateToPage('call');
this.unlockAchievement('first_call', 'First Call', 'Made your first video call!');
this.showToast('Room created successfully!', 'success');
}
async joinRoom() {
console.log('🚪 Joining room...');
this.showLoading(true, 'Joining the video call...');
const joinRoomIdInput = document.getElementById('joinRoomId');
const participantNameInput = document.getElementById('participantName');
const roomId = joinRoomIdInput ? joinRoomIdInput.value.trim() : '';
const participantName = participantNameInput ? participantNameInput.value.trim() : '';
if (!roomId) {
this.showToast('Please enter a room ID', 'error');
this.showLoading(false);
return;
}
this.roomId = roomId;
this.participantName = participantName || 'Guest';
// Simulate joining
await new Promise(resolve => setTimeout(resolve, 2000));
this.setupCallInterface('', roomId);
this.showLoading(false);
this.navigateToPage('call');
this.showToast(`Joined room ${roomId}!`, 'success');
}
setupCallInterface(roomName, roomId) {
const callRoomId = document.getElementById('callRoomId');
const callRoomName = document.getElementById('callRoomName');
if (callRoomId) callRoomId.textContent = roomId;
if (callRoomName) {
callRoomName.innerHTML = roomName ? `${roomName} (${roomId})` : `Room: ${roomId}`;
}
this.startCallTimer();
this.updateParticipantCount();
}
toggleMute() {
this.isAudioEnabled = !this.isAudioEnabled;
this.updateControlButton('muteBtn', this.isAudioEnabled, 'microphone');
this.showToast(this.isAudioEnabled ? 'Microphone on' : 'Microphone off', 'info');
}
toggleCamera() {
this.isVideoEnabled = !this.isVideoEnabled;
this.updateControlButton('cameraBtn', this.isVideoEnabled, 'video');
this.showToast(this.isVideoEnabled ? 'Camera on' : 'Camera off', 'info');
}
updateControlButton(buttonId, isEnabled, type) {
const button = document.getElementById(buttonId);
if (!button) return;
const icons = {
microphone: { on: 'fas fa-microphone', off: 'fas fa-microphone-slash' },
video: { on: 'fas fa-video', off: 'fas fa-video-slash' }
};
const icon = isEnabled ? icons[type].on : icons[type].off;
button.innerHTML = `
`;
button.classList.toggle('muted', !isEnabled);
}
toggleScreenShare() {
this.isScreenSharing = !this.isScreenSharing;
const shareBtn = document.getElementById('screenShareBtn');
if (shareBtn) {
shareBtn.classList.toggle('active', this.isScreenSharing);
}
this.showToast(this.isScreenSharing ? 'Screen sharing started' : 'Screen sharing stopped', 'info');
}
toggleChat() {
const chatPanel = document.getElementById('chatPanel');
const chatBtn = document.getElementById('chatBtn');
if (!chatPanel || !chatBtn) return;
this.isChatOpen = !this.isChatOpen;
chatPanel.classList.toggle('active', this.isChatOpen);
chatBtn.classList.toggle('active', this.isChatOpen);
this.showToast(this.isChatOpen ? 'Chat opened' : 'Chat closed', 'info');
}
sendMessage() {
const input = document.getElementById('chatInput');
if (!input) return;
const message = input.value.trim();
if (!message) return;
const messageData = {
sender: 'You',
content: message,
timestamp: new Date().toLocaleTimeString()
};
this.displayChatMessage(messageData);
input.value = '';
this.showToast('Message sent', 'success');
}
displayChatMessage(messageData) {
const messagesContainer = document.getElementById('chatMessages');
if (!messagesContainer) return;
const messageElement = document.createElement('div');
messageElement.className = 'chat-message';
messageElement.innerHTML = `
${messageData.sender}
${this.escapeHtml(messageData.content)}
${messageData.timestamp}
`;
messagesContainer.appendChild(messageElement);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
showReactions() {
const container = document.getElementById('reactionsContainer');
if (!container) return;
const emoji = this.reactions[Math.floor(Math.random() * this.reactions.length)];
const reactionElement = document.createElement('div');
reactionElement.className = 'reaction-emoji';
reactionElement.textContent = emoji;
const x = Math.random() * 160 - 80;
const y = Math.random() * 160 - 80;
reactionElement.style.left = `${100 + x}px`;
reactionElement.style.top = `${100 + y}px`;
container.appendChild(reactionElement);
setTimeout(() => {
if (reactionElement.parentNode) {
reactionElement.remove();
}
}, 3000);
this.showToast(`Sent ${emoji} reaction`, 'success');
}
showShareModal() {
const modal = document.getElementById('shareModal');
if (!modal) return;
const roomLink = `${window.location.origin}${window.location.pathname}?room=${this.roomId}`;
const shareLink = document.getElementById('shareLink');
if (shareLink) {
shareLink.value = roomLink;
}
modal.classList.remove('hidden');
this.showToast('Share modal opened', 'info');
}
closeShareModal() {
const modal = document.getElementById('shareModal');
if (modal) {
modal.classList.add('hidden');
}
}
async copyRoomLink() {
const roomLink = `${window.location.origin}${window.location.pathname}?room=${this.roomId}`;
try {
await navigator.clipboard.writeText(roomLink);
this.showToast('Room link copied to clipboard!', 'success');
} catch (error) {
this.showToast(`Room ID: ${this.roomId}`, 'info');
}
}
shareOnSocial(platform) {
const roomLink = `${window.location.origin}${window.location.pathname}?room=${this.roomId}`;
const text = `Join my video call on FreeCall! Room: ${this.roomId}`;
const platformData = this.socialPlatforms[platform];
if (!platformData) return;
let shareUrl = '';
switch (platform) {
case 'whatsapp':
shareUrl = `${platformData.url}${encodeURIComponent(text + ' ' + roomLink)}`;
break;
case 'telegram':
shareUrl = `${platformData.url}${encodeURIComponent(roomLink)}&text=${encodeURIComponent(text)}`;
break;
case 'twitter':
shareUrl = `${platformData.url}${encodeURIComponent(text + ' ' + roomLink)}`;
break;
case 'facebook':
shareUrl = `${platformData.url}${encodeURIComponent(roomLink)}`;
break;
case 'linkedin':
shareUrl = `${platformData.url}${encodeURIComponent(roomLink)}`;
break;
}
if (shareUrl) {
window.open(shareUrl, '_blank', 'width=600,height=400');
this.unlockAchievement('social_sharer', 'Social Butterfly', 'Shared FreeCall with friends!');
this.showToast(`Sharing on ${platform}`, 'success');
}
}
showSignaling() {
const modal = document.getElementById('signalingModal');
if (modal) {
modal.classList.remove('hidden');
}
const localOfferTextarea = document.getElementById('localOffer');
if (localOfferTextarea) {
localOfferTextarea.value = JSON.stringify({
type: 'offer',
sdp: 'Sample SDP offer for WebRTC connection...'
});
}
this.showToast('Connection offer generated', 'success');
}
closeSignaling() {
const modal = document.getElementById('signalingModal');
if (modal) {
modal.classList.add('hidden');
}
}
async copyOffer() {
const textarea = document.getElementById('localOffer');
if (!textarea) return;
try {
await navigator.clipboard.writeText(textarea.value);
this.showToast('Offer copied to clipboard', 'success');
} catch (error) {
textarea.select();
document.execCommand('copy');
this.showToast('Offer copied to clipboard', 'success');
}
}
processAnswer() {
this.showToast('Connection established!', 'success');
this.closeSignaling();
}
processOffer() {
const answerStep = document.getElementById('answerStep');
if (answerStep) {
answerStep.style.display = 'block';
}
this.showToast('Answer generated successfully', 'success');
}
async copyAnswer() {
const textarea = document.getElementById('generatedAnswer');
if (!textarea) return;
try {
await navigator.clipboard.writeText(textarea.value);
this.showToast('Answer copied to clipboard', 'success');
} catch (error) {
this.showToast('Answer copied', 'success');
}
}
startCallTimer() {
this.callStartTime = Date.now();
this.callTimer = setInterval(() => {
const elapsed = Date.now() - this.callStartTime;
const hours = Math.floor(elapsed / 3600000);
const minutes = Math.floor((elapsed % 3600000) / 60000);
const seconds = Math.floor((elapsed % 60000) / 1000);
const timeString = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
const timerElement = document.getElementById('callTimer');
if (timerElement) {
timerElement.textContent = timeString;
}
}, 1000);
}
stopCallTimer() {
if (this.callTimer) {
clearInterval(this.callTimer);
this.callTimer = null;
}
}
updateParticipantCount() {
const count = this.participants.size;
const text = count === 1 ? '1 participant' : `${count} participants`;
const countElement = document.getElementById('participantCount');
if (countElement) {
countElement.textContent = text;
}
}
endCall() {
if (confirm('Are you sure you want to end the call?')) {
this.stopCallTimer();
this.navigateToPage('home');
this.showToast('Call ended', 'info');
}
}
unlockAchievement(id, title, description) {
if (this.achievements.has(id)) return;
this.achievements.add(id);
const modal = document.getElementById('achievementModal');
const descriptionElement = document.getElementById('achievementDescription');
if (modal && descriptionElement) {
descriptionElement.textContent = description;
modal.classList.remove('hidden');
}
}
initParticles() {
const container = document.getElementById('particlesContainer');
if (!container) return;
container.innerHTML = '';
const colors = ['#00D4FF', '#4ECDC4', '#FF6B6B', '#FFD93D', '#A8E6CF'];
const particleCount = window.innerWidth < 768 ? 20 : 50;
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
const size = Math.random() * 4 + 2;
const color = colors[Math.floor(Math.random() * colors.length)];
const left = Math.random() * 100;
const animationDuration = Math.random() * 10 + 10;
const delay = Math.random() * 5;
particle.style.cssText = `
width: ${size}px;
height: ${size}px;
background: ${color};
left: ${left}%;
top: ${Math.random() * 100}%;
animation-duration: ${animationDuration}s;
animation-delay: ${delay}s;
opacity: ${this.isDarkTheme ? 0.8 : 0.4};
`;
container.appendChild(particle);
}
}
updateParticles() {
const particles = document.querySelectorAll('.particle');
particles.forEach(particle => {
const currentOpacity = parseFloat(particle.style.opacity);
particle.style.opacity = this.isDarkTheme ?
Math.min(currentOpacity * 2, 0.8) :
Math.max(currentOpacity / 2, 0.4);
});
}
initScrollAnimations() {
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
}
});
}, observerOptions);
document.querySelectorAll('.feature-card, .testimonial-card').forEach(card => {
card.style.opacity = '0';
card.style.transform = 'translateY(30px)';
card.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
observer.observe(card);
});
}
handleURLParams() {
const urlParams = new URLSearchParams(window.location.search);
const roomParam = urlParams.get('room');
if (roomParam) {
const joinRoomIdInput = document.getElementById('joinRoomId');
if (joinRoomIdInput) {
joinRoomIdInput.value = roomParam;
}
setTimeout(() => this.navigateToPage('join'), 500);
}
}
createRipple(event, button) {
if (!button) return;
const existingRipple = button.querySelector('.btn-ripple');
if (existingRipple) {
existingRipple.remove();
}
const ripple = document.createElement('span');
ripple.className = 'btn-ripple';
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = event.clientX - rect.left - size / 2;
const y = event.clientY - rect.top - size / 2;
ripple.style.cssText = `
width: ${size}px;
height: ${size}px;
left: ${x}px;
top: ${y}px;
`;
button.appendChild(ripple);
setTimeout(() => {
if (ripple.parentNode) {
ripple.remove();
}
}, 600);
}
showLoading(show, message = 'Setting up your beautiful video call...') {
const overlay = document.getElementById('loadingOverlay');
const textElement = overlay?.querySelector('.loading-text');
if (overlay) {
if (show) {
if (textElement) textElement.textContent = message;
overlay.classList.remove('hidden');
} else {
overlay.classList.add('hidden');
}
}
}
showToast(message, type = 'info') {
console.log(`🔔 Toast (${type}): ${message}`);
const container = document.getElementById('toastContainer');
if (!container) return;
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
container.appendChild(toast);
setTimeout(() => {
if (toast.parentNode) {
toast.style.transform = 'translateX(100%)';
setTimeout(() => {
if (toast.parentNode) {
toast.remove();
}
}, 300);
}
}, 3000);
}
}
// Initialize app
console.log('🎬 FreeCall - Beautiful Video Calling App Loading...');
// Ensure proper initialization
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
console.log('📱 DOM ready, initializing FreeCall...');
window.freeCallApp = new FreeCallApp();
});
} else {
console.log('📱 DOM already ready, initializing FreeCall...');
window.freeCallApp = new FreeCallApp();
}
// Console styling
setTimeout(() => {
console.log('%c🚀 Welcome to FreeCall! 🚀', 'color: #00D4FF; font-size: 20px; font-weight: bold;');
console.log('%cBuilt with ❤️ for beautiful video calling', 'color: #4ECDC4; font-size: 14px;');
}, 500);
0 Comments