/* Reply + reactions — macOS Ventura message features */

.composer-reply-bar {
    align-items: center;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--composer-shell-bg, var(--nexa-aside-fill, #161920));
    border: 1px solid var(--nexa-aside-stroke, var(--border));
    border-radius: 14px;
    display: flex;
    gap: 10px;
    margin-bottom: 10px;
    padding: 8px 10px 8px 12px;
}

.composer-reply-bar.hidden {
    display: none;
}

.composer-reply-accent {
    background: var(--selection-pill-fill, color-mix(in srgb, var(--dock-accent, #afb9cd) 55%, transparent));
    border: 0;
    border-radius: 4px;
    flex-shrink: 0;
    align-self: stretch;
    width: 3px;
}

.composer-reply-body {
    flex: 1;
    min-width: 0;
}

/* Clicking the banner (not its ✕) jumps to the quoted message. */
.composer-reply-body {
    border-radius: 8px;
    cursor: pointer;
}

.composer-reply-body:focus-visible {
    outline: 2px solid color-mix(in srgb, currentColor 45%, transparent);
    outline-offset: 2px;
}

.composer-reply-label {
    color: var(--dock-accent, var(--accent));
    font-size: 11px;
    font-weight: 600;
    margin: 0 0 2px;
}

.composer-reply-preview {
    color: var(--text-secondary);
    font-size: 12px;
    line-height: 1.35;
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.composer-reply-close {
    align-items: center;
    background: transparent;
    border: 0;
    border-radius: 0;
    color: var(--theme-text-muted, #a1a1aa);
    cursor: pointer;
    display: inline-flex;
    flex-shrink: 0;
    font-size: 0;
    height: 24px;
    justify-content: center;
    line-height: 0;
    padding: 0;
    width: 24px;
}

.composer-reply-close:hover {
    background: transparent;
    color: var(--theme-text, #f4f4f5);
}

.composer-reply-close .ui-icon {
    height: 14px;
    width: 14px;
}

.message-bubble-inner {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.message-reply-preview {
    border: none;
    border-left: 3px solid var(--accent);
    border-radius: 8px;
    cursor: pointer;
    display: block;
    font: inherit;
    margin: 0;
    max-width: 100%;
    min-width: 100%;
    padding: 4px 8px 4px 6px;
    text-align: left;
    transition: background 120ms ease;
    width: 0;
}

.message-bubble--own .message-reply-preview {
    background: color-mix(in srgb, var(--theme-text, #fff) 10%, transparent);
    border-left-color: color-mix(in srgb, var(--theme-tint, #fff) 55%, transparent);
}

.message-bubble--other .message-reply-preview {
    background: color-mix(in srgb, var(--theme-text, #fff) 8%, transparent);
    border-left-color: color-mix(in srgb, var(--theme-tint, #fff) 45%, transparent);
}

.message-reply-preview:hover {
    filter: brightness(1.06);
}

.message-reply-preview.is-unavailable {
    border-left-color: var(--text-secondary);
    cursor: default;
    opacity: 0.75;
}

.message-reply-author {
    color: var(--accent);
    display: block;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.2;
}

.message-bubble--own .message-reply-author {
    color: color-mix(in srgb, var(--bubble-own-text) 85%, var(--theme-text, #fff));
}

.message-bubble--other .message-reply-author {
    color: color-mix(in srgb, var(--bubble-other-text) 85%, var(--theme-text, #fff));
}

.message-reply-text {
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    color: var(--text-secondary);
    display: -webkit-box;
    font-size: 12px;
    line-height: 1.35;
    max-width: 100%;
    overflow: hidden;
    overflow-wrap: anywhere;
    text-overflow: ellipsis;
    word-break: break-word;
}

.message-bubble--own .message-reply-text {
    color: color-mix(in srgb, var(--bubble-own-text) 72%, transparent);
}

.message-bubble--other .message-reply-text {
    color: color-mix(in srgb, var(--bubble-other-text) 72%, transparent);
}

.message-body-row {
    display: block;
    max-width: 100%;
    min-width: 0;
}

.message-body-row::after {
    clear: both;
    content: "";
    display: table;
}

.message-text {
    overflow-wrap: anywhere;
    white-space: pre-wrap;
    word-break: break-word;
}

/* ── Swipe to reply (js/messageSwipeReply.js) ─────────────────────────────────
   Drag a bubble left; a reply arrow eases in from behind its right edge. */
:root {
    --swipe-reply-return: 350ms;
    --swipe-reply-ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Horizontal drags reach the gesture; vertical ones still scroll the thread. */
.message-row .message-bubble {
    touch-action: pan-y;
}

/* The arrow sits beneath the bubble and is uncovered as the bubble slides away. */
.message-shell > .message-bubble {
    z-index: 1;
}

.message-row.is-swiping .message-bubble {
    cursor: grabbing;
}

.message-row .message-bubble.is-swipe-returning {
    transition:
        border-radius var(--quickbar-duration, 280ms) var(--quickbar-ease, ease),
        padding-bottom var(--quickbar-duration, 280ms) var(--quickbar-ease, ease),
        transform var(--swipe-reply-return) var(--swipe-reply-ease);
}

/* No text selection while a swipe is in progress. */
html.is-swiping-message,
html.is-swiping-message * {
    user-select: none !important;
    -webkit-user-select: none !important;
}

.message-swipe-reply {
    align-items: center;
    background: var(--bubble-fill-other, var(--theme-section, #16181e));
    border: 1px solid var(--bubble-surface-border, color-mix(in srgb, var(--theme-tint, #ffffff) 6%, transparent));
    border-radius: 999px;
    color: var(--text-secondary);
    display: inline-flex;
    height: 28px;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    position: absolute;
    /* Fits the short pull (max 56px): fully uncovered by the time it arms. */
    right: 4px;
    top: 50%;
    transform: translateY(-50%) scale(0.6) rotate(-45deg);
    transition:
        background-color 160ms ease,
        color 160ms ease;
    width: 28px;
    z-index: 0;
}

.message-swipe-reply .ui-icon {
    height: 14px;
    width: 14px;
}

/* Past the threshold: letting go will reply. */
.message-swipe-reply.is-armed {
    background: var(--text);
    color: var(--bg, var(--theme-bg, #0a0a0a));
}

.message-swipe-reply.is-swipe-returning {
    transition:
        opacity var(--swipe-reply-return) var(--swipe-reply-ease),
        transform var(--swipe-reply-return) var(--swipe-reply-ease);
}

@media (prefers-reduced-motion: reduce) {
    .message-row .message-bubble.is-swipe-returning,
    .message-swipe-reply.is-swipe-returning {
        transition: none;
    }
}

/* ── Jump-to-message highlight (reply banner / quoted preview) ───────────────
   The bubble just turns a touch lighter, then eases back — no glow. Drawn on an
   overlay so the bubble's own fill is never swapped out mid-fade. */
.message-bubble.message-highlight-pulse::after {
    animation: highlightPulse 1.8s ease-in-out forwards;
    border-radius: inherit;
    content: "";
    inset: 0;
    pointer-events: none;
    position: absolute;
}

@keyframes highlightPulse {
    0%,
    40% {
        background-color: color-mix(in srgb, var(--theme-text, #ffffff) 7%, transparent);
    }

    100% {
        background-color: transparent;
    }
}

/* Jump from Saved Messages: a faint accent wash that eases out — no border,
   nothing that lingers (js/ui.js removes the class after 2.4s) */
.message-bubble.message-jump-pulse::after {
    animation: jumpPulse 2.4s ease-out forwards;
    border-radius: inherit;
    content: "";
    inset: 0;
    pointer-events: none;
    position: absolute;
}

@keyframes jumpPulse {
    0%,
    25% {
        background-color: color-mix(in srgb, var(--accent-primary, #ccff00) 10%, transparent);
    }

    100% {
        background-color: transparent;
    }
}

@media (prefers-reduced-motion: reduce) {
    .message-bubble.message-highlight-pulse::after,
    .message-bubble.message-jump-pulse::after {
        animation-duration: 0.6s;
    }
}

/* ── External link warning (inline, in the bubble; js/messageLinkBar.js) ──────
   One row: [Hold to open] … [Pause ⇄]. "Pause" morphs into a full-row option
   bar (src/chat/quickbar/LinkWarningRow.tsx). */
.message-quickbar__body.message-linkbar {
    display: block;
}

.message-linkbar__slot {
    position: relative;
    z-index: 1;
}

/* Closed row and open bar share one cell; the row's width is sprung by JS
   (compact closed → as wide as the options need), and the bubble follows it. */
.lw-row {
    display: grid;
    max-width: 100%;
    overflow: hidden;
    position: relative;
}

.lw-row__layer {
    align-items: center;
    display: flex;
    grid-area: 1 / 1;
    min-width: 0;
    position: relative;
    z-index: 1;
}

/* Out-of-flow copy of the open bar, only measured. */
.lw-row__sizer {
    align-items: center;
    display: flex;
    left: 0;
    pointer-events: none;
    position: absolute;
    top: 0;
    visibility: hidden;
    width: max-content;
}

/* Same box as the open bar, so the measured width matches it exactly. */
.lw-row__sizer,
.lw-row__open {
    box-sizing: border-box;
    gap: 2px;
    padding: 2px;
}

/* Options bar: out of flow, pinned right (width = measured options width, set
   inline). Only the closed view sizes the row. */
.lw-row__open {
    align-items: center;
    bottom: 0;
    display: flex;
    position: absolute;
    right: 0;
    top: 0;
    z-index: 1;
}

.lw-row__closed {
    gap: 6px;
    justify-content: space-between;
}

/* The closed view fills the (animated) row width once it's set. */
.lw-row__closed {
    width: 100%;
}

.lw-row__hold {
    display: inline-flex;
}

/* The one backdrop: pinned right, its width sprung by JS from the trigger's to
   the whole row's. Real width (not a scale morph) keeps the pill ends round. */
.lw-select__bg {
    background: color-mix(in srgb, currentColor 9%, transparent);
    border-radius: 999px;
    bottom: 0;
    pointer-events: none;
    position: absolute;
    right: 0;
    top: 0;
    transition: background-color 160ms ease;
    z-index: 0;
}

.lw-row:not([data-open]):has(.lw-select__trigger:hover) .lw-select__bg {
    background: color-mix(in srgb, currentColor 14%, transparent);
}

.lw-select__trigger {
    align-items: center;
    background: transparent;
    border: 0;
    border-radius: 999px;
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    flex: none;
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    gap: 2px;
    height: 28px;
    padding: 0 8px 0 11px;
}

.lw-select__trigger-label,
.lw-select__trigger-icon {
    align-items: center;
    display: inline-flex;
}

.lw-select__trigger-icon {
    opacity: 0.6;
    transform: rotate(-90deg);
}

.lw-select__chips {
    align-items: center;
    display: flex;
    flex: 1 1 auto;
    gap: 1px;
    justify-content: space-between;
    min-width: 0;
}

.lw-select__chip {
    align-items: center;
    background: transparent;
    border: 0;
    color: color-mix(in srgb, currentColor 62%, transparent);
    cursor: pointer;
    display: inline-flex;
    font: inherit;
    font-size: 12px;
    font-weight: 500;
    height: 24px;
    justify-content: center;
    padding: 0 8px;
    position: relative;
    transition: color 300ms ease;
    white-space: nowrap;
}

.lw-select__chip[data-active],
.lw-select__chip:hover {
    color: inherit;
}

.lw-select__chip-bg {
    background: color-mix(in srgb, currentColor 16%, transparent);
    inset: 0;
    position: absolute;
}

.lw-select__chip-label {
    position: relative;
    z-index: 1;
}

/* Pre-promoted, so the first open doesn't pay for layer creation mid-animation. */
.lw-row__open .lw-select__chip,
.lw-row__open .lw-select__icon-btn,
.lw-row__hold,
.lw-select__trigger {
    will-change: transform, opacity;
}

/* ✕ (back out) and ✓ (apply) bracket the options. */
.lw-select__icon-btn {
    align-items: center;
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex;
    flex: none;
    height: 24px;
    justify-content: center;
    padding: 0;
    width: 28px;
}

.lw-select__cancel {
    background: transparent;
    color: color-mix(in srgb, currentColor 62%, transparent);
    transition:
        background-color 160ms ease,
        color 160ms ease;
}

.lw-select__cancel:hover {
    background: color-mix(in srgb, currentColor 12%, transparent);
    color: inherit;
}

.lw-select__apply {
    background: var(--text, var(--theme-text, #f4f4f5));
    color: var(--bg, var(--theme-bg, #0a0a0a));
}

.lw-select__chip:focus-visible,
.lw-select__icon-btn:focus-visible,
.lw-select__trigger:focus-visible {
    outline: 2px solid color-mix(in srgb, currentColor 45%, transparent);
    outline-offset: -2px;
}

/* Hover feedback (the link bar has no shared hover pill). */
.message-linkbar__hold[data-state="idle"]:hover {
    background: color-mix(in srgb, currentColor 10%, transparent);
}

/* HoldToConfirmButton (src/components/ui/hold-to-confirm.tsx) as "Hold to open":
   a progress ring fills around the icon while held. */
.hold-confirm {
    touch-action: none;
    -webkit-touch-callout: none;
    user-select: none;
}

.message-quickbar__action.message-linkbar__hold {
    gap: 5px;
    padding-inline: 4px 10px;
    /* Press scale comes from the component (motion); a CSS transform transition
       would re-ease every frame it writes and make the press lag. */
    transition:
        background-color 120ms var(--ease-ui, ease),
        color 200ms ease;
}

.hold-confirm__ring {
    align-items: center;
    display: inline-flex;
    flex: none;
    justify-content: center;
    position: relative;
}

.hold-confirm__glyph {
    align-items: center;
    display: inline-flex;
    justify-content: center;
}

.hold-confirm__check {
    inset: 0;
    position: absolute;
}

.hold-confirm__progress {
    inset: 0;
    position: absolute;
    transform: rotate(-90deg);
}

.hold-confirm__label {
    display: inline-flex;
    overflow: hidden;
    position: relative;
    transition: opacity 200ms ease;
}

.hold-confirm__label[data-holding] {
    opacity: 0.6;
}

.hold-confirm__label-text {
    display: inline-block;
    white-space: nowrap;
}

.hold-confirm__sr {
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

/* Hold complete on touch: letting go opens the link. */
.hold-confirm[data-state="armed"] {
    background: color-mix(in srgb, currentColor 16%, transparent);
}

.hold-confirm[data-state="confirmed"] {
    color: var(--green, #86efac);
}

/* Phones show action buttons icon-only at 30px; "Hold to open" keeps its label. */
@media (max-width: 600px) {
    .message-quickbar__action.message-linkbar__hold {
        padding-inline: 4px 10px;
        width: auto;
    }
}

.message-react-fab {
    align-items: center;
    background: var(--theme-section, #1c1c1c);
    border: 1px solid var(--theme-border, #323232);
    border-radius: 999px;
    bottom: -6px;
    color: var(--text);
    cursor: pointer;
    display: inline-flex;
    font-size: 15px;
    height: 28px;
    justify-content: center;
    line-height: 1;
    opacity: 0;
    padding: 0;
    pointer-events: none;
    position: absolute;
    transition:
        opacity var(--duration-fast) ease,
        visibility var(--duration-fast) ease,
        background 120ms ease,
        border-color 120ms ease;
    visibility: hidden;
    width: 28px;
    z-index: 6;
}

.message-row--other .message-react-fab {
    right: -6px;
}

.message-row--own .message-react-fab {
    left: -6px;
}

.message-bubble:hover ~ .message-react-fab:not(.is-active) {
    opacity: 1;
    pointer-events: auto;
    transition-delay: 0.8s, 0.8s, 0s, 0s;
    visibility: visible;
}

.message-react-fab:hover:not(.is-active),
.message-react-fab:focus-visible:not(.is-active) {
    opacity: 1;
    pointer-events: auto;
    transition-delay: 0s;
    visibility: visible;
}

.message-react-fab:hover,
.message-react-fab:focus-visible {
    background: var(--theme-section, #262626);
    border-color: var(--theme-border, #4a4a4a);
    outline: none;
}

.message-row.has-quick-reaction .message-react-fab,
.message-row:has(.message-reaction-chip.is-mine) .message-react-fab,
.message-react-fab.is-active {
    opacity: 0;
    pointer-events: none;
    transition-delay: 0s;
    visibility: hidden;
}

.message-row.is-actions-pending .message-bubble:hover ~ .message-react-fab:not(.is-active) {
    opacity: 0.35;
}

.message-react-fab[aria-disabled="true"] {
    cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
    .message-bubble:hover ~ .message-react-fab:not(.is-active) {
        transition-delay: 0s;
    }
}

#uiDraftStatus.danger,
.composer-status.danger,
#uiCharCounter.danger,
.composer-char-counter.danger {
    color: var(--text-danger) !important;
}

.message-action-btn--delete {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    box-shadow: var(--shadow-bubble);
    color: var(--text-secondary);
    cursor: pointer;
    flex-shrink: 0;
    font-size: 13px;
    height: 28px;
    line-height: 1;
    min-width: 28px;
    padding: 0 7px;
    pointer-events: auto;
    position: relative;
    transition: background 120ms, color 120ms, border-color 120ms;
    z-index: 7;
}

.message-reactions {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: -8px;
    max-width: calc(100% - 12px);
    padding: 0 4px;
    position: relative;
    width: auto;
    z-index: 2;
}

.message-row:has(.message-reactions) {
    padding-bottom: 6px;
}

.message-reaction-chip {
    align-items: center;
    background: var(--theme-section, #1c1c1c);
    border: 1px solid var(--theme-border, #323232);
    border-radius: 999px;
    color: var(--text);
    cursor: pointer;
    display: inline-flex;
    font-size: 13px;
    gap: 4px;
    line-height: 1;
    min-height: 22px;
    padding: 3px 7px;
    transition: background 120ms, border-color 120ms;
}

.message-reaction-chip:has(.message-reaction-count) {
    padding: 3px 8px 3px 6px;
}

.message-reaction-chip:hover {
    background: var(--theme-section, #2a2a2a);
    border-color: var(--theme-border, #555);
}

.message-reaction-chip.is-mine {
    background: var(--theme-section, #262626);
    border-color: var(--theme-border, #5a5a5a);
}

.message-reaction-count {
    color: var(--text-secondary);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.reaction-picker {
    align-items: center;
    display: flex;
    flex-wrap: nowrap;
    gap: 2px;
    justify-content: flex-start;
    padding: 0;
}

.reaction-picker.is-expanded {
    flex-wrap: wrap;
    max-width: 280px;
}

.message-actions-card__preview {
    background: color-mix(in srgb, var(--theme-text, #ffffff) 7%, transparent);
    border: 1px solid color-mix(in srgb, var(--theme-tint, #ffffff) 8%, transparent);
    border-radius: 16px;
    margin: 0 0 10px;
    max-width: 100%;
    min-width: 0;
    padding: 12px 14px;
}

.message-actions-card__preview-author {
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.message-actions-card__preview-text {
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    color: var(--text-secondary);
    display: -webkit-box;
    font-size: 13px;
    line-height: 1.4;
    margin: 6px 0 0;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    overflow-wrap: anywhere;
    white-space: pre-wrap;
    word-break: break-word;
}

.reaction-picker--menu {
    gap: 4px;
    justify-content: space-between;
    margin: 0 0 10px;
    max-width: 100%;
    min-width: 0;
    overflow-x: auto;
    padding: 2px 2px 10px;
    scrollbar-width: none;
}

.reaction-picker--menu::-webkit-scrollbar {
    display: none;
}

.reaction-picker--menu .reaction-picker-btn,
.reaction-picker--menu .reaction-picker-more {
    background: color-mix(in srgb, var(--theme-text, #ffffff) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--theme-tint, #ffffff) 8%, transparent);
    border-radius: 999px;
    flex: 0 0 34px;
    font-size: 18px;
    height: 34px;
    width: 34px;
}

.reaction-picker--menu .reaction-picker-btn.is-active {
    background: color-mix(in srgb, var(--theme-text, #ffffff) 18%, transparent);
    border-color: color-mix(in srgb, var(--theme-tint, #ffffff) 14%, transparent);
}

.reaction-picker--menu .reaction-picker-btn:hover,
.reaction-picker--menu .reaction-picker-more:hover {
    background: color-mix(in srgb, var(--theme-text, #ffffff) 14%, transparent);
    border-color: color-mix(in srgb, var(--theme-tint, #ffffff) 12%, transparent);
    transform: none;
}

.message-actions-card__group {
    background: color-mix(in srgb, var(--theme-text, #ffffff) 6%, transparent);
    border: 1px solid color-mix(in srgb, var(--theme-tint, #ffffff) 8%, transparent);
    border-radius: 14px;
    margin: 0;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    padding: 4px;
}

.message-actions-card__group + .message-actions-card__group {
    margin-top: 8px;
}

.overlay-surface--message-actions .overlay-menu-item {
    border-radius: 10px;
    min-height: 44px;
}

.overlay-surface--message-actions .overlay-menu-item:hover,
.overlay-surface--message-actions .overlay-menu-item:focus-visible {
    background: color-mix(in srgb, var(--theme-text, #ffffff) 8%, transparent);
}

.overlay-surface--message-actions .overlay-menu-item.is-danger:hover {
    background: var(--danger-10);
}

.reaction-picker-btn,
.reaction-picker-more {
    align-items: center;
    background: transparent;
    border: none;
    border-radius: 10px;
    color: var(--text);
    cursor: pointer;
    display: inline-flex;
    flex-shrink: 0;
    font-size: 18px;
    height: 34px;
    justify-content: center;
    line-height: 1;
    padding: 0;
    transition: background 120ms, transform 100ms;
    width: 34px;
}

.reaction-picker-more {
    color: var(--text-secondary);
    font-size: 20px;
    font-weight: 500;
}

.reaction-picker-btn:hover,
.reaction-picker-more:hover {
    background: color-mix(in srgb, var(--theme-text, #fff) 8%, transparent);
    transform: scale(1.08);
}

.reaction-picker-btn.is-active {
    background: color-mix(in srgb, var(--theme-text, #fff) 12%, transparent);
}

.reaction-picker-btn:focus-visible,
.reaction-picker-more:focus-visible {
    background: color-mix(in srgb, var(--theme-text, #fff) 10%, transparent);
    outline: none;
}

.message-row--own .message-content-wrap .message-reactions {
    justify-content: flex-end;
}

.message-row--other .message-content-wrap .message-reactions {
    justify-content: flex-start;
}

.message-row.is-actions-pending .message-reaction-chip {
    opacity: 0.55;
}

.message-action-btn--delete[aria-disabled="true"] {
    cursor: not-allowed;
    opacity: 0.45;
}

.message-action-btn--delete:hover {
    background: var(--red-10);
    border-color: var(--red-20);
    color: var(--text-danger);
}

.message-action-btn--delete:disabled {
    cursor: not-allowed;
    opacity: 0.35;
    pointer-events: none;
}

/* ── Message bubbles: solid, quiet fills ──────────────────────────────────────
   Fully opaque, so the thread never shows through. Each fill is the bubble tone
   laid over the active theme's stage colour (the ratio the old translucent
   bubbles showed at), so they stay low-key and follow the chosen wallpaper.
   Declared on #page-chat so --chat-stage-fill resolves per theme; :root keeps
   defaults for bubbles rendered outside it (e.g. the overlay spotlight). */
:root {
    --bubble-fill-own: #24252c;
    --bubble-fill-other: #16181e;
    --bubble-surface-border: rgba(255, 255, 255, 0.06);
    --bubble-surface-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.08),
        0 8px 32px 0 rgba(0, 0, 0, 0.2);
}

#page-chat {
    --bubble-fill-own: color-mix(in srgb, rgb(63, 63, 70) 42%, var(--chat-stage-fill, #10131a));
    --bubble-fill-other: color-mix(in srgb, rgb(30, 30, 35) 45%, var(--chat-stage-fill, #10131a));
}

.message-row .message-bubble--own,
.message-row .message-bubble--other {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border: 1px solid var(--bubble-surface-border);
    box-shadow: var(--bubble-surface-shadow);
}

.message-row .message-bubble--own {
    background: var(--bubble-fill-own);
}

.message-row .message-bubble--other {
    background: var(--bubble-fill-other);
}

/* ── Inline message quick actions (right-click / double-click) ───────────────
   The panel lives inside .message-bubble, so bubble + actions read as one
   continuous surface and scroll together with the thread. */
:root {
    --quickbar-duration: 280ms;
    --quickbar-ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Registered so the reactions edge fades can transition as they toggle. */
@property --qb-fade-l {
    syntax: '<length>';
    inherits: false;
    initial-value: 0px;
}

@property --qb-fade-r {
    syntax: '<length>';
    inherits: false;
    initial-value: 0px;
}

.message-row .message-bubble {
    transition:
        border-radius var(--quickbar-duration) var(--quickbar-ease),
        padding-bottom var(--quickbar-duration) var(--quickbar-ease);
}

/* Width is pinned to px by JS for the duration of the resize (max-content can't animate). */
.message-row .message-bubble.is-quickbar-resizing {
    transition:
        border-radius var(--quickbar-duration) var(--quickbar-ease),
        padding-bottom var(--quickbar-duration) var(--quickbar-ease),
        width var(--quickbar-duration) var(--quickbar-ease);
}

/* Breathing room below an open message; the next one eases down in step with the panel. */
.message-row {
    transition: margin-bottom var(--quickbar-duration) var(--quickbar-ease);
}

.message-row.has-quickbar {
    margin-bottom: 14px;
}

/* The hover heart would sit on top of the open panel; hidden until it has fully collapsed. */
.message-row.quick-bar-open .message-react-fab {
    display: none;
}

/* The time floats right, so in a widened bubble it would drift away from short
   text. Keep text + time at their natural width, on the bubble's own side. */
.message-bubble.is-quickbar-layout .message-body-row {
    width: fit-content;
}

.message-bubble--own.is-quickbar-layout .message-body-row {
    margin-left: auto;
}

/* Open: drop the cluster tail so the grown bubble has an even, rounded base. */
.message-row .message-bubble.has-quickbar {
    border-radius: var(--radius-bubble);
    padding-bottom: 6px;
}

.message-quickbar {
    display: grid;
    grid-template-rows: 0fr;
    margin-inline: -6px;
    transition: grid-template-rows var(--quickbar-duration) var(--quickbar-ease);
    user-select: none;
    -webkit-user-select: none;
}

.message-quickbar.is-open {
    grid-template-rows: 1fr;
}

.message-quickbar__clip {
    min-height: 0;
    min-width: 0;
    overflow: hidden;
}

.message-quickbar__body {
    align-items: center;
    /* Soft divider between the message and its actions. */
    border-top: 1px solid color-mix(in srgb, var(--theme-tint, #ffffff) 8%, transparent);
    display: flex;
    gap: 2px;
    margin-top: 6px;
    opacity: 0;
    /* Small inner inset so the buttons don't sit on the bubble's edge; the open
       width is measured from this, so the bubble widens to fit it. */
    padding: 4px 4px 2px;
    transform: translateY(-6px) scale(0.97);
    transform-origin: top center;
    transition:
        opacity var(--quickbar-duration) var(--quickbar-ease),
        transform var(--quickbar-duration) var(--quickbar-ease);
}

.message-quickbar.is-open .message-quickbar__body {
    opacity: 1;
    transform: none;
}

/* Closing: contents fade out softly (200ms, ease-out) while the panel folds
   and the bubble narrows on a slightly slower clock (340ms, set on the row by
   js/messageQuickBar.js); hard-clipped meanwhile, so nothing paints past it */
.message-quickbar.is-closing {
    clip-path: inset(0);
    overflow: hidden;
}

.message-quickbar.is-closing .message-quickbar__body {
    opacity: 0;
    transition:
        opacity 200ms cubic-bezier(0.33, 0, 0.2, 1),
        transform var(--quickbar-duration) var(--quickbar-ease);
}

.message-quickbar__actions {
    display: flex;
    flex: none;
    gap: 2px;
}

/* ── Actions menu (src/chat/quickbar/QuickBarMenu.tsx) ───────────────────────
   Save and 🙂 open like the link row's Pause picker (.lw-select above): the
   trigger's backdrop grows by real left + width over the row (solid: the
   bubble's own fill + a wash of its text colour, so nothing shows through),
   the rest of the row eases back, the options slide in from the right. */
.message-bubble--own {
    --qb-surface: var(--bubble-fill-own);
}

.message-bubble--other {
    --qb-surface: var(--bubble-fill-other);
}

.message-quickbar__menu-host {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    position: relative;
    z-index: 1;
}

.qb-select {
    align-items: center;
    display: flex;
    flex: 1 1 auto;
    /* Nothing in the row may push past the bubble's edge */
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    position: relative;
}

.qb-select__row {
    align-items: center;
    gap: 2px;
    position: relative;
    z-index: 1;
}

.qb-select__rest {
    align-items: center;
    display: flex;
    gap: 2px;
}

/* One backdrop per trigger: rests under its pill, grows over the whole row */
.qb-select__bg {
    background: color-mix(in srgb, currentColor 9%, var(--qb-surface, var(--bubble-fill-other, #16181e)));
    border-radius: 999px;
    bottom: 0;
    pointer-events: none;
    position: absolute;
    top: 0;
    transition: background-color 160ms ease;
}

/* Hover tints only the hovered trigger's own backdrop */
.qb-select:not([data-open]):has(.qb-select__trigger[data-selector="save"]:hover:not(:disabled)) .qb-select__bg[data-selector="save"],
.qb-select:not([data-open]):has(.qb-select__trigger[data-selector="react"]:hover) .qb-select__bg[data-selector="react"] {
    background: color-mix(in srgb, currentColor 14%, var(--qb-surface, var(--bubble-fill-other, #16181e)));
}

.qb-select__trigger {
    align-items: center;
    background: transparent;
    border: 0;
    border-radius: 999px;
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    flex: none;
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    gap: 6px;
    /* Same height as Reply / Copy / Delete, so the row stays one line */
    height: 28px;
    justify-content: center;
    line-height: 1;
    padding: 0 12px;
    position: relative;
}

/* Delete: an action-looking trigger in the danger colour (no pill at rest) */
.qb-select__trigger--danger {
    color: var(--text-danger);
    padding: 0 9px 0 7px;
}

.qb-select__trigger--danger svg {
    flex: none;
}

/* Copy's icon slot: fixed size, the copy / ✓ glyphs crossfade inside it */
.qb-select__swap-icon {
    display: inline-flex;
    flex: none;
    height: 15px;
    position: relative;
    width: 15px;
}

.qb-select__swap-glyph {
    display: flex;
    inset: 0;
    position: absolute;
}

/* Delete bar: ✕ · prompt · Confirm */
.qb-select__prompt {
    flex: 1 1 auto;
    font-size: 12.5px;
    font-weight: 500;
    min-width: 0;
    overflow: hidden;
    padding: 0 4px;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.qb-select__confirm {
    align-items: center;
    background: var(--color-danger, #f62834);
    border: 0;
    border-radius: 999px;
    color: #ffffff;
    cursor: pointer;
    display: inline-flex;
    flex: none;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    gap: 5px;
    height: 24px;
    padding: 0 11px 0 9px;
    transition: background-color 160ms ease;
}

.qb-select__confirm:hover {
    background: var(--danger-hover, var(--color-danger, #f62834));
}

.qb-select__confirm:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--color-danger, #f62834) 55%, transparent);
    outline-offset: 2px;
}

/* 🙂 alone: a round button */
.qb-select__trigger:not(:has(.message-quickbar__label)) {
    padding: 0;
    width: 28px;
}

.qb-select__trigger:disabled {
    cursor: default;
    opacity: 0.4 !important;
}

.qb-select__trigger .ui-icon {
    display: block;
    flex: none;
    height: 15px;
    width: 15px;
}

/* Divider before 🙂: clear of both pills */
.qb-select__row .message-quickbar__divider {
    background: var(--border-subtle, color-mix(in srgb, currentColor 14%, transparent));
    margin: 6px 4px;
}

.qb-select__emoji {
    font-size: 15px;
    line-height: 1;
}

/* The open bar (one per trigger): over the grown backdrop, across the row */
.qb-select__bar {
    align-items: center;
    display: flex;
    gap: 2px;
    inset: 0;
    padding: 0 2px;
    position: absolute;
    z-index: 3;
}

.qb-select__bar[aria-hidden] {
    pointer-events: none;
}

.qb-select__chips {
    align-items: center;
    display: flex;
    flex: 1 1 auto;
    gap: 1px;
    min-width: 0;
}

/* Save: two equal capsules up to the edge */
.qb-select__chips--halves {
    gap: 4px;
}

.qb-select__chips--halves .qb-select__chip {
    flex: 1 1 0;
    min-width: 0;
}

.qb-select__strip {
    align-items: center;
    display: flex;
    flex: 1 1 auto;
    gap: 1px;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--qb-fade-l, 0px), #000 calc(100% - var(--qb-fade-r, 0px)), transparent);
    mask-image: linear-gradient(to right, transparent, #000 var(--qb-fade-l, 0px), #000 calc(100% - var(--qb-fade-r, 0px)), transparent);
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
}

.qb-select__strip::-webkit-scrollbar {
    display: none;
}

.qb-select__chip {
    align-items: center;
    background: transparent;
    border: 0;
    border-radius: 999px;
    color: color-mix(in srgb, currentColor 62%, transparent);
    cursor: pointer;
    display: inline-flex;
    flex: none;
    font: inherit;
    font-size: 12px;
    font-weight: 500;
    height: 24px;
    justify-content: center;
    padding: 0 8px;
    position: relative;
    transition: color 300ms ease;
    white-space: nowrap;
}

.qb-select__chip[aria-pressed="true"],
.qb-select__chip:hover:not(:disabled) {
    color: inherit;
}

.qb-select__chip:disabled {
    cursor: default;
    opacity: 0.45;
}

.qb-select__chip--emoji {
    color: inherit;
    font-size: 16px;
    line-height: 1;
    padding: 0;
    width: 28px;
}

.qb-select__chip-bg {
    background: color-mix(in srgb, currentColor 16%, transparent);
    inset: 0;
    position: absolute;
}

.qb-select__chip-label {
    align-items: center;
    display: inline-flex;
    gap: 5px;
    position: relative;
    z-index: 1;
}

.qb-select__chip .ui-icon {
    flex: none;
    height: 14px;
    width: 14px;
}

.qb-select__more .ui-icon {
    opacity: 0.7;
}

/* Pre-promoted, so the first open doesn't pay for layer creation mid-animation */
.qb-select__bar .qb-select__chip,
.qb-select__bar .qb-select__icon-btn,
.qb-select__bar .qb-select__prompt,
.qb-select__bar .qb-select__confirm,
.qb-select__rest,
.qb-select__trigger {
    will-change: transform, opacity;
}

/* ✕ backs out without applying */
.qb-select__icon-btn {
    align-items: center;
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex;
    flex: none;
    height: 24px;
    justify-content: center;
    padding: 0;
    width: 28px;
}

.qb-select__cancel {
    background: transparent;
    color: color-mix(in srgb, currentColor 62%, transparent);
    transition:
        background-color 160ms ease,
        color 160ms ease;
}

.qb-select__cancel:hover {
    background: color-mix(in srgb, currentColor 12%, transparent);
    color: inherit;
}

.qb-select__trigger:focus-visible,
.qb-select__chip:focus-visible,
.qb-select__icon-btn:focus-visible {
    outline: 2px solid color-mix(in srgb, currentColor 55%, transparent);
    outline-offset: -2px;
}

/* The bar's shared hover pill stays out of the way while a selector is open */
.message-quickbar__body:has(.qb-select[data-open]) > .message-quickbar__hover {
    opacity: 0 !important;
}

.message-quickbar__action,
.message-quickbar__reaction {
    align-items: center;
    background: transparent;
    border: 0;
    border-radius: 999px;
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    flex: none;
    height: 28px;
    justify-content: center;
    padding: 0;
    position: relative;
    /* Springy hover lift, shared by every button in the bar (was Copy-only). */
    transition:
        background-color 120ms var(--ease-ui, ease),
        transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.message-quickbar__action:hover:not(:disabled),
.message-quickbar__reaction:hover {
    transform: scale(1.05);
}

.message-quickbar__action:active:not(:disabled),
.message-quickbar__reaction:active {
    transform: scale(0.95);
    transition-duration: 120ms;
}

.message-quickbar__action {
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    gap: 4px;
    padding-inline: 7px 9px;
    white-space: nowrap;
}

.message-quickbar__reaction {
    width: 30px;
}

/* React island (Copy / Delete) renders straight into the actions row. */
.message-quickbar__buttons-host {
    display: contents;
}

/* AutoWidth's measured content; exiting labels pop out absolutely (popLayout),
   so they need positioned parents and don't count toward the width. */
.message-quickbar__autowidth {
    align-items: center;
    display: inline-flex;
    flex: none;
    position: relative;
    width: max-content;
}

.message-quickbar__swap,
.message-quickbar__delete {
    align-items: center;
    display: inline-flex;
    gap: 4px;
    position: relative;
}

.message-quickbar__delete {
    gap: 0;
}

/* Opens 0 → 30px around the ✕; overflow stays visible so its circle is never cut. */
.message-quickbar__cancel-slot {
    display: inline-flex;
    flex: none;
    overflow: visible;
}

/* Gap lives on the ✕ (not slot padding) so the slot can close to exactly 0. */
.message-quickbar__cancel-slot > .message-quickbar__icon {
    margin-left: 2px;
}

.message-quickbar__icon {
    align-items: center;
    display: flex;
}

.message-quickbar__action--icon {
    padding-inline: 0;
    width: 28px;
}

/* Delete's confirm step: filled, like the component's destructive button.
   White label and check on the red in every theme — not the theme text colour,
   which is near-black on the light themes. The icons are stroked lucide
   glyphs, so colour (currentColor stroke) is what turns them white; no fill. */
.message-quickbar__action.is-danger.is-confirming {
    background: var(--color-danger, #F62834) !important;
    color: #ffffff !important;
}

.message-quickbar__action.is-danger.is-confirming :is(.message-quickbar__label, .message-quickbar__icon, .ui-icon) {
    color: #ffffff !important;
}

.message-quickbar__action .ui-icon,
.message-quickbar__more .ui-icon {
    flex: none;
    height: 15px;
    width: 15px;
}

/* Phones: icons only, so the reactions strip keeps usable room. */
@media (max-width: 600px) {
    .message-quickbar__action {
        padding-inline: 0;
        width: 30px;
    }

    .message-quickbar__label {
        display: none;
    }
}

/* Shared hover highlight (positioned + sprung by JS), styled like the sidebar
   folder tree's pill. Buttons stay transparent and sit above it. */
.message-quickbar__body {
    position: relative;
}

.message-quickbar__hover {
    background: color-mix(
        in srgb,
        var(--color-accent, color-mix(in srgb, var(--theme-text, #fff) 8%, transparent)) 55%,
        transparent
    );
    border: 1px solid color-mix(
        in srgb,
        var(--color-accent, color-mix(in srgb, var(--theme-tint, #fff) 8%, transparent)) 45%,
        transparent
    );
    border-radius: 999px;
    box-sizing: border-box;
    left: 0;
    opacity: 0;
    pointer-events: none;
    position: absolute;
    top: 0;
    transition:
        background-color 160ms ease,
        border-color 160ms ease;
    z-index: 0;
}

.message-quickbar__hover.is-danger {
    background: color-mix(in srgb, var(--color-danger) 16%, transparent);
    border-color: color-mix(in srgb, var(--color-danger) 24%, transparent);
}

.message-quickbar__actions,
.message-quickbar__divider,
.message-quickbar__reactions {
    position: relative;
    z-index: 1;
}

.message-quickbar__action:focus-visible,
.message-quickbar__reaction:focus-visible {
    outline: 2px solid color-mix(in srgb, currentColor 55%, transparent);
    outline-offset: -2px;
}

.message-quickbar__action:disabled {
    cursor: default;
    opacity: 0.4;
}

.message-quickbar__action.is-danger {
    color: var(--text-danger);
}

.message-quickbar__divider {
    align-self: stretch;
    background: color-mix(in srgb, var(--theme-text, #ffffff) 8%, transparent);
    flex: none;
    margin: 6px 3px;
    width: 1px;
}

.message-quickbar__reactions {
    display: flex;
    flex: 1 1 auto;
    gap: 1px;
    /* Soft edge fades; each side only appears when there's more to scroll to. */
    -webkit-mask-image: linear-gradient(
        to right,
        transparent,
        #000 var(--qb-fade-l),
        #000 calc(100% - var(--qb-fade-r)),
        transparent
    );
    mask-image: linear-gradient(
        to right,
        transparent,
        #000 var(--qb-fade-l),
        #000 calc(100% - var(--qb-fade-r)),
        transparent
    );
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-behavior: smooth;
    scrollbar-width: none;
    transition:
        --qb-fade-l 180ms ease,
        --qb-fade-r 180ms ease;
    -webkit-overflow-scrolling: touch;
}

.message-quickbar__reactions::-webkit-scrollbar {
    display: none;
}

.message-quickbar__reaction {
    font-size: 17px;
    line-height: 1;
}

.message-quickbar__reaction.is-active {
    background: color-mix(in srgb, currentColor 16%, transparent);
}

.message-quickbar__more {
    opacity: 0.7;
}

@media (prefers-reduced-motion: reduce) {
    .message-row,
    .message-row .message-bubble,
    .message-row .message-bubble.is-quickbar-resizing,
    .message-quickbar,
    .message-quickbar__body {
        transition: none;
    }

    .message-quickbar__reactions {
        scroll-behavior: auto;
    }

    .message-quickbar__action:hover:not(:disabled),
    .message-quickbar__action:active:not(:disabled),
    .message-quickbar__reaction:hover,
    .message-quickbar__reaction:active {
        transform: none;
    }
}
