/* Milo — the floating AI assistant widget. Lives on every admin page (mounted in
   _DashboardLayout). The inner chat (.agents-bubble, .agents-message, etc.) is
   styled by agents.css; this file is the widget chrome on top of it. */

/* Type the theme colours so they degrade safely. A club with no brand
   colour makes _Layout emit an empty `--cui-nav-link-color`; the var()
   fallback does NOT apply to a set-but-empty property, so without these
   @property registrations `--spot-color` resolves to the empty token and
   every gradient/shadow that consumes it (bubble, panel header, borders)
   becomes invalid — producing white-on-white. With a typed `<color>`
   syntax + initial-value, an empty/invalid computed value falls back to
   the registered default, so the whole widget always has a usable colour. */
@property --spot-color {
    syntax: '<color>';
    inherits: true;
    initial-value: #5B7CFA;
}
@property --spot-color-soft {
    syntax: '<color>';
    inherits: true;
    initial-value: #eef1fe;
}
@property --spot-color-deep {
    syntax: '<color>';
    inherits: true;
    initial-value: #3550c7;
}

.spot {
    --spot-color: var(--cui-nav-link-color, #5B7CFA);
    --spot-color-soft: color-mix(in srgb, var(--spot-color, #5B7CFA) 14%, #ffffff);
    --spot-color-deep: color-mix(in srgb, var(--spot-color, #5B7CFA) 72%, #0f172a);
    --spot-bg: #ffffff;
    /* #43942 — semantic danger, taken from site.css's status tokens so the
       unread badge matches every other "needs you" colour in the admin. */
    --spot-danger: var(--status-danger-fg, #dc2626);
    --spot-border: rgba(15, 23, 42, 0.08);
    --spot-shadow: 0 24px 60px -12px rgba(15, 23, 42, 0.28), 0 10px 22px -10px rgba(15, 23, 42, 0.18);
    --spot-radius: 18px;
    /* The panel is positioned FROM this anchor, so its height has to subtract these or
       it overflows the top of the screen. Kept as variables so the two can't drift
       apart again — see the height calc on .spot__panel. */
    --spot-inset-bottom: 24px;
    --spot-panel-lift: 72px; /* panel's bottom offset from the anchor (clears the bubble) */
    --spot-top-gap: 16px;    /* breathing room so the header never touches the viewport edge */
    position: fixed;
    bottom: var(--spot-inset-bottom);
    right: 24px;
    z-index: 1050;
    font-family: 'Mulish', system-ui, -apple-system, sans-serif;
}

/* ============ BUBBLE ============ */
.spot__bubble {
    width: 58px;
    height: 58px;
    border-radius: 50%;
    border: none;
    /* Solid fallback first: when a club has no colour set, the body emits
       an empty `--cui-nav-link-color`, which makes `--spot-color` /
       `--spot-color-deep` resolve to the empty token (the var() fallback
       does NOT apply to a set-but-empty property). That invalidates the
       gradient and the bubble loses all background. background-color is a
       separate declaration that survives an invalid background-image, so
       the launcher always has a visible fill. */
    background-color: #5B7CFA;
    background-image: linear-gradient(135deg, var(--spot-color, #5B7CFA) 0%, var(--spot-color-deep, #3550c7) 100%);
    color: #fff;
    box-shadow: 0 10px 26px -4px color-mix(in srgb, var(--spot-color) 45%, transparent),
                0 4px 12px -2px rgba(15, 23, 42, 0.18);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
    padding: 0;
}
.spot__bubble:hover {
    transform: scale(1.08) rotate(-3deg);
    box-shadow: 0 14px 32px -4px color-mix(in srgb, var(--spot-color) 55%, transparent),
                0 6px 16px -2px rgba(15, 23, 42, 0.2);
}
.spot__bubble:active { transform: scale(0.95); }
.spot__bubble:focus-visible {
    outline: 3px solid color-mix(in srgb, var(--spot-color) 50%, transparent);
    outline-offset: 3px;
}
.spot__bubble-icon {
    width: 28px;
    height: 28px;
    transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Milo's bubble has a choreographed idle: he looks top-left for ~2s, holds
   still for ~5s, winks, then waits ~8s before repeating. One 15s loop, split
   across two animations that share the period so they stay in step:
   the pupil (inner circle) does the look; the whole icon does the wink. */
@keyframes spot-look {
    0%      { transform: translate(0, 0); }              /* centre */
    2.7%    { transform: translate(-3px, -3px); }        /* move up-left (≈0.4s) */
    16%     { transform: translate(-3px, -3px); }        /* HOLD top-left ≈ 2s */
    19%     { transform: translate(0, 0); }              /* ease back to centre */
    100%    { transform: translate(0, 0); }              /* still for the rest */
}
@keyframes spot-wink {
    0%, 46.67% { transform: scaleY(1); }                /* ≈ 7s in: 2s look + 5s wait */
    47.6%      { transform: scaleY(0.1); }
    48.6%      { transform: scaleY(1); }
    49.6%      { transform: scaleY(0.1); }
    50.6%      { transform: scaleY(1); }
    100%       { transform: scaleY(1); }                /* ≈ 8s wait, then loop */
}
.spot__bubble:not(:hover) .spot__bubble-icon > circle:last-child {
    transform-origin: center;
    animation: spot-look 15s ease-in-out infinite;
}
.spot__bubble:not(:hover) .spot__bubble-icon {
    transform-origin: center;
    animation: spot-wink 15s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .spot__bubble:not(:hover) .spot__bubble-icon,
    .spot__bubble:not(:hover) .spot__bubble-icon > circle:last-child,
    .spot__avatar-mark,
    .spot__avatar::before,
    .spot__avatar::after {
        animation: none;
    }
}

/* Pulse halo when there's a contextual nudge */
.spot__bubble-pulse {
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    pointer-events: none;
    border: 2px solid var(--spot-color);
    opacity: 0;
}
.spot--nudging .spot__bubble-pulse {
    animation: spot-pulse 2.2s ease-out infinite;
}
@keyframes spot-pulse {
    0%   { transform: scale(0.88); opacity: 0.7; }
    100% { transform: scale(1.55); opacity: 0; }
}
/* #43942 — the app-style unread badge: a HUMAN from ClubRight Support has
   replied and it hasn't been read. Deliberately the loudest thing on the
   launcher (red pill with a count) so it can't be mistaken for Milo's own
   green "replied" dot, which is a small quiet dot on the same corner. */
.spot__bubble-badge {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--radius-pill, 999px);
    background: var(--spot-danger, #dc2626);
    color: #fff;
    text-align: center;
    font-size: 11px;
    font-weight: 700;
    line-height: 20px;
    box-shadow: 0 0 0 2px #fff,
                0 2px 6px color-mix(in srgb, var(--spot-danger, #dc2626) 45%, transparent);
    animation: spotBadgePop 3.2s ease-in-out infinite;
}

/* The badge owns the top-right corner while it's up, so Milo's own status
   adornments move to the opposite corner rather than sitting under it — the
   two can never be confused for one another. */
.spot--unread .spot__bubble-status { right: auto; left: -6px; }
.spot--unread .spot__bubble-status--draft { right: auto; left: 2px; }

@keyframes spotBadgePop {
    0%, 72%, 100% { transform: scale(1); }
    80% { transform: scale(1.18); }
    88% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .spot__bubble-badge { animation: none; }
}

/* Shared pulse for small status dots (nudge, budget). */
@keyframes spot-pulse-dot {
    0%, 100% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.5); opacity: 0.55; }
}

/* ============ OFF-PLAN NUDGE TOAST (Grow) ============ */
/* Sits where the pill would; the operator chooses to action it —
   Milo never opens itself. */
.spot__nudge {
    display: inline-flex;
    align-items: stretch;
    max-width: 320px;
    background: var(--spot-bg);
    border-radius: 16px;
    box-shadow: var(--spot-shadow);
    overflow: hidden;
    animation: spot-rise 0.22s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
}
.spot__nudge-body {
    border: none;
    background: transparent;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 10px 12px 14px;
    cursor: pointer;
    text-align: left;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
    color: #0f172a;
}
.spot__nudge-dot {
    width: 8px;
    height: 8px;
    margin-top: 4px;
    border-radius: 50%;
    background: var(--spot-color);
    animation: spot-pulse-dot 1.4s ease-in-out infinite;
    flex-shrink: 0;
}
.spot__nudge-text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.spot__nudge-dismiss {
    border: none;
    border-left: 1px solid rgba(15, 23, 42, 0.08);
    background: transparent;
    padding: 0 12px;
    cursor: pointer;
    color: #64748b;
    font-size: 12px;
    flex-shrink: 0;
}
.spot__nudge-dismiss:hover { color: #0f172a; }

/* ============ PANEL ============ */
.spot__panel {
    position: absolute;
    bottom: var(--spot-panel-lift);
    right: 0;
    /* Wider + taller default so tables, multi-row member lists and tool
       payloads don't force the operator to scroll inside a tiny window.
       The expand button (.spot--expanded) still gives near-full-screen
       when an answer is unusually long. */
    width: 720px;
    max-width: calc(100vw - 32px);
    /* The panel's bottom edge sits at (--spot-inset-bottom + --spot-panel-lift) = 96px
       above the viewport floor, so its height must subtract that. It used to be
       calc(100vh - 60px), which ignored the offset entirely and pushed the top of the
       panel 36px ABOVE the viewport on every screen — the header (new chat / history /
       expand / close) was permanently unreachable, and the taller the chat, the worse
       it got. Mobile was never affected: it re-anchors with position: fixed + inset. */
    /* #44084 — the panel opens at the height of what it has to say (greeting + chips +
       composer) and grows with the conversation up to the old ceiling, then scrolls.
       A fixed-height empty canvas is the ChatGPT pattern; a panel that starts small
       reads as a colleague leaning in. The old value is now the max. */
    height: auto;
    min-height: 220px;
    max-height: min(820px, calc(100vh - var(--spot-inset-bottom) - var(--spot-panel-lift) - var(--spot-top-gap)));
    background: var(--spot-bg);
    border-radius: var(--spot-radius);
    box-shadow: var(--spot-shadow);
    border: 1px solid var(--spot-border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transform-origin: bottom right;
    animation: spot-rise 0.24s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
}
/* The support panel is tucked behind Milo, so when the human chat is slid out Milo
   needs enough height to hide it again. */
.spot__panel:has(~ .spot__support.open) { min-height: 560px; }

/* ── Get-support panel — tucked BEHIND Milo with just a tab poking out on the left
   (#42788). Click the tab and it slides fully out to the left of Milo, which stays
   put on the right. Only exists while the Milo panel is open (.spot--open), so
   closing Milo takes it with it. */
.spot__support {
    position: absolute;
    /* Shorter than Milo — inset top and bottom so it reads as tucked behind. */
    bottom: calc(var(--spot-panel-lift) + 26px);
    right: 0;
    width: 440px;
    max-width: calc(100vw - 32px);
    /* Follows Milo's rendered height (assistant-widget.js keeps --spot-panel-height
       current) so a short Milo panel doesn't leave the support panel poking out above it. */
    height: min(768px, calc(var(--spot-panel-height, 820px) - 52px), calc(100vh - var(--spot-inset-bottom) - var(--spot-panel-lift) - var(--spot-top-gap) - 52px));
    background: var(--spot-bg);
    border-radius: var(--spot-radius);
    box-shadow: var(--spot-shadow);
    border: 1px solid var(--spot-border);
    display: none;                 /* shown only when Milo is open (rule below) */
    flex-direction: column;
    overflow: hidden;
    padding-left: 40px;            /* leaves room for the narrow teal tab spine */
    padding-right: 34px;           /* keep content clear of the edge tucked behind Milo */
    z-index: -1;                   /* ALWAYS behind Milo, so it slides out FROM BEHIND */
    pointer-events: none;          /* body isn't interactive while peeking — the tab is */
    /* Peek: only the ~30px teal tab pokes out past Milo's left edge (no white
       gap beyond it — that read as a stray sliver). */
    transform: translateX(-313px);
    transition: transform 0.34s cubic-bezier(0.33, 1, 0.68, 1);
}
.spot--open .spot__support { display: flex; }
.spot__support.open {
    /* Slide out but keep ~30px of the right edge tucked behind Milo. Stays z-index:-1
       so it emerges from behind rather than popping on top. */
    transform: translateX(-690px);
    pointer-events: auto;
}

/* The teal tab spine — the entry point AND the identity (no separate header).
   Stays visible whether tucked away or expanded. Horizontal, wrapping label. */
.spot__support-tab {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    /* Narrow full-height spine — subtle, so Milo stays the hero, but always
       reachable. Vertical text (below) means the narrow width never squashes
       the label. #42790 */
    width: 30px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 12px 0;
    border: none;
    background: linear-gradient(180deg, #f06522 0%, #e8651a 100%);
    color: #fff;
    cursor: pointer;
    border-radius: var(--spot-radius) 0 0 var(--spot-radius);
    box-shadow: -4px 0 14px rgba(0, 0, 0, 0.14);
    pointer-events: auto;
    z-index: 2;
    transition: filter 0.15s;
}
.spot__support-tab:hover { filter: brightness(1.08); }
.spot__support-tab .fa { font-size: 12px; }
.spot__support-tab .fa { font-size: 16px; }
/* "Looking for human support?" — a quiet teal pointer in Milo's corner at the
   left edge, aimed at the support spine tucked behind. Clickable: opens support. */
.spot__human-hint {
    display: flex;
    align-items: center;
    gap: 6px;
    width: auto;
    justify-content: flex-start;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    color: #e8651a;
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: color 0.15s;
}
.spot__human-hint:hover { text-decoration: underline; color: #f06522; }
.spot__human-hint .fa { font-size: 11px; }
/* #44000 — one row under the composer: human support on the left, the help-centre door on
   the right, so neither reads as the other's afterthought. */
.spot__hints {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 12px;
    padding: 2px 16px 8px;
}
.spot__help-hint {
    display: flex;
    align-items: center;
    gap: 6px;
    color: #6b7a83;
    font-size: 12px;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    margin-left: auto; /* stays right when the row wraps or the human hint is absent */
}
.spot__help-hint:hover { text-decoration: underline; color: #13505e; }
.spot__help-hint .fa { font-size: 11px; }

/* Milo's handover line sits inside the (orange) ClubRight Support thread — give
   his own mark the club colour so it still reads as Milo talking, not the team. */
.spt-milo-avatar { color: var(--spot-color, #64748b); }
.spt-milo-avatar svg { width: 15px; height: 15px; }

/* Vertical text so the narrow spine never squashes the label. Reads bottom-to-top. */
.spot__support-tab-label {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    white-space: nowrap;
    font-weight: 700;
    font-size: 11px;
    letter-spacing: 0.03em;
    line-height: 1;
}

/* ── Conversations: slim actions bar + the chooser (#42790) ─────────────────── */
/* Only shown once a chat is live, so the operator can hop back to their list or
   start a fresh thread without losing the current one. Right-aligned + pill so
   it reads as controls, not a page header (which the panel deliberately omits). */
.spot__support-bar {
    flex: 0 0 auto;
    display: flex;
    justify-content: flex-end;
    gap: 6px;
    padding: 8px 4px 2px;
}
.spot__support-bar-btn {
    background: none;
    border: 1px solid var(--spot-border);
    border-radius: 999px;
    padding: 4px 11px;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    color: #e8651a;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    transition: background 0.15s, border-color 0.15s;
}
.spot__support-bar-btn:hover {
    background: color-mix(in srgb, #f06522 8%, #ffffff);
    border-color: color-mix(in srgb, #f06522 40%, var(--spot-border));
}
.spot__support-bar-btn .fa { font-size: 11px; }

/* While choosing, the reply box is meaningless — hide it. */
.spot__support.picking .spot__input { display: none; }

.spt-pick { padding: 2px 4px 10px; }
.spt-pick__loading { padding: 24px 8px; color: #94a3b8; font-size: 13px; }

/* ── #43546 — Milo beta notice + Give feedback ─────────────────────────────
   Persistent by design: no dismiss control. The chat variant sits between the
   widget header and the thread; the overview variant is a card on /ClubOverview. */
.milo-beta {
    display: flex;
    align-items: center;
    gap: 8px;
}

.milo-beta--chat {
    padding: 7px 14px;
    background: #fff7f2;
    border-bottom: 1px solid #fde4d3;
    font-size: 12px;
}

.milo-beta__pill {
    flex: 0 0 auto;
    padding: 2px 8px;
    border-radius: 999px;
    background: #EC6627;
    color: #fff;
    font-size: 10px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.milo-beta__text {
    flex: 1 1 auto;
    margin: 0;
    color: #52525b;
    min-width: 0;
}

.milo-beta__btn {
    flex: 0 0 auto;
    border: 1px solid #EC6627;
    background: #fff;
    color: #EC6627;
    border-radius: 999px;
    padding: 3px 11px;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
}

.milo-beta__btn:hover {
    background: #EC6627;
    color: #fff;
}

.milo-beta--overview {
    margin-bottom: 14px;
    padding: 14px 16px;
    background: #fff;
    border: 1px solid #fde4d3;
    border-left: 3px solid #EC6627;
    border-radius: 10px;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}

.milo-beta--overview .milo-beta__body {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.milo-beta--overview .milo-beta__text {
    font-size: 13px;
}

.milo-beta--overview .milo-beta__btn {
    padding: 6px 14px;
    font-size: 12px;
}

@media (max-width: 640px) {
    .milo-beta--overview {
        flex-direction: column;
        align-items: flex-start;
    }
    .milo-beta--overview .milo-beta__body {
        flex-direction: column;
        align-items: flex-start;
        gap: 6px;
    }
}

/* Drawer loading state: a ClubRight-orange life ring — the support tab's own
   icon, thrown to you — spinning steadily and bobbing like it's on water. */
.spt-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 42px 8px;
}

.spt-loading__ring {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    /* Classic lifebuoy: four orange panels alternating white… */
    background: conic-gradient(
        #EC6627 0 45deg,    #fff 45deg 90deg,
        #EC6627 90deg 135deg, #fff 135deg 180deg,
        #EC6627 180deg 225deg, #fff 225deg 270deg,
        #EC6627 270deg 315deg, #fff 315deg 360deg);
    /* …cut into a ring. */
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 13px), #000 calc(100% - 12px));
    mask: radial-gradient(farthest-side, transparent calc(100% - 13px), #000 calc(100% - 12px));
    filter: drop-shadow(0 2px 4px rgba(236, 102, 39, 0.35));
    animation: sptRingSpin 1.8s linear infinite, sptRingBob 2.6s ease-in-out infinite;
}

.spt-loading__text {
    font-size: 13px;
    font-weight: 600;
    color: #94a3b8;
}

@keyframes sptRingSpin {
    to { rotate: 360deg; }
}

/* rotate + translate as separate properties so the two animations compose. */
@keyframes sptRingBob {
    0%, 100% { translate: 0 0; }
    50% { translate: 0 -5px; }
}

@media (prefers-reduced-motion: reduce) {
    .spt-loading__ring { animation: none; }
}
.spt-pick__head {
    font-size: 15px;
    font-weight: 800;
    color: #0f172a;
    padding: 6px 6px 12px;
}
.spt-pick__new {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: linear-gradient(135deg, #f06522 0%, #e8651a 100%);
    color: #fff;
    border: none;
    border-radius: 12px;
    padding: 12px;
    font: inherit;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 6px 16px -6px rgba(240, 101, 34, 0.6);
    transition: filter 0.15s;
}
.spt-pick__new:hover { filter: brightness(1.06); }
.spt-pick__label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #94a3b8;
    padding: 16px 6px 6px;
}
.spt-pick__row {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    text-align: left;
    background: var(--spot-bg);
    border: 1px solid var(--spot-border);
    border-radius: 12px;
    padding: 10px 12px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.06s;
}
.spt-pick__row:hover {
    border-color: color-mix(in srgb, #f06522 45%, var(--spot-border));
    box-shadow: 0 4px 14px -8px rgba(240, 101, 34, 0.5);
}
.spt-pick__row:active { transform: translateY(1px); }
.spt-pick__row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.spt-pick__row-subject {
    font-size: 13.5px;
    font-weight: 700;
    color: #0f172a;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: flex;
    align-items: center;
    gap: 6px;
}
.spt-pick__row-preview {
    font-size: 12px;
    color: #94a3b8;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.spt-pick__row-meta {
    flex: 0 0 auto;
    font-size: 11px;
    color: #b6bcc7;
    white-space: nowrap;
}
/* #43458 — team-side typing + presence signals in the support panel. */
.spt-typing {
    margin: 4px 0 2px;
    font-size: 12px;
    font-style: italic;
    color: #94a3b8;
}

.spot__support-presence {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 14px 2px;
    font-size: 12px;
    font-weight: 600;
    color: #16a34a;
}

/* display:flex above would defeat the hidden attribute (author styles beat
   the UA [hidden] rule) — restate it or the row shows permanently. */
.spot__support-presence[hidden] {
    display: none;
}

.spot__support-presence-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #16a34a;
    animation: spot-pulse-dot 1.4s ease-in-out infinite;
}

.spt-pick__dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #f06522;
    box-shadow: 0 0 0 3px color-mix(in srgb, #f06522 20%, transparent);
}

@keyframes spot-rise {
    from { transform: translateY(18px) scale(0.96); opacity: 0; }
    to   { transform: translateY(0)    scale(1);    opacity: 1; }
}

.spot--expanded .spot__panel {
    position: fixed;
    inset: 24px;
    width: auto;
    height: auto;
    max-height: none;
}

/* ============ HEADER ============ */
.spot__header {
    background: linear-gradient(135deg, var(--spot-color) 0%, var(--spot-color-deep) 100%);
    color: #fff;
    padding: 14px 14px 14px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    position: relative;
    flex-shrink: 0;
}
.spot__brand {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    flex: 1;
}
.spot__avatar {
    position: relative;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.18);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 17px;
    flex-shrink: 0;
    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.18);
}

/* Consistent ring+dot Milo mark (matches the floating bubble and the
   onboarding hero — no more lightning bolt). */
.spot__avatar-mark {
    width: 22px;
    height: 22px;
    color: #fff;
    transform-origin: center;
    animation: spot-avatar-wink 8s ease-in-out infinite;
}

/* Subtle wonky pulse rings — same treatment as the onboarding hero, scaled
   to the 38px avatar. Two de-synced, non-multiple periods + opposite turn so
   it never visibly repeats. Faint by design. */
.spot__avatar::before,
.spot__avatar::after {
    content: "";
    position: absolute;
    inset: -5px;
    border: 1.5px solid rgba(255, 255, 255, 0.42);
    border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%;
    opacity: 0;
    pointer-events: none;
}

.spot__avatar::before {
    animation: spot-avatar-ripple-a 4.6s ease-out infinite;
}

.spot__avatar::after {
    border-radius: 60% 40% 38% 62% / 55% 58% 42% 45%;
    animation: spot-avatar-ripple-b 6.1s ease-out infinite;
    animation-delay: 2.3s;
}

@keyframes spot-avatar-ripple-a {
    0%   { transform: scale(0.7) rotate(-6deg); opacity: 0.5; }
    60%  { opacity: 0.18; }
    100% { transform: scale(2.3) rotate(34deg); opacity: 0; }
}

@keyframes spot-avatar-ripple-b {
    0%   { transform: scale(0.74) rotate(8deg); opacity: 0.44; }
    60%  { opacity: 0.16; }
    100% { transform: scale(2.6) rotate(-52deg); opacity: 0; }
}

/* Occasional wink — double-blink then hold open (8s cycle, matches the
   onboarding hero). */
@keyframes spot-avatar-wink {
    0%, 84%   { transform: scaleY(1); }
    88%       { transform: scaleY(0.08); }
    91%       { transform: scaleY(1); }
    94%       { transform: scaleY(0.08); }
    97%, 100% { transform: scaleY(1); }
}
.spot__brand-text { min-width: 0; line-height: 1.2; }
.spot__brand-name {
    font-size: 17px;
    font-weight: 700;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    letter-spacing: -0.01em;
}
.spot__persona-toggle {
    background: rgba(255, 255, 255, 0.18);
    border: none;
    color: #fff;
    font-size: 11px;
    font-weight: 600;
    padding: 3px 8px 3px 10px;
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    transition: background 0.15s ease;
    letter-spacing: 0.01em;
}
.spot__persona-toggle:hover { background: rgba(255, 255, 255, 0.3); }
.spot__brand-sub {
    font-size: 11px;
    opacity: 0.85;
    margin-top: 2px;
    font-weight: 400;
}
.spot__controls {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}
/* Labelled header actions (new chat, past chats): pills an operator can find, next to a
   thin divider, with the window controls as quiet icons after it. */
.spot__hdr-action {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 28px;
    padding: 0 10px;
    border-radius: 14px;
    border: 1px solid rgba(255, 255, 255, 0.35);
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, transform 0.12s;
}
.spot__hdr-action:hover { background: rgba(255, 255, 255, 0.26); border-color: rgba(255, 255, 255, 0.6); }
.spot__hdr-action:active { transform: scale(0.96); }
.spot__hdr-action .fa { font-size: 11px; }
.spot__controls-divider { width: 1px; height: 18px; background: rgba(255, 255, 255, 0.35); margin: 0 2px; }
.spot__icon-btn {
    width: 28px;
    height: 28px;
    border-radius: 7px;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.95);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, color 0.15s, transform 0.12s;
    font-size: 12px;
    padding: 0;
}
.spot__icon-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    color: #fff;
}
.spot__icon-btn:active { transform: scale(0.92); }

/* ============ PERSONA MENU ============ */
.spot__persona-menu {
    position: absolute;
    top: 76px;
    left: 12px;
    right: 12px;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 16px 40px -8px rgba(15, 23, 42, 0.28), 0 0 0 1px rgba(15, 23, 42, 0.05);
    z-index: 6;
    padding: 6px;
    animation: spot-rise 0.18s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
    max-height: 280px;
    overflow-y: auto;
}
.spot__persona-menu .agents-persona {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 9px;
    cursor: pointer;
    transition: background 0.12s ease;
    background: transparent;
    border: none;
    margin: 0;
}
.spot__persona-menu .agents-persona:hover { background: #f1f5f9; }
.spot__persona-menu .agents-persona--active {
    background: var(--spot-color-soft);
}
.spot__persona-menu .agents-persona__icon {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--spot-color-soft);
    color: var(--spot-color);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    flex-shrink: 0;
}
.spot__persona-menu .agents-persona__info { min-width: 0; }
.spot__persona-menu .agents-persona__name {
    font-size: 13px;
    font-weight: 700;
    color: #0f172a;
    letter-spacing: -0.005em;
}
.spot__persona-menu .agents-persona__desc {
    font-size: 11px;
    color: #64748b;
    margin-top: 1px;
}

/* ============ PAGE-AWARE TIPS ============ */
.spot__tips {
    padding: 12px 16px 8px;
    border-bottom: 1px solid #f1f5f9;
    flex-shrink: 0;
    background: #fafbfc;
}
.spot__tips-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #94a3b8;
    font-weight: 700;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    gap: 6px;
}
/* One scrollable row, never a second line: the chips bleed to the panel edge so a cut-off
   chip is the "there's more" affordance, and the scrollbar stays hidden. */
.spot__tip-chips {
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    overflow-x: auto;
    margin: 0 -16px;
    padding: 0 16px 2px;
    scrollbar-width: none;
}
.spot__tip-chips::-webkit-scrollbar { display: none; }
.spot__tip-chip {
    flex: 0 0 auto;
    white-space: nowrap;
    background: var(--spot-color-soft);
    color: var(--spot-color-deep);
    border: 1px solid color-mix(in srgb, var(--spot-color) 20%, #ffffff);
    border-radius: 999px;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.14s ease;
    line-height: 1.2;
    font-family: inherit;
}
.spot__tip-chip:hover {
    background: var(--spot-color);
    color: #fff;
    transform: translateY(-1px);
    box-shadow: 0 4px 10px -2px color-mix(in srgb, var(--spot-color) 40%, transparent);
}
.spot__tip-chip:active { transform: translateY(0); }

/* ============ MESSAGES — overrides for in-panel layout ============ */
.spot__panel .spot__messages.agents-messages {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 14px 16px;
    background: #fafbfc;
    height: auto !important;     /* agents.css sets fixed height for /Agents page */
    min-height: 0;
    margin: 0;
}
/* #42788 — Milo thread (#messages) and human thread (#humanMessages) are separate
   scrolls; only one is shown at a time. Explicit so a flex display can't leak the
   hidden one through. */
.spot__panel .spot__messages[hidden] { display: none; }
.spot__panel .spot__messages.agents-messages::-webkit-scrollbar { width: 6px; }
.spot__panel .spot__messages.agents-messages::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 999px; }

/* ============ SUGGESTIONS / USAGE / INPUT ============ */
.spot__suggestions {
    padding: 0 14px;
    flex-shrink: 0;
}
.spot__suggestions:empty { padding: 0; }
.spot__usage {
    padding: 4px 16px 0;
    font-size: 10px;
    color: #94a3b8;
    text-align: right;
    min-height: 0;
    flex-shrink: 0;
}
.spot__usage:empty { display: none; }

.spot__input.agents-input {
    padding: 10px 12px;
    border-top: 1px solid #f1f5f9;
    background: #fff;
    display: flex;
    align-items: flex-end;
    gap: 8px;
    margin: 0;
    flex-shrink: 0;
}
.spot__textarea.agents-input__textarea {
    flex: 1;
    min-width: 0;                  /* let it shrink inside the flex row, never overflow */
    border: 1px solid #e2e8f0;
    border-radius: 12px;
    padding: 10px 12px;
    resize: none;
    font-family: inherit;
    font-size: 14px;
    background: #f8fafc;
    transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
    line-height: 1.4;
    min-height: 42px;              /* one comfortable line — never clip the placeholder */
    max-height: 120px;
    overflow-y: auto;
}
.spot__textarea.agents-input__textarea:focus {
    outline: none;
    /* No coloured focus ring — it inherited the club colour (e.g. bright red on some
       clubs) and looked wrong. Just a subtle neutral border + white bg. #42788 */
    border-color: #cbd5e1;
    background: #fff;
    box-shadow: none;
}
/* A global focus rule was still painting a 2px club-colour outline on the composer
   (bright red on the Test Club). Kill it on both composers. #42788 */
.spot__textarea.agents-input__textarea:focus,
.spot__textarea.agents-input__textarea:focus-visible {
    outline: none !important;
    box-shadow: none !important;
}
.spot__send.agents-input__send {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: none;
    background: var(--spot-color);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.12s, background 0.12s, box-shadow 0.12s;
    box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--spot-color) 40%, transparent);
    font-size: 14px;
    flex-shrink: 0;
}
.spot__send.agents-input__send:hover { transform: scale(1.06); }
/* #44478 — the attach button sits in the composer row like Send: same size, quiet style,
   so the row reads box · attach · send at every width. */
.spot__input .agents-att-btn.spot__attach {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid #e2e8f0;
    background: #f8fafc;
    color: #64748b;
    font-size: 15px;
    line-height: 1;
    padding: 0;
    opacity: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.spot__input .agents-att-btn.spot__attach:hover { background: #fff; color: #f06522; border-color: #cbd5e1; opacity: 1; }
.spot__input .agents-att-btn.spot__attach:disabled { opacity: 0.5; cursor: not-allowed; }
.spot__send.agents-input__send:disabled,
.spot__send.agents-input__send.disabled {
    background: #cbd5e1;
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
}

.spot__hint {
    padding: 6px 14px 10px;
    font-size: 10px;
    color: #94a3b8;
    text-align: center;
    background: #fff;
    flex-shrink: 0;
}
/* ============ BUDGET STRIP ============ */
.spot__budget {
    /* #44081 — only shown when the week's allowance is nearly gone, as a sentence
       over a bar. Never a dollar figure here. */
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 6px 14px 2px;
    font-size: 11px;
    color: #64748b;
    background: #fff;
    flex-shrink: 0;
}
.spot__budget[hidden] { display: none; }
.spot__budget-bar {
    flex: 1;
    height: 4px;
    background: #f1f5f9;
    border-radius: 999px;
    overflow: hidden;
    position: relative;
}
.spot__budget-fill {
    display: block;
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, var(--spot-color) 0%, var(--spot-color-deep) 100%);
    border-radius: 999px;
    transition: width 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.spot__budget--warn .spot__budget-fill { background: linear-gradient(90deg, #f59e0b 0%, #d97706 100%); }
.spot__budget--danger .spot__budget-fill { background: linear-gradient(90deg, #ef4444 0%, #b91c1c 100%); }
.spot__budget--danger .spot__budget-text { color: #b91c1c; font-weight: 600; }
.spot__budget-text {
    white-space: normal;
    line-height: 1.35;
}

.spot__hint kbd {
    display: inline-block;
    padding: 1px 5px;
    margin: 0 1px;
    background: #f1f5f9;
    border: 1px solid #e2e8f0;
    border-bottom-width: 2px;
    border-radius: 4px;
    font-size: 10px;
    font-family: ui-monospace, SFMono-Regular, monospace;
    color: #475569;
}

/* ============ TOOL-USE CHIPS (during streaming) ============ */
/* agents.js renders <div class="agents-tool"> for in-flight tool calls — we just
   style them to feel alive */
.spot__messages .agents-tool {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #eef2ff;
    color: #4338ca;
    border-radius: 999px;
    padding: 4px 10px;
    font-size: 11px;
    font-weight: 600;
    margin: 4px 0;
    animation: spot-tool-in 0.22s ease backwards;
}
.spot__messages .agents-tool::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    animation: spot-pulse-dot 1.4s ease-in-out infinite;
}
@keyframes spot-tool-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ============ HISTORY DROPDOWN ============ */
.spot__history {
    position: absolute;
    top: 68px;
    right: 12px;
    width: 320px;
    max-width: calc(100% - 24px);
    max-height: 380px;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 16px 40px -8px rgba(15, 23, 42, 0.28), 0 0 0 1px rgba(15, 23, 42, 0.08);
    z-index: 7;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    animation: spot-rise 0.18s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
}
.spot__history-header {
    padding: 10px 14px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #64748b;
    border-bottom: 1px solid #f1f5f9;
    background: #fafbfc;
}
.spot__history-list {
    overflow-y: auto;
    flex: 1;
    padding: 4px;
}
.spot__history-empty {
    padding: 18px 14px;
    text-align: center;
    color: #94a3b8;
    font-size: 12px;
}
.spot__history-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: 100%;
    background: transparent;
    border: none;
    border-radius: 8px;
    padding: 9px 12px;
    text-align: left;
    cursor: pointer;
    transition: background 0.12s ease;
    font-family: inherit;
}
.spot__history-row + .spot__history-row { margin-top: 1px; }
.spot__history-row:hover { background: #f1f5f9; }
.spot__history-preview {
    font-size: 13px;
    color: #0f172a;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-height: 1.35;
}
.spot__history-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 10px;
    color: #94a3b8;
}
.spot__history-tag {
    background: #f1f5f9;
    color: #64748b;
    padding: 1px 6px;
    border-radius: 999px;
    font-size: 9px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* ============ MOBILE ============ */
@media (max-width: 640px) {
    .spot { --spot-inset-bottom: 16px; right: 16px; }
    .spot__panel {
        position: fixed;
        inset: 16px 16px 90px 16px;
        width: auto;
        height: auto;
        max-height: none;
    }
    .spot--expanded .spot__panel { inset: 8px; }
    /* The header has no room for labels beside the brand on a phone: icons only. */
    .spot__hdr-action-label { display: none; }
    .spot__hdr-action { padding: 0 9px; }
    /* No room to sit beside Milo — the panel becomes a bottom sheet, peeking as a
       bar at the bottom and sliding up full-screen when opened. */
    .spot__support {
        position: fixed;
        inset: 16px 16px 90px 16px;
        width: auto;
        height: auto;
        transform: translateY(calc(100% - 44px));
        /* Tab is a 44px bar across the TOP on mobile (not the left spine), so
           drop the desktop left padding and clear the tab from the top instead —
           keeps both the live thread and the conversations picker readable. */
        padding: 52px 12px 0;
    }
    /* No room to peek beside Milo on mobile, so an opened support sheet sits
       ON TOP of Milo (desktop keeps it behind, emerging from the side). Without
       this it opened behind Milo and looked like nothing happened — "human
       support is in there, I just can't find it". Entry is the "Looking for
       human support?" pointer in Milo. #42790 */
    .spot__support.open { transform: none; z-index: 60; }
    .spot__support-tab {
        left: 0; right: 0; top: 0; bottom: auto;
        transform: none;                 /* not a centred pill on mobile — full-width top bar */
        width: auto; height: 44px;
        padding: 8px 5px;
        writing-mode: horizontal-tb;
        flex-direction: row;
        border-radius: var(--spot-radius) var(--spot-radius) 0 0;
        box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.14);
    }
    /* Undo the vertical-text rotation — the mobile tab is a horizontal top bar. */
    .spot__support-tab-label { writing-mode: horizontal-tb; transform: none; }
    .spot__support-tab .fa { margin-bottom: 0; margin-right: 6px; }
}

/* ============ TALK TO A HUMAN (always-on) ============ */
.spot__human {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    width: calc(100% - 28px);
    margin: 0 14px 8px;
    padding: 8px 12px;
    border: 1px solid var(--spot-color-soft);
    border-radius: 10px;
    background: var(--spot-color-soft);
    color: var(--spot-color-deep);
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, transform 0.12s;
}
.spot__human:hover { background: var(--spot-color); color: #fff; }
.spot__human:active { transform: scale(0.98); }

/* ============ GET-SUPPORT PANEL CHROME ============ */
/* Teal header so a person vs. Milo (orange) is never ambiguous. */
.spot__support-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 14px 16px;
    color: #fff;
    background: linear-gradient(135deg, #f06522 0%, #e8651a 100%);
    flex: 0 0 auto;
}
.spot__support-name { font-weight: 700; font-size: 15px; }
.spot__support-sub { font-size: 12px; opacity: 0.85; margin-top: 2px; }
.spot__support-header .spot__icon-btn { color: #fff; opacity: 0.9; }
.spot__support-header .spot__icon-btn:hover { opacity: 1; }
.spot__support .spot__send.agents-input__send { background: #f06522; }
/* While the support panel is open, the "Back to the team" button lives in the
   panel itself — no need to also show "Talk to a human" on Milo. */
.spot--support-open .spot__human { opacity: 0.6; }

/* Hidden util — keeps inline display logic simple */
.spot [hidden] { display: none !important; }

/* ── #43336 — minimised-state adornments on the launcher ─────────────────────
   Top-right corner of the icon (the unread badge keeps the exact corner pixel;
   these sit just beside it on the rare occasion both show).
   thinking = cloud while a response streams; reply = green dot for an answer
   that landed unseen; draft = pencil when minimised with an unsent message. */
.spot__bubble-status {
    position: absolute;
    top: -6px;
    right: -6px;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}

/* Thinking: drawn thought cloud — eye-colour fill, bubble-dark outline
   (same recipe as the typing dots and the z's). */
.spot__bubble-status--thinking svg {
    width: 26px;
    height: 26px;
    display: block;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.25));
    animation: spotStatusBob 1.6s ease-in-out infinite;
}

.spot__cloud-outline {
    fill: var(--spot-color-deep, #3550c7);
    stroke: var(--spot-color-deep, #3550c7);
    stroke-width: 2.4;
}

.spot__cloud-fill {
    fill: currentColor;
}

/* Typing: three solid dots waving on the bubble's top-right corner — white
   with a soft dark shadow so they read on any club colour. */
.spot__bubble-status--draft {
    top: 4px;
    right: 2px;
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.spot__bubble-status--draft i {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    /* The thinking-cloud recipe: fill in Milo's eye colour, outline in the
       bubble's own dark shade — reads on the bubble AND on the page. */
    background: currentColor;
    box-shadow: 0 0 0 1.5px var(--spot-color-deep, #3550c7),
                0 1px 2px rgba(15, 23, 42, 0.35);
    animation: spotTypingWave 1.2s ease-in-out infinite;
}

.spot__bubble-status--draft i:nth-child(2) { animation-delay: 0.15s; }
.spot__bubble-status--draft i:nth-child(3) { animation-delay: 0.3s; }

@keyframes spotTypingWave {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
    30% { transform: translateY(-3px); opacity: 1; }
}

.spot__bubble-status--reply {
    width: 13px;
    height: 13px;
    background: #22c55e;
    border: 2px solid #fff;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    animation: spotStatusPing 3.2s ease-in-out infinite;
}

@keyframes spotStatusBob {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-2px); }
}

/* The reply dot gives a soft "I'm here" ping. */
@keyframes spotStatusPing {
    0%, 70%, 100% { transform: scale(1); }
    78% { transform: scale(1.3); }
    86% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .spot__bubble-status--thinking svg,
    .spot__bubble-status--draft i,
    .spot__bubble-status--reply {
        animation: none;
    }
}

/* Live-session badge in the history list — the one row that isn't history. */
.spot__history-tag--live {
    color: #16a34a;
    font-weight: 600;
}

/* ── Lifecycle ring: alive breathes, winding dims + slows, gone when over ── */
.spot__bubble-ring {
    position: absolute;
    inset: -5px;
    border-radius: 50%;
    border: 2px solid var(--spot-color);
    opacity: 0;
    pointer-events: none;
}

.spot--alive .spot__bubble-ring {
    animation: spotRingBreathe 3s ease-in-out infinite;
}

/* Final minutes: the ring turns ClubRight orange and breathes slowly — the
   visible "this chat is about to end" signal, matching the countdown clock. */
.spot--winding .spot__bubble-ring {
    border-color: #EC6627;
    animation: spotRingWinding 6s ease-in-out infinite;
}

@keyframes spotRingBreathe {
    0%, 100% { opacity: 0.2; transform: scale(1); }
    50% { opacity: 0.55; transform: scale(1.04); }
}

@keyframes spotRingWinding {
    0%, 100% { opacity: 0.3; transform: scale(1); }
    50% { opacity: 0.7; transform: scale(1.03); }
}

/* Ended while tucked away — Milo sleeps until clicked: z's escape the icon
   one by one, rising up and away, growing as they fade. */
.spot__bubble-status--sleep {
    width: 34px;
    height: 34px;
}

.spot__bubble-status--sleep b {
    position: absolute;
    bottom: 2px;
    left: 8px;
    font-size: 14px;
    line-height: 1;
    font-weight: 800;
    font-family: 'Mulish', system-ui, sans-serif;
    /* The thinking-cloud recipe: the glyph inherits Milo's eye colour from
       the bubble; the halo is the bubble's own dark shade, so the z's keep
       their outline as they drift off the bubble onto the page. */
    text-shadow: 0 0 2px var(--spot-color-deep, #3550c7),
                 0 0 5px color-mix(in srgb, var(--spot-color-deep, #3550c7) 50%, transparent),
                 0 1px 2px color-mix(in srgb, var(--spot-color-deep, #3550c7) 60%, transparent);
    opacity: 0;
    pointer-events: none;
    animation: spotZDrift 4.2s ease-out infinite;
}

.spot__bubble-status--sleep b:nth-child(2) { animation-delay: 1.4s; }
.spot__bubble-status--sleep b:nth-child(3) { animation-delay: 2.8s; }

@keyframes spotZDrift {
    0%   { transform: translate(0, 0) scale(0.75) rotate(-8deg); opacity: 0; }
    12%  { opacity: 1; }
    60%  { opacity: 0.6; }
    100% { transform: translate(16px, -26px) scale(1.6) rotate(10deg); opacity: 0; }
}

/* Sleepy eye: the look-around/blink idle pauses, the lid curve drops across
   the middle of the eye, and the pupil is clipped to below it — top half
   hidden, like a lid resting half over the eye. */
.spot__bubble-lid {
    display: none;
}

.spot--sleeping .spot__bubble .spot__bubble-icon {
    animation: none;
}

.spot--sleeping .spot__bubble .spot__bubble-icon > circle:last-child {
    animation: none;
    clip-path: url(#spotEyeLidClip);
}

.spot--sleeping .spot__bubble-lid {
    display: block;
}

@media (prefers-reduced-motion: reduce) {
    .spot--alive .spot__bubble-ring,
    .spot--winding .spot__bubble-ring {
        animation: none;
        opacity: 0.3;
    }
    /* One static z instead of the drifting trio. */
    .spot__bubble-status--sleep b {
        animation: none;
        opacity: 0.9;
    }
    .spot__bubble-status--sleep b:nth-child(2),
    .spot__bubble-status--sleep b:nth-child(3) {
        display: none;
    }
}

/* ── Expanded mode: draggable header + corner resize grips ──────────────── */
.spot--expanded .spot__header {
    cursor: move;
    user-select: none;
}

.spot__resize {
    position: absolute;
    width: 18px;
    height: 18px;
    display: none;
    z-index: 6;
}

.spot--expanded .spot__resize { display: block; }

.spot__resize--nw { top: 0; left: 0; cursor: nwse-resize; }
.spot__resize--ne { top: 0; right: 0; cursor: nesw-resize; }
.spot__resize--sw { bottom: 0; left: 0; cursor: nesw-resize; }
.spot__resize--se { bottom: 0; right: 0; cursor: nwse-resize; }

/* Small screens: the panel is already a full-width bottom sheet — expanding,
   dragging and resizing make no sense there, so the option goes away. */
@media (max-width: 640px) {
    #spotExpand,
    .spot__resize {
        display: none !important;
    }
}

/* ── Milo feedback modal (#43546 follow-on) ───────────────────────────────────
   The in-product feedback box behind every "Give feedback" button.

   Presented as a sibling of the onboarding Q&A overlay (onboarding-overlay.css
   `.onboarding-q`): same Milo hero strip, aperture mark, blurred backdrop and
   rise-in panel. Those are the only two moments where Milo asks the operator for
   something instead of answering them, so they should read as one conversation.
   The rules are restated here rather than shared because onboarding-overlay.css
   only loads on onboarding pages, and this button is on every admin page.

   Fixed to the viewport with its own backdrop rather than a Bootstrap modal: the
   widget can be open on any admin page, and _DashboardLayout carries no Bootstrap
   5 modal JS. z-index sits above the assistant panel so it works from inside the
   chat. */
/* Same colour source and same safe-degradation trick as the widget chrome above:
   a club with no brand colour makes _Layout emit an EMPTY `--cui-nav-link-color`,
   and a var() fallback does not apply to a set-but-empty property. The @property
   registration gives it a typed default so the hero gradient can never resolve to
   nothing and paint white-on-white. */
@property --milo-fb-color {
    syntax: '<color>';
    inherits: true;
    initial-value: #5B7CFA;
}

.milo-fb {
    --milo-fb-color: var(--cui-nav-link-color, #5B7CFA);
    position: fixed;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(15, 23, 42, 0.78);
    backdrop-filter: blur(6px);
    animation: milo-fb-fade-in 220ms ease;
}

.milo-fb[hidden] { display: none; }

@keyframes milo-fb-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* Kept as its own element so a click anywhere off the panel closes the box.
   The tint lives on the parent (above) so the blur applies to the whole layer. */
.milo-fb__backdrop {
    position: absolute;
    inset: 0;
}

.milo-fb__dialog {
    position: relative;
    width: 100%;
    max-width: 560px;
    max-height: calc(100vh - 48px);
    overflow-y: auto;
    background: #fff;
    border-radius: 22px;
    padding: 36px 40px 30px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.36);
    animation: milo-fb-rise 280ms cubic-bezier(.22,.61,.36,1);
}

@keyframes milo-fb-rise {
    from { transform: translateY(18px) scale(0.97); opacity: 0; }
    to   { transform: translateY(0) scale(1); opacity: 1; }
}

/* ── Hero strip ─────────────────────────────────────────────────────────────
   Bleeds to the panel edges (negative margins counter the panel padding): a deep
   angular gradient off the club colour, an oversized rotating aperture bleeding
   off the right, and the mark with its wonky pulse rings + occasional wink. */
.milo-fb__hero {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: 14px;
    margin: -36px -40px 24px;
    padding: 26px 40px;
    /* Fallback for browsers without color-mix() — still a bold deep gradient. */
    background: linear-gradient(115deg, var(--milo-fb-color) 0%, #1e1b4b 60%, #0b1020 130%);
    background:
        linear-gradient(115deg,
            var(--milo-fb-color) 0%,
            color-mix(in srgb, var(--milo-fb-color) 70%, #000) 55%,
            #0b1020 130%);
    /* Matches the widget header's own gradient direction so the two read as one
       surface when the box opens from inside the chat. */
    color: #fff;
    border-radius: 22px 22px 0 0;
}

.milo-fb__hero-bigmark {
    position: absolute;
    /* Pushed well off the edge: on this narrower panel a mark that sits fully
       inside the strip reads as a smudge behind the close button rather than as
       a graphic bleeding off it. */
    right: -78px;
    top: 50%;
    width: 190px;
    height: 190px;
    margin-top: -95px;
    color: #fff;
    opacity: 0.13;
    z-index: -1;
    pointer-events: none;
    animation: milo-fb-spin 24s linear infinite;
}

.milo-fb__hero-bigmark svg { width: 100%; height: 100%; }

@keyframes milo-fb-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

.milo-fb__hero-mark {
    position: relative;
    flex-shrink: 0;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.16);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Wonky pulse rings — blob-shaped (NOT circular) ripples expand out and fade, on
   de-synced periods and opposite turn directions so they never line up. Faint on
   purpose: a whisper that Milo is switched on, not a halo. */
.milo-fb__hero-mark::before,
.milo-fb__hero-mark::after {
    content: "";
    position: absolute;
    inset: -7px;
    border: 1.5px solid rgba(255, 255, 255, 0.42);
    border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%;
    opacity: 0;
    z-index: -1;
    pointer-events: none;
}

.milo-fb__hero-mark::before {
    animation: milo-fb-ripple-a 4.6s ease-out infinite;
}

.milo-fb__hero-mark::after {
    border-radius: 60% 40% 38% 62% / 55% 58% 42% 45%;
    animation: milo-fb-ripple-b 6.1s ease-out infinite;
    animation-delay: 2.3s;
}

@keyframes milo-fb-ripple-a {
    0%   { transform: scale(0.74) rotate(-6deg); opacity: 0.5; }
    60%  { opacity: 0.18; }
    100% { transform: scale(2.4) rotate(34deg); opacity: 0; }
}

@keyframes milo-fb-ripple-b {
    0%   { transform: scale(0.78) rotate(8deg); opacity: 0.44; }
    60%  { opacity: 0.16; }
    100% { transform: scale(2.7) rotate(-52deg); opacity: 0; }
}

.milo-fb__hero-mark svg {
    width: 25px;
    height: 25px;
    color: #fff;
    transform-origin: center;
    animation: milo-fb-wink 8s ease-in-out infinite;
}

/* Occasional wink — the aperture squashes shut for a beat (a quick double-blink)
   then holds open for the rest of the cycle: personality, not a strobe. */
@keyframes milo-fb-wink {
    0%, 84%   { transform: scaleY(1); }
    88%       { transform: scaleY(0.08); }
    91%       { transform: scaleY(1); }
    94%       { transform: scaleY(0.08); }
    97%, 100% { transform: scaleY(1); }
}

.milo-fb__hero-text {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
    position: relative;
}

.milo-fb__hero-name {
    font-weight: 800;
    font-size: 1.3rem;
    letter-spacing: -0.01em;
}

.milo-fb__hero-tag {
    font-size: 0.8rem;
    opacity: 0.92;
}

.milo-fb__close {
    position: absolute;
    top: 14px;
    right: 16px;
    background: rgba(255, 255, 255, 0.18);
    border: none;
    color: #fff;
    font-size: 0.95rem;
    cursor: pointer;
    padding: 6px 9px;
    line-height: 1;
    border-radius: 8px;
    z-index: 1;
}

.milo-fb__close:hover { background: rgba(255, 255, 255, 0.32); }

/* ── Body ───────────────────────────────────────────────────────────────── */
.milo-fb__prompt {
    margin: 0 0 6px;
    font-size: 1.15rem;
    font-weight: 700;
    color: #111827;
    line-height: 1.3;
}

.milo-fb__intro {
    margin: 0 0 18px;
    font-size: 0.88rem;
    line-height: 1.55;
    color: #6b7280;
}

.milo-fb__thumbs {
    display: flex;
    gap: 10px;
    margin-bottom: 18px;
}

.milo-fb__thumb {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    border: 1px solid #e5e7eb;
    background: #fff;
    color: #4b5563;
    border-radius: 12px;
    padding: 11px 12px;
    font-size: 0.87rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
}

.milo-fb__thumb-ic {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: #f1f5f9;
    color: #94a3b8;
    font-size: 0.75rem;
    transition: background 120ms ease, color 120ms ease;
}

.milo-fb__thumb:hover {
    border-color: #d4d4d8;
    background: #fafafa;
}

.milo-fb__thumb--on {
    border-color: var(--milo-fb-color);
    background: #fff;
    color: #111827;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--milo-fb-color) 18%, transparent);
}

.milo-fb__thumb--on .milo-fb__thumb-ic {
    background: var(--milo-fb-color);
    color: #fff;
}

.milo-fb__label {
    display: block;
    margin-bottom: 7px;
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: #9ca3af;
}

.milo-fb__input {
    width: 100%;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    padding: 12px 14px;
    font-family: inherit;
    font-size: 0.93rem;
    line-height: 1.55;
    color: #111827;
    background: #f9fafb;
    resize: vertical;
    transition: border-color 120ms ease, background 120ms ease, box-shadow 120ms ease;
}

.milo-fb__input::placeholder { color: #b4bac4; }

.milo-fb__input:focus {
    outline: none;
    background: #fff;
    border-color: var(--milo-fb-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--milo-fb-color) 18%, transparent);
}

.milo-fb__note {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 12px 0 0;
    padding: 10px 13px;
    background: #f8fafc;
    border-radius: 10px;
    font-size: 0.78rem;
    line-height: 1.45;
    color: #6b7280;
}

.milo-fb__note i { margin-top: 2px; color: #9ca3af; }

.milo-fb__error {
    margin: 12px 0 0;
    padding: 10px 13px;
    background: #fef2f2;
    border-radius: 10px;
    font-size: 0.83rem;
    line-height: 1.45;
    color: #b91c1c;
}

.milo-fb__actions {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 20px;
}

.milo-fb__actions--centered { justify-content: center; }

.milo-fb__send {
    border: none;
    background: var(--milo-fb-color);
    color: #fff;
    border-radius: 999px;
    padding: 11px 24px;
    font-size: 0.88rem;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 4px 12px color-mix(in srgb, var(--milo-fb-color) 32%, transparent);
    transition: filter 120ms ease, box-shadow 120ms ease;
}

.milo-fb__send:hover { filter: brightness(0.93); }

.milo-fb__send:disabled {
    opacity: .55;
    cursor: default;
    box-shadow: none;
}

.milo-fb__cancel {
    border: none;
    background: none;
    color: #6b7280;
    border-radius: 999px;
    padding: 11px 14px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
}

.milo-fb__cancel:hover { color: #111827; background: #f3f4f6; }

/* ── Waiting ────────────────────────────────────────────────────────────── */
.milo-fb__step--sending {
    text-align: center;
    padding: 34px 0 26px;
}

.milo-fb__thinking {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 14px;
}

.milo-fb__thinking-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--milo-fb-color);
    opacity: 0.4;
    animation: milo-fb-bounce 1.2s infinite ease-in-out;
}

.milo-fb__thinking-dot:nth-child(2) { animation-delay: 0.15s; }
.milo-fb__thinking-dot:nth-child(3) { animation-delay: 0.3s; }

@keyframes milo-fb-bounce {
    0%, 80%, 100% { opacity: 0.4; transform: translateY(0); }
    40% { opacity: 1; transform: translateY(-5px); }
}

.milo-fb__sendingtext {
    margin: 0;
    font-size: 0.88rem;
    color: #6b7280;
}

/* ── The reply ──────────────────────────────────────────────────────────── */
.milo-fb__replyrow {
    display: flex;
    gap: 13px;
    align-items: flex-start;
    background: #f8fafc;
    border-radius: 14px;
    padding: 18px 20px;
}

.milo-fb__replyavatar {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--milo-fb-color);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
}

.milo-fb__replyavatar svg { width: 19px; height: 19px; }

.milo-fb__reply {
    flex: 1 1 auto;
    margin: 0;
    font-size: 0.93rem;
    line-height: 1.6;
    color: #374151;
    white-space: pre-wrap;
}

/* Accessibility: kill the motion for anyone who's asked for reduced motion —
   the box keeps its colour and depth, it just stops moving. */
@media (prefers-reduced-motion: reduce) {
    .milo-fb,
    .milo-fb__dialog,
    .milo-fb__hero-bigmark,
    .milo-fb__hero-mark::before,
    .milo-fb__hero-mark::after,
    .milo-fb__hero-mark svg,
    .milo-fb__thinking-dot {
        animation: none;
    }
}

@media (max-width: 640px) {
    .milo-fb { padding: 12px; }
    .milo-fb__dialog { padding: 28px 22px 24px; }
    .milo-fb__hero { margin: -28px -22px 20px; padding: 20px 22px; }
    .milo-fb__thumbs { flex-direction: column; }
}

/* The chip Milo offers in-chat when it has just logged a gap — an invitation at
   the moment of frustration, not a permanent fixture. Styled as a quiet aside so
   it never competes with the answer above it. */
.agents-gapfb {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 4px 0 6px 42px;
    font-size: 12px;
    color: #71717a;
}

.agents-gapfb__btn {
    border: 1px solid #EC6627;
    background: #fff;
    color: #EC6627;
    border-radius: 999px;
    padding: 3px 11px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
}

.agents-gapfb__btn:hover { background: #EC6627; color: #fff; }

/* ============ #43849 — QUICK HIDE (per-page tuck to the edge) ============
   The 58px bubble can sit on top of a page's bottom-right Save button, so a
   small chevron beside it sweeps Milo to the edge for THIS page only — nothing
   is persisted, the next page has him back. While tucked, a slim tab at the
   bubble's height is the way back: click it and Milo "jumps out" with the
   widget's spring curve. The launcher's state narration survives as a dot on
   the tab, so nothing lands unseen while he's tucked. */
/* A ghost at rest: no chrome, just a faint slate chevron in the bubble's
   gutter — it wakes when the pointer nears Milo, and only on its own hover
   becomes a small white pill with the club-colour chevron. The 24px box is
   the WCAG touch target; the visible glyph stays much smaller. */
.spot__hide-arrow {
    position: fixed;
    right: 0;
    bottom: 41px; /* centred on the 58px bubble (bottom 24px): 24 + 29 - 12 */
    z-index: 1049; /* one under the bubble — it lives in the bubble's gutter */
    width: 24px;  /* WCAG 2.2 minimum touch target — it's the only way to tuck */
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: #64748b;
    font-size: 10px;
    cursor: pointer;
    opacity: 0.35;
    transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease,
                box-shadow 0.15s ease, transform 0.15s ease;
}
.spot__bubble:hover ~ .spot__hide-arrow { opacity: 0.85; }
.spot__hide-arrow:hover {
    opacity: 1;
    color: var(--spot-color, #5B7CFA);
    background: #ffffff;
    box-shadow: 0 4px 12px -2px rgba(15, 23, 42, 0.25);
    transform: translateX(1px);
}
.spot__hide-arrow:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--spot-color, #5B7CFA) 60%, transparent);
    outline-offset: 1px;
    opacity: 1;
}
.spot__tab {
    position: fixed;
    right: 0;
    bottom: 26px; /* the bubble's height band, not mid-screen — it marks where Milo went */
    z-index: 1050;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    width: 34px;
    padding: 12px 5px 12px 3px;
    border: none;
    border-radius: 14px 0 0 14px;
    background-image: linear-gradient(160deg, var(--spot-color, #5B7CFA) 0%, var(--spot-color-deep, #3550c7) 100%);
    color: #fff;
    box-shadow: -8px 0 20px -8px color-mix(in srgb, var(--spot-color, #5B7CFA) 55%, transparent);
    cursor: pointer;
    transition: width 0.18s ease, padding 0.18s ease;
}
.spot__tab:hover { width: 42px; padding-left: 9px; }
.spot__tab:focus-visible {
    outline: 3px solid color-mix(in srgb, var(--spot-color, #5B7CFA) 50%, transparent);
    outline-offset: 2px;
}
.spot__tab-arrow { font-size: 11px; opacity: 0.9; }
.spot__tab-eye { width: 20px; height: 20px; }

/* Unread badge — same red pill as the bubble's, sized for the tab. */
.spot__tab-badge {
    position: absolute;
    top: -6px;
    left: -9px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: #ef4444;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 18px;
}

/* State dot: the tuck-away narration (#43336/#43458) compressed to one dot —
   the full cloud/z theatre stays on the bubble while Milo is open. */
.spot__tab-status { width: 9px; height: 9px; border-radius: 50%; }
.spot__tab-status--thinking { background: #ffffff; animation: spot-tab-think 1.1s ease-in-out infinite; }
.spot__tab-status--reply { background: #22c55e; }
.spot__tab-status--human { background: #EC6627; } /* ClubRight orange — must match the bubble's human dot */
.spot__tab-status--draft { background: rgba(255, 255, 255, 0.75); }
@keyframes spot-tab-think {
    0%, 100% { opacity: 0.35; transform: scale(0.8); }
    50%      { opacity: 1; transform: scale(1.15); }
}

/* The Grow nudge's attention pulse, mirrored from the bubble ring. */
.spot--nudging .spot__tab::after {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 18px 0 0 18px;
    border: 2px solid color-mix(in srgb, var(--spot-color, #5B7CFA) 70%, #ffffff);
    animation: spot-pulse 2.2s ease-out infinite;
    pointer-events: none;
}

/* Tab settles in from the edge after a sweep — small spring overshoot. */
.spot__tab--settle { animation: spot-tab-settle 0.42s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes spot-tab-settle {
    0%   { transform: translateX(110%); }
    100% { transform: translateX(0); }
}

/* Milo sweeps IN (tuck): the resting bubble rushes toward the edge and shrinks.
   Tuck only runs while the panel is closed, so the bubble is all there is. */
.spot--sweeping .spot__bubble {
    animation: spot-sweep 0.38s cubic-bezier(0.55, 0, 0.85, 0.36) forwards;
    transform-origin: 100% 50%;
    pointer-events: none;
}
@keyframes spot-sweep {
    0%   { transform: translateX(0) scale(1); opacity: 1; }
    100% { transform: translateX(90px) scale(0.45); opacity: 0; }
}

/* Milo jumps OUT (restore): spring overshoot from the edge. */
.spot--emerging .spot__bubble { animation: spot-emerge-bubble 0.45s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes spot-emerge-bubble {
    0%   { transform: translateX(70px) scale(0.3); opacity: 0; }
    60%  { transform: translateX(-6px) scale(1.08); opacity: 1; }
    100% { transform: translateX(0) scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .spot__tab,
    .spot__hide-arrow,
    .spot__tab--settle,
    .spot--sweeping .spot__bubble,
    .spot--emerging .spot__bubble,
    .spot__tab-status--thinking,
    .spot--nudging .spot__tab::after {
        animation: none;
        transition: none;
    }
}
