/* ============================================================================
   BD INBOX, Messages.

   Jess's Harbour Carpentry reply queue, restyled 8 Sep 2026 to read the way the earlier
   panel did (~/claude-fleet/public/inbox-everse.css): a list of people on the
   left, a thread of bubbles on the right, and everything that is NOT a message
   the past jobs, the photo-upload link, Close, teach-me, behind an ⓘ.

   ⛔ THIS FILE REPLACES /ui/inbox.css ON THE HARBOUR CARPENTRY PAGE ONLY.
   The old shared skin (inbox.css + inbox.js) is left on disk untouched as the
   rollback: put the two <link>/<script> URLs back in run.py and the desk layout
   returns. Everse stopped loading the shared skin on 8 Sep, so nothing else
   reads it any more.

   ⛔ NOTHING IS RE-RENDERED. Every card below is still the one run.py wrote,
   with its draft box, send button, MMS thumbs, teach block and twelve wired
   endpoints. This stylesheet re-lays-out those exact nodes; bd-inbox.js only
   decides which card is on screen and tidies the history into runs. That is why
   it was safe to ship onto the tool Jess uses all day.

   ⛔ Every rule hangs off `body.bd-im`, which bd-inbox.js only adds once it has
   built the shell. Script fails to load → the page degrades to the old stacked
   list, never to a blank pane. Same fail-open as the skin it replaces.

   ⛔ Do not key anything off `#tab-messages`. The host is `.ib-host`.
   ⛔ Do not introduce an unprefixed class. run.py already owns .card .tab .tabs
   .search .name .label .active .done .in .out .primary .ghost .warn .copied
   .waiting .war-*, every new class here is `bd-`.
   ========================================================================== */

/* ── tokens ──────────────────────────────────────────────────────────────────
   Light and dark both ship, because the page has a working theme toggle and
   Jess uses it in daylight. The message-specific values live here; everything
   structural still reads run.py's --fg/--edge/--card tokens. */

body.bd-im {
  --bd-bar:      rgba(246,246,248,.82);
  --bd-pane:     #fff;
  --bd-pane2:    #f2f2f7;      /* the thread's paper, behind the bubbles */
  --bd-in:       #E9E9EB;      /* theirs */
  --bd-out:      #34C759;      /* ours, on SMS, iOS green */
  --bd-out-fg:   #fff;
  --bd-bot:      #F4F4F6;      /* the auto-reply, muted on purpose */
  --bd-sep:      rgba(60,60,67,.16);
  --bd-field:    #fff;
  --bd-sunk:     #EFEFF4;
  --bd-blue:     #007AFF;
  --bd-mute:     #8A8A8E;
  --bd-mute2:    #AEAEB2;
  --bd-red:      #FF3B30;      /* Urgent only, nothing else earns solid red */
  --bd-r:        18px;
  --bd-safe-b:   env(safe-area-inset-bottom, 0px);
}
html[data-theme=dark] body.bd-im {
  --bd-bar:      rgba(20,20,22,.78);
  --bd-pane:     #000;
  --bd-pane2:    #000;
  --bd-in:       #26252A;
  --bd-out:      #30D158;
  --bd-out-fg:   #fff;
  --bd-bot:      #1A1A1E;
  --bd-sep:      rgba(84,84,88,.42);
  --bd-field:    #1C1C1E;
  --bd-sunk:     #1C1C1E;
  --bd-blue:     #0B84FF;
  --bd-mute:     #98989F;
  --bd-mute2:    #636366;
  --bd-red:      #FF453A;      /* iOS dark-mode red, #FF3B30 vibrates on black */
}
/* Email is not a text message and should not look like one. Blue, like Messages
   uses for anything that is not SMS. */
body.bd-im .bd-thread.bd-email { --bd-out: var(--bd-blue); }

/* ── the frame ───────────────────────────────────────────────────────────────
   The whole app is exactly one screen tall and only the two inner panes scroll.
   run.py's body has padding-bottom:120px from the old long-page layout; leaving
   it on put the composer 120px below the fold. */

body.bd-im {
  height: 100dvh; overflow: hidden; padding-bottom: 0;
  overscroll-behavior: none;
}
body.bd-im .ib-app { display: flex; flex-direction: column; height: 100dvh; min-height: 0; }
body.bd-im .ib-body { flex: 1; min-height: 0; position: relative; }
body.bd-im .ib-body > .tab { position: absolute; inset: 0; overflow-y: auto; }
body.bd-im .ib-body > .tab[hidden] { display: none; }
/* The three non-message tabs keep their own look, they are lists of claims,
   photos and register rows, not conversations. They only need the gutter the
   old page's body padding used to give them. */
body.bd-im .ib-body > .tab:not(.ib-host) { padding: 16px 14px calc(40px + var(--bd-safe-b)); }
body.bd-im .ib-body > .tab:not(.ib-host) > * { max-width: 880px; margin-left: auto; margin-right: auto; }

/* ── top bar ─────────────────────────────────────────────────────────────────
   Dark in both themes: it sits under the black translucent iOS status bar and
   black + BD yellow is the brand. Unchanged intent from the old skin. */

body.bd-im .ib-top {
  flex: 0 0 auto; display: flex; align-items: center; gap: 10px;
  padding: calc(env(safe-area-inset-top) + 8px) 12px 8px;
  background: rgba(14,14,18,.92); color: #fff;
  border-bottom: .5px solid rgba(255,255,255,.10);
  overflow-x: auto; scrollbar-width: none;
}
body.bd-im .ib-top::-webkit-scrollbar { display: none; }
body.bd-im .ib-brand { display: flex; align-items: center; gap: 7px; flex: 0 0 auto; }
body.bd-im .ib-logo { height: 20px; width: auto; display: block; }
body.bd-im .ib-name { font-size: 13px; font-weight: 900; letter-spacing: -.2px; white-space: nowrap; }
body.bd-im .ib-spacer { flex: 1; }
body.bd-im .ib-stat { font-size: 11px; color: #9a9aa4; white-space: nowrap; flex: 0 0 auto; }
body.bd-im .ib-icon {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 50%;
  border: .5px solid rgba(255,255,255,.18); background: rgba(255,255,255,.10);
  color: var(--accent); cursor: pointer; font-family: inherit; font-size: 15px;
  display: flex; align-items: center; justify-content: center;
}
body.bd-im .ib-icon svg { display: block; width: 16px; height: 16px; }
body.bd-im .ib-icon:active { transform: scale(.92); }
body.bd-im .tabs { flex: 0 0 auto; padding-bottom: 0; margin: 0; }
/* On a phone the wordmark and four pills do not fit. The pills win, they are
   the navigation; the logo is decoration. */
@media (max-width: 560px) {
  body.bd-im .ib-name { display: none; }
  body.bd-im .ib-stat { display: none; }
}

/* ── the two panes ───────────────────────────────────────────────────────────
   Phone: one at a time, the thread comes in from the right.
   ⛔ The slide is an ANIMATION, not a transition, so no transform survives on
   the pane once it lands. A persistent transform makes the pane the containing
   block for `position:fixed`, and the ⓘ panel, which is a fixed overlay that
   lives INSIDE the card so `closest('.card')` still resolves for Close, would
   then be trapped inside it and mis-sized. */

/* ⛔ overflow:hidden, overriding the auto set on every .tab above. The message
   tab does not scroll, the list and the thread scroll independently inside it.
   Leaving it auto gave the whole host a second scrollbar and the sticky composer
   drifted with it. */
body.bd-im .ib-host { display: flex; overflow: hidden; background: var(--bd-pane); }
body.bd-im .bd-pane {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  background: var(--bd-pane); min-width: 0;
}
body.bd-im .bd-thread { z-index: 2; visibility: hidden; }
body.bd-im .ib-host.bd-open .bd-thread { visibility: visible; animation: bd-in .28s cubic-bezier(.32,.72,0,1); }
body.bd-im .ib-host.bd-open .bd-list { animation: bd-drift .28s cubic-bezier(.32,.72,0,1) both; }
@keyframes bd-in    { from { transform: translateX(100%); } }
@keyframes bd-drift { from { transform: translateX(0); } to { transform: translateX(-22%); } }

@media (min-width: 860px) {
  body.bd-im .bd-pane { position: relative; animation: none !important; transform: none !important; }
  body.bd-im .bd-list { flex: 0 0 336px; border-right: .5px solid var(--bd-sep); }
  body.bd-im .bd-thread { flex: 1; visibility: visible; }
  body.bd-im .bd-back { display: none !important; }
}

/* ── nav bars inside the panes ───────────────────────────────────────────── */

body.bd-im .bd-bar {
  position: relative; z-index: 3; flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px; min-height: 48px;
  padding: 8px 10px; background: var(--bd-bar);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: .5px solid var(--bd-sep); color: var(--fg);
}
body.bd-im .bd-bar-l, body.bd-im .bd-bar-r { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; min-width: 58px; }
body.bd-im .bd-bar-r { justify-content: flex-end; }
body.bd-im .bd-bar-c { flex: 1; min-width: 0; text-align: center; }
body.bd-im .bd-h { font-size: 16px; font-weight: 700; letter-spacing: -.01em; }
body.bd-im .bd-sub { display: block; font-size: 11.5px; color: var(--bd-mute); font-weight: 400; margin-top: 1px; }
body.bd-im .bd-back {
  display: inline-flex; align-items: center; gap: 1px; color: var(--bd-blue);
  font-size: 16px; background: none; border: 0; cursor: pointer; font-family: inherit;
  white-space: nowrap;
}
body.bd-im .bd-back .bd-chev { font-size: 25px; line-height: 1; margin-top: -2px; font-weight: 300; }
body.bd-im .bd-round {
  width: 31px; height: 31px; border-radius: 50%; flex: 0 0 31px;
  background: var(--bd-sunk); color: var(--fg); border: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 14px; font-family: inherit; font-weight: 600;
}
body.bd-im .bd-round:active { opacity: .6; }
body.bd-im .bd-round.bd-on { background: var(--accent); color: var(--ink); }

/* ── conversation list ───────────────────────────────────────────────────────
   .ib-rail is REUSED as the scroller on purpose: run.py's full-history search
   appends its #gsearch results panel to .ib-rail, so the 11k-conversation
   search still lands under the rows exactly where it used to. */

body.bd-im .ib-rail { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding-bottom: 8px; }
body.bd-im .bd-rows { display: block; }
body.bd-im .bd-row {
  position: relative; display: flex; align-items: flex-start; gap: 10px;
  width: 100%; padding: 9px 12px 9px 6px; text-align: left;
  background: none; border: 0; cursor: pointer; font-family: inherit; color: var(--fg);
}
body.bd-im .bd-row::after {
  content: ''; position: absolute; left: 72px; right: 0; bottom: 0;
  border-bottom: .5px solid var(--bd-sep);
}
body.bd-im .bd-row:last-child::after { border: 0; }
body.bd-im .bd-row:active { background: var(--bd-sunk); }
body.bd-im .bd-row.bd-sel { background: var(--bd-sunk); }
@media (min-width: 860px) {
  body.bd-im .bd-row.bd-sel { background: var(--accent); color: var(--ink); }
  body.bd-im .bd-row.bd-sel .bd-prev, body.bd-im .bd-row.bd-sel .bd-when { color: rgba(20,20,20,.66); }
  /* The tag colours are picked to read on the pane, not on BD yellow, "Mick"
     went pale blue on yellow and vanished, which is the one tag that must not. */
  body.bd-im .bd-row.bd-sel .bd-tag { background: rgba(255,255,255,.92); }
}
body.bd-im .bd-dot {
  flex: 0 0 9px; width: 9px; height: 9px; border-radius: 50%;
  background: var(--bd-blue); align-self: center; margin-left: 2px; visibility: hidden;
}
body.bd-im .bd-row.bd-unread .bd-dot { visibility: visible; }
body.bd-im .bd-av {
  flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 600; color: #fff; letter-spacing: .01em;
}
body.bd-im .bd-body { flex: 1; min-width: 0; padding-top: 1px; }
body.bd-im .bd-l1 { display: flex; align-items: baseline; gap: 6px; }
body.bd-im .bd-nm {
  flex: 1; font-size: 15.5px; font-weight: 600; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.bd-im .bd-row.bd-unread .bd-nm { font-weight: 700; }
body.bd-im .bd-when { flex: 0 0 auto; font-size: 13px; color: var(--bd-mute); }
body.bd-im .bd-prev {
  margin-top: 1px; font-size: 14px; line-height: 1.28; color: var(--bd-mute);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
body.bd-im .bd-row.bd-done { opacity: .5; }
body.bd-im .bd-tag {
  display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
  padding: 1px 6px; border-radius: 9px; margin-right: 5px; vertical-align: 1px;
}
/* Solid red, not a tint, Urgent has to out-shout Site, which is already red. */
body.bd-im .bd-tag.bd-urg  { background: var(--bd-red, #FF3B30); color: #fff; }
body.bd-im .bd-row.bd-sel .bd-tag.bd-urg { background: var(--bd-red, #FF3B30); color: #fff; }
/* Rush is amber, not red. Urgent is a problem, rush is a promise we have kept,
   so it must not compete with the thing that needs attention. */
body.bd-im .bd-tag.bd-rush { background: #FF9500; color: #fff; }
body.bd-im .bd-row.bd-sel .bd-tag.bd-rush { background: #FF9500; color: #fff; }
body.bd-im .bd-tag.bd-site { background: var(--bad-bg); color: var(--bad-fg); }
body.bd-im .bd-tag.bd-esc  { background: var(--info-bg); color: var(--info-fg); }
body.bd-im .bd-tag.bd-warn { background: var(--warn-bg); color: var(--warn-fg); }
body.bd-im .bd-tag.bd-ok   { background: var(--ok-bg); color: var(--ok-fg); }
body.bd-im .bd-none { padding: 54px 24px; text-align: center; color: var(--bd-mute); font-size: 14.5px; }

/* The the old system reconciliation line (see bd-inbox.js renderList). Sits above the
   first row, reads as a note rather than a conversation, and is deliberately not
   tappable, there is nothing to open, it is an answer. */
body.bd-im .bd-note {
  display: block; padding: 10px 14px; border-bottom: 1px solid var(--bd-sep);
  background: var(--info-bg); color: var(--info-fg); line-height: 1.35;
}
body.bd-im .bd-note b    { display: block; font-size: 13.5px; font-weight: 650; }
body.bd-im .bd-note span { display: block; font-size: 12.5px; opacity: .85; margin-top: 2px; }

/* search + refresh, at the bottom the way iOS puts it */
body.bd-im .bd-foot {
  flex: 0 0 auto; display: flex; align-items: center; gap: 9px;
  padding: 8px 11px calc(8px + var(--bd-safe-b));
  background: var(--bd-bar); border-top: .5px solid var(--bd-sep);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}
body.bd-im .bd-srch {
  flex: 1; display: flex; align-items: center; gap: 7px; min-width: 0;
  background: var(--bd-sunk); border-radius: 18px; padding: 7px 12px;
}
body.bd-im .bd-srch input {
  flex: 1; min-width: 0; background: none; border: 0; outline: none;
  font-size: 16px; font-family: inherit; color: var(--fg);
}
body.bd-im .bd-srch input::placeholder { color: var(--bd-mute); }
body.bd-im .bd-srch svg { flex: 0 0 15px; fill: var(--bd-mute); }

/* full-history results, still rendered by run.py into .ib-rail */
body.bd-im #gsearch { border-top: .5px solid var(--bd-sep); margin-top: 6px; padding-bottom: 8px; }
body.bd-im .gs-head {
  font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  color: var(--bd-mute); padding: 12px 14px 6px;
}
body.bd-im .gs-none { padding: 4px 14px 12px; font-size: 13px; color: var(--bd-mute); }
body.bd-im .gs-row {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  border-bottom: .5px solid var(--bd-sep); padding: 9px 14px; cursor: pointer;
  font-family: inherit; color: var(--fg);
}
body.bd-im .gs-row:active { background: var(--bd-sunk); }
body.bd-im .gs-name { display: block; font-size: 14.5px; font-weight: 600; }
body.bd-im .gs-meta { display: block; font-size: 12px; color: var(--bd-mute); margin-top: 1px; }

/* ── the thread ──────────────────────────────────────────────────────────────
   #ib-main is the scroller and the cards live inside it, inside their group
   wrappers. ⛔ The real chain is .ib-main > section.group > .group-body > .card,
   so nothing here uses a `>` combinator from .ib-main, that was the rule that
   silently ate the full-height card on 7 Sep. Only the open card displays, so
   no flex height has to be threaded through the wrappers at all. */

body.bd-im .ib-main {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  background: var(--bd-pane2); padding: 0;
}
body.bd-im .ib-main .ib-back,
body.bd-im .ib-main .group-title,
body.bd-im .ib-main .all-done { display: none; }
body.bd-im .ib-main .group { margin: 0; }
body.bd-im .ib-main .group.collapsed .group-body { display: block; }
body.bd-im .ib-main .card { display: none; }
/* ⛔ The composer has to sit on the BOTTOM of the pane even when there are only
   two messages, and `min-height:100%` cannot do it: percentage heights resolve
   against .group-body, which has no height of its own, so it silently becomes
   auto and the composer floated halfway up a black screen. The height is threaded
   down the real chain instead, .ib-main > section.group > .group-body > .card >
   .card-body, matched with :has() rather than `>` so it does not depend on that
   nesting staying exactly as it is. */
body.bd-im .ib-main { display: flex; flex-direction: column; }
body.bd-im .ib-main .group:has(.card.ib-open),
body.bd-im .ib-main .group-body:has(.card.ib-open) {
  flex: 1 0 auto; display: flex; flex-direction: column;
}
body.bd-im .ib-main .card.ib-open {
  flex: 1 0 auto; display: flex; flex-direction: column;
  margin: 0; border: 0; border-radius: 0; box-shadow: none;
  background: transparent; overflow: visible;
}
/* A ticked-off card still has to be readable, run.py hides .card-body on
   .done, which in a one-card-per-screen layout leaves a blank pane. */
body.bd-im .ib-main .card.ib-open.done { opacity: 1; }
body.bd-im .ib-main .card.ib-open.done .card-body { display: flex; }
/* ⛔ Only on a card that IS done. run.py shows this strip off the .done class;
   forcing it on every open card put a green "✓ undo" banner above a live
   conversation that had not been ticked off at all. */
body.bd-im .ib-main .card.ib-open.done .done-strip {
  display: flex; position: sticky; top: 0; z-index: 4; border-bottom: .5px solid var(--ok-edge);
}
/* ⛔ 1 0 auto all the way down, never 1 1 auto: the thread has to FILL a short
   pane but must keep its natural height on a long one. Allowing shrink squashed
   a 40-message thread and the sticky composer rode up over the last bubble. */
body.bd-im .ib-main .card.ib-open .card-body {
  flex: 1 0 auto; display: flex; flex-direction: column;
}
body.bd-im .bd-empty { padding: 60px 24px; text-align: center; color: var(--bd-mute); font-size: 15px; }

/* order inside the thread: what was said, then the photos, then the composer */
body.bd-im .ib-main .card.ib-open .site-banner  { order: 0; }
/* Short, real "why did this move" lines, run.py-generated. Sit with the site
   banner at the top of the thread, above the messages, never mixed into the
   bubbles themselves. */
body.bd-im .ib-main .card.ib-open .bd-sys       { order: 0.5; }
body.bd-im .ib-main .card.ib-open .customer-msg { order: 1; flex: 1 0 auto; }
body.bd-im .ib-main .card.ib-open .mms-row      { order: 2; }
body.bd-im .ib-main .card.ib-open .photo-got    { order: 3; }
/* ⛔ order 4, immediately above the composer. "Needs Mick" and "Check me" are
   the only two things on this page that must be read BEFORE a send, so they are
   the last thing between the thread and the draft, never behind the ⓘ. */
body.bd-im .ib-main .card.ib-open .bd-flag      { order: 4; }
/* The order, and its the workshop and rush buttons, sit between the warning and the draft.
   Same order value as .bd-flag so DOM order decides, which puts it under the flag. */
body.bd-im .ib-main .card.ib-open .bd-orderbar  { order: 4; flex: 0 0 auto; }
body.bd-im .ib-main .card.ib-open .reply-block  { order: 5; }
/* "Teach me a better answer" sits directly under the draft it is correcting. */
body.bd-im .ib-main .card.ib-open .feedback-block { order: 6; flex: 0 0 auto; }
body.bd-im .ib-main .card.ib-open .bd-info      { order: 7; }

body.bd-im .ib-main .card.ib-open .feedback-block {
  margin: 0 12px 10px; padding: 0;
  border: 0; background: none;
}
body.bd-im .ib-main .card.ib-open .feedback-toggle { font-size: 13px; }

body.bd-im .ib-main .bd-flag {
  flex: 0 0 auto; margin: 10px 12px 0; padding: 9px 13px; border-radius: 12px;
  background: var(--warn-bg); color: var(--warn-fg);
  border: .5px solid var(--warn-edge); font-size: 13.5px; font-weight: 600; line-height: 1.45;
}

/* Automated status-change lines, e.g. "Status set to Mick because...".
   Deliberately quieter than .bd-flag, this is a log line not a warning. */
body.bd-im .ib-main .bd-sys {
  flex: 0 0 auto; margin: 8px 12px 0; padding: 7px 12px; border-radius: 10px;
  background: var(--bd-bot); color: var(--bd-mute);
  border: .5px dashed var(--bd-sep); font-size: 12.5px; line-height: 1.4;
}
body.bd-im .ib-main .bd-sys + .bd-sys { margin-top: 4px; }

/* The pill on the draft box's label, surfacing that this is an AI-written
   suggestion, not building a second draft box, this labels the one that has
   always been there. */
.bd-ai-pill {
  display: inline-flex; align-items: center; gap: 4px; margin-right: 8px;
  padding: 2px 8px; border-radius: 999px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase;
  background: rgba(11,132,255,.14); color: #0B84FF; border: 1px solid rgba(11,132,255,.35);
}

/* ── bubbles ─────────────────────────────────────────────────────────────────
   These are run.py's own .hist-bubble nodes. bd-inbox.js only groups them into
   runs, lifts each timestamp out to the end of its run and drops in a day
   separator, no bubble is re-created, so nothing that reads the card's text
   (search index, sendReply's `who`) changes. */

body.bd-im .ib-main .customer-msg {
  background: transparent; border: 0; padding: 8px 12px 4px;
  display: flex; flex-direction: column;
}
body.bd-im .ib-main .customer-msg > .label { display: none; }
/* The headline message is the last bubble as well. One of them has to go. */
body.bd-im .ib-main .customer-msg:has(.hist) > p { display: none; }
/* No history (a first-contact conversation): the message IS the thread. */
body.bd-im .ib-main .customer-msg > p {
  max-width: 74%; width: fit-content; margin: 6px auto 6px 0; padding: 8px 13px 9px;
  border-radius: var(--bd-r); background: var(--bd-in); color: var(--fg);
  font-size: 16px; line-height: 1.31; max-height: none; overflow: visible;
  overflow-wrap: anywhere;
}
body.bd-im .ib-main .hist { margin: 0; }
body.bd-im .ib-main .hist > summary { display: none; }
body.bd-im .ib-main .hist-body {
  margin: 0; padding: 0; max-height: none; overflow: visible;
  background: none; border: 0; border-radius: 0; gap: 0;
}
body.bd-im .ib-main .hist-more {
  text-align: center; font-size: 12px; color: var(--bd-mute); margin: 6px 0 12px;
}
body.bd-im .ib-main .hist-bubble {
  position: relative; max-width: 74%; width: fit-content; margin: 2px 0;
  padding: 8px 13px 9px; border-radius: var(--bd-r);
  font-size: 16px; line-height: 1.31; border: 0;
  overflow-wrap: anywhere; word-break: normal;
}
body.bd-im .ib-main .hist-bubble.in  { align-self: flex-start; background: var(--bd-in);  color: var(--fg); }
body.bd-im .ib-main .hist-bubble.out { align-self: flex-end;   background: var(--bd-out); color: var(--bd-out-fg); }
body.bd-im .ib-main .hist-bubble.bot {
  align-self: flex-end; background: var(--bd-bot); color: var(--bd-mute);
  border: .5px dashed var(--bd-sep); font-size: 14.5px;
}
body.bd-im .ib-main .hist-bubble.bd-run { margin-top: 10px; }
/* The tail, only on the last bubble of a run, same as Messages. */
body.bd-im .ib-main .hist-bubble.bd-tail::before {
  content: ''; position: absolute; bottom: 0; width: 14px; height: 17px;
}
body.bd-im .ib-main .hist-bubble.in.bd-tail::before {
  left: -6px; background: var(--bd-in); border-bottom-right-radius: 15px;
  -webkit-mask: radial-gradient(circle at 0 0, transparent 14px, #000 14.5px);
  mask: radial-gradient(circle at 0 0, transparent 14px, #000 14.5px);
}
body.bd-im .ib-main .hist-bubble.out.bd-tail::before {
  right: -6px; background: var(--bd-out); border-bottom-left-radius: 15px;
  -webkit-mask: radial-gradient(circle at 100% 0, transparent 14px, #000 14.5px);
  mask: radial-gradient(circle at 100% 0, transparent 14px, #000 14.5px);
}
/* run.py writes a .hist-meta inside every bubble. In a thread that is noise on
   every line, so the script empties it and writes one stamp per run instead. */
body.bd-im .ib-main .hist-meta { display: none; }
body.bd-im .ib-main .hist-bubble.bot .hist-meta {
  display: block; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--bd-mute2); margin-bottom: 3px;
}
body.bd-im .bd-day {
  align-self: center; text-align: center; font-size: 12px; color: var(--bd-mute);
  margin: 16px 0 8px;
}
body.bd-im .bd-day b { font-weight: 700; }
body.bd-im .bd-stamp { font-size: 11px; color: var(--bd-mute); margin: 3px 4px 2px; }
body.bd-im .bd-stamp.bd-r { align-self: flex-end; }
body.bd-im .bd-stamp.bd-l { align-self: flex-start; }

/* photos: the picture is the bubble */
body.bd-im .ib-main .mms-row { padding: 4px 12px 0; }
body.bd-im .ib-main .mms-title { font-size: 11.5px; color: var(--bd-mute); margin-bottom: 6px; }
body.bd-im .ib-main .mms-thumbs { gap: 6px; }
body.bd-im .ib-main .mms-thumb {
  width: 104px; height: 104px; border-radius: 14px; border: .5px solid var(--bd-sep);
}
body.bd-im .ib-main .photo-got { padding: 8px 12px 0; }
body.bd-im .ib-main .photo-got:not(:empty) { padding: 8px 12px 0; }

/* the website-problem banner keeps its shout, just fitted to the thread */
body.bd-im .ib-main .site-banner { margin: 8px 12px 0; border-radius: 12px; }

/* ── composer ────────────────────────────────────────────────────────────────
   The draft box and the Send button are run.py's own nodes, same ids, same
   onclick, same /send call with its shownHash. Send stays a labelled pill and
   not a round arrow because sendReply() rewrites its text to "Sending…" and
   "Sent", and that state has to stay readable. */

body.bd-im .ib-main .card.ib-open .reply-block {
  position: sticky; bottom: 0; z-index: 5; flex: 0 0 auto;
  padding: 7px 10px calc(7px + var(--bd-safe-b));
  background: var(--bd-bar); border-top: .5px solid var(--bd-sep);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap;
}
body.bd-im .ib-main .reply-block > .label {
  flex: 1 0 100%; font-size: 10.5px; color: var(--bd-mute); margin: 0 0 5px 4px;
}
/* ⛔ `flex: 1` was not enough. .reply-actions is `flex: 0 0 auto` and holds BOTH
   Send and the saved-replies <select>, which is ~200px wide, so on a phone the
   two of them took the row and the box she actually types the customer's reply
   into collapsed to a ~150px sliver. Full width on its own line, actions under
   it. Seen 14 Sep 2026 on a 390px viewport. */
body.bd-im .ib-main .reply-edit {
  flex: 1 1 100%; min-width: 0; width: auto; margin: 0;
  background: var(--bd-field); border: .5px solid var(--bd-sep); border-radius: 18px;
  padding: 8px 14px; font-size: 16px; line-height: 1.32; resize: none;
  max-height: 168px; overflow-y: auto;
}
body.bd-im .ib-main .reply-edit:focus { border-color: var(--bd-blue); box-shadow: none; }
body.bd-im .ib-main .reply-actions {
  flex: 1 1 100%; margin: 6px 0 0; display: flex; gap: 8px; align-items: center;
  justify-content: flex-start;
}
body.bd-im .ib-main .reply-actions .snip { flex: 1 1 auto; min-width: 0; }
body.bd-im .ib-main .btn.send {
  background: var(--bd-out); color: var(--bd-out-fg); border-radius: 17px;
  padding: 9px 17px; font-size: 14px;
}
body.bd-im .ib-main .btn.send:disabled { opacity: .55; }
body.bd-im .ib-main .btn.send.sent { background: var(--bd-mute2); }
/* Awaiting the customer: there is no draft, so there is no composer either. */
body.bd-im .ib-main .reply-block.awaiting {
  background: var(--bd-bar); border-top: .5px solid var(--bd-sep); display: block; text-align: center;
}
body.bd-im .ib-main .awaiting-text { font-size: 13px; }

/* ── the ⓘ panel ─────────────────────────────────────────────────────────────
   Everything that is not a message: the job list orders, the photo-upload link, the
   phone number, Close and teach-me.

   ⛔ It is a child of the CARD, not of the body. closeSpam() and sendReply()
   both do btn.closest('.card') and read .name out of the header, so the header
   has to stay inside the card. position:fixed lifts it visually without moving
   it in the DOM, which is also why the pane slide is an animation, not a
   lingering transform. */

body.bd-im .bd-veil {
  position: fixed; inset: 0; z-index: 55; background: rgba(0,0,0,.42);
  display: none; opacity: 0; transition: opacity .18s;
}
body.bd-im.bd-info-open .bd-veil { display: block; opacity: 1; }
/* ⛔ On desktop the panel is a side column, not a modal sheet, so dimming the
   thread behind it is wrong, Jess reads the conversation and the order
   details together. The veil stays (tap outside still closes) but goes clear.
   The phone keeps the dim, where the panel really does cover the screen. */
@media (min-width: 860px) {
  body.bd-im.bd-info-open .bd-veil { background: transparent; }
  /* and the thread gives up the width instead of being covered by it */
  body.bd-im.bd-info-open .bd-thread { padding-right: 380px; }
}
body.bd-im .ib-main .card .bd-info { display: none; }
body.bd-im.bd-info-open .ib-main .card.ib-open .bd-info {
  display: block; position: fixed; z-index: 60;
  left: 0; right: 0; bottom: 0; top: auto; max-height: 86dvh; overflow-y: auto;
  background: var(--bd-pane); color: var(--fg);
  border-radius: 16px 16px 0 0; border-top: .5px solid var(--bd-sep);
  box-shadow: 0 -12px 40px -12px rgba(0,0,0,.45);
  padding-bottom: calc(18px + var(--bd-safe-b));
  animation: bd-rise .24s cubic-bezier(.32,.72,0,1);
}
@keyframes bd-rise { from { transform: translateY(22px); opacity: .5; } }
@media (min-width: 860px) {
  body.bd-im.bd-info-open .ib-main .card.ib-open .bd-info {
    left: auto; right: 0; top: 0; bottom: 0; width: 380px; max-height: none;
    border-radius: 0; border-top: 0; border-left: .5px solid var(--bd-sep);
    animation: bd-slide .24s cubic-bezier(.32,.72,0,1);
  }
  @keyframes bd-slide { from { transform: translateX(24px); opacity: .4; } }
}
body.bd-im .bd-grab {
  width: 36px; height: 5px; border-radius: 3px; background: var(--bd-sep);
  margin: 8px auto 2px;
}
@media (min-width: 860px) { body.bd-im .bd-grab { display: none; } }
body.bd-im .bd-info-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 16px 8px; border-bottom: .5px solid var(--bd-sep);
  position: sticky; top: 0; background: var(--bd-pane); z-index: 2;
}
body.bd-im .bd-info-head .bd-h { font-size: 17px; }
body.bd-im .bd-x { color: var(--bd-blue); font-size: 16px; background: none; border: 0; cursor: pointer; font-family: inherit; }

/* the card's own header, relocated into the panel */
body.bd-im .bd-info .card-header {
  border-bottom: .5px solid var(--bd-sep); padding: 12px 16px; gap: 10px;
}
body.bd-im .bd-info .card-left { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
body.bd-im .bd-info .photo-row { padding: 12px 16px; border-bottom: .5px solid var(--bd-sep); }
body.bd-im .bd-info .feedback-block { padding: 12px 16px 4px; }
body.bd-im .bd-info .photo-got { padding: 0 16px 12px; }
body.bd-im .bd-actions { display: flex; gap: 8px; flex-wrap: wrap; padding: 12px 16px; }
body.bd-im .bd-actions .btn { flex: 0 0 auto; }

/* ── triage row: Mark done · Close · Ask the boss ───────────────────────────────
   In the thread, under the draft, where she can see it. ⛔ Do not move these
   back behind the ⓘ: that is exactly how "there is no close button" happened.
   Deliberately NOT next to Send, Close is destructive-ish and a mis-tap next
   to the send button is the one mistake that costs a customer. */
/* ⛔ order:0 is deliberate, .card-body is an ordered flex column (see the order
   block above) and this pins the row to the TOP of the thread, under the bar and
   nowhere near Send. */
body.bd-im .bd-triage {
  order: 0;
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  padding: 10px 16px;
  border-bottom: .5px solid var(--bd-sep); background: var(--bd-bar);
}
body.bd-im .bd-triage .btn { flex: 0 0 auto; }
body.bd-im .bd-triage .ask-row { flex: 1 1 200px; min-width: 0; }
body.bd-im .bd-triage .ask-row input {
  width: 100%; box-sizing: border-box; background: var(--field, rgba(255,255,255,.06));
  border: .5px solid var(--bd-sep); border-radius: 11px; color: inherit;
  padding: 8px 12px; font-size: 13px; font-family: inherit;
}

/* the the job list panel, same markup the shared skin rendered, same guard */
body.bd-im .bd-cust { padding: 2px 0 6px; }
body.bd-im .ib-sec { padding: 10px 16px 12px; border-bottom: .5px solid var(--bd-sep); }
body.bd-im .ib-label {
  display: block; font-size: 10.5px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .06em; color: var(--bd-mute); margin-bottom: 6px;
}
body.bd-im .ib-field { margin-bottom: 8px; }
body.bd-im .ib-field .ib-label { margin-bottom: 3px; }
body.bd-im .ib-copyrow {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; background: var(--bd-sunk); border: 0; border-radius: 10px;
  padding: 8px 11px; font-family: inherit; font-size: 14px; color: var(--fg);
  cursor: pointer; text-align: left;
}
body.bd-im .ib-copyrow .v { overflow-wrap: anywhere; }
body.bd-im .ib-copyrow .c { flex: 0 0 auto; font-size: 11.5px; color: var(--bd-blue); }
body.bd-im .ib-copyrow.copied { background: var(--ok-bg); }
body.bd-im .ib-copyrow.copied .c { color: var(--ok-fg); }
body.bd-im .ib-muted { font-size: 13px; color: var(--bd-mute); line-height: 1.5; }
body.bd-im .ib-link { color: var(--bd-blue); text-decoration: none; font-size: 14px; }
body.bd-im .ib-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
body.bd-im .ib-chip {
  font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 9px;
  background: var(--chip); color: var(--chip-fg);
}
body.bd-im .ib-order {
  background: var(--bd-sunk); border-radius: 13px; padding: 11px 13px; margin-bottom: 9px;
}
body.bd-im .ib-order-top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
body.bd-im .ib-order-no { font-size: 14.5px; font-weight: 700; }
body.bd-im .ib-order-when { font-size: 12px; color: var(--bd-mute); }
body.bd-im .ib-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
body.bd-im .ib-pill {
  font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 9px;
  background: var(--chip); color: var(--chip-fg);
}
body.bd-im .ib-pill.ok   { background: var(--ok-bg);   color: var(--ok-fg); }
body.bd-im .ib-pill.warn { background: var(--warn-bg); color: var(--warn-fg); }
body.bd-im .ib-pill.bad  { background: var(--bad-bg);  color: var(--bad-fg); }
body.bd-im .ib-pill.info { background: var(--info-bg); color: var(--info-fg); }
body.bd-im .ib-order-build {
  margin-top: 8px; font-size: 13px; color: var(--fg2); line-height: 1.45;
  border-left: 2px solid var(--bd-sep); padding-left: 9px;
}
body.bd-im .ib-order-build.rush { border-left-color: var(--accent-dim); color: var(--fg); font-weight: 600; }
body.bd-im .ib-build-btn {
  margin-top: 8px; background: var(--cta-bg); color: var(--cta-fg); border: 0;
  border-radius: 11px; padding: 7px 13px; font-size: 12.5px; font-weight: 700;
  font-family: inherit; cursor: pointer;
}
body.bd-im .ib-build-btn:disabled { opacity: .55; }
/* Amber, and it sits under the the workshop button rather than beside it: rushing is the
   bigger commitment of the two, so it gets its own line and cannot be hit by accident. */
body.bd-im .ib-rush-btn { display: block; width: 100%; background: #FF9500; color: #fff; }
body.bd-im .ib-rush-on {
  margin-top: 8px; padding: 7px 11px; border-radius: 11px;
  background: rgba(255,149,0,.15); color: #C86A00;
  font-size: 12.5px; font-weight: 700;
}
body.bd-im .ib-order-items { margin-top: 8px; font-size: 13px; color: var(--fg2); line-height: 1.45; }
body.bd-im .ib-order-track { margin-top: 9px; }
/* ⛔ The ownership guard. The instruction, and NOTHING else, no order number,
   no items, no tracking. Never soften this into a banner over visible details. */
body.bd-im .ib-order-guard {
  background: var(--bad-bg); color: var(--bad-fg); border: .5px solid var(--bad-edge);
  border-radius: 12px; padding: 11px 13px; font-size: 13.5px; line-height: 1.5;
}

/* ── the filter sheet ────────────────────────────────────────────────────── */

body.bd-im .bd-sheet {
  position: fixed; inset: 0; z-index: 70; display: none;
  align-items: flex-end; justify-content: center; background: rgba(0,0,0,.42);
}
body.bd-im .bd-sheet.bd-on { display: flex; }
body.bd-im .bd-sheet-in {
  width: 100%; max-width: 460px; margin: 0 8px calc(8px + var(--bd-safe-b));
  background: var(--bd-pane); border-radius: 14px; overflow: hidden;
  border: .5px solid var(--bd-sep); animation: bd-rise .22s cubic-bezier(.32,.72,0,1);
}
body.bd-im .bd-sheet-h {
  padding: 12px 16px; font-size: 12.5px; color: var(--bd-mute); text-align: center;
  border-bottom: .5px solid var(--bd-sep);
}
body.bd-im .bd-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 14px 16px; font-size: 16.5px; text-align: left;
  border: 0; border-bottom: .5px solid var(--bd-sep); background: none;
  font-family: inherit; color: var(--fg); cursor: pointer;
}
body.bd-im .bd-opt:last-child { border-bottom: 0; }
body.bd-im .bd-opt:active { background: var(--bd-sunk); }
body.bd-im .bd-opt .bd-n { color: var(--bd-mute); font-size: 14.5px; }
body.bd-im .bd-opt.bd-on { color: var(--bd-blue); font-weight: 700; }

/* ── filter tabs ─────────────────────────────────────────────────────────────
   the old system puts its filters on the list, not behind a button, and so do we. The
   row scrolls sideways rather than wrapping, so adding a filter never pushes
   the conversations down the page. */
/* Open/Closed: a top-level split above the granular tabs, the old system's shape. */
body.bd-im .bd-octabs {
  position: relative; z-index: 3; flex: 0 0 auto;
  display: flex; gap: 6px; padding: 8px 10px 0; background: var(--bd-bar);
}
body.bd-im .bd-oc {
  flex: 1 1 0; padding: 7px 0; border: 0; border-radius: 10px;
  background: var(--bd-sunk); color: var(--bd-mute);
  font-family: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
body.bd-im .bd-oc.bd-on { background: var(--bd-blue); color: #fff; }

/* Sort + Filters popovers, anchored under the header's round buttons. */
body.bd-im .bd-sortmenu, body.bd-im .bd-filtmenu {
  position: absolute; top: 48px; right: 8px; z-index: 20;
  background: var(--bd-solid, #fff); border: .5px solid var(--bd-sep);
  border-radius: 14px; box-shadow: 0 12px 30px rgba(0,0,0,.22);
  padding: 6px; min-width: 190px;
}
body.bd-im .bd-sortmenu button {
  display: block; width: 100%; text-align: left; padding: 9px 12px; border: 0;
  background: none; border-radius: 9px; font-family: inherit; font-size: 13.5px;
  font-weight: 600; color: var(--fg); cursor: pointer;
}
body.bd-im .bd-sortmenu button.bd-on, body.bd-im .bd-sortmenu button:hover { background: var(--bd-sunk); }
body.bd-im .bd-filtmenu { max-width: 260px; max-height: 70vh; overflow-y: auto; }
body.bd-im .bd-filtgrp { padding: 6px 6px 8px; border-bottom: .5px solid var(--bd-sep); }
body.bd-im .bd-filtgrp:last-child { border-bottom: 0; }
body.bd-im .bd-filtgrp b {
  display: block; font-size: 10.5px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; color: var(--bd-mute); margin: 4px 6px 6px;
}
body.bd-im .bd-filtgrp button {
  display: inline-block; margin: 2px 4px 0 0; padding: 6px 11px; border: 0;
  border-radius: 999px; background: var(--bd-sunk); color: var(--fg);
  font-family: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
body.bd-im .bd-filtnone {
  display: block; margin: 0 6px; font-size: 12px; color: var(--bd-mute); line-height: 1.4;
}
body.bd-im .bd-tabs {
  position: relative; z-index: 3; flex: 0 0 auto;
  display: flex; align-items: center; gap: 6px;
  padding: 7px 10px; background: var(--bd-bar);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: .5px solid var(--bd-sep);
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
body.bd-im .bd-tabs::-webkit-scrollbar { display: none; }
body.bd-im .bd-tab {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  padding: 6px 12px; border: 0; border-radius: 999px;
  background: var(--bd-sunk); color: var(--fg);
  font-family: inherit; font-size: 13.5px; font-weight: 600; line-height: 1;
  white-space: nowrap; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
body.bd-im .bd-tab:active { opacity: .6; }
body.bd-im .bd-tab .bd-n {
  font-size: 12px; font-weight: 700; color: var(--bd-mute);
  min-width: 14px; text-align: center;
}
body.bd-im .bd-tab.bd-empty { opacity: .55; }
/* `hot` = a filter that matters the moment it is non-empty (Urgent). */
body.bd-im .bd-tab.bd-hot { background: var(--bd-red, #FF3B30); color: #fff; }
body.bd-im .bd-tab.bd-hot .bd-n { color: rgba(255,255,255,.85); }
body.bd-im .bd-tab.bd-on { background: var(--bd-blue); color: #fff; }
body.bd-im .bd-tab.bd-on .bd-n { color: rgba(255,255,255,.85); }

/* ── wide screens ────────────────────────────────────────────────────────────
   Last on purpose: these override padding set further up and a media query adds
   no specificity, so anywhere earlier the later rule would win. */

@media (min-width: 860px) {
  body.bd-im .ib-main .customer-msg,
  body.bd-im .ib-main .mms-row,
  body.bd-im .ib-main .photo-got {
    padding-left:  max(14px, calc((100% - 720px) / 2));
    padding-right: max(14px, calc((100% - 720px) / 2));
  }
  /* the flag is a box, so it takes the inset as MARGIN, padding would stretch
     its background the full width of the pane */
  body.bd-im .ib-main .bd-flag {
    margin-left:  max(14px, calc((100% - 720px) / 2));
    margin-right: max(14px, calc((100% - 720px) / 2));
  }
  body.bd-im .ib-main .card.ib-open .reply-block {
    padding-left:  max(12px, calc((100% - 720px) / 2));
    padding-right: max(12px, calc((100% - 720px) / 2));
  }
}

/* ── The order, in the thread ────────────────────────────────────────────────
   Sits between the warning flag and the draft. Quiet card, not a second header:
   it must be reachable at a glance without competing with the customer's words. */
body.bd-im .ib-main .card.ib-open .bd-orderbar {
  margin: 4px 12px 8px; padding: 10px 12px;
  background: var(--bd-sunk); border-radius: 14px;
}
body.bd-im .ib-main .card.ib-open .bd-orderbar .ib-sec { margin: 0; }
body.bd-im .ib-main .card.ib-open .bd-orderbar .ib-label {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase; opacity: .55;
}

/* ── Order chips in the conversation header ──────────────────────────────────
   The customer's order, one tap from the job list, without taking a pixel from the
   thread. See renderOrderChips() for why it lives here and not in the thread. */
body.bd-im .bd-ochips {
  display: flex; flex-wrap: nowrap; justify-content: safe center; gap: 6px;
  margin-top: 5px; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
body.bd-im .bd-ochips::-webkit-scrollbar { display: none; }
body.bd-im .bd-ochip {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 3px;
  padding: 3px 10px; border-radius: 999px; border: 0; cursor: pointer;
  font-family: inherit; font-size: 11.5px; font-weight: 500; line-height: 1.5;
  white-space: nowrap; text-decoration: none;
  background: var(--bd-sunk); color: var(--fg);
}
body.bd-im a.bd-ochip b { color: var(--bd-blue); font-weight: 700; }
body.bd-im .bd-ochip.rush { background: #ffedc2; color: #6b4300; }
body.bd-im .bd-ochip.rush b { color: #6b4300; }
body.bd-im .bd-ochip-more { color: var(--bd-mute); }
body.bd-im .bd-ochip:active { opacity: .6; }
body.bd-im .ib-order-nolink { color: var(--bd-blue); text-decoration: none; }
body.bd-im .ib-order-nolink:hover { text-decoration: underline; }

/* ---- Phone: recents, keypad, voicemail, call sheet. Drawn only once the
   business number exists. Tokens only, so dark mode is free. ---- */
body.bd-im .bd-ochip-call { color: #1a7f37; background: #e3f7e8; font-weight: 600; }
html[data-theme=dark] body.bd-im .bd-ochip-call { color: #30D158; background: rgba(48,209,88,.16); }
/* Desktop has the Call button in the top bar, so no floating one over the search box. */
@media (min-width: 561px) { body.bd-has-dialbtn .bd-dial-fab { display: none; } }
@media (max-width: 560px) { #dial-btn { display: none; } body.bd-im .bd-dial-fab { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); left: auto; right: 16px; } }
@media (max-width: 560px) {
  body.bd-im .bd-ochips .bd-ochip-more:not(:only-child) { display: none; }
  body.bd-im:has(.bd-open) .bd-dial-fab { display: none; }
  /* The tab has its own keypad; the floating button would sit on the bottom bar. */
  body.bd-im:has(#tab-phone:not([hidden])) .bd-dial-fab { display: none; }
}
.bd-dial-fab {
  position: fixed; left: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); z-index: 60;
  width: 48px; height: 48px; border-radius: 50%; border: 0; cursor: pointer;
  background: #34c759; color: #fff; font-size: 20px; line-height: 1;
  box-shadow: 0 6px 18px rgba(0,0,0,.22);
}
body.bd-im #tabn-phone.bd-ph-badge-red { background: var(--bd-red); color: #fff; }

/* -- frame -- */
body.bd-im .ib-body > #tab-phone { padding: 0; }
body.bd-im .ib-body > #tab-phone > * { max-width: none; }
body.bd-im .ib-body > #tab-phone > #ph-status { padding: 24px; }
body.bd-im .bd-ph {
  display: grid; grid-template-columns: minmax(360px, 440px) 1fr; grid-template-rows: minmax(0, 1fr); gap: 0;
  height: calc(100vh - 58px); min-height: 520px; overflow: hidden; background: var(--bd-pane);
  font-family: inherit; color: var(--fg);
}
body.bd-im .bd-ph-list { border-right: .5px solid var(--bd-sep); display: flex; flex-direction: column; min-width: 0; min-height: 0; }
body.bd-im .bd-ph-top { padding: 12px 16px 6px; background: var(--bd-pane); position: sticky; top: 0; z-index: 2; }
body.bd-im .bd-ph-segrow { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
body.bd-im .bd-ph-title { font-size: 30px; font-weight: 700; letter-spacing: -.4px; margin: 10px 0 2px; }
body.bd-im .bd-ph-seg[hidden] { display: none; }
body.bd-im .bd-ph-seg {
  display: inline-flex; background: var(--bd-sunk); border-radius: 9px; padding: 2px; gap: 2px;
}
body.bd-im .bd-ph-seg button {
  border: 0; background: none; border-radius: 7px; padding: 5px 12px; font: inherit; font-size: 13px;
  font-weight: 600; color: var(--fg); cursor: pointer; transition: background .15s, box-shadow .15s;
}
body.bd-im .bd-ph-seg button.on { background: var(--bd-pane); box-shadow: 0 1px 3px rgba(0,0,0,.14); }
html[data-theme=dark] body.bd-im .bd-ph-seg button.on { background: #48484A; }
body.bd-im .bd-ph-seg-view { display: none; }
body.bd-im .bd-ph-rows { overflow: auto; flex: 1; padding-bottom: 24px; }
body.bd-im .bd-ph-day {
  font-size: 12px; font-weight: 700; color: var(--bd-mute); text-transform: uppercase; letter-spacing: .5px;
  padding: 14px 16px 4px;
}
body.bd-im .bd-ph-row {
  display: flex; align-items: center; gap: 12px; padding: 9px 12px 9px 16px; cursor: pointer;
  position: relative; transition: background .12s;
}
body.bd-im .bd-ph-row + .bd-ph-row::before {
  content: ''; position: absolute; left: 68px; right: 0; top: 0; border-top: .5px solid var(--bd-sep);
}
body.bd-im .bd-ph-row:active { background: var(--bd-sunk); }
@media (hover: hover) { body.bd-im .bd-ph-row:hover { background: var(--bd-sunk); } }
body.bd-im .bd-ph-av {
  width: 40px; height: 40px; border-radius: 50%; flex: 0 0 40px; display: inline-flex; align-items: center;
  justify-content: center; color: #fff; font-weight: 700; font-size: 15px; letter-spacing: .3px;
  background-image: linear-gradient(180deg, rgba(255,255,255,.22), rgba(255,255,255,0));
}
body.bd-im .bd-ph-av svg { width: 22px; height: 22px; }
body.bd-im .bd-ph-av-xl { width: 76px; height: 76px; flex-basis: 76px; font-size: 28px; }
body.bd-im .bd-ph-av-xl svg { width: 40px; height: 40px; }
body.bd-im .bd-ph-av-call { width: 104px; height: 104px; flex-basis: 104px; font-size: 40px; }
body.bd-im .bd-ph-av-call svg { width: 54px; height: 54px; }
body.bd-im .bd-ph-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
body.bd-im .bd-ph-main b { font-size: 16px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body.bd-im .bd-ph-missed .bd-ph-main b { color: var(--bd-red); }
body.bd-im .bd-ph-sub { font-size: 13px; color: var(--bd-mute); display: flex; align-items: center; gap: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body.bd-im .bd-ph-dir { width: 14px; height: 14px; flex: 0 0 14px; color: var(--bd-mute2); }
body.bd-im .bd-ph-missed .bd-ph-dir { color: var(--bd-red); }
body.bd-im .bd-ph-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
body.bd-im .bd-ph-when { font-size: 14px; color: var(--bd-mute); }
body.bd-im .bd-ph-info {
  border: 0; background: none; color: var(--bd-blue); width: 32px; height: 32px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
body.bd-im .bd-ph-info svg { width: 20px; height: 20px; }
body.bd-im .bd-ph-info:hover { background: rgba(0,122,255,.1); }
body.bd-im .bd-ph-empty { padding: 48px 16px; text-align: center; color: var(--bd-mute); font-size: 15px; }
body.bd-im .bd-ph-err { margin: 10px 16px 0; padding: 10px 12px; border-radius: 10px; background: rgba(255,59,48,.1); color: var(--bd-red); font-size: 13px; }

/* voicemail rows */
body.bd-im .bd-ph-vmrow { flex-wrap: wrap; }
body.bd-im .bd-ph-vmrow .bd-ph-sub { white-space: normal; display: block; line-height: 1.3;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
body.bd-im .bd-ph-dot { width: 8px; height: 8px; border-radius: 50%; background: transparent; flex: 0 0 8px; margin-left: -8px; }
body.bd-im .bd-ph-unheard .bd-ph-dot { background: var(--bd-blue); }
body.bd-im .bd-ph-vmrow .bd-ph-right i { color: var(--bd-mute2); transition: transform .2s; }
body.bd-im .bd-ph-open .bd-ph-right i { transform: rotate(90deg); }
body.bd-im .bd-ph-vmx { flex-basis: 100%; padding: 6px 0 4px 52px; cursor: default; }
body.bd-im .bd-ph-player { display: flex; align-items: center; gap: 10px; background: var(--bd-sunk); border-radius: 14px; padding: 8px 12px 8px 8px; }
body.bd-im .bd-ph-play {
  width: 36px; height: 36px; border-radius: 50%; border: 0; background: var(--bd-blue); color: #fff;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer; flex: 0 0 36px;
}
body.bd-im .bd-ph-play svg { width: 16px; height: 16px; }
body.bd-im .bd-ph-play:disabled { opacity: .4; }
body.bd-im .bd-ph-track { flex: 1; height: 6px; border-radius: 3px; background: rgba(120,120,128,.28); overflow: hidden; cursor: pointer; }
body.bd-im .bd-ph-fill { height: 100%; width: 0; background: var(--bd-blue); border-radius: 3px; transition: width .2s linear; }
body.bd-im .bd-ph-time { font-size: 12px; color: var(--bd-mute); font-variant-numeric: tabular-nums; min-width: 52px; text-align: right; }
body.bd-im .bd-ph-norec { font-size: 13px; color: var(--bd-mute); }
body.bd-im .bd-ph-transcript { font-size: 15px; line-height: 1.45; margin: 10px 0 8px; color: var(--fg); }
body.bd-im .bd-ph-vmacts { display: flex; gap: 8px; flex-wrap: wrap; }
body.bd-im .bd-ph-act {
  display: inline-flex; align-items: center; gap: 6px; border: 0; border-radius: 999px; padding: 7px 14px;
  background: var(--bd-sunk); color: var(--bd-blue); font: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer; text-decoration: none;
}
body.bd-im .bd-ph-act svg { width: 16px; height: 16px; }
body.bd-im .bd-ph-act-call { background: var(--bd-out); color: #fff; }

/* -- keypad -- */
body.bd-im .bd-ph-pad { display: flex; align-items: center; justify-content: center; padding: 24px; background: var(--bd-pane2); }
/* Desktop: the pad sits in a real card so it reads as a dialler, not digits floating in an empty pane. */
body.bd-im .bd-ph-padcard {
  width: 100%; max-width: 380px; display: flex; flex-direction: column; align-items: center;
  background: var(--bd-pane); border-radius: 24px; padding: 26px 24px 30px;
  box-shadow: 0 1px 0 rgba(0,0,0,.04), 0 12px 32px rgba(0,0,0,.08);
}
html[data-theme=dark] body.bd-im .bd-ph-padcard { background: #1C1C1E; box-shadow: 0 12px 32px rgba(0,0,0,.4); }
body.bd-im .bd-ph-num:empty::before { content: 'Enter a number'; color: var(--bd-mute2); font-size: 22px; font-weight: 400; letter-spacing: 0; direction: ltr; }
body.bd-im .bd-ph-line { font-size: 12px; color: var(--bd-mute); font-weight: 600; text-transform: uppercase; letter-spacing: .6px; }
body.bd-im .bd-ph-demo { display: inline-block; background: var(--accent); color: #111; border-radius: 6px; padding: 1px 6px; font-size: 10px; letter-spacing: .4px; margin-left: 4px; vertical-align: 1px; }
body.bd-im .bd-ph-display { height: 88px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; width: 100%; padding-bottom: 14px; }
body.bd-im .bd-ph-who { font-size: 15px; color: var(--bd-mute); min-height: 20px; }
body.bd-im .bd-ph-num {
  font-size: 38px; font-weight: 400; letter-spacing: 1px; min-height: 48px; font-variant-numeric: tabular-nums;
  white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: clip; direction: rtl; unicode-bidi: plaintext; text-align: center;
}
body.bd-im .bd-ph-num-long { font-size: 28px; }
body.bd-im .bd-ph-keys { display: grid; grid-template-columns: repeat(3, 76px); gap: 14px 22px; justify-content: center; }
body.bd-im .bd-ph-key {
  width: 76px; height: 76px; border-radius: 50%; border: 0; background: var(--bd-in); color: var(--fg);
  display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer;
  font: inherit; -webkit-tap-highlight-color: transparent; user-select: none; touch-action: manipulation;
  transition: background .1s, transform .08s;
}
body.bd-im .bd-ph-key b { font-size: 32px; font-weight: 400; line-height: 1; }
body.bd-im .bd-ph-key small { font-size: 10px; font-weight: 700; letter-spacing: 1.6px; margin-top: 2px; color: var(--fg); opacity: .8; }
body.bd-im .bd-ph-key:active { background: var(--bd-mute2); transform: scale(.94); }
html[data-theme=dark] body.bd-im .bd-ph-key { background: #333336; }
html[data-theme=dark] body.bd-im .bd-ph-key:active { background: #636366; }
body.bd-im .bd-ph-go { display: grid; grid-template-columns: 76px 76px 76px; gap: 14px 22px; margin-top: 16px; align-items: center; justify-items: center; }
body.bd-im .bd-ph-callbtn {
  width: 76px; height: 76px; border-radius: 50%; border: 0; background: var(--bd-out); color: #fff; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; box-shadow: 0 8px 24px rgba(52,199,89,.35);
  transition: transform .08s, filter .1s;
}
body.bd-im .bd-ph-callbtn svg { width: 32px; height: 32px; }
body.bd-im .bd-ph-callbtn:active { transform: scale(.94); filter: brightness(.92); }
body.bd-im .bd-ph-back { border: 0; background: none; color: var(--bd-mute); cursor: pointer; width: 48px; height: 48px; display: inline-flex; align-items: center; justify-content: center; }
body.bd-im .bd-ph-back svg { width: 28px; height: 28px; }
body.bd-im .bd-ph-staff { margin-top: 18px; font-size: 13px; color: var(--bd-mute); display: flex; align-items: center; gap: 6px; }
body.bd-im .bd-ph-staff select { font: inherit; font-weight: 600; color: var(--bd-blue); border: 0; background: none; padding: 0; cursor: pointer; }

/* -- bottom bar (phones) -- */
body.bd-im .bd-ph-nav { display: none; }

/* -- contact sheet -- */
.bd-ph-sheet { position: fixed; inset: 0; z-index: 210; background: rgba(0,0,0,.4); display: flex; align-items: flex-end; justify-content: center; animation: bd-ph-fade .18s ease-out; }
.bd-ph-sheetcard {
  position: relative; width: 100%; max-width: 440px; background: var(--bd-pane, #fff); color: var(--fg, #111);
  border-radius: 22px 22px 0 0; padding: 8px 20px calc(24px + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -12px 40px rgba(0,0,0,.25); font-family: inherit; animation: bd-ph-up .22s cubic-bezier(.2,.8,.2,1);
  max-height: 86vh; overflow: auto;
}
@media (min-width: 561px) {
  .bd-ph-sheet { align-items: center; }
  .bd-ph-sheetcard { border-radius: 22px; padding-bottom: 20px; }
}
.bd-ph-grab { width: 36px; height: 5px; border-radius: 3px; background: var(--bd-mute2, #ccc); margin: 4px auto 8px; }
.bd-ph-sheetx { position: absolute; right: 14px; top: 14px; border: 0; background: var(--bd-sunk, #efeff4); color: var(--bd-mute, #888); width: 30px; height: 30px; border-radius: 50%; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.bd-ph-sheetx svg { width: 16px; height: 16px; }
.bd-ph-contact { display: flex; flex-direction: column; align-items: center; padding: 16px 0 8px; gap: 4px; }
.bd-ph-contact h3 { margin: 10px 0 0; font-size: 22px; font-weight: 700; letter-spacing: -.3px; }
.bd-ph-cnum { color: var(--bd-mute, #888); font-size: 15px; }
.bd-ph-cacts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 14px 0 8px; }
.bd-ph-cact {
  border: 0; border-radius: 14px; background: var(--bd-sunk, #efeff4); color: var(--bd-blue, #007AFF); padding: 12px 6px 10px;
  display: flex; flex-direction: column; align-items: center; gap: 6px; font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.bd-ph-cact svg { width: 22px; height: 22px; }
.bd-ph-cact-call { background: var(--bd-out, #34C759); color: #fff; }
.bd-ph-chist .bd-ph-day { padding: 12px 0 4px; }
.bd-ph-hrow { display: flex; align-items: center; gap: 8px; padding: 9px 0; border-top: .5px solid var(--bd-sep, #ddd); font-size: 15px; }
.bd-ph-hrow .bd-ph-when { margin-left: auto; font-size: 13px; }
.bd-ph-hrow.bd-ph-missed { color: var(--bd-red, #FF3B30); }
.bd-ph-hrow.bd-ph-missed .bd-ph-dir { color: var(--bd-red, #FF3B30); }
@keyframes bd-ph-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes bd-ph-up { from { transform: translateY(40px); opacity: .6; } to { transform: none; opacity: 1; } }

/* -- the call sheet: full screen, dark, the one Hollywood moment -- */
.bd-call { position: fixed; inset: 0; z-index: 300; color: #fff; font-family: inherit; animation: bd-ph-fade .2s ease-out; }
.bd-call-out { animation: bd-call-out .22s ease-in forwards; }
@keyframes bd-call-out { to { opacity: 0; transform: scale(1.02); } }
.bd-call-bg {
  position: absolute; inset: 0;
  background:
    radial-gradient(60% 45% at 50% 28%, color-mix(in srgb, var(--bd-call-tint, #5E5CE6) 55%, transparent), transparent 70%),
    linear-gradient(180deg, #1c1c1f 0%, #050506 100%);
}
.bd-call-body {
  position: relative; height: 100%; display: flex; flex-direction: column; align-items: center;
  padding: calc(18px + env(safe-area-inset-top, 0px)) 24px calc(34px + env(safe-area-inset-bottom, 0px));
}
.bd-call-top { width: 100%; text-align: center; font-size: 13px; color: rgba(255,255,255,.55); letter-spacing: .3px; }
.bd-call-hero { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 4px; }
.bd-call-rings { position: relative; width: 104px; height: 104px; margin-bottom: 22px; display: flex; align-items: center; justify-content: center; }
.bd-call-rings i { position: absolute; inset: 0; border-radius: 50%; border: 2px solid rgba(255,255,255,.35); opacity: 0; }
.bd-call-ringing .bd-call-rings i { animation: bd-call-ring 2.4s ease-out infinite; }
.bd-call-ringing .bd-call-rings i:nth-child(2) { animation-delay: .8s; }
.bd-call-ringing .bd-call-rings i:nth-child(3) { animation-delay: 1.6s; }
@keyframes bd-call-ring { 0% { transform: scale(1); opacity: .7; } 100% { transform: scale(2.4); opacity: 0; } }
.bd-call-live .bd-call-rings::after {
  content: ''; position: absolute; inset: -6px; border-radius: 50%; border: 3px solid var(--bd-out, #34C759);
  animation: bd-call-live 1.6s ease-in-out infinite;
}
@keyframes bd-call-live { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.bd-call .bd-ph-av { box-shadow: 0 18px 50px rgba(0,0,0,.5); }
.bd-call-name { margin: 0; font-size: 32px; font-weight: 600; letter-spacing: -.5px; line-height: 1.1; }
.bd-call-num { font-size: 17px; color: rgba(255,255,255,.7); font-variant-numeric: tabular-nums; min-height: 22px; }
.bd-call-status { margin-top: 14px; font-size: 15px; color: rgba(255,255,255,.72); max-width: 320px; line-height: 1.4; min-height: 42px; }
.bd-call-failed .bd-call-status { color: #FF6961; }
.bd-call-acts { display: grid; grid-template-columns: repeat(3, 84px); gap: 18px; justify-content: center; align-items: start; }
.bd-call-act { display: flex; flex-direction: column; align-items: center; gap: 8px; font-size: 13px; color: rgba(255,255,255,.85); }
.bd-call-act button, .bd-call-act a.bd-call-go {
  width: 72px; height: 72px; border-radius: 50%; border: 0; cursor: pointer; color: #fff;
  display: inline-flex; align-items: center; justify-content: center; background: rgba(255,255,255,.18);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); transition: transform .08s, filter .1s;
}
.bd-call-act button svg, .bd-call-act a.bd-call-go svg { width: 30px; height: 30px; }
.bd-call-act button:active, .bd-call-act a.bd-call-go:active { transform: scale(.94); }
.bd-call-act a.bd-call-go { text-decoration: none; -webkit-tap-highlight-color: transparent; }
/* One-tap fallback: the old ring-my-phone-first bridge, kept as a quiet link. */
.bd-call-alt { margin-top: 10px; background: none; border: 0; padding: 6px 10px; color: rgba(255,255,255,.78); font: inherit; font-size: 14px; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.bd-call-alt[hidden], .bd-call-ringing .bd-call-alt, .bd-call-live .bd-call-alt { display: none; }
.bd-call-go { background: var(--bd-out, #34C759) !important; box-shadow: 0 10px 30px rgba(52,199,89,.45); }
.bd-call-end { background: #FF3B30 !important; }
.bd-call-ringing .bd-call-act-main, .bd-call-live .bd-call-act-main { visibility: hidden; }
.bd-call-failed .bd-call-act-main span::after { content: ' again'; }

/* -- phones: one panel at a time under a bottom bar -- */
@media (max-width: 760px) {
  body.bd-im .bd-ph { grid-template-columns: 1fr; height: calc(100vh - 58px); }
  body.bd-im .bd-ph-list { border-right: 0; padding-bottom: 70px; }
  body.bd-im .bd-ph-pad { display: none; padding: 12px 16px calc(78px + env(safe-area-inset-bottom, 0px)); background: var(--bd-pane); }
  body.bd-im .bd-ph-mode-keypad .bd-ph-list { display: none; }
  body.bd-im .bd-ph-mode-keypad .bd-ph-pad { display: flex; }
  body.bd-im .bd-ph-padcard { background: none; box-shadow: none; border-radius: 0; padding: 0; }
  /* The dark desktop card rule is more specific, so it must be cleared here too. */
  html[data-theme=dark] body.bd-im .bd-ph-padcard { background: none; box-shadow: none; }
  body.bd-im .bd-ph-keys { grid-template-columns: repeat(3, 72px); gap: 12px 24px; }
  body.bd-im .bd-ph-key { width: 72px; height: 72px; }
  body.bd-im .bd-ph-go { grid-template-columns: 72px 72px 72px; gap: 12px 24px; }
  body.bd-im .bd-ph-nav {
    display: grid; grid-template-columns: repeat(3, 1fr); position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    background: var(--bd-bar); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
    border-top: .5px solid var(--bd-sep); padding: 6px 0 calc(6px + env(safe-area-inset-bottom, 0px));
  }
  body.bd-im .bd-ph-nav button {
    border: 0; background: none; color: var(--bd-mute); display: flex; flex-direction: column; align-items: center; gap: 2px;
    font: inherit; font-size: 10px; font-weight: 600; cursor: pointer; padding: 4px 0;
  }
  body.bd-im .bd-ph-nav button svg { width: 24px; height: 24px; }
  body.bd-im .bd-ph-nav button.on { color: var(--bd-blue); }
  body.bd-im .bd-ph-title { font-size: 28px; }
}
/* Desktop: the keypad is always on the right, so the list column chooses
   Recents or Voicemail with a segmented control instead of the bottom bar. */
@media (min-width: 761px) {
  body.bd-im .bd-ph-seg-view { display: inline-flex; }
}

/* ============================================================================
   MOON, the polish layer.  21 Sep 2026.

   Mick asked for the ruixen "moon chat" look (21st.dev/@ruixen.ui): a near
   black canvas with one big soft dome of light cresting off the bottom edge,
   glass panels with a hairline rim, fully round pill navigation, squircle keys
   and calm motion.

   ⛔ ADDITIVE AND LAST. Nothing above it moved and no node, id, class or
   handler changed. Deleting this block, from the banner to the end of the
   file, puts the Messages skin back exactly as it was. That is why it is one
   block and not a hundred edits spread through the file.

   ⛔ It hangs off `body.bd-im`, the same class bd-inbox.js adds once the shell
   is built. Script fails, no moon, and the page still degrades to the plain
   stacked list. Same fail-open as everything above it.

   The dome is BD yellow, not the reference violet. One accent per app, and
   Harbour Carpentry's is yellow on black.

   ⛔ Send stays a labelled pill with squared-off corners, NOT the reference's
   round arrow key. sendReply() rewrites its text to "Sending…" and "Sent" and
   that state has to stay readable. Same reason as the note further up.
   ========================================================================== */

body.bd-im {
  /* ⛔ NO DOME. Jess, 21 Sep 2026: "remove the yellow line through the
     background it makes it hard to read". It was one backlit disc crested just
     below the viewport, and the bright band of it crossed the thread straight
     through the message bubbles. The light theme had already been dialled down
     once for the same reason; this is the same verdict on the dark one.
     The rest of the moon layer (glass panels, hairlines, pills) is untouched,
     so putting the gradient back here is all it takes to restore it. */
  --moon-dome: none;
  --moon-face:  #08080b;
  --moon-glass: rgba(255,255,255,.055);
  --moon-hair:  rgba(255,255,255,.11);
  --moon-hair2: rgba(255,255,255,.17);
  --moon-ease:  cubic-bezier(.32,.72,0,1);
}
html[data-theme=light] body.bd-im {
  /* ⛔ Off here too, see the note above. The light theme's hint was already the
     second attempt at this and it is still a yellow wash over text she reads
     all day. Plain pane, readable words. */
  --moon-dome: none;
  --moon-face:  #eceef3;
  --moon-glass: rgba(255,255,255,.66);
  --moon-hair:  rgba(22,22,34,.10);
  --moon-hair2: rgba(22,22,34,.16);
}

/* ⛔ background-attachment:fixed, and that is the whole trick. The dome is
   painted onto the panes themselves rather than onto a layer behind them,
   because the panes are opaque and a layer behind them is a layer you never
   see. Anchoring it to the viewport instead of the element means the list and
   the thread, side by side on a desk or stacked on a phone, share ONE
   continuous dome instead of getting half of it each.
   It also keeps the panes opaque, so the thread sliding over the list still
   hides the list, which a translucent pane would not. */
body.bd-im .ib-host,
body.bd-im .bd-pane {
  background-color: var(--moon-face);
  background-image: var(--moon-dome);
  /* ⛔ background-attachment:fixed REMOVED 23 Sep 2026 (Jess: "its very choppy
     and not super smooth"). An ancestor with a viewport-anchored background
     takes the scroller inside it off the compositor: every frame of every
     scroll in the list AND the thread became a full main-thread repaint, and
     the six live backdrop-filter bars then re-blurred against that fresh paint.
     It was also doing NOTHING - --moon-dome has been `none` in both themes
     since 21 Sep, so there is no image left to anchor. If the dome ever comes
     back, give it its own position:fixed layer, do not put this line back. */
  background-repeat: no-repeat;
}
/* ⛔ The thread scroller had its own solid background and that is what hid the
   dome on the right-hand pane. It inherits the pane's now. */
body.bd-im .ib-main { background: transparent; }

/* run.py's three corner washes fought the dome for the same space. Turned down
   rather than off: they are what makes the light theme readable in daylight. */
html[data-theme=dark] body.bd-im:before { opacity: .3; }

/* ── the top bar, glass instead of a slab ─────────────────────────────────── */
body.bd-im .ib-top {
  background: rgba(10,10,14,.6);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: 1px solid rgba(255,255,255,.08);
}
body.bd-im .ib-name { letter-spacing: -.03em; font-weight: 800; }
body.bd-im .ib-icon {
  border-radius: 12px; width: 34px; height: 34px;
  border: 1px solid rgba(255,255,255,.14); background: rgba(255,255,255,.055);
  transition: background .22s var(--moon-ease), transform .16s var(--moon-ease);
}
body.bd-im .ib-icon:hover { background: rgba(255,255,255,.11); }

/* ── quick-action pills, straight off the reference ───────────────────────── */
body.bd-im .tabs button {
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: 999px; padding: 8px 16px;
  font-size: 12.5px; font-weight: 600; letter-spacing: -.01em;
  color: rgba(255,255,255,.74); box-shadow: none;
  transition: background .22s var(--moon-ease), border-color .22s var(--moon-ease),
              color .22s var(--moon-ease), transform .16s var(--moon-ease);
}
body.bd-im .tabs button:hover { background: rgba(255,255,255,.1); color: #fff; }
body.bd-im .tabs button.on {
  background: rgba(255,236,0,.13); border-color: rgba(255,236,0,.5);
  color: #FFEC00; box-shadow: 0 0 24px -8px rgba(255,236,0,.85);
}
body.bd-im .tabs button b { opacity: .55; font-weight: 600; }

/* ── the nav bar over the thread ──────────────────────────────────────────── */
body.bd-im .bd-top {
  background: rgba(10,10,14,.5);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--moon-hair);
}
body.bd-im .bd-h, body.bd-im .bd-info-head .bd-h { letter-spacing: -.03em; }

/* ── the composer, a floating glass slab ──────────────────────────────────── */
body.bd-im .ib-main .card.ib-open .reply-block {
  margin: 0 10px calc(10px + var(--bd-safe-b));
  padding: 11px 12px 9px;
  border-radius: 24px;
  border: 1px solid var(--moon-hair); border-top: 1px solid var(--moon-hair);
  background: var(--moon-glass);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 20px 44px -24px rgba(0,0,0,.95);
}
body.bd-im .ib-main .reply-block > .label { letter-spacing: .02em; opacity: .8; }
body.bd-im .ib-main .reply-edit {
  background: transparent; border: 0; border-radius: 0;
  padding: 2px 6px 4px; line-height: 1.38;
}
body.bd-im .ib-main .reply-edit:focus { border: 0; outline: none; box-shadow: none; }
body.bd-im .ib-main .reply-actions .snip,
body.bd-im .ib-main .bd-triage .ask-row input {
  border-radius: 999px; border: 1px solid var(--moon-hair2); background: transparent;
}
body.bd-im .ib-main .btn.attach {
  border-radius: 999px; border: 1px solid var(--moon-hair2); background: transparent;
}
body.bd-im .ib-main .btn.send {
  border-radius: 14px; padding: 10px 19px; font-size: 13.5px; letter-spacing: -.01em;
  box-shadow: 0 12px 26px -14px var(--bd-out);
  transition: transform .16s var(--moon-ease), box-shadow .22s var(--moon-ease);
}
body.bd-im .ib-main .btn.send:active { transform: scale(.96); }

/* ── everything that was a box becomes a pill or a squircle ───────────────── */
body.bd-im .ib-main .hist-bubble { border-radius: 20px; }
body.bd-im .ib-main .hist-bubble.out { box-shadow: 0 12px 28px -18px var(--bd-out); }
body.bd-im .bd-tag,
body.bd-im .ib-main .att-chip,
body.bd-im .ib-main .tag { border-radius: 999px; }
body.bd-im .bd-actions .btn,
body.bd-im .bd-triage .btn,
body.bd-im .bd-info .btn { border-radius: 999px; padding: 8px 15px; }
body.bd-im .ib-main .bd-flag { border-radius: 16px; }
body.bd-im .bd-row { transition: background .22s var(--moon-ease); }
body.bd-im .bd-search, body.bd-im .search {
  border-radius: 999px; border: 1px solid var(--moon-hair2);
}

/* No scroll bars anywhere, the reference has none and this is a phone tool. */
body.bd-im, body.bd-im * { scrollbar-width: none; }
body.bd-im *::-webkit-scrollbar { width: 0; height: 0; }

/* ── Mark done · Close, on the bar with the person's name ────────────────────
   Jess, 21 Sep 2026: "put close and mark done on the same bar as the person
   name so i dont have to scroll up to close anything". They were at the top of
   the thread, which scrolls away under a long conversation; the header bar
   never moves. Built by renderHeadActions().

   ⛔ The card's own Close button stays in the DOM below, hidden, because
   closeSpam() reads its data-conv and its .card, and the header bar is outside
   the card. The header button only clicks it. */
body.bd-im .bd-headacts { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
body.bd-im .bd-headbtn {
  flex: 0 0 auto; padding: 6px 13px; border-radius: 999px;
  border: 1px solid var(--moon-hair2, var(--bd-sep)); background: transparent;
  color: var(--fg); cursor: pointer; font-family: inherit;
  font-size: 12.5px; font-weight: 600; line-height: 1.3; white-space: nowrap;
}
body.bd-im .bd-headbtn:active { opacity: .6; }
body.bd-im .bd-headbtn-close { color: var(--bad-fg, #b42318); }
body.bd-im .ib-main .card.ib-open > .card-body > .card-foot { display: none; }
/* On a phone the name keeps its room: compact pills, and the right-hand side
   stops reserving its 58px. */
@media (max-width: 560px) {
  body.bd-im .bd-thread .bd-bar-r { min-width: 0; }
  body.bd-im .bd-headbtn { padding: 5px 9px; font-size: 11.5px; }
}

/* ---- Fleet icon set ----
   The glyphs in this skin are inline <svg class="i21"> from /icons.js, sized
   1em by the module itself. Only the gap beside a word belongs here. */
.bd-tag .i21, .bd-ochip .i21, .bd-tab .i21, .ib-rush-on .i21, .bd-ph-act .i21, .bd-ph-nav .i21 { margin-right: .3em; }
.bd-round .i21, .bd-fab .i21, .bd-ph-callbtn .i21, .bd-ph-back .i21, .bd-ph-play .i21, .bd-ph-info .i21, .bd-ph-sheetx .i21, .bd-ph-cact .i21, .bd-call-act button .i21, .bd-call-act a.bd-call-go .i21, .bd-ph-nav .i21 { margin-right: 0; }
.bd-ochip > .i21:first-child { margin-right: .26em; }

/* ---- Who is in a conversation, and who finished one ----
   Added 23 Sep 2026 with per-user logins. Two states in one chip: amber while
   somebody else has the conversation open (the collision worth preventing), grey
   once it is done and says who did it. The chip only exists in the DOM when it
   has something to say, so a one-person shop never sees it at all. */
body.bd-im .card-who {
  font-size: 11px; font-weight: 600; line-height: 1; white-space: nowrap;
  padding: 3px 7px; border-radius: 999px; flex: 0 0 auto;
  color: #9a9aa4; background: rgba(128, 128, 128, .14);
}
body.bd-im .card-who.busy {
  color: #b7791f; background: rgba(214, 158, 46, .16);
  box-shadow: inset 0 0 0 1px rgba(214, 158, 46, .34);
}
body.bd-light .card-who.busy { color: #8a5a10; }
/* The signed-in name sits with the other header stats and goes the same way they
   do on a narrow phone, where the tabs need every pixel. */
body.bd-im .ib-me { font-weight: 600; color: #c8c8d0; }
body.bd-light .ib-me { color: #44444c; }

/* ---- A one-line message ----
   flash() takes a node or a string; this is the string case. Three call sites
   (Copy on the contact card, "no thread yet", the short-number warning) had
   assumed it existed since they were written and silently said nothing. */
.bd-toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(22px + env(safe-area-inset-bottom, 0px)); z-index: 9000;
  max-width: min(92vw, 420px); padding: 10px 14px; border-radius: 12px;
  font-size: 13.5px; font-weight: 600; line-height: 1.35; text-align: center;
  color: #f4f4f6; background: rgba(28, 28, 32, .94);
  box-shadow: 0 8px 26px rgba(0, 0, 0, .34); opacity: 1;
  transition: opacity .28s ease, transform .28s ease;
}
.bd-toast-out { opacity: 0; transform: translateX(-50%) translateY(6px); }
body.bd-light .bd-toast { color: #fff; background: rgba(24, 24, 28, .92); }

/* ---- The app phone ----
   Off is the resting state and looks like any other top-bar button. On is green,
   because "can this machine answer the phone right now" has to be readable from
   across a room, not from a tooltip. */
#appphone-btn.bd-on {
  color: #1c7c3a; border-color: rgba(52, 168, 83, .45);
  background: rgba(52, 168, 83, .14);
}
#appphone-btn.bd-busy { opacity: .6; }
.bd-call-act button.bd-on { background: #d69e2e; color: #1c1c20; }

/* Pass the call on: names only, no numbers, and the warning sits above them
   because the transfer is blind - the customer goes straight through. */
.bd-call-xferbox {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px));
}
.bd-call-xfertip {
  flex: 1 0 100%; text-align: center; font-size: 12px; font-weight: 600;
  color: rgba(255, 255, 255, .72);
}
.bd-call-xferbox button {
  appearance: none; cursor: pointer; font: inherit; font-weight: 700;
  font-size: 13.5px; padding: 9px 15px; border-radius: 999px;
  color: #fff; background: rgba(255, 255, 255, .16);
  border: 1px solid rgba(255, 255, 255, .26);
}
.bd-call-xferbox button:disabled { opacity: .55; cursor: default; }
/* Off because something broke, as opposed to off because nobody turned it on.
   This has to survive the message that announced it: the message is gone in two
   seconds and the phone is still not answering. */
#appphone-btn.bd-bad {
  color: #b23c2e; border-color: rgba(200, 70, 50, .45);
  background: rgba(200, 70, 50, .12);
}

/* ---- Recorded calls (25 Sep 2026): Recents row + panel, and the call-notes
   bubble in a thread. Internal only; styled apart from sent messages. ---- */
.bd-ph-recbadge {
  display: inline-block; padding: 0 6px; border-radius: 6px; font-size: 10.5px;
  font-weight: 600; letter-spacing: .02em; color: #2f6f4f;
  background: rgba(60, 150, 100, .12); border: .5px solid rgba(60, 150, 100, .35);
}
.bd-ph-recsum { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: .85; }
.bd-ph-summary { margin: 10px 0 6px; font-size: 13px; line-height: 1.5; }
.bd-ph-calltx { margin: 4px 0 8px; }
.bd-ph-calltx summary { cursor: pointer; font-size: 12px; opacity: .75; }
.bd-ph-calltx .bd-ph-transcript { max-height: 260px; overflow: auto; }
.hist-bubble.note,
body.bd-im .ib-main .hist-bubble.note {
  align-self: stretch; max-width: 100%; width: auto; color: var(--fg); font-size: 14px;
  background: rgba(90, 120, 200, .08);
  border: 1px dashed rgba(90, 120, 200, .45);
}
.hist-bubble.note .hist-rec { display: block; width: 100%; height: 32px; margin-top: 6px; }

/* ---- 29 Sep 2026: list order, phone header, no zoom ---- */
body.bd-im .bd-sec {
  position: sticky; top: 0; z-index: 2;
  padding: 7px 16px 5px; font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--bd-mute);
  background: var(--bd-bar); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: .5px solid var(--bd-sep);
}

/* The name and number sit dead centre on a phone. The two sides of the bar were
   different widths (a back button one side, two pills and a button the other),
   so "centre of what was left" was well left of the middle of the screen. The
   sides are now equal columns and the pills get a row of their own. */
@media (max-width: 560px) {
  body.bd-im .bd-thread .bd-bar {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, auto) minmax(0, 1fr);
    column-gap: 6px; row-gap: 2px; align-items: center;
  }
  body.bd-im .bd-thread .bd-bar-c,
  body.bd-im .bd-thread .bd-bar-r { display: contents; }
  body.bd-im .bd-thread .bd-bar-l { grid-column: 1; grid-row: 1; min-width: 0; justify-self: start; }
  body.bd-im .bd-thread .bd-bar [data-bd="who"] {
    grid-column: 2; grid-row: 1; min-width: 0; text-align: center;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  body.bd-im .bd-thread .bd-bar [data-bd="info"] { grid-column: 3; grid-row: 1; justify-self: end; }
  body.bd-im .bd-thread .bd-bar [data-bd="whosub"] {
    grid-column: 1 / -1; grid-row: 2; text-align: center; margin-top: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  body.bd-im .bd-thread .bd-bar .bd-ochips { grid-column: 1 / -1; grid-row: 3; justify-content: safe center; margin-top: 2px; }
  body.bd-im .bd-thread .bd-bar .bd-headacts { grid-column: 1 / -1; grid-row: 4; justify-self: center; }
}

/* Anything under 16px makes an iPhone zoom in when the box is tapped. */
@media (pointer: coarse) {
  body.bd-im input, body.bd-im textarea, body.bd-im select,
  body input[type="text"], body input[type="search"], body textarea { font-size: 16px !important; }
}

/* ---- 30 Sep 2026: the contact name sits dead centre on a computer too ----
   Mick: "the mark done and close pushing the contact name right to the left".
   The bar was back-slot | name (flex 1) | Mark done + Close + i, so the name was
   centred in whatever the buttons left over, well left of the pane's middle.
   Both side slots now grow from the same zero basis, so they stay equal width
   and the name lands in the true centre; they never shrink below their own
   buttons, so nothing overlaps. Phones use the grid in the block above. */
@media (min-width: 561px) {
  body.bd-im .bd-thread .bd-bar-l,
  body.bd-im .bd-thread .bd-bar-r { flex: 1 1 0; min-width: max-content; }
  body.bd-im .bd-thread .bd-bar-c { flex: 0 1 auto; min-width: 0; max-width: 60%; }
  body.bd-im .bd-thread .bd-bar [data-bd="who"],
  body.bd-im .bd-thread .bd-bar [data-bd="whosub"] {
    display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}

/* ══ Round 2 polish (30 Sep 2026) ═══════════════════════════════════════════
   Mick on live: calls read like texts, the menus were unreadable in dark,
   "Waiting on customer" duplicated itself, and the keypad bubble sat on the
   rows. Last in the file so it wins without !important. */

/* ── popovers: a solid sheet in BOTH themes. --bd-solid was never defined, so
   the fallback #fff sat under dark mode's white text. ── */
body.bd-im { --bd-pop: #FFFFFF; --bd-pop-fg: #1C1C1E; --bd-pop-hi: rgba(118,118,128,.14); }
html[data-theme=dark] body.bd-im { --bd-pop: #2C2C2E; --bd-pop-fg: #F2F2F7; --bd-pop-hi: rgba(255,255,255,.10); }
body.bd-im .bd-sortmenu, body.bd-im .bd-filtmenu {
  z-index: 80; background: var(--bd-pop); color: var(--bd-pop-fg);
  border: .5px solid var(--bd-sep); border-radius: 14px;
  box-shadow: 0 18px 44px rgba(0,0,0,.24), 0 2px 8px rgba(0,0,0,.10);
}
html[data-theme=dark] body.bd-im .bd-sortmenu, html[data-theme=dark] body.bd-im .bd-filtmenu {
  box-shadow: 0 18px 44px rgba(0,0,0,.6), 0 0 0 .5px rgba(255,255,255,.08);
}
body.bd-im .bd-sortmenu button { color: var(--bd-pop-fg); font-weight: 500; font-size: 14px; position: relative; padding-left: 30px; }
body.bd-im .bd-sortmenu button.bd-on { background: none; color: var(--bd-blue); font-weight: 600; }
body.bd-im .bd-sortmenu button.bd-on::before {
  content: ""; position: absolute; left: 12px; top: 50%; width: 5px; height: 10px; margin-top: -7px;
  border: solid currentColor; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
body.bd-im .bd-sortmenu button:hover { background: var(--bd-pop-hi); }
body.bd-im .bd-filtgrp b { color: var(--bd-mute); font-weight: 600; letter-spacing: .02em; }
body.bd-im .bd-filtgrp button { background: var(--bd-pop-hi); color: var(--bd-pop-fg); font-weight: 500; }
body.bd-im .bd-filtgrp button:hover { background: var(--bd-blue); color: #fff; }
body.bd-im .bd-filtnone { color: var(--bd-mute); }

/* ── filter chips: one clean scrolling row, nothing clipped at either end ── */
body.bd-im .bd-tabs { padding: 8px 12px; gap: 6px; scroll-padding: 0 12px; }
body.bd-im .bd-tabs::after { content: ""; flex: 0 0 6px; }
body.bd-im .bd-tab { padding: 7px 12px; font-size: 13px; font-weight: 600; line-height: 1.1; }
body.bd-im .bd-tab .bd-n { font-size: 12px; font-weight: 600; }
body.bd-im .bd-tab .bd-n:empty { display: none; }
html[data-theme=dark] body.bd-im .bd-tab { background: #2C2C2E; color: #F2F2F7; }
html[data-theme=dark] body.bd-im .bd-tab .bd-n { color: #AEAEB2; }
html[data-theme=dark] body.bd-im .bd-tab.bd-on { background: var(--bd-blue); color: #fff; }
html[data-theme=dark] body.bd-im .bd-tab.bd-on .bd-n,
html[data-theme=dark] body.bd-im .bd-tab.bd-hot .bd-n { color: rgba(255,255,255,.85); }
html[data-theme=dark] body.bd-im .bd-tab.bd-hot { background: var(--bd-red); color: #fff; }
body.bd-im .bd-oc { font-weight: 600; font-size: 13px; }
html[data-theme=dark] body.bd-im .bd-oc { background: #1C1C1E; color: #AEAEB2; }
html[data-theme=dark] body.bd-im .bd-oc.bd-on { background: var(--bd-blue); color: #fff; }

/* ── the the old system line: one quiet row, the reason behind "Why" ── */
body.bd-im .bd-note.bd-note-slim {
  background: none; color: var(--bd-mute); padding: 8px 14px 6px; border-bottom: .5px solid var(--bd-sep);
}
body.bd-im .bd-note-slim .bd-note-l { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; }
body.bd-im .bd-note-slim .bd-note-l b { display: inline; font-size: 12.5px; font-weight: 600; color: var(--fg); }
body.bd-im .bd-note-slim .bd-note-p { display: inline; margin: 0; opacity: 1; }
body.bd-im .bd-note-slim .bd-note-p::before { content: "·"; margin-right: 8px; }
body.bd-im .bd-note-why {
  margin-left: auto; border: 0; background: none; padding: 0 2px; color: var(--bd-blue);
  font: inherit; font-size: 12.5px; font-weight: 500; cursor: pointer;
}
body.bd-im .bd-note-more { margin: 4px 0 2px; font-size: 12px; line-height: 1.4; color: var(--bd-mute); }

/* ── keypad: in the list header on a phone, never floating over the rows ── */
body.bd-im .bd-dialround { color: #fff; background: #34C759; }
html[data-theme=dark] body.bd-im .bd-dialround { background: #30D158; }
@media (min-width: 561px) { body.bd-im .bd-dialround { display: none; } }
@media (max-width: 560px) { .bd-dial-fab, body.bd-im .bd-dial-fab { display: none; } }

/* ── "Waiting on the customer" was said twice: the system line in the thread
   already says it plainly, the italic copy above the composer goes. ── */
body.bd-im .ib-main .card .reply-block.awaiting { display: none; }

/* ── call log: a phone call reads as a call record, not a chat bubble ── */
body.bd-im .bd-callic { display: inline-flex; vertical-align: -2px; margin-right: 5px; color: var(--bd-mute); }
body.bd-im .bd-callic svg { width: 13px; height: 13px; }
body.bd-im .hist-call {
  --hc-tint: #34C759; --hc-bg: rgba(52,199,89,.14);
  display: block; width: min(100%, 520px); margin: 10px auto; padding: 12px 14px;
  background: var(--bd-pane); border: .5px solid var(--bd-sep); border-radius: 16px;
  box-shadow: 0 1px 3px rgba(0,0,0,.05); color: var(--fg); font-style: normal; text-align: left;
}
html[data-theme=dark] body.bd-im .hist-call { background: #1C1C1E; box-shadow: none; }
body.bd-im .hist-call.k-missed    { --hc-tint: #FF3B30; --hc-bg: rgba(255,59,48,.12); }
body.bd-im .hist-call.k-voicemail { --hc-tint: #FF9500; --hc-bg: rgba(255,149,0,.14); }
body.bd-im .hist-call.k-outbound  { --hc-tint: #007AFF; --hc-bg: rgba(0,122,255,.12); }
body.bd-im .hist-call.k-oldsys    { --hc-tint: #8E8E93; --hc-bg: rgba(142,142,147,.16); }
html[data-theme=dark] body.bd-im .hist-call.k-missed { --hc-tint: #FF453A; }
html[data-theme=dark] body.bd-im .hist-call.k-outbound { --hc-tint: #0A84FF; }
body.bd-im .hist-call .hc-head { display: flex; align-items: center; gap: 11px; }
body.bd-im .hist-call .hc-ic {
  flex: 0 0 34px; width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--hc-bg); color: var(--hc-tint);
}
body.bd-im .hist-call .hc-ic svg { width: 16px; height: 16px; }
body.bd-im .hist-call .hc-t { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
body.bd-im .hist-call .hc-t b { font-size: 14.5px; font-weight: 600; color: var(--fg); line-height: 1.25; }
body.bd-im .hist-call.k-missed .hc-t b { color: var(--hc-tint); }
body.bd-im .hist-call .hc-t span { font-size: 12.5px; color: var(--bd-mute); line-height: 1.3; }
body.bd-im .hist-call .hc-dur {
  flex: 0 0 auto; font-size: 13px; font-weight: 500; color: var(--bd-mute);
  font-variant-numeric: tabular-nums;
}
body.bd-im .hist-call .hc-sum {
  margin: 10px 0 0; padding: 0; font-size: 13.5px; line-height: 1.45; color: var(--fg); font-style: normal;
}
body.bd-im .hist-call audio.hc-rec { display: block; width: 100%; height: 36px; margin-top: 10px; border-radius: 18px; }
body.bd-im .hist-call details.hc-tr { margin-top: 10px; border-top: .5px solid var(--bd-sep); padding-top: 8px; }
body.bd-im .hist-call details.hc-tr > summary {
  list-style: none; cursor: pointer; font-size: 13px; font-weight: 600; color: var(--bd-blue);
  display: flex; align-items: center; gap: 6px;
}
body.bd-im .hist-call details.hc-tr > summary::-webkit-details-marker { display: none; }
body.bd-im .hist-call details.hc-tr > summary::after {
  content: ""; width: 6px; height: 6px; border: solid currentColor; border-width: 0 1.8px 1.8px 0;
  transform: rotate(45deg); margin-top: -3px; transition: transform .15s;
}
body.bd-im .hist-call details.hc-tr[open] > summary::after { transform: rotate(-135deg); margin-top: 3px; }
body.bd-im .hist-call .hc-tr-b {
  margin-top: 8px; max-height: 280px; overflow-y: auto; padding: 10px 12px;
  background: var(--bd-sunk); border-radius: 10px; font-size: 13px; line-height: 1.5;
}
html[data-theme=dark] body.bd-im .hist-call .hc-tr-b { background: #2C2C2E; }
body.bd-im .hist-call .hc-tr-b p { margin: 0 0 6px; color: var(--fg); font-style: normal; }
body.bd-im .hist-call .hc-tr-b p:last-child { margin-bottom: 0; }
body.bd-im .hist-call .hc-tr-b b { font-weight: 600; color: var(--bd-mute); margin-right: 4px; }
body.bd-im .hist-call .hc-none { display: block; margin-top: 8px; font-size: 12.5px; color: var(--bd-mute); }
body.bd-im .hist-call .hist-meta { display: none; }
body.bd-im .hist-call details.hc-tr > summary::before { content: none; display: none; }
html[data-theme=dark] body.bd-im .hist-call audio.hc-rec { color-scheme: dark; }
/* The chip row scrolls; a soft fade on the right edge says so instead of a hard clip. */
body.bd-im .bd-tabs {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}
/* A ticked-off conversation: a solid, readable bar, never a see-through wash
   over the first bubble. */
body.bd-im .ib-main .card.ib-open.done .done-strip {
  background: linear-gradient(var(--ok-bg), var(--ok-bg)), var(--bd-pane2);
  padding: 9px 16px; font-size: 13px;
}
body.bd-im .ib-main .card.ib-open.done .done-strip .dn { font-size: 0; }
body.bd-im .ib-main .card.ib-open.done .done-strip .dn::before { content: "Marked done"; font-size: 13px; font-weight: 600; }
body.bd-im .ib-main .card.ib-open.done .done-strip .undo {
  margin-left: auto; text-decoration: none; font-size: 13px; font-weight: 600; color: var(--bd-blue); text-transform: capitalize;
}
