/* =============================================================================
   Notifications bell + dropdown panel
   -----------------------------------------------------------------------------
   Skinned to the SAP-blue box system (core/tokens.css, components/header-sapblue.css):
   a solid brand-blue panel header — the same treatment the data tables use — over a
   white list with cool-gray rules and severity accents taken from the --tbl-* status
   pairs, so the panel reads as part of the same product rather than a stray widget.

   SPECIFICITY NOTE (important, do not "simplify" these selectors):
   app.css @imports this file BEFORE components/dropdowns.css, and head.php re-links
   dropdowns.css after that. Panel-level rules therefore have to be written as
   .app-dropdown__menu.app-notifications-menu (0,2,0) so the generic .app-dropdown__menu
   rules cannot silently win a specificity tie. That tie is exactly what used to defeat
   `padding: 0` (the panel kept dropdowns.css's 6px gutter, so the header strip never
   reached the panel edges) and `display: flex` (the panel stayed `display: block`, so
   the header/body never actually flexed and the body's own max-height had to duplicate
   the panel's). Both are fixed here.
   ============================================================================= */

/* ---- Bell button --------------------------------------------------------- */

.app-header__notifications {
    position: relative;
}

.app-header__notifications-button {
    height: 36px;
    width: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--app-border);
    border-radius: var(--app-radius-md);
    background: var(--app-surface);
    color: var(--app-text);
    cursor: pointer;
    transition: background-color 140ms ease, border-color 140ms ease, color 140ms ease;
}

.app-header__notifications-button:hover {
    background: var(--app-surface-muted);
    color: var(--app-primary);
    border-color: color-mix(in srgb, var(--app-primary) 35%, var(--app-border));
}

/* Open state, mirroring the .app-user-button[aria-expanded="true"] treatment in
   header-sapblue.css so both header menus feel the same when open. Scoped with
   .app-header to reach that file's weight without !important. */
.app-header .app-header__notifications-button[aria-expanded="true"] {
    background: var(--hdr-active, rgba(255, 255, 255, .18));
    border-color: rgba(255, 255, 255, .5);
    color: var(--hdr-text, #fff);
}

.app-header__notifications-icon {
    width: 18px;
    height: 18px;
    display: block;
    fill: currentColor;
}

.app-header__notifications-badge {
    position: absolute;
    top: -5px;
    inset-inline-end: -5px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--app-danger, #b42318);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
    letter-spacing: .01em;
    /* Ring painted in the bar's own blue: the badge overlaps the button border, and
       without it the red sits directly on the border line and reads as smudged. */
    box-shadow: 0 0 0 2px var(--hdr-bg, #005c9e);
}

.app-header__notifications-badge[hidden] {
    display: none;
}

/* ---- Panel --------------------------------------------------------------- */

.app-dropdown__menu.app-notifications-menu {
    width: min(23.5rem, calc(100vw - 1.5rem));
    min-width: 18rem;
    max-height: min(26rem, calc(100vh - var(--app-header-height) - 1rem));
    padding: 0;
    overflow: hidden;
    display: none;
    background: var(--app-surface, #fff);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--app-radius-md, 4px);
    box-shadow: 0 12px 32px rgba(0, 43, 79, .18), 0 2px 6px rgba(0, 43, 79, .08);
}

.app-dropdown.is-open > .app-dropdown__menu.app-notifications-menu {
    display: flex;
    flex-direction: column;
    animation: app-notifications-menu-in 140ms ease-out;
}

@keyframes app-notifications-menu-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ---- Panel header (solid brand blue, like the table headers) -------------- */

.app-notifications-menu__header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
    background: var(--tbl-head-bg, #005c9e);
    border-bottom: 1px solid var(--tbl-head-rule, #003f6e);
}

.app-notifications-menu__title {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .01em;
    color: var(--tbl-head-text, #fff);
}

/* The bell holds only unread items now, so the header says so. Without it an empty bell
   reads as "nothing ever happened" rather than "you have read everything". */
.app-notifications-menu__hint {
    flex: 1 1 auto;
    font-size: 11px;
    font-weight: 600;
    color: var(--tbl-head-text, #fff);
    opacity: .72;
}

/* The way out to the full list. Sized to the same 26px touch target as the mark-all control
   beside it so the header row does not look ragged. */
.app-notifications-menu__all {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 6px;
    color: var(--tbl-head-text, #fff);
    opacity: .82;
    text-decoration: none;
}

.app-notifications-menu__all:hover {
    opacity: 1;
    background: rgba(255, 255, 255, .14);
}

.app-notifications-menu__all:focus-visible {
    outline: 2px solid var(--tbl-head-text, #fff);
    outline-offset: 1px;
}

.app-notifications-menu__all svg {
    width: 15px;
    height: 15px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.9;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.app-notifications-menu__mark-all {
    flex: 0 0 auto;
    padding: 5px 10px;
    border: 1px solid rgba(255, 255, 255, .35);
    border-radius: 999px;
    background: rgba(255, 255, 255, .10);
    color: var(--tbl-head-text, #fff);
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: background-color 140ms ease, border-color 140ms ease, opacity 140ms ease;
}

.app-notifications-menu__mark-all:hover:not(:disabled) {
    background: rgba(255, 255, 255, .22);
    border-color: rgba(255, 255, 255, .6);
}

.app-notifications-menu__mark-all:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 1px;
}

.app-notifications-menu__mark-all:disabled {
    opacity: .45;
    cursor: default;
}

/* ---- Body ---------------------------------------------------------------- */

.app-notifications-menu__body {
    flex: 1 1 auto;
    min-height: 0;
    /* Stated, not merely dropped. An earlier revision capped the body at 18rem, and a
       cached copy of that revision still loads alongside this one (app.css @imports
       this file without a version). A deleted declaration overrides nothing, so the
       stale cap survived and the body stopped short of the panel it was told to fill.
       `none` is a declaration the fresh copy can actually win with. */
    max-height: none;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--tbl-border, #bcc3cd) transparent;
}

.app-notifications-menu__body::-webkit-scrollbar {
    width: 10px;
}

.app-notifications-menu__body::-webkit-scrollbar-track {
    background: transparent;
}

.app-notifications-menu__body::-webkit-scrollbar-thumb {
    background: var(--tbl-border, #bcc3cd);
    border: 3px solid var(--app-surface, #fff);
    border-radius: 999px;
}

.app-notifications-menu__body::-webkit-scrollbar-thumb:hover {
    background: var(--tbl-border-strong, #8f9aa8);
}

/* ---- Empty / loading / error states -------------------------------------- */

.app-notifications-menu__state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 30px 16px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--app-text-muted);
    text-align: center;
}

/* These states are toggled via the `hidden` attribute. Now that they carry an
   explicit `display`, the UA's `[hidden] { display: none }` no longer wins — so
   it has to be restated here or every state would render at once. */
.app-notifications-menu__state[hidden] {
    display: none;
}

/* Glyph colours are baked into the data-URIs (the app has no dark theme; if one
   lands, swap these for mask-image + background-color so they follow the tokens). */
.app-notifications-menu__state::before {
    content: "";
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: 999px;
    background: var(--tbl-control-bg, #f0f2f5) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236b7a8a'%3E%3Cpath d='M12 22a2.5 2.5 0 0 0 2.45-2h-4.9A2.5 2.5 0 0 0 12 22Zm7-6V11a7 7 0 0 0-5.25-6.77V3a1.25 1.25 0 1 0-2.5 0v1.23A7 7 0 0 0 6 11v5l-2 2v1h16v-1l-2-2Z'/%3E%3C/svg%3E") center / 19px 19px no-repeat;
}

.app-notifications-menu__state[data-notifications-loading]::before {
    width: 24px;
    height: 24px;
    background: transparent;
    border: 2px solid var(--tbl-border, #bcc3cd);
    border-top-color: var(--app-primary, #005c9e);
    animation: app-notifications-spin 700ms linear infinite;
}

.app-notifications-menu__state[data-notifications-error]::before {
    background: var(--tbl-danger-bg, #f7e8e7) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23b1302a'%3E%3Cpath d='M12 2 1 21h22L12 2Zm1 14h-2v2h2v-2Zm0-7h-2v5h2V9Z'/%3E%3C/svg%3E") center / 19px 19px no-repeat;
}

@keyframes app-notifications-spin {
    to { transform: rotate(360deg); }
}

/* ---- List ---------------------------------------------------------------- */

.app-notifications-menu__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.app-notifications-menu__list[hidden] {
    display: none;
}

.app-notifications-menu__list > li + li {
    border-top: 1px solid var(--tbl-row-line, #d8dde4);
}

/* The row wraps the main action and the archive action as siblings — the archive
   control cannot be nested inside the item button (nested <button> is invalid). */
.app-notifications-row {
    border-radius: 0;
    display: flex;
    align-items: flex-start;
    background: var(--app-surface, #fff);
    /* Severity rail, transparent by default so read rows stay quiet. */
    border-inline-start: 3px solid transparent;
    transition: background-color 120ms ease;
}

/* The severity class lives on a span inside the item button, so :has() is what
   keeps the rail in CSS instead of forcing a second class into the JS renderer.
   Where :has() is unsupported the rail just stays transparent and the severity
   pill still carries the meaning. */
.app-notifications-row:has(.app-notifications-item__severity--info) {
    border-inline-start-color: var(--tbl-info, #1a5c8a);
}

.app-notifications-row:has(.app-notifications-item__severity--warning) {
    border-inline-start-color: var(--tbl-warning, #b25900);
}

.app-notifications-row:has(.app-notifications-item__severity--critical) {
    border-inline-start-color: var(--tbl-danger, #b1302a);
}

/* Read rows mute the rail and drop the tint, so unread items lead the eye.
   Must stay after the severity rules — same weight, later wins. */
.app-notifications-row:not(:has(.is-unread)) {
    border-inline-start-color: var(--tbl-border, #bcc3cd);
}

.app-notifications-row:has(.is-unread) {
    background: color-mix(in srgb, var(--app-primary) 5%, var(--app-surface));
}

.app-notifications-row:hover,
.app-notifications-row:has(.is-unread):hover {
    background: var(--tbl-brand-light, #e5f0fa);
}

/* ---- Item ---------------------------------------------------------------- */

.app-notifications-item {
    border-radius: 0;
    display: block;
    flex: 1 1 auto;
    min-width: 0;
    border: 0;
    background: transparent;
    text-align: start;
    padding: 10px 12px;
    cursor: pointer;
    color: inherit;
    font: inherit;
}

.app-notifications-item:focus-visible {
    outline: 2px solid var(--app-primary, #005c9e);
    outline-offset: -2px;
}

/* Fallback tint for browsers without :has() — the row-level rule above is the
   primary path and overrides this one where it is supported. */
.app-notifications-item.is-unread {
    background: color-mix(in srgb, var(--app-primary) 5%, transparent);
}

.app-notifications-item__title {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    margin-bottom: 3px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--app-text);
}

.app-notifications-item.is-unread .app-notifications-item__title {
    font-weight: 700;
}

/* Unread dot, pushed to the far end of the title line. */
.app-notifications-item.is-unread .app-notifications-item__title::after {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    margin-inline-start: auto;
    border-radius: 999px;
    background: var(--app-primary, #005c9e);
}

.app-notifications-item__message {
    margin-bottom: 5px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--app-text-muted);
    /* Two-line clamp keeps rows a predictable height, so one long message cannot
       push the rest of the list out of the panel. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.app-notifications-item__meta {
    font-size: 11px;
    letter-spacing: .01em;
    color: var(--app-text-muted);
}

.app-notifications-item__severity {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    height: 16px;
    padding: 0 6px;
    border-radius: var(--tbl-radius-sm, 2px);
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
}

.app-notifications-item__severity--info {
    background: var(--tbl-info-bg, #e3edf5);
    color: var(--tbl-info, #1a5c8a);
}

.app-notifications-item__severity--warning {
    background: var(--tbl-warning-bg, #fcf0e0);
    color: var(--tbl-warning, #b25900);
}

.app-notifications-item__severity--critical {
    background: var(--tbl-danger-bg, #f7e8e7);
    color: var(--tbl-danger, #b1302a);
}

/* ---- Archive control ----------------------------------------------------- */

.app-notifications-item__archive {
    flex: 0 0 auto;
    align-self: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    margin-inline-end: 8px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--app-text-muted);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    /* Revealed on hover/focus so the list stays visually calm, but it is always in
       the accessibility tree and reachable by keyboard. */
    opacity: 0;
    transition: opacity 120ms ease, background-color 120ms ease, color 120ms ease;
}

.app-notifications-row:hover .app-notifications-item__archive,
.app-notifications-item__archive:focus-visible {
    opacity: 1;
}

.app-notifications-item__archive:hover {
    background: var(--tbl-danger-bg, #f7e8e7);
    color: var(--tbl-danger, #b1302a);
}

.app-notifications-item__archive:focus-visible {
    outline: 2px solid var(--app-primary, #005c9e);
    outline-offset: 1px;
}

/* Touch devices never fire hover, which left the archive control permanently
   invisible there. Keep it shown when hover is unavailable. */
@media (hover: none) {
    .app-notifications-item__archive {
        opacity: 1;
    }
}

/* ---- Resize grip --------------------------------------------------------- */

/* The panel is pinned to its inline-END edge (.app-dropdown__menu--end), so the only
   corner that can follow the pointer is the bottom inline-START one: growing the width
   moves the start edge outward while the end edge stays put. A native `resize: both`
   puts its handle on the bottom-right corner instead — i.e. on the pinned edge in LTR —
   where the handle slides away from the cursor as you drag. Hence a custom grip.
   Injected by notifications-bell.js, so it never appears without its behaviour. */
.app-notifications-menu__resize {
    position: absolute;
    inset-block-end: 0;
    inset-inline-start: 0;
    width: 16px;
    height: 16px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--tbl-border-strong, #8f9aa8);
    cursor: nesw-resize;
    /* Without this the browser claims the gesture for scrolling and pointermove stops. */
    touch-action: none;
    opacity: 0;
    transition: opacity 120ms ease, color 120ms ease;
}

[dir="rtl"] .app-notifications-menu__resize {
    cursor: nwse-resize;
}

.app-notifications-menu__resize::before {
    content: "";
    position: absolute;
    inset: 3px;
    background: repeating-linear-gradient(45deg, currentColor 0 1px, transparent 1px 3px);
}

[dir="rtl"] .app-notifications-menu__resize::before {
    background: repeating-linear-gradient(-45deg, currentColor 0 1px, transparent 1px 3px);
}

.app-dropdown__menu.app-notifications-menu:hover .app-notifications-menu__resize,
.app-notifications-menu.is-resizing .app-notifications-menu__resize,
.app-notifications-menu__resize:focus-visible {
    opacity: 1;
}

.app-notifications-menu__resize:hover,
.app-notifications-menu.is-resizing .app-notifications-menu__resize {
    color: var(--app-primary, #005c9e);
}

.app-notifications-menu__resize:focus-visible {
    outline: 2px solid var(--app-primary, #005c9e);
    outline-offset: -2px;
}

/* Stops the drag from selecting the notification text it passes over. */
.app-notifications-menu.is-resizing {
    user-select: none;
}

/* Touch has no hover, so the grip would never reveal itself there. */
@media (hover: none) {
    .app-notifications-menu__resize {
        opacity: 1;
    }
}

/* ---- Responsive / motion ------------------------------------------------- */

@media (max-width: 480px) {
    .app-dropdown__menu.app-notifications-menu {
        width: calc(100vw - 1rem);
        max-height: min(30rem, calc(100vh - var(--app-header-height) - .75rem));
    }
}

@media (prefers-reduced-motion: reduce) {
    .app-dropdown.is-open > .app-dropdown__menu.app-notifications-menu {
        animation: none;
    }

    .app-notifications-menu__state[data-notifications-loading]::before {
        animation: none;
    }
}

/* -------------------------------------------------------------------------
 * Sticky notifications (dismiss_policy = entity_opened), added 2026-10-05.
 *
 * These are the ones "Mark all read" deliberately leaves behind: work assigned
 * to you, cleared only by opening the task. They need to look deliberate rather
 * than stuck, or the bell reads as broken.
 * ------------------------------------------------------------------------- */

.app-notifications-item.is-sticky {
    /* The marker sits on the inline-start edge so it mirrors under dir="rtl". */
    border-inline-start: 2px solid var(--app-warning);
}

.app-notifications-item__sticky {
    display: inline-block;
    margin-inline-start: 6px;
    padding: 0 6px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--app-warning) 14%, #fff);
    color: var(--app-warning);
    font-size: calc(var(--ui-small-font-size) * .88);
    white-space: nowrap;
}

/* =========================================================================
 * The floating chat dock (assets/js/components/chat-dock.js), 2026-10-05.
 * Lives in this file because it sits beside the bell in the header furniture
 * and shares its badge styling; a third stylesheet for one panel would be a
 * third place to keep the two in step.
 * ========================================================================= */

.chat-dock {
    position: fixed;
    bottom: 0;
    /* inset-inline-end, not right: the dock sits in the corner the writing
       direction ends at, which is the LEFT in Arabic. */
    inset-inline-end: 24px;
    z-index: 900;
    display: flex;
    flex-direction: column;
    width: min(340px, calc(100vw - 32px));
    height: min(460px, calc(100vh - 120px));
    border: 1px solid var(--app-border);
    border-bottom: 0;
    border-radius: var(--app-radius-md) var(--app-radius-md) 0 0;
    background: var(--app-surface);
    box-shadow: var(--app-shadow-md);
    overflow: hidden;
}

.chat-dock__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ui-space-sm);
    padding: var(--ui-space-xs) var(--ui-space-sm);
    background: var(--app-primary);
    color: #fff;
}

.chat-dock__title { font-weight: 600; font-size: var(--ui-small-font-size); }
.chat-dock__tools { display: flex; align-items: center; gap: var(--ui-space-2xs); }

.chat-dock__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 0;
    border-radius: var(--app-radius-sm);
    background: transparent;
    color: #fff;
    font-size: var(--ui-font-size);
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
}

.chat-dock__icon:hover { background: rgba(255, 255, 255, .18); }
.chat-dock__icon.is-muted { opacity: .5; }

.chat-dock__body { flex: 1 1 auto; min-height: 0; display: flex; }
.chat-dock__list { flex: 1 1 auto; overflow-y: auto; }
.chat-dock__thread { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.chat-dock__empty {
    margin: 0;
    padding: var(--ui-space-md);
    color: var(--app-text-muted);
    font-size: var(--ui-small-font-size);
    text-align: center;
}

.chat-dock__item {
    display: flex;
    align-items: center;
    gap: var(--ui-space-sm);
    width: 100%;
    padding: var(--ui-space-sm);
    border: 0;
    border-bottom: 1px solid var(--app-border);
    background: none;
    color: var(--app-text);
    font: inherit;
    text-align: start;
    cursor: pointer;
}

.chat-dock__item:hover { background: var(--app-surface-muted); }
.chat-dock__item.is-unread .chat-dock__item-title { font-weight: 700; }

.chat-dock__avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--app-primary) 14%, #fff);
    color: var(--app-primary);
    font-size: calc(var(--ui-small-font-size) * .9);
    font-weight: 600;
    unicode-bidi: isolate;
}

.chat-dock__item-body { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }

.chat-dock__item-title,
.chat-dock__item-preview { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.chat-dock__item-preview {
    color: var(--app-text-muted);
    font-size: calc(var(--ui-small-font-size) * .9);
}

.chat-dock__badge {
    flex: 0 0 auto;
    min-width: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--app-danger);
    color: #fff;
    font-size: calc(var(--ui-small-font-size) * .82);
    text-align: center;
    unicode-bidi: isolate;
}

.chat-dock__thread-head {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs);
    padding: var(--ui-space-xs) var(--ui-space-sm);
    border-bottom: 1px solid var(--app-border);
    font-size: var(--ui-small-font-size);
    font-weight: 600;
}

.chat-dock__back {
    border: 0;
    background: none;
    color: var(--app-primary);
    font-size: var(--ui-font-size);
    line-height: 1;
    cursor: pointer;
}

/* The chevron points back along the reading direction, so it has to flip. */
[dir="rtl"] .chat-dock__back { transform: scaleX(-1); }

.chat-dock__messages {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--ui-space-2xs);
    padding: var(--ui-space-sm);
    background: var(--app-bg);
}

.chat-dock__msg {
    display: flex;
    flex-direction: column;
    max-width: 85%;
    padding: 4px var(--ui-space-xs);
    border: 1px solid var(--app-border);
    border-radius: var(--app-radius-md);
    background: var(--app-surface);
    font-size: var(--ui-small-font-size);
    margin-inline-end: auto;
    overflow-wrap: anywhere;
}

.chat-dock__msg.is-mine {
    margin-inline-end: 0;
    margin-inline-start: auto;
    border-color: color-mix(in srgb, var(--app-primary) 35%, var(--app-border));
    background: color-mix(in srgb, var(--app-primary) 8%, #fff);
}

.chat-dock__msg--deleted { color: var(--app-text-muted); background: var(--app-surface-muted); }
.chat-dock__msg-author { color: var(--app-primary); font-weight: 600; }

.chat-dock__msg-time {
    align-self: flex-end;
    color: var(--app-text-muted);
    font-size: calc(var(--ui-small-font-size) * .8);
}

.chat-dock__composer {
    display: flex;
    gap: var(--ui-space-2xs);
    padding: var(--ui-space-xs);
    border-top: 1px solid var(--app-border);
}

.chat-dock__composer .app-input { flex: 1 1 auto; min-width: 0; }

/* On a phone the dock is the whole screen -- a 340px panel in a 375px viewport
   is a panel with no room for either pane. */
@media (max-width: 640px) {
    .chat-dock {
        inset-inline: 0;
        width: 100%;
        height: min(70vh, 520px);
        border-radius: 0;
    }
}

/* The dock's own unread count, beside its title. The header badge up top serves
   the shut state; once the dock is open the reader is looking at the bottom of
   the screen and a number in the opposite corner is one they have to go and find. */
.chat-dock__head-badge {
    display: inline-block;
    min-width: 18px;
    margin-inline-start: 6px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--app-danger);
    color: #fff;
    font-size: calc(var(--ui-small-font-size) * .82);
    text-align: center;
    unicode-bidi: isolate;
}

/* A short pulse when the dock pops open on an arriving message, so the movement
   is noticed without the panel sliding about. Honours reduced-motion. */
@keyframes chat-dock-arrive {
    0%   { transform: translateY(8px); opacity: .6; }
    100% { transform: translateY(0);   opacity: 1; }
}

.chat-dock:not([hidden]) {
    animation: chat-dock-arrive .18s ease-out;
}

@media (prefers-reduced-motion: reduce) {
    .chat-dock:not([hidden]) { animation: none; }
}
