/* ==========================================
   SalmasFlix — Chat v2 (Foundation 2026)

   Floating partner bubble + iMessage/X-style chat panel. Owns:
     - `.sfx-chat-bubble` — 56px circular FAB-style entry point with
       avatar, unread badge, online dot, message blip preview
     - `.sfx-chat-panel` — expandable chat surface (380x560 desktop,
       full-screen bottom-sheet on mobile)
     - `.sfx-chat-msg` — iMessage-shape bubbles with grouping tail
       logic (4-min window, same sender), tap-to-reveal timestamps
     - day-separator chips, typing/recording indicators, composer

   Theme-token discipline (CLAUDE.md standing rule): every accent uses
   `var(--primary)` / `var(--secondary)` / `rgba(var(--primary-rgb), X)`
   so all 8 presets retint cleanly. Red `#ef4444` is allowed as
   semantic danger (recording dot, unread badge).

   The legacy `.chat-sidebar` chrome stays in `chat.css` and is
   force-hidden when the v2 bubble initialises (feature flag
   `sfx_chat_v2 = '0'` falls back to legacy). See bubble.ts.
   ========================================== */
@layer components {

/* ==========================================
   FLOATING BUBBLE
   ========================================== */

/* Wave 17 — chat bubble is the locked-pair sibling ABOVE the FAB.
   Inherits the FAB's full chrome (gradient body, spinning ring, pulsing
   glow at FULL intensity) but is sized smaller (44px desktop / 40px
   mobile = ~78% of the FAB) so the FAB still reads as the primary
   action. Position is derived from `sfx-fab-position` events (see
   bubble.ts); no independent drag, no localStorage position. */
.sfx-chat-bubble {
    position: fixed;
    /* Default position fallback before fab-position event fires —
       sits horizontally centered on FAB's bottom-right default
       (FAB is 56px@right:24, bubble is 44px → right offset = 24+6=30). */
    bottom: calc(106px + env(safe-area-inset-bottom, 0px));
    right: calc(30px + env(safe-area-inset-right, 0px));
    width: 44px;
    height: 44px;
    border-radius: 50%;
    /* Match FAB chrome — same gradient body + same gradient border. */
    border: 2px solid rgba(var(--primary-rgb), 0.6);
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    color: #fff;
    box-shadow: 0 4px 20px rgba(var(--primary-rgb), 0.4),
                0 0 15px rgba(var(--secondary-alt-rgb), 0.3);
    z-index: 999;
    cursor: pointer;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Wave 17 follow-up — also smooth `left/top/right/bottom` so the
       bubble glides with the FAB during snap-to-edge or visibility
       transitions. The `.dragging` class clears these mid-drag so the
       follow stays instant during active mouse movement. */
    transition: transform 0.3s ease, box-shadow 0.3s ease,
                background 0.3s ease, border-color 0.3s ease,
                filter 0.3s ease, opacity 0.3s ease,
                left 0.25s ease, top 0.25s ease,
                right 0.25s ease, bottom 0.25s ease;
    padding: 0;
    overflow: visible;
}

/* Wave 17 follow-up — rotating ring around the bubble retired. The
   FAB still has its spinning ring (it's the primary action); the
   chat bubble keeps only the pulsing glow halo + glass border. */

/* Pulsing glow halo — identical to FAB. */
.sfx-chat-bubble::after {
    content: '';
    position: absolute;
    inset: -10px;
    border-radius: 50%;
    background: radial-gradient(circle,
        rgba(var(--secondary-alt-rgb), 0.25) 0%,
        rgba(var(--primary-rgb), 0.1) 40%,
        transparent 70%);
    animation: fab-glow-pulse 3s ease-in-out infinite;
    pointer-events: none;
    z-index: -2;
}

.sfx-chat-bubble.hidden { display: none; }

.sfx-chat-bubble:hover {
    transform: scale(1.06);
    background: linear-gradient(135deg, var(--primary-light), var(--primary));
    box-shadow: 0 6px 28px rgba(var(--primary-rgb), 0.5),
                0 0 20px rgba(var(--secondary-alt-rgb), 0.4);
}

/* Wave 17 follow-up — partner offline. Avatar greys out + bubble
   chrome dims so the cluster reads "no one's there right now" without
   hiding the affordance. The status dot stays grey separately. */
.sfx-chat-bubble.offline {
    filter: grayscale(0.85) brightness(0.78);
    opacity: 0.78;
}
.sfx-chat-bubble.offline:hover {
    /* Restore color on hover so the user can still tell it's tappable. */
    filter: grayscale(0) brightness(1);
    opacity: 1;
}

/* Bubble tracks the FAB's drag/snap classes. `dragging` mirrors the
   FAB scale-up; `snapping` enables a coordinated transition so both
   circles ease to the snap target together. */
.sfx-chat-bubble.dragging {
    transform: scale(1.08);
    transition: none;
    cursor: grabbing;
}

.sfx-chat-bubble.snapping {
    transition: left 0.3s ease, right 0.3s ease, top 0.3s ease,
                bottom 0.3s ease, transform 0.2s ease,
                background 0.2s ease, border-color 0.2s ease,
                filter 0.3s ease;
}

/* When the FAB sits too close to the top of the viewport, the bubble
   flips below the FAB instead of above so it stays visible. */
.sfx-chat-bubble.flipped-below {
    /* No visual change beyond positioning, but reserved for future
       tweaks (e.g. pointing the panel transform-origin downward). */
}

/* Avatar inside bubble — fills almost the entire circle */
.sfx-chat-bubble-avatar {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    background: linear-gradient(135deg, var(--primary), var(--secondary));
    display: flex;
    align-items: center;
    justify-content: center;
    color: #0d0b1e;
    font-weight: 700;
    font-size: 1.3rem;
    overflow: hidden;
    pointer-events: none;
}

.sfx-chat-bubble-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Unread badge — top-right */
.sfx-chat-bubble-badge {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 10px;
    background: #ef4444;
    color: #fff;
    font-size: 0.7rem;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 6px rgba(239, 68, 68, 0.5);
    pointer-events: none;
    line-height: 1;
}

.sfx-chat-bubble-badge.hidden { display: none; }

/* Online status dot — bottom-right */
.sfx-chat-bubble-status {
    position: absolute;
    bottom: 2px;
    right: 2px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: #6b7280; /* offline grey */
    border: 2px solid var(--bg-dark);
    pointer-events: none;
    transition: background 0.2s ease;
}

.sfx-chat-bubble-status.online {
    background: #22c55e; /* online green */
    box-shadow: 0 0 8px rgba(34, 197, 94, 0.6);
}

/* Debug indicator — only shown when ?debug=1 in URL */
.sfx-chat-bubble-debug {
    position: absolute;
    top: -2px;
    left: -2px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--primary);
    pointer-events: none;
    box-shadow: 0 0 6px rgba(var(--primary-rgb), 0.8);
}

/* Message blip — slides up from bubble showing recent message preview */
.sfx-chat-blip {
    position: fixed;
    bottom: calc(108px + env(safe-area-inset-bottom, 0px));
    right: calc(24px + env(safe-area-inset-right, 0px));
    max-width: 280px;
    min-width: 180px;
    padding: 10px 14px;
    background: rgba(var(--secondary-rgb), 0.18);
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    border: 1px solid rgba(var(--secondary-rgb), 0.4);
    border-radius: 14px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
    color: #fff;
    font-size: 0.82rem;
    line-height: 1.35;
    opacity: 0;
    transform: translateY(8px) scale(0.96);
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease;
    z-index: 998;
}

.sfx-chat-blip.visible {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
    cursor: pointer;
}

.sfx-chat-blip-sender {
    display: block;
    font-size: 0.66rem;
    font-weight: 600;
    color: var(--primary);
    margin-bottom: 2px;
    letter-spacing: 0.3px;
}

.sfx-chat-blip-text {
    display: block;
    color: rgba(255, 255, 255, 0.92);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Hide bubble + blip in fullscreen sync (mirror FAB rule) */
body.media-fs-active .sfx-chat-bubble,
body.media-fs-active .sfx-chat-blip {
    display: none !important;
    visibility: hidden !important;
    opacity: 0 !important;
    pointer-events: none !important;
}

/* When v2 panel is open, bubble fades but stays mounted so it can
   animate the panel close back to its own corner */
.sfx-chat-bubble.panel-open {
    opacity: 0;
    pointer-events: none;
    transform: scale(0.85);
}

/* ==========================================
   CHAT PANEL — desktop "emerging from bubble"
   ========================================== */

.sfx-chat-panel {
    position: fixed;
    /* Wave 17 follow-up — fluid sizing across all viewport widths.
       clamp() keeps the panel snug on small laptops, comfortable on
       desktop, and naturally narrower on phones where the JS layout
       overrides take over (mobile bottom-sheet block below). */
    width: clamp(320px, 30vw, 400px);
    height: clamp(420px, 70vh, 600px);
    max-height: calc(100vh - 96px);
    bottom: calc(108px + env(safe-area-inset-bottom, 0px));
    right: calc(24px + env(safe-area-inset-right, 0px));
    background: rgba(13, 11, 30, 0.92);
    backdrop-filter: blur(28px) saturate(180%);
    -webkit-backdrop-filter: blur(28px) saturate(180%);
    border: 1px solid rgba(var(--secondary-rgb), 0.35);
    border-radius: 18px;
    box-shadow: 0 18px 48px rgba(0, 0, 0, 0.55),
                0 0 0 1px rgba(var(--primary-rgb), 0.08) inset;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* Wave 17 follow-up — panel layers ABOVE the FAB (1000) so opening
       the chat covers the FAB instead of being half-hidden by it. */
    z-index: 1500;

    /* Hidden state — collapsed at bubble corner */
    opacity: 0;
    pointer-events: none;
    transform-origin: bottom right;
    transform: scale(0.2) translate(40%, 40%);
    transition: opacity 0.32s cubic-bezier(0.2, 0.9, 0.3, 1),
                transform 0.32s cubic-bezier(0.2, 0.9, 0.3, 1);
}

.sfx-chat-panel.open {
    opacity: 1;
    pointer-events: auto;
    transform: scale(1) translate(0, 0);
}

/* Wave 17 follow-up — the panel is positioned by JS to sit ABOVE
   (or below, when FAB is in top half) the FAB cluster, not OVER it.
   The FAB stays visible and tappable while the panel is open. The
   earlier `body.sfx-chat-open .fab-container { opacity: 0 }` rule
   was reverted because the user explicitly wants the FAB to stay
   visible. */

/* Hide v2 panel in fullscreen sync */
body.media-fs-active .sfx-chat-panel {
    display: none !important;
    visibility: hidden !important;
}

/* ==========================================
   PANEL HEADER
   ========================================== */

.sfx-chat-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    flex-shrink: 0;
    position: relative;
}

/* Drag handle — mobile only, centered pill */
.sfx-chat-drag-handle {
    display: none;
    position: absolute;
    top: 6px;
    left: 50%;
    transform: translateX(-50%);
    width: 36px;
    height: 5px;
    border-radius: 2.5px;
    background: rgba(255, 255, 255, 0.25);
    pointer-events: none;
}

.sfx-chat-header-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary), var(--secondary));
    color: #0d0b1e;
    font-weight: 700;
    font-size: 0.8rem;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    flex-shrink: 0;
}

.sfx-chat-header-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.sfx-chat-header-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.sfx-chat-header-name {
    font-weight: 700;
    font-size: 0.92rem;
    color: rgba(255, 255, 255, 0.95);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.2;
    display: flex;
    align-items: center;
    gap: 6px;
}

.sfx-chat-header-status {
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.55);
    font-weight: 500;
}

.sfx-chat-header-status.online {
    color: #22c55e;
}

.sfx-chat-header-shield {
    color: #22c55e;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 2px;
    filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.4));
}

.sfx-chat-header-shield[hidden] { display: none; }

/* Wave 17 — call button in panel header. Sits between the shield (E2E
   verification) and the close X. Visually a soft glass circle with a
   themed primary→secondary fill on hover. When a call is active, body
   gets `data-call-active="1"` (set by call.ts state machine) and the
   button flips to red so the user knows tapping ends the call. */
.sfx-chat-header-call {
    width: 30px;
    height: 30px;
    min-width: 30px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(var(--primary-rgb), 0.12);
    border: 1px solid rgba(var(--primary-rgb), 0.30);
    color: var(--primary);
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    transition: background 0.18s ease, border-color 0.18s ease,
                color 0.18s ease, transform 0.15s ease, box-shadow 0.18s ease;
}

.sfx-chat-header-call:hover {
    background: linear-gradient(135deg,
        rgba(var(--primary-rgb), 0.22),
        rgba(var(--secondary-rgb), 0.18));
    border-color: rgba(var(--primary-rgb), 0.55);
    color: #fff;
    transform: scale(1.08);
    box-shadow: 0 3px 12px rgba(var(--primary-rgb), 0.35);
}

.sfx-chat-header-call:active {
    transform: scale(0.94);
}

/* Mid-call state — flip to "end call" red. Hooked from call.ts via
   document.body[data-call-active="1"] (see below for state plumbing). */
body[data-call-active="1"] .sfx-chat-header-call {
    background: linear-gradient(135deg, #ef4444, #dc2626);
    border-color: rgba(239, 68, 68, 0.6);
    color: #fff;
    animation: sfx-chat-call-pulse 1.6s ease-in-out infinite;
}

body[data-call-active="1"] .sfx-chat-header-call:hover {
    background: linear-gradient(135deg, #f87171, #dc2626);
    border-color: rgba(239, 68, 68, 0.8);
    color: #fff;
    box-shadow: 0 3px 12px rgba(239, 68, 68, 0.45);
}

@keyframes sfx-chat-call-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.5); }
    50%      { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); }
}

.sfx-chat-close {
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.7);
    width: 32px;
    height: 32px;
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s ease, color 0.2s ease;
    flex-shrink: 0;
    padding: 0;
}

.sfx-chat-close:hover {
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
}

/* ==========================================
   MESSAGE LIST
   ========================================== */

.sfx-chat-messages {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 8px 12px 4px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: rgba(var(--secondary-rgb), 0.3) transparent;
}

.sfx-chat-messages::-webkit-scrollbar {
    width: 4px;
}

.sfx-chat-messages::-webkit-scrollbar-thumb {
    background: rgba(var(--secondary-rgb), 0.3);
    border-radius: 2px;
}

/* Day separator chip — sticks to top when scrolling X-style.
   The bg has to be opaque enough that scrolling messages don't
   bleed through the chip and visually collide with adjacent
   timestamps; the legacy 0.06 alpha was too transparent. Pinned
   in a small inline-flex pill, with breathing room above so a
   per-message timestamp chip just below doesn't kiss the day
   chip when both happen to render close together. */
.sfx-chat-day {
    align-self: center;
    margin: 16px 0 10px;
    padding: 5px 14px;
    background: rgba(20, 20, 35, 0.92);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.5px;
    color: rgba(255, 255, 255, 0.7);
    text-transform: uppercase;
    position: sticky;
    top: 6px;
    z-index: 3;
    backdrop-filter: blur(12px) saturate(150%);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}

/* Message group — vertical stack of consecutive msgs from same sender */
.sfx-chat-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 6px;
}

.sfx-chat-group.mine {
    align-items: flex-end;
}

.sfx-chat-group.theirs {
    align-items: flex-start;
}

/* iMessage-style bubble */
.sfx-chat-msg {
    max-width: 78%;
    padding: 8px 12px;
    border-radius: 18px;
    font-size: 0.88rem;
    line-height: 1.38;
    word-break: break-word;
    overflow-wrap: anywhere;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
    animation: sfx-msg-pop 0.18s ease;
    position: relative;
}

@keyframes sfx-msg-pop {
    from { opacity: 0; transform: translateY(4px) scale(0.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Wave 17 follow-up — split bubble colors so receiver and sender are
   instantly distinguishable + match the therapy chat's split palette:
     - Sender (mine)   = SECONDARY gradient (purple-ish in default)
     - Receiver (theirs) = PRIMARY gradient (gold in default)
   White text on both. */
.sfx-chat-msg.mine {
    background: linear-gradient(135deg, var(--secondary), var(--secondary-dark));
    color: #fff;
    align-self: flex-end;
    box-shadow: 0 2px 8px rgba(var(--secondary-rgb), 0.3);
}

.sfx-chat-msg.theirs {
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    color: #fff;
    align-self: flex-start;
    box-shadow: 0 2px 8px rgba(var(--primary-rgb), 0.3);
}

/* Tail on FIRST message of a group — iMessage spike effect */
.sfx-chat-msg.first-of-group.mine { border-bottom-right-radius: 4px; }
.sfx-chat-msg.first-of-group.theirs { border-bottom-left-radius: 4px; }

/* Mid-group: keep tight 4px on the matching side so consecutive bubbles
   read as one stream. Apply at TOP of the matching side too for a
   "stacked" look. */
.sfx-chat-msg.in-group.mine {
    border-top-right-radius: 4px;
    border-bottom-right-radius: 4px;
}

.sfx-chat-msg.in-group.theirs {
    border-top-left-radius: 4px;
    border-bottom-left-radius: 4px;
}

/* Last message of group recovers a normal bottom corner */
.sfx-chat-msg.last-of-group.mine {
    border-bottom-right-radius: 18px;
}

.sfx-chat-msg.last-of-group.theirs {
    border-bottom-left-radius: 18px;
}

/* System / call entries — centered, neutral */
.sfx-chat-system {
    align-self: center;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 12px;
    padding: 6px 12px;
    margin: 6px 0;
    max-width: 78%;
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.6);
    text-align: center;
}

/* Sync tag pill */
/* Wave 17 follow-up — `.sfx-chat-msg-tag` (the "SYNC" pill that used
   to live inside message bubbles) was retired. Tag info now surfaces
   on the timestamp chip when the user taps a group. See the
   `.sfx-chat-ts-sync` rule below. */

/* Wave 17 follow-up — Instagram-style timestamp visibility.
   Default: hidden via `display: none` (reliable across browsers; the
   earlier height:0→auto trick was visually opaque but the height
   transition can't tween to/from auto, leaving some browsers stuck
   at 0 even with the class flipped).
   `.always-visible` — added by JS when the gap from the previous
   group > 30 min — stays revealed permanently.
   `.visible` — added on group tap for 5 seconds — pops in briefly
   so users can inspect short gaps on demand.
   The chip text is "<time>" or "<time> · sync" when the message
   was sent from the sync tab — replaces the in-bubble SYNC tag. */
.sfx-chat-ts {
    display: none;
    align-self: center;
    padding: 2px 10px;
    margin: 4px 0 8px;
    font-size: 0.62rem;
    color: rgba(255, 255, 255, 0.55);
    font-variant-numeric: tabular-nums;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.04);
    animation: sfx-chat-ts-pop 0.18s ease;
}

.sfx-chat-ts.always-visible,
.sfx-chat-ts.visible {
    display: inline-block;
}

/* Wave 17 follow-up — `.sfx-chat-ts-sync` (the SYNC suffix on the
   group chip) is retired. The chip now shows time only. The SYNC
   indicator moved to per-message tap — see `.sfx-chat-msg::before`
   below. */

@keyframes sfx-chat-ts-pop {
    from { opacity: 0; transform: translateY(-3px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Per-message side-meta — shown on tap. Position depends on which
   side the bubble sits on: mine (right-aligned) shows meta to the
   LEFT; theirs (left-aligned) shows meta to the RIGHT. Either way
   the meta sits on the side opposite the message tail, so it points
   inward toward the conversation flow. Content comes from
   `data-meta` attribute set in bubble.ts during render. */
.sfx-chat-msg::before {
    content: attr(data-meta);
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.62rem;
    color: rgba(255, 255, 255, 0.55);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.18s ease, transform 0.18s ease;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}
.sfx-chat-msg.mine::before {
    right: calc(100% + 8px);
}
.sfx-chat-msg.theirs::before {
    left: calc(100% + 8px);
}
.sfx-chat-msg.show-meta::before {
    opacity: 1;
}
/* On tap the bubble dims slightly so the meta reads as a "peek"
   action rather than a permanent annotation. */
.sfx-chat-msg.show-meta {
    filter: brightness(1.06);
}

/* Voice note bubble — keeps existing shape, restyled */
.sfx-chat-voice {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 200px;
}

.sfx-chat-voice-play {
    background: rgba(255, 255, 255, 0.18);
    border: none;
    color: inherit;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 0.85rem;
    line-height: 1;
}

.sfx-chat-voice-play:hover {
    background: rgba(255, 255, 255, 0.28);
}

.sfx-chat-voice-wave {
    flex: 1;
    height: 28px;
    display: flex;
    align-items: center;
    gap: 2px;
    min-width: 100px;
}

.sfx-chat-voice-bar {
    width: 3px;
    background: currentColor;
    border-radius: 2px;
    opacity: 0.5;
    transition: opacity 0.1s;
}

.sfx-chat-voice-bar.played { opacity: 1; }

.sfx-chat-voice-meta {
    font-size: 0.7rem;
    opacity: 0.7;
    min-width: 30px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.sfx-chat-voice-speed {
    background: rgba(255, 255, 255, 0.18);
    border: none;
    color: inherit;
    font-size: 0.62rem;
    font-weight: 700;
    width: 30px;
    text-align: center;
    padding: 2px 0;
    border-radius: 8px;
    cursor: pointer;
    line-height: 1.2;
    flex-shrink: 0;
}

.sfx-chat-voice-speed.active {
    background: rgba(0, 0, 0, 0.18);
}

/* ==========================================
   TYPING + RECORDING INDICATORS
   ========================================== */

.sfx-chat-typing {
    align-self: flex-start;
    margin: 4px 0 6px;
    background: rgba(255, 255, 255, 0.07);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 18px 18px 18px 4px;
    padding: 10px 14px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    animation: sfx-msg-pop 0.18s ease;
    transition: opacity 0.2s ease;
}

.sfx-chat-typing[hidden] { display: none; }

.sfx-chat-typing-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.55);
    animation: sfx-typing-bounce 1.2s ease-in-out infinite;
}

.sfx-chat-typing-dot:nth-child(1) { animation-delay: 0ms; }
.sfx-chat-typing-dot:nth-child(2) { animation-delay: 200ms; }
.sfx-chat-typing-dot:nth-child(3) { animation-delay: 400ms; }

@keyframes sfx-typing-bounce {
    0%, 60%, 100% { transform: scale(1); opacity: 0.4; }
    30% { transform: scale(1.4); opacity: 1; }
}

/* Recording indicator — pulsing red dot + animated waveform bars */
.sfx-chat-recording {
    align-self: flex-start;
    margin: 4px 0 6px;
    background: rgba(255, 255, 255, 0.07);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 18px 18px 18px 4px;
    padding: 8px 14px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    animation: sfx-msg-pop 0.18s ease;
}

.sfx-chat-recording[hidden] { display: none; }

.sfx-chat-recording-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    animation: sfx-rec-pulse 1.2s ease-in-out infinite;
}

@keyframes sfx-rec-pulse {
    0%, 100% { opacity: 0.6; transform: scale(1); }
    50% { opacity: 1; transform: scale(1.2); }
}

.sfx-chat-recording-wave {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    height: 18px;
}

.sfx-chat-recording-bar {
    width: 3px;
    height: 8px;
    border-radius: 1.5px;
    background: rgba(255, 255, 255, 0.7);
    animation: sfx-rec-wave 0.8s ease-in-out infinite;
}

.sfx-chat-recording-bar:nth-child(1) { animation-delay: 0ms; }
.sfx-chat-recording-bar:nth-child(2) { animation-delay: 130ms; }
.sfx-chat-recording-bar:nth-child(3) { animation-delay: 260ms; }

@keyframes sfx-rec-wave {
    0%, 100% { height: 6px; }
    50% { height: 16px; }
}

.sfx-chat-recording-label {
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.65);
    font-weight: 500;
}

/* ==========================================
   COMPOSER
   ========================================== */

.sfx-chat-composer {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    flex-shrink: 0;
    min-height: 56px;
    /* visualViewport keyboard adaptation — JS sets translateY */
    transition: transform 0.2s ease;
}

.sfx-chat-composer-avatar {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary), var(--secondary));
    color: #0d0b1e;
    font-weight: 700;
    font-size: 0.7rem;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    flex-shrink: 0;
}

.sfx-chat-composer-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.sfx-chat-composer-input {
    flex: 1;
    min-width: 0;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 16px;
    padding: 8px 14px;
    color: #fff;
    font-size: 0.9rem;
    font-family: inherit;
    outline: none;
    transition: border-color 0.2s ease;
    line-height: 1.3;
}

.sfx-chat-composer-input::placeholder {
    color: rgba(255, 255, 255, 0.4);
}

.sfx-chat-composer-input:focus {
    border-color: rgba(var(--primary-rgb), 0.5);
}

/* Wave 17 follow-up — composer action buttons themed by intent:
     - send  → primary (the gold "go" action)
     - mic   → secondary (voice note / the alternate input)
     - emoji → neutral white-tinted (just a discoverability cue)
   The base ".sfx-chat-composer-btn" rule keeps the neutral chrome;
   per-button overrides below apply the colored tint. */
.sfx-chat-composer-btn {
    width: 32px;
    height: 32px;
    min-width: 32px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.7);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    padding: 0;
    transition: background 0.2s ease, border-color 0.2s ease,
                color 0.2s ease, transform 0.2s ease;
}

.sfx-chat-composer-btn:hover {
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    transform: scale(1.05);
}

.sfx-chat-composer-btn[hidden] { display: none; }

.sfx-chat-composer-mic.recording {
    background: linear-gradient(135deg, #ef4444, #c0392b);
    color: #fff;
    border-color: transparent;
    animation: sfx-mic-pulse 1s ease infinite;
}

@keyframes sfx-mic-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); }
    50% { box-shadow: 0 0 0 8px rgba(239, 68, 68, 0); }
}

/* Send button — disabled by default, lights up when input has chars */
/* Send (idle) — primary tint, slightly faded until input has text */
.sfx-chat-composer-send {
    background: rgba(var(--primary-rgb), 0.10);
    border-color: rgba(var(--primary-rgb), 0.30);
    color: var(--primary);
    pointer-events: none;
    opacity: 0.55;
    transform: translateY(2px);
}

/* Send (active) — solid primary gradient, white SVG */
.sfx-chat-composer-send.active {
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    color: #fff;
    border-color: transparent;
    pointer-events: auto;
    opacity: 1;
    transform: translateY(0) scale(1.05);
}

/* Mic (voice note) — secondary tint by default */
.sfx-chat-composer-mic {
    background: rgba(var(--secondary-rgb), 0.10);
    border-color: rgba(var(--secondary-rgb), 0.30);
    color: var(--secondary);
}
.sfx-chat-composer-mic:hover {
    background: linear-gradient(135deg,
        rgba(var(--secondary-rgb), 0.22),
        rgba(var(--secondary-dark-rgb, var(--secondary-rgb)), 0.18));
    border-color: rgba(var(--secondary-rgb), 0.55);
    color: #fff;
}

/* Recording state replaces composer body with a status bar */
.sfx-chat-composer.recording .sfx-chat-composer-input,
.sfx-chat-composer.recording .sfx-chat-composer-emoji,
.sfx-chat-composer.recording .sfx-chat-composer-send {
    display: none;
}

.sfx-chat-composer-recbar {
    flex: 1;
    display: none;
    align-items: center;
    gap: 8px;
    padding: 0 12px;
    color: #ef4444;
    font-size: 0.85rem;
    font-weight: 600;
}

.sfx-chat-composer.recording .sfx-chat-composer-recbar {
    display: inline-flex;
}

.sfx-chat-composer-recbar-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    animation: sfx-rec-pulse 1.2s ease-in-out infinite;
}

.sfx-chat-composer-recbar-time {
    font-variant-numeric: tabular-nums;
}

.sfx-chat-composer-recbar-hint {
    opacity: 0.55;
    font-weight: 500;
    margin-left: auto;
}

/* Quick reactions row — horizontally scrollable. Wave 17 follow-up:
   - Mobile: `touch-action: pan-x` so phones swipe horizontally without
     the panel intercepting for drag-down-dismiss.
   - Laptop: thin themed scrollbar so users SEE the affordance + the
     wheel handler in bubble.ts (`_wireReactionsWheelScroll`) maps
     vertical mouse-wheel to horizontal scrollLeft. Without this,
     a laptop with no trackpad can't scroll the row.
   `overscroll-behavior: contain` prevents the swipe from chaining
   into the messages list above. */
.sfx-chat-reactions {
    display: flex;
    gap: 6px;
    padding: 6px 12px 10px;
    overflow-x: auto;
    overflow-y: hidden;
    border-top: 1px solid rgba(255, 255, 255, 0.05);
    flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    flex-shrink: 0;
    touch-action: pan-x;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: rgba(var(--secondary-rgb), 0.4) transparent;
}

.sfx-chat-reactions::-webkit-scrollbar {
    display: block;
    height: 4px;
}
.sfx-chat-reactions::-webkit-scrollbar-track { background: transparent; }
.sfx-chat-reactions::-webkit-scrollbar-thumb {
    background: rgba(var(--secondary-rgb), 0.4);
    border-radius: 2px;
}
.sfx-chat-reactions::-webkit-scrollbar-thumb:hover {
    background: rgba(var(--secondary-rgb), 0.7);
}

.sfx-chat-reactions::-webkit-scrollbar { display: none; }

.sfx-chat-reaction-btn {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.85);
    padding: 5px 10px;
    border-radius: 14px;
    font-size: 0.75rem;
    cursor: pointer;
    white-space: nowrap;
    font-family: inherit;
    flex-shrink: 0;
    min-height: 30px;
    transition: background 0.18s ease, border-color 0.18s ease,
                transform 0.15s ease;
}

.sfx-chat-reaction-btn:hover {
    background: rgba(var(--secondary-rgb), 0.12);
    border-color: rgba(var(--secondary-rgb), 0.25);
    transform: scale(1.04);
}

/* No-session placeholder */
.sfx-chat-no-session {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    padding: 20px;
    text-align: center;
    color: rgba(255, 255, 255, 0.55);
    font-size: 0.88rem;
}

.sfx-chat-no-session[hidden] { display: none; }

.sfx-chat-no-session-btn {
    background: linear-gradient(135deg, var(--primary), var(--primary-light));
    border: none;
    color: #0d0b1e;
    padding: 9px 22px;
    border-radius: 16px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    min-height: 44px;
    transition: transform 0.18s ease;
}

.sfx-chat-no-session-btn:hover { transform: scale(1.04); }

/* ==========================================
   MOBILE — full-screen bottom sheet
   ========================================== */

@media (max-width: 600px) {
    .sfx-chat-bubble {
        /* Wave 17 follow-up — phone bubble = 40px (~78% of phone FAB
           which is 52px). bottom: FAB(32) + FAB.height(52) + gap(10)
           + safe = 94. right: FAB.right(16) + (FAB.size - bubble.size)/2 = 16+6 = 22. */
        width: 40px;
        height: 40px;
        bottom: calc(94px + env(safe-area-inset-bottom, 0px));
        right: calc(22px + env(safe-area-inset-right, 0px));
    }

    .sfx-chat-bubble-avatar { font-size: 1rem; }

    /* Wave 17 follow-up — emoji button hidden on phones. Native iOS
       and Android keyboards have an emoji input; the in-app picker
       button just steals composer width. Send + mic stay visible. */
    .sfx-chat-composer-emoji { display: none !important; }

    .sfx-chat-blip {
        bottom: calc(86px + env(safe-area-inset-bottom, 0px));
        right: calc(16px + env(safe-area-inset-right, 0px));
        max-width: calc(100vw - 32px);
    }

    .sfx-chat-panel {
        width: 100vw;
        height: 100vh;
        height: 100dvh;
        max-height: 100dvh;
        bottom: 0;
        right: 0;
        left: 0;
        top: 0;
        border-radius: 0;
        border: none;
        padding-top: env(safe-area-inset-top, 0px);
        transform-origin: bottom right;
        transform: translateY(100%) scale(1);
    }

    .sfx-chat-panel.open {
        transform: translateY(0) scale(1);
    }

    .sfx-chat-drag-handle { display: block; }

    .sfx-chat-header {
        padding: 20px 16px 14px;
        gap: 12px;
    }

    /* Phone bumps — iPhone 14 Pro Max (430px) made the legacy desktop-
       sized chrome feel cramped. Bumping every interactive element
       ~15-25% so they're glance-readable + thumb-comfortable. */
    .sfx-chat-header-avatar { width: 40px; height: 40px; font-size: 1rem; }
    .sfx-chat-header-name { font-size: 1.02rem; }
    .sfx-chat-header-status { font-size: 0.78rem; }
    .sfx-chat-header-call,
    .sfx-chat-close {
        width: 38px; height: 38px; min-width: 38px;
    }

    .sfx-chat-msg {
        max-width: 82%;
        padding: 9px 13px;
        font-size: 0.95rem;
    }

    .sfx-chat-composer {
        padding: 9px 11px;
        padding-bottom: calc(9px + env(safe-area-inset-bottom, 0px));
        min-height: 60px;
        gap: 8px;
    }

    .sfx-chat-composer-avatar { width: 28px; height: 28px; }

    .sfx-chat-composer-btn {
        width: 42px;
        height: 42px;
        min-width: 42px;
    }

    .sfx-chat-composer-input {
        font-size: 1rem;
        padding: 10px 14px;
    }

    /* Suggested-reply pills — bigger tap target + readable text. */
    .sfx-chat-reactions {
        padding: 8px 12px 10px;
        gap: 8px;
    }
    .sfx-chat-reaction-btn {
        font-size: 0.85rem;
        padding: 8px 14px;
        min-height: 38px;
        border-radius: 999px;
    }
}

/* Phone landscape — keep panel slightly inset */
@media (max-height: 500px) and (orientation: landscape) {
    .sfx-chat-panel {
        max-height: 100dvh;
    }
}

/* When the panel is in a drag-down dismiss gesture, show the
   transform delta inline — JS sets --sfx-chat-drag-y */
.sfx-chat-panel.dragging {
    transform: translateY(var(--sfx-chat-drag-y, 0)) scale(1);
    transition: none;
}

/* ==========================================
   LEGACY KILL-SWITCH — when v3 is ON, hide
   the old sidebar and toggle button entirely.
   v2 selectors kept for one release cycle as
   back-compat (bubble.ts still sets both
   dataset.chatV2 and dataset.chatV3).
   ========================================== */

body[data-chat-v3="1"] #chat-toggle,
body[data-chat-v3="1"] #chat-sidebar,
body[data-chat-v2="1"] #chat-toggle,
body[data-chat-v2="1"] #chat-sidebar {
    display: none !important;
    visibility: hidden !important;
    pointer-events: none !important;
}

} /* end @layer components */
