+
+
+
+
+
+ Hope
+Voice companion
+
-
-
-
-
-
-
-
- Idle
- thinking…
-
-
+
+
+
+
+
+
+
-
+
+
+ I'm here.
+Speak naturally. I’ll listen, remember, and answer in real time.
+
+
+
+
+
+ Ready when you are
+ Thinking…
+
+
+
+
+
+
+
+
+
+
+
+
+ Secure connection ready
+
+ + + Your memory stays in Shane’s private profile. +
+
+
+
+
+
+
+ Conversation
+Live transcript
+
-
-
-
-
-
-
- Disconnected
-
-
-
-
-
- Conversation
-
-
-
-
-
+
-
-
-
Voice
-
+
diff --git a/web/manifest.json b/web/manifest.json
index 02b18ae..de15600 100644
--- a/web/manifest.json
+++ b/web/manifest.json
@@ -1,11 +1,11 @@
{
- "name": "Voice Assistant",
- "short_name": "Voice",
- "description": "Real-time voice assistant — Azure Speech + Gemma LLM",
+ "name": "Hope Voice Companion",
+ "short_name": "Hope",
+ "description": "A private, real-time voice companion with personal memory.",
"start_url": "/",
"display": "standalone",
- "background_color": "#09090b",
- "theme_color": "#09090b",
+ "background_color": "#08111f",
+ "theme_color": "#08111f",
"icons": [
{
"src": "favicon.svg",
diff --git a/web/style.css b/web/style.css
index af4cccb..a59eda9 100644
--- a/web/style.css
+++ b/web/style.css
@@ -1,421 +1,817 @@
:root {
- --bg: #09090b;
- --panel: rgba(255, 255, 255, 0.05);
- --panel-strong: rgba(255, 255, 255, 0.08);
- --border: rgba(255, 255, 255, 0.09);
- --text: #e4e4e7;
- --text-dim: #a1a1aa;
- --text-faint: #71717a;
- --accent-1: #60a5fa;
- --accent-2: #a78bfa;
- --user-bubble: rgba(96, 165, 250, 0.14);
- --agent-bubble: rgba(167, 139, 250, 0.14);
- --danger: #ef4444;
+ --canvas: #08111f;
+ --canvas-deep: #050b14;
+ --surface: #0d1929;
+ --surface-raised: #132238;
+ --surface-soft: #172941;
+ --line: rgba(183, 204, 235, 0.13);
+ --line-strong: rgba(183, 204, 235, 0.22);
+ --ink: #f4f7fb;
+ --ink-soft: #c5d1e2;
+ --ink-muted: #8395ad;
+ --iris: #8ba7ff;
+ --iris-strong: #6f8ff7;
+ --iris-deep: #3c5fc9;
+ --warm: #ffb38e;
+ --mint: #76d9b2;
+ --danger: #ff806f;
+ --user-bubble: #1b3150;
+ --agent-bubble: #14243a;
+ --focus: #b5c5ff;
+ --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
+ --z-panel: 40;
+ --z-backdrop: 50;
+ --z-sheet: 60;
color-scheme: dark;
}
-@media (prefers-color-scheme: light) {
- :root {
- --bg: #fafafa;
- --panel: rgba(0, 0, 0, 0.04);
- --panel-strong: rgba(0, 0, 0, 0.07);
- --border: rgba(0, 0, 0, 0.1);
- --text: #18181b;
- --text-dim: #52525b;
- --text-faint: #a1a1aa;
- --user-bubble: rgba(37, 99, 235, 0.1);
- --agent-bubble: rgba(124, 58, 237, 0.1);
- color-scheme: light;
- }
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
}
-* { margin: 0; padding: 0; box-sizing: border-box; }
-
-html, body { height: 100%; }
+html {
+ min-height: 100%;
+ background: var(--canvas-deep);
+}
body {
- font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
- background: var(--bg);
- color: var(--text);
min-height: 100vh;
- display: flex;
- justify-content: center;
- align-items: flex-start;
- padding: calc(2rem + env(safe-area-inset-top)) calc(1rem + env(safe-area-inset-right))
- calc(2rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
+ min-height: 100dvh;
+ padding: calc(1.25rem + env(safe-area-inset-top))
+ calc(1.25rem + env(safe-area-inset-right))
+ calc(1.25rem + env(safe-area-inset-bottom))
+ calc(1.25rem + env(safe-area-inset-left));
+ overflow-x: hidden;
+ color: var(--ink);
+ background:
+ radial-gradient(circle at 16% 8%, rgba(86, 115, 207, 0.16), transparent 34rem),
+ radial-gradient(circle at 88% 92%, rgba(255, 179, 142, 0.07), transparent 30rem),
+ var(--canvas);
+ font-family: "Avenir Next", "Segoe UI Variable", "Segoe UI", system-ui, -apple-system, sans-serif;
+ -webkit-font-smoothing: antialiased;
}
-.container {
- width: 100%;
- max-width: 680px;
+button,
+input,
+select {
+ font: inherit;
}
-header {
- text-align: center;
- margin-bottom: 1.5rem;
+button {
+ color: inherit;
}
-h1 {
- font-size: 2rem;
+[hidden] {
+ display: none !important;
+}
+
+.skip-link {
+ position: fixed;
+ top: 0.75rem;
+ left: 0.75rem;
+ z-index: 100;
+ padding: 0.7rem 1rem;
+ border-radius: 8px;
+ color: var(--canvas);
+ background: var(--ink);
+ font-size: 0.85rem;
font-weight: 700;
- background: linear-gradient(135deg, var(--accent-1), var(--accent-2));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
+ transform: translateY(-160%);
+ transition: transform 180ms var(--ease-out);
}
-.subtitle {
- color: var(--text-faint);
- margin-top: 0.5rem;
- font-size: 0.9rem;
+.skip-link:focus {
+ transform: translateY(0);
}
-/* ── Orb ─────────────────────────────────────────────────────────────────── */
-.orb-stage {
+.app-shell {
+ width: min(1180px, 100%);
+ margin: 0 auto;
+}
+
+/* ── Header ─────────────────────────────────────────────────────────────── */
+.topbar {
+ min-height: 62px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1.25rem;
+ margin-bottom: 1.25rem;
+ padding: 0.25rem 0.15rem;
+}
+
+.brand,
+.topbar-actions,
+.identity-chip,
+.tasks-trigger {
+ display: flex;
+ align-items: center;
+}
+
+.brand {
+ gap: 0.8rem;
+}
+
+.brand-glyph {
+ position: relative;
+ width: 38px;
+ height: 38px;
+ flex: 0 0 38px;
+ border: 1px solid rgba(139, 167, 255, 0.55);
+ border-radius: 50%;
+}
+
+.brand-glyph::before,
+.brand-glyph::after,
+.brand-glyph i {
+ content: "";
+ position: absolute;
+ border-radius: 50%;
+}
+
+.brand-glyph::before {
+ inset: 7px;
+ border: 1px solid rgba(139, 167, 255, 0.35);
+}
+
+.brand-glyph::after {
+ width: 8px;
+ height: 8px;
+ right: 4px;
+ top: 5px;
+ background: var(--warm);
+ box-shadow: 0 0 12px rgba(255, 179, 142, 0.52);
+}
+
+.brand-glyph i {
+ width: 6px;
+ height: 6px;
+ inset: 0;
+ margin: auto;
+ background: var(--iris);
+}
+
+.brand h1 {
+ color: var(--ink);
+ font-size: 1.18rem;
+ font-weight: 680;
+ letter-spacing: -0.02em;
+}
+
+.brand p {
+ margin-top: 0.1rem;
+ color: var(--ink-muted);
+ font-size: 0.74rem;
+}
+
+.topbar-actions {
+ justify-content: flex-end;
+ gap: 0.65rem;
+}
+
+.identity-chip {
+ min-height: 38px;
+ gap: 0.55rem;
+ padding: 0 0.85rem;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ color: var(--ink-soft);
+ background: rgba(13, 25, 41, 0.72);
+ font-size: 0.78rem;
+}
+
+.identity-chip strong {
+ color: var(--ink);
+ font-weight: 650;
+}
+
+.presence-dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--mint);
+ box-shadow: 0 0 0 4px rgba(118, 217, 178, 0.1);
+}
+
+/* ── Main workspace ─────────────────────────────────────────────────────── */
+.workspace {
+ display: grid;
+ grid-template-columns: minmax(390px, 0.92fr) minmax(420px, 1.08fr);
+ height: min(700px, calc(100dvh - 108px));
+ min-height: 610px;
+ border: 1px solid var(--line);
+ border-radius: 16px;
+ overflow: hidden;
+ background: var(--surface);
+ box-shadow: 0 8px 8px rgba(2, 7, 14, 0.18);
+}
+
+.voice-console {
+ position: relative;
display: flex;
flex-direction: column;
align-items: center;
- margin-bottom: 1.75rem;
+ min-width: 0;
+ padding: clamp(2rem, 4vw, 3.5rem) clamp(1.5rem, 4vw, 3.25rem) 1.6rem;
+ overflow: hidden;
+ background:
+ radial-gradient(circle at 50% 38%, rgba(90, 121, 215, 0.14), transparent 18rem),
+ var(--surface);
+}
+
+.voice-console::after {
+ content: "";
+ position: absolute;
+ left: 10%;
+ right: 10%;
+ bottom: 0;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, rgba(139, 167, 255, 0.34), transparent);
+}
+
+.console-intro {
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ text-align: center;
+}
+
+.console-intro h2 {
+ color: var(--ink);
+ font-size: 2rem;
+ font-weight: 620;
+ letter-spacing: -0.035em;
+ text-wrap: balance;
+}
+
+.console-intro p {
+ max-width: 38ch;
+ margin: 0.55rem auto 0;
+ color: var(--ink-muted);
+ font-size: 0.91rem;
+ line-height: 1.55;
+ text-wrap: pretty;
+}
+
+/* ── Voice presence ─────────────────────────────────────────────────────── */
+.orb-stage {
+ position: relative;
+ z-index: 1;
+ flex: 1;
+ width: 100%;
+ min-height: 310px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding-top: 0.75rem;
}
.orb {
--pulse-scale: 1;
+ --pulse-opacity: 0.28;
position: relative;
- width: 200px;
- height: 200px;
+ width: 260px;
+ height: 260px;
display: grid;
place-items: center;
+ isolation: isolate;
}
.orb-core {
- width: 130px;
- height: 130px;
+ position: relative;
+ z-index: 3;
+ width: 116px;
+ height: 116px;
+ overflow: hidden;
border-radius: 50%;
- background: radial-gradient(circle at 35% 30%, var(--accent-1), var(--accent-2) 70%);
+ background:
+ radial-gradient(circle at 32% 24%, rgba(244, 247, 251, 0.96) 0 3%, transparent 20%),
+ radial-gradient(circle at 38% 30%, #b9c9ff, #6f8ff7 42%, #3d57ab 72%, #23305b 100%);
box-shadow:
- 0 0 60px 8px color-mix(in srgb, var(--accent-2) 45%, transparent),
- inset 0 0 30px rgba(255, 255, 255, 0.15);
+ 0 0 0 1px rgba(213, 222, 255, 0.24),
+ 0 12px 28px rgba(2, 8, 20, 0.34),
+ 0 0 52px rgba(111, 143, 247, 0.32),
+ inset -12px -14px 26px rgba(10, 20, 50, 0.34);
transform: scale(var(--pulse-scale));
- transition: box-shadow 0.3s ease;
- animation: breathe 4s ease-in-out infinite;
+ transition: filter 220ms ease, box-shadow 220ms ease, transform 90ms linear;
+}
+
+.orb-shimmer {
+ position: absolute;
+ width: 90px;
+ height: 34px;
+ left: 9px;
+ top: 18px;
+ border-radius: 50%;
+ border-top: 1px solid rgba(255, 255, 255, 0.52);
+ transform: rotate(-22deg);
+ opacity: 0.7;
+}
+
+.orb-ring,
+.orb-orbit {
+ position: absolute;
+ border-radius: 50%;
+ pointer-events: none;
}
.orb-ring {
- position: absolute;
- inset: 0;
- border-radius: 50%;
- border: 1px solid color-mix(in srgb, var(--accent-2) 35%, transparent);
- opacity: var(--pulse-opacity, 0.35);
+ z-index: 2;
+ width: 164px;
+ height: 164px;
+ border: 1px solid rgba(139, 167, 255, 0.2);
+ opacity: var(--pulse-opacity);
transform: scale(var(--pulse-scale));
- transition: opacity 0.2s ease;
+ transition: opacity 180ms ease, transform 90ms linear;
+}
+
+.orb-orbit {
+ z-index: 1;
+ border: 1px solid rgba(139, 167, 255, 0.15);
+}
+
+.orbit-one {
+ width: 214px;
+ height: 140px;
+ transform: rotate(-18deg);
+}
+
+.orbit-one::after {
+ content: "";
+ position: absolute;
+ width: 7px;
+ height: 7px;
+ top: 12px;
+ right: 37px;
+ border-radius: 50%;
+ background: var(--warm);
+ box-shadow: 0 0 13px rgba(255, 179, 142, 0.65);
+}
+
+.orbit-two {
+ width: 230px;
+ height: 230px;
+ border-color: rgba(139, 167, 255, 0.08);
}
-/* Per-state glow */
.orb[data-state="idle"] .orb-core {
- filter: saturate(0.5) brightness(0.75);
- box-shadow: 0 0 30px 4px color-mix(in srgb, var(--accent-2) 25%, transparent);
+ filter: saturate(0.72) brightness(0.78);
+ box-shadow:
+ 0 0 0 1px rgba(213, 222, 255, 0.13),
+ 0 12px 28px rgba(2, 8, 20, 0.3),
+ 0 0 28px rgba(111, 143, 247, 0.16);
+}
+
+.orb[data-state="connecting"] .orbit-one,
+.orb[data-state="thinking"] .orbit-one {
+ animation: orbit-turn 3.5s linear infinite;
}
.orb[data-state="connecting"] .orb-core {
- animation-duration: 1.6s;
- filter: saturate(0.8) brightness(0.9);
+ animation: presence-breathe 1.7s ease-in-out infinite;
}
.orb[data-state="listening"] .orb-core {
- box-shadow: 0 0 70px 12px color-mix(in srgb, var(--accent-1) 55%, transparent),
- inset 0 0 30px rgba(255, 255, 255, 0.18);
+ box-shadow:
+ 0 0 0 1px rgba(213, 222, 255, 0.4),
+ 0 12px 28px rgba(2, 8, 20, 0.34),
+ 0 0 68px rgba(111, 143, 247, 0.56),
+ inset -12px -14px 26px rgba(10, 20, 50, 0.28);
+}
+
+.orb[data-state="listening"] .orb-ring {
+ border-color: rgba(139, 167, 255, 0.5);
}
.orb[data-state="thinking"] .orb-core {
- animation-duration: 2s;
- filter: saturate(1.1) brightness(1.05);
- box-shadow: 0 0 75px 14px color-mix(in srgb, var(--accent-2) 60%, transparent),
- inset 0 0 30px rgba(255, 255, 255, 0.2);
+ background:
+ radial-gradient(circle at 32% 24%, rgba(255, 255, 255, 0.9) 0 3%, transparent 20%),
+ radial-gradient(circle at 38% 30%, #f3c9b5, #a783ca 42%, #5d68bd 72%, #29365f 100%);
+ box-shadow: 0 0 62px rgba(167, 131, 202, 0.48);
}
.orb[data-state="speaking"] .orb-core {
- animation: none;
- box-shadow: 0 0 90px 18px color-mix(in srgb, var(--accent-1) 65%, transparent),
- inset 0 0 34px rgba(255, 255, 255, 0.22);
+ box-shadow:
+ 0 0 0 1px rgba(213, 222, 255, 0.45),
+ 0 12px 28px rgba(2, 8, 20, 0.34),
+ 0 0 78px rgba(111, 143, 247, 0.64),
+ 0 0 105px rgba(255, 179, 142, 0.11);
}
-@keyframes breathe {
- 0%, 100% { transform: scale(calc(var(--pulse-scale) * 1)); }
- 50% { transform: scale(calc(var(--pulse-scale) * 1.05)); }
+.orb[data-state="speaking"] .orbit-one::after {
+ background: #ffd0b8;
+}
+
+@keyframes presence-breathe {
+ 0%, 100% { transform: scale(calc(var(--pulse-scale) * 0.98)); }
+ 50% { transform: scale(calc(var(--pulse-scale) * 1.045)); }
+}
+
+@keyframes orbit-turn {
+ to { transform: rotate(342deg); }
}
.orb-labels {
+ min-height: 46px;
+ margin-top: 0.2rem;
display: flex;
flex-direction: column;
align-items: center;
- gap: 0.4rem;
- margin-top: 1rem;
- min-height: 3.6rem;
+ gap: 0.35rem;
}
.state-label {
- font-size: 0.85rem;
+ color: var(--ink-soft);
+ font-size: 0.83rem;
font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--text-dim);
-}
-
-.thinking-chip {
- font-size: 0.75rem;
- padding: 0.25rem 0.75rem;
- border-radius: 999px;
- background: var(--panel-strong);
- border: 1px solid var(--border);
- color: var(--text-dim);
- animation: chipPulse 1.4s ease-in-out infinite;
-}
-
-@keyframes chipPulse {
- 0%, 100% { opacity: 0.55; }
- 50% { opacity: 1; }
}
+.thinking-chip,
.barge-hint {
- font-size: 0.75rem;
- color: var(--text-faint);
- opacity: 0.6;
+ color: var(--ink-muted);
+ font-size: 0.73rem;
}
-/* ── Controls ────────────────────────────────────────────────────────────── */
+.thinking-chip::before {
+ content: "";
+ display: inline-block;
+ width: 5px;
+ height: 5px;
+ margin: 0 0.42rem 0.1rem 0;
+ border-radius: 50%;
+ background: var(--warm);
+ vertical-align: middle;
+ animation: think-pulse 1.2s ease-in-out infinite;
+}
+
+@keyframes think-pulse {
+ 50% { opacity: 0.28; transform: scale(0.75); }
+}
+
+/* ── Buttons and controls ───────────────────────────────────────────────── */
.controls {
+ position: relative;
+ z-index: 2;
display: flex;
- gap: 0.75rem;
- justify-content: center;
align-items: center;
- margin-bottom: 1.25rem;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 0.6rem;
+ width: 100%;
}
.btn {
- padding: 0.75rem 2rem;
- border: none;
- border-radius: 8px;
- font-size: 1rem;
- font-weight: 600;
+ min-height: 42px;
+ border: 0;
+ border-radius: 9px;
+ padding: 0.68rem 1rem;
cursor: pointer;
- transition: all 0.2s;
- font-family: inherit;
+ font-size: 0.84rem;
+ font-weight: 650;
+ line-height: 1;
+ transition: color 180ms ease, background 180ms ease, border-color 180ms ease, transform 180ms var(--ease-out), opacity 180ms ease;
+}
+
+.btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+}
+
+.btn:active:not(:disabled) {
+ transform: translateY(0);
+}
+
+.btn:focus-visible,
+.voice-card:focus-visible {
+ outline: 2px solid var(--focus);
+ outline-offset: 3px;
}
.btn:disabled {
- opacity: 0.4;
+ opacity: 0.38;
cursor: not-allowed;
}
.btn-primary {
- background: #3b82f6;
- color: white;
+ position: relative;
+ min-width: 180px;
+ color: #07101d;
+ background: var(--ink);
}
.btn-primary:hover:not(:disabled) {
- background: #2563eb;
- transform: translateY(-1px);
+ background: #dfe7f4;
+}
+
+.button-spark {
+ display: inline-block;
+ width: 7px;
+ height: 7px;
+ margin-right: 0.5rem;
+ border-radius: 50%;
+ background: var(--iris-deep);
+ box-shadow: 0 0 0 4px rgba(60, 95, 201, 0.12);
+}
+
+.btn-primary:disabled,
+.btn-danger:disabled {
+ display: none;
}
.btn-danger {
- background: var(--danger);
- color: white;
+ color: #fff4f1;
+ background: #8f403a;
}
.btn-danger:hover:not(:disabled) {
- background: #dc2626;
+ background: #a84b43;
+}
+
+.btn-secondary {
+ color: var(--ink-soft);
+ background: var(--surface-raised);
+ border: 1px solid var(--line);
+}
+
+.btn-secondary:hover:not(:disabled) {
+ color: var(--ink);
+ border-color: var(--line-strong);
+ background: var(--surface-soft);
}
.btn-icon {
- display: grid;
- place-items: center;
- width: 44px;
- height: 44px;
+ width: 42px;
+ min-width: 42px;
+ height: 42px;
padding: 0;
- border-radius: 50%;
- background: var(--panel);
- color: var(--text-dim);
- border: 1px solid var(--border);
+ display: inline-grid;
+ place-items: center;
+ color: var(--ink-muted);
+ background: var(--surface-raised);
+ border: 1px solid var(--line);
}
-.btn-icon:hover {
- color: var(--text);
- background: var(--panel-strong);
+.btn-icon:hover:not(:disabled) {
+ color: var(--ink);
+ border-color: var(--line-strong);
+ background: var(--surface-soft);
}
.btn-icon.muted {
- color: #ef4444;
- border-color: #ef4444;
- background: rgba(239, 68, 68, 0.1);
+ color: #ffd1ca;
+ border-color: rgba(255, 128, 111, 0.5);
+ background: rgba(143, 64, 58, 0.4);
}
.btn-ghost {
+ min-height: 34px;
+ padding: 0.45rem 0.65rem;
+ color: var(--ink-muted);
background: transparent;
- color: var(--text-faint);
- padding: 0.4rem 0.75rem;
- font-size: 0.8rem;
- border-radius: 6px;
}
-.btn-ghost:hover {
- color: var(--text);
- background: var(--panel-strong);
+.btn-ghost:hover:not(:disabled) {
+ color: var(--ink);
+ background: var(--surface-raised);
+}
+
+.tasks-trigger {
+ position: relative;
+ min-height: 38px;
+ gap: 0.45rem;
+ padding: 0 0.8rem;
+ font-size: 0.78rem;
+}
+
+.tasks-badge {
+ min-width: 17px;
+ height: 17px;
+ display: inline-grid;
+ place-items: center;
+ padding: 0 4px;
+ border-radius: 999px;
+ color: #07101d;
+ background: var(--warm);
+ font-size: 0.64rem;
+ font-weight: 750;
+}
+
+.connection-strip {
+ width: min(340px, 100%);
+ margin-top: 1rem;
}
-/* ── Status + mic meter ──────────────────────────────────────────────────── */
.status {
+ min-height: 20px;
+ color: var(--ink-muted);
+ font-size: 0.72rem;
text-align: center;
- padding: 0.75rem;
- background: var(--panel);
- border: 1px solid var(--border);
- border-radius: 8px;
- margin-bottom: 0.6rem;
- font-size: 0.9rem;
- color: var(--text-dim);
}
.mic-meter {
- height: 4px;
- background: var(--panel-strong);
- border-radius: 2px;
- margin-bottom: 1.5rem;
+ height: 3px;
+ margin-top: 0.55rem;
overflow: hidden;
+ border-radius: 999px;
+ background: rgba(139, 167, 255, 0.1);
}
.mic-meter-fill {
display: block;
+ width: 0;
height: 100%;
- width: 0%;
- background: linear-gradient(90deg, var(--accent-1), var(--accent-2));
- border-radius: 2px;
- transition: width 0.1s linear;
+ border-radius: inherit;
+ background: var(--iris);
+ transition: width 80ms linear;
}
-/* ── Transcript ──────────────────────────────────────────────────────────── */
+.privacy-note {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ margin-top: 1.15rem;
+ color: var(--ink-muted);
+ font-size: 0.7rem;
+}
+
+.privacy-note svg {
+ color: var(--mint);
+}
+
+/* ── Conversation ───────────────────────────────────────────────────────── */
.transcript {
- background: var(--panel);
- backdrop-filter: blur(12px);
- -webkit-backdrop-filter: blur(12px);
- border: 1px solid var(--border);
- border-radius: 12px;
- padding: 1rem;
- max-height: 50vh;
- overflow-y: auto;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ padding: clamp(1.4rem, 3vw, 2.1rem);
+ border-left: 1px solid var(--line);
+ background: #0a1524;
}
.transcript-header {
display: flex;
align-items: center;
justify-content: space-between;
- font-weight: 700;
- color: var(--text-dim);
- margin-bottom: 1rem;
- font-size: 0.85rem;
- text-transform: uppercase;
- letter-spacing: 0.05em;
+ gap: 1rem;
+ padding-bottom: 1.1rem;
+ border-bottom: 1px solid var(--line);
+}
+
+.transcript-header h2 {
+ color: var(--ink);
+ font-size: 1rem;
+ font-weight: 650;
+ letter-spacing: -0.01em;
+}
+
+.transcript-header p {
+ margin-top: 0.22rem;
+ color: var(--ink-muted);
+ font-size: 0.7rem;
+}
+
+#messages {
+ flex: 1;
+ min-height: 0;
+ overflow-y: auto;
+ padding: 1.25rem 0.2rem 1rem 0;
+ scroll-behavior: smooth;
+}
+
+#messages:empty {
+ display: grid;
+ place-items: center;
+}
+
+#messages:empty::before {
+ content: "Your conversation will appear here.\A Start when you’re ready—there’s nothing to configure.";
+ max-width: 30ch;
+ color: var(--ink-muted);
+ font-size: 0.84rem;
+ line-height: 1.65;
+ text-align: center;
+ white-space: pre-wrap;
}
.message-row {
+ position: relative;
display: flex;
align-items: flex-end;
- gap: 0.5rem;
- margin-bottom: 0.6rem;
- position: relative;
- animation: msgIn 120ms ease-out;
-}
-
-@keyframes msgIn {
- from { opacity: 0; transform: translateY(6px); }
- to { opacity: 1; transform: translateY(0); }
+ gap: 0.55rem;
+ margin-bottom: 0.85rem;
+ animation: message-in 180ms var(--ease-out);
}
.message-row.user {
justify-content: flex-end;
}
+.message-row.system {
+ justify-content: center;
+}
+
+.message-row.system .bubble {
+ padding: 0.35rem 0.65rem;
+ color: var(--ink-muted);
+ background: transparent;
+ font-size: 0.7rem;
+}
+
+@keyframes message-in {
+ from { opacity: 0; transform: translateY(5px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
.avatar-dot {
- width: 24px;
- height: 24px;
- border-radius: 50%;
- background: linear-gradient(135deg, var(--accent-1), var(--accent-2));
- flex-shrink: 0;
+ position: relative;
+ width: 27px;
+ height: 27px;
+ flex: 0 0 27px;
margin-bottom: 2px;
+ border: 1px solid rgba(139, 167, 255, 0.38);
+ border-radius: 50%;
+}
+
+.avatar-dot::after {
+ content: "";
+ position: absolute;
+ inset: 8px;
+ border-radius: 50%;
+ background: var(--iris);
}
.bubble {
- max-width: 78%;
- padding: 0.6rem 0.9rem;
- border-radius: 14px;
- font-size: 0.95rem;
- line-height: 1.5;
- position: relative;
+ max-width: min(82%, 58ch);
+ padding: 0.72rem 0.9rem;
+ border-radius: 12px;
+ color: var(--ink-soft);
+ font-size: 0.9rem;
+ line-height: 1.55;
+ overflow-wrap: anywhere;
}
.message-row.user .bubble {
+ color: #e8efff;
background: var(--user-bubble);
- border-bottom-right-radius: 4px;
+ border-bottom-right-radius: 3px;
}
.message-row.agent .bubble {
background: var(--agent-bubble);
- border-bottom-left-radius: 4px;
+ border-bottom-left-radius: 3px;
}
+.message-row.partial,
.bubble.partial {
- opacity: 0.55;
+ opacity: 0.58;
}
-/* Timestamps on hover (CSS only, from data-ts attribute) */
.message-row::after {
content: attr(data-ts);
position: absolute;
- bottom: -1.1rem;
- font-size: 0.68rem;
- color: var(--text-faint);
+ bottom: -0.9rem;
+ color: var(--ink-muted);
+ font-size: 0.62rem;
opacity: 0;
- transition: opacity 0.15s ease;
pointer-events: none;
+ transition: opacity 150ms ease;
}
.message-row:hover::after {
- opacity: 1;
+ opacity: 0.75;
}
-.message-row.user::after {
- right: 0;
-}
+.message-row.user::after { right: 0; }
+.message-row.agent::after { left: 2rem; }
-.message-row.agent::after {
- left: 2rem;
-}
-
-/* ── Agent audio visualizer (bars on latest agent bubble) ─────────────────── */
.audio-viz {
+ height: 13px;
+ margin-left: 0.5rem;
display: inline-flex;
align-items: flex-end;
gap: 2px;
- height: 14px;
- margin-left: 0.6rem;
vertical-align: middle;
}
.audio-viz i {
- width: 3px;
+ width: 2px;
height: 15%;
border-radius: 2px;
- background: linear-gradient(180deg, var(--accent-2), var(--accent-1));
- opacity: 0.8;
- transition: height 0.08s linear;
+ background: var(--iris);
+ opacity: 0.78;
+ transition: height 70ms linear;
}
-/* ── Settings sheet (voice picker) ───────────────────────────────────────── */
+/* ── Voice settings ─────────────────────────────────────────────────────── */
.sheet-backdrop {
position: fixed;
inset: 0;
- background: rgba(0, 0, 0, 0.5);
- z-index: 90;
+ z-index: var(--z-backdrop);
+ background: rgba(2, 7, 14, 0.68);
opacity: 0;
- transition: opacity 0.2s ease;
+ transition: opacity 200ms ease;
}
.sheet-backdrop:not([hidden]) {
@@ -426,21 +822,18 @@ h1 {
position: fixed;
left: 50%;
bottom: 0;
- transform: translate(-50%, 100%);
- width: 100%;
- max-width: 680px;
- max-height: 75vh;
- background: var(--panel-strong);
- backdrop-filter: blur(12px);
- -webkit-backdrop-filter: blur(12px);
- border: 1px solid var(--border);
- border-bottom: none;
- border-radius: 16px 16px 0 0;
+ z-index: var(--z-sheet);
+ width: min(660px, 100%);
+ max-height: min(76vh, 680px);
padding: 0.75rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom));
- z-index: 100;
- transition: transform 0.25s cubic-bezier(0.32, 0.72, 0, 1);
display: flex;
flex-direction: column;
+ border: 1px solid var(--line-strong);
+ border-bottom: 0;
+ border-radius: 16px 16px 0 0;
+ background: #101e31;
+ transform: translate(-50%, 102%);
+ transition: transform 240ms var(--ease-out);
}
.settings-sheet.open {
@@ -449,250 +842,324 @@ h1 {
.sheet-handle {
width: 36px;
- height: 4px;
- border-radius: 2px;
- background: var(--border);
- margin: 0 auto 0.75rem;
-}
-
-.sheet-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 1rem;
-}
-
-.sheet-header h2 {
- font-size: 1.1rem;
- font-weight: 700;
-}
-
-.voice-list {
- overflow-y: auto;
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
- padding-right: 0.25rem;
-}
-
-.voice-card {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 0.75rem;
- padding: 0.8rem 1rem;
- border-radius: 10px;
- background: var(--panel);
- border: 1px solid var(--border);
- cursor: pointer;
- transition: all 0.15s ease;
-}
-
-.voice-card:hover {
- background: var(--panel-strong);
-}
-
-.voice-card.active {
- border-color: color-mix(in srgb, var(--accent-2) 60%, transparent);
- background: var(--agent-bubble);
-}
-
-.voice-name {
- font-size: 0.95rem;
- font-weight: 500;
-}
-
-/* ── Scrollbar ───────────────────────────────────────────────────────────── */
-.transcript::-webkit-scrollbar,
-.voice-list::-webkit-scrollbar { width: 6px; }
-.transcript::-webkit-scrollbar-track,
-.voice-list::-webkit-scrollbar-track { background: transparent; }
-.transcript::-webkit-scrollbar-thumb,
-.voice-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
-
-/* ── Task panel ──────────────────────────────────────────────────────────── */
-.tasks-fab {
- position: fixed;
- bottom: calc(1.5rem + env(safe-area-inset-bottom));
- right: 1.5rem;
- z-index: 100;
-}
-
-.tasks-badge {
- position: absolute;
- top: -4px;
- right: -4px;
- background: #3b82f6;
- color: #fff;
- font-size: 0.65rem;
- font-weight: 700;
- min-width: 18px;
- height: 18px;
- border-radius: 9px;
- display: grid;
- place-items: center;
- padding: 0 4px;
-}
-
-.tasks-panel {
- position: fixed;
- top: 0;
- right: -320px;
- width: 320px;
- max-width: 85vw;
- height: 100dvh;
- background: var(--panel);
- border-left: 1px solid var(--border);
- z-index: 200;
- display: flex;
- flex-direction: column;
- transition: right 0.25s ease;
-}
-
-.tasks-panel.open {
- right: 0;
+ height: 3px;
+ margin: 0 auto 1rem;
+ border-radius: 999px;
+ background: var(--line-strong);
}
+.sheet-header,
.tasks-header {
display: flex;
align-items: center;
justify-content: space-between;
- padding: 1rem;
- border-bottom: 1px solid var(--border);
+ gap: 1rem;
}
+.sheet-header {
+ padding-bottom: 1rem;
+}
+
+.sheet-header h2,
.tasks-header h2 {
+ color: var(--ink);
font-size: 1rem;
- margin: 0;
+ font-weight: 650;
+}
+
+.sheet-header p,
+.tasks-header p {
+ margin-top: 0.25rem;
+ color: var(--ink-muted);
+ font-size: 0.72rem;
+}
+
+.voice-list {
+ min-height: 0;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 0.4rem;
+ padding: 0.15rem 0.2rem 0 0;
+}
+
+.voice-card {
+ min-height: 54px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.8rem;
+ padding: 0.65rem 0.75rem 0.65rem 1rem;
+ border: 1px solid transparent;
+ border-radius: 10px;
+ cursor: pointer;
+ color: var(--ink-soft);
+ background: rgba(23, 41, 65, 0.55);
+ transition: color 160ms ease, background 160ms ease, border-color 160ms ease;
+}
+
+.voice-card:hover {
+ color: var(--ink);
+ background: var(--surface-soft);
+}
+
+.voice-card.active {
+ color: var(--ink);
+ border-color: rgba(139, 167, 255, 0.42);
+ background: rgba(60, 95, 201, 0.18);
+}
+
+.voice-name {
+ font-size: 0.86rem;
+ font-weight: 600;
+}
+
+.voice-card.active .voice-name::after {
+ content: "Selected";
+ display: inline-block;
+ margin-left: 0.55rem;
+ color: var(--iris);
+ font-size: 0.66rem;
+ font-weight: 550;
+}
+
+.voice-preview {
+ min-height: 32px;
+ color: var(--ink-muted);
+}
+
+.voice-preview::before {
+ content: "Listen";
+}
+
+/* ── Tasks ──────────────────────────────────────────────────────────────── */
+.tasks-panel {
+ position: fixed;
+ top: 0;
+ right: 0;
+ z-index: var(--z-panel);
+ width: min(380px, 92vw);
+ height: 100dvh;
+ display: flex;
+ flex-direction: column;
+ border-left: 1px solid var(--line-strong);
+ background: #0d1929;
+ transform: translateX(102%);
+ transition: transform 240ms var(--ease-out);
+}
+
+.tasks-panel.open {
+ transform: translateX(0);
+}
+
+.tasks-header {
+ padding: calc(1.1rem + env(safe-area-inset-top)) 1.1rem 1rem;
+ border-bottom: 1px solid var(--line);
}
.tasks-list {
flex: 1;
overflow-y: auto;
- padding: 0.75rem;
+ padding: 0.9rem;
display: flex;
flex-direction: column;
- gap: 0.75rem;
+ gap: 0.65rem;
}
.tasks-empty {
- color: var(--text-faint);
- font-size: 0.85rem;
+ min-height: 180px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 0.35rem;
+ color: var(--ink-muted);
text-align: center;
- margin-top: 2rem;
+ font-size: 0.78rem;
+}
+
+.tasks-empty strong {
+ color: var(--ink-soft);
+ font-size: 0.86rem;
}
.task-card {
- background: var(--panel-strong);
- border: 1px solid var(--border);
+ padding: 0.85rem;
border-radius: 10px;
- padding: 0.75rem;
- font-size: 0.82rem;
+ color: var(--ink-soft);
+ background: var(--surface-raised);
+ font-size: 0.8rem;
}
.task-card-header {
display: flex;
align-items: center;
gap: 0.5rem;
- margin-bottom: 0.4rem;
+ margin-bottom: 0.45rem;
}
.task-status-dot {
- width: 8px;
- height: 8px;
+ width: 7px;
+ height: 7px;
+ flex: 0 0 7px;
border-radius: 50%;
- background: #6b7280;
- flex-shrink: 0;
+ background: var(--ink-muted);
}
.task-status-dot.running {
- background: #3b82f6;
- animation: pulse-dot 1.5s infinite;
+ background: var(--iris);
+ animation: status-pulse 1.4s ease-in-out infinite;
}
-.task-status-dot.completed {
- background: #22c55e;
-}
+.task-status-dot.completed { background: var(--mint); }
+.task-status-dot.failed { background: var(--danger); }
-.task-status-dot.failed {
- background: #ef4444;
-}
-
-@keyframes pulse-dot {
- 0%, 100% { opacity: 1; }
- 50% { opacity: 0.4; }
+@keyframes status-pulse {
+ 50% { opacity: 0.3; }
}
.task-desc {
- font-weight: 600;
- color: var(--text);
flex: 1;
overflow: hidden;
+ color: var(--ink);
+ font-weight: 600;
text-overflow: ellipsis;
white-space: nowrap;
}
.task-steps {
+ max-height: 200px;
margin-top: 0.5rem;
- padding-left: 0;
- list-style: none;
+ overflow-y: auto;
display: flex;
flex-direction: column;
gap: 0.3rem;
- max-height: 200px;
- overflow-y: auto;
+ list-style: none;
+}
+
+.task-step,
+.task-result,
+.task-error {
+ padding: 0.42rem 0.5rem;
+ border-radius: 6px;
+ font-size: 0.72rem;
}
.task-step {
- font-size: 0.75rem;
- color: var(--text-dim);
- padding: 0.25rem 0.4rem;
- border-radius: 4px;
- background: rgba(0,0,0,0.15);
+ color: var(--ink-muted);
+ background: rgba(5, 11, 20, 0.3);
}
-.task-step.tool_call {
- color: #60a5fa;
-}
+.task-step.tool_call { color: #a9bbff; }
+.task-step.tool_result { color: var(--ink-muted); }
+.task-step.text { color: var(--ink-soft); }
+.task-result { margin-top: 0.5rem; color: #bcebd8; background: rgba(118, 217, 178, 0.1); }
+.task-error { margin-top: 0.5rem; color: #ffc2ba; background: rgba(255, 128, 111, 0.1); }
-.task-step.tool_result {
- color: var(--text-faint);
-}
+/* ── Responsive ─────────────────────────────────────────────────────────── */
+@media (max-width: 880px) {
+ body {
+ padding: calc(0.85rem + env(safe-area-inset-top))
+ calc(0.85rem + env(safe-area-inset-right))
+ calc(0.85rem + env(safe-area-inset-bottom))
+ calc(0.85rem + env(safe-area-inset-left));
+ }
-.task-step.text {
- color: var(--text);
- font-weight: 500;
-}
+ .workspace {
+ grid-template-columns: 1fr;
+ height: auto;
+ min-height: auto;
+ }
-.task-result {
- margin-top: 0.5rem;
- padding: 0.5rem;
- background: rgba(34, 197, 94, 0.1);
- border-radius: 6px;
- font-size: 0.8rem;
- color: var(--text);
-}
+ .voice-console {
+ min-height: 620px;
+ }
-.task-error {
- margin-top: 0.5rem;
- padding: 0.5rem;
- background: rgba(239, 68, 68, 0.1);
- border-radius: 6px;
- font-size: 0.8rem;
- color: #fca5a5;
+ .transcript {
+ min-height: 430px;
+ max-height: 62dvh;
+ border-top: 1px solid var(--line);
+ border-left: 0;
+ }
}
-/* ── Reduced motion ──────────────────────────────────────────────────────── */
+@media (max-width: 560px) {
+ body {
+ padding-right: env(safe-area-inset-right);
+ padding-left: env(safe-area-inset-left);
+ }
+
+ .topbar {
+ padding-right: 0.85rem;
+ padding-left: 0.85rem;
+ margin-bottom: 0.65rem;
+ }
+
+ .brand p,
+ .identity-chip {
+ display: none;
+ }
+
+ .workspace {
+ border-right: 0;
+ border-left: 0;
+ border-radius: 0;
+ }
+
+ .voice-console {
+ min-height: calc(100dvh - 82px);
+ padding: 2.1rem 1.15rem 1.25rem;
+ }
+
+ .console-intro h2 {
+ font-size: 1.7rem;
+ }
+
+ .orb-stage {
+ min-height: 300px;
+ }
+
+ .orb {
+ width: 235px;
+ height: 235px;
+ transform: scale(0.94);
+ }
+
+ .controls {
+ max-width: 330px;
+ }
+
+ .btn-primary,
+ .btn-danger {
+ flex: 1 1 180px;
+ }
+
+ .privacy-note {
+ margin-top: 1rem;
+ }
+
+ .transcript {
+ min-height: 480px;
+ max-height: none;
+ padding: 1.25rem 1rem;
+ }
+
+ .tasks-panel {
+ width: 100vw;
+ }
+
+ .bubble {
+ max-width: 86%;
+ }
+}
+
@media (prefers-reduced-motion: reduce) {
- .orb-core,
- .thinking-chip,
- .message-row,
- .settings-sheet,
- .sheet-backdrop,
- .tasks-panel,
- .audio-viz i,
- .mic-meter-fill {
- animation: none !important;
- transition: none !important;
+ *,
+ *::before,
+ *::after {
+ scroll-behavior: auto !important;
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
}
}
-
-
+
+
Background Tasks
-
+
+ Background tasks
+Longer work continues here.
+
-
No tasks yet. Ask Hope to research something.
+
+ Nothing running
+ Ask Hope to research or compare something.
+