
    /* Voice input buttons are now enabled */

    /* Legacy floating-guide styles removed 2026-07-12 — the guide is now the
       shared page-guide component (src/styles/page-guide.css). The unscoped
       .guide-* rules that lived here were matching the new component DOM
       (task-2 review finding). */

    /* ========================================================
     * Chat head — iSpirit identity + inline persona row
     * Replaces the legacy .chat-persona-bar. Sits above #messages.
     * Pattern adapted from docs/design/handoff/ui_kits/ispirit-app/app.css.
     * ======================================================== */
    .chat-head {
      display: grid;
      grid-template-columns: auto 1fr auto;
      align-items: center;
      gap: 14px;
      padding: 12px 16px;
      margin: 0 0 12px;
      border: 1px solid rgba(148, 121, 255, 0.22);
      border-radius: 16px;
      background: linear-gradient(180deg, rgba(15, 23, 42, 0.7), rgba(11, 15, 20, 0.75));
      box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
      position: relative;
    }
    .chat-head .avatar-ring {
      position: relative;
      padding: 6px;
      border-radius: 50%;
      background: conic-gradient(from 0deg,
        #4FACFE 0%, #FFFFFF 20%, #9479FF 40%,
        #4FACFE 60%, #FFFFFF 80%, #4FACFE 100%);
      animation: chat-head-ring 3s linear infinite;
      width: 56px;
      height: 56px;
      box-sizing: border-box;
      box-shadow: 0 0 12px rgba(79, 172, 254, 0.45);
    }
    @keyframes chat-head-ring { to { transform: rotate(360deg); } }
    @media (prefers-reduced-motion: reduce) {
      .chat-head .avatar-ring { animation: none; }
    }
    .chat-head .avatar-ring img {
      width: 44px; height: 44px;
      border-radius: 50%;
      display: block;
      object-fit: cover;
      /* No counter-rotation — the img rides the parent's rotation so the
         entire avatar (face + ring) visibly circles. This is the original
         88ec503 behavior. */
    }

    .chat-head-meta { min-width: 0; }
    .chat-head-name {
      display: flex;
      align-items: baseline;
      flex-wrap: wrap;
      gap: 6px;
      font-size: 14.5px;
      line-height: 1.2;
    }
    .chat-head-name .persona-name {
      font-weight: 600;
      color: #f1f5f9;
    }
    .chat-head-name .as {
      color: rgba(148, 163, 184, 0.85);
      font-weight: 400;
      font-size: 13px;
    }
    .chat-head-name .as::before {
      content: '·';
      margin-right: 6px;
      color: rgba(148, 163, 184, 0.4);
    }
    .chat-head-name [data-role="ispirit-nickname"] {
      color: #e2e8f0;
      font-weight: 500;
    }
    .chat-head-sub {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-top: 4px;
      font-family: ui-monospace, 'SF Mono', Menlo, monospace;
      font-size: 11.5px;
      color: rgba(148, 163, 184, 0.85);
      letter-spacing: 0.02em;
    }
    .chat-head-sub .live {
      width: 6px; height: 6px; border-radius: 50%;
      background: #34d399;
      box-shadow: 0 0 8px rgba(52, 211, 153, 0.85);
      animation: chat-head-live 2s ease-in-out infinite;
    }
    @keyframes chat-head-live {
      0%, 100% { opacity: 1; }
      50%      { opacity: 0.55; transform: scale(0.9); }
    }
    @media (prefers-reduced-motion: reduce) {
      .chat-head-sub .live { animation: none; }
    }
    .chat-head-sub .stage-chip {
      display: inline-flex; align-items: center;
      padding: 2px 8px;
      border-radius: 999px;
      background: rgba(79, 172, 254, 0.12);
      border: 1px solid rgba(79, 172, 254, 0.32);
      color: #93c5fd;
      font-size: 10.5px; font-weight: 600;
      letter-spacing: 0.04em;
      text-transform: uppercase;
    }
    .chat-head-sub .persona-tag {
      font-size: 11px;
      color: rgba(148, 163, 184, 0.88);  /* composited ~4.6:1 — was 0.7 ≈ 4.21:1 (round 41 a11y) */
    }

    .chat-head-personas {
      display: flex;
      gap: 4px;
      padding: 4px;
      background: rgba(8, 13, 26, 0.55);
      border: 1px solid rgba(148, 163, 184, 0.15);
      border-radius: 999px;
      align-items: center;
    }
    .chat-head-personas .persona-btn {
      width: 32px; height: 32px;
      padding: 0;
      background: transparent;
      border: 2px solid transparent;
      border-radius: 50%;
      cursor: pointer;
      opacity: 0.85;
      transition: opacity 0.18s, transform 0.18s, border-color 0.18s, box-shadow 0.18s;
      display: inline-flex; align-items: center; justify-content: center;
    }
    .chat-head-personas .persona-btn img {
      width: 28px; height: 28px;
      border-radius: 50%;
      display: block;
      object-fit: cover;
    }
    .chat-head-personas .persona-btn:hover {
      opacity: 0.9;
      transform: scale(1.06);
    }
    .chat-head-personas .persona-btn.on {
      opacity: 1;
      transform: scale(1.1);
      border-color: #4FACFE;
      box-shadow: 0 0 0 2px rgba(79, 172, 254, 0.25), 0 4px 12px rgba(79, 172, 254, 0.35);
    }
    .chat-head-personas .persona-btn:focus-visible {
      outline: 2px solid #93c5fd;
      outline-offset: 2px;
    }

    /* Mobile: stack the persona row below the identity block */
    @media (max-width: 720px) {
      .chat-head {
        grid-template-columns: auto 1fr;
        grid-template-rows: auto auto;
        gap: 10px 12px;
      }
      .chat-head .avatar-ring { grid-row: 1; grid-column: 1; }
      .chat-head-meta         { grid-row: 1; grid-column: 2; }
      .chat-head-personas     { grid-row: 2; grid-column: 1 / -1; justify-self: start; }
    }

    /* Cozy mode: warm paper + serif for the iSpirit-as label */
    [data-ux-mode="cozy"] .chat-head {
      background: #FFFBF2;
      border-color: rgba(166, 130, 85, 0.28);
      box-shadow: 0 6px 18px rgba(90, 60, 30, 0.08);
    }
    /* Cozy: bold rose ↔ deep-burgundy ↔ cream sweep, with a 3-stop
       high-contrast pattern so the rotation reads against the cream paper
       background. Box-shadow re-tinted to rose. */
    [data-ux-mode="cozy"] .chat-head .avatar-ring {
      background: conic-gradient(from 0deg,
        #C66B6B 0%, #FFFFFF 20%, #8B3A3A 40%,
        #C66B6B 60%, #FFFFFF 80%, #C66B6B 100%);
      box-shadow: 0 0 12px rgba(198, 107, 107, 0.45);
    }
    [data-ux-mode="cozy"] .chat-head-name .persona-name {
      font-family: 'Fraunces', Georgia, serif;
      color: #1A2438;
      font-weight: 600;
    }
    [data-ux-mode="cozy"] .chat-head-name [data-role="ispirit-nickname"] {
      font-family: 'Fraunces', Georgia, serif;
      font-style: italic;
      color: #1A2438;
    }
    [data-ux-mode="cozy"] .chat-head-name .as {
      color: rgba(26, 36, 56, 0.55);
    }
    [data-ux-mode="cozy"] .chat-head-sub { color: #5A5540; }
    [data-ux-mode="cozy"] .chat-head-sub .stage-chip {
      background: rgba(182, 151, 99, 0.15);
      border-color: rgba(182, 151, 99, 0.4);
      color: #8a6d4b;
    }
    [data-ux-mode="cozy"] .chat-head-personas {
      background: rgba(182, 151, 99, 0.06);
      border-color: rgba(166, 130, 85, 0.22);
    }
    [data-ux-mode="cozy"] .chat-head-personas .persona-btn.on {
      border-color: #C66B6B;
      box-shadow: 0 0 0 2px rgba(198, 107, 107, 0.25), 0 4px 12px rgba(198, 107, 107, 0.35);
    }

    /* ─────────────────────────────────────────────────────────────
       Phase 4 redesign — two-column chat-shell aside
       ───────────────────────────────────────────────────────────── */

    /* .chat-shell grid is defined in app-shell.css (1fr 320px, collapses at 1100px).
       Below 1100px we hide the aside entirely so the thread stays full-width. */
    @media (max-width: 1100px) {
      .chat-side { display: none; }
    }

    /* Ensure .chat-inner stretches inside the left column */
    .chat-shell .chat-inner {
      min-width: 0;
    }

    /* Sticky positioning for the aside so it stays in view while scrolling */
    .chat-side {
      position: sticky;
      top: 24px;
    }

    /* Card spacing inside aside */
    .chat-side .card + .card {
      margin-top: 14px;
    }

    /* Guide description text */
    .guide-desc {
      font-size: 13px;
      color: var(--fg-muted);
      margin: 0 0 10px;
      line-height: 1.55;
    }

    /* Hidden file input — display:none is functional, not decorative */
    .composer-file-input {
      display: none;
    }

    /* ─────────────────────────────────────────────────────────────
       Phase 4 redesign — chat page-head + composer trim
       ───────────────────────────────────────────────────────────── */
    body.chat-page main.chat {
      /* Replace legacy full-bleed dark canvas: let app-shell.css .main
         own the padding + max-width via .page-head wrapper. */
      max-width: 1600px;
      margin: 0 auto;
      padding: 28px 32px 80px;
    }
    /* Round 5: kill the legacy 40px inner padding so the thread fills the
       left grid column instead of leaving a horizontal moat. */
    body.chat-page .chat-inner { padding: 0; }
    /* Round 5b: composer is position:sticky bottom:0 with z-index:100. When
       the thread is taller than the viewport, the composer floats over the
       last message bubbles. Reserve composer-height + breathing room as
       bottom padding on the message log so the stuck composer never visually
       covers real content. ~100px = composer (~70px) + breathing (30px). */
    body.chat-page .chat-log { padding-bottom: 100px; }
    /* Composer needs a solid backdrop so messages aren't ghosted through it
       when it sticks above them. */
    body.chat-page .composer {
      background: rgba(5, 10, 20, 0.92);
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
      border-top: 1px solid var(--border);
      padding: 12px 16px;
      margin: 0 -16px -16px;
      border-radius: 0 0 16px 16px;
    }
    /* Layout fix (2026-06-28): app-shell.css sets `.composer { display: grid;
       grid-template-columns: auto auto 1fr auto }`. The hidden #filePick input
       drops a grid column, so the `1fr` track lands on #send — making the Send
       button ~440px wide and the input tiny. Re-assert the intended flex row
       (from styles.css) with higher specificity so the textarea grows and the
       buttons stay fixed, regardless of stylesheet load order. */
    body.chat-page .composer {
      display: flex;
      align-items: center;
      gap: 8px;
    }
    body.chat-page .composer .voice-input-wrapper {
      flex: 1 1 auto;
      min-width: 0;
      display: flex;
    }
    body.chat-page .composer .voice-input-wrapper textarea,
    body.chat-page .composer #text {
      flex: 1 1 auto;
      min-width: 0;
      width: 100%;
    }
    body.chat-page .composer #attachBtn,
    body.chat-page .composer #send {
      flex: 0 0 auto;
    }
    @media (max-width: 720px) {
      body.chat-page main.chat { padding: 16px 16px 80px; }
    }
    .chat-page-head { margin-bottom: 18px; }
    /* Phase 4: actions row sits BELOW the description, left-aligned (matches design ref 18).
       The header flex now has only one child (the content div) so no space-between push. */
    .chat-page-head-actions {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-top: 16px;
    }
    .chat-page-head-actions .icon-inline {
      width: 16px; height: 16px; display: inline-block;
    }

    /* Phase 4: composer icon buttons (paperclip / mic) — small, ghost. */
    .composer .composer-btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 36px;
      height: 36px;
      border-radius: 10px;
      background: transparent;
      border: 1px solid rgba(255, 255, 255, 0.08);
      color: var(--fg-muted, #94a3b8);
      cursor: pointer;
      flex: 0 0 auto;
      padding: 0;
      transition: all 0.18s;
    }
    .composer .composer-btn:hover {
      background: rgba(255, 255, 255, 0.04);
      color: var(--fg);
      border-color: rgba(255, 255, 255, 0.18);
    }
    .composer .composer-btn svg { width: 16px; height: 16px; }
    [data-ux-mode="cozy"] .composer .composer-btn {
      border-color: rgba(166, 130, 85, 0.25);
      color: #5A5540;
    }
    [data-ux-mode="cozy"] .composer .composer-btn:hover {
      background: rgba(198, 107, 107, 0.08);
    }

    /* ── 附件（回形针）按钮 — 图标被压扁修复（2026-06-28）──
       #attachBtn 带 .btn 类，因此被全局 .btn 规则（styles.css:1136 —
       padding 14px 20px、color #fff、min-height 48px）+ 44px 触控目标下限
       （styles.css:2742 `button { min-width:44px }`）凭特异性压过：44px 的
       border-box 按钮减去 40px 水平内边距只剩约 4px 内容宽度，16px 的回形针
       SVG（flex 子项）被压到约 4px 宽 —— 用户几乎看不见。与 app-shell.css:255
       记录的 topbar .btn-icon 压扁问题同源。修复：固定为整洁的 44px 方形、
       清除内边距、给图标固定 20px 不收缩、提高描边对比；保留 44px 满足
       WCAG 2.5.5 触控目标（桌面 + 移动端皆可）。 */
    body.chat-page .composer #attachBtn {
      width: 44px;
      height: 44px;
      min-width: 44px;
      min-height: 44px !important;   /* 压过 .btn min-height:48 → 方形 */
      padding: 0 !important;         /* 清除 .btn 的 14px 20px 压扁 */
      flex: 0 0 auto;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 0;
      background: transparent;
      border: 1px solid rgba(255, 255, 255, 0.14);
      border-radius: 12px;
      color: #cbd5e1;                /* 比 #94a3b8 更亮 */
      box-shadow: none;
    }
    body.chat-page .composer #attachBtn svg {
      width: 20px !important;
      height: 20px !important;
      flex: 0 0 auto;                /* 永不让图标 flex 收缩 */
    }
    body.chat-page .composer #attachBtn:hover {
      background: rgba(255, 255, 255, 0.06);
      color: #ffffff;
      border-color: rgba(255, 255, 255, 0.24);
    }
    /* 温暖模式的配色（暖纸边框 + 大地色墨水）由 cozy-theme.css
       `.composer .composer-btn`（!important）负责；上面只设尺寸/内边距，
       因此在温暖模式下仍然生效。此处无需再覆盖颜色。 */

    /* ═══════════════════════════════════════════════════════════════
       DESIGN-GAP CLOSURE — chat.html  (2026-05-17)
       Aligns live page to mockup 18-app-chat.png
       ═══════════════════════════════════════════════════════════════ */

    /* ── 1. Mode buttons: calm dark with subtle accent (not neon solid) ── */
    .chat-page-head-actions #chatDeepThinkerBtn,
    .chat-page-head-actions #chatVoiceModeBtn {
      background: rgba(15, 23, 42, 0.75);
      border: 1px solid rgba(148, 121, 255, 0.28);
      color: var(--fg-muted, #94a3b8);
      font-size: 13px;
      font-weight: 500;
      padding: 8px 16px;
      min-height: unset;
      border-radius: var(--radius-pill, 999px);
      box-shadow: none;
      backdrop-filter: blur(8px);
      -webkit-backdrop-filter: blur(8px);
      transition: background 0.18s, border-color 0.18s, color 0.18s, box-shadow 0.18s;
    }
    /* Remove the glass shimmer pseudo-element on these specific buttons */
    .chat-page-head-actions #chatDeepThinkerBtn::before,
    .chat-page-head-actions #chatVoiceModeBtn::before {
      display: none;
    }
    .chat-page-head-actions #chatDeepThinkerBtn:hover,
    .chat-page-head-actions #chatVoiceModeBtn:hover {
      background: rgba(148, 121, 255, 0.10);
      border-color: rgba(148, 121, 255, 0.55);
      color: var(--fg, #e6edf3);
      box-shadow: none;
      transform: none;
    }
    /* Active / toggled-on state — gradient allowed */
    .chat-page-head-actions #chatDeepThinkerBtn.active,
    .chat-page-head-actions #chatVoiceModeBtn.active {
      background: linear-gradient(135deg, rgba(79,172,254,0.22), rgba(148,121,255,0.22));
      border-color: rgba(148, 121, 255, 0.55);
      color: var(--fg-strong, #ffffff);
      box-shadow: 0 0 12px rgba(148,121,255,0.18);
    }
    [data-ux-mode="cozy"] .chat-page-head-actions #chatDeepThinkerBtn,
    [data-ux-mode="cozy"] .chat-page-head-actions #chatVoiceModeBtn {
      background: rgba(255, 251, 242, 0.85);
      border-color: rgba(166, 130, 85, 0.30);
      color: #5A5540;
    }

    /* ── 2. User chat bubbles: purple→violet gradient, right-aligned ──
     *  Lightest stop darkened #a78bfa → #7c3aed (and mid #8b5cf6 → #6d28d9)
     *  so white body text + the timestamp clear WCAG AA even at the
     *  bottom-right where the timestamp sits (review F3 2026-06-19;
     *  was ~1.85:1 white-on-#a78bfa). */
    body.chat-page .bubble.user {
      background: linear-gradient(135deg, #5b21b6 0%, #6d28d9 50%, #7c3aed 100%);
      color: #ffffff;
      border: 1px solid rgba(124, 58, 237, 0.45);
      border-bottom-right-radius: 4px;
      border-bottom-left-radius: var(--radius-md, 14px);
      box-shadow: 0 4px 16px rgba(91, 33, 182, 0.30);
    }
    body.chat-page .bubble.user .bubble-text {
      color: #ffffff;
    }
    body.chat-page .bubble.user .bubble-time {
      color: rgba(255,255,255,0.92);
    }
    [data-ux-mode="cozy"] body.chat-page .bubble.user,
    [data-ux-mode="cozy"].chat-page .bubble.user {
      background: linear-gradient(135deg, #7c3aed 0%, #a78bfa 100%);
    }

    /* ── 3. Assistant (iSpirit) bubble: dark card, left-aligned, calm border ── */
    body.chat-page .bubble.assistant {
      background: rgba(15, 23, 42, 0.88);
      border: 1px solid rgba(148, 121, 255, 0.22);
      border-bottom-left-radius: 4px;
      box-shadow: 0 4px 18px rgba(0, 0, 0, 0.32);
    }
    /* iSpirit avatar: calm size, no neon, soft glow ring */
    body.chat-page .row.assistant .avatar {
      width: 40px;
      height: 40px;
      min-width: 40px;
      flex: 0 0 40px;
      border-radius: 50%;
      background: rgba(148, 121, 255, 0.15);
      border: 2px solid rgba(148, 121, 255, 0.30);
      padding: 0;
      font-size: 22px;
    }
    body.chat-page .row.assistant .avatar img {
      width: 100%;
      height: 100%;
      border-radius: 50%;
      object-fit: cover;
    }

    /* ── 4. Right-rail cards: thin bordered, dark, calm headings ── */
    body.chat-page .chat-side .card {
      background: rgba(8, 13, 26, 0.82);
      border: 1px solid rgba(148, 121, 255, 0.18);
      border-radius: var(--radius-md, 14px);
      padding: 16px;
      margin-bottom: 0;
    }
    body.chat-page .chat-side .card-title {
      font-size: 13px;
      font-weight: 600;
      color: var(--fg, #e6edf3);
      letter-spacing: 0.01em;
    }
    body.chat-page .chat-side .guide-desc {
      font-size: 12px;
      color: var(--fg-muted, #94a3b8);
      line-height: 1.55;
      margin: 0 0 8px;
    }
    body.chat-page .chat-side .guide-block h4 {
      font-size: 11px;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.10em;
      color: var(--fg-muted, #94a3b8);
      margin-bottom: 6px;
    }
    body.chat-page .chat-side .guide-line {
      font-size: 12px;
      color: var(--fg-muted, #94a3b8);
      font-family: var(--font-sans, sans-serif);
      padding: 3px 0;
      opacity: 0.85;
      position: relative;
      padding-left: 12px;
    }
    body.chat-page .chat-side .guide-line::before {
      content: '·';
      position: absolute;
      left: 0;
      color: var(--accent-purple, #9479FF);
    }
    body.chat-page .chat-side .hold-list li {
      font-size: 12px;
      color: var(--fg-muted, #94a3b8);
      background: rgba(15, 23, 42, 0.60);
      border: 1px solid rgba(148, 121, 255, 0.14);
      border-radius: 8px;
      padding: 8px 10px;
    }

    /* ── 5. Composer: send button uses brand cyan→purple gradient ── */
    body.chat-page .composer #send {
      background: linear-gradient(135deg, var(--accent-cyan, #4FACFE) 0%, var(--accent-purple, #9479FF) 100%);
      border: none;
      color: #ffffff;
      font-weight: 600;
      font-size: 13px;
      padding: 8px 18px;
      border-radius: var(--radius-pill, 999px);
      box-shadow: 0 2px 12px rgba(148, 121, 255, 0.28);
      min-height: unset;
    }
    body.chat-page .composer #send::before { display: none; }
    body.chat-page .composer #send:hover {
      background: linear-gradient(135deg, #62b8ff 0%, #a88bff 100%);
      box-shadow: 0 4px 18px rgba(148, 121, 255, 0.38);
      transform: none;
    }
    [data-ux-mode="cozy"] body.chat-page .composer #send {
      background: linear-gradient(135deg, #C66B6B 0%, #7c3aed 100%);
    }
    /* 移动端触控目标（round 58 MED-4）：上面的 #send 覆盖规则（min-height:unset
       + 8px padding）凭 ID 特异性压过了 app-shell.css 的 44px @media 规则，
       手机上的主发送按钮只有 29px 高（WCAG 2.5.5）。在同等特异性下恢复 ≥44px；
       同时把头部工具栏按钮（语音 / 深度思考模式）提升到 44px（round 58 LOW-3）。 */
    @media (max-width: 900px) {
      /* Android 视觉对齐（2026-06-12）：手机端发送控件变为 44px 圆形渐变按钮，
         内含居中纸飞机图标（mask-image data-URI，符合 CSP，不是脚本）。"Send"
         文字在视觉上隐藏（font-size:0），但保留在 DOM + aria-label 中供屏幕阅读器
         使用。桌面端保留带文字的胶囊按钮（上面的规则）。 */
      body.chat-page .composer #send {
        min-height: 44px;
        width: 44px;
        height: 44px;
        min-width: 44px;
        padding: 0;
        font-size: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        border-radius: 999px;
      }
      body.chat-page .composer #send::before {
        content: "";
        display: block;
        width: 19px;
        height: 19px;
        background-color: #ffffff;
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m22 2-7 20-4-9-9-4Z'/%3E%3Cpath d='M22 2 11 13'/%3E%3C/svg%3E") center / contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m22 2-7 20-4-9-9-4Z'/%3E%3Cpath d='M22 2 11 13'/%3E%3C/svg%3E") center / contain no-repeat;
      }
      body.chat-page .composer #send .spinner { display: none; }
      body.chat-page .chat-page-head-actions .btn { min-height: 44px; }
    }

    /* ── 6. Composer: textarea placeholder text ── */
    body.chat-page .composer textarea::placeholder {
      color: var(--fg-muted, #94a3b8);
      opacity: 0.65;
    }

    /* ── 7. chat-head: calm the persona/voice pill row (no neon) ── */
    body.chat-page .chat-head {
      background: rgba(8, 13, 26, 0.70);
      border-color: rgba(148, 121, 255, 0.18);
      padding: 10px 14px;
    }
    body.chat-page .chat-head-sub .stage-chip {
      background: rgba(148, 121, 255, 0.10);
      border-color: rgba(148, 121, 255, 0.28);
      color: var(--fg-muted, #94a3b8);
      font-size: 10px;
    }

    /* ═══════════════════════════════════════════════════════════════
       ROUND 7 — close remaining gaps vs target 18-app-chat.png
       ═══════════════════════════════════════════════════════════════ */

    /* R7-1. chat-head: tighten avatar ring (44 → fits target density) */
    body.chat-page .chat-head .avatar-ring {
      width: 48px;
      height: 48px;
      padding: 4px;
    }
    body.chat-page .chat-head .avatar-ring img {
      width: 40px;
      height: 40px;
    }

    /* R7-2. persona picker dots: smaller + tighter cluster */
    body.chat-page .chat-head-personas {
      gap: 3px;
      padding: 3px;
    }
    body.chat-page .chat-head-personas .persona-btn {
      width: 28px;
      height: 28px;
    }
    body.chat-page .chat-head-personas .persona-btn img {
      width: 24px;
      height: 24px;
    }

    /* ── 人格切换头像 — 标准模式压扁修复（2026-06-28）──
       人格切换器是纯 <button class="persona-btn">（不带 .btn），因此被全局
       兜底按钮规则（styles.css:1295 `button:not(.icon-btn):not(.btn)
       :not(.primary):not(.danger)` —— padding 12px 16px + 渐变填充，特异性
       0,4,1）以及 44px 触控目标下限（styles.css:2742 `button { min-width:44px }`）
       捕获。两者共同压过上面的 28px 尺寸，配合 box-sizing:border-box 只剩约
       12px 内容宽 —— 头像 <img> 在过大的渐变胶囊里被压成窄条（用户反馈：标准
       模式下"AI 照片显示不正常"，而温暖模式正常）。温暖模式靠自身的
       :not(.persona-btn) 兜底 + 覆盖规则（cozy-theme.css:1883）逃过此问题，
       标准模式没有。此处恢复圆形头像，并限定 standard 模式，绝不影响正常的
       温暖模式规则。 */
    [data-ux-mode="standard"] .chat-head-personas .persona-btn {
      min-width: 0 !important;
      min-height: 0 !important;
      width: 32px !important;
      height: 32px !important;
      padding: 0 !important;
      border: 2px solid transparent !important;
      border-radius: 50% !important;
      background: transparent !important;
      box-shadow: none !important;
    }
    [data-ux-mode="standard"] .chat-head-personas .persona-btn img {
      width: 28px !important;
      height: 28px !important;
      border-radius: 50% !important;
      object-fit: cover;
      display: block;
      flex: 0 0 auto;                /* 永不让头像 flex 收缩 */
    }
    [data-ux-mode="standard"] .chat-head-personas .persona-btn.on {
      border-color: #4FACFE !important;
      box-shadow: 0 0 0 2px rgba(79, 172, 254, 0.25),
                  0 4px 12px rgba(79, 172, 254, 0.35) !important;
    }

    /* R7-3. chat page-head action pills: slimmer + ghost-icon style */
    .chat-page-head-actions #chatDeepThinkerBtn,
    .chat-page-head-actions #chatVoiceModeBtn {
      padding: 6px 14px;
      font-size: 12.5px;
      gap: 6px;
      display: inline-flex;
      align-items: center;
    }
    .chat-page-head-actions .icon-inline {
      width: 14px;
      height: 14px;
      opacity: 0.75;
    }

    /* R7-4. assistant bubble: slightly more breathing room + softer card */
    body.chat-page .bubble.assistant {
      background: rgba(15, 23, 42, 0.78);
      padding: 14px 16px;
      max-width: 78%;
    }
    body.chat-page .bubble.user {
      padding: 12px 16px;
      max-width: 72%;
    }
    body.chat-page .row {
      align-items: flex-start;
      margin-bottom: 4px;
    }
    body.chat-page .messages {
      gap: 14px;
      padding: 8px 4px 0;
    }

    /* R7-5. composer: warmer pill shape, slimmer profile, icons left-grouped */
    body.chat-page .composer {
      padding: 8px 10px;
      gap: 8px;
      border-radius: 18px;
      background: rgba(8, 13, 26, 0.92);
      border: 1px solid rgba(148, 121, 255, 0.22);
    }
    body.chat-page .composer textarea {
      font-size: 13.5px;
      padding: 8px 4px;
    }
    /* QA R5 (2026-07-18)：温馨模式下输入框使用 --cozy-text-lift 22px 字号
       （cozy-theme.css:442，用于提升温馨模式输入的可读性，此处不应单独缩小），
       又挤在 72px 温馨麦克风按钮旁的窄列中。即使是较短的默认占位符
       （"对你的灵宠说点什么…"）换行后也需要约 208px 高度，而输入框只有 102px，
       出现明显裁切（这个问题独立于 chat_init.js 中按宽度限定的语音优先占位符，
       且早于那次改动就存在）。用独立的媒体查询包裹（确认这个文件里周围的规则
       并不像 R7-5 注释暗示的那样可靠地限定在移动端 —— 实测同一段落的
       font-size:13.5px 在 1400px 宽度下依然生效），让加高只在移动端出现；
       桌面温馨模式本就有余量，不加限定的 210px 下限会显得明显过高。需要
       !important 才能压过特异性更高的 ID 规则
       `[data-ux-mode="cozy"] #text`（cozy-theme.css，min-height:56px）以及
       基础规则 `.composer textarea` 的 max-height:120px（app-shell.css）。
       标准模式不受影响。 */
    @media (max-width: 480px) {
      [data-ux-mode="cozy"] body.chat-page .composer textarea {
        min-height: 210px !important;
        max-height: 230px !important;
        height: auto !important;
      }
    }
    body.chat-page .composer .composer-btn {
      width: 34px;
      height: 34px;
      border-radius: 12px;
    }

    /* R7-6. side cards: tighten + match target rhythm */
    body.chat-page .chat-side .card {
      padding: 14px;
    }
    body.chat-page .chat-side .card + .card {
      margin-top: 12px;
    }
    body.chat-page .chat-side .card-head {
      margin-bottom: 8px;
    }
    body.chat-page .chat-side .guide-block {
      margin-top: 12px;
      padding-top: 10px;
    }
    body.chat-page .chat-side .hold-list li {
      font-size: 12.5px;
      line-height: 1.5;
    }

    /* R7-7. memory citation badge — "✨ Drew from N past memories" */
    body.chat-page .memory-citation-badge,
    body.chat-page .citations-badge {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      font-size: 11px;
      color: rgba(148, 121, 255, 0.85);
      background: rgba(148, 121, 255, 0.10);
      border: 1px solid rgba(148, 121, 255, 0.22);
      padding: 3px 9px;
      border-radius: 999px;
      margin-top: 6px;
      cursor: pointer;
      transition: background 0.18s, border-color 0.18s;
    }
    body.chat-page .memory-citation-badge:hover,
    body.chat-page .citations-badge:hover {
      background: rgba(148, 121, 255, 0.18);
      border-color: rgba(148, 121, 255, 0.42);
    }

    /* R7-8. "Explore the conversation as a journal entry" pill (if rendered
       by chat-ui.js as .conversation-followup or .journal-pill, keep generic) */
    body.chat-page .journal-from-chat-pill,
    body.chat-page .conversation-followup-pill {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-size: 12px;
      color: var(--fg-muted, #94a3b8);
      background: rgba(15, 23, 42, 0.70);
      border: 1px dashed rgba(148, 121, 255, 0.30);
      padding: 7px 14px;
      border-radius: 999px;
      margin: 10px 0;
      cursor: pointer;
      transition: all 0.18s;
    }
    body.chat-page .journal-from-chat-pill:hover,
    body.chat-page .conversation-followup-pill:hover {
      color: var(--fg, #e6edf3);
      border-color: rgba(148, 121, 255, 0.55);
      background: rgba(148, 121, 255, 0.08);
    }

    /* R7-9. timestamp: subtler under bubble */
    body.chat-page .bubble-time {
      font-size: 10.5px;
      opacity: 0.55;
      margin-top: 5px;
    }
    body.chat-page .bubble.assistant .bubble-time {
      color: rgba(148, 163, 184, 0.88);  /* composited ~4.6:1 — was 0.7 ≈ 4.09:1 (round 41 a11y) */
    }

    /* R7-10. row gap between avatar and bubble (assistant side) — tighter */
    body.chat-page .row.assistant {
      gap: 8px;
    }
    body.chat-page .row.assistant .avatar {
      margin: 0;
    }

    /* ═══════════════════════════════════════════════════════════════
       ROUND 7b — chat layout fixes (user-bubble right + avatar,
       real internal scrolling, composer in-flow, page-head moved to
       right column for more chat top-room)
       ═══════════════════════════════════════════════════════════════ */

    /* 7b-1. Make <main class="chat"> a 2-column grid on desktop:
       left = thread (fills viewport height), right = page-head + cards. */
    @media (min-width: 1100px) {
      body.chat-page main.chat {
        display: grid;
        grid-template-columns: 1fr 340px;
        grid-template-areas:
          "thread side-head"
          "thread side-cards";
        grid-template-rows: auto 1fr;
        column-gap: 22px;
        row-gap: 16px;
        /* Fill viewport minus topbar (~65px) and our own top/bottom padding. */
        height: calc(100dvh - 65px);
        padding: 20px 32px 20px;
        max-width: 1600px;
        margin: 0 auto;
        overflow: hidden;
      }
      body.chat-page .chat-page-head {
        grid-area: side-head;
        margin: 0;
        align-self: start;
      }
      /* Collapse .chat-shell out of the layout so its children
         (.chat-inner + .chat-side) participate directly in main.chat's
         grid. Without display:contents, .chat-shell remains a 2-col
         grid (app-shell.css) and chat-side's grid-area can't escape it. */
      body.chat-page .chat-shell {
        display: contents;
      }
      body.chat-page .chat-shell > .chat-inner {
        grid-area: thread;
        align-self: stretch;
        height: 100%;
        min-height: 0;
      }
      body.chat-page .chat-shell > .chat-side {
        grid-area: side-cards;
        position: static;
        align-self: start;
        margin-top: 0;
        max-height: 100%;
        overflow-y: auto;
      }
      /* Tighter page-head when it sits in the narrow right column. */
      body.chat-page .chat-page-head .eyebrow { font-size: 11px; }
      body.chat-page .chat-page-head h1 { font-size: 22px; line-height: 1.18; }
      body.chat-page .chat-page-head p { font-size: 13px; line-height: 1.5; margin-top: 6px; }
      body.chat-page .chat-page-head-actions { margin-top: 12px; flex-wrap: wrap; }
    }

    /* 7b-2. Thread becomes a flex column: messages take the leftover
       vertical space and scroll inside; composer sits in normal flow
       below them (no more sticky overlap). */
    body.chat-page .chat-shell .chat-inner {
      display: flex;
      flex-direction: column;
      min-height: 0;
      height: 100%;
    }
    body.chat-page .chat-inner > .messages,
    body.chat-page .chat-inner > #messages {
      flex: 1 1 auto;
      min-height: 0;
      overflow-y: auto;
      overscroll-behavior: contain;
      padding: 8px 4px 12px;          /* drop the legacy 100px reserve */
      scroll-behavior: smooth;
    }
    body.chat-page .chat-inner > .composer {
      position: relative;             /* override the prior sticky positioning */
      bottom: auto;
      flex: 0 0 auto;
      margin: 12px 0 0;
      border-radius: 16px;
      border: 1px solid rgba(148, 121, 255, 0.22);
    }

    /* 7b-3. User row: avatar on the FAR RIGHT, bubble immediately to its
       left, both anchored right. JS already appends children as
       [bubble, avatar] for the user role (app.js:634-635), so plain
       `flex-direction: row + justify-content: flex-end` lays them out
       correctly. We override `.bubble-row.user { flex-direction: row-reverse }`
       from app-shell.css (which was double-reversing). Re-enables the user
       avatar (overrides styles.css P-02a `.row.user .avatar { display: none }`). */
    body.chat-page .row.user.bubble-row,
    body.chat-page .row.user {
      flex-direction: row;
      justify-content: flex-end;
    }
    body.chat-page .row.user .avatar {
      display: inline-grid;           /* un-hide; overrides .row.user .avatar { display:none } */
      place-items: center;
      width: 36px;
      height: 36px;
      min-width: 36px;
      flex: 0 0 36px;
      margin: 0;
      padding: 0;
      border-radius: 50%;
      overflow: hidden;
      background: linear-gradient(135deg, #6d28d9 0%, #8b5cf6 100%);
      border: 2px solid rgba(167, 139, 250, 0.35);
      color: #fff;
      font-size: 14px;
      font-weight: 600;
    }
    body.chat-page .row.user .avatar img {
      width: 100%;
      height: 100%;
      border-radius: 50%;
      object-fit: cover;
      display: block;
    }

    /* 7b-4. Mobile fallback (<1100px): drop the grid, restore vertical
       flow, let the page scroll naturally. Aside hidden by existing rule. */
    @media (max-width: 1099.98px) {
      body.chat-page main.chat {
        display: block;
        height: auto;
        padding: 20px 16px 80px;
      }
      body.chat-page .chat-page-head {
        margin: 0 0 18px;
      }
      body.chat-page .chat-shell {
        height: auto;
      }
      body.chat-page .chat-shell .chat-inner {
        height: auto;
      }
      body.chat-page .chat-inner > .messages,
      body.chat-page .chat-inner > #messages {
        /* QA round 5（iOS 外壳巡检）：280px 按桌面头部估算，手机头部
           实际约 460px，导致最新消息被吸底输入框 + 底部导航遮住。
           改为按视口适配 —— app.js 首次渲染后会把页面滚到对话区
           （scrollPageToThread），此时输入框回到文档流、位于列表之下。 */
        max-height: calc(100dvh - 250px);
      }
    }

/* --- Consent-first chat → CEC proposal card --- */
/* Rendered after an assistant turn when the iSpirit proposed real work via
   the propose_task tool. The user dispatches (spends one CEC credit, by their
   tap) or declines. No silent spend (§4.9). */
.cec-proposal-card {
  margin: 10px 0 14px 52px;
  max-width: 560px;
  border: 1px solid rgba(124, 156, 255, 0.45);
  border-radius: 14px;
  padding: 14px 16px;
  background: linear-gradient(180deg, rgba(28, 38, 66, 0.92), rgba(20, 28, 50, 0.92));
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.25);
}
.cec-proposal-head {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #9db4ff;
  margin-bottom: 6px;
}
.cec-proposal-title {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.35;
  color: #f2f5ff;
  margin-bottom: 6px;
}
.cec-proposal-cost {
  font-size: 13px;
  color: #b9c2da;
  margin-bottom: 12px;
}
.cec-proposal-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.cec-proposal-run {
  appearance: none;
  border: none;
  border-radius: 10px;
  padding: 9px 16px;
  font-size: 14px;
  font-weight: 600;
  color: #0b1220;
  background: linear-gradient(180deg, #aebfff, #7c9cff);
  cursor: pointer;
  display: inline-block;
  text-decoration: none;
}
a.cec-proposal-run:hover { color: #0b1220; }
.cec-proposal-run:hover { filter: brightness(1.06); }
.cec-proposal-run:disabled { opacity: 0.6; cursor: default; }
.cec-proposal-skip {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 10px;
  padding: 9px 16px;
  font-size: 14px;
  font-weight: 500;
  color: #c6cee0;
  background: transparent;
  cursor: pointer;
}
.cec-proposal-skip:hover { background: rgba(255, 255, 255, 0.06); }
.cec-proposal-status {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.4;
  color: #a8e6c1;
}
.cec-proposal-status.cec-proposal-error { color: #ffb4b4; }
.cec-proposal-dispatched { border-color: rgba(120, 220, 160, 0.4); }
.cec-proposal-done { border-color: rgba(120, 220, 160, 0.7); }

/* Cozy mode (Dev Rule #43): light surface, no dark-on-dark. */
[data-ux-mode="cozy"] .cec-proposal-card {
  border-color: rgba(176, 142, 90, 0.45);
  background: linear-gradient(180deg, rgba(255, 251, 242, 0.96), rgba(250, 243, 228, 0.96));
  box-shadow: 0 3px 14px rgba(120, 100, 60, 0.12);
}
[data-ux-mode="cozy"] .cec-proposal-head { color: #9a7b3c; }
[data-ux-mode="cozy"] .cec-proposal-title { color: #2c2716; }
[data-ux-mode="cozy"] .cec-proposal-cost { color: #6b6450; }
[data-ux-mode="cozy"] .cec-proposal-run {
  color: #2c2716;
  background: linear-gradient(180deg, #f0d59a, #e0b86a);
}
[data-ux-mode="cozy"] .cec-proposal-skip {
  border-color: rgba(120, 100, 60, 0.28);
  color: #6b6450;
}
[data-ux-mode="cozy"] .cec-proposal-status { color: #3a7d52; }
[data-ux-mode="cozy"] .cec-proposal-status.cec-proposal-error { color: #b04a4a; }
[data-ux-mode="cozy"] .cec-proposal-done { border-color: rgba(58, 125, 82, 0.6); }

/* QA round 55 LOW-2: at phone width the composer sat in document flow below
   the fold (y≈1033 in an 844px viewport) — you had to scroll to type. The
   round-5b sticky rule had been lost in a refactor; restore it mobile-scoped.
   The solid backdrop + .chat-log padding-bottom:100px above already handle
   the overlap. Offset clears the fixed mobile bottom-nav when present. */
@media (max-width: 720px) {
  /* position:fixed (not sticky): the composer sits under a STACK of
     overflow:hidden ancestors (.chat-inner, main.chat) and the page scroller
     is the .app grid — sticky can never escape that to the viewport. Fixed
     ignores ancestor clipping. Selector mirrors the desktop un-stick rule
     `body.chat-page .chat-inner > .composer` (0,2,2) so this wins. */
  body.chat-page .chat-inner > .composer,
  body.chat-page .composer {
    position: fixed;
    left: 8px;
    right: 8px;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 8px);
    z-index: 100;
    margin: 0;
  }
  body.chat-page.has-mobile-bottom-nav .chat-inner > .composer,
  body.chat-page.has-mobile-bottom-nav .composer {
    bottom: calc(env(safe-area-inset-bottom, 0px) + 64px);
  }
  /* Reserve room so the fixed composer + bottom nav never cover the last
     messages: composer (~76px) + nav (~64px) + breathing. */
  body.chat-page .chat-log { padding-bottom: 170px; }
  /* Composer icon buttons (attach / mic) were 32x32 — tap-target floor. */
  body.chat-page .composer .composer-btn { width: 44px; height: 44px; }
  /* .chat-inner is overflow:hidden (desktop corner clipping) — that makes it
     the sticky containing scroller and the composer never lifts. The page
     scrolls on <body> at phone width, so visible overflow is safe here. */
  body.chat-page .chat-inner { overflow: visible; }
}

/* Today's Focus panel (chat daily home) */
.today-focus { display: flex; flex-direction: column; gap: 14px; }
.tf-section { display: flex; flex-direction: column; gap: 6px; }
.tf-section-title { font-size: 0.78rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--text-muted); margin: 0 0 2px; }
.tf-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border-radius: 10px; text-decoration: none; color: var(--text-primary);
  background: color-mix(in srgb, var(--accent-purple) 6%, transparent); }
.tf-row:hover { background: color-mix(in srgb, var(--accent-purple) 14%, transparent); }
.tf-ic { flex: 0 0 auto; width: 16px; height: 16px; color: var(--accent-purple); }
.tf-main { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.tf-title { font-size: 0.9rem; font-weight: 600; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.tf-sub { font-size: 0.76rem; color: var(--text-muted); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.tf-when { flex: 0 0 auto; font-size: 0.72rem; color: var(--text-muted); }
.tf-loading, .tf-empty, .tf-err { font-size: 0.85rem; color: var(--text-muted);
  padding: 10px; text-decoration: none; display: block; }
.tf-err { border: none; background: none; cursor: pointer; text-align: left; }
.tf-chip-row { display: flex; flex-wrap: wrap; gap: 6px; }
.tf-chip { display: inline-flex; align-items: center; gap: 5px; padding: 5px 9px;
  border-radius: 999px; text-decoration: none; font-size: 0.82rem; font-weight: 600;
  color: var(--text-primary); background: color-mix(in srgb, var(--accent-purple) 10%, transparent); }
.tf-chip:hover { background: color-mix(in srgb, var(--accent-purple) 18%, transparent); }
.tf-chip-ic { width: 13px; height: 13px; color: var(--accent-purple); }
/* Today's habits — a tf-row that carries an action, not a link. */
.tf-habit-row { cursor: default; flex-wrap: wrap; }
.tf-habit-row:hover { background: color-mix(in srgb, var(--accent-purple) 6%, transparent); }
.tf-habit-btn { flex: 0 0 auto; padding: 5px 11px; border-radius: 999px; border: none;
  font-size: 0.78rem; font-weight: 700; cursor: pointer; color: var(--text-primary);
  background: color-mix(in srgb, var(--accent-purple) 22%, transparent); }
.tf-habit-btn:hover:not(:disabled) { background: color-mix(in srgb, var(--accent-purple) 34%, transparent); }
.tf-habit-btn:disabled { cursor: default; opacity: 0.75; }
.tf-habit-err { flex: 0 0 100%; font-size: 0.74rem; color: var(--danger); padding-left: 26px; }
/* Starter wizards — the way in for someone with no history yet. Slightly
   warmer than a plain row so the section reads as an offer, not a backlog. */
.tf-starter-row { align-items: flex-start;
  background: color-mix(in srgb, var(--accent-purple) 10%, transparent); }
.tf-starter-row:hover { background: color-mix(in srgb, var(--accent-purple) 18%, transparent); }
.tf-starter-row .tf-sub { white-space: normal; overflow: visible;
  text-overflow: clip; line-height: 1.35; margin-top: 2px; }
.tf-starter-cost { align-self: center; opacity: 0.8; white-space: nowrap; }
/* Mobile strip: shown only < 1100px (desktop .chat-side already hides there) */
.today-focus-mobile { display: none; }
@media (max-width: 1100px) {
  .today-focus-mobile { display: block; margin-bottom: 14px;
    border: 1px solid var(--card-border, rgba(255,255,255,0.08)); border-radius: 12px; padding: 10px; }
  .today-focus-mobile > summary { font-weight: 700; cursor: pointer; padding: 4px; }
}

/* §97 remainder (sweep-08): these bare chips are filled by the styles.css button
   catch-all with white text on the light --accent gradient (2.49:1). A
   standard-scoped !important restores the AA --gradient-brand (the app-shell
   scoped rule mysteriously lost the cascade to the catch-all; !important is the
   codebase's documented way to beat that over-broad catch-all). Cozy excluded. */
:root:not([data-ux-mode="cozy"]) .tf-habit-btn,
:root:not([data-ux-mode="cozy"]) .persona-picker-chip {
  background: var(--gradient-brand) !important;
  color: #ffffff !important;
}

/* ── Composer "Tidy" button (2026-08-29, spec 2026-08-29-chat-composer-tidy-design) ──
   Same hard-size shape as #attachBtn above (it carries `.btn`, so the same
   icon-crush applies). Two glyphs, one shown: sparkles idle, undo arrow while
   the tidied text sits untouched in the box. The note is a transient status
   line above the composer (the form is position:sticky, so absolute works). */
body.chat-page .composer #tidyBtn {
  width: 44px; height: 44px; min-width: 44px;
  min-height: 44px !important;
  padding: 0 !important;
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 0;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 12px;
  color: #cbd5e1;
  box-shadow: none;
  position: relative;
}
body.chat-page .composer #tidyBtn svg { width: 20px !important; height: 20px !important; flex: 0 0 auto; }
body.chat-page .composer #tidyBtn .tidy-icon-undo { display: none; }
body.chat-page .composer #tidyBtn.is-undo .tidy-icon-undo { display: block; }
body.chat-page .composer #tidyBtn.is-undo .tidy-icon-sparkles { display: none; }
body.chat-page .composer #tidyBtn:hover { background: rgba(255, 255, 255, 0.06); color: #ffffff; border-color: rgba(255, 255, 255, 0.24); }
body.chat-page .composer #tidyBtn.is-undo { border-color: rgba(129, 140, 248, 0.55); color: #c7d2fe; }
body.chat-page .composer #tidyBtn.is-busy { cursor: progress; }
body.chat-page .composer #tidyBtn.is-busy svg { animation: tidy-pulse 0.9s ease-in-out infinite; }
@keyframes tidy-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) {
  body.chat-page .composer #tidyBtn.is-busy svg { animation: none; opacity: 0.6; }
}
.composer-tidy-note {
  position: absolute; right: 16px; bottom: calc(100% + 8px);
  max-width: min(320px, 80vw);
  padding: 6px 10px; border-radius: 10px;
  font-size: 12px; line-height: 1.3;
  background: rgba(15, 23, 42, 0.96); color: #e2e8f0;
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  opacity: 0; transform: translateY(4px); pointer-events: none;
  transition: opacity 0.18s, transform 0.18s;
}
.composer-tidy-note.is-visible { opacity: 1; transform: none; }
[data-ux-mode="cozy"] body.chat-page .composer #tidyBtn { border-color: rgba(166, 130, 85, 0.30); color: #5A5540; }
[data-ux-mode="cozy"] body.chat-page .composer #tidyBtn:hover { background: rgba(198, 107, 107, 0.08); color: #3b3328; }
[data-ux-mode="cozy"] body.chat-page .composer #tidyBtn.is-undo { border-color: rgba(198, 107, 107, 0.55); color: #8a4a3a; }
/* !important on purpose: cozy-theme.css paints every [role="status"]:not(#verifyNudge)
   as a gold→rose toast with cream text — and its :not(#id) carries ID specificity, so
   an !important of equal weight still lost to it (theme loads later). #composer +
   body.chat-page lifts this above (1,3,1 vs 1,2,0). Measured 1.1:1 before. */
[data-ux-mode="cozy"] body.chat-page #composer .composer-tidy-note {
  background: var(--cozy-paper-elevated, #fbf6ee) !important; color: var(--cozy-ink, #1A2438) !important;
  border-color: rgba(166, 130, 85, 0.35) !important; box-shadow: 0 6px 20px rgba(90, 60, 30, 0.14) !important;
  padding: 6px 10px !important; border-radius: 10px !important; font-size: 12px !important;
}

/* Phones in cozy: the theme's 24px composer padding + 16px gaps + 64px mic left the
   textarea 66px wide once Tidy arrived (measured 2026-08-29, 390px viewport). Reclaim
   ~76px: tighter shell, 44px mic (still the tap floor), lighter textarea padding.
   #composer in the selector = ID specificity so this beats the theme's !important
   rules of equal weight that load AFTER this sheet. */
@media (max-width: 480px) {
  [data-ux-mode="cozy"] body.chat-page #composer.composer { padding: 10px 12px !important; gap: 8px !important; }
  [data-ux-mode="cozy"] body.chat-page #composer .voice-input-btn,
  [data-ux-mode="cozy"] body.chat-page #composer .voice-input-btn-minimal {
    width: 44px !important; height: 44px !important; min-width: 44px !important; min-height: 44px !important;
    margin: 0 !important; flex: 0 0 auto !important;
  }
  [data-ux-mode="cozy"] body.chat-page #composer .voice-input-btn svg { width: 20px !important; height: 20px !important; }
  [data-ux-mode="cozy"] body.chat-page #composer textarea { padding-left: 12px !important; padding-right: 12px !important; }
}
