/* =========================================================
   ai-chat-interactions.css  (FINAL)
   - Footer controls OUTSIDE bubble (ChatGPT-like)
   - Copy/Edit + Variant switcher (clean)
   - Inline edit UI
   - Toast
   ========================================================= */


/* =========================
   1) Kill tap highlight / focus
   ========================= */
*{
  -webkit-tap-highlight-color: transparent;
}

/* box-shadow is deliberately not reset here: browsers draw none on these controls, so a reset only cancels the rings
   and halos written for them on purpose (owner 2026-09-15). */
.chat-input,
.chat-button,
button,
input,
textarea{
  outline: none !important;
  -webkit-appearance: none;
  appearance: none;
}

.chat-input:focus,
.chat-input:active,
.chat-button:focus,
.chat-button:active,
button:focus,
button:active,
input:focus,
input:active,
textarea:focus,
textarea:active{
  outline: none !important;
}

.chat-input::before,
.chat-input::after,
.chat-button::before,
.chat-button::after,
button::before,
button::after{
  content: none !important;
  display: none !important;
}

.chat-button{
  background-image: none !important;
}


/* =========================
   2) Layout: bubble on top, footer on new line
   (IMPORTANT: prevents bubble being full-width)
   ========================= */

/* ✅ 每条消息改为 column：bubble 上、footer 下 */
.chat-messages .msg{
  display: flex;
  flex-direction: column;
  gap: 6px;                 /* bubble 与 footer 间距 */
  align-items: flex-start;  /* assistant 默认左贴 */
}

/* ✅ 用户消息右贴 */
.chat-messages .msg.user{
  align-items: flex-end;
}

/* ✅ bubble 不要被撑满（按内容收缩） */
.chat-messages .msg > .bubble{
  width: fit-content;
  max-width: 78%;           /* 你原本的最大宽 */
  display: inline-block;
}

/* ✅ footer 永远另起一行，并贴着气泡边缘 */
.chat-messages .msg > .msg-footer{
  display: inline-flex;     /* 不占满整行 */
  align-items: center;
  gap: 10px;

  /* 关键：让 footer 跟随 msg 的 align-items */
  align-self: inherit;

  /* 视觉：像“元信息行” */
  opacity: .9;
}

/* footer 内部：左边 actions，右边 variant（互不遮挡） */
.chat-messages .msg > .msg-footer{
  justify-content: flex-end;
}

/* 如果你希望 assistant 的 footer 也靠右（更像 ChatGPT），保留；否则删掉 */
.chat-messages .msg.assistant > .msg-footer{
  justify-content: flex-end;
}

/* ✅ 预留【用户消息】footer 高度（2026-07-18）：footer 落定才挂载会撑高用户行、把下面的
   AI 回复顶下去。这里给用户行提前留出 footer 高度、footer 改绝对定位落进预留带 →
   落定挂载时零高度变化、回复不被顶。仅用户行需要（回复的 footer 在末尾、下面无内容可顶）。
   显隐/hover/透明度行为不受影响（仍由上面的规则控制）。 */
.chat-messages .msg.user{
  position: relative;
  padding-bottom: calc(var(--footer-btn-box) + 6px);  /* 按钮盒 + 气泡↔footer 间距 6（补回 .msg 的 gap:6px，绝对定位后 gap 失效）*/
}
/* ★ 修根因(2026-07-20)：图+文字消息拆成两行(图行 + .msg-grouped 文字行)，footer 只挂末行(文字行)。
   上面无差别给每个 .msg.user 预留 46px，图行也吃了→在图↔文字间撑出间隙。图行(后紧跟 .msg-grouped
   attachment rows carry no footer, so no reserve; this :has() rule zeroes it precisely. */
.chat-messages .msg.user:has(+ .msg.user.msg-grouped){
  padding-bottom: 0;
}
.chat-messages .msg.user > .msg-footer{
  position: absolute;
  right: 0;
  bottom: 0;                    /* footer(高=按钮盒)落在预留带底部 → 距气泡底恒 6px,与原 gap 一致 */
}

/* ✅ 根治 F5 footer reflow（2026-07-18）：assistant footer 改【绝对定位】→ 脱离布局流、对行高零贡献 →
   footer 被 rebindFromModel 造/清空/重填任何状态,行高恒 = 固定 padding → 零 reflow。
   ★关键位置:assistant 消息【左对齐】(ai-chat-base.css `.msg{align-items:flex-start}`,footer 是 inline-flex+
   align-self:inherit 也跟着左),所以用 left:0——之前误用 right:0 把图标甩到整行右下角=位置回归,已纠正。
   user footer sits right:0 (user rows are right-aligned); reserve = --footer-btn-box + 6px gap.
   Search-source thumb footers can overflow the reserve (hover-only, rare) - revisit if it bites. */
.chat-messages .msg.assistant{
  position: relative;
  padding-bottom: calc(var(--footer-btn-box) + 6px);
}
.chat-messages .msg.assistant > .msg-footer{
  position: absolute;
  left: 0;
  bottom: 0;
}


/* =========================
   3) Footer show/hide (clean)
   - desktop hover show
   - mobile always show
   ========================= */

/* 默认隐藏（桌面更干净） */
.chat-messages .msg > .msg-footer{
  opacity: 0;
  pointer-events: none;
  transform: translateY(-1px);
  transition: opacity .12s ease, transform .12s ease;
}

/* Streaming 期间完全隐藏 footer（含搜索来源缩略图），生成结束后才显示 */
.chat-messages .msg.ai-thinking > .msg-footer{
  display: none;
}
/* ✅ Fallback: 确保所有设备都能点击按钮（防止媒体查询遗漏） */
html:not([data-input="touch"]) .chat-messages .msg > .msg-footer:hover,
html:not([data-input="touch"]) .chat-messages .msg > .msg-footer:focus-within{
  opacity: .9;
  pointer-events: auto;
  transform: translateY(0);
}

@media (hover: hover) and (pointer: fine){
  html:not([data-input="touch"]) .chat-messages .msg:hover > .msg-footer{
    opacity: .9;
    pointer-events: auto;
    transform: translateY(0);
  }
}

/* 移动端无 hover：一直显示 */
@media (hover: none) and (pointer: coarse){
  .chat-messages .msg > .msg-footer{
    opacity: .9;
    pointer-events: auto;
    transform: none;
  }
}

/* ★设备矩阵补洞(2026-08-06 footdiag 实测):hover∧coarse(触屏主指针笔记本)与 hover:none∧fine
   落在"桌面 hover∧fine 揭示"与"移动 ¬hover∧coarse 常驻"两条之间,哪条都不激活 → 图标永不出现。
   凡不满足 hover∧fine 的设备一律常驻(与移动端同语义;真桌面不受影响)。 */
@media (hover: hover) and (pointer: coarse), (hover: none) and (pointer: fine){
  .chat-messages .msg > .msg-footer{
    opacity: .9;
    pointer-events: auto;
    transform: none;
  }
}
/* 同一补洞的精确补集写法(Media Queries 4 not):枚举法漏掉的组合(pointer:none 等)也收进来。
   两条并存:老浏览器认枚举条,新浏览器两条都认,语义一致。 */
@media not ((hover: hover) and (pointer: fine)){
  .chat-messages .msg > .msg-footer{
    opacity: .9;
    pointer-events: auto;
    transform: none;
  }
}

/* ✅ 兜底：任何设备上点击/触摸消息时都显示按钮 */
.chat-messages .msg:focus-within > .msg-footer,
.chat-messages .msg:active > .msg-footer{
  opacity: .9;
  pointer-events: auto;
  transform: translateY(0);
}


/* =========================
   4) Actions (Copy/Edit) - OUTSIDE bubble
   ========================= */

.msg-actions{
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: -7px; /* align icons with text (compensate button padding) */
}

/* Box size = --footer-btn-box, shared with .variant-chevron (owner 2026-08-08: one footer standard) */
.msg-iconbtn{
  min-width: var(--footer-btn-box);
  min-height: var(--footer-btn-box);
  padding: 7px;             /* centers the 18px icon in the 32px box */
  border-radius: var(--radius-icon-btn);

  border: none;
  background: transparent;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  cursor: pointer;
  user-select: none;
  opacity: .55;
}
/* 反馈类 hover 不设媒体门(owner 机型连 any-pointer 都报假而物理悬停真实——媒体位不可信;
   :hover 本身只在真悬停时触发,触屏轻点瞬时套用=无害按压反馈)。:active 孪生=§5.3 规则2。 */
html:not([data-input="touch"]) .msg-iconbtn:hover,
html:not([data-input="touch"]) .msg-iconbtn:active{
  opacity: 1;
  background: var(--color-bg-hover);
}

.msg-iconbtn svg{
  width: var(--icon-size);              /* ✅ SVG 图标放大 (15px → 18px) */
  height: var(--icon-size);             /* ✅ SVG 图标放大 (15px → 18px) */
  display: block;
}

/* ✅ 移动端：更小的图标 */
@media (max-width: 768px), (max-height: 500px) {
  .msg-iconbtn svg{
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
  }
}


/* =========================
   5) Variant switcher ( < 2/2 > )
   ========================= */

.msg-variant{
  display: inline-flex;
  align-items: center;
}

/* ✅ footer 内部间距：actions 和 variant 分开一点 */
.chat-messages .msg > .msg-footer .msg-variant{
  margin-left: 6px;
}

.msg-variant-nav{
  display: inline-flex;
  align-items: center;
  gap: 6px;

  font-size: 14px;
  color: rgba(0,0,0,.55);
}

/* ✅ Chevron variant buttons — same box source as .msg-iconbtn */
.msg-variant-nav button.variant-chevron{
  min-width: var(--footer-btn-box);
  min-height: var(--footer-btn-box);
  padding: 4px;
  border-radius: calc(6px * var(--corner-k));

  border: none;
  background: transparent;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  cursor: pointer;
  color: rgba(0,0,0,.5);
  transition: opacity .15s ease, background .15s ease;
}

.msg-variant-nav button.variant-chevron .chevron-icon{
  display: block;
  width: var(--icon-size);
  height: var(--icon-size);
}
/* Feedback hover stays ungated (media bits lie on the owner's machine, see .msg-iconbtn
   note above); :active twin per §5.3 rule 2; :not(:disabled) keeps dead arrows inert. */
html:not([data-input="touch"]) .msg-variant-nav button.variant-chevron:not(:disabled):hover,
html:not([data-input="touch"]) .msg-variant-nav button.variant-chevron:not(:disabled):active{
  color: rgba(0,0,0,.8);
  background: var(--color-bg-hover);
}

.msg-variant-nav button.variant-chevron:disabled{
  opacity: .25;
  cursor: default;
  background: transparent;
}

/* ✅ 2/2 label 稍微大一点 */
.msg-variant-label,
.msg-variant-nav span{
  min-width: 34px;
  text-align: center;
  opacity: .75;
  font-size: 14px;
}

/* ✅ 移动端：更小的标签 */
@media (max-width: 768px), (max-height: 500px) {
  .msg-variant-label,
  .msg-variant-nav span{
    min-width: 28px;
    font-size: 11px;
  }
}


/* =========================
   6) Inline edit UI (inside bubble)
   ========================= */

/* 编辑时隐藏 footer（避免干扰） */
.chat-messages .msg .bubble[data-editing="1"] ~ .msg-footer{
  opacity: 0 !important;
  pointer-events: none !important;
}

/* ✅ 编辑时：整个消息行和气泡全宽 */
.chat-messages .msg.user:has(.bubble[data-editing="1"]){
  align-items: stretch !important;
  width: 100%;
}

.chat-messages .msg.user > .bubble[data-editing="1"]{
  width: 100% !important;
  max-width: 100% !important;
  background: var(--color-bg-surface);
  border-radius: calc(16px * var(--corner-k));
  padding: 12px;
}

/* 原地编辑 textarea - 统一灰色背景，无白色内框 */
.bubble-editbox{
  width: 100%;
  box-sizing: border-box;

  border: none;
  border-radius: 0;

  padding: 0;
  font-size: 14px;
  line-height: 1.6;

  outline: none;
  resize: none;
  background: transparent;

  min-height: 60px;
}
/* The placeholder follows the app's own text token, which flips with .dark-mode-active. Without this it fell to the
   store theme's global rule (65% of the STORE text colour = black), invisible on the dark bubble once the text was
   deleted (owner 2026-09-06, phone, dark mode). */
.bubble-editbox::placeholder { color: var(--color-text-secondary); opacity: 1; }

/* 编辑态按钮条 */
.bubble-editbar{
  margin-top: 12px;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.bubble-btn{
  padding: 8px 16px;
  border-radius: 20px;
  corner-shape: round;
  border: none;
  background: rgba(0,0,0,.08);
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: background .15s ease;
}
html:not([data-input="touch"]) .bubble-btn:hover{
  background: rgba(0,0,0,.12);
}

.bubble-btn.primary{
  background: #111;
  color: #fff;
}
html:not([data-input="touch"]) .bubble-btn.primary:hover{
  background: #333;
}


/* =========================
   7) Toast
   ========================= */

.ai-toast{
  position: fixed;
  left: 50%;
  bottom: 84px;
  transform: translateX(-50%);

  background: #111;
  color: #fff;

  padding: 8px 10px;
  border-radius: calc(12px * var(--corner-k));
  font-size: 13px;

  opacity: 0;
  pointer-events: none;
  transition: opacity .15s ease;

  z-index: 9999999;
}

.ai-toast.show{
  opacity: 1;
}


/* =========================
   8) Mobile Long Press Context Menu
   ========================= */

/* ✅ 禁用图片的文字选择，但保留文字内容的选择 */
@media (hover: none) and (pointer: coarse) {
  .chat-messages .bubble img {
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none; /* 禁用 iOS 长按弹出默认菜单 */
  }
}

.msg-context-menu{
  position: fixed;
  background: var(--color-bg-panel);
  border-radius: calc(12px * var(--corner-k));
  box-shadow: 0 4px 20px var(--color-shadow), 0 0 1px rgba(0,0,0,.1);
  padding: 4px;
  z-index: 999999;

  /* 初始状态：缩小+透明+不可点击 */
  opacity: 0;
  transform: scale(0.92);
  transition: opacity .15s ease, transform .15s ease;
  pointer-events: none;  /* ✅ 修复：透明时不阻止点击 */
}

.msg-context-menu.visible{
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;  /* ✅ 可见时才允许交互 */
}

.msg-context-menu-item{
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-radius: calc(8px * var(--corner-k));
  cursor: pointer;
  user-select: none;
  white-space: nowrap;

  /* 过渡效果 */
  transition: background .12s ease;
}

.msg-context-menu-item:active{
  background: var(--color-bg-card);
}

.msg-context-menu-icon{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-size);
  height: var(--icon-size);
  opacity: .7;
  flex-shrink: 0; /* 防止图标被压缩 */
}

.msg-context-menu-icon svg{
  width: var(--icon-size);
  height: var(--icon-size);
  display: block;
}

.msg-context-menu-label{
  font-size: 14px;               /* 菜单项全站基准 14px(字号阶梯,原 15px 孤值) */
  color: var(--color-text);      /* 原 #111 硬编码 → 颜色单一源 */
  font-weight: 400;
}

/* ✅ 移动端优化：稍小的菜单 */
@media (max-width: 768px), (max-height: 500px) {
  .msg-context-menu-item{
    padding: 9px 12px;
    gap: 8px;
  }

  .msg-context-menu-icon{
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
  }

  .msg-context-menu-icon svg{
    width: var(--icon-size-sm);
    height: var(--icon-size-sm);
  }

  .msg-context-menu-label{
    font-size: 14px;
  }
}


/* =========================
   9) Dark Mode
   ========================= */

/* Icon buttons (copy, edit, etc.) */
.dark-mode .msg-iconbtn{
  color: rgba(255,255,255,.55);
}
.dark-mode .msg-iconbtn svg{
  color: rgba(255,255,255,.55);
}
/* 背景不再单写:--color-bg-hover 本就双主题(暗=0.06,顺带归并这里曾漂移的 0.08);只补 svg 颜色 */
html:not([data-input="touch"]) .dark-mode .msg-iconbtn:hover,
html:not([data-input="touch"]) .dark-mode .msg-iconbtn:active{
  opacity: 1;
}
html:not([data-input="touch"]) .dark-mode .msg-iconbtn:hover svg,
html:not([data-input="touch"]) .dark-mode .msg-iconbtn:active svg{
  color: rgba(255,255,255,.85);
}

/* Variant switcher ( < 2/2 > ) */
.dark-mode .msg-variant-nav{
  color: rgba(255,255,255,.55);
}
.dark-mode .msg-variant-nav button.variant-chevron{
  color: rgba(255,255,255,.5);
}
html:not([data-input="touch"]) .dark-mode .msg-variant-nav button.variant-chevron:not(:disabled):hover,
html:not([data-input="touch"]) .dark-mode .msg-variant-nav button.variant-chevron:not(:disabled):active{
  color: rgba(255,255,255,.8);
  background: var(--color-bg-hover);
}

/* Inline edit UI */
.dark-mode .chat-messages .msg.user > .bubble[data-editing="1"]{
  background: #2a2a2a;
}
.dark-mode .bubble-editbox{
  color: rgba(255,255,255,.9);
}
.dark-mode .bubble-btn{
  background: rgba(255,255,255,.1);
  color: rgba(255,255,255,.8);
}
html:not([data-input="touch"]) .dark-mode .bubble-btn:hover{
  background: rgba(255,255,255,.15);
}
.dark-mode .bubble-btn.primary{
  background: #e0e0e0;
  color: #111;
}
html:not([data-input="touch"]) .dark-mode .bubble-btn.primary:hover{
  background: #fff;
}

/* Context menu (long press on mobile) */
.dark-mode .msg-context-menu{
  box-shadow: 0 4px 20px rgba(0,0,0,.4), 0 0 1px rgba(0,0,0,.3);
}
.dark-mode .msg-context-menu-icon{
  color: rgba(255,255,255,.7);
}
.dark-mode .msg-context-menu-icon svg{
  color: rgba(255,255,255,.7);
}
.dark-mode .msg-context-menu-label{
  color: rgba(255,255,255,.9);
}

/* Photoswipe lightbox close button — fix centering */
.pswp__button {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Read-aloud footer button (owner 2026-09-06): lit while it speaks, dimmed while the audio is on its way */
.msg-speak.is-playing { color: var(--color-text); }
/* Working, not disabled: dimming the button was read as "nothing happened" (owner 2026-09-06). It stays lit and
   tappable - a second tap stops - while the player bar carries the state. */
.msg-speak.is-busy { color: var(--color-text); }

/* Read-aloud player (owner 2026-09-06): up on the tap itself, under the chat header, following the sidebar like it does.
   Buttons are the header's one 36px box (.chat-header-btn); the face is the panel's. */
.voice-bar {
  position: fixed;
  top: 73px;
  left: calc(var(--sidebar-width, 240px) + 16px);
  right: 16px;
  z-index: 99;
  display: none;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 999px;
  corner-shape: round;
  background: var(--color-bg-panel);
  box-shadow: var(--menu-shadow);
  transition: left 0.3s cubic-bezier(0.2, 0, 0, 1);
}
.chat-sidebar.collapsed ~ .chat-main .voice-bar { left: calc(var(--sidebar-width-collapsed, 60px) + 16px); }
.voice-bar.is-open { display: flex; }
.voice-bar-time { flex: 1 1 auto; font-size: 14px; font-variant-numeric: tabular-nums; color: var(--color-text); }
/* play / pause at the head of the bar: the 3D control's triangle and the pause drawn to pair with it */
.voice-bar-play { flex-shrink: 0; }
/* the head control is the one you reach for, and its glyph carries less ink than the arcs at the same size,
   so it is drawn larger (owner 2026-09-06) - still inside the 36px box it shares with the rest */
.voice-bar-play svg { width: 30px; height: 30px; }
/* Preparing: the line itself shows the work, a light travelling across the word (owner 2026-09-06) */
.voice-bar.is-loading .voice-bar-time {
  color: var(--color-text-secondary);
  background: linear-gradient(100deg, var(--color-text-secondary) 40%, var(--color-text) 50%, var(--color-text-secondary) 60%);
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: voiceShimmer 5s linear infinite;
}
@keyframes voiceShimmer { from { background-position: 150% 0; } to { background-position: -150% 0; } }
.voice-bar-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.voice-bar-speed { font-size: 14px; font-family: inherit; color: var(--color-text); width: auto; padding: 0 10px; }
/* the two skip buttons are one glyph with its number inside, the second mirrored. The three glyphs are sized to read as
   one size (owner 2026-09-06): the arcs a touch larger, the number inside them small, the cross smaller than both. */
.voice-bar-btn { position: relative; }
.voice-bar-btn svg { width: var(--icon-size); height: var(--icon-size); }
.voice-bar-fwd svg { transform: scaleX(-1); }
.voice-bar-15 { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 7px; letter-spacing: 0; }
.voice-bar-close svg { width: var(--icon-size-sm); height: var(--icon-size-sm); }
@media (max-width: 768px), (max-height: 500px) {
  .voice-bar { left: 12px; right: 12px; top: calc(60px + 13px); }
}

