Spaces:
Running
Running
| /* ========================= | |
| BubbleGuard Apple-Style UI | |
| Dark-mode optimized (2025) | |
| ========================= */ | |
| /* ---------- Design Tokens ---------- */ | |
| :root{ | |
| /* Typography */ | |
| --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"; | |
| /* Light palette */ | |
| --bg: #f5f5f7; | |
| --bg-radial-1: #ffffff; | |
| --bg-radial-2: rgba(10,132,255,.08); | |
| --sheet: #ffffffcc; /* frosted surfaces */ | |
| --border: #e5e5ea; | |
| --text: #111114; | |
| --muted: #6e6e73; | |
| /* Bubbles */ | |
| --blue: #0A84FF; /* outgoing */ | |
| --blue-press: #0a7af0; | |
| --incoming: #E5E5EA; /* incoming */ | |
| --incoming-text: #000; | |
| /* Accents */ | |
| --focus: rgba(10,132,255,.5); | |
| --focus-outer: rgba(10,132,255,.15); | |
| /* Shadows */ | |
| --shadow: 0 6px 24px rgba(0,0,0,.06); | |
| --shadow-strong: 0 10px 28px rgba(0,0,0,.10); | |
| /* Overlays/Pop */ | |
| --popover-bg: rgba(28,28,30,.96); | |
| --chip-bg: rgba(118,118,128,.18); | |
| /* Misc */ | |
| --danger: #ff3b30; | |
| /* Timestamp color (light mode) */ | |
| --meta-color: #000; | |
| } | |
| [data-bs-theme="dark"]{ | |
| /* Dark palette tuned for contrast */ | |
| --bg: #0b0b0f; | |
| --bg-radial-1: #121217; | |
| --bg-radial-2: rgba(10,132,255,.10); | |
| --sheet: rgba(22,22,26,.76); | |
| --border: #2a2a31; | |
| --text: #ececf2; | |
| --muted: #a1a1aa; | |
| /* Bubbles */ | |
| --blue: #0A84FF; | |
| --blue-press: #0a74e0; | |
| --incoming: #1f1f24; /* deeper slate for dark */ | |
| --incoming-text: #ececf2; | |
| /* Accents */ | |
| --focus: rgba(10,132,255,.6); | |
| --focus-outer: rgba(10,132,255,.22); | |
| /* Shadows (softer/lower spread in dark to avoid haze) */ | |
| --shadow: 0 8px 24px rgba(0,0,0,.45); | |
| --shadow-strong: 0 12px 36px rgba(0,0,0,.55); | |
| --popover-bg: rgba(18,18,20,.98); | |
| --chip-bg: rgba(255,255,255,.08); | |
| /* Timestamp color (dark mode) */ | |
| --meta-color: #fff; | |
| } | |
| /* ---------- Base Layout ---------- */ | |
| html, body { height:100%; } | |
| body{ | |
| font-family: var(--font-ui); | |
| background: | |
| radial-gradient(900px 360px at 80% -10%, var(--bg-radial-1), transparent 60%), | |
| radial-gradient(900px 360px at -10% 110%, var(--bg-radial-2), transparent 70%), | |
| var(--bg); | |
| color: var(--text); | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| } | |
| /* Smooth theme transitions (respect reduced motion) */ | |
| @media (prefers-reduced-motion: no-preference){ | |
| body, .glass, .composer-wrap, .bubble, .input-ios, .ios-toast { | |
| transition: background-color .25s ease, color .25s ease, border-color .25s ease, box-shadow .25s ease; | |
| } | |
| } | |
| .app{ height:100dvh; display:grid; grid-template-rows:auto 1fr auto; } | |
| /* ---------- Header ---------- */ | |
| .glass{ | |
| backdrop-filter: saturate(1.15) blur(14px); | |
| background: var(--sheet); | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .header-logo{ width:28px; height:28px; border-radius:8px; } | |
| .app-title{ font-weight:600; letter-spacing:.2px; } | |
| .subtle{ color: var(--muted); font-size:.82rem; } | |
| /* Icon buttons (header + composer) */ | |
| .btn-ico{ | |
| border: none; | |
| background: transparent; | |
| font-size: 20px; | |
| line-height: 1; | |
| padding: .35rem .5rem; | |
| border-radius: 10px; | |
| color: inherit; | |
| } | |
| .btn-ico:hover{ background: color-mix(in oklab, var(--border), transparent 70%); } | |
| .btn-ico:focus-visible{ outline: 2px solid var(--focus); outline-offset: 2px; } | |
| /* ---------- Chat Area ---------- */ | |
| .container.chat-wrap{ padding: 14px 14px 8px; overflow:auto; } | |
| .row-start, .row-end{ | |
| display:flex; gap:.6rem; align-items:flex-end; margin-bottom: .5rem; | |
| } | |
| .row-end{ justify-content: flex-end; } | |
| .avatar{ width:28px; height:28px; border-radius:50%; flex:0 0 28px; } | |
| /* ---------- Bubbles ---------- */ | |
| .bubble{ | |
| max-width: 76%; | |
| border-radius: 20px; | |
| padding: 8px 12px; | |
| position: relative; | |
| box-shadow: var(--shadow); | |
| word-wrap: break-word; | |
| /* New message pop-in animation */ | |
| animation: pop .28s ease-out both; | |
| animation-delay: var(--bubble-delay, 0s); | |
| } | |
| .bubble .copy{ font-size: .98rem; line-height: 1.25rem; } | |
| /* timestamp uses theme token for color */ | |
| .bubble .meta{ | |
| font-size: .72rem; | |
| color: var(--meta-color); | |
| margin-top: 2px; | |
| text-align: right; | |
| } | |
| .bubble-you{ | |
| background: var(--blue); | |
| color: #fff; | |
| border-bottom-right-radius: 6px; /* iMessage corner */ | |
| /* Outgoing bubbles lift slightly as they appear */ | |
| animation-name: popYou, pop; /* first run popYou (translate), pop already set for scale */ | |
| } | |
| @keyframes popYou{ | |
| 0% { transform: translateY(6px) scale(.94); opacity:0; } | |
| 70% { transform: translateY(0) scale(1.04); opacity:1; } | |
| 100% { transform: translateY(0) scale(1); } | |
| } | |
| .bubble-them{ | |
| background: var(--incoming); | |
| color: var(--incoming-text); | |
| border-bottom-left-radius: 6px; | |
| } | |
| /* Bubble tails */ | |
| .bubble-you::after, .bubble-them::after{ | |
| content:""; position:absolute; bottom:0; width:10px; height:14px; background:transparent; | |
| } | |
| .bubble-you::after{ | |
| right:-2px; border-bottom-right-radius: 4px; | |
| box-shadow: 2px 2px 0 0 var(--blue); | |
| } | |
| .bubble-them::after{ | |
| left:-2px; border-bottom-left-radius: 4px; | |
| box-shadow: -2px 2px 0 0 var(--incoming); | |
| } | |
| /* Media inside bubbles */ | |
| .chat-image{ | |
| max-width: 260px; border-radius: 14px; display:block; box-shadow: var(--shadow-strong); | |
| animation: pop .28s ease-out both; | |
| } | |
| .audio-ios{ width: 260px; } | |
| /* ---------- Composer ---------- */ | |
| .composer-wrap{ | |
| backdrop-filter: blur(18px) saturate(1.1); | |
| border-top: 1px solid var(--border); | |
| background: var(--sheet); | |
| } | |
| .composer{ | |
| display:grid; grid-template-columns: auto 1fr auto auto auto; | |
| gap: .5rem; align-items:center; padding: .6rem 0; | |
| } | |
| .input-shell{ position: relative; display:flex; align-items:center; width:100%; } | |
| .input-ios{ | |
| background: color-mix(in oklab, var(--incoming), transparent 75%); | |
| border: 1px solid color-mix(in oklab, var(--border), transparent 20%); | |
| color: var(--text); | |
| border-radius: 18px; | |
| padding: .55rem 2.8rem .55rem .8rem; | |
| box-shadow: none; resize: none; width:100%; | |
| caret-color: var(--blue); | |
| } | |
| .input-ios::placeholder{ color: color-mix(in oklab, var(--muted), #000 0%); opacity:.8; } | |
| [data-bs-theme="dark"] .input-ios::placeholder{ color: color-mix(in oklab, var(--muted), #fff 8%); opacity:.85; } | |
| .input-ios:focus{ | |
| border-color: color-mix(in oklab, var(--blue), var(--border) 55%); | |
| outline: none; | |
| box-shadow: 0 0 0 .22rem var(--focus-outer); | |
| } | |
| /* typing indicator inside input — now bouncing */ | |
| .typing{ position:absolute; right:.8rem; top:50%; transform: translateY(-50%); } | |
| .typing-dot{ | |
| width:6px;height:6px;border-radius:999px;display:inline-block;background: color-mix(in oklab, var(--muted), #9aa0a6 15%); | |
| animation: bounceDot 1s infinite ease-in-out; | |
| } | |
| .typing-dot:nth-child(2){animation-delay:.16s} | |
| .typing-dot:nth-child(3){animation-delay:.32s} | |
| /* Send button */ | |
| .send-ios{ | |
| background: var(--blue); | |
| border: none; | |
| color: #fff; | |
| width: 36px; height: 36px; border-radius: 50%; | |
| display:inline-flex; align-items:center; justify-content:center; | |
| font-weight:600; font-size: 16px; | |
| box-shadow: 0 6px 18px color-mix(in oklab, var(--blue), transparent 65%); | |
| } | |
| /* click pulse feedback */ | |
| .send-ios:active{ background: var(--blue-press); animation: pulse .4s ease; } | |
| .send-ios:focus-visible{ outline: 2px solid var(--focus); outline-offset: 2px; } | |
| /* ---------- Toast (iOS banner style) ---------- */ | |
| .toast-zone{ position: fixed; bottom: 16px; right: 16px; z-index: 1080; } | |
| .ios-toast{ | |
| background: var(--popover-bg); | |
| color: #fff; | |
| border: 0; | |
| border-radius: 14px; | |
| box-shadow: var(--shadow); | |
| animation: toastSlide .3s ease both; | |
| } | |
| .ios-toast .toast-body{ padding: .6rem .8rem; } | |
| /* ---------- Drag & Drop highlight ---------- */ | |
| .drop{ | |
| outline: 2px dashed color-mix(in oklab, var(--blue), #fff 0%); | |
| outline-offset: 6px; | |
| border-radius: 12px; | |
| } | |
| /* ---------- Block “blast” effect ---------- */ | |
| .bubble-blast{ | |
| animation: popout .4s ease forwards; | |
| filter: saturate(1.1); | |
| background-image: linear-gradient(0deg, rgba(255,255,255,.08), transparent); | |
| } | |
| /* ---------- Extras: ticks, reactions, reply banner ---------- */ | |
| /* Delivered ticks */ | |
| .meta .ticks { margin-left:.35rem; display:inline-flex; gap:2px; vertical-align:baseline; } | |
| .tick-solo, .tick-double { font-size:.72rem; opacity:.8; color: currentColor; } | |
| .tick-double::after { content:"✓✓"; letter-spacing:-2px; } | |
| .tick-solo::after { content:"✓"; } | |
| /* Reactions popover */ | |
| .react-pop{ | |
| position:absolute; bottom:calc(100% + 6px); left:50%; transform:translateX(-50%); | |
| background: var(--popover-bg); color:#fff; border-radius:999px; padding:.25rem .35rem; | |
| display:flex; gap:.15rem; box-shadow: var(--shadow); z-index: 20; user-select:none; | |
| animation: popMenu .16s ease-out both; | |
| } | |
| .react-pop button{ | |
| background:transparent; border:0; font-size:1rem; line-height:1; padding:.25rem .35rem; border-radius:10px; color:#fff; | |
| } | |
| .react-pop button:focus-visible{ outline:2px solid rgba(255,255,255,.35); outline-offset:2px; } | |
| /* Reaction badges under bubble */ | |
| .react-row{ | |
| display:flex; gap:.25rem; margin-top:.25rem; flex-wrap:wrap; | |
| } | |
| .react-chip{ | |
| background: var(--chip-bg); color: var(--text); | |
| border-radius: 999px; padding:.05rem .45rem; font-size:.75rem; display:inline-flex; gap:.25rem; align-items:center; | |
| border: 1px solid var(--border); | |
| animation: reactionPop .24s ease-out both; | |
| } | |
| /* Reply banner */ | |
| .reply-banner{ | |
| border-bottom:1px solid var(--border); | |
| background: color-mix(in oklab, var(--sheet), transparent 0%); | |
| } | |
| .reply-banner .rb-body{ | |
| padding:.35rem .75rem; display:flex; align-items:center; gap:.75rem; max-width: 980px; margin: 0 auto; | |
| } | |
| .rb-line{ flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } | |
| .rb-label{ color: var(--muted); margin-right:.35rem; } | |
| .rb-snippet{ color: var(--text); opacity:.95; } | |
| .rb-close{ margin-left:auto; } | |
| /* Swipe hint (subtle blue outline pulse) */ | |
| @keyframes hintPulse{ | |
| 0%{ box-shadow: 0 0 0 0 color-mix(in oklab, var(--blue), transparent 75%); } | |
| 100%{ box-shadow: 0 0 0 10px transparent; } | |
| } | |
| .bubble-them.swipe-hint{ animation: hintPulse .9s ease-out 1; } | |
| /* Ensure bubbles anchor popovers */ | |
| .bubble { position: relative; } | |
| /* ---------- Animations ---------- */ | |
| @keyframes pop{ | |
| 0% { transform: scale(.88); opacity: 0; } | |
| 70% { transform: scale(1.04); opacity: 1; } | |
| 100% { transform: scale(1); } | |
| } | |
| @keyframes popout{ | |
| 0%{ transform: scale(1); opacity:1 } | |
| 70%{ transform: scale(1.04); opacity:.75 } | |
| 100%{ transform: scale(.82); opacity:0 } | |
| } | |
| @keyframes bounceDot{ | |
| 0%, 80%, 100% { transform: translateY(0); } | |
| 40% { transform: translateY(-4px); } | |
| } | |
| @keyframes pulse{ | |
| 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(10,132,255,.5); } | |
| 70% { transform: scale(1.05); box-shadow: 0 0 0 8px rgba(10,132,255,0); } | |
| 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(10,132,255,0); } | |
| } | |
| @keyframes popMenu{ | |
| 0% { transform: translateX(-50%) scale(.86); opacity:0; } | |
| 100%{ transform: translateX(-50%) scale(1); opacity:1; } | |
| } | |
| @keyframes reactionPop{ | |
| 0% { transform: scale(.75); opacity:0; } | |
| 70%{ transform: scale(1.12); opacity:1; } | |
| 100%{ transform: scale(1); } | |
| } | |
| @keyframes toastSlide{ | |
| 0% { transform: translateY(16px); opacity:0; } | |
| 100%{ transform: translateY(0); opacity:1; } | |
| } | |
| /* ---------- Accessibility & Polish ---------- */ | |
| /* Visible selection & caret */ | |
| ::selection{ background: color-mix(in oklab, var(--blue), #ffffff 20%); color:#fff; } | |
| /* High-contrast focus outlines on anchors/controls */ | |
| a:focus-visible, button:focus-visible, textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } | |
| /* Scrollbar (subtle, both themes) */ | |
| *{ scrollbar-width: thin; scrollbar-color: color-mix(in oklab, var(--muted), #000 0%) transparent; } | |
| ::-webkit-scrollbar{ height:10px; width:10px; } | |
| ::-webkit-scrollbar-thumb{ background: color-mix(in oklab, var(--muted), transparent 60%); border-radius: 10px; } | |
| ::-webkit-scrollbar-track{ background: transparent; } | |
| /* Reduced motion */ | |
| @media (prefers-reduced-motion: reduce){ | |
| *{ animation: none ; transition: none ; } | |
| } | |
| /* ---------- Small-screen tweaks ---------- */ | |
| @media (max-width: 460px){ | |
| .bubble{ max-width: 84%; } | |
| .chat-image, .audio-ios{ max-width: 220px; } | |
| } | |