/* ============================================================
   chat-bubble.css — Shared ChatBubble component stylesheet
   Token-driven. Do not add hardcoded brand colors here.
   Bubble background/foreground come from inline CSS variables
   set per-instance by the component.
   ============================================================ */

/* ── Root (bubble row + its sibling overflow menu) ───────────── */
/* ADO #10563 triad round 6: this wraps .ui-chat-bubble-row and the (conditional)
   .ui-chat-bubble-overflow-menu as siblings -- the menu is no longer a child of
   .ui-chat-bubble-stack (see that rule's comment below for why). A plain flex column keeps
   both in normal flow (so the overflow-y:auto chat scroller's content height still grows to
   include an open menu) while removing the menu from the stack's own width computation. */
.ui-chat-bubble-root {
    display: flex;
    flex-direction: column;
    width: 100%;
    gap: var(--meb-space-stack-xs);
}

/* ── Row (outer flex container) ─────────────────────────────── */

.ui-chat-bubble-row {
    display: flex;
    width: 100%;
    gap: var(--meb-space-inline-md);
    align-items: flex-end;
    overflow: visible;
}

.ui-chat-bubble-row--other {
    justify-content: flex-start;
}

.ui-chat-bubble-row--current {
    justify-content: flex-end;
    /* Reserve the current-user tail's outside reach inside the row so parent scroll containers do not clip it. */
    padding-right: calc(var(--chat-bubble-tail-width, 20px) - 9px);
    box-sizing: border-box;
}

/* ── Avatar slot ─────────────────────────────────────────────── */

.ui-chat-bubble-avatar-slot {
    flex: 0 0 auto;
    display: flex;
    align-items: flex-end;
    padding-bottom: var(--meb-space-stack-xs);
}

/* ── Bubble surface (shared base) ───────────────────────────── */

.ui-chat-bubble-surface {
    position: relative;
    /* ADO #10563 triad round 4 (#4): width:100% of .ui-chat-bubble-stack, NOT an independent
       fit-content/max-width pair here -- see .ui-chat-bubble-stack below for why the 72%/34rem cap
       moved there. */
    width: 100%;
    border-radius: var(--meb-border-radius-sm);
    padding: var(--meb-space-stack-sm) var(--meb-space-inline-md);
    background: var(--chat-bubble-background, var(--meb-surface-card));
    color: var(--chat-bubble-foreground, var(--meb-text-default));
    font-family: var(--meb-font-family-primary);
    font-size: var(--meb-font-size-body-desktop);
    line-height: var(--meb-font-lineheight-body);
    border: 1px solid transparent;
    word-break: break-word;
    overflow: visible;
}

/* ── Expandable bubble button reset ──────────────────────────── */

.ui-chat-bubble-surface--expandable {
    appearance: none;
    border: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
    /* Re-declare tokens overridden by button reset */
    background: var(--chat-bubble-background, var(--meb-surface-card));
    color: var(--chat-bubble-foreground, var(--meb-text-default));
    padding: var(--meb-space-stack-sm) var(--meb-space-inline-md);
    border-radius: var(--meb-border-radius-sm);
    /* ADO #10563 triad round 4 (#4): matches .ui-chat-bubble-surface's width:100% above -- the
       72%/34rem cap lives on .ui-chat-bubble-stack now. */
    width: 100%;
    overflow: visible;
}

.ui-chat-bubble-surface--expandable:focus-visible {
    outline: var(--meb-focus-ring-width) solid var(--meb-accent-primary);
    outline-offset: var(--meb-focus-ring-offset);
}

/* ── Message text ────────────────────────────────────────────── */

/* Keep content above the tail pseudo-element */
.ui-chat-bubble-message,
.ui-chat-bubble-meta {
    position: relative;
    z-index: 1;
}

.ui-chat-bubble-message {
    display: -webkit-box;
    line-clamp: var(--chat-bubble-preview-lines, 3);
    -webkit-line-clamp: var(--chat-bubble-preview-lines, 3);
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    text-align: left;
    max-height: calc(var(--chat-bubble-preview-lines, 3) * 1lh);
}

/* Full surface (non-expandable) — remove clamp so full message shows */
.ui-chat-bubble-surface:not(.ui-chat-bubble-surface--expandable) .ui-chat-bubble-message {
    display: block;
    line-clamp: unset;
    -webkit-line-clamp: unset;
    max-height: none;
    overflow: visible;
}

/* ── Meta row (time + view more) ─────────────────────────────── */

.ui-chat-bubble-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--meb-space-inline-sm);
    width: 100%;
    min-width: 0;
    margin-top: var(--meb-space-stack-xs);
}

.ui-chat-bubble-time {
    flex: 0 0 auto;
    font-size: var(--meb-font-size-body-sm-desktop);
    line-height: var(--meb-font-lineheight-tight);
    opacity: 0.78;
}

.ui-chat-bubble-more {
    margin-left: auto;
    flex: 0 0 auto;
    font-size: var(--meb-font-size-body-sm-desktop);
    line-height: var(--meb-font-lineheight-tight);
    font-weight: var(--meb-font-weight-semibold);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ── Tail pseudo-element ─────────────────────────────────────── */

/* Shared base for both tails */
.ui-chat-bubble-surface--other::before,
.ui-chat-bubble-surface--current::after {
    content: "";
    position: absolute;
    /* Align the rendered tail with the bubble's painted bottom edge.
       The bubble has a transparent border, so lifting the tail by the tokenized border width
       prevents the anti-aliased triangle from reading slightly below the bubble. */
    bottom: var(--meb-border-width-sm);
    width: var(--chat-bubble-tail-width, 20px);
    height: var(--chat-bubble-tail-height, 18px);
    background: var(--chat-bubble-background, var(--meb-surface-card));
    pointer-events: none;
    z-index: 0;
}

/* Other-user tail: points left */
.ui-chat-bubble-surface--other::before {
    left: calc(-1 * var(--chat-bubble-tail-width, 20px) + 9px);
    clip-path: polygon(100% 42%, 0 100%, 100% 100%);
}

/* Current-user tail: points right */
.ui-chat-bubble-surface--current::after {
    right: calc(-1 * var(--chat-bubble-tail-width, 20px) + 9px);
    clip-path: polygon(0 42%, 100% 100%, 0 100%);
}

/* ── Trailing overflow-menu slot (ADO #10563) ────────────────── */
/* Mirrors .ui-chat-bubble-avatar-slot's box model so the trailing slot occupies the same
   vertical rhythm as the leading avatar slot it is the counterpart of. */

.ui-chat-bubble-trailing-slot {
    flex: 0 0 auto;
    display: flex;
    align-items: flex-end;
    padding-bottom: var(--meb-space-stack-xs);
}

.ui-chat-bubble-overflow {
    position: relative;
}

/* ADO #10563 triad round 3 (#6) introduced this stack so the (then-nested) overflow menu could
   render IN NORMAL FLOW directly below the bubble, not absolutely positioned over the
   overflow-y:auto chat scroller. Triad round 6 moved the menu OUT of this stack entirely (see
   .ui-chat-bubble-root and .ui-chat-bubble-overflow-menu below) because nesting it here let the
   menu's own min-width inflate this stack's shrink-to-fit width every time it opened -- this
   stack now holds ONLY the bubble body, exactly as it did before the menu ever existed.
   flex-start: the trigger only ever renders for the OTHER-user (left-aligned) bubble
   (ShouldRenderOverflowTrigger => !IsCurrentUser), so this stack never needs to mirror the
   current-user's right alignment. */
/* ADO #10563 triad round 4 (#4): the 72%/34rem cap moved here from .ui-chat-bubble-surface. That
   surface is `width: fit-content` and a flex CHILD of this stack; the stack itself carried no
   width, so the surface's percentage max-width resolved against a containing block whose own width
   was determined BY the surface -- a circular fit-content/percentage case CSS leaves
   implementation-defined, and WKWebView/Chromium resolve it differently. This stack is instead a
   flex item of the definite-width (100%) `.ui-chat-bubble-row`, so `min(72%, 34rem)` here resolves
   against a real number on every engine. The surface fills `width: 100%` of whatever this stack
   settles on (its own auto/shrink-to-fit width, bounded by this max-width) -- same visual result,
   non-circular math. */
.ui-chat-bubble-stack {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--meb-space-stack-xs);
    max-width: min(72%, 34rem);
    min-width: 0;
}

/* Always-visible, low-emphasis trigger -- not hover-only (design #10533 decision 8): a
   compliance control that only appears on hover is undiscoverable on touch and to
   low-vision users. Gains emphasis on hover/focus instead. */
.ui-chat-bubble-overflow-trigger {
    appearance: none;
    border: none;
    background: transparent;
    color: var(--meb-text-muted, var(--meb-text-default));
    opacity: 0.62;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--meb-border-radius-sm);
    cursor: pointer;
}

.ui-chat-bubble-overflow-trigger:hover,
.ui-chat-bubble-overflow-trigger:focus-visible {
    opacity: 1;
    background: var(--meb-surface-input-filled);
}

.ui-chat-bubble-overflow-trigger:focus-visible {
    outline: var(--meb-focus-ring-width) solid var(--meb-accent-primary);
    outline-offset: var(--meb-focus-ring-offset);
}

/* ADO #10563 round 2 (#5) anchored this `right: 0` under the trigger to stop it opening off the
   right edge of the scroller/viewport. Triad round 3 (#6) went further: the SAME overflow-y:auto
   chat scroller that motivated that fix also clips the menu VERTICALLY for the newest (bottom-
   most) bubble -- exactly the message a user is most likely to act on -- because `top: 100%`
   opened it downward past the scroller's visible bottom with no way to see or reach it. The fix
   was to stop taking it out of flow at all: this rule is not position:absolute. Triad round 6:
   the menu is now a normal flow SIBLING of .ui-chat-bubble-row (inside .ui-chat-bubble-root, see
   above), rendered after the row closes -- no longer a child of .ui-chat-bubble-stack -- which
   both keeps it after the trigger in DOM order (Tab reaches it) and out of the stack's own width
   computation (the min-width below no longer inflates the stack when the menu opens).
   Triad round 15: align-self: flex-end was WRONG despite the comment above claiming it "aligns it
   to the row's trailing edge (where the trigger lives)" -- the trigger does NOT live at the row's
   trailing edge. .ui-chat-bubble-root is width:100% of the chat scroller, but the row inside it is
   justify-content:flex-start with no flex-grow on any child, so for any message shorter than the
   full row width the row's actual content (avatar + stack + trigger) ends well short of the
   root's right edge -- flex-end anchored the menu to that far edge instead, opening it nowhere
   near a short bubble's trigger. The trigger only ever renders for OTHER-user rows
   (ShouldRenderOverflowTrigger => !IsCurrentUser), which ALSO always render the leading avatar
   slot (ShouldRenderOtherAvatar => !IsCurrentUser, same guard) -- so the trigger's row always
   starts with exactly one avatar slot before the bubble. align-self: flex-start plus a
   margin-left equal to that avatar slot's own width lands the menu at the bubble's own left edge
   -- directly under the bubble/trigger's neighbourhood -- regardless of the stack's shrink-to-fit
   width, which this in-flow sibling has no access to. --chat-bubble-avatar-slot-width is that
   width: it mirrors avatar.css's `.ui-avatar-wrapper.size-md` (48px -- Avatar Size="md" is the
   only size ChatBubble ever renders in this slot), referenced via var()+fallback the same way
   --chat-bubble-tail-width is above, rather than a bare number at the use site. max-width is
   reduced by the same amount so the menu can never be pushed past the root's own right edge by
   the added margin.
   Triad round 16: --chat-bubble-avatar-slot-width was referenced via var(..., 48px) but never
   DEFINED anywhere -- the 48px fallback was silently the only value that ever applied, and it
   omitted .ui-chat-bubble-row's own `gap: var(--meb-space-inline-md)` between the avatar slot and
   the stack. The avatar slot's right edge sits at 48px from the root's left edge, but the STACK
   (the bubble itself) starts a further gap past that -- so a bare 48px margin-left landed the menu
   one row-gap short of the bubble's actual left edge, not "at it" as this comment already claimed.
   Defining the variable HERE, scoped to this rule, folds the row's own gap into the offset so the
   menu's left edge finally matches the bubble's; the 48px-only fallback stays as the defensive
   last-resort if this custom property is ever read before this rule's cascade applies. */
.ui-chat-bubble-overflow-menu {
    --chat-bubble-avatar-slot-width: calc(48px + var(--meb-space-inline-md));
    align-self: flex-start;
    margin-left: var(--chat-bubble-avatar-slot-width, 48px);
    width: fit-content;
    max-width: calc(100% - var(--chat-bubble-avatar-slot-width, 48px));
    min-width: 10rem;
    padding: var(--meb-space-stack-xs);
    background: var(--meb-surface-card);
    border: var(--meb-border-width-sm) solid var(--meb-border-default);
    border-radius: var(--meb-border-radius-sm);
    box-shadow: var(--meb-shadow-dropdown, var(--meb-shadow-sm));
    display: flex;
    flex-direction: column;
    gap: var(--meb-space-stack-xs);
}

.ui-chat-bubble-overflow-item {
    appearance: none;
    border: none;
    background: transparent;
    text-align: left;
    width: 100%;
    min-height: 2.75rem;
    padding: var(--meb-space-stack-xs) var(--meb-space-inline-sm);
    border-radius: var(--meb-border-radius-sm);
    font-family: var(--meb-font-family-primary);
    font-size: var(--meb-font-size-body-sm-desktop);
    color: var(--meb-text-default);
    cursor: pointer;
}

.ui-chat-bubble-overflow-item:hover,
.ui-chat-bubble-overflow-item:focus-visible {
    background: var(--meb-surface-input-filled);
}

.ui-chat-bubble-overflow-item:disabled {
    opacity: 0.6;
    cursor: default;
}

/* ── State badge slot (ADO #10563 scaffold; #10567 populates it) ─ */

.ui-chat-bubble-state-badge-slot {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--meb-space-inline-xs);
}

/* ── Mobile ──────────────────────────────────────────────────── */

/* ADO #10563 triad round 8 (#5): keyed off the MOBILE RENDER STRUCTURE's own root class
   (.mobile-root -- the class MobileBingoGameplay.razor's <main> element carries;
   DesktopBingoGameplay.razor's root carries no such class) instead of a viewport media query.
   Pre-fix this lived under a 640px-wide viewport media query, while ScreenSizeService.MobileBreakpoint
   (CT-01) picks the MOBILE render structure at any width BELOW 768px -- so a 641-767px viewport
   rendered MobileBingoGameplay (the mobile render structure) while this override's OWN narrower
   query had already stopped matching, silently leaving the DESKTOP-shaped 72% cap on
   .ui-chat-bubble-stack (see its rule above) in effect for that band, inside a page that is
   otherwise entirely in its mobile layout. Selecting on the render structure's own root class
   keeps this in sync with CT-01 by construction -- there is no second number to drift. */
.mobile-root .ui-chat-bubble-stack {
    max-width: 86%;
}
