/** * User Interface Styles * * CSS custom properties and component styles for the user-facing interface. * This file is imported after admin.css to allow user-specific overrides. */ /* ============================================================================= * Speech Bubble Component * ============================================================================= */ .speech-bubble { pointer-events: none; font-family: sans-serif; /* Padding MUST be here (not on .bubble-content) for -webkit-line-clamp to work in Chrome. Chrome breaks line-clamp when padding is on the clamped element itself. */ background-color: var(--bubble-bg, #374151); border: 2px solid var(--bubble-border, #4B5563); padding: var(--padding, 8px); border-radius: var(--border-radius, 8px); } .speech-bubble .bubble-content { /* WARNING: -webkit-line-clamp breaks if padding is on this element in Chrome. Padding must be on the parent (.speech-bubble) instead. */ display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; color: var(--bubble-text, #F9FAFB); font-size: var(--font-size, 12px); line-height: 1.5; word-wrap: break-word; overflow-wrap: break-word; } .speech-bubble .bubble-content.whisper { font-style: italic; } /* Tail pointing down (bubble is above avatar) */ .speech-bubble.tail-below::after { content: ''; position: absolute; bottom: 0; left: var(--tail-offset, 50%); transform: translateX(-50%) translateY(100%); width: 0; height: 0; border-left: var(--tail-size, 8px) solid transparent; border-right: var(--tail-size, 8px) solid transparent; border-top: var(--tail-size, 8px) solid var(--bubble-bg, #374151); } /* Tail border (for outline effect) */ .speech-bubble.tail-below::before { content: ''; position: absolute; bottom: 0; left: var(--tail-offset, 50%); transform: translateX(-50%) translateY(100%); width: 0; height: 0; border-left: calc(var(--tail-size, 8px) + 2px) solid transparent; border-right: calc(var(--tail-size, 8px) + 2px) solid transparent; border-top: calc(var(--tail-size, 8px) + 2px) solid var(--bubble-border, #4B5563); margin-left: 0; margin-bottom: -2px; } /* Tail pointing up (bubble is below avatar) */ .speech-bubble.tail-above::after { content: ''; position: absolute; top: 0; left: var(--tail-offset, 50%); transform: translateX(-50%) translateY(-100%); width: 0; height: 0; border-left: var(--tail-size, 8px) solid transparent; border-right: var(--tail-size, 8px) solid transparent; border-bottom: var(--tail-size, 8px) solid var(--bubble-bg, #374151); } /* Tail border (for outline effect) */ .speech-bubble.tail-above::before { content: ''; position: absolute; top: 0; left: var(--tail-offset, 50%); transform: translateX(-50%) translateY(-100%); width: 0; height: 0; border-left: calc(var(--tail-size, 8px) + 2px) solid transparent; border-right: calc(var(--tail-size, 8px) + 2px) solid transparent; border-bottom: calc(var(--tail-size, 8px) + 2px) solid var(--bubble-border, #4B5563); margin-top: -2px; } /* ============================================================================= * Username Label Component * ============================================================================= */ .username-label { pointer-events: none; font-family: sans-serif; font-size: var(--font-size, 12px); color: #fff; white-space: nowrap; /* Black outline via text-shadow (matches canvas 3px stroke) */ text-shadow: -1.5px -1.5px 0 #000, 1.5px -1.5px 0 #000, -1.5px 1.5px 0 #000, 1.5px 1.5px 0 #000, 0px -1.5px 0 #000, 0px 1.5px 0 #000, -1.5px 0px 0 #000, 1.5px 0px 0 #000; }