  * { margin: 0; padding: 0; box-sizing: border-box; }

  :root {
    /* ── DMSi Brand Palette ── */
    --brand-500: #9e3004;
    --brand-400: #df4405;
    --brand-300: #e56937;
    --brand-200: #f0a98c;
    --brand-100: #FCECE6;

    --action-600: #00486B;
    --action-500: #00365A;
    --action-400: #0077C8;
    --action-300: #459AD4;
    --action-200: #D0E5F4;
    --action-100: #E7F2F9;

    /* ── Standard Palette ── */
    --neutral-600: #000000;
    --neutral-500: #353636;
    --neutral-400: #6b6d6d;
    --neutral-300: #C1C1C1;
    --neutral-200: #EBEBEB;
    --neutral-100: #F7F7F7;
    --neutral-000: #ffffff;

    --success-500: #126240;
    --success-400: #27D68B;
    --success-300: #61E1AA;
    --success-200: #D7F7E9;
    --success-100: #EEFBF6;

    --warning-500: #91670C;
    --warning-400: #F0A913;
    --warning-300: #F4C053;
    --warning-200: #F9DFA9;
    --warning-100: #FCEFD4;

    --critical-500: #892615;
    --critical-400: #CC391F;
    --critical-300: #DD5E48;
    --critical-200: #F0B7AD;
    --critical-100: #FBEDEA;

    /* ── Chart Order ── */
    --teal-400: #40C1AC;
    --purple-400: #8D267A;
    --orange-400: #CC391F;
    --chart-1: var(--action-400);
    --chart-2: var(--brand-400);
    --chart-3: var(--teal-400);
    --chart-4: var(--warning-400);
    --chart-5: var(--neutral-400);
    --chart-6: var(--purple-400);
    --chart-7: var(--orange-400);

    /* ── UI Surfaces (light mode default) ── */
    --bg: var(--neutral-100);
    --surface: var(--neutral-000);
    --surface2: var(--neutral-200);
    --border: var(--neutral-300);
    --text: var(--neutral-500);
    --text-muted: var(--neutral-400);

    /* ── Semantic Colors (light mode default) ── */
    --accent: var(--action-400);
    --accent-dim: var(--action-200);
    --green: var(--success-500);
    --yellow: var(--warning-500);
    --red: var(--critical-400);
    --orange: var(--brand-500);
    --btn-text: var(--neutral-000);
    --shadow: rgba(0,0,0,0.12);
    --accent-bg: rgba(0,119,200,0.10);
    --accent-bg2: rgba(0,119,200,0.12);
    --accent-bg3: rgba(0,119,200,0.15);
    --green-bg: rgba(18,98,64,0.15);
    --green-bg-subtle: rgba(18,98,64,0.08);
    --green-bg-row: rgba(18,98,64,0.06);
    --yellow-bg: rgba(145,103,12,0.15);
    --yellow-bg-subtle: rgba(145,103,12,0.08);
    --red-bg: rgba(204,57,31,0.15);
    --red-bg-subtle: rgba(204,57,31,0.06);
    --red-border: rgba(204,57,31,0.4);
    --radius: 8px;

    /* ── Typography ── */
    --font-heading: 'Montserrat', sans-serif;
    --font-ui: 'Open Sans', sans-serif;
    --font-body: 'Inter', sans-serif;
    --text-heading: 24px;
    --text-body: 12px;
    --text-caption: 12px;
    --text-badge: 10px;
    --leading-body: 150%;
    --leading-caption: 16px;
    --weight-regular: 400;
    --weight-semibold: 600;
    --weight-bold: 700;
  }

  /* Dark mode disabled for beta — light mode forced regardless of OS preference.
     To re-enable, uncomment the @media block below.
  @media (prefers-color-scheme: dark) {
    :root {
      --bg: var(--neutral-600);
      --surface: var(--neutral-500);
      --surface2: var(--neutral-400);
      --border: var(--neutral-400);
      --text: var(--neutral-100);
      --text-muted: var(--neutral-300);
      --accent: var(--action-400);
      --accent-dim: var(--action-500);
      --green: var(--success-300);
      --yellow: var(--warning-400);
      --red: var(--critical-300);
      --orange: var(--brand-400);
      --btn-text: var(--neutral-600);
      --shadow: rgba(0,0,0,0.3);
      --accent-bg: rgba(0,119,200,0.10);
      --accent-bg2: rgba(0,119,200,0.12);
      --accent-bg3: rgba(0,119,200,0.15);
      --green-bg: rgba(97,225,170,0.15);
      --green-bg-subtle: rgba(97,225,170,0.08);
      --green-bg-row: rgba(97,225,170,0.06);
      --yellow-bg: rgba(240,169,19,0.15);
      --yellow-bg-subtle: rgba(240,169,19,0.08);
      --red-bg: rgba(221,94,72,0.15);
      --red-bg-subtle: rgba(221,94,72,0.06);
      --red-border: rgba(221,94,72,0.4);
    }
  }
  */

  body {
    font-family: var(--font-body);
    background: var(--bg);
    color: var(--text);
    height: 100vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

  /* Body text elements use Inter (Paragraph style) */
  .chat-bubble,
  .action-object,
  .preview-field-value,
  .preview-card-body,
  .inline-action .inline-label,
  .order-lines-table-row {
    font-family: var(--font-body);
  }

  /* ── Top Bar ── */
  .topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 24px;
    background: var(--action-600);
    flex-shrink: 0;
    min-height: 56px;
  }

  .topbar-left {
    display: flex;
    align-items: center;
    gap: 14px;
  }

  .logo {
    font-family: var(--font-heading);
    font-size: var(--text-heading);
    letter-spacing: -0.5px;
    color: var(--neutral-000);
    white-space: nowrap;
  }

  .logo-light { font-weight: var(--weight-regular); }
  .logo-bold { font-weight: var(--weight-semibold); }

  .beta-badge {
    font-size: var(--text-badge);
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    letter-spacing: 1px;
    background: var(--accent);
    color: var(--neutral-000);
    padding: 2px 8px;
    border-radius: 4px;
  }

  /* DMS-396: in-app "What's New" overlay (sidebar-triggered; no navigation → no auth/chat-state loss). */
  .whats-new-overlay {
    position: fixed; inset: 0; z-index: 9998;
    background: rgba(0,0,0,0.5);
    display: flex; align-items: center; justify-content: center;
    padding: 40px 20px;
  }
  .whats-new-overlay.hidden { display: none; }
  .whats-new-card {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 12px; width: 760px; max-width: 100%; max-height: 85vh;
    display: flex; flex-direction: column; overflow: hidden;
    box-shadow: 0 8px 32px var(--shadow);
  }
  .whats-new-card-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px 24px; flex-shrink: 0;
    background: var(--action-600); color: var(--neutral-000);
  }
  .whats-new-card-title {
    font-family: var(--font-heading); font-size: 14px; font-weight: var(--weight-semibold);
    text-transform: uppercase; letter-spacing: 1px;
  }
  .whats-new-close {
    background: none; border: none; color: var(--neutral-000);
    font-size: 24px; line-height: 1; cursor: pointer; padding: 0 4px; opacity: 0.8;
  }
  .whats-new-close:hover { opacity: 1; }
  .whats-new-card-body {
    padding: 24px 32px 32px; overflow-y: auto;
    font-size: 14px; line-height: 1.6; color: var(--text);
  }
  .whats-new-card-body h1 { font-family: var(--font-heading); font-size: 22px; margin: 4px 0 2px; color: var(--action-500); }
  .whats-new-card-body h2 { font-family: var(--font-heading); font-size: 17px; margin: 24px 0 8px; padding-bottom: 5px; border-bottom: 1px solid var(--border); color: var(--action-600); }
  .whats-new-card-body h3 { font-size: 14px; margin: 16px 0 4px; color: var(--action-600); }
  .whats-new-card-body a { color: var(--accent); }
  .whats-new-card-body code { background: var(--neutral-200); padding: 1px 5px; border-radius: 4px; font-size: 12px; }
  .whats-new-card-body hr { border: none; border-top: 1px solid var(--border); margin: 20px 0; }
  .whats-new-card-body ul { padding-left: 20px; margin: 8px 0; }
  .whats-new-card-body li { margin: 4px 0; }
  .whats-new-card-body em { color: var(--text-muted); }
  .whats-new-status { color: var(--text-muted); }
  .whats-new-status.error { color: var(--red); }

  /* ── DMS-395: "Send feedback" modal (mirrors the What's New overlay) ── */
  .feedback-overlay {
    position: fixed; inset: 0; z-index: 9998;
    background: rgba(0,0,0,0.5);
    display: flex; align-items: center; justify-content: center;
    padding: 40px 20px;
  }
  .feedback-overlay.hidden { display: none; }
  .feedback-card {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 12px; width: 520px; max-width: 100%; max-height: 85vh;
    display: flex; flex-direction: column; overflow: hidden;
    box-shadow: 0 8px 32px var(--shadow);
  }
  .feedback-card-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px 24px; flex-shrink: 0;
    background: var(--action-600); color: var(--neutral-000);
  }
  .feedback-card-title {
    font-family: var(--font-heading); font-size: 14px; font-weight: var(--weight-semibold);
    text-transform: uppercase; letter-spacing: 1px;
  }
  .feedback-close {
    background: none; border: none; color: var(--neutral-000);
    font-size: 24px; line-height: 1; cursor: pointer; padding: 0 4px; opacity: 0.8;
  }
  .feedback-close:hover { opacity: 1; }
  .feedback-card-body {
    padding: 20px 24px; overflow-y: auto;
    font-size: 14px; line-height: 1.5; color: var(--text);
  }
  .feedback-intro { color: var(--text-muted); margin-bottom: 16px; font-size: 13px; }
  .feedback-field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 16px; }
  .feedback-label {
    font-family: var(--font-heading);
    font-size: 11px;
    font-weight: var(--weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
  }
  .feedback-select,
  .feedback-textarea {
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--text);
    background: var(--neutral-000);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 8px 10px;
    width: 100%;
    transition: border-color .15s;
  }
  .feedback-select { cursor: pointer; }
  .feedback-textarea { resize: vertical; min-height: 96px; line-height: 1.5; }
  .feedback-select:focus,
  .feedback-textarea:focus { outline: none; border-color: var(--accent); }
  .feedback-error {
    color: var(--red);
    background: var(--red-bg-subtle);
    border: 1px solid var(--red-border);
    border-radius: 6px;
    padding: 8px 10px;
    font-size: 13px;
    margin-top: 4px;
  }
  .feedback-error[hidden] { display: none; }
  .feedback-card-footer {
    display: flex; justify-content: flex-end; gap: 10px;
    padding: 14px 24px; flex-shrink: 0;
    border-top: 1px solid var(--border);
  }
  .feedback-btn {
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: var(--weight-semibold);
    border-radius: 6px;
    padding: 8px 16px;
    cursor: pointer;
    transition: opacity .15s, background .15s, border-color .15s;
  }
  .feedback-btn:disabled { opacity: 0.6; cursor: default; }
  .feedback-btn-primary {
    background: var(--accent);
    color: var(--btn-text);
    border: 1px solid var(--accent);
  }
  .feedback-btn-primary:hover:not(:disabled) { opacity: 0.85; }
  .feedback-btn-secondary {
    background: transparent;
    color: var(--text-muted);
    border: 1px solid var(--border);
  }
  .feedback-btn-secondary:hover:not(:disabled) { color: var(--text); border-color: var(--accent); }

  /* DMS-584: feedback trigger is a floating pill, bottom-right of the chat
     panel and offset just above the composer (positioned against
     .chat-input-area). Hidden while disabled (no answerable conversation yet)
     and while any full-screen overlay is open, so it never covers the last
     message. The feedback overlay + POST /feedback wiring (DMS-395) is
     unchanged; only the trigger moved. */
  .feedback-fab {
    position: absolute;
    right: 18px;
    bottom: calc(100% + 12px);
    z-index: 30;
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: var(--weight-semibold);
    color: var(--text-muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 7px 14px;
    cursor: pointer;
    white-space: nowrap;
    box-shadow: 0 2px 10px var(--shadow);
    transition: color .15s, border-color .15s, box-shadow .15s;
  }
  .feedback-fab:hover:not(:disabled) {
    color: var(--accent); border-color: var(--accent);
    box-shadow: 0 4px 14px var(--shadow);
  }
  /* updateFeedbackButton() toggles :disabled; a disabled FAB is not shown. */
  .feedback-fab:disabled { display: none; }
  /* Overlays are full-screen; drop the FAB entirely while one is open. */
  body:has(#login-overlay:not(.hidden)) .feedback-fab,
  body:has(#whats-new-overlay:not(.hidden)) .feedback-fab,
  body:has(#feedback-overlay:not(.hidden)) .feedback-fab { display: none; }

  /* Toast — small, transient confirmation/error, bottom-center. */
  .feedback-toast {
    position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
    z-index: 9999;
    background: var(--neutral-500); color: var(--neutral-000);
    font-family: var(--font-body); font-size: 13px;
    padding: 10px 18px; border-radius: 8px;
    box-shadow: 0 4px 16px var(--shadow);
    max-width: 80vw;
  }
  .feedback-toast[hidden] { display: none; }
  .feedback-toast.error { background: var(--critical-500); }

  /* ── Left Sidebar ── */
  .sidebar {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-right: 1px solid var(--border);
    background: var(--surface);
  }

  .sidebar-top {
    flex-shrink: 0;
    padding: 16px;
    position: relative;
  }

  .sidebar-nav {
    padding: 8px 16px;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }

  .sidebar-nav-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--text-body);
    padding: 6px 8px;
    cursor: pointer;
    border-radius: 4px;
    transition: background 0.12s;
  }

  .sidebar-nav-item:hover { background: var(--neutral-200); }
  /* DMS-584: nav glyphs are inline SVGs (no emoji), muted to match the label. */
  .sidebar-nav-item .nav-icon {
    display: inline-flex; align-items: center; flex-shrink: 0;
    color: var(--text-muted);
  }
  .sidebar-nav-item .nav-icon svg { width: 15px; height: 15px; display: block; }

  .sidebar-divider {
    border: none;
    border-top: 1px solid var(--border);
    margin: 8px 16px;
  }

  .sidebar-search {
    display: block;
    width: calc(100% - 32px);
    margin: 0 16px 8px;
    padding: 6px 10px;
    font-size: var(--text-body);
    font-family: var(--font-body);
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface);
    color: var(--text);
    outline: none;
  }

  .sidebar-search:focus { border-color: var(--accent); }

  .new-conv-btn {
    background: var(--accent);
    border: none;
    border-radius: var(--radius);
    padding: 8px 14px;
    font-size: var(--text-body);
    font-weight: var(--weight-semibold);
    cursor: pointer;
    transition: opacity 0.15s;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .new-conv-btn:hover { opacity: 0.85; }

  .new-conv-btn .arrow {
    font-size: var(--text-badge);
    margin-left: 6px;
  }

  .new-conv-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 12px;
    right: 12px;
    background: var(--surface2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    z-index: 10;
    box-shadow: 0 4px 12px var(--shadow);
  }

  .new-conv-menu.open { display: block; }

  .new-conv-menu-item {
    padding: 10px 14px;
    font-size: var(--text-caption);
    cursor: pointer;
    transition: background 0.12s;
    border-bottom: 1px solid var(--border);
  }

  .new-conv-menu-item:last-child { border-bottom: none; }
  .new-conv-menu-item:hover { background: var(--accent-dim); color: var(--accent); }

  .sidebar-section-label {
    padding: 8px 16px 4px;
    font-size: 16px;
    font-weight: var(--weight-bold);
    color: var(--accent);
  }

  .conv-list-wrap {
    overflow-y: auto;
    flex: 1;
    min-height: 0;
  }

  .conv-list { list-style: none; }

  .conv-item {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    cursor: pointer;
    transition: background 0.12s;
    border-bottom: 1px solid var(--border);
  }

  .conv-item:last-child { border-bottom: none; }
  .conv-item:hover { background: var(--surface2); }

  .conv-item.active {
    background: var(--action-100);
    border-left: 3px solid var(--accent);
    padding-left: 9px;
  }

  .conv-item-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
  }

  .conv-item-title {
    font-size: var(--text-caption);
    font-weight: var(--weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .conv-item-meta {
    font-size: var(--text-badge);
    color: var(--text-muted);
  }

  .conv-item-agent {
    font-size: var(--text-badge);
    color: var(--accent);
    font-weight: var(--weight-semibold);
  }

  .conv-rename-input {
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--accent);
    border-radius: 4px;
    padding: 2px 6px;
    font-size: var(--text-caption);
    font-family: inherit;
    outline: none;
    width: 100%;
  }

  .conv-btn {
    display: inline-flex; align-items: center; justify-content: center;
    background: none;
    color: var(--text-muted);
    border: none;
    font-size: 11px;
    cursor: pointer;
    padding: 2px 4px;
    border-radius: 3px;
    flex-shrink: 0;
    transition: color 0.12s;
    opacity: 0;
  }
  .conv-btn.rename svg { width: 13px; height: 13px; display: block; }

  .conv-item:hover .conv-btn { opacity: 1; }

  .conv-btn.rename:hover { color: var(--accent); }
  .conv-btn.delete:hover { color: var(--red); }

  /* ── Actions Column ── */
  .actions-column {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-right: 1px solid var(--border);
  }

  .actions-column-header {
    padding: 14px 12px;
    font-size: var(--text-badge);
    font-weight: var(--weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-shrink: 0;
  }

  .actions-column-body {
    overflow-y: auto;
    flex: 1;
  }

  /* ── Layout ── */
  .layout {
    display: grid;
    grid-template-columns: 320px 260px 1fr minmax(320px, 400px);
    gap: 0;
    flex: 1;
    overflow: hidden;
  }

  .column {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-right: 1px solid var(--border);
  }

  .column:last-child { border-right: none; }

  .column-header {
    padding: 14px 18px;
    font-size: var(--text-body);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-body);
    color: var(--text);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
  }

  .column-header #chat-conv-title {
    font-size: 18px;
    font-weight: var(--weight-bold);
  }

  .column-body {
    flex: 1;
    overflow-y: auto;
    padding: 12px;
  }

  .action-item {
    display: grid;
    grid-template-columns: 52px 1fr 36px;
    align-items: center;
    gap: 0;
    padding: 6px 12px;
    transition: opacity 0.25s, background 0.15s;
    cursor: default;
    border-bottom: 1px solid var(--border);
  }

  .action-item:last-child { border-bottom: none; }

  .action-item:hover { background: var(--surface2); }

  .action-item.highlight,
  .inline-action.highlight {
    background: var(--accent-bg2);
  }

  .action-item.undone {
    opacity: 0.35;
  }

  .action-item.undone .action-badge { filter: grayscale(1); }

  .action-undo-btn {
    background: none;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 2px 0;
    font-size: var(--text-badge);
    cursor: pointer;
    transition: all 0.15s;
    line-height: 1.3;
    text-align: center;
    width: 32px;
  }

  .action-undo-btn:hover {
    background: var(--accent-dim);
    color: var(--accent);
    border-color: var(--accent-dim);
  }

  .action-item.undone .action-undo-btn {
    opacity: 1;
  }

  .action-badge {
    font-size: var(--text-badge);
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    padding: 2px 0;
    border-radius: 3px;
    letter-spacing: 0.3px;
    text-align: center;
    width: 46px;
  }

  .action-badge.create { background: var(--green-bg); color: var(--green); }
  .action-badge.read   { background: var(--accent-bg3); color: var(--accent); }
  .action-badge.update { background: var(--yellow-bg); color: var(--yellow); }
  .action-badge.delete { background: var(--red-bg); color: var(--red); }

  .action-details {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    padding: 0 8px;
  }

  .action-object {
    font-size: var(--text-body);
    font-weight: var(--weight-regular);
    line-height: var(--leading-body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .action-id {
    font-size: var(--text-caption);
    line-height: var(--leading-caption);
    color: var(--text-muted);
  }


  /* ── Inline Tool Calls ── */
  .inline-actions {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 6px;
  }

  .inline-action {
    display: grid;
    grid-template-columns: 46px 1fr auto;
    align-items: center;
    gap: 0;
    padding: 4px 8px;
    border-radius: 4px;
    border: 1px solid var(--border);
    background: var(--bg);
    font-size: var(--text-caption);
    transition: opacity 0.25s, background 0.15s;
  }

  .inline-action.undone {
    opacity: 0.35;
  }

  .inline-action.undone .action-badge { filter: grayscale(1); }

  .inline-action .action-badge {
    font-size: var(--text-badge);
    width: 46px;
    padding: 2px 0;
  }

  .inline-action .inline-label {
    font-size: var(--text-caption);
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 0 8px;
  }

  .inline-action .action-undo-btn {
    width: 32px;
    font-size: 9px;
    padding: 1px 0;
    justify-self: end;
  }

  /* DMS-584: finished tool rows (a settled turn, a 1-2 row run, or an expanded
     compacted run) read as flat, slightly greyed text, no border or pill, so
     completed activity recedes and the conversation stays the focus. The LIVE
     streaming rows are scoped OUT (they live under [data-stream-live] and are
     untouched) so an in-flight run looks exactly as it does today (DMS-541). The
     undo control and the status dot survive the restyle and stay clickable: the
     undo button keeps its own control chrome, and the success/error dot colors
     are set explicitly (not inherited) so muting the label never hides them. */
  .chat-msg.actions:not([data-stream-live]) .inline-action {
    border: none;
    background: transparent;
    padding: 3px 8px;
  }
  .chat-msg.actions:not([data-stream-live]) .inline-action .action-badge {
    background: transparent;
    padding: 0;
  }
  .chat-msg.actions:not([data-stream-live]) .inline-action .inline-label {
    color: var(--text-muted);
  }
  /* Keep the revert / hover highlight visible on the flat rows. */
  .chat-msg.actions:not([data-stream-live]) .inline-action.highlight {
    background: var(--accent-bg2);
  }

  /* ── Chat ── */
  .chat-column { background: var(--bg); }
  .chat-column .column-body {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 20px 24px;
    background: var(--neutral-000);
  }

  .chat-msg {
    display: flex;
    flex-direction: column;
    max-width: 85%;
  }

  .chat-msg.agent   { align-self: flex-start; }
  .chat-msg.user    { align-self: flex-end; }
  .chat-msg.actions { align-self: stretch; max-width: 100%; }

  .chat-msg.revert-highlight {
    outline: 1px solid var(--red-border);
    border-radius: 8px;
    background: var(--red-bg-subtle);
  }

  .chat-msg.revert-highlight .chat-bubble {
    opacity: 0.5;
  }

  .chat-msg.revert-highlight .inline-actions {
    opacity: 0.5;
  }

  .revert-btn {
    background: none;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 2px 8px;
    font-size: var(--text-badge);
    cursor: pointer;
    transition: all 0.15s;
    align-self: flex-end;
    margin-top: 4px;
  }

  .revert-btn:hover {
    background: var(--red-bg);
    color: var(--red);
    border-color: var(--red-border);
  }

  .chat-agent-name {
    font-size: var(--text-caption);
    font-weight: var(--weight-semibold);
    color: var(--accent);
    margin-bottom: 3px;
    padding-left: 2px;
  }

  .chat-bubble {
    padding: 10px 14px;
    border-radius: 12px;
    font-size: var(--text-body);
    line-height: var(--leading-body);
  }

  .chat-msg.agent .chat-bubble {
    background: var(--neutral-100);
    border-top-left-radius: 4px;
  }

  .chat-msg.user .chat-bubble {
    background: var(--accent);
    color: var(--neutral-000);
    border-top-right-radius: 4px;
  }

  /* DMS-584: attachments render as a compact pill (paperclip + filename) inside
     the user bubble, not a full-width iframe/image preview. The bubble is
     accent-colored, so the pill is a translucent-white chip that stays legible
     on it. */
  .chat-attachment {
    /* DMS-643: block-level flex + fit-content, not inline-flex. The chip still
       shrink-wraps, but the message text now starts on the line BELOW it in
       every case. As inline-flex the text ran on beside the chip, which only
       became visible once previewable files started breaking to a new line
       (the preview below is a block) and non-previewable ones did not. */
    display: flex;
    width: fit-content;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    margin-bottom: 8px;
    padding: 5px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.16);
    border: 1px solid rgba(255, 255, 255, 0.28);
    color: var(--neutral-000);
  }

  .chat-attachment-icon { width: 14px; height: 14px; flex-shrink: 0; opacity: 0.9; }

  .chat-attachment-name {
    font-size: 12px;
    font-family: var(--font-body);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 240px;
  }

  /* DMS-643: the inline preview sits UNDER the pill, always rendered, never
     click-to-expand. The pre-DMS-584 rules assumed a light bubble; the bubble is
     accent-coloured now, so the preview is a white card that reads as a document
     sitting on it rather than a transparent hole in it. */
  .chat-attachment-preview {
    margin-bottom: 8px;
    border-radius: 8px;
    overflow: hidden;
    background: var(--neutral-000);
    border: 1px solid rgba(255, 255, 255, 0.28);
    line-height: 0;   /* kill the inline-descender gap under the img/iframe */
  }

  /* An explicit width, not `width: 100%`. The user bubble is a shrink-to-fit
     flex item, so a percentage width on the iframe resolves against a parent
     whose width the iframe is itself supposed to determine — the circularity
     collapses to the iframe's 300px intrinsic default and squeezes the PDF
     viewer into a column. A fixed width sizes the bubble; max-width lets it
     shrink again on a narrow window, where .chat-msg's 85% cap binds first. */
  .chat-attachment-pdf {
    width: 460px;
    max-width: 100%;
    height: 420px;
    border: none;
    display: block;
    background: var(--neutral-100);
  }

  .chat-attachment-img {
    max-width: 100%;
    max-height: 420px;
    display: block;
    margin: 0 auto;
  }

  .chat-attachment-error {
    margin-bottom: 8px;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: 12px;
    background: rgba(255, 255, 255, 0.16);
    border: 1px solid rgba(255, 255, 255, 0.28);
    color: var(--neutral-000);
  }

  .chat-input-area {
    position: relative;
    padding: 16px 18px;
    border-top: 1px solid var(--border);
    background: var(--surface);
    flex-shrink: 0;
  }

  .chat-input-wrap {
    display: flex;
    gap: 8px;
    align-items: flex-end;
  }

  .chat-input-wrap textarea {
    flex: 1;
    background: var(--neutral-000);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 10px 14px;
    font-size: var(--text-body);
    font-family: var(--font-body);
    resize: none;
    outline: none;
    min-height: 42px;
    max-height: 120px;
  }

  .chat-input-wrap textarea:focus { border-color: var(--accent); }

  .chat-input-wrap textarea::placeholder { color: var(--text-muted); }

  .send-btn {
    background: var(--accent);
    border: none;
    border-radius: var(--radius);
    padding: 10px 16px;
    font-size: var(--text-body);
    font-weight: var(--weight-semibold);
    cursor: pointer;
    transition: opacity 0.15s;
    white-space: nowrap;
  }

  .send-btn:hover { opacity: 0.85; }

  /* ── Pending Changes Preview ── */
  .preview-column .column-body {
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .preview-disclaimer {
    font-size: var(--text-caption);
    color: var(--text-muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 8px 12px;
    line-height: var(--leading-caption);
  }

  .preview-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
  }

  .preview-card-header {
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .preview-card-title {
    font-weight: var(--weight-semibold);
    font-size: var(--text-body);
  }

  .preview-card-op {
    font-size: var(--text-badge);
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    padding: 2px 6px;
    border-radius: 3px;
    letter-spacing: 0.3px;
  }

  .preview-card-op.create { background: var(--green-bg); color: var(--green); }
  .preview-card-op.update { background: var(--yellow-bg); color: var(--yellow); }
  .preview-card-op.delete { background: var(--red-bg); color: var(--red); }

  .preview-card-body {
    padding: 10px 14px;
    font-size: var(--text-body);
  }

  .preview-card-body.deleted {
    text-decoration: line-through;
    opacity: 0.6;
  }

  .preview-field {
    display: flex;
    justify-content: space-between;
    padding: 4px 0;
    border-bottom: 1px solid var(--border);
  }

  .preview-field:last-child { border-bottom: none; }

  .preview-field-label {
    color: var(--text-muted);
    font-size: var(--text-caption);
    min-width: 70px;
  }

  .preview-field-value {
    text-align: right;
    font-size: var(--text-body);
  }

  .field-created {
    background: var(--green-bg-subtle);
    padding: 2px 6px;
    border-radius: 3px;
    color: var(--green);
  }

  .field-updated {
    background: var(--yellow-bg-subtle);
    padding: 2px 6px;
    border-radius: 3px;
    color: var(--yellow);
  }

  .order-lines-table {
    width: 100%;
    margin-top: 6px;
  }

  .order-lines-table-header {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: 4px;
    padding: 6px 0;
    font-size: var(--text-badge);
    font-weight: var(--weight-semibold);
    text-transform: uppercase;
    color: var(--text-muted);
    letter-spacing: 0.3px;
    border-bottom: 1px solid var(--border);
  }

  .order-lines-table-row {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: 4px;
    padding: 6px 0;
    font-size: var(--text-caption);
    border-bottom: 1px solid var(--border);
  }

  .order-lines-table-row:last-child { border-bottom: none; }

  .order-lines-table-row.row-created {
    background: var(--green-bg-row);
  }

  .order-lines-table-row .amount { text-align: right; }

  .order-total-row {
    display: flex;
    justify-content: space-between;
    padding: 8px 0 2px;
    font-weight: var(--weight-semibold);
    font-size: var(--text-body);
    border-top: 1px solid var(--border);
    margin-top: 4px;
  }

  .order-total-row .total-label { color: var(--text-muted); }

  .preview-card-apply {
    padding: 8px 14px;
    border-top: 1px solid var(--border);
  }

  .preview-card-apply-btn {
    border: none;
    border-radius: var(--radius);
    padding: 6px 12px;
    font-size: var(--text-caption);
    font-weight: var(--weight-semibold);
    cursor: pointer;
    transition: opacity 0.15s;
    width: 100%;
  }

  .preview-card-apply-btn:hover { opacity: 0.85; }
  .preview-card-apply-btn.op-create { background: var(--green); }
  .preview-card-apply-btn.op-update { background: var(--yellow); }
  .preview-card-apply-btn.op-delete { background: var(--red); }

  .preview-footer {
    padding: 12px;
    border-top: 1px solid var(--border);
    background: var(--surface);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .preview-count {
    font-size: var(--text-caption);
    color: var(--text-muted);
    text-align: center;
  }

  .apply-btn {
    background: var(--green);
    border: none;
    border-radius: var(--radius);
    padding: 10px 16px;
    font-size: var(--text-body);
    font-weight: var(--weight-semibold);
    cursor: pointer;
    transition: opacity 0.15s;
    width: 100%;
  }

  .apply-btn:hover { opacity: 0.85; }

  /* ── Dev Panel ── */
  .dev-toggle {
    position: fixed;
    bottom: 12px;
    left: 12px;
    z-index: 100;
    background: var(--surface2);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-muted);
    font-size: var(--text-badge);
    font-weight: var(--weight-semibold);
    letter-spacing: 0.5px;
    padding: 4px 8px;
    cursor: pointer;
    opacity: 0.6;
    transition: opacity 0.15s;
  }

  .dev-toggle:hover { opacity: 1; }

  .dev-panel {
    display: none;
    position: fixed;
    bottom: 12px;
    left: 12px;
    z-index: 100;
    background: var(--surface2);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 10px 12px;
    font-size: 11px;
    min-width: 160px;
    box-shadow: 0 2px 8px var(--shadow);
  }

  .dev-panel.open { display: block; }

  .dev-panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
    color: var(--text-muted);
    font-size: 9px;
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }

  .dev-panel-close {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 13px;
    padding: 0 2px;
    line-height: 1;
  }

  .dev-panel-close:hover { color: var(--text); }

  .dev-panel label {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 3px 0;
    cursor: pointer;
    color: var(--text);
    font-size: 11px;
  }

  .dev-panel input[type="checkbox"] {
    accent-color: var(--accent);
  }

  /* ── Toggle: no-undo ── */
  .no-undo .action-undo-btn { display: none; }
  .no-undo .revert-btn { display: none; }
  .no-undo .action-item { grid-template-columns: 52px 1fr; }
  .no-undo .inline-action { grid-template-columns: 46px 1fr; }
  .no-undo .action-item.undone { opacity: 1; }
  .no-undo .action-item.undone .action-badge { filter: none; }
  .no-undo .inline-action.undone { opacity: 1; }
  .no-undo .inline-action.undone .action-badge { filter: none; }
  .no-undo .chat-msg.revert-highlight { outline: none; background: none; }
  .no-undo .chat-msg.revert-highlight .chat-bubble { opacity: 1; }
  .no-undo .chat-msg.revert-highlight .inline-actions { opacity: 1; }
  .no-undo .preview-card-apply { display: none; }
  .no-undo .preview-footer { display: none; }
  .no-undo .preview-disclaimer { display: none; }

  /* ── Toggle: no-actions ── */
  .no-actions .actions-column { display: none; }
  .no-actions .layout { grid-template-columns: 320px 1fr minmax(320px, 400px); }

  /* ── Toggle: no-changes ── */
  .no-changes .preview-column { display: none; }
  .no-changes .layout { grid-template-columns: 320px 260px 1fr; }

  /* ── Both actions + changes hidden ── */
  .no-actions.no-changes .layout { grid-template-columns: 320px 1fr; }

  /* ── Element overrides (moved from inline styles) ── */
  .topbar-disclaimer { font-size: var(--text-caption); color: rgba(255,255,255,0.7); }
  #action-count { font-size: var(--text-badge); font-weight: var(--weight-regular); }
  #chat-agent-label { font-size: var(--text-caption); font-weight: var(--weight-regular); color: var(--text-muted); text-decoration: none; }
  #preview-title { text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); }
  #pending-count { font-size: var(--text-caption); font-weight: var(--weight-regular); color: var(--yellow); }
  .table-amt { text-align: right; }
  .empty-state { padding: 6px 0; color: var(--text-muted); font-size: var(--text-caption); }
  .empty-state-centered { color: var(--text-muted); text-align: center; margin-top: 40px; }

  /* ── Scrollbar ── */
  ::-webkit-scrollbar { width: 6px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
  ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

  .new-conv-btn { color: var(--btn-text); }
  .send-btn { color: var(--btn-text); }
  .preview-card-apply-btn { color: var(--btn-text); }
  .apply-btn { color: var(--btn-text); }

  /* Logout Button */
  .logout-btn {
    background: none; border: 1px solid rgba(255,255,255,0.3); border-radius: 6px;
    color: var(--neutral-000); font-size: 12px; padding: 6px 14px; cursor: pointer;
    transition: all .15s; flex-shrink: 0;
  }
  .logout-btn:hover { color: var(--red); border-color: var(--red); }

  /* ── DMS-397: build version pill ────────────────────────────────────
     Muted white-on-dark chip in the topbar showing the deployed build
     (git describe value from GET /version). Kept low-contrast so it reads
     as metadata, not a control. `[hidden]` keeps it out of the layout
     until loadAppVersion() populates it (fail-silent). */
  .version-pill {
    font-size: 11px; letter-spacing: 0.02em; color: rgba(255,255,255,0.55);
    font-variant-numeric: tabular-nums; cursor: default; user-select: text;
    white-space: nowrap; flex-shrink: 0;
  }
  .version-pill[hidden] { display: none; }

  /* ── DMS-207 UX-2: Chat-window branch picker ────────────────────────
     Picker lives INSIDE the chat-window header (not the topbar), so users
     understand the branch is per-conversation, not global. White-on-light
     since the chat header sits on the white --surface, unlike the prior
     topbar placement. Two states:
       - editable: <select> (multi-branch) or pill (single-branch)
       - locked: lock pill + "+ New chat" affordance, post-first-message */
  .topbar-right {
    display: flex; align-items: center; gap: 12px; flex-shrink: 0;
  }

  /* Chat column header gets a flex layout so the picker can sit beside
     the title block. DMS-584: both hug the left edge (title, then picker)
     instead of the picker floating on the right. */
  .chat-column-header {
    flex-direction: row;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 16px;
  }
  .chat-column-header-titles {
    display: flex; flex-direction: column; gap: 2px; min-width: 0;
  }

  .chat-branch-picker {
    display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
    flex-shrink: 0;
  }
  .chat-branch-picker[hidden] { display: none; }
  .chat-branch-picker-row {
    display: flex; align-items: center; gap: 6px;
  }
  .chat-branch-picker-label {
    font-family: var(--font-heading);
    font-size: 10px;
    font-weight: var(--weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
  }
  /* ── DMS-666: branch combobox (replaces <select> + separate filter box) ──
     One text input that doubles as the filter, with a listbox we render
     ourselves so the filtered options are visible while the user types. The
     native popup could not do this: it takes keyboard focus, so typing after
     it opened went to the popup's own type-ahead instead of the filter. */
  .chat-branch-combo {
    position: relative;
    display: inline-flex;
    align-items: center;
  }
  .chat-branch-combo[hidden] { display: none; }
  .chat-branch-picker-input {
    font-family: var(--font-body);
    font-size: 12px;
    background: var(--neutral-000);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 5px 22px 5px 10px;   /* room for the caret */
    cursor: pointer;
    width: 260px;          /* matches .chat-branch-listbox — no overhang */
    max-width: 260px;
    text-overflow: ellipsis;
    transition: background .15s, border-color .15s;
  }
  .chat-branch-picker-input:hover { border-color: var(--accent); }
  .chat-branch-picker-input:focus {
    outline: none;
    border-color: var(--accent);
    background: var(--neutral-000);
    cursor: text;
  }
  .chat-branch-picker-input::placeholder { color: var(--text-muted); }
  .chat-branch-combo-caret {
    position: absolute;
    right: 8px;
    font-size: 10px;
    color: var(--text-muted);
    pointer-events: none;
  }
  .chat-branch-listbox {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 40;
    width: 260px;
    /* The chat `.column` ancestor sets overflow:hidden, so an absolutely
       positioned dropdown is clipped rather than allowed to overhang. Clamp to
       the viewport so a short window shrinks the list instead of cutting it
       off mid-row (a full escape needs position:fixed + JS repositioning —
       its own ticket). */
    max-height: min(280px, 45vh);
    overflow-y: auto;
    margin: 0;
    padding: 4px;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  }
  .chat-branch-listbox[hidden] { display: none; }
  .chat-branch-listbox-opt {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 6px 8px;
    border-radius: 5px;
    font-family: var(--font-body);
    font-size: 12px;
    color: var(--text);
    cursor: pointer;
  }
  /* `active` is the keyboard/hover highlight — it is NOT a selection. Only a
     click or Enter commits, so this styling must never read as "chosen". */
  .chat-branch-listbox-opt.active,
  .chat-branch-listbox-opt:hover {
    background: var(--accent-bg);
  }
  .chat-branch-listbox-opt.current {
    font-weight: var(--weight-semibold);
  }
  .chat-branch-listbox-opt.sentinel {
    color: var(--brand-500);
    border-top: 1px solid var(--border);
    margin-top: 4px;
    padding-top: 8px;
  }
  .chat-branch-listbox-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .chat-branch-listbox-sub,
  .chat-branch-listbox-tag {
    flex: 0 0 auto;
    font-size: 10px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.4px;
  }
  .chat-branch-listbox-empty,
  .chat-branch-listbox-more {
    padding: 8px;
    font-family: var(--font-body);
    font-size: 11px;
    color: var(--text-muted);
  }
  /* The cap notice sits at the TOP of the list and stays put while the rows
     scroll under it — at the bottom of 50 rows it was below the fold, so a
     user whose branch was capped out read "not authorized" instead of
     "keep typing". top:-4px cancels the list's own padding so nothing shows
     through above it when stuck. */
  .chat-branch-listbox-more {
    position: sticky;
    top: -4px;
    z-index: 1;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    margin-bottom: 4px;
  }
  /* High-contrast / forced-colors: background-color is discarded, so the
     highlight above vanishes and the user cannot see which row Enter commits.
     Restore it with system colours, which forced-colors preserves.

     ONLY the highlighted row opts out of forced colours. Excluding the base
     rule (as this block first did) kept every row's authored `color:
     var(--text)` against a system `Canvas` background the parent listbox does
     NOT opt out of — near-black on black under a dark high-contrast theme.
     The unhighlighted rows must stay under forced colours so the UA paints
     them CanvasText on Canvas.

     This block sits after the .sentinel / .listbox-sub / .listbox-tag rules on
     purpose: forced-color-adjust is inherited, so the highlighted row's
     children keep their authored colours and have to be repainted here, and a
     media query adds no specificity — source order is what wins those ties. */
  @media (forced-colors: active) {
    .chat-branch-listbox-opt {
      border: 1px solid transparent;   /* reserve the space so rows don't jump */
    }
    .chat-branch-listbox-opt.active,
    .chat-branch-listbox-opt.active.sentinel,
    .chat-branch-listbox-opt:hover,
    .chat-branch-listbox-opt.sentinel:hover {
      forced-color-adjust: none;
      background: Highlight;
      color: HighlightText;
      border-color: HighlightText;
    }
    .chat-branch-listbox-opt.active .chat-branch-listbox-sub,
    .chat-branch-listbox-opt.active .chat-branch-listbox-tag,
    .chat-branch-listbox-opt:hover .chat-branch-listbox-sub,
    .chat-branch-listbox-opt:hover .chat-branch-listbox-tag {
      color: HighlightText;
    }
    .chat-branch-listbox-opt.current::after {
      content: ' \2713';               /* 'current' must not rely on weight alone */
    }
  }
  /* DMS-666: screen-reader-only mirror of the cap / no-match notices. Not
     display:none and not hidden — either would take it out of the a11y tree
     and silence the announcement. */
  .chat-branch-combo-status {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  /* Single-branch users: non-interactive pill. */
  .chat-branch-picker-pill {
    display: inline-flex; align-items: center; gap: 6px;
    font-family: var(--font-body); font-size: 12px;
    background: var(--neutral-100);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 5px 10px;
  }
  .chat-branch-picker-pill[hidden] { display: none; }
  .chat-branch-picker-pill-label {
    font-family: var(--font-heading);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
  }
  .chat-branch-picker-pill-value {
    font-weight: var(--weight-semibold);
  }
  /* All-branches sentinel: brand-orange highlight on the editable input. */
  .chat-branch-picker-input.all-branches {
    background: var(--brand-100);
    border-color: var(--brand-300);
    color: var(--brand-500);
    font-weight: var(--weight-semibold);
  }

  /* ── DMS-207 UX-2: Locked-picker pill (post-first-message) ───────────
     Visual: same shape as the editable pill but with a lock icon and a
     dim background to signal "non-interactive." Tooltip explains why and
     how to recover (start a new chat). */
  .chat-branch-picker-locked {
    display: inline-flex; align-items: center; gap: 6px;
    font-family: var(--font-body); font-size: 12px;
    background: var(--neutral-200);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 5px 10px;
    cursor: not-allowed;
  }
  .chat-branch-picker-locked[hidden] { display: none; }
  .chat-branch-picker-lock-icon {
    display: inline-flex; align-items: center;
    opacity: 0.65;
  }
  .chat-branch-picker-lock-icon svg { width: 11px; height: 11px; display: block; }
  .chat-branch-picker-locked-value {
    font-weight: var(--weight-semibold);
  }
  /* Locked + all-branches: keep the brand-orange signal so the
     read-only fanout mode is still legible at a glance. */
  .chat-branch-picker-locked.all-branches {
    background: var(--brand-100);
    border-color: var(--brand-300);
    color: var(--brand-500);
  }
  .chat-branch-picker-locked.all-branches .chat-branch-picker-locked-value {
    color: var(--brand-500);
  }

  /* Inline "+ New chat" affordance next to the locked pill. Subtle until
     hover so it doesn't compete with the chat input or send button. */
  .chat-branch-new-chat-btn {
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--accent);
    font-family: var(--font-body);
    font-size: 11px;
    font-weight: var(--weight-semibold);
    padding: 4px 10px;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s;
    white-space: nowrap;
  }
  .chat-branch-new-chat-btn[hidden] { display: none; }
  .chat-branch-new-chat-btn:hover {
    background: var(--accent-bg);
    border-color: var(--accent);
  }

  /* ── DMS-207 RT-E (MB-11): In-flight picker gate ─────────────────────
     When a /query is in flight, disable the editable picker so the user
     can't swap branches mid-request and race the response. Post-first-
     message lock supersedes this (uses .locked instead). */
  .chat-branch-picker-input:disabled {
    cursor: not-allowed;
    opacity: 0.55;
    background: var(--neutral-100);
  }
  .chat-branch-picker.in-flight {
    cursor: not-allowed;
  }
  .chat-branch-picker.in-flight .chat-branch-picker-pill {
    opacity: 0.55;
  }

  /* ── DMS-207 RT-E (MB-12): Branch load-failure banner ────────────────
     Shown only when /branches errored AND the host is Agility (heuristic
     in app.js). Yellow warning theme to match other GUI warnings.
     Refresh re-fetches; Re-login triggers the existing logout flow. */
  .branch-load-banner {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 24px;
    background: var(--warning-100);
    border-bottom: 1px solid var(--warning-200);
    color: var(--warning-500);
    font-family: var(--font-body);
    font-size: 12px;
    flex-shrink: 0;
  }
  .branch-load-banner[hidden] { display: none; }
  .branch-load-banner-icon {
    display: inline-flex; align-items: center;
    flex-shrink: 0;
  }
  .branch-load-banner-icon svg { width: 15px; height: 15px; display: block; }
  .branch-load-banner-text {
    flex: 1;
    font-weight: var(--weight-semibold);
  }
  .branch-load-banner-btn {
    background: var(--warning-500);
    color: var(--neutral-000);
    border: none;
    border-radius: 4px;
    padding: 4px 12px;
    font-size: 11px;
    font-weight: var(--weight-semibold);
    font-family: var(--font-body);
    cursor: pointer;
    transition: opacity .15s;
    flex-shrink: 0;
  }
  .branch-load-banner-btn:hover { opacity: 0.85; }
  .branch-load-banner-btn-secondary {
    background: transparent;
    color: var(--warning-500);
    border: 1px solid var(--warning-500);
  }
  .branch-load-banner-btn-secondary:hover {
    background: var(--warning-200);
    opacity: 1;
  }

  /* ── DMS-207 UX-2: Scope Indicator (chat-window header) ─────────────
     Now sits beneath the chat-window picker (was: between topbar and
     layout). Same semantics — reflects the scope the NEXT /query will run
     under — but visually attached to the conversation it scopes. */
  .chat-scope-indicator {
    display: flex; align-items: center; gap: 8px;
    margin-top: 2px;
    padding: 2px 0;
    font-family: var(--font-body);
    font-size: 11px;
    color: var(--text-muted);
    flex-shrink: 0;
    justify-content: flex-start;
  }
  .chat-scope-indicator[hidden] { display: none; }
  .chat-scope-warning {
    background: var(--warning-100);
    color: var(--warning-500);
    border: 1px solid var(--warning-200);
    border-radius: 4px;
    font-size: 10px;
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 2px 8px;
  }
  .chat-scope-warning[hidden] { display: none; }
  /* DMS-207 RT-E (MB-12) — "no branch selected, writes disabled" badge.
     Shown next to the scope value when an Agility user has branch_id=null
     (typically because /branches failed to load). Critical-red theme to
     distinguish from the all-branches read-only warning. */
  .chat-scope-no-branch {
    display: inline-flex; align-items: center; gap: 4px;
    background: var(--critical-100);
    color: var(--critical-500);
    border: 1px solid var(--critical-200);
    border-radius: 4px;
    font-size: 10px;
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 2px 8px;
  }
  .chat-scope-no-branch[hidden] { display: none; }
  .chat-scope-icon { width: 12px; height: 12px; flex-shrink: 0; }

  /* ── DMS-207 UX-3: Branch-affects hint (under picker) ───────────────
     Single-line muted-info note explaining which categories of tools
     vary by branch. Variants:
       - .mixed   → "Branch affects pricing/inventory/orders; customer/
                     contact/supplier search is company-wide."
       - .all-off → "Branch context recorded but no tools in this agent
                     vary by branch."
       - .all-on  → "All tools in this agent vary by branch."
     Hidden for Frameworks (picker hidden) and "All branches" sentinel
     (read-only fanout warning supersedes). */
  .chat-branch-affects-hint {
    font-family: var(--font-body);
    font-size: 11px;
    color: var(--text-muted);
    line-height: 1.35;
    padding: 2px 0;
    margin-top: 2px;
    max-width: 480px;
    text-align: left;
    align-self: flex-start;
    font-style: italic;
  }
  .chat-branch-affects-hint[hidden] { display: none; }
  .chat-branch-affects-hint.all-off {
    color: var(--accent);
    font-style: normal;
  }

  /* ── DMS-368: All-branches progress stub ────────────────────────────
     Shown next to the "Thinking..." bubble while a /query is in flight
     against the "*" sentinel. Phase 2 (DMS-371) will replace the static
     copy with real per-branch progress streamed from the backend. */
  .branch-progress {
    display: inline-flex; align-items: center; gap: 8px;
    margin-top: 6px;
    font-family: var(--font-body);
    font-size: 11px;
    color: var(--brand-500);
    font-style: italic;
  }
  .branch-progress-spinner {
    width: 10px; height: 10px;
    border: 2px solid var(--brand-200);
    border-top-color: var(--brand-500);
    border-radius: 50%;
    animation: branch-spin 0.9s linear infinite;
    flex-shrink: 0;
  }
  @keyframes branch-spin {
    to { transform: rotate(360deg); }
  }

  /* DMS-541 §14.6f: streamed tool rows reuse the finished-card component
     (.inline-action), gaining a per-row status dot inside the label cell (so
     the 3-col grid is untouched) and a staggered entrance so a parallel batch
     reads as a cascade. On `done` the same rows finalize in place — no swap. */
  .inline-action .action-status {
    display: inline-block;
    width: 10px; height: 10px;
    margin-right: 6px;
    vertical-align: middle;
    text-align: center;
    line-height: 10px;
    font-weight: 700;
    font-size: 11px;
  }
  .inline-action .action-status.running {
    border: 2px solid var(--accent-dim);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: branch-spin 0.9s linear infinite;
  }
  .inline-action .action-status.success::before { content: '\2713'; color: var(--success-500); }
  .inline-action .action-status.error::before { content: '\2715'; color: var(--brand-500); }

  @keyframes stream-row-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
  }
  /* Entrance + spinner are motion — only under no-preference. Stagger is driven
     by a per-row inline animation-delay set at tool_start (presentation only;
     status truth is never delayed). */
  @media (prefers-reduced-motion: no-preference) {
    .inline-action.stream-enter { animation: stream-row-in 0.28s ease both; }
  }
  @media (prefers-reduced-motion: reduce) {
    .inline-action .action-status.running {
      animation: none;
      border-top-color: var(--accent-dim);
    }
  }

  /* DMS-541 §14.6j(a)/§14.6k(b): the 3-dot indicator stands ALONE (no "Thinking"
     text) with a polished scale+opacity wave — alive, not metronomic. Static
     under prefers-reduced-motion. */
  /* §14.6m: hug the dots. .chat-msg.agent is a flex column, so a default bubble
     stretches to its widest sibling (the agent-name label) and the dots swim
     left in empty space. align-self:flex-start + fit-content shrink the pill to
     its content; balanced padding lets the dots own it. Border-radius family is
     inherited from .chat-bubble (12px + the agent top-left 4px) — unchanged. */
  .chat-bubble.thinking-only {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    width: fit-content;
    max-width: 100%;
    padding: 9px 14px;
  }
  .thinking-dots {
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }
  .thinking-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--accent);
    /* Resting state == the animation's 0%/100% keyframe, so a static (reduced-
       motion) render matches the loop seam and there is no jump when it starts. */
    opacity: 0.3;
    transform: scale(0.7);
  }
  /* Seam-free: 0% and 100% are identical, so the loop never snaps. Each dot
     swells + brightens in turn for a rolling "breathing" cadence. */
  @keyframes thinking-dance {
    0%, 100% { opacity: 0.3; transform: scale(0.7); }
    35%      { opacity: 1;   transform: scale(1.15); }
    70%      { opacity: 0.5; transform: scale(0.85); }
  }
  @media (prefers-reduced-motion: no-preference) {
    .thinking-dot {
      animation: thinking-dance 1.4s cubic-bezier(0.45, 0, 0.55, 1) infinite;
    }
    .thinking-dot:nth-child(2) { animation-delay: 0.18s; }
    .thinking-dot:nth-child(3) { animation-delay: 0.36s; }
  }

  /* DMS-584: the compacted run summary ("Worked: 3x Customer searches, ...")
     and its expanded header read as the same flat, greyed text as the rows
     (no card border) with a subtle hover to signal they toggle open / closed. */
  .actions-collapsed,
  .actions-expanded-header {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    margin-top: 6px;
    padding: 3px 8px;
    border: none;
    border-radius: 4px;
    background: transparent;
    font-family: var(--font-body);
    font-size: var(--text-caption);
    color: var(--text-muted);
    cursor: pointer;
    text-align: left;
  }
  .actions-collapsed:hover,
  .actions-expanded-header:hover {
    background: var(--surface2);
    color: var(--text);
  }
  .actions-collapsed .actions-collapsed-label,
  .actions-expanded-header .actions-collapsed-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .actions-collapsed .actions-collapsed-hint,
  .actions-expanded-header .actions-collapsed-hint {
    margin-left: auto;
    color: var(--accent);
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    flex-shrink: 0;
  }

  /* Narrow viewport: stack chat-window picker beneath the title so it
     doesn't push the conversation title offscreen on small windows. */
  @media (max-width: 720px) {
    .topbar-disclaimer { display: none; }
    .chat-column-header {
      flex-direction: column;
      align-items: stretch;
    }
    .chat-branch-picker {
      align-items: flex-start;
    }
    .chat-branch-picker-label { display: none; }
    .chat-branch-picker-input { width: 100%; max-width: 100%; font-size: 11px; }
    .chat-branch-combo { width: 100%; }
    .chat-branch-listbox { width: 100%; min-width: 200px; }
    .chat-scope-indicator { justify-content: flex-start; }
    .chat-branch-affects-hint { text-align: left; max-width: 100%; }
    /* DMS-584: shrink the floating feedback trigger so it does not crowd the
       last message on narrow screens. */
    .feedback-fab { right: 10px; bottom: calc(100% + 10px); font-size: 11px; padding: 6px 11px; }
  }

  /* ── DMS-207 UX-2: Sidebar branch chip ──────────────────────────────
     Tiny chip below each conv-item's date so users can see at a glance
     which branch each conversation is scoped to. Hidden entirely for
     Frameworks users (renderConvBranchChip returns ''). */
  .conv-item-meta-row {
    display: flex; align-items: center; gap: 6px;
    flex-wrap: wrap;
  }
  .conv-item-branch {
    font-family: var(--font-body);
    font-size: 9px;
    font-weight: var(--weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--accent-bg);
    color: var(--accent);
    border: 1px solid var(--accent-bg2);
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .conv-item-branch.all-branches {
    background: var(--yellow-bg-subtle);
    color: var(--warning-500);
    border-color: var(--warning-200);
  }
  .conv-item-branch.unset {
    background: transparent;
    color: var(--text-muted);
    border-color: var(--border);
  }

  /* Login Overlay */
  .login-overlay {
    position: fixed; inset: 0; z-index: 9999;
    background: var(--bg); display: flex; align-items: center; justify-content: center;
  }
  .login-overlay.hidden { display: none; }
  .login-card {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 12px; padding: 40px; width: 380px; box-shadow: 0 8px 32px var(--shadow);
  }
  .login-logo { font-family: var(--font-heading); font-size: var(--text-heading); font-weight: var(--weight-bold); text-align: center; margin-bottom: 4px; }
  .login-subtitle { text-align: center; color: var(--text-muted); font-size: 13px; margin-bottom: 24px; }
  .login-label { display: block; font-size: 12px; font-weight: var(--weight-semibold); margin-bottom: 4px; margin-top: 12px; }
  .login-input {
    display: block; width: 100%; padding: 8px 10px; font-size: 13px;
    border: 1px solid var(--border); border-radius: 6px; background: var(--bg);
    color: var(--text); box-sizing: border-box;
  }
  .login-input:focus { outline: none; border-color: var(--accent); }
  .login-btn {
    display: block; width: 100%; margin-top: 20px; padding: 10px;
    background: var(--accent); color: var(--btn-text); border: none; border-radius: 6px;
    font-size: 14px; font-weight: var(--weight-semibold); cursor: pointer;
  }
  .login-btn:hover { opacity: .9; }
  .login-btn:disabled { opacity: .5; cursor: not-allowed; }
  .login-error { color: var(--critical-400); font-size: 12px; margin-top: 8px; min-height: 16px; }

  /* File Upload */
  /* DMS-802: moved here from an inline style attribute, which a style-src
     without 'unsafe-inline' refuses. The picker opens through attachFile(). */
  #file-input { display: none; }
  .attach-btn {
    background: none; border: none; cursor: pointer; padding: 6px;
    color: var(--text-muted); display: flex; align-items: center; flex-shrink: 0;
  }
  .attach-btn:hover { color: var(--accent); }
  .file-indicator {
    display: none; font-size: 12px;
  }
  /* DMS-584: pending attachment shows as a compact pill hugging its content. */
  .file-indicator.visible {
    display: inline-flex; align-items: center; gap: 6px;
    width: fit-content; max-width: calc(100% - 20px);
    padding: 4px 10px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 999px; margin: 0 10px 6px;
  }
  .file-indicator-icon { width: 13px; height: 13px; flex-shrink: 0; color: var(--text-muted); }
  .file-indicator-name {
    color: var(--text); font-size: 12px; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; max-width: 200px;
  }
  .file-indicator-remove {
    background: none; border: none; cursor: pointer; color: var(--text-muted);
    font-size: 14px; padding: 0 2px; line-height: 1;
  }
  .file-indicator-remove:hover { color: var(--critical-400); }

  /* Loading / Thinking State */
  .chat-msg.thinking .chat-bubble {
    color: var(--text-muted); font-style: italic;
  }
  .chat-input-area.loading .send-btn { opacity: .5; pointer-events: none; }
  .chat-input-area.loading #chat-input { opacity: .6; pointer-events: none; }
  /* DMS-606 (c): the chips are disabled in markup while a request is in
     flight; dim them so they read as inert rather than merely unresponsive. */
  .chat-input-area.loading #quick-actions { opacity: .5; }
  .quick-action-chip:disabled { cursor: default; }

  /* Empty State */
  .empty-state-chat {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    height: 100%; color: var(--text-muted); text-align: center; padding: 40px;
  }
  .empty-state-chat h3 { margin: 0 0 8px; font-size: 24px; font-weight: var(--weight-regular); color: var(--text-muted); }
  .empty-state-chat p { margin: 0 0 20px; font-size: 13px; }
  /* DMS-476: AUP AI disclosure line in the new-chat empty state. Shown on all
     viewports (unlike .topbar-disclaimer, which is hidden on mobile). */
  .empty-state-chat p.ai-disclosure { margin: 4px 0 0; font-size: 12px; font-style: italic; opacity: 0.85; }
  .suggested-prompts { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
  .suggested-prompt-chip {
    padding: 8px 14px; font-size: 12px; border: 1px solid var(--border);
    border-radius: 20px; cursor: pointer; background: var(--surface);
    color: var(--text); transition: border-color .15s;
  }
  .suggested-prompt-chip:hover { border-color: var(--accent); }

  /* Markdown inside chat bubbles */
  .chat-bubble h1, .chat-bubble h2, .chat-bubble h3 { margin: 8px 0 4px; font-size: 14px; font-weight: var(--weight-bold); }
  .chat-bubble h2 { font-size: 13px; }
  .chat-bubble h3 { font-size: 13px; font-weight: var(--weight-semibold); }
  .chat-bubble p { margin: 4px 0; }
  .chat-bubble ul, .chat-bubble ol { margin: 4px 0; padding-left: 20px; }
  .chat-bubble li { margin: 2px 0; }
  .chat-bubble code { background: var(--bg); padding: 1px 4px; border-radius: 3px; font-size: 12px; }
  .chat-bubble pre { background: var(--bg); padding: 8px; border-radius: 6px; overflow-x: auto; margin: 6px 0; }
  .chat-bubble pre code { background: none; padding: 0; }
  .chat-bubble table { display: block; overflow-x: auto; width: 100%; border-collapse: collapse; margin: 6px 0; font-size: 12px; }
  .chat-bubble th, .chat-bubble td { padding: 4px 8px; border: 1px solid var(--border); text-align: left; }
  .chat-bubble th { background: var(--bg); font-weight: var(--weight-semibold); }
  .chat-bubble strong { font-weight: var(--weight-bold); }
  .chat-bubble hr { border: none; border-top: 1px solid var(--border); margin: 8px 0; }

/* ══════════════════════════════════════════════════════════════════════════
   Interaction blocks — choice + confirm cards (DMS-398)
   Reuses the mockup's visual language (docs/reference/20260804-interaction-
   blocks-mockup.html) mapped onto the real GUI tokens (--neutral-*, --action-*).
   ══════════════════════════════════════════════════════════════════════════ */

/* shared card frame */
.icard {
  margin-top: 10px;
  border: 1px solid var(--action-200);
  border-radius: var(--radius);
  background: var(--neutral-000);
  overflow: hidden;
}
.icard.ib-disabled { opacity: .6; pointer-events: none; }
.icard .ihead {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; background: var(--action-100);
  font-family: var(--font-heading); font-size: 11px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--action-600);
}
.icard .ihead.gate { background: var(--warning-100); color: var(--warning-500); }
.icard .ibody { padding: 12px; }

/* choice options */
.icard .opt {
  display: flex; gap: 10px; align-items: center; width: 100%;
  text-align: left; cursor: pointer;
  background: var(--neutral-000); border: 1px solid var(--neutral-300);
  border-radius: var(--radius); padding: 10px 12px; margin-bottom: 8px;
  font: inherit; color: var(--neutral-500);
  transition: border-color .12s, background .12s, box-shadow .12s;
}
.icard .opt:hover { border-color: var(--action-400); background: var(--action-100); }
.icard .opt:active { transform: translateY(1px); }
.icard .opt:disabled { cursor: default; }
.icard .opt .k {
  flex: 0 0 auto; font-family: ui-monospace, Menlo, monospace; font-size: 11px;
  color: var(--neutral-400); border: 1px solid var(--neutral-300);
  border-radius: 5px; padding: 1px 6px; margin-top: 1px;
}
.icard .opt b { display: block; font-weight: 600; font-size: 13.5px; }
.icard .opt span.d { display: block; font-size: 12.5px; color: var(--neutral-400); }
.icard .opt.selected {
  border-color: var(--success-500); background: var(--success-100);
  box-shadow: inset 0 0 0 1px var(--success-500);
}

/* choice badges */
.icard .ib-hold {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 3px; font-size: 11px; font-weight: 600;
  color: var(--critical-400); background: var(--critical-100);
  border-radius: 999px; padding: 1px 8px;
}
.icard .ib-hold-icon { width: 12px; height: 12px; flex-shrink: 0; }
.icard .ib-badges { display: block; font-size: 11.5px; color: var(--neutral-400); margin-top: 2px; }

/* free-text "other" / branch input */
.icard .other { display: flex; gap: 8px; margin-top: 2px; }
.icard .other input {
  flex: 1; font: inherit; font-size: 13px; padding: 8px 10px;
  border: 1px solid var(--neutral-300); border-radius: var(--radius);
  color: var(--neutral-500); background: var(--neutral-000);
}
.icard .other input::placeholder { color: var(--neutral-400); }

/* confirm buttons */
.icard .btnrow { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; align-items: center; }
.icard .ib-btn {
  font: inherit; font-size: 13.5px; font-weight: 600; padding: 8px 16px;
  border-radius: var(--radius); cursor: pointer; border: 1px solid transparent;
  transition: filter .12s, transform .08s;
}
.icard .ib-btn:hover { filter: brightness(1.07); }
.icard .ib-btn:active { transform: translateY(1px); }
.icard .ib-btn:disabled { cursor: default; opacity: .6; }
.icard .ib-btn.primary { background: var(--success-500); color: #fff; }
.icard .ib-btn.neutral { background: var(--neutral-000); color: var(--neutral-500); border-color: var(--neutral-300); }
.icard .ib-btn.danger { background: var(--neutral-000); color: var(--critical-400); border-color: var(--critical-400); }

/* confirm args table (what-you-see-is-what-executes) */
.icard .ib-gridwrap { overflow-x: auto; border: 1px solid var(--neutral-300); border-radius: var(--radius); margin-top: 6px; }
.icard .ib-grid { border-collapse: collapse; width: 100%; font-size: 13px; }
/* DMS-649 render finding 1 — make the wrap's `overflow-x: auto` above actually
   work. `width: 100%` alone forces the table BOX to the wrap's width, so only
   the CELLS overflow and scrollWidth === clientWidth: no scrollbar ever
   appears, and the clipped content is unreachable (measured: 195px of the money
   column off-card at a 800px viewport, with the overflow metric reporting 0).
   A `min-width` lets the box grow past the wrap, which is the condition
   `overflow-x: auto` scrolls on.
   `min-content`, NOT `max-content`: an unbreakable cell (every price cell, the
   size labels, the headers — all `white-space: nowrap`) contributes its full
   width either way, but prose that CAN wrap contributes only its longest word
   instead of its whole unwrapped line. That is exactly the width below which
   something would clip. Measured on the real cards: overflow 0 at 1440 and
   1152 (nothing changes on a normal window), 197-220px of genuinely scrollable
   width at 800, where the money used to be unreachable. `max-content` instead
   put a 27px scrollbar on a 1440 ledger card, for prose that was wrapping
   perfectly well. */
.icard .ib-gridwrap > .ib-grid { min-width: min-content; }
.icard .ib-grid th {
  background: var(--neutral-100); font-family: var(--font-heading); font-size: 10.5px;
  font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--neutral-400); text-align: left; padding: 6px 10px;
  border-bottom: 1px solid var(--neutral-300); white-space: nowrap;
}
.icard .ib-grid td { padding: 6px 10px; border-bottom: 1px solid var(--neutral-200); color: var(--neutral-500); }
.icard .ib-grid td.ib-k { font-weight: 600; color: var(--neutral-400); white-space: nowrap; width: 1%; }
.icard .ib-grid tr:last-child td { border-bottom: none; }
.icard .ib-linelabel {
  font-family: var(--font-heading); font-size: 10.5px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--neutral-400);
  margin: 10px 0 4px;
}

/* ── D36 (§12.25): editable confirm card ──────────────────────────────────── */
/* editable cells inside the args grid + line-items table — subtle bordered
   inputs so the card reads as a form, not a static receipt */
.icard .ib-edit {
  font: inherit; font-size: 13px; padding: 5px 8px;
  border: 1px solid var(--neutral-300); border-radius: 6px;
  color: var(--neutral-500); background: var(--neutral-000);
  width: 100%; box-sizing: border-box; max-width: 240px;
}
.icard .ib-edit:focus {
  outline: none; border-color: var(--action-400);
  box-shadow: 0 0 0 2px var(--action-100);
}
.icard select.ib-edit { cursor: pointer; }
.icard .ib-editgrid td { padding: 4px 8px; }
.icard .ib-editgrid .ib-edit { min-width: 64px; }
/* Size inputs to the data they hold. Without this every cell inherited the
   240px max-width and a 2-digit quantity rendered in a 470px-wide column. */
.icard .ib-editgrid input.ib-edit[type="number"] { max-width: 96px; }
.icard .ib-editgrid input.ib-edit[type="text"] { max-width: 168px; }
/* leftover-arg inputs on a ledger item row sit inline in a wrapping flex row */
.icard .ib-l-meta .ib-edit { max-width: 120px; }

/* the card preamble (D13): ordinary assistant markdown, not card data */
.chat-bubble .ib-preamble > :first-child { margin-top: 0; }
.chat-bubble .ib-preamble > :last-child { margin-bottom: 8px; }
.chat-bubble .ib-preamble table {
  border-collapse: collapse; font-size: 12.5px; margin: 8px 0;
}
.chat-bubble .ib-preamble th, .chat-bubble .ib-preamble td {
  border: 1px solid var(--neutral-300); padding: 4px 8px; text-align: left;
}

/* per-line + header free-text note affordance */
.icard .ib-note-cell { width: 1%; white-space: nowrap; }
.icard .ib-note-toggle {
  font: inherit; font-size: 11.5px; font-weight: 600; cursor: pointer;
  color: var(--action-600); background: transparent;
  border: 1px solid var(--neutral-300); border-radius: 999px;
  padding: 2px 10px; white-space: nowrap;
}
.icard .ib-note-toggle:hover { border-color: var(--action-400); background: var(--action-100); }
.icard .ib-note-toggle:disabled { cursor: default; opacity: .6; }
.icard .ib-note-inputrow.hidden { display: none; }
.icard .ib-note-row { margin: 8px 0 2px; display: flex; }
.icard .ib-note-input {
  flex: 1; width: 100%; box-sizing: border-box; font: inherit; font-size: 12.5px;
  padding: 6px 9px; border: 1px dashed var(--neutral-300); border-radius: 6px;
  color: var(--neutral-500); background: var(--neutral-100);
}
.icard .ib-note-input::placeholder { color: var(--neutral-400); }
.icard .ib-note-input:focus {
  outline: none; border-style: solid; border-color: var(--action-400);
  box-shadow: 0 0 0 2px var(--action-100);
}

/* ── DMS-649 Ledger v2: the dimensional confirm card ──────────────────────── */
/* v1 (DMS-589) boxed each dimensional line in its own grey card-within-a-card,
   so a mixed order rendered as alternating flat tables and grey boxes. v2 is ONE
   ledger table for the whole order: item rows separated by a rule, sizes
   indented under their item on a rail. No group boxes. */

/* header block — two-column key/value grid, replacing the flat k/v table */
.icard .ib-hgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 2px 18px; margin-top: 4px;
}
.icard .ib-hf { display: flex; align-items: baseline; gap: 8px; padding: 3px 0; min-width: 0; }
.icard .ib-hf-k {
  flex: 0 0 104px; font-family: var(--font-heading); font-size: 10.5px;
  font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--neutral-400);
}
.icard .ib-hf-v { flex: 1 1 auto; min-width: 0; font-size: 13px; color: var(--neutral-500); }
.icard .ib-hf-id { font-weight: 700; color: var(--neutral-500); }
.icard .ib-hf-ro { color: var(--neutral-500); }
/* identity args are not editable — the link says why and hands over the note */
.icard .ib-idlock {
  font: inherit; font-size: 11px; font-weight: 500; cursor: pointer;
  background: none; border: 0; padding: 0 0 0 8px; color: var(--neutral-400);
}
.icard .ib-idlock:hover { color: var(--action-400); }
.icard .ib-idmsg {
  display: block; margin-top: 3px; font-size: 11px; line-height: 1.45;
  color: var(--neutral-400);
}
.icard .ib-idmsg.hidden { display: none; }

/* the one-line legend under "Line items" */
.icard .ib-legend {
  font-size: 10.5px; line-height: 1.4; color: var(--neutral-400); margin: -2px 0 2px;
}

/* ledger table */
.icard .ib-ledger td { border-bottom: none; vertical-align: top; }
.icard .ib-ledger tr.ib-l-item > td { border-top: 1px solid var(--neutral-300); }
.icard .ib-ledger tr.ib-l-head + tr.ib-l-item > td { border-top: none; }
/* shrink-to-fit columns: Item/size takes the slack, Qty/UOM hug their content
   (a 2-digit qty was otherwise given an equal share of the table width) */
.icard .ib-ledger th.ib-c-num, .icard .ib-ledger td.ib-c-num {
  width: 1%; white-space: nowrap;
}
.icard .ib-ledger .ib-note-cell { vertical-align: middle; }

/* item row identity cell */
.icard .ib-l-code {
  font-family: var(--font-heading); font-size: 12.5px; font-weight: 700;
  color: var(--neutral-500);
}
.icard .ib-l-desc { font-size: 12px; color: var(--neutral-400); margin-left: 7px; }
.icard .ib-l-chip {
  display: inline-block; margin-left: 7px; font-size: 10.5px; font-weight: 600;
  background: var(--action-100); color: var(--action-600);
  border-radius: 999px; padding: 1px 8px; white-space: nowrap;
}
/* Leftover args (line uom, price, seq, …) — every arg stays visible (D6/AC-8),
   but quietly: this is provenance, not the order. Sized deliberately smaller
   than the Qty/UOM controls so it cannot compete with them for the eye, which
   is the failure the v1 card had (three micro-typography styles, all shouting).
   The `.ib-editgrid` selector is matched here to outrank the generic
   `.ib-editgrid input.ib-edit[type=...]` width caps above. */
.icard .ib-l-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px 12px; margin-top: 2px;
}
.icard .ib-l-metabit { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; }
.icard .ib-l-metak {
  font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--neutral-400);
}
.icard .ib-l-metav { color: var(--neutral-400); }
.icard .ib-editgrid .ib-l-meta input.ib-edit,
.icard .ib-editgrid .ib-l-meta select.ib-edit {
  max-width: 88px; min-width: 0; font-size: 11px; padding: 2px 6px;
}

/* size rows — indented under their item on a rail */
.icard .ib-l-sizecell {
  padding-left: 26px !important; border-left: 3px solid var(--action-200);
  white-space: nowrap; cursor: pointer;
}
.icard .ib-l-sizecell:focus-visible { outline: 2px solid var(--action-400); outline-offset: -2px; }
.icard .ib-l-sizelabel { font-weight: 600; font-size: 12.5px; color: var(--neutral-500); }
.icard .ib-l-lock { color: var(--neutral-400); margin-left: 6px; vertical-align: -1px; }
.icard .ib-l-sizecell:hover .ib-l-lock { color: var(--action-400); }
/* the muted subline under a size label / UOM (bundle wording, dropped fields) */
.icard .ib-l-sub {
  display: block; font-size: 10.5px; line-height: 1.4; color: var(--neutral-400);
  font-weight: 400; white-space: normal;
}
.icard .ib-l-sub-drop { font-style: italic; }
/* DMS-649 finding 6 — a tally row with no physical dimension is dropped before
   the wire, so it is shown as provenance rather than as part of the order:
   muted, no editable quantity, and (via its price cell) an explicit "not
   priced". Same visual register as the DMS-647 piece-count subline above, which
   is the existing idiom for "on the card, not going to the ERP". */
.icard tr.ib-l-notsent > td { opacity: .62; }
.icard tr.ib-l-notsent .ib-l-sizelabel { text-decoration: line-through; }

/* the per-size "change…" affordance: a link, not a pill */
.icard .ib-note-toggle.ib-l-change {
  border: 0; background: none; padding: 0; font-size: 11px; font-weight: 500;
  color: var(--neutral-400); text-decoration: none;
}
.icard tr:hover .ib-note-toggle.ib-l-change { color: var(--action-400); }
.icard .ib-note-toggle.ib-l-change.open { color: var(--action-600); font-weight: 700; }
.icard .ib-note-toggle .ib-tg-open { display: none; }
.icard .ib-note-toggle.open .ib-tg-open { display: inline; }
.icard .ib-note-toggle.open .ib-tg-shut { display: none; }
.icard .ib-note-help {
  font-size: 10.5px; line-height: 1.45; color: var(--neutral-400); margin-top: 4px;
}

/* subtotal row — the ordered tally total, a sum of the sizes above and NEVER
   the stored line quantity (DMS-523: Agility stores a converted number the
   client cannot compute) */
.icard .ib-l-subtotal > td {
  background: var(--neutral-100); font-size: 12px; font-weight: 700;
  color: var(--neutral-500);
}
.icard .ib-l-subtotal > td:first-child { padding-left: 26px; }
.icard .ib-l-subtotal > td.updated { color: var(--warning-500); }
.icard .ib-sum-upd {
  margin-left: 5px; font-size: 9.5px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--warning-500);
}
.icard .ib-l-est { font-size: 10.5px; font-weight: 400; color: var(--neutral-400); }
/* the args quantity, demoted to provenance beneath the total (Open C) */
.icard .ib-l-prov > td {
  font-size: 11px; font-weight: 400; color: var(--neutral-400);
  padding-top: 2px; padding-left: 26px;
}
/* what a UNIT is (§5.4) — the card must not let "Qty 2 · UNIT" read as 2 boards */
.icard .ib-l-foot {
  font-size: 11px; line-height: 1.45; color: var(--neutral-400); margin: 6px 2px 0;
}

/* ── DMS-649 §10.2: the read-only Price (quote) column ────────────────────────
   Present only when the server returned a quote block; absent entirely
   otherwise, so there is no empty-column state to style. Right-aligned and
   shrink-to-fit like Qty/UOM — Item/size keeps the slack.
   Scoped to `.ib-grid`, not `.ib-ledger`: DMS-649 finding 5 (Path A) put the
   same column on the flat plain-line table, which is a `.ib-grid .ib-editgrid`
   and not a ledger. Both tables carry `.ib-grid`. */
.icard .ib-grid th.ib-c-price, .icard .ib-grid td.ib-c-price {
  width: 1%; white-space: nowrap; text-align: right;
}
.icard .ib-grid th.ib-c-price { font-size: 10.5px; }
.icard .ib-p-ext {
  display: block; font-size: 12.5px; font-weight: 600; color: var(--neutral-500);
  font-variant-numeric: tabular-nums;
}
/* the unit rate, subordinate to the extended amount it multiplies out to */
.icard .ib-p-unit {
  display: block; font-size: 10.5px; line-height: 1.4; color: var(--neutral-400);
  font-variant-numeric: tabular-nums;
}
/* a parent fallback is normal and correct — stated, never warned about */
.icard .ib-p-src {
  display: block; font-size: 10px; line-height: 1.4; color: var(--neutral-400);
}
.icard .ib-c-price.updated .ib-p-ext, .icard td.ib-p-sub.updated {
  color: var(--warning-500);
}
.icard .ib-l-subtotal > td.ib-p-sub { font-variant-numeric: tabular-nums; }

/* DMS-649 findings 6/7 (C2, "no silent holes") — a row with no number says so.
   Deliberately NOT styled like money: lighter, italic and left of the numeric
   rhythm, so it cannot be skim-read as an amount, and above all so it is never
   confused with a legitimate $0.00 (which stays in .ib-p-ext, bold and dark). */
.icard .ib-p-none {
  display: block; font-size: 11px; font-weight: 600; font-style: italic;
  color: var(--neutral-400);
}
.icard .ib-p-why {
  display: block; font-size: 10px; line-height: 1.35; font-weight: 400;
  color: var(--neutral-400); white-space: normal; max-width: 190px;
}
.icard td.ib-c-price.ib-p-unpriced { text-align: right; }

/* DMS-649 finding 10 — the quoted rate no longer applies to this row (a uom
   edit), so the amount is struck rather than blanked or silently recomputed,
   and the row says what will fix it. */
.icard .ib-c-price.stale .ib-p-ext {
  text-decoration: line-through; color: var(--neutral-400);
}
.icard .ib-c-price.stale .ib-p-unit, .icard .ib-c-price.stale .ib-p-src {
  text-decoration: line-through; color: var(--neutral-300);
}
.icard .ib-p-stale { display: none; }
.icard .ib-c-price.stale .ib-p-stale {
  display: block; font-size: 9.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--warning-500);
}

/* the estimated order total */
.icard .ib-grid tr.ib-l-grand > td {
  border-top: 1px solid var(--neutral-300); background: var(--neutral-100);
  font-size: 12.5px; font-weight: 700; color: var(--neutral-500);
  font-variant-numeric: tabular-nums;
}
.icard .ib-grid tr.ib-l-grand > td.updated { color: var(--warning-500); }
/* R1 — the tally subtotal's "(excludes the sizes above marked not priced)"
   reads exactly like the grand total's qualifier, because it says the same
   thing one level down; shared rule so the two can never drift apart. */
.icard .ib-l-grandq, .icard .ib-l-subq {
  margin-left: 6px; font-size: 10.5px; font-weight: 400; color: var(--neutral-400);
}
.icard .ib-p-tag {
  font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--warning-500);
}
/* the re-quote sentence, shown only while an edit is pending */
.icard .ib-p-rehint { color: var(--warning-500); }
.icard .ib-p-rehint.hidden { display: none; }
/* a `price` in the args transmits nothing (DMS-526) — say so where it renders */
.icard .ib-l-ignored { font-size: 10px; color: var(--neutral-400); margin-left: 5px; }

/* ── DMS-547 (§5.2): per-cell dirty state ─────────────────────────────────── */
.icard .ib-cell { display: inline-block; max-width: 100%; }
.icard .ib-edit.dirty {
  background: var(--warning-100); border-color: var(--warning-400);
}
.icard .ib-was {
  display: block; margin-top: 2px; font-size: 10.5px; line-height: 1.3;
  color: var(--warning-500); white-space: nowrap;
}
.icard .ib-was.hidden { display: none; }
.icard .ib-revert {
  font: inherit; font-size: 10.5px; font-weight: 600; cursor: pointer;
  background: none; border: 0; padding: 0 0 0 6px; color: var(--action-400);
  display: inline-flex; align-items: center; gap: 3px;
}
.icard .ib-revert:hover { color: var(--action-600); }
/* the pending-changes pill beside the buttons */
.icard .ib-dirtychip {
  font-size: 11px; font-weight: 600; border-radius: 999px; padding: 3px 10px;
  background: var(--warning-100); color: var(--warning-500); white-space: nowrap;
}
.icard .ib-dirtychip.hidden { display: none; }

/* dirty state: the Approve → "Update order" button morph (AC-24) */
.icard .btnrow.dirty {
  padding-top: 10px; margin-top: 8px; border-top: 1px dashed var(--warning-300);
}
/* "Update order" — visually distinct from the green Approve primary */
.icard .ib-btn.update { background: var(--action-400); color: #fff; }
.icard .ib-btn.update:hover { filter: brightness(1.07); }

/* inline field errors (HTTP 422 — card stays open, AC-12) */
.icard .ib-cellmsg {
  display: flex; align-items: center; gap: 6px; margin: 8px 2px 0;
  font-size: 12px; color: var(--critical-400);
}
.icard .ib-cellmsg::before {
  content: "!"; font-weight: 700; background: var(--critical-400); color: #fff;
  width: 15px; height: 15px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; font-size: 10px; flex-shrink: 0;
}

/* carousel stepper (v1.1 multi-question choice) */
.icard .ib-progress {
  font-family: var(--font-heading); font-size: 10.5px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--neutral-400);
  margin-bottom: 8px;
}
.icard .ib-qprompt {
  font-size: 13.5px; font-weight: 600; color: var(--neutral-500);
  margin-bottom: 10px;
}
.icard .ib-carousel-nav {
  display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; align-items: center;
}
.icard .opt-value {
  /* unsourced option — plain value chip (no metadata badges) */
  border-color: var(--neutral-300);
}
.icard .opt-value:hover {
  border-color: var(--action-400);
}
/* Section 13 fix 5: muted legend — badged (ERP-sourced) vs plain (assistant) */
.icard .ib-legend {
  font-size: 11.5px; color: var(--neutral-400); line-height: 1.4;
  margin: 6px 2px 2px;
}

/* Section 13 fix 3: styled error bubble — ONE presentation for soft tool
   errors (HTTP 200 is_error) and thrown/5xx/timeout errors. */
.chat-msg.is-error .chat-bubble {
  border: 1px solid var(--critical-400);
  background: var(--critical-100);
  color: var(--critical-400);
}

/* frozen answer receipt (choice/confirm outcome, D23 branch hand-off) */
.ib-receipt {
  margin-top: 10px; border: 1px solid var(--neutral-200); border-radius: var(--radius);
  background: var(--neutral-100); padding: 9px 12px; font-size: 13px;
  color: var(--neutral-400); display: flex; align-items: center; gap: 8px;
}
.ib-receipt.ok { background: var(--success-100); border-color: var(--success-200); }
.ib-receipt .check { color: var(--success-500); font-weight: 700; flex-shrink: 0; }
.ib-receipt.receipt-link { cursor: pointer; }
.ib-receipt.receipt-link:hover { border-color: var(--action-400); color: var(--action-600); }

/* DMS-584: a choice/carousel receipt collapses to "Asked N questions" and
   expands to the answered question + answer labels. The header is a full-width
   button (check + summary + show/hide hint) that stacks the detail below it, so
   the collapsible receipt is a column, not the plain single-row flex receipt. */
.ib-receipt.ib-receipt-collapsible { display: block; padding: 0; }
.ib-receipt-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 12px; border: none; border-radius: var(--radius);
  background: transparent; font: inherit; font-size: 13px;
  color: var(--neutral-400); cursor: pointer; text-align: left;
}
.ib-receipt-head:hover { color: var(--action-600); }
.ib-receipt-head .ib-receipt-summary {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ib-receipt-head .ib-receipt-hint {
  margin-left: auto; color: var(--action-600); font-size: 9px;
  text-transform: uppercase; letter-spacing: .04em; flex-shrink: 0;
}
.ib-receipt-qa {
  padding: 0 12px 10px 32px; display: flex; flex-direction: column; gap: 6px;
}
.ib-receipt-qa-row { display: flex; flex-direction: column; gap: 1px; }
.ib-receipt-qa-row .ib-receipt-q { font-size: 12px; color: var(--neutral-400); }
.ib-receipt-qa-row .ib-receipt-a { font-size: 13px; font-weight: 600; color: var(--neutral-500); }


/* ── DMS-598: file intake (drag-and-drop, toasts, quick-action chips) ── */

/* Full-window drag overlay (D1). DMSi blue scrim + dashed white card. It is
   purely visual — pointer-events:none so drag events reach the window handlers
   and the overlay can't itself trigger a dragleave flicker. */
.drop-overlay {
  position: fixed; inset: 0; z-index: 8000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 72, 107, 0.88);
  pointer-events: none;
  animation: drop-overlay-fade 0.12s ease-out;
}
.drop-overlay.hidden { display: none; }
.drop-overlay-card {
  border: 2px dashed rgba(255, 255, 255, 0.9);
  border-radius: 16px;
  padding: 36px 52px;
  text-align: center;
  color: var(--neutral-000);
  background: rgba(255, 255, 255, 0.06);
}
.drop-overlay-icon { font-size: 40px; line-height: 1; display: block; margin-bottom: 10px; }
.drop-overlay-title {
  font-family: var(--font-heading); font-size: 22px; font-weight: var(--weight-semibold);
  margin-bottom: 8px;
}
.drop-overlay-subtitle { font-family: var(--font-body); font-size: 13px; opacity: 0.85; }
@keyframes drop-overlay-fade { from { opacity: 0; } to { opacity: 1; } }

/* Transient toast stack (§5.2.4). */
.app-toast-wrap {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
  z-index: 10000; display: flex; flex-direction: column; align-items: center;
  gap: 8px; pointer-events: none; max-width: 80vw;
}
.app-toast {
  background: var(--neutral-500); color: var(--neutral-000);
  font-family: var(--font-body); font-size: 13px;
  padding: 10px 18px; border-radius: 8px; box-shadow: 0 4px 16px var(--shadow);
  opacity: 0; transform: translateY(8px); transition: opacity 0.25s, transform 0.25s;
}
.app-toast.show { opacity: 1; transform: translateY(0); }
.app-toast-error { background: var(--critical-500); }
.app-toast-warn  { background: var(--warning-500); }
.app-toast-ok    { background: var(--success-500); }

/* Quick-action chips shown after a file attaches (D3). */
.quick-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 10px 6px; }
.quick-actions[hidden] { display: none; }
.quick-action-chip {
  padding: 8px 16px; font-size: 13px; font-family: var(--font-body);
  font-weight: var(--weight-semibold); border-radius: 20px; cursor: pointer;
  transition: opacity 0.15s, border-color 0.15s;
}
.quick-action-primary { background: var(--accent); color: var(--neutral-000); border: none; }
.quick-action-primary:hover { opacity: 0.9; }
.quick-action-secondary {
  background: var(--surface); color: var(--text); border: 1px solid var(--border);
}
.quick-action-secondary:hover { border-color: var(--accent); }

/* Composer collapse when chips are showing (D3). max-height + opacity so it
   slides; respect prefers-reduced-motion. */
.chat-input-wrap {
  max-height: 240px; overflow: hidden; visibility: visible;
  transition: max-height 0.2s ease, opacity 0.2s ease, visibility 0s;
}
/* DMS-606 (a): visibility:hidden takes the textarea, paperclip and Send button
   out of the tab order and the a11y tree — pointer-events alone left them
   focusable and screen-reader-announced while invisible. Delayed to the end of
   the collapse transition, immediate on expand. */
.chat-input-wrap.collapsed {
  max-height: 0; opacity: 0; margin: 0; pointer-events: none;
  visibility: hidden;
  transition: max-height 0.2s ease, opacity 0.2s ease, visibility 0s linear 0.2s;
}
@media (prefers-reduced-motion: reduce) {
  .chat-input-wrap { transition: none; }
  /* .collapsed is (0,2,0) against the rule above at (0,1,0), and a media query
     adds no specificity — without this the delayed visibility survives here. */
  .chat-input-wrap.collapsed { transition: none; }
  .drop-overlay { animation: none; }
  .app-toast { transition: none; }
}

/* File pill: image thumbnail (D9), type icon, and size. */
.file-pill-thumb {
  width: 28px; height: 28px; border-radius: 4px; object-fit: cover;
  border: 1px solid var(--border); flex-shrink: 0;
}
.file-pill-size { color: var(--text-muted); font-size: 11px; flex-shrink: 0; }

/* Failed-send inline notice (D5). */
.composer-notice {
  margin: 0 10px 6px; padding: 6px 10px; font-size: 12px;
  color: var(--critical-500); background: var(--critical-100);
  border: 1px solid var(--critical-200); border-radius: 6px;
}
.composer-notice[hidden] { display: none; }

/* DMS-800: why Send is disabled. Always rendered (it is a live region), so it
   takes no space until it has text. */
.composer-status:not(:empty) {
  margin: 0 10px 6px; font-size: 12px; color: var(--text-muted);
}
.composer-status.error { color: var(--critical-500); }
.send-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

/* Composer hint under the input row. */
.composer-hint {
  margin: 6px 10px 0; font-size: 11px; color: var(--text-muted); line-height: 1.4;
}
.composer-hint[hidden] { display: none; }

/* Upload starter chip (D6): visually distinct from typed starters. */
.upload-starter-chip {
  border-style: dashed !important; border-color: var(--accent) !important;
  color: var(--accent); font-weight: var(--weight-semibold);
  background: var(--action-100);
}
.upload-starter-chip:hover { background: var(--action-200); }
