diff --git a/client/src/app/approval-page.component.scss b/client/src/app/approval-page.component.scss index e5310bb..7dbcf7a 100644 --- a/client/src/app/approval-page.component.scss +++ b/client/src/app/approval-page.component.scss @@ -1,5 +1,11 @@ .approval-card { border: 1px solid var(--surface-border-soft); - border-radius: 1rem; - background: var(--panel-soft-background); + border-radius: 1.15rem; + background: var(--surface-background); + transition: border-color 160ms ease, transform 160ms ease; +} + +.approval-card:hover { + border-color: color-mix(in srgb, var(--accent-color) 35%, transparent); + transform: translateY(-1px); } diff --git a/client/src/app/chat-page.component.scss b/client/src/app/chat-page.component.scss index 688489e..4961caf 100644 --- a/client/src/app/chat-page.component.scss +++ b/client/src/app/chat-page.component.scss @@ -8,27 +8,31 @@ min-height: 100dvh; } +/* ── Panel ──────────────────────────────────────────────────────────────── */ .panel { border: 1px solid var(--surface-border); - border-radius: 1.75rem; + border-radius: 2rem; background: var(--panel-background); - backdrop-filter: blur(18px); - box-shadow: 0 20px 60px var(--shadow-color); + backdrop-filter: blur(22px); + -webkit-backdrop-filter: blur(22px); + box-shadow: + 0 28px 72px var(--shadow-color), + inset 0 1px 0 rgba(255, 255, 255, 0.07); } +/* ── Chat page shell ────────────────────────────────────────────────────── */ .chat-page { display: flex; flex-direction: column; - width: min(95vw, 95%); + width: min(96vw, 98%); height: min(calc(100dvh - 2rem), 1024px); max-height: 1024px; margin-inline: auto; overflow-x: hidden; } -.chat-header { - flex: 0 0 auto; -} +/* ── Header ─────────────────────────────────────────────────────────────── */ +.chat-header { flex: 0 0 auto; } .chat-header-main { display: flex; @@ -39,53 +43,72 @@ .chat-header-title { margin: 0; - font-size: clamp(1.35rem, 2vw, 1.75rem); + font-size: clamp(1.1rem, 2vw, 1.45rem); + font-weight: 700; line-height: 1.1; + background: linear-gradient(135deg, var(--page-text) 40%, var(--accent-color) 100%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; } -.call-modal-backdrop { - position: fixed; - inset: 0; - z-index: 1250; - display: grid; - place-items: center; - padding: 1.5rem; - background: rgba(3, 8, 14, 0.52); - backdrop-filter: blur(8px); -} - +/* ── Back link ───────────────────────────────────────────────────────────── */ .back-link { display: inline-flex; align-items: center; justify-content: center; - width: 2rem; - height: 2rem; - color: var(--link-color); + width: 2.25rem; + height: 2.25rem; + border-radius: 999px; + color: var(--page-text-muted); + background: var(--badge-background); + border: 1px solid var(--surface-border-soft); text-decoration: none; - font-size: 1.4rem; + font-size: 1.15rem; line-height: 1; + transition: color 160ms ease, background 160ms ease, border-color 160ms ease, transform 160ms ease; } +.back-link:hover, +.back-link:focus-visible { + color: var(--accent-color); + background: var(--accent-color-soft); + border-color: color-mix(in srgb, var(--accent-color) 35%, transparent); + transform: translateX(-2px); +} + +/* ── Status indicators ───────────────────────────────────────────────────── */ .status-indicators { display: flex; flex-wrap: wrap; - gap: 0.9rem; + gap: 0.5rem; margin-left: auto; + align-items: center; } .status-indicator { display: inline-flex; align-items: center; - gap: 0.45rem; - font-size: 0.9rem; + gap: 0.42rem; + padding: 0.32rem 0.75rem; + border-radius: 999px; + font-size: 0.72rem; + font-family: var(--font-mono); + font-weight: 500; + letter-spacing: 0.08em; + text-transform: uppercase; color: var(--page-text-soft); + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--surface-border-soft); } .expand-action-icon { - font-size: 1.9rem; + font-size: 1.25rem; line-height: 1; + opacity: 0.7; } +/* ── Layout ──────────────────────────────────────────────────────────────── */ .chat-layout { display: grid; flex: 1 1 auto; @@ -94,7 +117,6 @@ min-height: 0; } - .chat-main { display: grid; grid-template-rows: minmax(0, 1fr) auto; @@ -102,47 +124,66 @@ min-height: 0; } +/* ── Conversation scroll area ────────────────────────────────────────────── */ .conversation { display: grid; - gap: 0.85rem; + gap: 0.75rem; align-content: start; min-height: 0; overflow: auto; - padding: 0.5rem 0; + padding: 0.75rem 0.25rem; } +/* ── Bubble ──────────────────────────────────────────────────────────────── */ .bubble { position: relative; align-self: start; - max-width: min(75%, 34rem); - padding: 0.9rem 3.4rem 0.9rem 1rem; - border-radius: 1.2rem; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.14); + max-width: min(78%, 36rem); + padding: 0.85rem 3.25rem 0.85rem 1rem; + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.22); } .bubble-actions { position: absolute; top: 0.45rem; - right: 0.55rem; + right: 0.5rem; display: flex; align-items: flex-start; - gap: 0.35rem; + gap: 0.28rem; + opacity: 0; + transition: opacity 160ms ease; +} + +.bubble:hover .bubble-actions { + opacity: 1; } .bubble-action { - width: 1.5rem; - height: 1.5rem; + width: 1.45rem; + height: 1.45rem; padding: 0; border: 0; border-radius: 999px; - color: #fff; - background: var(--badge-background); + color: var(--page-text-muted); + background: rgba(255, 255, 255, 0.1); line-height: 1; - font-size: 0.9rem; + font-size: 0.8rem; + transition: background 120ms ease, color 120ms ease; +} + +.bubble-action:hover { + background: rgba(255, 255, 255, 0.18); + color: var(--page-text); } .bubble-delete { - background: var(--danger-background); + background: rgba(239, 68, 68, 0.2); + color: #fca5a5; +} + +.bubble-delete:hover { + background: rgba(239, 68, 68, 0.35); + color: #fff; } .bubble-forward-menu { @@ -153,9 +194,10 @@ min-width: 12rem; padding: 0.45rem; border: 1px solid var(--surface-border); - border-radius: 0.85rem; - background: var(--surface-background); - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.18); + border-radius: 0.9rem; + background: var(--panel-background); + backdrop-filter: blur(16px); + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45); } .bubble-forward-select { @@ -164,6 +206,7 @@ border-radius: 0.65rem; color: var(--page-text); background: var(--input-background); + padding: 0.35rem 0.65rem; } .emoji-only-text { @@ -171,19 +214,134 @@ line-height: 1.15; } +/* ── Bubble: image / video / download ───────────────────────────────────── */ +.bubble-image, +.bubble-video { + width: 200px; + max-width: 100%; + height: auto; + display: block; + border-radius: 1rem; + border: 1px solid var(--surface-border-soft); +} + +.bubble-video { background: #000; } + +.bubble-download { + color: var(--accent-color); + font-size: 0.85rem; + font-weight: 600; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 0.35rem; +} + +.bubble-download:hover { color: var(--link-color); } + +.bubble-preview { display: grid; gap: 0.45rem; } + +.bubble-preview-label { + font-size: 0.72rem; + font-weight: 700; + font-family: var(--font-mono); + text-transform: uppercase; + letter-spacing: 0.08em; + opacity: 0.65; +} + +.bubble-preview-image { + display: block; + width: min(240px, 100%); + max-width: 100%; + height: auto; + border: 1px solid var(--surface-border); + border-radius: 1rem; +} + +/* ── Voice bubble ────────────────────────────────────────────────────────── */ +.voice-bubble { display: grid; gap: 0.6rem; } + +.voice-bubble-label { + font-size: 0.78rem; + font-weight: 700; + font-family: var(--font-mono); + letter-spacing: 0.08em; + text-transform: uppercase; + opacity: 0.7; + color: var(--accent-color); +} + +.voice-player { + display: block; + width: min(100%, 18rem); +} + +.bubble-json { + white-space: pre-wrap; + word-break: break-word; + margin: 0; + font-family: var(--font-mono); + font-size: 0.82rem; + opacity: 0.9; +} + +/* ── Bubble metadata ─────────────────────────────────────────────────────── */ +.bubble-author { font-weight: 600; } + +/* ── Empty state ─────────────────────────────────────────────────────────── */ +.empty-chat { + padding: 1.5rem; + border: 1px dashed var(--surface-border); + border-radius: 1.25rem; + color: var(--page-text-muted); + text-align: center; + font-size: 0.9rem; + font-family: var(--font-mono); + background: rgba(255, 255, 255, 0.02); +} + +.empty-peers { min-height: 10rem; } + +/* ── Composer ────────────────────────────────────────────────────────────── */ .composer { display: grid; - gap: 0.85rem; + gap: 0.75rem; flex: 0 0 auto; - padding-top: 1rem; - margin-top: 1rem; + padding: 1rem 0 0; + margin-top: 0.75rem; border-top: 1px solid var(--surface-border-soft); } +.composer-textarea, +.composer-textarea:focus { + color: var(--page-text); + background-color: var(--input-background); + border-color: var(--input-border); + border-radius: 1rem; + box-shadow: none; + transition: border-color 160ms ease, box-shadow 160ms ease; +} + +.composer-textarea:focus { + border-color: color-mix(in srgb, var(--accent-color) 50%, transparent); + box-shadow: 0 0 0 3px var(--accent-color-soft); +} + +.composer-textarea::placeholder { color: var(--placeholder-color); } + +.composer-textarea { + min-height: calc(2 * 1.5rem + 1.25rem); + max-height: calc(6 * 1.5rem + 1.25rem); + overflow-y: auto; + resize: none; +} + +/* ── Composer toolbar ────────────────────────────────────────────────────── */ .composer-toolbar { display: flex; flex-wrap: wrap; - gap: 0.85rem; + gap: 0.55rem; align-items: center; justify-content: space-between; } @@ -192,10 +350,131 @@ display: flex; flex: 1 1 auto; flex-wrap: wrap; - gap: 0.6rem; + gap: 0.45rem; align-items: center; } +/* All composer icon buttons share base sizing */ +.composer-camera, +.composer-call, +.composer-dictation, +.composer-hangup, +.composer-voice, +.composer-image-generate, +.composer-emoji-trigger, +.composer-plus, +.send-emoji { + width: 2.85rem; + height: 2.85rem; + border: 0; + border-radius: 999px; + font-size: 1.2rem; + transition: transform 160ms ease, opacity 160ms ease, box-shadow 160ms ease; +} + +.composer-camera:hover, +.composer-call:hover, +.composer-dictation:hover, +.composer-voice:hover, +.composer-image-generate:hover, +.composer-emoji-trigger:hover, +.composer-plus:hover, +.send-emoji:hover { + transform: translateY(-1px); +} + +:is( + .composer-camera, + .composer-call, + .composer-dictation, + .composer-hangup, + .composer-voice, + .composer-image-generate, + .composer-emoji-trigger, + .composer-plus, + .send-emoji +):disabled { + opacity: 0.38; + transform: none; +} + +.composer-file-input { display: none; } + +/* Individual button colors */ +.composer-call { + color: #fff; + background: linear-gradient(135deg, #059669, #10b981); + box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3); +} + +.composer-hangup { + color: #fff; + background: linear-gradient(135deg, #dc2626, #ef4444); + box-shadow: 0 4px 16px rgba(220, 38, 38, 0.3); +} + +.composer-voice { + color: #fff; + background: linear-gradient(135deg, #d97706, #f59e0b); + box-shadow: 0 4px 16px rgba(245, 158, 11, 0.25); +} + +.composer-voice-recording { + color: #fff; + background: linear-gradient(135deg, #db2777, #ec4899) !important; + box-shadow: 0 0 0 3px rgba(236, 72, 153, 0.2), 0 4px 16px rgba(219, 39, 119, 0.35) !important; + animation: voice-pulse 1.2s ease-in-out infinite; +} + +@keyframes voice-pulse { + 0%, 100% { box-shadow: 0 0 0 3px rgba(236, 72, 153, 0.2); } + 50% { box-shadow: 0 0 0 6px rgba(236, 72, 153, 0.08); } +} + +.composer-dictation { + color: #1a1a1a; + background: linear-gradient(135deg, #fbbf24, #fde68a); + box-shadow: 0 4px 16px rgba(251, 191, 36, 0.25); +} + +.composer-dictation-active { + color: #fff !important; + background: linear-gradient(135deg, #db2777, #ec4899) !important; + box-shadow: 0 4px 16px rgba(219, 39, 119, 0.3) !important; +} + +.composer-plus { + color: #fff; + background: linear-gradient(135deg, #059669, #34d399); + font-size: 1.5rem; + font-weight: 700; + box-shadow: 0 4px 16px rgba(5, 150, 105, 0.3); +} + +.composer-image-generate { + color: #fff; + background: linear-gradient(135deg, #7c3aed, #a78bfa); + box-shadow: 0 4px 16px rgba(124, 58, 237, 0.3); +} + +.composer-emoji-trigger { + color: #fff; + background: linear-gradient(135deg, #4f46e5, #818cf8); + box-shadow: 0 4px 16px rgba(79, 70, 229, 0.28); +} + +.send-emoji { + color: #fff; + background: var(--accent-gradient); + box-shadow: 0 4px 20px rgba(13, 148, 136, 0.4); +} + +.send-emoji:not(:disabled):hover { + background: var(--accent-gradient-hover); + box-shadow: 0 6px 24px rgba(13, 148, 136, 0.5); +} + +/* ── Receive speed ───────────────────────────────────────────────────────── */ .composer-receive-speed { display: inline-flex; flex: 0 0 auto; @@ -208,106 +487,21 @@ } .composer-receive-speed-label { - font-size: 0.75rem; - letter-spacing: 0.12em; + font-size: 0.68rem; + letter-spacing: 0.14em; text-transform: uppercase; + font-family: var(--font-mono); + color: var(--accent-color); } .composer-receive-speed-value { - font-size: 0.92rem; + font-size: 0.88rem; font-variant-numeric: tabular-nums; + font-family: var(--font-mono); } -.composer-emoji-picker-shell { - position: relative; -} - -.composer-file-input { - display: none; -} - -.composer-camera, -.composer-call, -.composer-dictation, -.composer-hangup, -.composer-voice, -.composer-image-generate, -.composer-emoji-trigger, -.composer-plus, -.send-emoji { - width: 3.25rem; - height: 3.25rem; - border: 0; - border-radius: 999px; - font-size: 1.35rem; -} - -.composer-textarea, -.composer-textarea:focus { - color: var(--page-text); - background-color: var(--input-background); - border-color: var(--input-border); - box-shadow: none; -} - -.composer-textarea::placeholder { - color: var(--placeholder-color); -} - -.composer-textarea { - min-height: calc(2 * 1.5rem + 1.25rem); - max-height: calc(6 * 1.5rem + 1.25rem); - overflow-y: auto; - resize: none; -} - -.composer-call { - color: #fff; - background: #e53935; -} - -.composer-dictation-active, -.composer-hangup, -.composer-voice-recording { - color: #fff; - background: linear-gradient(135deg, #ff7d63, #dc3e5d); -} - -.composer-voice { - color: #fff; - background: #fb8c00; -} - -.composer-voice-recording { - box-shadow: 0 0 0 0.2rem rgba(220, 62, 93, 0.18); -} - -.composer-dictation { - color: #1f1f1f; - background: #fdd835; -} - -.composer-plus { - color: #fff; - background: #43a047; - font-size: 1.76rem; - font-weight: 700; -} - -.composer-image-generate { - color: #fff; - background: #1e88e5; -} - -.composer-emoji-trigger { - color: #fff; - background: #3949ab; -} - -.send-emoji { - color: #fff; - background: #8e24aa; -} +/* ── Emoji picker ────────────────────────────────────────────────────────── */ +.composer-emoji-picker-shell { position: relative; } .composer-emoji-picker { position: absolute; @@ -317,124 +511,62 @@ display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0.35rem; - width: min(14rem, 70vw); - max-height: 10.35rem; + width: min(15rem, 72vw); + max-height: 10.5rem; overflow-y: auto; overflow-x: hidden; - padding: 0.65rem; + padding: 0.75rem; border: 1px solid var(--surface-border); - border-radius: 1rem; + border-radius: 1.25rem; background: var(--panel-background); - box-shadow: 0 18px 36px rgba(0, 0, 0, 0.18); + backdrop-filter: blur(20px); + box-shadow: 0 20px 48px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .composer-emoji-option { - width: 2.1rem; - height: 2.1rem; + width: 2.15rem; + height: 2.15rem; padding: 0; border: 0; border-radius: 0.75rem; background: var(--surface-background); font-size: 1.2rem; line-height: 1; + transition: background 120ms ease, transform 120ms ease; } .composer-emoji-option:hover, .composer-emoji-option:focus-visible { background: var(--surface-hover-background); + transform: scale(1.12); } -.bubble-author, -.bubble-download, -.voice-bubble-label { - font-weight: 600; -} - -.bubble-preview { - display: grid; - gap: 0.45rem; -} - -.bubble-preview-label { - font-size: 0.82rem; - font-weight: 600; - opacity: 0.78; -} - -.bubble-preview-image { - display: block; - width: min(240px, 100%); - max-width: 100%; - height: auto; - border: 1px solid var(--surface-border); - border-radius: 1rem; - background: #fff; -} - -.bubble-image, -.bubble-video { - width: 200px; - max-width: 100%; - height: auto; - display: block; - border-radius: 1rem; -} - -.bubble-video { - background: #000; -} -.bubble-download { color: inherit; } - -.voice-bubble { - display: grid; - gap: 0.65rem; -} - -.voice-bubble-label { font-size: 0.88rem; } - -.voice-player { - display: block; - width: min(100%, 18rem); -} - -.bubble-json { - white-space: pre-wrap; - word-break: break-word; - margin: 0; -} - -.empty-chat { - padding: 1.25rem; - border: 1px dashed var(--input-border); - border-radius: 1rem; - color: var(--page-text-muted); - text-align: center; -} - -.empty-peers { - min-height: 10rem; -} - -.h3, -.small { - color: var(--page-text); -} +/* ── Misc helpers ────────────────────────────────────────────────────────── */ +.h3, .small { color: var(--page-text); } +/* ── Mobile ──────────────────────────────────────────────────────────────── */ @media (max-width: 767.98px) { - .chat-layout { - grid-template-columns: 1fr; - } + .chat-layout { grid-template-columns: 1fr; } .status-indicators { width: 100%; margin-left: 0; } - .bubble { - max-width: 88%; - } + .bubble { max-width: 90%; } - .composer-toolbar { - justify-content: flex-start; + .composer-toolbar { justify-content: flex-start; } + + .composer-call, + .composer-hangup, + .composer-voice, + .composer-dictation, + .composer-image-generate, + .composer-emoji-trigger, + .composer-plus, + .send-emoji { + width: 2.6rem; + height: 2.6rem; + font-size: 1.1rem; } } diff --git a/client/src/app/home-page.component.scss b/client/src/app/home-page.component.scss index 04f9fe7..5caf3c2 100644 --- a/client/src/app/home-page.component.scss +++ b/client/src/app/home-page.component.scss @@ -8,186 +8,108 @@ min-height: 100dvh; } +/* ── Panel primitives ───────────────────────────────────────────────────── */ .hero-panel, .panel, .session-card, .empty-state { border: 1px solid var(--surface-border); background: var(--panel-background); - backdrop-filter: blur(18px); - box-shadow: 0 20px 60px var(--shadow-color); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + box-shadow: + 0 24px 64px var(--shadow-color), + inset 0 1px 0 rgba(255, 255, 255, 0.06); } -.hero-panel { - border-radius: 2rem; -} - -.panel, -.session-card { - border-radius: 1.5rem; -} +.hero-panel { border-radius: 2rem; } +.panel { border-radius: 1.75rem; } +.session-card { border-radius: 1.5rem; } .panel-muted { background: var(--panel-alt-background); } -.hero-copy { - max-width: 52rem; -} +/* ── Hero header ────────────────────────────────────────────────────────── */ +.hero-copy { max-width: 52rem; } .eyebrow { display: inline-flex; align-items: center; gap: 0.5rem; - padding: 0.45rem 0.85rem; + padding: 0.4rem 0.9rem; border-radius: 999px; - margin-bottom: 1rem; - letter-spacing: 0.14em; + margin-bottom: 0.75rem; + letter-spacing: 0.18em; text-transform: uppercase; - font-size: 0.72rem; + font-size: 0.68rem; font-weight: 700; + font-family: var(--font-mono); color: var(--accent-color); background: var(--accent-color-soft); + border: 1px solid color-mix(in srgb, var(--accent-color) 25%, transparent); } +.eyebrow::before { + content: ''; + width: 0.45rem; + height: 0.45rem; + border-radius: 50%; + background: var(--accent-color); + animation: glow-pulse 3s ease-in-out infinite; +} + +/* ── Theme toggle ───────────────────────────────────────────────────────── */ .theme-toggle { display: inline-flex; align-items: center; - gap: 0.55rem; + gap: 0.5rem; min-width: 7.5rem; - height: 3rem; - padding: 0 0.95rem; + height: 2.75rem; + padding: 0 1rem; border: 1px solid var(--surface-border); border-radius: 999px; color: var(--page-text); - background: var(--panel-soft-background); - font-size: 0.95rem; - font-weight: 700; - text-transform: capitalize; + background: rgba(255, 255, 255, 0.04); + font-size: 0.88rem; + font-weight: 600; + font-family: var(--font-mono); + text-transform: uppercase; + letter-spacing: 0.06em; line-height: 1; - transition: transform 160ms ease, background 160ms ease, border-color 160ms ease; + transition: transform 160ms ease, background 160ms ease, border-color 160ms ease, box-shadow 160ms ease; } -.theme-toggle-icon { - font-size: 1.25rem; -} - -.theme-toggle-label { - letter-spacing: 0.03em; -} +.theme-toggle-icon { font-size: 1.15rem; } +.theme-toggle-label { letter-spacing: 0.06em; } .theme-toggle:hover, .theme-toggle:focus-visible { - border-color: color-mix(in srgb, var(--accent-color) 35%, var(--surface-border)); + border-color: color-mix(in srgb, var(--accent-color) 40%, transparent); background: var(--surface-hover-background); transform: translateY(-1px); + box-shadow: 0 0 0 3px var(--accent-color-soft); } +/* ── Session card ───────────────────────────────────────────────────────── */ .session-card { min-width: min(100%, 18rem); } .status-pill { display: inline-flex; - padding: 0.45rem 0.8rem; + align-items: center; + gap: 0.5rem; + padding: 0.38rem 0.85rem; border-radius: 999px; background: var(--badge-background); -} - -.btn-accent, -.btn-accent:hover, -.btn-accent:focus-visible { - color: #06111d; - border: 0; -} - -.btn-accent { - background: var(--accent-gradient); -} - -.btn-accent:hover, -.btn-accent:focus-visible { - background: var(--accent-gradient-hover); -} - -.access-key-panel { - padding: 1rem; - border-radius: 1rem; - background: var(--panel-soft-background); -} - -.dictation-language-panel, -.dictation-language-select-shell { - display: grid; - gap: 0.75rem; -} - -.user-search-panel { - display: grid; - gap: 0.75rem; -} - -.user-search-shell { - display: grid; - gap: 0.75rem; -} - -.user-search-results { - display: grid; - gap: 0.65rem; -} - -.user-search-result { - display: flex; - align-items: center; - justify-content: space-between; - gap: 1rem; - width: 100%; - padding: 0.9rem 1rem; border: 1px solid var(--surface-border-soft); - border-radius: 0.9rem; - color: var(--page-text); - background: var(--surface-background); - text-align: left; - transition: border-color 160ms ease, background 160ms ease, transform 160ms ease; -} - -.user-search-result:hover, -.user-search-result:focus-visible { - border-color: color-mix(in srgb, var(--accent-color) 35%, var(--surface-border)); - background: var(--surface-hover-background); - transform: translateY(-1px); -} - -.user-search-result-copy { - display: grid; - gap: 0.1rem; - min-width: 0; -} - -.user-search-result-action { - flex: 0 0 auto; - font-size: 0.82rem; - font-weight: 700; + font-family: var(--font-mono); + font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; - color: var(--accent-color); -} - -.access-key-card { - border-radius: 0.9rem; - border: 1px solid var(--surface-border-soft); - background: var(--surface-background); -} - -.empty-state { - border-radius: 1.25rem; -} - -.info-rail article { - padding: 1rem 1.1rem; - border-radius: 1rem; - background: var(--panel-soft-background); + color: var(--page-text-soft); } +/* ── Auth form card ─────────────────────────────────────────────────────── */ .form-control, .form-control:focus, .form-select, @@ -195,17 +117,21 @@ color: var(--page-text); background-color: var(--input-background); border-color: var(--input-border); + border-radius: 0.85rem; box-shadow: none; + transition: border-color 160ms ease, box-shadow 160ms ease; } -.form-control::placeholder { - color: var(--placeholder-color); +.form-control:focus, +.form-select:focus { + border-color: color-mix(in srgb, var(--accent-color) 55%, transparent); + box-shadow: 0 0 0 3px var(--accent-color-soft); } +.form-control::placeholder { color: var(--placeholder-color); } + .form-label, -.h3, -.h4, -.display-5, +.h3, .h4, .h5, .fw-semibold, .fw-bold { color: var(--page-text); @@ -216,3 +142,134 @@ .small { color: var(--page-text-muted) !important; } + +/* Auth tab toggle */ +.btn-group .btn { + border-radius: 0.75rem; + font-weight: 500; + font-size: 0.9rem; +} + +.btn-group .btn-primary { + background: var(--accent-gradient); + border-color: transparent; + color: #fff; + box-shadow: 0 2px 12px rgba(13, 148, 136, 0.28); +} + +.btn-group .btn-outline-primary { + color: var(--page-text-muted); + border-color: var(--surface-border); + background: transparent; +} + +.btn-group .btn-outline-primary:hover { + background: var(--panel-soft-background); + color: var(--page-text); +} + +/* ── Access key / settings panels ──────────────────────────────────────── */ +.access-key-panel { + padding: 1.1rem 1.25rem; + border-radius: 1.25rem; + background: var(--panel-soft-background); + border: 1px solid var(--surface-border-soft); + transition: border-color 160ms ease; +} + +.access-key-panel:hover { + border-color: var(--surface-border); +} + +.access-key-card { + border-radius: 1rem; + border: 1px solid var(--surface-border-soft); + background: var(--surface-background); + transition: border-color 160ms ease; +} + +.access-key-card:hover { + border-color: var(--surface-border); +} + +/* ── User search ────────────────────────────────────────────────────────── */ +.user-search-panel, +.user-search-shell, +.dictation-language-panel, +.dictation-language-select-shell { + display: grid; + gap: 0.75rem; +} + +.user-search-results { + display: grid; + gap: 0.5rem; +} + +.user-search-result { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + width: 100%; + padding: 0.85rem 1rem; + border: 1px solid var(--surface-border-soft); + border-radius: 1rem; + color: var(--page-text); + background: var(--surface-background); + text-align: left; + transition: border-color 160ms ease, background 160ms ease, transform 160ms ease; +} + +.user-search-result:hover, +.user-search-result:focus-visible { + border-color: color-mix(in srgb, var(--accent-color) 38%, transparent); + background: var(--surface-hover-background); + transform: translateY(-1px); +} + +.user-search-result-copy { + display: grid; + gap: 0.08rem; + min-width: 0; +} + +.user-search-result-action { + flex: 0 0 auto; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + font-family: var(--font-mono); + color: var(--accent-color); +} + +/* ── How-it-works info rail ─────────────────────────────────────────────── */ +.info-rail article { + padding: 1rem 1.15rem; + border-radius: 1rem; + background: var(--panel-soft-background); + border: 1px solid var(--surface-border-soft); + position: relative; + overflow: hidden; +} + +.info-rail article::before { + content: attr(data-step); + position: absolute; + top: 0.65rem; + right: 0.9rem; + font-family: var(--font-mono); + font-size: 0.65rem; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--accent-color); + opacity: 0.7; +} + +/* ── Empty state ────────────────────────────────────────────────────────── */ +.empty-state { + border-radius: 1.25rem; + border: 1px dashed var(--surface-border); + background: var(--panel-soft-background) !important; +} diff --git a/client/src/index.html b/client/src/index.html index 679e609..2e96ab7 100644 --- a/client/src/index.html +++ b/client/src/index.html @@ -5,7 +5,7 @@ PrivateChat - + @@ -14,7 +14,7 @@ - + diff --git a/client/src/styles.scss b/client/src/styles.scss index 151291d..6a541a0 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -1,108 +1,104 @@ @use 'bootstrap/scss/bootstrap'; +/* ── Design Tokens ───────────────────────────────────────────────────────── */ :root { - --page-text: #142236; - --page-text-muted: rgba(39, 63, 91, 0.72); - --page-text-soft: rgba(39, 63, 91, 0.82); - --page-background: - radial-gradient(circle at top left, rgba(81, 168, 255, 0.2), transparent 30%), - radial-gradient(circle at top right, rgba(129, 244, 215, 0.22), transparent 24%), - linear-gradient(180deg, #f6fbff 0%, #e8f1fb 100%); - --panel-background: rgba(255, 255, 255, 0.82); - --panel-alt-background: rgba(241, 247, 255, 0.9); - --panel-soft-background: rgba(20, 34, 54, 0.04); - --surface-background: rgba(255, 255, 255, 0.82); - --surface-hover-background: rgba(235, 244, 255, 0.98); - --surface-border: rgba(33, 62, 94, 0.12); - --surface-border-soft: rgba(33, 62, 94, 0.08); - --input-background: rgba(255, 255, 255, 0.92); - --input-border: rgba(77, 114, 154, 0.26); - --placeholder-color: rgba(55, 83, 118, 0.52); - --accent-color: #138a7b; - --accent-color-soft: rgba(19, 138, 123, 0.1); - --accent-gradient: linear-gradient(135deg, #8df0df, #6cb6ff); - --accent-gradient-hover: linear-gradient(135deg, #a6f5e8, #86c4ff); - --link-color: #2f7cd6; - --badge-background: rgba(20, 34, 54, 0.08); - --incoming-bubble-background: #d9ebff; - --incoming-bubble-text: #183759; - --outgoing-bubble-background: #d9f5df; - --outgoing-bubble-text: #1e4d2f; - --danger-background: #d94b53; - --shadow-color: rgba(41, 73, 110, 0.14); - color-scheme: light; -} + /* Text */ + --page-text: #e2e8f4; + --page-text-muted: rgba(180, 196, 224, 0.68); + --page-text-soft: rgba(180, 196, 224, 0.82); -@media (prefers-color-scheme: dark) { - :root:not([data-theme]) { - --page-text: #eff3ff; - --page-text-muted: rgba(231, 238, 249, 0.72); - --page-text-soft: rgba(231, 238, 249, 0.84); - --page-background: - radial-gradient(circle at top left, rgba(129, 244, 215, 0.18), transparent 28%), - radial-gradient(circle at top right, rgba(85, 168, 255, 0.18), transparent 24%), - linear-gradient(180deg, #08111d 0%, #101d31 100%); - --panel-background: rgba(9, 16, 28, 0.78); - --panel-alt-background: rgba(15, 27, 44, 0.78); - --panel-soft-background: rgba(255, 255, 255, 0.04); - --surface-background: rgba(8, 14, 23, 0.7); - --surface-hover-background: rgba(16, 30, 49, 0.92); - --surface-border: rgba(255, 255, 255, 0.12); - --surface-border-soft: rgba(255, 255, 255, 0.08); - --input-background: rgba(255, 255, 255, 0.06); - --input-border: rgba(255, 255, 255, 0.16); - --placeholder-color: rgba(239, 243, 255, 0.5); - --accent-color: #81f4d7; - --accent-color-soft: rgba(129, 244, 215, 0.1); - --accent-gradient: linear-gradient(135deg, #81f4d7, #55a8ff); - --accent-gradient-hover: linear-gradient(135deg, #9bf7e0, #7abaff); - --link-color: #9bd5ff; - --badge-background: rgba(255, 255, 255, 0.08); - --incoming-bubble-background: #dcefff; - --incoming-bubble-text: #0f2540; - --outgoing-bubble-background: #def7dd; - --outgoing-bubble-text: #153420; - --danger-background: #d94b53; - --shadow-color: rgba(0, 0, 0, 0.28); - color-scheme: dark; - } -} - -:root[data-theme='dark'] { - --page-text: #eff3ff; - --page-text-muted: rgba(231, 238, 249, 0.72); - --page-text-soft: rgba(231, 238, 249, 0.84); + /* Page background: deep obsidian with teal/blue aurora */ --page-background: - radial-gradient(circle at top left, rgba(129, 244, 215, 0.18), transparent 28%), - radial-gradient(circle at top right, rgba(85, 168, 255, 0.18), transparent 24%), - linear-gradient(180deg, #08111d 0%, #101d31 100%); - --panel-background: rgba(9, 16, 28, 0.78); - --panel-alt-background: rgba(15, 27, 44, 0.78); - --panel-soft-background: rgba(255, 255, 255, 0.04); - --surface-background: rgba(8, 14, 23, 0.7); - --surface-hover-background: rgba(16, 30, 49, 0.92); - --surface-border: rgba(255, 255, 255, 0.12); - --surface-border-soft: rgba(255, 255, 255, 0.08); - --input-background: rgba(255, 255, 255, 0.06); - --input-border: rgba(255, 255, 255, 0.16); - --placeholder-color: rgba(239, 243, 255, 0.5); - --accent-color: #81f4d7; - --accent-color-soft: rgba(129, 244, 215, 0.1); - --accent-gradient: linear-gradient(135deg, #81f4d7, #55a8ff); - --accent-gradient-hover: linear-gradient(135deg, #9bf7e0, #7abaff); - --link-color: #9bd5ff; - --badge-background: rgba(255, 255, 255, 0.08); - --incoming-bubble-background: #dcefff; - --incoming-bubble-text: #0f2540; - --outgoing-bubble-background: #def7dd; - --outgoing-bubble-text: #153420; - --danger-background: #d94b53; - --shadow-color: rgba(0, 0, 0, 0.28); + radial-gradient(circle at 12% 8%, rgba(13, 148, 136, 0.22), transparent 28%), + radial-gradient(circle at 90% 5%, rgba(59, 130, 246, 0.18), transparent 24%), + radial-gradient(circle at 50% 95%, rgba(99, 102, 241, 0.12), transparent 30%), + linear-gradient(180deg, #030712 0%, #080f1e 100%); + + /* Panels */ + --panel-background: rgba(11, 17, 32, 0.72); + --panel-alt-background: rgba(15, 23, 42, 0.78); + --panel-soft-background: rgba(255, 255, 255, 0.04); + + /* Surfaces */ + --surface-background: rgba(8, 14, 24, 0.65); + --surface-hover-background: rgba(17, 28, 50, 0.92); + --surface-border: rgba(255, 255, 255, 0.08); + --surface-border-soft: rgba(255, 255, 255, 0.05); + + /* Inputs */ + --input-background: rgba(0, 0, 0, 0.35); + --input-border: rgba(255, 255, 255, 0.12); + --placeholder-color: rgba(148, 168, 210, 0.45); + + /* Accent — teal-to-blue gradient */ + --accent-color: #2dd4bf; + --accent-color-soft: rgba(45, 212, 191, 0.12); + --accent-gradient: linear-gradient(135deg, #0d9488, #3b82f6); + --accent-gradient-hover: linear-gradient(135deg, #14b8a6, #60a5fa); + + /* Link */ + --link-color: #60a5fa; + + /* Badges / Pills */ + --badge-background: rgba(255, 255, 255, 0.07); + + /* Chat bubbles */ + --incoming-bubble-background: rgba(30, 58, 138, 0.22); + --incoming-bubble-border: rgba(59, 130, 246, 0.28); + --incoming-bubble-text: #dbeafe; + --outgoing-bubble-background: rgba(6, 78, 59, 0.25); + --outgoing-bubble-border: rgba(45, 212, 191, 0.30); + --outgoing-bubble-text: #d1fae5; + + /* Status LEDs */ + --led-ok: #10b981; + --led-connecting: #f59e0b; + --led-offline: #ef4444; + + /* Shadow */ + --shadow-color: rgba(0, 0, 0, 0.55); + + /* Typography */ + --font-mono: 'JetBrains Mono', 'Fira Code', monospace; + color-scheme: dark; } -html, -body { +/* Light theme override */ +:root[data-theme='light'] { + --page-text: #0f172a; + --page-text-muted: rgba(30, 50, 80, 0.66); + --page-text-soft: rgba(30, 50, 80, 0.82); + --page-background: + radial-gradient(circle at 12% 8%, rgba(13, 148, 136, 0.15), transparent 28%), + radial-gradient(circle at 90% 5%, rgba(59, 130, 246, 0.12), transparent 24%), + linear-gradient(180deg, #f0fafa 0%, #e8f1fb 100%); + --panel-background: rgba(255, 255, 255, 0.82); + --panel-alt-background: rgba(241, 248, 255, 0.88); + --panel-soft-background: rgba(15, 23, 42, 0.04); + --surface-background: rgba(255, 255, 255, 0.75); + --surface-hover-background: rgba(236, 248, 255, 0.98); + --surface-border: rgba(30, 60, 100, 0.12); + --surface-border-soft: rgba(30, 60, 100, 0.07); + --input-background: rgba(255, 255, 255, 0.9); + --input-border: rgba(100, 130, 180, 0.28); + --placeholder-color: rgba(60, 90, 130, 0.48); + --accent-color: #0d9488; + --accent-color-soft: rgba(13, 148, 136, 0.1); + --incoming-bubble-background: #dbeafe; + --incoming-bubble-border: rgba(59, 130, 246, 0.28); + --incoming-bubble-text: #1e3a5f; + --outgoing-bubble-background: #d1fae5; + --outgoing-bubble-border: rgba(13, 148, 136, 0.28); + --outgoing-bubble-text: #064e3b; + --shadow-color: rgba(30, 60, 100, 0.14); + color-scheme: light; +} + +/* ── Base ────────────────────────────────────────────────────────────────── */ +@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); + +html, body { min-height: 100dvh; } @@ -113,18 +109,28 @@ body { background: var(--page-background); background-attachment: fixed; transition: - background 180ms ease, - color 180ms ease, - border-color 180ms ease, - box-shadow 180ms ease; + background 220ms ease, + color 220ms ease, + border-color 220ms ease, + box-shadow 220ms ease; } -button, -input, -textarea { +button, input, textarea, select { font: inherit; } +/* Scrollbar */ +::-webkit-scrollbar { width: 5px; height: 5px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + border-radius: 10px; +} +::-webkit-scrollbar-thumb:hover { + background: rgba(45, 212, 191, 0.35); +} + +/* ── Bootstrap overrides ────────────────────────────────────────────────── */ .text-secondary { color: var(--page-text-muted) !important; } @@ -177,6 +183,7 @@ textarea { border: 1px solid var(--surface-border); } +/* ── Modals (shared across pages) ───────────────────────────────────────── */ .call-choice-backdrop { position: fixed; inset: 0; @@ -184,8 +191,8 @@ textarea { display: grid; place-items: center; padding: 1rem; - background: rgba(3, 8, 14, 0.46); - backdrop-filter: blur(6px); + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(10px); } .call-choice-card { @@ -199,8 +206,8 @@ textarea { display: grid; place-items: center; padding: 0.75rem; - background: rgba(3, 8, 14, 0.56); - backdrop-filter: blur(8px); + background: rgba(0, 0, 0, 0.65); + backdrop-filter: blur(12px); } .conversation-modal { @@ -227,9 +234,10 @@ textarea { } .conversation-modal-eyebrow { - font-size: 0.78rem; - letter-spacing: 0.14em; - color: var(--page-text-soft); + font-size: 0.72rem; + letter-spacing: 0.16em; + color: var(--accent-color); + font-family: var(--font-mono); } .conversation-modal-close { @@ -242,6 +250,11 @@ textarea { background: var(--badge-background); font-size: 1.35rem; line-height: 1; + transition: background 160ms ease; +} + +.conversation-modal-close:hover { + background: rgba(255, 255, 255, 0.12); } .conversation-modal-body { @@ -252,9 +265,10 @@ textarea { .call-choice-eyebrow { margin-bottom: 0.45rem; - font-size: 0.78rem; - letter-spacing: 0.16em; - color: var(--page-text-soft); + font-size: 0.72rem; + letter-spacing: 0.18em; + color: var(--accent-color); + font-family: var(--font-mono); } .call-choice-actions { @@ -273,15 +287,14 @@ textarea { color: var(--page-text); background: var(--surface-background); text-align: left; + transition: border-color 160ms ease, background 160ms ease, transform 160ms ease; } .call-choice-button:hover, -.call-choice-button:focus-visible, -.peer-tile:hover, -.peer-tile:focus-visible, -.peer-tile-active { - border-color: color-mix(in srgb, var(--accent-color) 35%, transparent); +.call-choice-button:focus-visible { + border-color: color-mix(in srgb, var(--accent-color) 40%, transparent); background: var(--surface-hover-background); + transform: translateY(-1px); } .call-choice-icon { @@ -292,6 +305,7 @@ textarea { border-radius: 999px; background: var(--badge-background); font-size: 1.2rem; + border: 1px solid var(--surface-border); } .status-indicator-action { @@ -315,6 +329,7 @@ textarea { opacity: 1; } +/* ── Status LEDs ─────────────────────────────────────────────────────────── */ .status-led, .peer-tile-delete, .bubble-spinner { @@ -322,23 +337,28 @@ textarea { } .status-led { - width: 0.8rem; - height: 0.8rem; - box-shadow: 0 0 0 1px var(--input-border); + width: 0.55rem; + height: 0.55rem; + flex-shrink: 0; + box-shadow: 0 0 6px currentColor; } .status-led-ok { - background: #59d66f; + color: var(--led-ok); + background: var(--led-ok); } .status-led-connecting { - background: #f3ad3d; + color: var(--led-connecting); + background: var(--led-connecting); } .status-led-offline { - background: #eb5d64; + color: var(--led-offline); + background: var(--led-offline); } +/* ── Peer dropdown ───────────────────────────────────────────────────────── */ .peer-dropdown { position: relative; min-width: min(18rem, 42vw); @@ -346,8 +366,8 @@ textarea { .peer-dropdown-trigger { width: 100%; - padding-top: 0.56rem; - padding-bottom: 0.56rem; + padding-top: 0.52rem; + padding-bottom: 0.52rem; } .peer-dropdown-menu { @@ -356,15 +376,16 @@ textarea { left: 0; z-index: 4; display: grid; - gap: 0.75rem; + gap: 0.65rem; width: 100%; max-height: calc(3 * 4.55rem + 1.5rem); overflow: auto; padding: 0.75rem; border: 1px solid var(--surface-border); - border-radius: 1rem; + border-radius: 1.2rem; background: var(--panel-background); - box-shadow: 0 18px 36px rgba(0, 0, 0, 0.18); + backdrop-filter: blur(20px); + box-shadow: 0 20px 48px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.06); } .peer-tile { @@ -373,12 +394,12 @@ textarea { gap: 0.75rem; align-items: center; width: 100%; - padding: 0.8rem 0.85rem 0.8rem 1rem; + padding: 0.75rem 0.85rem 0.75rem 1rem; border: 1px solid var(--surface-border); border-radius: 1rem; color: inherit; background: var(--surface-background); - font-size: 1.05em; + font-size: 1em; transition: transform 160ms ease, border-color 160ms ease, background 160ms ease; } @@ -403,9 +424,10 @@ textarea { } .peer-dropdown-caret { - font-size: 4.02rem; + font-size: 1.1rem; line-height: 1; transition: transform 160ms ease; + opacity: 0.6; } .peer-dropdown-caret-open { @@ -413,29 +435,34 @@ textarea { } .peer-tile-delete { - width: 1.54rem; - height: 1.54rem; + width: 1.5rem; + height: 1.5rem; padding: 0; border: 0; background: transparent; font-size: 0.7rem; line-height: 1; + opacity: 0.5; + transition: opacity 160ms ease, background 160ms ease; } .peer-tile-delete:hover, .peer-tile-delete:focus-visible { - background: var(--badge-background); + opacity: 1; + background: rgba(239, 68, 68, 0.15); } .peer-tile:hover, .peer-tile:focus-visible, .peer-tile-active { transform: translateY(-1px); + border-color: color-mix(in srgb, var(--accent-color) 38%, transparent); + background: var(--surface-hover-background); } .peer-tile-unread { - border-color: #c62828; - box-shadow: inset 0 0 0 2px #c62828; + border-color: #ef4444; + box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.4), 0 0 12px rgba(239, 68, 68, 0.15); } .peer-tile-row { @@ -452,6 +479,7 @@ textarea { min-width: 0; } +/* Typing indicator */ .peer-typing-dots { display: inline-flex; align-items: center; @@ -463,72 +491,77 @@ textarea { width: 0.27rem; height: 0.27rem; border-radius: 999px; - background: var(--page-text); - opacity: 0.28; + background: var(--accent-color); + opacity: 0.35; animation: peer-typing-pulse 900ms infinite ease-in-out; } -.peer-typing-dots span:nth-child(2) { - animation-delay: 120ms; -} - -.peer-typing-dots span:nth-child(3) { - animation-delay: 240ms; -} +.peer-typing-dots span:nth-child(2) { animation-delay: 120ms; } +.peer-typing-dots span:nth-child(3) { animation-delay: 240ms; } .peer-tile-status { flex: 0 0 auto; } +/* ── Chat Bubbles ────────────────────────────────────────────────────────── */ .bubble-incoming { justify-self: start; color: var(--incoming-bubble-text); background: var(--incoming-bubble-background); + border: 1px solid var(--incoming-bubble-border); + border-radius: 1.25rem 1.25rem 1.25rem 0.35rem; } .bubble-outgoing { justify-self: end; color: var(--outgoing-bubble-text); background: var(--outgoing-bubble-background); + border: 1px solid var(--outgoing-bubble-border); + border-radius: 1.25rem 1.25rem 0.35rem 1.25rem; } .bubble-pending { - opacity: 0.58; - filter: grayscale(0.28); + opacity: 0.52; + filter: grayscale(0.32); } .bubble-system { justify-self: center; max-width: 90%; color: var(--page-text-soft); - background: var(--badge-background); + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--surface-border-soft); + font-family: var(--font-mono); + font-size: 0.75rem; } .bubble-emoji-only { max-width: none; padding: 0; + border: none; border-radius: 0; background: transparent; box-shadow: none; } .bubble-meta { - display: grid; - gap: 0.12rem; - margin-bottom: 0.35rem; - font-size: 0.78rem; - opacity: 0.7; + display: flex; + align-items: baseline; + gap: 0.45rem; + margin-bottom: 0.3rem; + font-size: 0.72rem; + opacity: 0.65; + font-family: var(--font-mono); } -.bubble-time { - display: block; -} +.bubble-time { display: block; } .bubble-delivery-state { display: inline-block; margin-top: 0.1rem; - font-size: 0.72rem; + font-size: 0.68rem; letter-spacing: 0.06em; + color: var(--accent-color); } .bubble-system-status { @@ -545,34 +578,55 @@ textarea { animation: bubble-spin 700ms linear infinite; } +/* ── Keyframes ───────────────────────────────────────────────────────────── */ @keyframes peer-typing-pulse { - 0%, - 80%, - 100% { - opacity: 0.28; - transform: translateY(0); - } - - 40% { - opacity: 1; - transform: translateY(-1px); - } + 0%, 80%, 100% { opacity: 0.35; transform: translateY(0); } + 40% { opacity: 1; transform: translateY(-2px); } } @keyframes bubble-spin { - to { - transform: rotate(360deg); - } + to { transform: rotate(360deg); } } -@media (max-width: 767.98px) { - .peer-dropdown { - min-width: min(100%, 18rem); - } +@keyframes glow-pulse { + 0%, 100% { opacity: 0.5; box-shadow: 0 0 6px currentColor; } + 50% { opacity: 1; box-shadow: 0 0 14px currentColor; } +} - .conversation-modal-backdrop { - padding: 0; - } +.status-led-ok { animation: glow-pulse 3s ease-in-out infinite; } + +/* ── Global accent button (used across pages) ───────────────────────────── */ +.btn-accent, +.btn-accent:hover, +.btn-accent:focus-visible { + color: #fff; + border: 0; + font-weight: 600; + letter-spacing: 0.02em; +} + +.btn-accent { + background: var(--accent-gradient); + box-shadow: 0 4px 20px rgba(13, 148, 136, 0.3); + transition: opacity 160ms ease, transform 160ms ease, box-shadow 160ms ease; +} + +.btn-accent:hover, +.btn-accent:focus-visible { + background: var(--accent-gradient-hover); + transform: translateY(-1px); + box-shadow: 0 8px 28px rgba(13, 148, 136, 0.4); +} + +.btn-accent:active { + transform: scale(0.97); +} + +/* ── Mobile ──────────────────────────────────────────────────────────────── */ +@media (max-width: 767.98px) { + .peer-dropdown { min-width: min(100%, 18rem); } + + .conversation-modal-backdrop { padding: 0; } .conversation-modal { width: 100vw; diff --git a/package-lock.json b/package-lock.json index a9af35b..475125e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,94 @@ "name": "private-chat", "version": "1.0.0", "devDependencies": { - "concurrently": "^9.2.1" + "concurrently": "^9.2.1", + "puppeteer": "^24.41.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz", + "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.3", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.4", + "tar-fs": "^3.1.1", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" } }, "node_modules/ansi-regex": { @@ -37,6 +124,168 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz", + "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.7.tgz", + "integrity": "sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.0.tgz", + "integrity": "sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz", + "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/basic-ftp": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz", + "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -67,6 +316,20 @@ "node": ">=8" } }, + "node_modules/chromium-bidi": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", + "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -127,6 +390,83 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1595872", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1595872.tgz", + "integrity": "sha512-kRfgp8vWVjBu/fbYCiVFiOqsCk3CrMKEo3WbgGT2NXK2dG7vawWPBljixajVgGK9II8rDO9G0oD0zLt3I1daRg==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -134,6 +474,36 @@ "dev": true, "license": "MIT" }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -144,6 +514,110 @@ "node": ">=6" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -154,6 +628,37 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -164,6 +669,68 @@ "node": ">=8" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -174,6 +741,253 @@ "node": ">=8" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/puppeteer": { + "version": "24.41.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.41.0.tgz", + "integrity": "sha512-W6Fk0J3TPjjtwjXOyR/qf+YaL0H/Uq8HIgHcXG4mNM/IgbKMCH/HPyK0Fi2qbTU/QpSl9bCte2yBpGHKejTpIw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.13.0", + "chromium-bidi": "14.0.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1595872", + "puppeteer-core": "24.41.0", + "typed-query-selector": "^2.12.1" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "24.41.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.41.0.tgz", + "integrity": "sha512-rLIUri7E/NQ3APSEYCCozaSJx0u8Tu9wxO6BJwnvXmIgILSK3L0TombaVh3izp1njAGrO6H2ru0hcIrLF+gWLw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.13.0", + "chromium-bidi": "14.0.0", + "debug": "^4.4.3", + "devtools-protocol": "0.0.1595872", + "typed-query-selector": "^2.12.1", + "webdriver-bidi-protocol": "0.4.1", + "ws": "^8.19.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -184,6 +998,16 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", @@ -194,6 +1018,19 @@ "tslib": "^2.1.0" } }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shell-quote": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", @@ -207,6 +1044,70 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamx": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -251,6 +1152,54 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -268,6 +1217,28 @@ "dev": true, "license": "0BSD" }, + "node_modules/typed-query-selector": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.1.tgz", + "integrity": "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", + "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -286,6 +1257,35 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -324,6 +1324,27 @@ "engines": { "node": ">=12" } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index ca04ae4..6bd1085 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "restart": "npm run build && sudo systemctl restart privatechat.service" }, "devDependencies": { - "concurrently": "^9.2.1" + "concurrently": "^9.2.1", + "puppeteer": "^24.41.0" } }