+
You / Assistant
← HIDE in white theme
+
…message text…
← restyle as flat bubble
+ We target those classes (not the .bubble class, which is for the floating
+ ephemeral stack) because the persistent conversation rows live here. ─── */
+
+/* 1) Kill the old "You / Assistant / Tool call" uppercase mono eyebrow. The
+ Vocero mobile design replaces it with a name+timestamp meta line above
+ each bubble instead. */
+html[data-theme="white"] .chat-history .hist-role,
+html[data-theme="white"] .chat-history .bubble-role {
+ display: none !important;
+}
+
+/* 2) Layout: each row is a flex column with room for the 36 px avatar circle
+ sitting outside the bubble on the role side. */
+html[data-theme="white"] .chat-history .hist-msg,
+html[data-theme="white"] #bubble-stack .bubble {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ max-width: calc(100% - 56px);
+ box-sizing: border-box;
+ position: relative;
+ margin-top: 8px;
+ padding-top: 22px; /* 22 px reserved for the "Vocero 16:14" meta label above */
+}
+/* Anchor hist-body/bubble-body so absolute-positioned floating meta labels
+ (painted via ::before on the body) use the bubble itself as the reference
+ box instead of climbing up to chat-history. This is the ROOT FIX of the
+ "16:14 timestamp floats in the middle of the page" bug from the previous
+ screenshot. */
+html[data-theme="white"] .chat-history .hist-msg .hist-body,
+html[data-theme="white"] #bubble-stack .bubble .bubble-body {
+ position: relative;
+}
+
+/* 3) FLIP the default dark-theme alignment. Screenshot reference:
+ ASSISTANT = left side (blue bot avatar left of bubble, grey bubble)
+ USER = right side (EM/AV initials circle on RIGHT, light-blue bubble)
+ The default dark purple theme stores them the opposite way, so we flip
+ align-self AND the auto margin here. */
+html[data-theme="white"] .chat-history .hist-msg.assistant,
+html[data-theme="white"] #bubble-stack .bubble.assistant {
+ align-self: flex-start !important;
+ margin-right: auto !important;
+ margin-left: 52px !important; /* 36 avatar + 16 gap */
+}
+html[data-theme="white"] .chat-history .hist-msg.user,
+html[data-theme="white"] #bubble-stack .bubble.user {
+ align-self: flex-end !important;
+ margin-left: auto !important;
+ margin-right: 52px !important;
+}
+
+/* 4) The actual speech bubble body.
+ Assistant (grey flat 200-level): #F3F4F6 rounded 18 except bottom-left corner 6px
+ User (light-blue 100): #DBEAFE rounded 18 except bottom-right corner 6px
+ Drop every original dark-theme decoration: glass backdrop, 28px deep
+ drop shadow, gradient borders. Keep it perfectly flat. */
+html[data-theme="white"] .chat-history .hist-msg .hist-body,
+html[data-theme="white"] #bubble-stack .bubble .bubble-body {
+ padding: 12px 15px !important;
+ border-radius: 18px !important;
+ font-size: clamp(14.5px, 3.3vw, 16.5px) !important;
+ line-height: 1.45 !important;
+ letter-spacing: -0.005em !important;
+ color: #0f172a !important;
+ background: #ffffff;
+ border: 1px solid transparent !important;
+ box-shadow: none !important;
+ backdrop-filter: none !important;
+ -webkit-backdrop-filter: none !important;
+ word-break: break-word;
+ white-space: pre-wrap;
+}
+html[data-theme="white"] .chat-history .hist-msg.assistant .hist-body,
+html[data-theme="white"] #bubble-stack .bubble.assistant .bubble-body {
+ background: #f3f4f6 !important;
+ border-bottom-left-radius: 6px !important;
+ color: #0f172a !important;
+}
+html[data-theme="white"] .chat-history .hist-msg.user .hist-body,
+html[data-theme="white"] #bubble-stack .bubble.user .bubble-body {
+ background: #dbeafe !important;
+ border-bottom-right-radius: 6px !important;
+ color: #0f172a !important;
+}
+/* Partial-streaming bubble (growing AI response) = same shape, slightly lower opacity */
+html[data-theme="white"] .chat-history .hist-body.partial,
+html[data-theme="white"] .bubble-body.partial {
+ opacity: 0.92;
+}
+
+/* 5) AVATAR circles outside each bubble (painted on the row wrapper ::before)
+ Assistant: blue circle + inline robot SVG, LEFT, outside bubble
+ User : light-blue "AV"/"EM" initials, RIGHT, outside bubble
+ Initials placeholder for user is pulled from data-user-initials attribute
+ if the chat renderer writes it; fallback is the letters "AV" (matches the
+ Alessandro V… user shown in the customer screenshot).
+
+ NOTE 2026-09-10: we replaced the 🤖 emoji with a tiny hand-crafted SVG
+ robot icon painted via background-image. The emoji rendered as a
+ crown-head robot on some Android versions; the SVG is pixel-perfect
+ cross-platform and matches the deep-blue assistant avatar. */
+html[data-theme="white"] .chat-history .hist-msg::before,
+html[data-theme="white"] #bubble-stack .bubble::before {
+ position: absolute !important;
+ top: 22px !important; /* line up with bubble body, below the meta line */
+ width: 36px;
+ height: 36px;
+ border-radius: 999px;
+ display: inline-flex !important;
+ align-items: center;
+ justify-content: center;
+ color: #ffffff;
+ font-size: 14px;
+ font-weight: 700;
+ letter-spacing: -0.01em;
+ z-index: 2;
+ content: "";
+ box-shadow: 0 2px 8px rgba(15, 23, 42, 0.1);
+}
+html[data-theme="white"] .chat-history .hist-msg.assistant::before,
+html[data-theme="white"] #bubble-stack .bubble.assistant::before {
+ left: -52px;
+ background-color: #2563eb !important;
+ background-image: url("data:image/svg+xml;utf8,
");
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: 20px 20px;
+ border: 1px solid rgba(59, 130, 246, 0.25);
+}
+/* Remove the old ::after with the robot emoji that was overlaying the avatar. */
+html[data-theme="white"] .chat-history .hist-msg.assistant::after,
+html[data-theme="white"] #bubble-stack .bubble.assistant::after {
+ display: none !important;
+ content: none !important;
+}
+html[data-theme="white"] .chat-history .hist-msg.user::before,
+html[data-theme="white"] #bubble-stack .bubble.user::before {
+ right: -52px;
+ background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%);
+ border: 1px solid rgba(96, 165, 250, 0.35);
+ /* Pull initials from a custom data attribute when chat.js sets it, else show
+ "AV" as a generic 2-letter default that matches the customer screenshot */
+ content: attr(data-user-initials, "AV");
+ align-items: center;
+ justify-content: center;
+}
+
+/* 6) META label "name HH:MM" on the same single line, ONE pseudo-element.
+ ──── USER FIX 2026-09-10: remove the hardcoded user name ────
+ The previous iteration hardcoded the Spanish names "Vocero" (assistant)
+ and "Emilio" (user) plus a fake "16:14" timestamp. Instead we now read
+ BOTH values dynamically from data attributes written by ui/chat.js at the
+ moment each row is inserted:
+ • assistant: data-asst-name + data-timestamp on .hist-body
+ • user : data-user-name + data-timestamp on .hist-body
+ Names fall back to "Vocero" / "Usuario" (Spanish generic) when chat.js
+ hasn't resolved a profile yet; timestamp falls back to "" which leaves
+ just the name visible. The concat format uses two non-breaking spaces
+ (\A0\A0 = U+00A0 ×2) between name and time, matching the screenshot.
+
+ ──── ROOT CAUSE FIX of the previous "timestamp in the middle of the page" bug ────
+ The earlier implementation split the meta across TWO selectors that used
+ different relative reference boxes:
+ • `> :first-child::before` → targetted .hist-role (hidden, display:none)
+ with `position:absolute; top:-20px` which had NO containing block, so
+ the browser walked up and used chat-history (full-width) → label
+ ended up at left=50% → "16:14" alone in the page centre.
+ NEW approach:
+ • Use the BUBBLE body itself (.hist-body / .bubble-body) as the single
+ relative reference box. Paint both NAME + HH:MM in ONE `content:`
+ string via `.hist-body::before`. Same absolute positioning as
+ before, but now contained inside the width of each bubble → name and
+ timestamp sit *perfectly aligned* above their bubble on every row,
+ at any viewport width. */
+html[data-theme="white"] .chat-history .hist-msg.assistant .hist-body::before,
+html[data-theme="white"] #bubble-stack .bubble.assistant .bubble-body::before {
+ /* Assistant meta = "
" */
+ content: attr(data-asst-name, "Vocero") "\A0\A0" attr(data-timestamp, "");
+ position: absolute;
+ top: -22px;
+ left: 0;
+ width: auto;
+ height: 16px;
+ line-height: 16px;
+ font-size: 12.5px;
+ font-weight: 600;
+ color: #64748b;
+ letter-spacing: -0.01em;
+ white-space: nowrap;
+ pointer-events: none;
+ display: inline-block !important;
+}
+html[data-theme="white"] .chat-history .hist-msg.user .hist-body::before,
+html[data-theme="white"] #bubble-stack .bubble.user .bubble-body::before {
+ /* User meta = " "
+ Falls back to "Usuario" when no caller profile has been injected yet,
+ never "Emilio" — user explicitly flagged the hard-coded name as wrong. */
+ content: attr(data-user-name, "Usuario") "\A0\A0" attr(data-timestamp, "");
+ position: absolute;
+ top: -22px;
+ right: 0;
+ width: auto;
+ height: 16px;
+ line-height: 16px;
+ font-size: 12.5px;
+ font-weight: 600;
+ color: #64748b;
+ letter-spacing: -0.01em;
+ white-space: nowrap;
+ pointer-events: none;
+ text-align: right;
+ display: inline-block !important;
+}
+/* Tool-call rows: shrink to pale inline card with no avatar */
+html[data-theme="white"] .chat-history .hist-msg.tool,
+html[data-theme="white"] .chat-history .bubble.tool {
+ max-width: 100% !important;
+ padding-top: 0;
+ margin: 6px 0 !important;
+ align-self: center !important;
+}
+html[data-theme="white"] .chat-history .hist-msg.tool::before,
+html[data-theme="white"] .chat-history .bubble.tool::before,
+html[data-theme="white"] .chat-history .hist-msg.tool::after,
+html[data-theme="white"] .chat-history .bubble.tool::after {
+ display: none !important;
+ content: none;
+}
+/* Also strip the floating meta from tool rows (they don't have a human role). */
+html[data-theme="white"] .chat-history .hist-msg.tool .hist-body::before {
+ content: none !important;
+ display: none !important;
+}
+
+/* ── App footer: thin white bar, just a subtle separator + brand line ─── */
+html[data-theme="white"] .app-footer {
+ background: #ffffff;
+ backdrop-filter: none;
+ -webkit-backdrop-filter: none;
+ padding-top: 10px;
+ padding-bottom: max(10px, env(safe-area-inset-bottom, 0px));
+}
+html[data-theme="white"] .app-footer::before {
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(37, 99, 235, 0.28) 30%,
+ rgba(59, 130, 246, 0.28) 70%,
+ transparent
+ );
+ opacity: 0.6;
+}
+html[data-theme="white"] .app-footer-text {
+ color: rgba(15, 23, 42, 0.6);
+ background: none;
+ -webkit-text-fill-color: inherit;
+ -webkit-background-clip: initial;
+ background-clip: initial;
+ filter: none;
+ letter-spacing: 0.12em;
+ font-weight: 600;
+}
+
+/* ── Modals: light theme restyle to match the white palette ─────────── */
+html[data-theme="white"] .modal-content {
+ background: #ffffff;
+ color: #0f172a;
+ border: 1px solid rgba(15, 23, 42, 0.08);
+ box-shadow: 0 30px 80px rgba(15, 23, 42, 0.18);
+}
+html[data-theme="white"] .modal-header h2 {
+ color: #0f172a;
+}
+html[data-theme="white"] .modal-header {
+ border-bottom-color: rgba(15, 23, 42, 0.08);
+}
+html[data-theme="white"] .modal-footer {
+ border-top-color: rgba(15, 23, 42, 0.08);
+}
+html[data-theme="white"] .modal input[type="text"],
+html[data-theme="white"] .modal input[type="password"],
+html[data-theme="white"] .modal textarea,
+html[data-theme="white"] .modal select {
+ background: #f8fafc;
+ border-color: rgba(15, 23, 42, 0.1);
+ color: #0f172a;
+}
+html[data-theme="white"] .modal input[type="text"]:focus,
+html[data-theme="white"] .modal input[type="password"]:focus,
+html[data-theme="white"] .modal textarea:focus,
+html[data-theme="white"] .modal select:focus {
+ border-color: #3b82f6;
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
+}
+html[data-theme="white"] .btn.primary {
+ background: linear-gradient(135deg, #2563eb, #3b82f6);
+ color: #ffffff;
+ border-color: transparent;
+}
+html[data-theme="white"] .btn.primary:disabled {
+ opacity: 0.6;
+ filter: grayscale(0%);
+}
+html[data-theme="white"] .btn.secondary {
+ background: #f1f5f9;
+ color: #0f172a;
+ border-color: rgba(15, 23, 42, 0.1);
+}
+html[data-theme="white"] .btn.secondary:hover {
+ background: #e2e8f0;
+}
+
+/* ── Reports sidebar restyle (the off-canvas panel + left sidebar) ───── */
+html[data-theme="white"] .reports-sidebar,
+html[data-theme="white"] .reports-sidebar-inner {
+ background: #ffffff;
+ color: #0f172a;
+ border-color: rgba(15, 23, 42, 0.08);
+}
+html[data-theme="white"] .reports-sidebar-header {
+ border-bottom-color: rgba(15, 23, 42, 0.08);
+ color: #0f172a;
+}
+html[data-theme="white"] .reports-sidebar-header h3 {
+ color: #0f172a;
+}
+
+/* ── Limit modal (budget) ───────────────────────────────────────────── */
+html[data-theme="white"] .limit-card {
+ background: #ffffff;
+ border: 1px solid rgba(15, 23, 42, 0.08);
+}
+html[data-theme="white"] .limit-title,
+html[data-theme="white"] .limit-msg {
+ color: #0f172a;
+}
+html[data-theme="white"] .limit-note {
+ color: rgba(15, 23, 42, 0.62);
+}
+
+/* ── User profile modal ─────────────────────────────────────────────── */
+html[data-theme="white"] .user-profile-card {
+ background: #ffffff;
+}
+html[data-theme="white"] .user-profile-avatar {
+ background: linear-gradient(135deg, #2563eb, #60a5fa);
+ color: #ffffff;
+ border-color: rgba(37, 99, 235, 0.2);
+}
+html[data-theme="white"] .user-profile-title {
+ color: #0f172a;
+}
+html[data-theme="white"] .user-profile-subtitle {
+ color: rgba(15, 23, 42, 0.65);
+}
+
+/* ── Tools modal switches ───────────────────────────────────────────── */
+html[data-theme="white"] .switch-track {
+ background: #cbd5e1;
+}
+html[data-theme="white"] .switch input:checked + .switch-track {
+ background: #2563eb;
+}
+
+/* ── Mobile: tighten when room is short ─────────────────────────────── */
+@media (max-width: 480px) {
+ html[data-theme="white"] .topbar {
+ padding: 14px 14px 4px;
+ }
+ html[data-theme="white"] .status-card {
+ margin: 10px 14px 4px;
+ }
+ html[data-theme="white"] .chat-panel {
+ margin: 4px 14px 0;
+ }
+ html[data-theme="white"] .white-waveform-left {
+ left: calc(50% - 58px - 72px);
+ }
+ html[data-theme="white"] .white-waveform-right {
+ right: calc(50% - 58px - 72px);
+ }
+ html[data-theme="white"] .white-waveform {
+ gap: 5px;
+ }
+ html[data-theme="white"] .white-waveform .w-bar {
+ width: 5px;
+ }
+}
+@media (max-height: 640px) {
+ html[data-theme="white"] .status-card {
+ padding: 10px;
+ }
+ html[data-theme="white"] .white-mic-stage {
+ padding: 14px 0 4px;
+ }
+ html[data-theme="white"] .white-mic-circle {
+ width: 98px;
+ height: 98px;
+ }
+ html[data-theme="white"] .white-mic-circle .wmc-icon {
+ width: 40px;
+ height: 40px;
+ }
+ html[data-theme="white"] .white-mic-circle.state-processing .wmc-spinner,
+ html[data-theme="white"] .white-mic-circle.state-connecting .wmc-spinner,
+ html[data-theme="white"] .white-mic-circle.state-queued .wmc-spinner {
+ width: 34px;
+ height: 34px;
+ }
+ html[data-theme="white"] .white-waveform .w-bar {
+ height: calc(var(--bar-h, 0.5) * 56px);
+ }
+ html[data-theme="white"] .white-waveform {
+ height: 56px;
+ }
+ html[data-theme="white"] .white-waveform-left {
+ left: calc(50% - 49px - 76px);
+ top: calc(14px + 49px);
+ }
+ html[data-theme="white"] .white-waveform-right {
+ right: calc(50% - 49px - 76px);
+ top: calc(14px + 49px);
+ }
+}