    /* ── Stub banner ───────────────────────────────────────────────────────── */
    .stub-banner {
      background: var(--amber-tint);
      border: 1px solid var(--amber-border);
      padding: 10px 16px;
      border-radius: 12px;
      margin-bottom: 16px;
      font-size: 13px;
      color: var(--amber);
    }

    /* ── Delivered panel (post-Confirm downloads) ──────────────────────────── */
    .delivered-panel {
      margin-top: 16px;
      padding: 14px 18px;
      border-radius: 12px;
      background: var(--green-tint);
      border: 1px solid var(--green-border);
      display: flex;
      gap: 10px;
      align-items: center;
      flex-wrap: wrap;
    }
    .delivered-panel .msg { font-size: 13px; font-weight: 600; color: var(--green); margin-right: 4px; }

    /* ── Single Window DecMessage request export (BETA) ────────────────────── */
    /* Shared by the confirmed-list row (a sibling <li>, not nested inside
       .entry-item) and the post-Confirm .delivered-panel (a flex child with
       flex-wrap already on) — .sw-details' flex-basis:100% only matters in
       the latter; it's a no-op outside a flex container. */
    .sw-export-row {
      display: flex;
      align-items: flex-start;
      flex-wrap: wrap;
      gap: 10px;
      padding: 2px 10px 12px;
      margin: 0 -10px;
    }
    .sw-details { flex-basis: 100%; font-size: 13px; color: var(--ink-3); }
    .sw-details summary { cursor: pointer; font-weight: 550; color: var(--ink-2); }
    .sw-details summary:hover { color: var(--accent-ink); }
    .sw-notes-body { margin-top: 8px; line-height: 1.55; }
    .sw-notes-intro { color: var(--amber); font-weight: 600; margin-bottom: 6px; }
    .sw-notes-section { margin-bottom: 10px; }
    .sw-notes-section ul { margin: 4px 0 0 18px; }
    .sw-notes-section li { margin-bottom: 2px; }
    .sw-notes-missing strong { color: var(--red); }
    .sw-notes-missing li { color: var(--red); }
    .sw-notes-error { color: var(--red); }
    .sw-unavailable { color: var(--ink-3); font-size: 13px; line-height: 1.5; }

    /* ── Toast ─────────────────────────────────────────────────────────────── */
    #toast {
      position: fixed;
      top: 72px;
      right: 28px;
      background: rgba(29, 29, 31, 0.92);
      -webkit-backdrop-filter: blur(12px);
      backdrop-filter: blur(12px);
      color: #fff;
      padding: 11px 18px;
      border-radius: 12px;
      font-size: 13px;
      box-shadow: 0 8px 28px -6px rgba(0, 0, 0, 0.35);
      opacity: 0;
      transform: translateY(6px);
      transition: opacity 0.3s, transform 0.3s;
      pointer-events: none;
      z-index: 9999;
      max-width: min(420px, calc(100vw - 32px));
      overflow-wrap: anywhere;
    }
    #toast.show { opacity: 1; transform: none; }
    /* Issue #522: the way out of a refusal. Inside the dark toast, so it takes
       the toast's own white; underlined because it is a link-shaped action,
       not a second primary (U0-2.3). No new token — inherits currentColor. */
    #toast .toast-action {
      /* #toast is pointer-events: none on purpose — it must never block the
         page it floats over. That also makes anything inside it unclickable,
         so the action takes its own events back and nothing else does. The
         RED for this caught it only because it clicked; asserting the button
         existed would have passed on a button nobody could press. */
      pointer-events: auto;
      display: block;
      margin-top: 8px;
      padding: 0;
      border: 0;
      background: transparent;
      color: inherit;
      font: inherit;
      font-weight: 650;
      text-decoration: underline;
      cursor: pointer;
    }
    #toast .toast-action:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
    /* Issue #522, owner: 高亮闪一下. Existing amber, no new colour (U0-1.4);
       the animation runs once and the class then just marks where you landed,
       so the highlight is still there when the eye arrives. */
    @keyframes locate-flash {
      0%   { background: var(--amber-tint); }
      60%  { background: var(--amber-tint); }
      100% { background: transparent; }
    }
    .field-row.field-located .label,
    .field-row.field-located input[type=text] { animation: locate-flash 1.2s ease-out; }
    .field-row.field-located .label { color: var(--amber); }
    .line-items-table td.cell-located {
      animation: locate-flash 1.2s ease-out;
      box-shadow: inset 0 0 0 1px var(--amber-border);
    }
    @media (prefers-reduced-motion: reduce) {
      .field-row.field-located .label,
      .field-row.field-located input[type=text],
      .line-items-table td.cell-located { animation: none; }
    }
    #toast.success { background: rgba(24, 118, 58, 0.94); }
    #toast.error   { background: rgba(190, 10, 30, 0.94); }
    @media (max-width: 600px) {
      #toast { right: 16px; }
    }

    /* ── Loading ───────────────────────────────────────────────────────────── */
    .spinner {
      display: inline-block;
      width: 13px; height: 13px;
      border: 2px solid rgba(255, 255, 255, 0.35);
      border-top-color: #fff;
      border-radius: 50%;
      animation: spin 0.7s linear infinite;
      vertical-align: middle;
    }
    .spinner.dark { border-color: rgba(0, 0, 0, 0.15); border-top-color: var(--accent); }
    @keyframes spin { to { transform: rotate(360deg); } }

    .empty-state { text-align: center; color: var(--ink-3); padding: 34px 16px; font-size: 13px; }
    .empty-state .icon-svg { width: 26px; height: 26px; display: block; margin: 0 auto 8px; opacity: 0.5; }

    /* ── #711 手机窄屏：只补触达尺寸，不动桌面像素 ─────────────────────────
       owner 2026-08-20：「移动端的很多文字跟排版都是很难去用的」。
       实测 390×844：工作台 10 个、复核面板 46 个可点元素小于 44×44，
       其中 33 个是 23px 上下的签字点与术语按钮。
       字号那条**不在这里改**——本屏 135 处小字全部正好落在 U0-2.1 的 13px
       下限上，抬到 14 是设计体系的改动（要么新增 CSS 变量，而 U0-6.2 禁止；
       要么逐条改 115 个选择器），归 owner 裁，见 #711。
       规则写在本文件而不是共享的 ui-copy.css：共享资产里每一条的作用域由
       文件决定，08-20 已在 #710 上栽过一次。 */
    @media (max-width: 600px) {
      /* 签字点。点错的后果是**给错的字段签了字**，不是审美问题。
         44 仍装得进 .fields-grid 的 54px 那一列（见上面 560px 那条）。 */
      .signoff-dot { width: 44px; height: 44px; line-height: 41px; }
      .signoff-dot.rule-conflict,
      .signoff-dot.rule-overridden { width: 54px; height: 44px; line-height: 41px; }
      /* 术语帮助 (?)：它是行内元素，撑高度会顶开标签行，所以只给它
         一个 44×44 的边框盒并让文字居中，行高不跟着长。 */
      .term-help-trigger {
        display: inline-flex; align-items: center; justify-content: center;
        min-width: 44px; min-height: 44px; padding: 0; margin-left: 0.1em;
        vertical-align: middle;
      }
      /* 其余按钮与导航链接托底。**刻意排除商品项表格内部**——那里的几何
         由 #251 的列预算防线锁着，撑高会把长列挤成横滚。 */
      button, .btn, .btn-small, a.nav-link, .logout-link, .operator-chip,
      .source-tabs button {
        min-height: 44px;
        min-width: 44px;
      }
      /* 只放过表体里**纯排版性**的按钮。三类留在 44：表头的 (?) 术语帮助、
         查码表、核对申报要素——后两个是复核时真要点的入口（HS 归类与申报要素
         正是 ADR-0008/0027 §6 说的「不可替代的人工判断」），点不中就等于
         这两件事在手机上做不了。撑高的是行高，不是列宽，#251 锁的是列宽。 */
      #line-items-table button:not(.term-help-trigger, .btn-small, .element-split-toggle),
      .line-items-scroll button:not(.term-help-trigger, .btn-small, .element-split-toggle),
      #containers-table button:not(.term-help-trigger, .btn-small) {
        min-height: 0;
        min-width: 0;
      }
    }
