/* ============================================================
   app.inbox-legacy.css (inbox fix X0, 2026-09-21)

   These rules were twelve inline <style> blocks in app.html. They
   loaded AFTER app.linear.css, so at equal specificity they silently
   beat it, including fixes that file already makes. They are moved
   here verbatim and in their original order, and app.html links this
   file after app.css and BEFORE app.linear.css, so the theme now wins
   a tie. Against app.css nothing changes: these rules still load after
   it. Each block keeps the comment that preceded it in app.html and a
   marker naming its old id and lines (at fix/base 2be85f9).
   The security gate <style> stays inline in app.html on purpose.
   ============================================================ */

/* ---- was <style id="bd-inbox-css"> at app.html:57-600 ---- */
  /* INBOX (gated feature) - scoped bd-inbox-* styles. Inline here because
       app.css/app.linear.css must not be edited for this feature. Channel
       colors reuse the existing .avatar-source.* palette from app.css. */
    /* Automatic reply chip. Slate, deliberately NOT the indigo of the Human
       agent chip: that colour already means "a different mode is active", and
       this means "no person wrote this". */
    .bd-inbox-autochip {
      display: inline-block;
      margin-inline-start: 6px;
      padding: 0 6px;
      border-radius: var(--radius-sm);
      font-family: var(--font-sans);
      font-size: var(--fs-2xs);
      font-weight: 600;
      white-space: nowrap;
      background: rgba(100, 116, 139, .14);
      color: #475569;
    }
    html[data-theme="dark"] .bd-inbox-autochip {
      background: rgba(148, 163, 184, .18);
      color: #cbd5e1;
    }
    .bd-app-marker { font-style: italic; opacity: .85; }
    /* Inbox fix (COLOUR collector survivor): white on #ef4444 was 3.76:1;
       --danger-btn is 5.38:1 in both themes. */
    .bd-inbox-navbadge { margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px;
      border-radius: var(--radius-full); background: var(--danger-btn, #d70015); color: #fff; font-size: 11px; font-weight: 600;
      line-height: 18px; text-align: center; }
    .bd-inbox-navbadge[hidden] { display: none !important; }
    /* Make the inbox feel like a real chat app: anchor to the viewport height
       instead of a magic 280px cap, so the thread list no longer collapses to
       a 200px peephole and the message pane fills the screen. */
    .bd-inbox-layout { display: grid; grid-template-columns: 360px minmax(0, 1fr);
      gap: var(--space-4); align-items: stretch;
      height: calc(100vh - 220px); min-height: 560px; }
    .bd-inbox-layout[hidden], .bd-inbox-thread[hidden], .bd-inbox-pane-empty[hidden],
    .bd-inbox-paused-note[hidden], .bd-inbox-reply-error[hidden],
    .bd-inbox-disabled[hidden] { display: none !important; }
    @media (max-width: 900px) { .bd-inbox-layout { grid-template-columns: 1fr; height: auto; } }
    .bd-inbox-list { border: 1px solid rgba(127,127,127,.18); border-radius: var(--radius-lg);
      overflow-y: auto; height: 100%; min-height: 0; }
    .bd-inbox-row { display: flex; gap: 12px; padding: 12px 14px; cursor: pointer;
      border-bottom: 1px solid rgba(127,127,127,.12); align-items: flex-start; }
    .bd-inbox-row:last-child { border-bottom: none; }
    .bd-inbox-row:hover { background: rgba(127,127,127,.07); }
    .bd-inbox-row.is-active { background: rgba(127,127,127,.12); }
    /* Contact avatar: initials in a colour derived from the identifier, with
       the channel as a corner badge. Replaces the channel-icon-only avatar,
       which was identical on every row from the same app. */
    .bd-inbox-avatar { position: relative; flex: none; width: 38px; height: 38px;
      border-radius: 50%; display: inline-flex; align-items: center;
      justify-content: center;
      background: hsl(var(--bd-av-h, 210) 62% 46%);
      color: #fff; }
    .bd-inbox-avatar-ini { font-size: 15px; font-weight: 700; line-height: 1;
      letter-spacing: .3px; user-select: none; }
    .bd-inbox-avatar-ch { position: absolute; right: -2px; bottom: -2px;
      width: 17px; height: 17px; border-radius: 50%;
      display: inline-flex; align-items: center; justify-content: center;
      border: 2px solid var(--bg-elevated, #fff); }
    .bd-inbox-avatar-ch svg { width: 11px; height: 11px; }
    @media (max-width: 900px) {
      .bd-inbox-avatar { width: 44px; height: 44px; }
      .bd-inbox-avatar-ini { font-size: 17px; }
    }
    .bd-inbox-chbadge { flex: none; width: 26px; height: 26px; border-radius: var(--radius-md);
      display: inline-flex; align-items: center; justify-content: center;
      font-size: 12px; font-weight: 700; margin-top: 2px; }
    .bd-inbox-row-main { flex: 1; min-width: 0; }
    .bd-inbox-row-top { display: flex; align-items: baseline; gap: 8px; }
    .bd-inbox-row-name { font-size: 14px; font-weight: 600; white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis; flex: 1; }
    .bd-inbox-row.is-unread .bd-inbox-row-name { font-weight: 700; }
    /* Inbox fix C4: the opacity fades that stood here (.6 on the time, .7
       on the preview, .95 on an unread preview) cut the theme's AA greys to
       2.29:1 and 2.82:1. Removed; the colour is the theme's token alone. */
    .bd-inbox-row-time { font-size: 11px; flex: none; }
    .bd-inbox-row-preview { font-size: 13px; white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
    .bd-inbox-row.is-unread .bd-inbox-row-preview { font-weight: 600; }
    .bd-inbox-unread-dot { flex: none; width: 8px; height: 8px; border-radius: 50%;
      background: var(--brand); margin-top: 9px; }
    /* Tri-state AI status pill on each thread row.
         green  = AI is answering this conversation
         amber  = channel AI on but this contact is paused (you reply)
         grey   = AI is off for this channel (channel gate wins) */
    .bd-inbox-aibadge { display: inline-block; font-size: 11px; font-weight: 600;
      padding: 1px 6px; border-radius: var(--radius-sm); margin-top: 3px; }
    .bd-inbox-aibadge.is-active { background: rgba(52,211,153,.18); color: #047857; }
    html[data-theme="dark"] .bd-inbox-aibadge.is-active { color: #34d399; }
    .bd-inbox-aibadge.is-paused { background: rgba(245,165,36,.16); color: #b45309; }
    html[data-theme="dark"] .bd-inbox-aibadge.is-paused { color: #fbbf24; }
    .bd-inbox-aibadge.is-off { background: rgba(127,127,127,.16); color: var(--text-secondary, #64748b); }
    .bd-inbox-row-topics { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
    .bd-inbox-topic-chip { display: inline-block; font-size: 10px; font-weight: 600;
      padding: 1px 6px; border-radius: var(--radius-sm); background: rgba(99,102,241,.14);
      color: #4338ca; white-space: nowrap; }
    html[data-theme="dark"] .bd-inbox-topic-chip { color: #a5b4fc; }
    .bd-inbox-pane { border: 1px solid rgba(127,127,127,.18); border-radius: var(--radius-lg);
      display: flex; flex-direction: column; height: 100%; min-height: 0; }
    /* Phone layout fix (2026-08-04). The max-width:900px rule above drops the
       layout's fixed height, so .bd-inbox-list's `height:100%` resolved against
       auto and the list grew to fit EVERY thread - measured 4217px with 38
       threads, pushing the conversation pane and its reply box to y=4639 on an
       862px screen. Staff could read messages on a phone but never reach the
       composer. These MUST come after the .bd-inbox-list / .bd-inbox-pane base
       rules above: a media query adds no specificity, so the base
       `height:100%` / `min-height:0` win on source order otherwise. */
    @media (max-width: 900px) {
      .bd-inbox-list { height: auto; max-height: 40vh; }
      /* Bounded so .bd-inbox-messages (flex:1, overflow-y:auto) scrolls inside
         the pane and the reply box stays on screen instead of being pushed
         below a growing message history. */
      .bd-inbox-pane { height: auto; min-height: 60vh; max-height: 80vh; }
      /* Master-detail. With the list still on screen the pane began ~335px
         down, so on a long history the composer landed BELOW the fold -
         measured 2026-08-23: textarea at y=885 on an 862px viewport, out of
         reach, which is why staff reported threads they "cannot answer".
         Scrolling it into view on open was too fragile: any re-render or 5s
         poll undid it. With a thread open the list steps aside and the pane
         owns the viewport, so the reply box is reachable no matter how long
         the conversation is. */
      body.inbox-thread-open .bd-inbox-list { display: none; }
      /* Full-screen, not just "tall". A height of calc(100vh - Npx) still
         starts BELOW the page header and channel chips, so the composer stayed
         off-screen (measured y=974 on an 862px viewport). Pinning the pane to
         the viewport makes the reply box reachable regardless of what sits
         above it, and .bd-inbox-messages (flex:1, overflow-y:auto) scrolls the
         history inside. */
      body.inbox-thread-open .bd-inbox-pane {
        position: fixed;
        inset: 0;
        /* ABOVE the brand bar (z-index 100), not below it. At 40 the pane was
           pinned to inset:0 and therefore started UNDERNEATH the sticky header,
           which put the back button at y=18 inside the header's band. The
           button rendered, and measured as visible, but the header swallowed
           every tap on it: staff opened a conversation on a phone and had no
           way back to the list (reported 2026-09-12). A visibility check does
           not catch this; only a real click does. Modals sit at 320+ and still
           come out on top. */
        z-index: 120;
        min-height: 0;
        height: auto;
        max-height: none;
        border: none;
        border-radius: 0;
        background: var(--bg-elevated, #fff);
      }
      /* The pane above is opaque, full-screen and at 120; .toast-container
         (app.css) sits at 100, so while a thread was open EVERY toast the
         portal raises was drawn underneath it. Staff tapped Resolve, Assign
         or Snooze, the request failed, and nothing appeared at all. Exactly
         the same class of bug as the back button this block fixed: one thing
         layered over another. Modals stay above both at 200+, so their
         ordering is unchanged. */
      body.inbox-thread-open .toast-container { z-index: 130; }
      body.inbox-thread-open .bd-inbox-thread { height: 100%; }
      body.inbox-thread-open .bd-inbox-back { display: inline-flex; }
    }
    .bd-inbox-back { display: none; flex: none; padding: 4px 10px; font-size: 18px;
      line-height: 1; }
    /* Notification opt-in. Sits in the inbox toolbar; hidden entirely when the
       browser cannot do push at all, so it never advertises a dead control. */
    .bd-push-cta { display: none; align-items: center; gap: 8px; }
    .bd-push-cta.is-shown { display: inline-flex; }
    .bd-push-hint { display: none; margin: 8px 0 0; padding: 10px 12px;
      border: 1px solid rgba(127,127,127,.25); border-radius: var(--radius-md);
      font-size: 13px; line-height: 1.45; color: var(--text-secondary); }
    .bd-push-hint.is-shown { display: block; }
    /* Inbox fix S21: no opacity. At .65 the sentence that says the inbox is
       off was the quietest thing on a screen whose only job is to say it. The
       placeholders take the secondary grey; the disabled note is a notice,
       drawn like the panes it stands in for (surface, border, radius). */
    .bd-inbox-pane-empty, .bd-inbox-empty, .bd-inbox-disabled {
      padding: 32px 16px; text-align: center; font-size: 13px;
      color: var(--text-secondary); }
    .bd-inbox-disabled { color: var(--text-primary); background: var(--bg-elevated);
      border: 1px solid var(--border); border-radius: var(--radius-lg); }
    /* Intentional inbox empty state: bold title + guidance + optional CTA. */
    .bd-inbox-empty-state { padding: 40px 20px; text-align: center;
      display: flex; flex-direction: column; align-items: center; gap: 8px; }
    .bd-inbox-empty-title { font-size: var(--fs-md, 16px); font-weight: 700; color: var(--text-primary); }
    .bd-inbox-empty-sub { font-size: 13px; color: var(--text-secondary);
      max-width: 320px; line-height: 1.5; }
    .bd-inbox-empty-state .btn { margin-top: 6px; }
    .bd-inbox-thread { display: flex; flex-direction: column; flex: 1; min-height: 0; }
    .bd-inbox-thread-head { display: flex; align-items: center; gap: 10px;
      padding: 12px 14px; border-bottom: 1px solid rgba(127,127,127,.14); }
    .bd-inbox-thread-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; }
    .bd-inbox-older { display: block; width: calc(100% - 16px); margin: 8px;
      padding: 9px 10px; font-size: 12px; font-weight: 600; cursor: pointer;
      color: var(--text-secondary, #64748b); background: transparent;
      border: 1px dashed var(--border-control, #d0d5dd); border-radius: var(--radius-md, 10px); }
    /* Inbox fix addendum 8: "Show older" is aria-busy while it loads, never
       disabled (a disabled button drops keyboard focus to the page), so the
       old :disabled fade matched nothing and is gone. Busy: no hover change
       and the progress cursor; the label already reads "Loading…". */
    .bd-inbox-older:hover:not([aria-busy="true"]) { color: var(--text-primary, #0f172a);
      border-style: solid; }
    .bd-inbox-older[aria-busy="true"] { cursor: progress; }
    .bd-inbox-older-end { padding: 10px; text-align: center; font-size: 11px;
      color: var(--text-tertiary, #8a8f98); }
    .bd-inbox-thread-name { font-size: 14px; font-weight: 700; white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis; }
    /* Inbox fix S22: no opacity (.65 made the channel line 2.37:1). */
    .bd-inbox-thread-sub { font-size: 12px; white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis; }
    /* Inbox fix X5 / C2: the amber edge was rgba(245,165,36,.55), 1.37:1 on
       the thread header. --warning is the theme's amber in both palettes and
       holds 3:1 as an edge and 4.5:1 as text on the button's own fill. */
    #inbox-ai-toggle.is-ai-off { color: var(--warning); border-color: var(--warning); }
    #inbox-ai-toggle.is-ai-channel-off { color: var(--text-secondary, #64748b);
      border-color: rgba(127,127,127,.4); opacity: .75; }
    .bd-inbox-paused-note.is-channel-off { background: rgba(127,127,127,.12);
      color: var(--text-secondary, #64748b); }
    .bd-inbox-paused-note { padding: 8px 14px; font-size: 12px;
      background: rgba(245,165,36,.12); color: #b45309;
      border-bottom: 1px solid rgba(127,127,127,.12); }
    html[data-theme="dark"] .bd-inbox-paused-note { color: #fbbf24; }
    /* Staff assignment: header dropdown, row chip, team table. */
    .bd-inbox-assign-select { height: 30px; padding: 2px 8px; font-size: 12px;
      max-width: 160px; }
    .bd-inbox-assign-select[hidden] { display: none !important; }
    .bd-inbox-assignee { display: inline-block; margin-top: 4px; margin-left: 6px;
      font-size: 11px; font-weight: 600; padding: 1px 8px; border-radius: 999px;
      background: rgba(99,102,241,.16); color: #4338ca; vertical-align: middle; }
    html[data-theme="dark"] .bd-inbox-assignee { color: #a5b4fc; }
    .bd-inbox-assignee.is-unassigned { background: rgba(127,127,127,.16);
      color: var(--text-secondary, #64748b); }
    .bd-inbox-team-wrap { max-height: 60vh; overflow-y: auto; }
    .bd-inbox-team-table { width: 100%; border-collapse: collapse; font-size: 13px; }
    .bd-inbox-team-table th, .bd-inbox-team-table td { text-align: left;
      padding: 8px 10px; border-bottom: 1px solid rgba(127,127,127,.14); }
    .bd-inbox-team-table th { font-size: 11px; text-transform: uppercase;
      letter-spacing: .04em; }
    .bd-inbox-team-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
    .bd-inbox-team-role { font-size: 11px; color: var(--text-secondary); margin-left: 6px; }
    /* W4-a: real-time presence + edit-collision warning. */
    .bd-inbox-presence-note { padding: 6px 14px; font-size: 12px;
      background: rgba(99,102,241,.10); color: #4338ca;
      border-bottom: 1px solid rgba(127,127,127,.12); }
    html[data-theme="dark"] .bd-inbox-presence-note { color: #a5b4fc; }
    /* Inbox fix: the 7px anonymous-dot version of .bd-inbox-viewer-dot that
       stood here loaded after app.css's wave-4 initials badge (18px, "who
       else is in this thread") and squashed it to 18x7 with the letter
       spilling out. The badge's own rule in app.css decides it now. */
    /* Roomier messages: bigger text (15px) + chat-app bubbles with a tail. */
    .bd-inbox-messages { flex: 1; overflow-y: auto; padding: var(--space-5);
      display: flex; flex-direction: column; gap: var(--space-3); }
    .bd-inbox-msg { max-width: 70%; display: flex; flex-direction: column; }
    .bd-inbox-msg.is-in { align-self: flex-start; align-items: flex-start; }
    .bd-inbox-msg.is-out { align-self: flex-end; align-items: flex-end; }
    .bd-inbox-msg-bubble { padding: 10px 14px; border-radius: 16px; font-size: 15px;
      line-height: 1.5; background: rgba(127,127,127,.10); overflow-wrap: anywhere; }
    .bd-inbox-msg.is-out .bd-inbox-msg-bubble { background: var(--brand-soft);
      border-bottom-right-radius: 6px; }
    .bd-inbox-msg.is-in .bd-inbox-msg-bubble { border-bottom-left-radius: 6px; }
    .bd-inbox-msg.is-agent .bd-inbox-msg-bubble { background: rgba(52,211,153,.16); }
    .bd-inbox-msg-bubble p { margin: 0 0 6px; }
    .bd-inbox-msg-bubble p:last-child { margin-bottom: 0; }
    /* Inbox fix C5 / C1: no opacity (.55 took the meta line to 2.11:1 and the
       "Not delivered" mark to 1.54:1 in dark; the ticks inherit it). */
    .bd-inbox-msg-meta { font-size: 11px; margin-top: 3px; }
    /* Inbox fix S7c / S23 (interface I4): the send failure is the one line
       that says a reply did not go. #ef4444 was 3.76:1 on white; --danger is
       5.38:1 light, 4.99:1 dark. It reads at the composer's own size
       (--fs-base; 16px on phones, below) rather than 12px. */
    .bd-inbox-reply-error { padding: 6px 14px; font-size: var(--fs-base, 14px); font-weight: 500;
      color: var(--danger, #d70015); }
    /* The list-load error (app.js loadInbox) carries both classes: the error's
       colour and type, and the empty state's box (32px 16px, the rule above
       S21), which the error's smaller padding would otherwise replace. */
    .bd-inbox-empty.bd-inbox-reply-error { padding: 32px 16px; }
    .bd-inbox-replybox { display: flex; gap: 10px; padding: 12px 14px;
      border-top: 1px solid rgba(127,127,127,.14); align-items: flex-end; }
    .bd-inbox-textarea { flex: 1; resize: none; font: inherit; font-size: 15px;
      padding: 10px 12px; min-height: 44px; border-radius: var(--radius-md);
      border: 1px solid rgba(127,127,127,.25); background: transparent; color: inherit; }
    .bd-inbox-textarea:focus { outline: none; border-color: var(--brand); }
    /* Phone composer (2026-08-04). The reply bar is one flex row - textarea
       plus attach/send - which squeezed the textarea to 123px on a 358px
       screen. Give it a full row and let the buttons wrap underneath. Must sit
       after the .bd-inbox-textarea base rule: the media query adds no
       specificity, so `flex:1` above would otherwise win on source order. */
    @media (max-width: 900px) {
      .bd-inbox-replybox { flex-wrap: wrap; }
      /* Lift the composer out of the phone's bottom gesture strip (2026-09-19).
         Measured at iPhone size: Send ended 12pt above the screen edge, so its
         lower half sat inside the 34pt strip where iOS watches for the swipe to
         go home, and a thumb, which lands low on a button, was sometimes taken
         for the start of that swipe: "Send needs several taps". Only with the
         keyboard DOWN, which is when the bar drops to the edge. A 40px floor
         clears the strip whether or not env() reports the inset (it reads 0
         without viewport-fit=cover, which this page deliberately does not set),
         and Android's gesture bar gets the same clearance. */
      .bd-inbox-replybox {
        padding-bottom: max(40px, calc(12px + env(safe-area-inset-bottom, 0px)));
      }
      /* order:-1 puts the text box on the first line, so EVERY button lands on
         one row beneath it instead of some above and some below. Measured
         2026-09-13 on a 412px screen before this: fast-replies, attach and
         template on row one, the text box on row two, and Send alone on row
         three at x=14, hard left, which is what the owner reported. The auto
         margin goes on Send itself, not on Later: Later is display:none on a
         channel that cannot schedule, and an auto margin on a hidden item
         pushes nothing. */
      .bd-inbox-textarea { flex: 1 0 100%; width: 100%; order: -1; }
      #inbox-send-btn { margin-left: auto; }
    }

    /* ------------------------------------------------------------------
       Phone filter sheet (2026-09-13, owner: "too many button filters,
       combine it into filter button"). Four rows of chips stood between
       opening the inbox and seeing a conversation. Search and one Filters
       button stay visible; everything else collapses.
       Desktop is untouched: the toggle is hidden and the sheet is a plain
       block, so a laptop sees exactly what it saw before.
       ------------------------------------------------------------------ */
    /* Thread actions: one menu at every width (inbox fix S3 / G1 / G1b / M8,
       2026-09-21). Above 900px the wrapper used to be display:contents, so
       all eight actions sat in the header's one flex row beside the name.
       With every capability on they needed 765px in English and 1145px in
       Georgian against a 688-762px header: the name and channel line were
       crushed to 0px, the assign select to 18px, and Profile, Snooze and
       Resolve were clipped out of reach by the pane (GEOMETRY S1, STATES
       #3). The row now keeps only the back button, the name, the assign
       select and the AI switch; everything else is in the More menu, whose
       open/close script is width-agnostic (app.js "setMore").
       The scoped [hidden] rule is the one place a blanket hidden rule is
       safe: every child here is toggled with el.hidden (checked one by one,
       none is revealed by style.display, which is what makes the global
       version unsafe elsewhere) and .btn's display would otherwise keep a
       gated button on screen. Direct children only, so it cannot reach into
       the snooze menu or anything a script reveals. */
    .bd-inbox-more { display: inline-block; position: relative; flex: none; }
    .bd-inbox-more-menu > [hidden] { display: none !important; }
    /* Drawn as the header's other secondary button (.btn-secondary.btn-sm,
       app.linear.css: 28px, 13px/600, --radius-md, --border-control). */
    .bd-inbox-more-btn {
      display: inline-flex;
      align-items: center;
      height: 28px;
      padding: 0 11px;
      font: inherit;
      font-size: var(--fs-sm, 13px);
      font-weight: 600;
      line-height: 1;
      color: var(--text-primary, inherit);
      background: var(--bg-elevated, #fff);
      border: 1px solid var(--border-control, rgba(127,127,127,.25));
      border-radius: var(--radius-md, 10px);
      cursor: pointer;
      white-space: nowrap;
    }
    .bd-inbox-more-btn:hover { background: var(--bg-hover); }
    .bd-inbox-more-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
    .bd-inbox-more-btn[aria-expanded="true"] { border-color: var(--brand); }
    .bd-inbox-more-menu {
      display: none;
      position: absolute;
      right: 0;
      top: calc(100% + 6px);
      /* Under the snooze sub-menu's own z-index:20 so its options are not
         painted behind this list, and above the thread body. */
      z-index: 15;
      min-width: 190px;
      padding: 6px;
      background: var(--bg-elevated, #fff);
      border: 1px solid var(--border, rgba(127,127,127,.25));
      border-radius: var(--radius-md, 10px);
      box-shadow: 0 10px 28px rgba(0,0,0,.22);
    }
    .bd-inbox-more-menu.is-open { display: block; }
    /* One row per action, reading as a list rather than a row of chips. */
    .bd-inbox-more-menu > .btn,
    .bd-inbox-more-menu .bd-inbox-snooze-wrap > .btn {
      display: flex;
      justify-content: flex-start;
      width: 100%;
      margin: 0;
      border: 0;
      background: transparent;
      border-radius: var(--radius-sm, 6px);
      box-shadow: none;
      padding: 9px 10px;
      font-size: 13px;
    }
    /* The wrap carries an INLINE display:inline-block (portal_shell.html),
       which only !important beats; :not([hidden]) keeps the gate above in
       charge when inbox_snooze is off. */
    .bd-inbox-more-menu > .bd-inbox-snooze-wrap:not([hidden]) { display: block !important; width: 100%; }

    /* ------------------------------------------------------------------
       Phone type scale (2026-09-13, owner: "the text can be a bit bigger").
       Measured before this: conversation names 14px, previews 13px, times
       11px, message text 15px. That is a desktop scale shown on a 412px
       screen. The phone norms this targets: iOS system body text is 17px, the
       browser default is 16px, and Apple's minimum tap target is 44px.

       TWO REAL FAULTS came out of the same measurement and are fixed here:
         * the composer, the search box and the assign box were all under 16px,
           which is the threshold where Safari on iPhone ZOOMS THE PAGE as soon
           as you tap the field. That is the jump-and-pinch-back behaviour.
           Every text field on a phone is now at least 16px.
         * rows in the new More menu were 28px tall against a 44px minimum.

       Phone only. The desktop scale is deliberately untouched.
       ------------------------------------------------------------------ */
    @media (max-width: 900px) {
      /* The conversation list */
      .bd-inbox-row-name { font-size: 16px; }
      .bd-inbox-row-preview { font-size: 15px; }
      .bd-inbox-row-time { font-size: 13px; }
      .bd-inbox-aibadge, .bd-inbox-assignee, .bd-inbox-statusbadge,
      .bd-inbox-slabadge, .bd-inbox-winchip { font-size: 12px; }
      .bd-inbox-topic-chip { font-size: 11px; }
      .bd-inbox-empty-title { font-size: 17px; }
      .bd-inbox-empty-sub { font-size: 15px; }

      /* Inside a conversation */
      .bd-inbox-thread-name { font-size: 17px; }
      .bd-inbox-thread-sub { font-size: 13px; }
      .bd-inbox-msg-bubble { font-size: 17px; }
      .bd-inbox-msg-meta { font-size: 12px; }
      .bd-inbox-paused-note, .bd-inbox-presence-note { font-size: 13px; }
      .bd-inbox-reply-error { font-size: var(--fs-md, 16px); }
      .bd-media-caption { font-size: 15px; }

      /* Anything you type into: 16px or Safari zooms the page */
      .bd-inbox-textarea { font-size: 16px; }
      #inbox-search { font-size: 16px; }
      .bd-inbox-find .input { font-size: 16px; }
      .bd-inbox-assign-select { font-size: 16px; height: 36px; }

      /* Controls, sized for a thumb */
      /* Same !important reason as the menu rows: the theme pins .btn heights.
         Send is the most-tapped control in the product. */
      #inbox-send-btn, #inbox-later-btn, #inbox-attach-btn, #inbox-canned-btn,
      #inbox-template-btn, .bd-inbox-back {
        height: auto !important;
        min-height: 44px;
        font-size: 16px;
      }
      #inbox-send-btn, #inbox-later-btn { padding: 10px 18px !important; }
      /* Live-2 item 3: at this size (16px, 10px/18px padding) "Sending…"
         measures 106.06px EN / 133.55px KA (the wider) -- app.linear.css's
         desktop 118px floor is too narrow here. 138px clears both.
         !important for the same reason as this block's other overrides:
         app.linear.css loads after this file and its unscoped
         `#inbox-send-btn { min-width: 118px }` is the same specificity
         (one id), so it would otherwise win on source order regardless of
         this @media block. */
      #inbox-send-btn { min-width: 138px !important; }
      .bd-inbox-back { font-size: 20px; padding: 4px 14px !important; }
      .bd-inbox-more-btn { font-size: 15px; padding: 9px 14px; height: auto; min-height: 44px; }
      /* !important is required, not preferred: app.linear.css pins
         `.btn-sm { height: 28px !important; padding: 0 11px !important }`,
         which is why the first attempt changed the text size and left the row
         28px tall. Measured, then matched. */
      .bd-inbox-more-menu > .btn,
      .bd-inbox-more-menu .bd-inbox-snooze-wrap > .btn {
        font-size: 15px;
        height: auto !important;
        min-height: 44px;        /* Apple's minimum tap target */
        padding: 12px 12px !important;
        justify-content: flex-start;
      }
      .bd-inbox-snooze-opt { font-size: 15px !important; padding: 12px 12px !important; }
      .bd-filters-sheet .chip { font-size: 14px; padding: 8px 14px; }
    }

    /* NOT a .chip. It looked like one, so it wore the class, and then two
       stylesheets' `.chip { display: inline-flex }` fought this rule for the
       one property that decides whether the button exists on a laptop. It
       kept winning even at higher specificity, measured in chromium
       2026-09-13. The button carries its own class only, so nothing competes;
       the look below is the chip look, written out. */
    .bd-filters-toggle {
      display: none;
      align-items: center;
      gap: 6px;
      padding: 6px 14px;
      font: inherit;
      font-size: 13px;
      font-weight: 500;
      color: var(--text-secondary, inherit);
      background: var(--surface-1, rgba(0,0,0,.025));
      border: 1px solid var(--border-control, rgba(127,127,127,.25));
      border-radius: var(--radius-full, 9999px);
      cursor: pointer;
      white-space: nowrap;
    }
    .filter-row-top { display: flex; align-items: center; gap: var(--space-3); }
    .filter-row-top .filter-search { flex: 1; min-width: 0; }
    .bd-filter-count { margin-left: 6px; font-variant-numeric: tabular-nums; }
    @media (max-width: 900px) {
      /* Sized here, not in the type-scale block above: the base
         .bd-filters-toggle rule is defined further down this file and would
         win on source order. */
      .bd-filters-toggle { display: inline-flex; flex: none;
        font-size: 15px; padding: 9px 14px; }
      .bd-filters-toggle[aria-expanded="true"] { border-color: var(--brand); }
      .bd-filters-sheet { display: none; }
      /* flex, not block (Live-2 item 1): app.css now lays the sheet out as
         a column with a gap between its two rows; overriding only `display`
         here keeps that gap instead of collapsing it back to a block's 0. */
      .bd-filters-sheet.is-open { display: flex; }
      /* Inside the sheet the rows stack, so each group reads as a group
         instead of four groups running together across wrapped lines. */
      .bd-filters-sheet .filter-row { flex-direction: column;
        align-items: stretch; gap: var(--space-2); }
      .bd-filters-sheet .chip-group { flex-wrap: wrap; }

      /* "Select a conversation" was a 60vh empty box under a list clipped to
         40vh, so most of the screen said nothing (owner, 2026-09-13). With no
         thread open the pane is gone and the list gets the whole page; the
         40vh clamp existed only to keep the pane's composer reachable, which
         does not apply when there is no pane. */
      body:not(.inbox-thread-open) .bd-inbox-pane { display: none; }
      body:not(.inbox-thread-open) .bd-inbox-list { max-height: none; }

      /* Tap targets (owner, 2026-09-13: "fix number 3"). Every chip measured
         26px tall on a phone, well under the 44px a thumb needs, and nineteen
         of them stack in the filter sheet.

         !important is REQUIRED here, not sloppiness. app.linear.css:880 has a
         fifteen-selector pill rule that ends with
             min-height: 0 !important; height: auto !important;
             padding: 4px 11px !important; font-size: 11.5px !important;
         so a later, more specific, perfectly correct rule loses to it silently.
         That same rule is why the Filters button once refused to hide on
         desktop for an entire round with no explanation, and why the 14px
         font-size set for this sheet a few lines above never took either: the
         chips are still rendering at 11.5px.

         Phone widths only. The desktop header packs these controls into one
         row and both desktop probes verify it unchanged. */
      /* Inbox fix M13 (decision 1): .chip left this rule. With the pill
         block no longer !important, the 44px chip rule lives in
         app.linear.css after the pill component, without !important. */
      .bd-filters-toggle {
        min-height: 44px !important;
        height: auto !important;
        font-size: 14px !important;
        padding-top: 6px !important;
        padding-bottom: 6px !important;
      }
      /* Catches any .btn (as opposed to .chip) that ends up in this sheet,
         since a .btn does not get the chip-row's own height rule. The
         saved-view button that motivated this rule was removed 2026-09-21
         (board item 24); left in place in case another .btn lands here. */
      .bd-filters-sheet .btn-sm { min-height: 44px !important; height: auto !important; }
    }
    /* Inline media attachments (image / audio / video) inside a message
       bubble, shared by the inbox thread and the conversation detail panel. */
    .bd-media-img { max-width: 280px; max-height: 280px; border-radius: var(--radius-md);
      display: block; cursor: zoom-in; }
    .bd-media-imglink { display: inline-block; }
    .bd-media-audio { width: 240px; max-width: 100%; margin-top: 2px; }
    .bd-media-video { max-width: 320px; width: 100%; border-radius: var(--radius-md);
      display: block; }
    .bd-media-caption { margin-top: 6px; font-size: 14px; line-height: 1.45;
      overflow-wrap: anywhere; }
    /* I2 customer-profile slide-over sections (scoped bd-cp-* classes; app.css
       must not be edited, so styles live here like bd-inbox-css). */
    .bd-cp-block { margin-top: 14px; }
    .bd-cp-block:first-child { margin-top: 4px; }
    .bd-cp-h { font-size: 12px; font-weight: 700; letter-spacing: .01em;
      text-transform: uppercase; color: var(--text-secondary); margin-bottom: 7px; }
    .bd-cp-row { display: flex; justify-content: space-between; align-items: baseline;
      gap: 10px; width: 100%; padding: 7px 10px; border-radius: var(--radius-md, 10px); text-align: left;
      background: var(--surface-2, rgba(127,127,127,.06)); margin-top: 6px;
      border: 0; font: inherit; color: inherit; }
    .bd-cp-row-main { font-size: 13px; font-weight: 600; overflow-wrap: anywhere; }
    .bd-cp-row-sub { font-size: 12px; color: var(--text-secondary); white-space: nowrap; }
    button.bd-cp-row.is-link { cursor: pointer; }
    button.bd-cp-row.is-link:hover { background: var(--surface-3, rgba(127,127,127,.12)); }
    .bd-cp-note { font-size: 12.5px; color: var(--text-secondary); line-height: 1.45; }
    /* Clickable customer-line pill on the Conversations detail (I2): the .pill
       class carries no border, so strip the native button chrome. */
    button.conv-contact { border: 0; font: inherit; cursor: pointer; }
    button.conv-contact.is-link:hover { text-decoration: underline; }
    /* Tabbed customer profile (2026-07-05 UX round 2): tab bar + panels inside
       the conv-panel slide-over body. Owner ask: history no longer forces a
       long scroll - Overview / Activity / Memory / Notes tabs. */
    .bd-pf-tabs { display: flex; gap: 2px; flex-wrap: wrap;
      border-bottom: 1px solid var(--border, rgba(127,127,127,.2));
      margin: 0 0 12px; position: sticky; top: 0; z-index: 2;
      background: var(--bg-elevated, var(--surface-1, #fff)); }
    .bd-pf-tab { appearance: none; -webkit-appearance: none; border: 0;
      background: transparent; font: inherit; font-size: 13px; font-weight: 600;
      color: var(--text-secondary, #64748b); padding: 9px 12px; cursor: pointer;
      border-bottom: 2px solid transparent; margin-bottom: -1px;
      /* M22: tab-like controls elsewhere are --radius-md; the top corners
         take it and the bottom stays square for the underline. */
      border-radius: var(--radius-md, 10px) var(--radius-md, 10px) 0 0; }
    .bd-pf-tab:hover { color: var(--text-primary, inherit); }
    .bd-pf-tab[aria-selected="true"] { color: var(--brand, #2563eb);
      border-bottom-color: var(--brand, #2563eb); }
    .bd-pf-tab:focus-visible { outline: 2px solid var(--brand, #2563eb);
      outline-offset: -2px; }
    .bd-pf-panel[hidden] { display: none; }
    .bd-pf-panel { animation: bd-pf-fade .15s ease; }
    .bd-pf-panel:focus { outline: none; }
    @keyframes bd-pf-fade { from { opacity: .35; } to { opacity: 1; } }
    .bd-pf-empty { font-size: 12.5px; color: var(--text-secondary); padding: 12px 2px; }
/* ---- end of was <style id="bd-inbox-css"> ---- */

/* ---- was <style id="bd-camp-css"> at app.html:603-663 ---- */
  /* Campaigns styles - same convention as bd-inbox-css: scoped bd-camp-*
       classes in an inline block. */
    .bd-camp-grid { display: grid; grid-template-columns: minmax(0,1fr); gap: 16px; }
    @media (min-width: 1100px) { .bd-camp-grid { grid-template-columns: minmax(0,3fr) minmax(0,2fr); } }
    .bd-camp-row { padding: 12px 14px; border-bottom: 1px solid rgba(127,127,127,.12);
      cursor: pointer; }
    .bd-camp-row:last-child { border-bottom: none; }
    .bd-camp-row-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
    .bd-camp-name { font-weight: 600; font-size: 14px; }
    .bd-camp-meta { font-size: 12px; opacity: .65; margin-top: 4px; }
    .bd-camp-badge { font-size: 11px; padding: 2px 8px; border-radius: var(--radius-full);
      letter-spacing: .02em; font-weight: 600; text-transform: uppercase; }
    .bd-camp-badge.q { background: rgba(245,158,11,.15); color: #d97706; }
    .bd-camp-badge.s { background: var(--brand-soft); color: var(--brand); }
    .bd-camp-badge.ok { background: rgba(52,211,153,.15); color: #10b981; }
    .bd-camp-badge.err { background: rgba(239,68,68,.14); color: #ef4444; }
    .bd-camp-badge.off { background: rgba(127,127,127,.15); color: inherit; opacity: .75; }
    .bd-camp-actions { display: flex; gap: 6px; margin-top: 8px; }
    .bd-camp-detail { font-size: 12px; margin-top: 8px; padding: 8px 10px;
      border-radius: var(--radius-md); background: rgba(127,127,127,.08); }
    .bd-camp-empty { padding: 28px 14px; text-align: center; font-size: 13px; opacity: .6; }
    .bd-camp-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.55);
      display: flex; align-items: center; justify-content: center;
      padding: 24px 16px; z-index: 320; }
    .bd-camp-backdrop[hidden] { display: none; }
    .bd-camp-modal { position: relative; width: 100%; max-width: 620px;
      max-height: calc(100vh - 48px); overflow-y: auto; border-radius: var(--radius-lg);
      background: var(--bg-elevated, #fff); color: var(--text-primary, #0f172a);
      border: 1px solid var(--border, rgba(127,127,127,.25));
      padding: 20px 22px; box-shadow: var(--shadow-lg); }
    .bd-camp-modal h2 { margin: 0 0 14px; font-size: 16px; color: var(--text-primary); }
    .bd-camp-close { position: absolute; top: 12px; right: 14px; border: none;
      background: transparent; color: var(--text-secondary, #64748b);
      font-size: 24px; line-height: 1; cursor: pointer; padding: 4px 8px;
      border-radius: var(--radius-md); }
    .bd-camp-close:hover { background: var(--bg-hover, rgba(127,127,127,.12));
      color: var(--text-primary); }
    .bd-camp-field { margin-bottom: 12px; }
    /* Inbox fix G5: this Campaigns label style reached every .bd-camp-field
       in the portal, including the inbox settings modal, whose seat rows are
       <label class="bd-inbox-seat">: display:block, capitals and 12px beat
       .bd-inbox-seat { display:flex } (0,1,1 over 0,1,0). Scoped to the two
       Campaigns dialogs with :where(), which adds no specificity, so inside
       Campaigns nothing changes. */
    :where(#camp-modal) .bd-camp-field label { display: block; font-size: 12px; font-weight: 600;
      color: var(--text-secondary, inherit); margin-bottom: 4px;
      text-transform: uppercase; letter-spacing: .03em; }
    .bd-camp-field .input, .bd-camp-field select, .bd-camp-field textarea {
      width: 100%; font: inherit; font-size: 13px; padding: 8px 10px;
      border-radius: var(--radius-md); border: 1px solid var(--border, rgba(127,127,127,.3));
      background: var(--bg-subtle, transparent); color: var(--text-primary, inherit);
      box-sizing: border-box; }
    .bd-camp-field select option { background: var(--bg-elevated, #fff);
      color: var(--text-primary, #0f172a); }
    .bd-camp-field textarea { resize: vertical; min-height: 84px; }
    .bd-camp-hint { font-size: 12px; color: var(--text-secondary, inherit);
      margin-top: 5px; line-height: 1.45; }
    .bd-camp-hint code { font: inherit; background: none; padding: 0; }
    .bd-camp-preview { font-size: 13px; padding: 9px 12px; border-radius: var(--radius-sm);
      background: var(--brand-soft); margin-bottom: 12px; }
    .bd-camp-modal-foot { display: flex; gap: 8px; justify-content: flex-end;
      margin-top: 16px; flex-wrap: wrap; }
    .bd-camp-test { display: flex; gap: 8px; align-items: center; }
    .bd-camp-test .input { flex: 1; }
    .bd-camp-tplbody { font-size: 12px; opacity: .75; margin-top: 4px; white-space: pre-wrap; }
    .bd-camp-reject { font-size: 12px; color: #ef4444; margin-top: 3px; }
    .bd-camp-disabled { padding: 24px; text-align: center; font-size: 13px; opacity: .65; }
/* ---- end of was <style id="bd-camp-css"> ---- */

/* ---- LIVE5 L5D: one guided "Send a message" wizard, replacing the old
   "New Template" / "New Campaign" pair (CAMPAIGN-RESEARCH.md section 3). ---- */
    .bd-camp-preview { white-space: pre-line; }
    .camp-wiz-label { font-size: 12px; font-weight: 600; color: var(--text-secondary, inherit);
      margin-bottom: 6px; text-transform: uppercase; letter-spacing: .03em; }
    .camp-wiz-count { font-size: 12.5px; color: var(--text-secondary, inherit); margin-bottom: 10px; }
    .camp-aud-choices { display: flex; flex-direction: column; gap: 2px; }
    .camp-aud-choice { display: flex; align-items: center; gap: 10px; padding: 9px 4px;
      border-radius: var(--radius-md); cursor: pointer; font-size: 13.5px; }
    .camp-aud-choice:hover { background: var(--bg-hover, rgba(127,127,127,.08)); }
    .camp-aud-choice input[type="radio"] { accent-color: var(--brand); flex: none;
      width: 16px; height: 16px; cursor: pointer; }
    .camp-aud-choice input[type="radio"]:disabled { cursor: not-allowed; }
    .camp-aud-choice input[type="radio"]:disabled ~ .camp-aud-choice-label { opacity: .5; }
    .camp-aud-choice-label { flex: 1; }
    .camp-aud-count { font-size: 12.5px; color: var(--text-secondary, inherit); flex: none; }
    /* "More options" reuses the existing muted <details> chevron
       (.chmg-tech, app.inbox-legacy.css ~1405) unchanged; only its own
       vertical rhythm is added here. */
    .bd-camp-more { margin: 6px 0 12px; }
    .bd-camp-more[open] { padding-bottom: 4px; }
    .camp-chip-btn { margin-bottom: 6px; }
    .camp-wiz-ready-list { display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px; }
    .camp-wiz-ready-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px;
      border: 1px solid var(--border, rgba(127,127,127,.25)); border-radius: var(--radius-md);
      cursor: pointer; font-size: 13.5px; }
    .camp-wiz-ready-row.is-picked { border-color: var(--brand); background: var(--brand-soft); }
    .camp-wiz-ready-row input[type="radio"] { accent-color: var(--brand); flex: none; }
    .camp-wiz-ready-row input[type="radio"]:disabled { cursor: not-allowed; }
    .camp-wiz-ready-name { flex: 1; font-weight: 600; }
    .camp-wiz-ready-status { font-size: 12px; color: var(--text-secondary, inherit); flex: none; }
    .bd-camp-wiz-nav { display: flex; gap: 8px; justify-content: space-between;
      margin-top: 16px; flex-wrap: wrap; }
/* ---- end LIVE5 L5D wizard ---- */

/* ---- was <style id="bd-auto-css"> at app.html:666-751 ---- */
  /* Automation (sequences + order alerts) styles - scoped bd-auto-* in an
       inline block, same convention as bd-camp-css. */
    .bd-auto-disabled { padding: 24px; text-align: center; font-size: 13px; opacity: .65; }
    .bd-auto-hint { font-size: 12px; opacity: .72; line-height: 1.5; }
    .bd-auto-empty { padding: 22px 4px; text-align: center; font-size: 13px; opacity: .6; }
    .bd-auto-seq-item { display: flex; justify-content: space-between; align-items: center;
      gap: 12px; padding: 12px 0; border-bottom: 1px solid rgba(127,127,127,.12); }
    .bd-auto-seq-item:last-child { border-bottom: 0; }
    /* Narrow screens: stack the title block above the action buttons so the
       sequence name stops squeezing into one word per line. */
    @media (max-width: 520px) {
      .bd-auto-seq-item { flex-wrap: wrap; }
      .bd-auto-seq-item > div:first-child { flex: 1 1 100%; min-width: 0; }
      .bd-auto-seq-actions { flex-wrap: wrap; }
    }
    .bd-auto-seq-meta { font-size: 12px; opacity: .7; margin-top: 2px; }
    .bd-auto-badge { font-size: 11px; padding: 2px 8px; border-radius: 999px; font-weight: 600; }
    .bd-auto-badge.on { background: rgba(16,185,129,.16); color: #10b981; }
    .bd-auto-badge.off { background: rgba(127,127,127,.16); }
    .bd-auto-seq-actions { display: flex; gap: 6px; flex: none; }
    .bd-auto-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
    .bd-auto-row > label { width: 110px; font-size: 12px; font-weight: 600; opacity: .7; flex: none; }
    .bd-auto-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px;
      background: rgba(127,127,127,.1); padding: 3px 8px; border-radius: 6px; word-break: break-all; }
    .bd-auto-secret-reveal { margin-top: 10px; padding: 10px 12px; border-radius: 8px;
      background: rgba(245,158,11,.1); font-size: 12px; }
    .bd-auto-secret-reveal .bd-auto-code { display: inline-block; margin-top: 6px; }
    .bd-auto-msg-row { margin-bottom: 12px; }
    .bd-auto-msg-row > label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 4px; }
    .bd-auto-msg-row textarea { width: 100%; min-height: 52px; resize: vertical; font-size: 13px;
      padding: 8px 10px; border-radius: 8px; box-sizing: border-box; }
    .bd-auto-note { margin-top: 10px; padding: 10px 12px; border-radius: 8px;
      background: rgba(245,158,11,.1); font-size: 12px; line-height: 1.5; }
    .bd-auto-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.5);
      display: flex; align-items: center; justify-content: center; z-index: 1200; padding: 16px; }
    /* Same fix pattern as the security-gate block at the top of this file and
       .bd-camp-backdrop[hidden]: the base rule sets display:flex, which beats
       the UA stylesheet's [hidden]{display:none}, so the modal would render on
       every page and the close button would do nothing. Force the attribute to
       win. */
    .bd-auto-modal-backdrop[hidden] { display: none !important; }
    /* Use the real portal design tokens (there is no --card token; the old
       var(--card,#fff) always fell back to white, which on the dark theme put
       near-white inherited text on a white surface). Match the .bd-camp-modal
       token usage: --bg-elevated surface, --text-primary text, --border. */
    .bd-auto-modal { background: var(--bg-elevated, #fff); color: var(--text-primary, #0f172a);
      border: 1px solid var(--border, rgba(127,127,127,.25)); border-radius: 14px; width: 100%;
      max-width: 560px; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow-lg, 0 20px 60px rgba(0,0,0,.3)); }
    .bd-auto-modal-head, .bd-auto-modal-foot { display: flex; justify-content: space-between;
      align-items: center; padding: 14px 18px; }
    .bd-auto-modal-foot { gap: 8px; justify-content: flex-end; border-top: 1px solid var(--border, rgba(127,127,127,.12)); }
    .bd-auto-modal-head { border-bottom: 1px solid var(--border, rgba(127,127,127,.12)); }
    .bd-auto-modal-head strong { color: var(--text-primary); }
    .bd-auto-modal-x { background: none; border: 0; font-size: 22px; cursor: pointer; opacity: .6;
      line-height: 1; color: var(--text-secondary, #64748b); }
    .bd-auto-modal-x:hover { opacity: 1; color: var(--text-primary); }
    .bd-auto-modal-body { padding: 16px 18px; }
    .bd-auto-field { display: block; margin-bottom: 14px; }
    .bd-auto-field > span { display: block; font-size: 12px; font-weight: 600; margin-bottom: 5px;
      color: var(--text-secondary, inherit); }
    .bd-auto-field input[type=text], .bd-auto-field select { width: 100%; padding: 8px 10px;
      border-radius: 8px; font-size: 13px; box-sizing: border-box;
      border: 1px solid var(--border, rgba(127,127,127,.3)); background: var(--bg-subtle, transparent);
      color: var(--text-primary, inherit); }
    .bd-auto-field select option { background: var(--bg-elevated, #fff); color: var(--text-primary, #0f172a); }
    .bd-auto-step { display: flex; gap: 8px; align-items: flex-start; margin-bottom: 8px; }
    .bd-auto-step .bd-auto-delay { width: 120px; flex: none; }
    .bd-auto-step .bd-auto-delay input { width: 64px; padding: 6px 8px; border-radius: 6px; font-size: 13px;
      border: 1px solid var(--border, rgba(127,127,127,.3)); background: var(--bg-subtle, transparent);
      color: var(--text-primary, inherit); box-sizing: border-box; }
    .bd-auto-step textarea, .bd-auto-msg-row textarea { border: 1px solid var(--border, rgba(127,127,127,.3));
      background: var(--bg-subtle, transparent); color: var(--text-primary, inherit); }
    .bd-auto-step-x { background: none; border: 0; cursor: pointer; opacity: .55; font-size: 18px; flex: none;
      color: var(--text-secondary, inherit); }
    /* Per-step WhatsApp-template picker: full-width row under the message. */
    .bd-auto-step { flex-wrap: wrap; }
    .bd-auto-step .bd-auto-step-tplrow { flex-basis: 100%; display: flex; gap: 8px;
      margin-top: 2px; }
    .bd-auto-step .bd-auto-step-tpl, .bd-auto-step .bd-auto-step-tplparams {
      flex: 1; min-width: 0; padding: 6px 8px; border-radius: 6px; font-size: 13px;
      border: 1px solid var(--border, rgba(127,127,127,.3));
      background: var(--bg-subtle, transparent); color: var(--text-primary, inherit); }
    .bd-auto-step .bd-auto-step-tpl option { background: var(--bg-elevated, #fff);
      color: var(--text-primary, #0f172a); }
    .bd-auto-check { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 10px; }
    .bd-auto-check input { width: auto; }
/* ---- end of was <style id="bd-auto-css"> ---- */

/* ---- was <style id="bd-inbox2-css"> at app.html:754-792 ---- */
  /* Inbox stage 2 styles (notes panel + canned replies) - same convention
       as bd-inbox-css: scoped bd-inbox2-* classes in an inline block. */
    .bd-inbox2-notes { padding: 10px 14px; border-bottom: 1px solid rgba(127,127,127,.14);
      background: rgba(245,158,11,.06); max-height: 260px; overflow-y: auto; }
    .bd-inbox2-notes[hidden] { display: none !important; }
    .bd-inbox2-notes-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
    .bd-inbox2-internal-tag { display: inline-block; font-size: 11px; font-weight: 700;
      letter-spacing: .05em; text-transform: uppercase; padding: 1px 6px; border-radius: var(--radius-sm);
      background: rgba(245,158,11,.22); color: #b45309; flex: none; }
    html[data-theme="dark"] .bd-inbox2-internal-tag { color: #fbbf24; }
    .bd-inbox2-notes-hint { font-size: 12px; color: var(--text-secondary); }
    .bd-inbox2-notes-list { display: flex; flex-direction: column; gap: 8px; }
    .bd-inbox2-notes-empty { font-size: 12px; color: var(--text-secondary); padding: 4px 0; }
    .bd-inbox2-note { background: rgba(245,158,11,.10); border: 1px dashed rgba(245,158,11,.35);
      border-radius: var(--radius-md); padding: 7px 10px; }
    .bd-inbox2-note-meta { display: flex; align-items: center; gap: 6px;
      font-size: 11px; }
    .bd-inbox2-note-meta .bd-inbox2-note-who { font-weight: 600; }
    .bd-inbox2-note-del { margin-left: auto; border: none; background: transparent;
      color: var(--text-secondary); font-size: var(--fs-md, 16px); line-height: 1; cursor: pointer;
      padding: 2px 6px; border-radius: 6px; }
    .bd-inbox2-note-del:hover { background: var(--danger-soft); color: var(--danger); }
    .bd-inbox2-note-body { font-size: 13px; line-height: 1.45; margin-top: 3px;
      white-space: pre-wrap; overflow-wrap: anywhere; }
    .bd-inbox2-note-add { display: flex; gap: 8px; align-items: flex-end; margin-top: 10px; }
    .bd-inbox2-canned-open { flex: none; }
    .bd-inbox2-canned-list { border: 1px solid rgba(127,127,127,.18); border-radius: var(--radius-md);
      max-height: 280px; overflow-y: auto; margin-bottom: 10px; }
    .bd-inbox2-canned-row { display: flex; gap: 10px; align-items: center; padding: 9px 12px;
      cursor: pointer; border-bottom: 1px solid rgba(127,127,127,.12); }
    .bd-inbox2-canned-row:last-child { border-bottom: none; }
    .bd-inbox2-canned-row:hover { background: rgba(127,127,127,.07); }
    .bd-inbox2-canned-main { flex: 1; min-width: 0; }
    .bd-inbox2-canned-title { font-size: 13px; font-weight: 600; white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis; }
    .bd-inbox2-canned-body { font-size: 12px; white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
    .bd-inbox2-canned-actions { flex: none; display: flex; gap: 4px; }
    .bd-inbox2-canned-empty { padding: 22px 14px; text-align: center; font-size: 13px; color: var(--text-secondary); }
/* ---- end of was <style id="bd-inbox2-css"> ---- */

/* ---- was <style id="bd-seats-css"> at app.html:800-812 ---- */
  /* Inbox stage 3 (seats + SLA card) - same inline-block convention.
       body.role-staff is set by app.js applyRoleGate() from /me role;
       hiding here is courtesy only, the server returns 403 owner_required
       for staff on owner-only endpoints. The analytics KPI strip override
       lays out the KPI cards in rows of three (app.css is
       root-owned, so the override lives here; the 640px single-column
       media rule below 641px still applies untouched). */
    body.role-staff [data-owner-only] { display: none !important; }
    /* Seats (2026-08-03): a staff seat is an inbox operator. Inbox is the
       only page it gets, so every other nav item and every now-empty group
       label is hidden. The router also forces the route to 'inbox', so a
       typed #settings deep link lands on the inbox rather than a blank
       shell. Server-side, owner-only writes stay enforced independently. */
    body.role-staff .nav-item:not([data-route="inbox"]) { display: none !important; }
    body.role-staff .nav-group-label { display: none !important; }
    @media (min-width: 641px) {
      #app-shell .an-kpi-strip { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    }
/* ---- end of was <style id="bd-seats-css"> ---- */

/* ---- was <style id="bd-sla-css"> at app.html:818-823 ---- */
  /* W4-b: SLA response-time badge - same scoped inline-block convention as
       bd-inbox-css (app.css/app.linear.css are root-owned, not edited for
       features). Box shape matches .bd-inbox-aibadge; colors reuse the
       existing --warning-soft/--danger-soft tokens (same pairing as
       .badge-warning/.badge-danger in app.css). */
    .bd-inbox-slabadge { display: inline-block; font-size: 11px; font-weight: 600;
      padding: 1px 6px; border-radius: var(--radius-sm); margin-top: 3px; }
    .bd-inbox-slabadge.is-at-risk { background: var(--warning-soft); color: #b45309; }
    .bd-inbox-slabadge.is-breached { background: var(--danger-soft); color: #b91c1c; }
/* ---- end of was <style id="bd-sla-css"> ---- */

/* ---- was <style id="bd-booking-css"> at app.html:826-901 ---- */
  /* Bookings page: row layout + modal field spacing. Reuses .activity-row,
       .badge and .bd-camp-* (modal) from the existing styles. */
    /* Bookings - redesigned card layout (theme-var based, light + dark). */
    #bookings-list-wrap { padding: 2px 0; }
    .conv-head-sub { margin: 3px 0 0; font-size: 13px; color: var(--text-tertiary); }
    /* Summary stat strip */
    .bk-stats { display: flex; gap: 10px; margin: 2px 0 16px; flex-wrap: wrap; }
    .bk-stat { flex: 1; min-width: 120px; background: var(--bg-elevated);
      border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; }
    .bk-stat .n { font-size: 22px; font-weight: 800; line-height: 1; color: var(--text-primary); }
    .bk-stat .l { font-size: 12px; color: var(--text-tertiary); margin-top: 5px; }
    .bk-stat.pending .n { color: var(--warning); }
    .bk-stat.confirmed .n { color: var(--success); }
    #bookings-list { display: flex; flex-direction: column; gap: 10px; }
    /* margin-bottom: 0 overrides the app.linear.css §11 margin-bottom: var(--space-3) that
       would otherwise double-stack with the flex gap above, giving ~22px between cards. */
    .bk-card { display: flex; gap: 14px; align-items: stretch; padding: 13px 15px;
      background: var(--bg-elevated); border: 1px solid var(--border);
      border-radius: var(--radius-lg); margin-bottom: 0;
      transition: border-color .15s, box-shadow .15s; }
    .bk-card:hover { border-color: var(--border-strong);
      box-shadow: 0 1px 3px rgba(0,0,0,.06); }
    .bk-card.is-cancelled { opacity: .6; }
    /* Calendar date chip */
    .bk-date { flex-shrink: 0; width: 66px; display: flex; flex-direction: column;
      align-items: center; justify-content: center; gap: 1px; padding: 8px 5px;
      border-radius: var(--radius-md); background: var(--brand-soft);
      border: 1px solid var(--border); text-align: center; line-height: 1.15; }
    .bk-date .mon { font-size: 10.5px; font-weight: 700; text-transform: uppercase;
      letter-spacing: .05em; color: var(--brand); }
    .bk-date .day { font-size: 21px; font-weight: 800; line-height: 1.05; color: var(--text-primary); }
    .bk-date .tm  { font-size: 10.5px; font-weight: 600; color: var(--text-secondary);
      margin-top: 3px; white-space: nowrap; letter-spacing: -.1px; }
    .bk-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; justify-content: center; }
    /* display:flex overrides the app.linear.css block+text-overflow pattern; overflow:hidden
       keeps content from escaping; the inner span does the actual ellipsis truncation. */
    .bk-title { font-size: 14.5px; font-weight: 700; color: var(--text-primary);
      display: flex; align-items: center; gap: 8px; overflow: hidden; }
    .bk-title > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .bk-svc-ico { width: 16px; height: 16px; flex-shrink: 0; color: var(--text-tertiary); }
    .bk-meta { font-size: 12.5px; color: var(--text-secondary); }
    .bk-meta b { color: var(--text-primary); font-weight: 600; }
    .bk-party { color: var(--text-tertiary); flex-shrink: 0; }
    .bk-notes { font-size: 12px; color: var(--text-tertiary); font-style: italic;
      margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* min-width: 150px ensures the right column stays the same width across all cards
       (cards with two action buttons are ~150px wide; without actions only the pill is
       shown at ~90px - without a floor the body text area shifts 60px between rows). */
    .bk-side { flex-shrink: 0; min-width: 150px; display: flex; flex-direction: column;
      align-items: flex-end; justify-content: space-between; gap: 10px; }
    .bk-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
    /* Status pill (soft chip) */
    .bk-pill { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px;
      border-radius: var(--radius-full); font-size: 11px; font-weight: 700;
      text-transform: uppercase; letter-spacing: .02em; white-space: nowrap; }
    .bk-pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
    .bk-pill.requested { background: var(--warning-soft); color: var(--warning); }
    .bk-pill.confirmed { background: var(--success-soft); color: var(--success); }
    .bk-pill.cancelled { background: var(--danger-soft);  color: var(--danger); }
    .bk-pill.completed { background: var(--brand-soft);   color: var(--brand); }
    /* Header count + empty state */
    .bk-count { font-size: 12.5px; color: var(--text-tertiary); font-weight: 500; margin-left: 8px; }
    .bk-empty { text-align: center; padding: 46px 20px; color: var(--text-tertiary); }
    .bk-empty .bk-empty-ico { width: 38px; height: 38px; opacity: .45; margin: 0 auto 10px; }
    .bk-empty .bk-empty-t { font-size: 14px; font-weight: 600; color: var(--text-secondary); }
    .bk-empty .bk-empty-s { font-size: 12.5px; margin-top: 3px; }
    /* Modal: two-up field rows + service hint */
    .bk-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
    .bk-svc-hint { font-size: 12px; color: var(--text-tertiary); margin-top: 5px; min-height: 15px; }
    .bk-svc-hint b { color: var(--text-secondary); font-weight: 600; }
    @media (max-width: 560px) {
      .bk-card { flex-wrap: wrap; }
      .bk-side { align-items: flex-start; min-width: 0; width: 100%; flex-direction: row;
        justify-content: space-between; }
      .bk-form-row { grid-template-columns: 1fr; }
    }
/* ---- end of was <style id="bd-booking-css"> ---- */

/* ---- was <style id="bd-uifix-css"> at app.html:906-979 ---- */
  /* UI fixes round 1 (uifix1) - same inline-block convention. Covers:
       password-eye swap (the hidden attribute does not hide inline SVG, so
       the swap is driven here by CSS), the dismissible campaigns billing
       note, the notes modal list, and the Channel Breakdown bars. */
    /* Password toggle: exactly one eye icon at a time. */
    .password-toggle-btn svg[hidden] { display: none !important; }
    input::-ms-reveal { display: none; }
    /* Campaigns billing note: X close + persistent dismiss link. */
    .bd-billing-note-close { flex: none; border: none; background: transparent;
      color: inherit; opacity: .55; font-size: 17px; line-height: 1; cursor: pointer;
      padding: 2px 7px; border-radius: 6px; }
    .bd-billing-note-close:hover { opacity: 1; background: rgba(127,127,127,.12); }
    .bd-billing-note-never { display: block; margin-top: 7px; padding: 0; border: none;
      background: transparent; color: var(--brand); font-size: 12px; font-weight: 600;
      cursor: pointer; text-decoration: underline; }
    .bd-billing-note-never:hover { color: var(--brand-hover); }
    /* Notes modal: scrollable list, breathing room around the amber rows.
       50vh (not a fixed 300px) so it breathes on larger screens. */
    /* Inbox fix G12: the section spacing is the dialog shell's own
       (app.linear.css), so these no longer set margins. */
    #inbox-notes-modal .bd-inbox2-notes-list { max-height: 50vh; overflow-y: auto; }
    /* AI handback: "Note for AI" indicator dot + modal helper text. The accent
       (lime) dot marks that an instruction is currently active for the contact.
       app.css is root-owned, so these inbox additions live here. */
    /* Inbox fix C20: the lime was in no token; the brand marks "set". */
    .bd-ai-note-dot { display: inline-block; width: 7px; height: 7px;
      margin-left: 6px; border-radius: 50%; background: var(--brand);
      box-shadow: 0 0 0 2px var(--brand-soft); vertical-align: middle; }
    .bd-ai-note-dot[hidden] { display: none; }
    /* Inbox fix G12: margins come from the dialog shell (app.linear.css). The
       empty meta line no longer reserves 16px (it held an empty gap). */
    #inbox-ai-note-modal .bd-ai-note-hint { display: block; font-size: 12px;
      color: var(--text-secondary, #9aa3b2); line-height: 1.45; }
    /* display:block: an inline-block textarea sat on a text line and left a
       6px descender gap under it (G12). */
    #inbox-ai-note-modal textarea { width: 100%; display: block; }
    #inbox-ai-note-modal .bd-ai-note-foot { display: flex; gap: 8px;
      justify-content: flex-end; }
    #inbox-ai-note-modal .bd-ai-note-meta { font-size: 12px;
      color: var(--text-secondary, #9aa3b2); }
    #inbox-ai-note-modal .bd-ai-note-meta:empty { display: none; }
    /* Channel Breakdown: horizontal brand-colored bars (no chart lib). */
    .bd-chanbars { display: flex; flex-direction: column; gap: 14px; padding: 6px 2px 2px; }
    .bd-chanbar-row { min-width: 0; }
    .bd-chanbar-head { display: flex; justify-content: space-between;
      align-items: baseline; gap: 10px; margin-bottom: 5px; }
    .bd-chanbar-name { font-size: 13px; font-weight: 600; color: var(--text-primary); }
    .bd-chanbar-stat { font-size: 12px; color: var(--text-secondary);
      font-variant-numeric: tabular-nums; white-space: nowrap; }
    .bd-chanbar-track { height: 8px; border-radius: var(--radius-full);
      background: rgba(127,127,127,.16); overflow: hidden; }
    .bd-chanbar-fill { height: 100%; border-radius: var(--radius-full); min-width: 8px;
      transition: width .4s ease; }
    .bd-chanbars-empty { font-size: 13px; opacity: .6; padding: 18px 0; text-align: center; }
    /* AI gates (aitoggle1): compact per-channel switch on the Channels page.
       Injected as a full-width 4th grid child of each .channel-row, indented
       to line up under the channel name (32px icon + 12px gap). */
    .bd-ai-toggle { grid-column: 1 / -1; position: relative; display: flex;
      align-items: center; gap: 8px; padding: 2px 0 4px 44px;
      cursor: pointer; user-select: none; }
    .bd-ai-toggle input { position: absolute; opacity: 0; pointer-events: none;
      width: 0; height: 0; }
    .bd-ai-toggle-name { font-size: 12px; font-weight: 600;
      color: var(--text-secondary); }
    .bd-ai-toggle-mark { flex: 0 0 30px; width: 30px; height: 17px;
      border-radius: 999px; background: var(--border); position: relative;
      transition: background .18s ease; }
    .bd-ai-toggle-mark::after { content: ""; position: absolute; top: 2px;
      left: 2px; width: 13px; height: 13px; border-radius: 50%;
      background: #fff; transition: transform .18s ease;
      box-shadow: 0 1px 3px rgba(0,0,0,.18); }
    .bd-ai-toggle input:checked + .bd-ai-toggle-mark { background: var(--brand); }
    .bd-ai-toggle input:checked + .bd-ai-toggle-mark::after { transform: translateX(13px); }
    .bd-ai-toggle-state { font-size: 11px; font-weight: 600;
      color: var(--text-tertiary); min-width: 20px; }
    .bd-ai-toggle:has(input:disabled) { cursor: not-allowed; opacity: .65; }
    /* AI gates master row ("AI Everywhere") above the channels card. */
    .bd-ai-master { display: flex; align-items: center; justify-content: space-between;
      flex-wrap: wrap; gap: 12px 16px; margin-bottom: 16px; }
    .bd-ai-master-hint { font-size: 12px; color: var(--text-tertiary);
      margin: 4px 0 0; line-height: 1.4; }
    .bd-ai-master-actions { display: flex; gap: 8px; flex: none; }
/* ---- end of was <style id="bd-uifix-css"> ---- */

/* ---- was <style id="bd-ovchan-css"> at app.html:986-1016 ---- */
  /* Overview "Channels" card: the per-channel AI-status list rendered by
       renderOverviewChannelStatus() in app.js. The .ov-chan-* classes had no
       styling, so the section rendered as raw stacked divs (channel name +
       bare "AI on"/"AI off" text). Styled here as a tidy status list with
       branded icon chips and pill badges. app.css is root-owned, so it lives
       in this scoped block. */
    .ov-chan-list { display: flex; flex-direction: column; }
    .ov-chan-row { display: flex; align-items: center; justify-content: space-between;
      gap: 12px; padding: 11px 2px; border-bottom: 1px solid var(--border); }
    .ov-chan-row:last-child { border-bottom: 0; }
    .ov-chan-name { display: inline-flex; align-items: center; gap: 10px; min-width: 0;
      font-size: 13px; font-weight: 600; color: var(--text-primary); }
    /* Slightly larger, softer icon chip than the shared .ov-chan-ico default so
       the brand glyph reads at a glance in the overview card. */
    .ov-chan-list .ov-chan-ico { width: 26px; height: 26px; border-radius: 7px;
      margin-right: 0; }
    .ov-chan-list .ov-chan-ico svg { width: 15px; height: 15px; }
    /* Status badge: pill with a leading dot. On = success, off = neutral/muted. */
    .ov-chan-pill { display: inline-flex; align-items: center; gap: 6px; flex: none;
      padding: 4px 11px 4px 9px; border-radius: var(--radius-full, 999px);
      font-size: 11.5px; font-weight: 600; line-height: 1; letter-spacing: .01em;
      white-space: nowrap; }
    .ov-chan-pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
      background: currentColor; flex: none; }
    .ov-chan-pill.is-on { color: #047857; background: var(--success-soft, #d1fae5); }
    .ov-chan-pill.is-off { color: var(--text-secondary, #475569);
      background: rgba(127, 127, 127, .12); }
    /* Dark theme remaps --success-soft to a deep green, so the light-mode
       #047857 text would vanish on it; use a light mint instead. */
    html[data-theme="dark"] .ov-chan-pill.is-on { color: #6ee7b7; }
    /* Loading skeleton + unavailable state inside the card. */
    .ov-chan-skel { display: flex; flex-direction: column; gap: 0; }
    .ov-chan-skel .skeleton-line { display: block; height: 16px; margin: 11px 0; }
    .ov-chan-empty { font-size: 13px; color: var(--text-secondary); line-height: 1.5;
      padding: 4px 2px; }
/* ---- end of was <style id="bd-ovchan-css"> ---- */

/* ---- was <style id="bd-login-css"> at app.html:1020-1075 ---- */
  /* Login screen redesign + sign-in loading overlay. app.css is root-owned,
       so the brand lockup, the heading tweaks and the loading overlay live in
       this scoped block. The base .login-* layout still comes from app.css. */
    /* Bot Dynamics AI logo (the rounded-square gradient sparkle icon, exported
       from the brand design). Inline SVG needs an explicit box. The "AI" in the
       wordmark uses the brand purple; the rest follows the theme text color so
       it stays legible in both light and dark. */
    .bd-logo-icon { display: inline-block; flex: none; border-radius: 24%; }
    .bd-ai-accent { color: #9333EA; }
    html[data-theme="dark"] .bd-ai-accent { color: #b98cf2; }

    /* Top brand bar: small icon in place of the old dot. */
    .brand-bar-logo { width: 22px; height: 22px; }

    /* Login card: larger brand lockup leading the heading (replaces the old
       "Welcome back" line). */
    .login-brand { display: inline-flex; align-items: center; gap: 11px;
      margin-bottom: 8px; }
    .login-brand-logo { width: 40px; height: 40px; }
    .login-brand-name { font-size: 19px; font-weight: 800; letter-spacing: -0.02em;
      color: var(--text-primary); }
    /* Give the heading a touch more presence now that it leads the card. */
    .login-heading h1 { font-size: 26px; font-weight: 700; }

    /* "Sequence" loader (from the brand design handoff): the sparkle mark's
       four arms fire in a clockwise sweep with a glow pulse as each hits full
       length, and the whole mark does a smooth half-rotation each 1.6s loop.
       Shown full-screen during login only. Driven by the Loader module. */
    .bd-loader-overlay { position: fixed; inset: 0; z-index: 9990;
      display: flex; flex-direction: column; align-items: center;
      justify-content: center; gap: 22px; background: #160F38;
      animation: bd-loader-fade .14s ease both; }
    .bd-loader-overlay[hidden] { display: none !important; }
    @keyframes bd-loader-fade { from { opacity: 0; } to { opacity: 1; } }
    .bd-seq { --bd-speed: 1.6s; width: 64px; height: 64px; transform-origin: center;
      animation: bd-seqspin var(--bd-speed) cubic-bezier(.7,0,.3,1) infinite; }
    .bd-seq line { transform-origin: center; stroke-width: 2.6; stroke-linecap: round;
      animation: bd-seqarm var(--bd-speed) cubic-bezier(.65,0,.35,1) infinite; }
    .bd-seq line:nth-child(1) { stroke: #C4B5FD; animation-delay: 0s; }
    .bd-seq line:nth-child(2) { stroke: #B7A6F5; animation-delay: .13s; }
    .bd-seq line:nth-child(3) { stroke: #A78BFA; animation-delay: .26s; }
    .bd-seq line:nth-child(4) { stroke: #9333EA; animation-delay: .39s; }
    @keyframes bd-seqarm {
      0%,100% { transform: scaleY(.12); opacity: .3;
        filter: drop-shadow(0 0 0 rgba(167,139,250,0)); }
      45%     { transform: scaleY(1); opacity: 1;
        filter: drop-shadow(0 0 4px rgba(167,139,250,.8)); }
      70%     { transform: scaleY(1); opacity: .9;
        filter: drop-shadow(0 0 0 rgba(167,139,250,0)); }
    }
    @keyframes bd-seqspin { to { transform: rotate(180deg); } }
    .bd-loader-label { color: #9C95C4; font-size: 13.5px; font-weight: 500;
      letter-spacing: .01em; }
    @media (prefers-reduced-motion: reduce) {
      .bd-loader-overlay { animation: none; }
      .bd-seq, .bd-seq line { animation-duration: 3s; }
    }
/* ---- end of was <style id="bd-login-css"> ---- */

/* ---- was <style id="bd-chrome-css"> at app.html:1082-1442 ---- */
  /* CHROME REDESIGN - grouped sidebar nav, profile menu, channel cards.
       Inline here because app.css / app.linear.css must not be edited. Reuses
       the existing design tokens (--brand, --space-*, --radius-*, --border).
       Works WITH the live icon-rail (app.linear.css §5): on desktop the rail
       collapses to 76px and expands on hover; group labels fade with the same
       hover mechanism the nav labels already use. */
    /* ---- Grouped sidebar nav ---- */
    /* The nav is its own scroll container: a long list scrolls inside the
       sidebar, and overscroll-behavior:contain stops the wheel from bleeding
       to the page behind once the nav reaches its end (owner complaint a). */
    .sidebar-nav { overflow-y: auto; overscroll-behavior: contain;
      flex: 1 1 auto; min-height: 0; scrollbar-width: thin; }
    .sidebar-nav::-webkit-scrollbar { width: 7px; }
    .sidebar-nav::-webkit-scrollbar-thumb { background: var(--border-strong, var(--border));
      border-radius: 999px; }
    .nav-group { display: flex; flex-direction: column; gap: 2px; }
    .nav-group + .nav-group { margin-top: 14px; }
    .nav-group-label { font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em;
      text-transform: uppercase; color: var(--text-tertiary); padding: 2px 12px 4px;
      white-space: nowrap; overflow: hidden; }

    /* Icon-rail (desktop, >=901px - matches app.linear.css §5): collapse the
       group labels to a thin divider when the rail is narrow, fade them in on
       hover exactly like .nav-label. */
    @media (min-width: 901px) {
      .nav-group + .nav-group { margin-top: 10px; }
      .nav-group-label {
        height: 1px; padding: 0; margin: 6px 10px; line-height: 0;
        color: transparent; background: var(--border);
        opacity: 1; transition: color 130ms ease, background 130ms ease,
          height 130ms ease, margin 130ms ease, padding 130ms ease;
      }
      .sidebar:hover .nav-group-label {
        height: auto; line-height: 1.4; padding: 8px 12px 4px; margin: 2px 0 0;
        background: transparent; color: var(--text-tertiary);
      }
    }
    /* Mobile drawer keeps full labels (no collapse). */

    /* ---- Profile menu (top-right account dropdown) ---- */
    .bd-pm { min-width: 244px; padding: 0; overflow: hidden; }
    .bd-pm-head { display: flex; align-items: center; gap: 10px;
      padding: 12px 14px; border-bottom: 1px solid var(--border);
      background: var(--bg-subtle); }
    .bd-pm-avatar { flex: none; width: 36px; height: 36px; border-radius: 50%;
      display: inline-flex; align-items: center; justify-content: center;
      font-weight: 700; font-size: 14px; background: var(--brand-soft);
      color: var(--brand-text, var(--brand)); }
    .bd-pm-id { min-width: 0; flex: 1; }
    .bd-pm-name { font-size: 14px; font-weight: 600; color: var(--text-primary);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .bd-pm-sub { font-size: 12px; color: var(--text-tertiary);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .bd-pm-badges { display: flex; gap: 6px; align-items: center; margin-top: 4px; }
    .bd-pm-section { padding: 6px; }
    .bd-pm-divider { height: 1px; background: var(--border); margin: 0; border: 0; }
    .bd-pm .dropdown-item { font-size: 13px; }
    .bd-pm .dropdown-item .bd-pm-ico { flex: none; width: 15px; height: 15px;
      color: var(--text-tertiary); }
    .bd-pm .dropdown-item.danger .bd-pm-ico { color: var(--danger); }

    /* ---- Channels page: hero-grade card GRID ----
       The page still emits one ".channel-row[data-channel=X]" per channel (so
       wireChannelRows() selectors + the renderAiGates AI-toggle injection both
       resolve), but channelCard() now produces a self-contained vertical card:
       a top row (icon chip + status pill), a body (name + connected identity
       or value pitch + help line), and a footer with the single primary
       action. The AI-Replies switch is appended by renderAiGates as the card's
       last child and renders as a full-width footer strip. The wrapping
       .settings-card chrome is dropped on these pages so the grid breathes. */
    [data-page="channels"] #channels-body .settings-card.is-wide,
    [data-page="settings"] #settings-body .settings-card.is-wide {
      padding: 0; background: transparent; border: 0; box-shadow: none;
    }
    /* Hide the redundant "Channels" card heading on the dedicated page (the
       page already has its own <h1>); keep it on the Settings page. */
    [data-page="channels"] #channels-body .settings-card.is-wide > h3 { display: none; }
    [data-page="settings"] #settings-body .settings-card.is-wide > h3 { padding: 16px 18px 4px; }
    [data-page="channels"] #channels-body .settings-warning {
      margin: 0 0 14px; grid-column: 1 / -1;
    }
    [data-page="settings"] #settings-body .settings-card.is-wide .settings-warning {
      margin: 0 18px 8px;
    }
    /* The card grid: auto-fill responsive columns. The warning banner spans
       the full width via grid-column:1/-1 above. */
    [data-page="channels"] #channels-body .settings-card.is-wide {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
      gap: 16px;
    }
    /* Each channel becomes a card. !important overrides the base
       .channel-row grid rules from app.css without editing that file. */
    [data-page="channels"] #channels-body .channel-row {
      display: flex !important;
      flex-direction: column;
      align-items: stretch;
      gap: 0 !important;
      padding: 0 !important;
      border: 1px solid var(--border) !important;
      border-radius: var(--radius-lg, 14px);
      background: var(--bg-elevated);
      box-shadow: var(--shadow-xs);
      overflow: hidden;
      transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;
    }
    [data-page="channels"] #channels-body .channel-row:hover {
      border-color: var(--border-strong, var(--border));
      box-shadow: var(--shadow-sm, var(--shadow-xs));
      transform: translateY(-1px);
    }
    /* Connected cards get a subtle green accent so connected-vs-not reads at a
       glance. We can't add a class to the card (it's cloned markup), so we key
       off the presence of a "...-badge-connected" status pill via :has(). */
    [data-page="channels"] #channels-body .channel-row:has(.wa-badge-connected),
    [data-page="channels"] #channels-body .channel-row:has(.tg-badge-connected),
    [data-page="channels"] #channels-body .channel-row:has(.ig-badge-connected),
    [data-page="channels"] #channels-body .channel-row:has(.mg-badge-connected),
    [data-page="channels"] #channels-body .channel-row:has(.channel-status.is-connected) {
      border-color: color-mix(in srgb, #22c55e 38%, var(--border));
    }
    /* Card top: icon chip + status pill, pushed apart. */
    [data-page="channels"] #channels-body .chcard-top {
      display: flex; align-items: center; justify-content: space-between;
      padding: 16px 16px 10px;
    }
    [data-page="channels"] #channels-body .chcard-ico {
      width: 46px; height: 46px; border-radius: 12px;
      display: inline-flex; align-items: center; justify-content: center;
      background: var(--bg-subtle);
    }
    [data-page="channels"] #channels-body .chcard-ico .bd-ch-ico { width: 30px; height: 30px; }
    /* Card body: name, identity / pitch, help line. flex:1 so the footer sits
       flush at the bottom on every card regardless of text length. */
    [data-page="channels"] #channels-body .chcard-body {
      padding: 0 16px 14px; flex: 1 1 auto; min-width: 0;
    }
    [data-page="channels"] #channels-body .channel-name {
      font-size: 15px; font-weight: 600; color: var(--text-primary);
    }
    [data-page="channels"] #channels-body .chcard-identity {
      margin-top: 4px; display: flex; flex-direction: column; gap: 2px;
      font-size: 13px; line-height: 1.45;
    }
    [data-page="channels"] #channels-body .chcard-id-value {
      font-weight: 600; color: var(--text-primary);
      font-variant-numeric: tabular-nums; word-break: break-word;
    }
    [data-page="channels"] #channels-body .chcard-id-sub { color: var(--text-secondary); font-size: 12px; }
    [data-page="channels"] #channels-body .chcard-pitch { color: var(--text-secondary); }
    [data-page="channels"] #channels-body .wa-cloud-substate { font-size: 12px; }
    [data-page="channels"] #channels-body .channel-help {
      margin-top: 8px; font-size: 12px; color: var(--text-tertiary); line-height: 1.45;
    }
    /* Card footer: the single primary action, full-width. */
    [data-page="channels"] #channels-body .chcard-foot {
      padding: 0 16px 14px; display: flex;
    }
    [data-page="channels"] #channels-body .chcard-foot:empty { display: none; }
    [data-page="channels"] #channels-body .chcard-btn { width: 100%; justify-content: center; }
    [data-page="channels"] #channels-body .chcard-foot .channel-status {
      /* "Owner only" lock note rendered in the footer slot. */
      width: 100%; text-align: center; background: var(--bg-subtle);
    }
    /* The AI-Replies switch (appended last) becomes a divided footer strip. */
    [data-page="channels"] #channels-body .bd-ai-toggle {
      padding: 12px 16px !important; margin-top: auto;
      border-top: 1px solid var(--border); background: var(--bg-subtle);
      justify-content: space-between;
    }
    [data-page="channels"] #channels-body .bd-ai-toggle-name { flex: 1; }

    /* Settings page keeps the compact list look (only the dedicated Channels
       page becomes the card grid). The same channelCard() markup is laid out
       as a horizontal row: icon | body | footer-action, pill tucked beside the
       name in the body. */
    [data-page="settings"] #settings-body .channel-row {
      display: flex !important;
      align-items: center;
      gap: 12px !important;
      padding: 14px 18px !important;
      border-bottom: 1px solid var(--border);
    }
    [data-page="settings"] #settings-body .chcard-top {
      flex: none; padding: 0; display: block;
    }
    [data-page="settings"] #settings-body .chcard-top .chcard-pill,
    [data-page="settings"] #settings-body .chcard-top .wa-badge,
    [data-page="settings"] #settings-body .chcard-top .tg-badge,
    [data-page="settings"] #settings-body .chcard-top .ig-badge,
    [data-page="settings"] #settings-body .chcard-top .mg-badge,
    [data-page="settings"] #settings-body .chcard-top .channel-status { display: none; }
    [data-page="settings"] #settings-body .chcard-ico {
      width: 38px; height: 38px; border-radius: 10px;
      display: inline-flex; align-items: center; justify-content: center;
      background: var(--bg-subtle);
    }
    [data-page="settings"] #settings-body .chcard-ico .bd-ch-ico { width: 22px; height: 22px; }
    [data-page="settings"] #settings-body .chcard-body { flex: 1 1 auto; min-width: 0; padding: 0; }
    [data-page="settings"] #settings-body .channel-name { font-size: 14px; font-weight: 600; }
    [data-page="settings"] #settings-body .chcard-identity {
      margin-top: 2px; font-size: 12px; color: var(--text-secondary);
      display: flex; flex-wrap: wrap; gap: 3px 8px;
    }
    [data-page="settings"] #settings-body .chcard-id-value { font-weight: 600; color: var(--text-primary); }
    [data-page="settings"] #settings-body .chcard-foot { flex: none; padding: 0; display: flex; align-items: center; }
    [data-page="settings"] #settings-body .chcard-btn { width: auto; }
    [data-page="settings"] #settings-body .bd-ai-toggle {
      flex-basis: 100%; padding: 6px 0 2px 50px !important;
    }
    [data-page="settings"] #settings-body .channel-row { flex-wrap: wrap; }
    [data-page="settings"] #settings-body .channel-help { font-size: 11.5px; color: var(--text-tertiary);
      margin-top: 3px; line-height: 1.4; }

    /* CLIENT PORTAL: connecting Facebook / Instagram is Facebook Login only.
       The manual "paste your Meta App credentials" path is withdrawn from the
       UI here. The markup is deliberately LEFT IN PLACE and only hidden, so
       every id these wizards bind to still resolves and no handler goes null.
       The ADMIN console keeps its paste form as the operator fallback. */
    #meta-creds-form,
    #meta-wizard-modal .meta-pane[data-meta-step="credentials"] > p.meta-intro,
    #meta-steps,
    #mg-generate-card, #mg-webhook-card, #mg-next-btn, #mg-regen-btn, #mg-steps,
    #mg-wizard-modal .mg-pane[data-mg-step="webhook"] > p.mg-intro,
    #mg-wizard-modal .mg-pane[data-mg-step="credentials"],
    #ig-generate-card, #ig-webhook-card, #ig-next-btn, #ig-regen-btn, #ig-steps,
    #ig-wizard-modal .ig-pane[data-ig-step="webhook"] > p.ig-intro,
    #ig-wizard-modal .ig-pane[data-ig-step="credentials"] {
      display: none !important;
    }

    /* Facebook-Login Page picker (MetaPopup). Full-width stacked choices so a
       single returned Page still reads as "pick this", not as nothing having
       happened - which is exactly how it read when it was inline buttons. */
    .meta-fb-picker, .mg-fb-picker, .ig-fb-picker {
      display: flex; flex-direction: column; gap: 8px; margin-top: 12px;
      padding-top: 12px; border-top: 1px solid var(--border-subtle, rgba(128,128,128,.25));
    }
    .meta-fb-picker .btn, .mg-fb-picker .btn, .ig-fb-picker .btn {
      width: 100%; justify-content: space-between; text-align: left;
      gap: 10px; cursor: pointer;
    }
    /* The chevron is what makes a full-width row read as "press me" rather
       than as a disabled text field, which is how the plain bordered version
       read and why the connect step kept getting missed. */
    .meta-fb-picker .btn::after, .mg-fb-picker .btn::after, .ig-fb-picker .btn::after {
      content: "\2192"; font-size: 16px; line-height: 1; opacity: .85; flex: none;
    }
    .meta-fb-picker .mg-help, .mg-fb-picker .mg-help, .ig-fb-picker .mg-help {
      margin: 0 0 2px; font-weight: 600;
    }

    /* Plain fallback for the help line outside the channels page. */
    .channel-help { font-size: 11.5px; color: var(--text-tertiary);
      margin-top: 3px; line-height: 1.4; }
    /* The matching opacity de-emphasis for Instagram / Messenger lived here,
       from the same reversed "permanent off" policy. Both channels are now
       first-class, so they render like every other channel. */

    /* ---- Channel Manage popup sections (Status / Actions / Help) ----
       The connected/success panes of the WhatsApp + Telegram + Meta wizards
       keep ALL their ids + handlers; these rules only group their content into
       readable sections via the .chmg-* wrappers added in the redesign. */
    .chmg-section { padding: 14px 0; border-top: 1px solid var(--border); }
    .chmg-section:first-of-type { border-top: 0; }
    .chmg-section-label { font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em;
      text-transform: uppercase; color: var(--text-tertiary); margin-bottom: 8px; }
    .chmg-help { font-size: 12.5px; color: var(--text-secondary); line-height: 1.5; margin: 0; }
    /* Connection summary block at the top of a Manage dialog: status pill,
       a one-line identity sentence, and a soft hint. Replaces the old
       celebratory check-circle + big title. */
    .chmg-summary { padding: 2px 0 4px; }
    .chmg-summary-badge { display: inline-flex; margin-bottom: 10px; }
    .chmg-summary-line { margin: 0; font-size: 14.5px; line-height: 1.5;
      color: var(--text-primary); }
    .chmg-summary-line strong, .chmg-summary-line .tg-bot-username {
      font-weight: 600; color: var(--text-primary); }
    .chmg-summary-hint { margin: 6px 0 0; font-size: 12.5px;
      color: var(--text-tertiary); line-height: 1.45; }
    /* Actions row: wrap, left-aligned; destructive action pushed to the end. */
    .chmg-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
    .chmg-actions .chmg-danger { margin-left: auto; }
    .chmg-danger { color: var(--danger); }
    .chmg-danger:hover { color: #fff; background: var(--danger); border-color: var(--danger); }
    /* Technical details <details>: muted, low-key, no celebration styling. */
    .chmg-tech { margin: 4px 0 2px; }
    .chmg-tech > summary { cursor: pointer; font-size: 12.5px; font-weight: 600;
      color: var(--text-secondary); list-style: none; padding: 8px 0;
      display: flex; align-items: center; gap: 6px; }
    .chmg-tech > summary::-webkit-details-marker { display: none; }
    .chmg-tech > summary::before { content: "›"; transition: transform .15s ease;
      display: inline-block; font-size: 15px; }
    .chmg-tech[open] > summary::before { transform: rotate(90deg); }
    /* Guided connect flow: one big CTA + a "what happens next" list. */
    .chmg-connect-lead { margin-bottom: 6px; }
    .chmg-connect-cta { width: 100%; }
    .chmg-next-list { margin: 12px 0 4px; padding: 0; list-style: none;
      display: flex; flex-direction: column; gap: 8px; }
    .chmg-next-list li { position: relative; padding-left: 24px;
      font-size: 13px; color: var(--text-secondary); line-height: 1.45; }
    .chmg-next-list li::before { content: ""; position: absolute; left: 4px; top: 6px;
      width: 7px; height: 7px; border-radius: 50%; background: var(--brand); }
    .chmg-advanced { border-top: 1px solid var(--border); margin-top: 14px; padding-top: 4px; }

    /* ---- Settings page redesign (card field rows + action strips) --------
       Targets only [data-page="settings"] so the Channels page is unaffected.
       Goal: consistent label/value alignment, buttons in a dedicated row,
       descriptive hint text, no floating elements. */

    /* Card header: slightly more breathing room */
    [data-page="settings"] #settings-body .settings-card > h3 {
      font-size: 12px; font-weight: 700; letter-spacing: 0.07em;
      text-transform: uppercase; color: var(--text-tertiary);
      padding: 18px 18px 10px; margin: 0; border-bottom: 1px solid var(--border);
    }

    /* Field rows: key left (fixed 40%), value right, both baseline-aligned.
       Overrides whatever app.css sets so the grid is consistent across cards. */
    [data-page="settings"] #settings-body .settings-field {
      display: flex !important; align-items: baseline !important;
      gap: 8px; padding: 9px 18px !important; border-bottom: 1px solid var(--border);
    }
    [data-page="settings"] #settings-body .settings-field:last-of-type {
      border-bottom: 0;
    }
    [data-page="settings"] #settings-body .settings-field .key {
      flex: 0 0 38%; min-width: 0; font-size: 12.5px;
      color: var(--text-tertiary); white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis;
    }
    [data-page="settings"] #settings-body .settings-field .val {
      flex: 1 1 0; min-width: 0; font-size: 13px;
      color: var(--text-primary); word-break: break-word;
    }
    [data-page="settings"] #settings-body .settings-field .val.mono {
      font-family: var(--font-mono, monospace); font-size: 12.5px;
    }
    /* Chips strip inside a .val */
    [data-page="settings"] #settings-body .settings-chips {
      display: flex; flex-wrap: wrap; gap: 4px; margin: 0;
    }

    /* Action strip at the bottom of a card: buttons left-aligned with gap */
    [data-page="settings"] #settings-body .stg-card-actions {
      display: flex; flex-wrap: wrap; align-items: center;
      gap: 8px; padding: 12px 18px 14px;
    }
    /* Ghost/link buttons in action strip get auto left-push */
    [data-page="settings"] #settings-body .stg-card-actions .btn-ghost {
      margin-left: auto; text-decoration: none;
    }

    /* Hint text between last field row and action strip */
    [data-page="settings"] #settings-body .stg-card-hint {
      font-size: 12.5px; color: var(--text-tertiary); line-height: 1.5;
      margin: 0; padding: 8px 18px 0;
    }
    /* Remove top-border on a field row that immediately follows a hint */
    [data-page="settings"] #settings-body .stg-card-hint + .settings-field {
      border-top: 1px solid var(--border);
    }

    /* Suppress the old per-channel compact row rules that leaked from
       the removed Channels card - no channel rows remain on this page. */
    [data-page="settings"] #settings-body .channel-row { display: none !important; }
/* ---- end of was <style id="bd-chrome-css"> ---- */

/* ---- was <style id="bd-ob-css2"> at app.html:1447-1527 ---- */
  /* Outbound page redesign (2026-07-05, w136-outbound). Scoped bd-ob-*
       additions layered on the base .bd-ob-* / .bl-table rules that live in the
       root-owned app.linear.css / app.css (not edited here). All colour comes
       from the portal tokens so light + dark both flip automatically. */
    /* Owner fix 2: the reminder-time <select>s (and the new history filter
       select) showed white option text on a white menu until hover/selection.
       Force explicit token colours on EVERY outbound select AND its <option>s,
       mirroring the working .bd-auto-field select option pattern. Attribute+
       element specificity (0,1,1) beats the .input class, and the tokens flip
       with the theme so it reads correctly in both. */
    [data-page="outbound"] select {
      background: var(--bg-elevated, #fff); color: var(--text-primary, #0f172a); }
    [data-page="outbound"] select option {
      background: var(--bg-elevated, #fff); color: var(--text-primary, #0f172a); }

    /* Top row: the primary action (Place a call) and the do-not-call list as
       two equal columns, so a tall reminders form no longer strands one card
       with a big gap beside it. Reminders + history sit full-width below. */
    .bd-ob-top { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
    @media (max-width: 860px) { .bd-ob-top { grid-template-columns: 1fr; } }
    .bd-ob-settings-wide { margin-top: 20px; }
    /* Place a call is the page's primary action - a whisper-quiet brand top edge
       (not decoration: it marks the one thing this page is for). */
    .bd-ob-primary { border-top: 2px solid var(--brand); }
    /* The do-not-call empty state reads better left-aligned inside its card
       than centered in a tall column. */
    [data-page="outbound"] #ob-optout-list .bd-contacts-empty {
      text-align: left; padding: 10px 2px; }
    /* Narrow screens: let a do-not-call row wrap (phone / reason / Remove)
       instead of pushing the card wider than the viewport, and let the
       reason wrap instead of ellipsizing into the Remove button. */
    [data-page="outbound"] .bd-ob-row { flex-wrap: wrap; }
    @media (max-width: 520px) {
      [data-page="outbound"] .bd-ob-reason { white-space: normal; }
    }

    /* Summary strip - compact stat tiles, calls-first. */
    .bd-ob-summary { display: grid; gap: 12px; margin-bottom: 20px;
      grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
    .bd-ob-summary[hidden] { display: none; }
    .bd-ob-stat { padding: 14px 16px; border: 1px solid var(--border);
      border-radius: var(--radius-md, 10px); background: var(--bg-elevated); }
    .bd-ob-stat-v { font-size: 24px; font-weight: 650; line-height: 1.1; color: var(--text-primary); }
    .bd-ob-stat-l { font-size: 12.5px; color: var(--text-secondary); margin-top: 4px; }
    .bd-ob-stat-sub { font-size: 11.5px; color: var(--text-tertiary); margin-top: 2px; }

    /* Schedule-for-later reveal. */
    .bd-ob-check { display: inline-flex; align-items: center; gap: 8px; font-size: 13px;
      font-weight: 500; color: var(--text-primary); cursor: pointer; }
    .bd-ob-when { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
    .bd-ob-when[hidden] { display: none; }
    .bd-ob-when-hint { font-size: 11.5px; color: var(--text-tertiary); line-height: 1.45; }
    .bd-ob-card-sub { font-size: 12.5px; color: var(--text-secondary);
      margin: -4px 0 14px; line-height: 1.5; }

    /* History header + filter bar. */
    .bd-ob-hist-head { display: flex; align-items: center; justify-content: space-between;
      gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
    .bd-ob-filter { display: flex; gap: 8px; align-items: center; }
    .bd-ob-filter[hidden] { display: none; }
    .bd-ob-search { max-width: 180px; }
    .bd-ob-outcome-sel { max-width: 168px; }

    /* Outcome chip - state colour carries MEANING, not decoration. The dot is
       currentColor so it always matches the chip's semantic tone. */
    .bd-ob-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px;
      font-size: 12px; font-weight: 600; line-height: 1.5; border-radius: var(--radius-full, 999px);
      white-space: nowrap; }
    .bd-ob-chip::before { content: ""; width: 7px; height: 7px; border-radius: 50%;
      background: currentColor; flex: none; }
    .bd-ob-chip.is-connected { color: var(--success); background: var(--success-soft); }
    .bd-ob-chip.is-missed    { color: var(--warning); background: var(--warning-soft); }
    .bd-ob-chip.is-failed    { color: var(--danger);  background: var(--danger-soft); }
    .bd-ob-chip.is-pending   { color: var(--brand-text, var(--brand)); background: var(--brand-soft); }

    /* History rows. */
    .bd-ob-num { font-variant-numeric: tabular-nums; }
    .bd-ob-sub { font-size: 11.5px; color: var(--text-tertiary); margin-top: 3px; line-height: 1.4; }
    .bd-ob-when-cell { color: var(--text-secondary); white-space: nowrap; }
    .bd-ob-len { color: var(--text-tertiary); font-variant-numeric: tabular-nums; }
    .bd-ob-actions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
    body.role-staff .bd-ob-redial { display: none; }
    .bd-ob-noresults { padding: 22px 4px; text-align: center; font-size: 13px; color: var(--text-tertiary); }
/* ---- end of was <style id="bd-ob-css2"> ---- */

/* The X0 bridges that stood here (W0, 2026-09-21) are gone: inbox fix
   addendum 9 fixed each theme rule they beat, in app.linear.css. */
