  /* Project toolbar (workspace list / workspace thread / activity). Scrolls
     horizontally at ANY width once its buttons (New Workspace + 7 nav tabs,
     plus Restart/sudo on the System project) exceed the available space —
     not just under the mobile breakpoint. #main can be narrower than that
     well before mobile widths (sidebar open on a laptop, System project's
     extra buttons), and the page sets `overflow-x: hidden` globally, so
     without this the overflow silently clips with no way to reach it. */
  #main-toolbar {
    position: relative;
    padding: 12px 24px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  #main-toolbar .spacer { flex: 1; }
  #main-toolbar button, #main-toolbar .link-btn {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 7px;
    padding: 7px 12px;
    font-size: 12px;
    cursor: pointer;
    flex-shrink: 0;
  }
  #main-toolbar button.primary {
    background: var(--accent);
    border: none;
    color: #070605;
    font-weight: 700;
  }
  #main-toolbar button:hover { color: var(--text); border-color: var(--text-dim); }
  #main-toolbar button.primary:hover { filter: brightness(1.08); color: #070605; }

  /* Nav tabs (Workspaces/Tasks/Work Items/...) read as an actual tab strip, not a
     row of bordered buttons like the ones above (+ New Workspace, Restart,
     sudo) — no border/box of their own; the sliding holographic pill in
     holo-theme.css (.tab-indicator-pill) is what shows which one is open. */
  #main-toolbar .toolbar-nav-btn {
    border-color: transparent;
    padding: 8px 16px;
  }
  #main-toolbar .toolbar-nav-btn:hover { border-color: transparent; }

  /* Click affordance for the horizontal scroll above — faded arrows
     overlaid on the toolbar's edges, only shown while there's more
     content to scroll to in that direction. */
  #main-toolbar-wrap { position: relative; border-bottom: 1px solid var(--border); }
  #main-toolbar-wrap #main-toolbar { border-bottom: none; }
  .toolbar-scroll-btn {
    position: absolute;
    top: 0; bottom: 0;
    width: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    color: var(--text-dim);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
    z-index: 2;
  }
  .toolbar-scroll-btn.visible { opacity: 1; pointer-events: auto; }
  .toolbar-scroll-btn:hover { color: var(--text); }
  #toolbar-scroll-left { left: 0; justify-content: flex-start; background: linear-gradient(90deg, var(--bg) 45%, transparent); }
  #toolbar-scroll-right { right: 0; justify-content: flex-end; background: linear-gradient(270deg, var(--bg) 45%, transparent); }

  /* overflow-y: auto is a safety valve, not the primary scroll mechanism
     (#messages below handles that day-to-day) — it only engages when the
     thread header plus the tasks/pinned panels (both independently capped,
     but capped ≠ zero) are tall enough to squeeze #messages-wrap to its
     min-height: 0 floor and still not leave room for #composer. Without
     it that overflow has nowhere to go but clipped past the bottom of the
     viewport (body is overflow: hidden — see base.css), taking the Send
     button with it and leaving no way to scroll back down to it. */
  #view-body { flex: 1; display: flex; flex-direction: column; min-height: 0; overflow-y: auto; }

  /* Workspace list */
  #workspace-list-toolbar {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 14px 24px 0;
  }
  #workspace-search-input {
    flex: 1; max-width: 360px;
    background: var(--panel);
    border-radius: 8px; padding: 8px 12px; font-size: 12.5px;
  }
  #workspace-sort-select { width: auto; min-width: 160px; flex-shrink: 0; }
  #workspace-status-filter { display: flex; gap: 4px; flex-shrink: 0; }
  #workspace-status-filter button {
    background: transparent; border: 1px solid var(--border); color: var(--text-dim);
    border-radius: 20px; padding: 6px 12px; font-size: 11.5px; font-family: inherit; cursor: pointer;
  }
  #workspace-status-filter button:hover { color: var(--text); border-color: var(--text-dim); }
  #workspace-status-filter button.active { background: var(--accent); border-color: var(--accent); color: #070605; font-weight: 700; }
  #workspace-archived-toggle {
    display: flex; align-items: center; gap: 5px; flex-shrink: 0;
    font-size: 11.5px; color: var(--text-dim); cursor: pointer; white-space: nowrap;
  }
  #workspace-count { color: var(--text-dim); font-size: 11.5px; margin-left: auto; flex-shrink: 0; white-space: nowrap; }
  #workspace-list { flex: 1; overflow-y: auto; padding: 16px 24px; }
  .workspace-row {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 14px 16px;
    margin-bottom: 10px;
    cursor: pointer;
    transition: border-color 0.12s;
  }
  .workspace-row:hover { border-color: var(--accent); }
  .workspace-row.archived { opacity: 0.6; }
  .workspace-row.stale { border-color: rgba(245,184,79,0.35); }
  .workspace-stale-tag {
    display: flex; align-items: center; gap: 3px;
    font-size: 10.5px; font-weight: 700; color: var(--amber);
  }
  .workspace-stale-tag .icon-svg { color: var(--amber); width: 13px; height: 13px; }
  /* Content-sized, not `flex: 1` — a bare flex:1 grows this box to fill
     every pixel of leftover row width regardless of how short the actual
     title text is, which on a wide viewport leaves a dead gap between the
     text and the badges/select/date/actions that follow (they end up
     shoved out to the far edge instead of sitting next to the title).
     Sizing to content (capped for readability) keeps the row visually
     tight; see .archive below for how the trailing actions get pushed to
     the right edge instead. Wrapping instead of an ellipsis means the full
     title is always visible, never clipped, at any width. */
  .workspace-row .title {
    flex: 0 1 auto; min-width: 0; max-width: 640px;
    font-size: 13.5px; font-weight: 600;
    white-space: normal; word-break: break-word;
  }
  .workspace-agent-badge {
    color: var(--text-dim); background: var(--panel-2); border: 1px solid var(--border);
  }
  .workspace-tag { flex-shrink: 0; font-size: 12px; }
  .workspace-running {
    flex-shrink: 0; font-size: 10.5px; font-weight: 700; color: var(--accent-2);
    display: flex; align-items: center; gap: 3px;
  }
  /* Red, not amber like .workspace-stale-tag — this isn't a "when you get to it"
     housekeeping nudge, it's an agent mid-turn blocked on a real decision
     (see waiting-workspaces endpoints). Reuses the same pulse the sudo-unlock
     button uses for "something is stuck waiting on you" (holo-theme.css). */
  .workspace-waiting {
    flex-shrink: 0; font-size: 10.5px; font-weight: 700; color: var(--red);
    display: flex; align-items: center; gap: 3px;
    animation: sudo-needs-attention 1.6s ease-in-out infinite;
  }
  .workspace-waiting .icon-svg { color: var(--red); width: 13px; height: 13px; }
  @media (prefers-reduced-motion: reduce) {
    .workspace-waiting { animation: none; }
  }
  .workspace-status-select { flex-shrink: 0; font-weight: 700; }
  .workspace-status-select.status-open { color: var(--green); border-color: rgba(62,207,142,0.4); }
  .workspace-status-select.status-pending { color: var(--amber); border-color: rgba(245,184,79,0.4); }
  .workspace-status-select.status-closed { color: var(--text-dim); }
  .workspace-status-select.status-open:hover, .workspace-status-select.status-open:focus {
    border-color: var(--green); box-shadow: 0 0 0 3px rgba(62,207,142,0.18);
  }
  .workspace-status-select.status-pending:hover, .workspace-status-select.status-pending:focus {
    border-color: var(--amber); box-shadow: 0 0 0 3px rgba(245,184,79,0.18);
  }
  .workspace-row .meta { font-size: 11px; color: var(--text-dim); flex-shrink: 0; }
  /* Pins the action icons to the row's right edge — the reclaimed space
     from .title no longer being flex:1 (see above) collects here as a
     single gap before the actions, instead of a gap in the middle of the
     row next to the title. */
  .workspace-row .archive { margin-left: auto; }
  .workspace-row .archive, .workspace-row .del {
    color: var(--text-dim); font-size: 13px; padding: 2px 6px; border-radius: 5px; flex-shrink: 0;
  }
  .workspace-row .archive:hover { color: var(--text); }
  .workspace-row .del:hover { color: var(--red); }
  .workspace-row .archive:hover .icon-svg { color: var(--text); filter: none; }
  #workspace-empty { color: var(--text-dim); font-size: 13px; padding: 8px 4px; }

  /* Workspace thread header — title/rename, live status, agent, start time */
  #thread-header { padding: 14px 24px 10px; border-bottom: 1px solid var(--border); }
  .thread-title-row { display: flex; align-items: center; gap: 10px; }
  #thread-title {
    font-size: 15px;
    font-weight: 700;
    margin: 0;
    cursor: pointer;
    border-radius: 6px;
    padding: 2px 6px;
    margin-left: -6px;
  }
  #thread-title:hover { background: var(--panel-2); }
  #thread-title-input {
    font-size: 15px;
    font-weight: 700;
    font-family: inherit;
    background: var(--panel-2);
    border: 1px solid var(--accent);
    color: var(--text);
    border-radius: 6px;
    padding: 2px 6px;
    outline: none;
    flex: 1;
    max-width: 420px;
  }
  .thread-title-row .badge { flex-shrink: 0; }
  .thread-meta-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 5px;
    font-size: 11.5px;
    color: var(--text-dim);
  }
  .thread-agent-label {
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 2px 7px;
  }
  #thread-workspace-status-select { margin-left: auto; }
  #thread-archive-btn {
    background: transparent; border: 1px solid var(--border); color: var(--text-dim);
    border-radius: 6px; padding: 3px 9px; font-size: 11px; font-family: inherit; cursor: pointer;
  }
  #thread-archive-btn:hover { color: var(--text); border-color: var(--text-dim); }

  /* Export control — one icon button that opens a small dropdown of formats,
     same open/close-on-outside-click shape as #notifications-panel (see
     sidebar.css) rather than a select+button pair crowding the meta row. */
  .thread-export-wrap { position: relative; }
  #thread-export-btn {
    display: flex; align-items: center; justify-content: center;
    width: 26px; height: 26px;
    background: transparent; border: 1px solid var(--border); color: var(--text-dim);
    border-radius: 6px; padding: 0; cursor: pointer;
  }
  #thread-export-btn:hover { color: var(--text); border-color: var(--text-dim); }
  #thread-export-btn .icon-svg { width: 14px; height: 14px; }
  .thread-export-wrap.open #thread-export-btn { color: var(--text); border-color: var(--accent); background: var(--panel-2); }
  #thread-export-menu {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 40;
    min-width: 168px;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 20px 50px rgba(0,0,0,0.5);
    overflow: hidden;
    padding: 4px;
  }
  .thread-export-wrap.open #thread-export-menu { display: block; }
  #thread-export-menu button {
    display: flex; align-items: center; gap: 8px; width: 100%;
    background: transparent; border: none; color: var(--text);
    border-radius: 6px; padding: 7px 8px; font-size: 12.5px; font-family: inherit;
    text-align: left; cursor: pointer;
  }
  #thread-export-menu button:hover { background: var(--panel); }
  #thread-export-menu button .icon-svg { width: 14px; height: 14px; flex-shrink: 0; }
  #thread-export-menu button small { color: var(--text-dim); font-weight: 400; margin-left: 4px; }

  /* Workspace thread messages */
  #messages-wrap { flex: 1; display: flex; flex-direction: column; min-height: 0; position: relative; }
  #scroll-bottom-btn {
    position: absolute;
    bottom: 14px;
    right: 28px;
    background: var(--panel);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: 20px;
    padding: 6px 14px;
    font-size: 12px;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(0,0,0,0.35);
  }
  #scroll-bottom-btn:hover { border-color: var(--text-dim); }
  #messages { flex: 1; overflow-y: auto; padding: 16px 24px; }
  .msg-turn { margin-bottom: 18px; }
  .msg-system-note {
    display: flex;
    align-items: center;
    gap: 6px;
    justify-content: flex-end;
    margin: 0 0 4px;
    font-size: 11px;
    color: var(--text-dim);
    font-style: italic;
  }
  .msg-system-note .icon-svg { width: 13px; height: 13px; }
  .msg-user {
    background: var(--panel-2);
    border-radius: 10px 10px 4px 10px;
    padding: 10px 14px;
    font-size: 13.5px;
    font-family: var(--font-body);
    max-width: 80%;
    margin-left: auto;
    white-space: pre-wrap;
    word-break: break-word;
  }
  .msg-assistant-group { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
  .msg-assistant {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 10px 10px 10px 4px;
    padding: 10px 14px;
    font-size: 13.5px;
    font-family: var(--font-body);
    max-width: 85%;
    margin-right: auto;
    white-space: pre-wrap;
    word-break: break-word;
  }
  .msg-user p, .msg-assistant p { margin: 0 0 8px; }
  .msg-user p:last-child, .msg-assistant p:last-child { margin-bottom: 0; }
  /* Assistant bubble content sits inside .msg-assistant-body (see the
     copy/timestamp footer added alongside it), so the first/last-child
     margin reset targets that wrapper's children, not .msg-assistant's. */
  .msg-user > *:first-child, .msg-assistant-body > *:first-child { margin-top: 0; }
  .msg-user > *:last-child, .msg-assistant-body > *:last-child { margin-bottom: 0; }
  .msg-user ul, .msg-user ol, .msg-assistant ul, .msg-assistant ol {
    margin: 4px 0 8px;
    padding-left: 22px;
  }
  .msg-user li, .msg-assistant li { margin: 3px 0; line-height: 1.45; }
  .msg-user li > ul, .msg-user li > ol,
  .msg-assistant li > ul, .msg-assistant li > ol {
    margin: 3px 0 3px;
  }
  .msg-user ul ul, .msg-assistant ul ul { list-style-type: circle; }
  .msg-user ul ul ul, .msg-assistant ul ul ul { list-style-type: square; }
  .msg-user li::marker, .msg-assistant li::marker { color: var(--text-dim); }
  .msg-user li.task-item, .msg-assistant li.task-item { list-style: none; }
  .msg-user h1, .msg-user h2, .msg-user h3, .msg-user h4, .msg-user h5, .msg-user h6,
  .msg-assistant h1, .msg-assistant h2, .msg-assistant h3,
  .msg-assistant h4, .msg-assistant h5, .msg-assistant h6 {
    margin: 10px 0 6px;
    font-weight: 700;
    line-height: 1.3;
  }
  .msg-user h1, .msg-assistant h1 { font-size: 1.2em; }
  .msg-user h2, .msg-assistant h2 { font-size: 1.12em; }
  .msg-user h3, .msg-user h4, .msg-user h5, .msg-user h6,
  .msg-assistant h3, .msg-assistant h4, .msg-assistant h5, .msg-assistant h6 { font-size: 1.05em; }
  .msg-user code, .msg-assistant code {
    background: rgba(255,255,255,0.08);
    border-radius: 4px;
    padding: 1px 5px;
    font-family: var(--mono);
    font-size: 0.9em;
  }
  .msg-user pre.msg-code, .msg-assistant pre.msg-code {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    margin: 6px 0;
    overflow-x: auto;
  }
  .msg-user pre.msg-code code, .msg-assistant pre.msg-code code {
    background: none;
    padding: 0;
    font-size: 12px;
    line-height: 1.5;
    white-space: pre;
  }

  /* Fenced code blocks render as an "artifact card" — a filename/language
     header plus copy/download/expand actions — instead of a bare <pre>, so
     the inner pre.msg-code loses its own border/margin and sits flush under
     the header (see buildArtifactCard() in markdown.js, artifacts.js for
     the button behavior). */
  .artifact-card {
    margin: 8px 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
  }
  .artifact-card pre.msg-code {
    margin: 0;
    border: none;
    border-radius: 0;
  }
  .artifact-header {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 6px 8px 6px 10px;
    background: rgba(255,255,255,0.03);
    border-bottom: 1px solid var(--border);
  }
  .artifact-header .icon-svg { width: 13px; height: 13px; color: var(--text-dim); filter: none; }
  .artifact-name {
    font-family: var(--mono);
    font-size: 11.5px;
    color: var(--text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }
  .artifact-lang {
    font-size: 10px;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    flex-shrink: 0;
    opacity: 0.7;
  }
  .artifact-actions { display: flex; align-items: center; gap: 1px; margin-left: auto; flex-shrink: 0; }
  .artifact-btn {
    background: transparent;
    border: none;
    color: var(--text-dim);
    cursor: pointer;
    width: 22px;
    height: 22px;
    padding: 0;
    border-radius: 5px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }
  .artifact-btn:hover { background: var(--bg); color: var(--text); }
  .artifact-btn .icon-svg { width: 13px; height: 13px; color: inherit; filter: none; }
  .artifact-btn:hover .icon-svg { color: inherit; filter: none; }
  /* Markdown tables render as a "table card" (see buildTableCard() in
     markdown.js) — a header bar with row/col count + copy/download-as-CSV
     actions (tables.js) above a real scrollable <table>, mirroring the
     artifact-card treatment fenced code blocks get above. */
  .table-card {
    margin: 8px 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
  }
  .table-header {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 6px 8px 6px 10px;
    background: rgba(255,255,255,0.03);
    border-bottom: 1px solid var(--border);
  }
  .table-header .icon-svg { width: 13px; height: 13px; color: var(--text-dim); filter: none; }
  .table-label { font-size: 11.5px; color: var(--text-dim); }
  .table-dims { font-size: 10px; color: var(--text-dim); opacity: 0.7; }
  .table-actions { display: flex; align-items: center; gap: 1px; margin-left: auto; flex-shrink: 0; }
  .table-btn {
    background: transparent;
    border: none;
    color: var(--text-dim);
    cursor: pointer;
    width: 22px;
    height: 22px;
    padding: 0;
    border-radius: 5px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }
  .table-btn:hover { background: var(--bg); color: var(--text); }
  .table-btn .icon-svg { width: 13px; height: 13px; color: inherit; filter: none; }
  .table-btn:hover .icon-svg { color: inherit; filter: none; }
  .msg-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .msg-table { border-collapse: collapse; width: 100%; font-size: 12.5px; }
  .msg-table th, .msg-table td {
    padding: 6px 10px;
    border-bottom: 1px solid var(--border);
    text-align: left;
    white-space: nowrap;
  }
  .msg-table thead th {
    background: rgba(255,255,255,0.03);
    color: var(--text-dim);
    font-weight: 700;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    border-bottom: 1px solid var(--border);
  }
  .msg-table tbody tr:last-child td { border-bottom: none; }
  .msg-table tbody tr:nth-child(even) { background: rgba(255,255,255,0.015); }
  /* Report cards — standard rendering for a "review"/"summary"/"recommendations"
     fenced JSON block (see buildReportCard() in markdown.js), mirroring the
     artifact-card/table-card header treatment above. */
  .report-card {
    margin: 8px 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
  }
  .report-header {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 6px 8px 6px 10px;
    background: rgba(255,255,255,0.03);
    border-bottom: 1px solid var(--border);
  }
  .report-header .icon-svg { width: 13px; height: 13px; color: var(--text-dim); filter: none; }
  .report-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.03em;
  }
  .report-title { font-size: 11.5px; color: var(--text-dim); opacity: 0.8; }
  .report-summary-row {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--border);
    background: rgba(255,255,255,0.015);
  }
  .report-summary { flex: 1; margin: 0; font-size: 12.5px; line-height: 1.5; font-style: italic; }
  .report-listen {
    flex-shrink: 0;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 20px;
    padding: 2px 9px;
    font-size: 10px;
    cursor: pointer;
  }
  .report-listen:hover { color: var(--text); border-color: var(--text-dim); }
  .report-listen.playing { color: var(--verdigris); border-color: var(--verdigris); }
  .report-listen.loading { cursor: default; }
  .report-body { padding: 4px 10px; }
  .report-item { padding: 7px 0; border-bottom: 1px solid var(--border); }
  .report-item:last-child { border-bottom: none; }
  .report-item-head { display: flex; align-items: baseline; gap: 7px; }
  .report-item-label { font-size: 13px; font-weight: 600; }
  .report-item-detail { margin-top: 2px; font-size: 12.5px; color: var(--text-dim); }
  .report-empty { padding: 6px 0; font-size: 12.5px; color: var(--text-dim); }
  .report-tag {
    flex-shrink: 0;
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 1px 6px;
    border-radius: 4px;
    border: 1px solid currentColor;
  }
  .report-tag-red { color: var(--red); }
  .report-tag-amber { color: var(--amber); }
  .report-tag-verdigris { color: var(--verdigris); }
  .report-tag-dim { color: var(--text-dim); }
  .msg-user blockquote, .msg-assistant blockquote {
    margin: 6px 0;
    padding: 2px 0 2px 10px;
    border-left: 3px solid var(--border);
    color: var(--text-dim);
  }
  .msg-user blockquote p, .msg-assistant blockquote p { margin: 0 0 4px; }
  .msg-user blockquote p:last-child, .msg-assistant blockquote p:last-child { margin-bottom: 0; }
  .msg-user hr, .msg-assistant hr { border: none; border-top: 1px solid var(--border); margin: 10px 0; }
  .msg-user del, .msg-assistant del { color: var(--text-dim); }
  .msg-user a, .msg-assistant a {
    color: var(--accent-2);
    text-decoration: underline;
    text-underline-offset: 2px;
    word-break: break-all;
  }
  .msg-user a:hover, .msg-assistant a:hover { color: var(--accent); }
  .msg-img-link { display: inline-block; }
  .msg-img {
    display: block;
    max-width: 100%;
    max-height: 360px;
    border-radius: 8px;
    margin: 6px 0;
    border: 1px solid var(--border);
  }
  .msg-bubble-foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 6px;
  }
  .msg-bubble-time { font-size: 10.5px; color: var(--text-dim); white-space: nowrap; }
  .msg-bubble-copy {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 20px;
    padding: 2px 9px;
    font-size: 10px;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s, color 0.12s, border-color 0.12s;
  }
  .msg-assistant:hover .msg-bubble-copy, .msg-bubble-copy:focus-visible { opacity: 1; }
  .msg-bubble-copy:hover { color: var(--text); border-color: var(--text-dim); }
  .msg-bubble-listen.loading, .msg-bubble-listen.playing { opacity: 1; }
  .msg-bubble-listen.playing { color: var(--verdigris); border-color: var(--verdigris); }
  .msg-bubble-listen.loading { cursor: default; }
  .msg-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 8px 2px 0;
  }
  /* Live "how long is this likely to take" chip — see etaBadgeHtml() in
     workspace-thread.js. Sits next to the running/queued status badge and
     updates in place as the run's current action changes. */
  .eta-badge {
    background: rgba(62,90,76,0.15);
    color: var(--accent);
    animation: eta-badge-fade 0.4s ease;
  }
  .eta-badge .icon-svg { color: var(--accent); }
  @keyframes eta-badge-fade { 0% { opacity: 0.3; } 100% { opacity: 1; } }
  .actions-toggle {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 20px;
    padding: 3px 10px;
    font-size: 10.5px;
    cursor: pointer;
  }
  .actions-toggle:hover { color: var(--text); border-color: var(--text-dim); }
  .msg-actions { margin-top: 8px; }

  /* Pin toggle — sits in a turn's .msg-meta row (pins the operator's prompt)
     and in each assistant bubble's .msg-bubble-foot (pins that one reply). */
  .pin-toggle {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 20px;
    padding: 2px 8px;
    font-size: 11px;
    line-height: 1.5;
    cursor: pointer;
    opacity: 0.55;
    transition: opacity 0.12s, color 0.12s, border-color 0.12s;
  }
  .pin-toggle:hover { opacity: 1; color: var(--text); border-color: var(--text-dim); }
  .pin-toggle.pinned { opacity: 1; color: var(--amber); border-color: var(--amber); }
  .pin-toggle:hover .icon-svg { color: var(--text); filter: none; }
  .pin-toggle.pinned .icon-svg { color: var(--amber); filter: drop-shadow(0 0 5px rgba(245,184,79,0.5)); }
  .msg-bubble-foot .pin-toggle { margin-right: auto; opacity: 0; }
  .msg-assistant:hover .msg-bubble-foot .pin-toggle,
  .msg-bubble-foot .pin-toggle.pinned,
  .msg-bubble-foot .pin-toggle:focus-visible { opacity: 1; }
  .msg-bubble-foot .pin-toggle.pinned { opacity: 1 !important; }

  /* Pinned panel — collapsible strip above the message list */
  #pinned-panel {
    border-bottom: 1px solid var(--border);
    background: var(--panel);
    padding: 8px 24px;
  }
  #pinned-toggle {
    color: var(--amber);
    font-size: 11.5px;
    font-weight: 700;
    padding: 3px 0;
  }
  /* Capped and independently scrollable for the same reason as
     #workspace-tasks-list (tasks.css) — an unbounded list of pins can push the
     composer off the bottom of a short mobile viewport with no way back. */
  #pinned-list { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; max-height: 240px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .pinned-item {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 6px 10px;
    font-size: 12px;
  }
  .pinned-author {
    flex-shrink: 0;
    font-weight: 700;
    color: var(--text-dim);
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
  }
  /* min-width: 0 is required for the ellipsis above to actually engage —
     a flex item's default min-width is its content size, which for
     nowrap text is its full unwrapped width, so without this a long pin
     just pushes the jump/remove buttons off the row instead of truncating. */
  .pinned-text { flex: 1; min-width: 0; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pinned-time { flex-shrink: 0; color: var(--text-dim); font-size: 10.5px; }
  .pinned-jump, .pinned-remove {
    flex-shrink: 0;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 14px;
    padding: 2px 8px;
    font-size: 10.5px;
    cursor: pointer;
  }
  .pinned-jump:hover { color: var(--text); border-color: var(--text-dim); }
  .pinned-remove:hover { color: var(--red); border-color: var(--red); }

  /* Brief highlight when jumping to a pinned message from the panel */
  .pin-flash { animation: pin-flash-anim 1.4s ease; }
  @keyframes pin-flash-anim {
    0% { box-shadow: 0 0 0 2px var(--amber); }
    100% { box-shadow: 0 0 0 0 transparent; }
  }

  /* Tasks panel — same collapsible-strip pattern as the pinned panel above,
     showing this workspace's own tasks (see tasks.css for .task-row) instead of
     the old project-wide Tasks tab. */
  #workspace-tasks-panel {
    border-bottom: 1px solid var(--border);
    background: var(--panel);
    padding: 8px 24px;
  }
  #workspace-tasks-toggle {
    color: var(--accent);
    font-size: 11.5px;
    font-weight: 700;
    padding: 3px 0;
  }

