<template>
  <a-drawer
    :visible="visible"
    :width="drawerWidth"
    :placement="isMobile ? 'bottom' : 'right'"
    :height="isMobile ? '100vh' : undefined"
    :footer="false"
    class="ai-chat-drawer"
    unmount-on-close
    @cancel="close"
  >
    <template #title>
      <div class="ai-chat-title">
        <a-avatar :size="36" class="ai-chat-title__avatar">
          <img src="@/assets/img/ai.png" alt="小妍助理" />
        </a-avatar>
        <div class="ai-chat-title__copy">
          <div class="ai-chat-title__name">小妍助理</div>
          <div class="ai-chat-title__sub">
            <span class="status-dot"></span>
            在线
          </div>
        </div>
      </div>
    </template>

    <div class="ai-chat-shell" @paste="handlePaste">
      <aside class="conversation-panel" :class="{ 'conversation-panel--open': showConversationPanel }">
        <div class="conversation-panel__head">
          <div>
            <div class="conversation-panel__label">会话</div>
            <div class="conversation-panel__count">{{ conversations.length }} 条</div>
          </div>
          <a-tooltip content="新建对话">
            <a-button type="primary" shape="circle" @click="createConversationAndOpen">
              <template #icon><icon-plus /></template>
            </a-button>
          </a-tooltip>
        </div>

        <div class="conversation-list">
          <button
            v-for="item in conversations"
            :key="item.id"
            class="conversation-item"
            :class="{ 'conversation-item--active': item.id === currentConversationId }"
            @click="openConversation(item.id)"
          >
            <span class="conversation-item__top">
              <span class="conversation-item__title">{{ item.title || '小妍助理对话' }}</span>
              <span v-if="unreadMap[item.id]" class="conversation-item__dot"></span>
            </span>
            <span class="conversation-item__preview">{{ item.last_message_preview || '尚未开始' }}</span>
            <span class="conversation-item__foot">
              <span>{{ formatShortTime(item.update_time) || '新对话' }}</span>
              <span v-if="item.conversation_no">NO.{{ item.conversation_no }}</span>
            </span>
          </button>

          <div v-if="!conversations.length" class="conversation-empty">
            <a-avatar :size="42" class="conversation-empty__avatar">
              <img src="@/assets/img/ai.png" alt="小妍助理" />
            </a-avatar>
            <div>暂无会话</div>
          </div>
        </div>
      </aside>

      <main
        class="chat-main"
        :class="{ 'chat-main--dragging': dragging }"
        @dragenter.prevent="dragging = true"
        @dragover.prevent="dragging = true"
        @dragleave.prevent="dragging = false"
        @drop.prevent="handleDrop"
      >
        <div class="chat-toolbar">
          <a-button v-if="isMobile" type="text" shape="circle" @click="showConversationPanel = !showConversationPanel">
            <template #icon><icon-menu /></template>
          </a-button>

          <div class="chat-toolbar__identity">
            <a-avatar :size="34" class="chat-toolbar__avatar">
              <img src="@/assets/img/ai.png" alt="小妍助理" />
            </a-avatar>
            <div class="chat-toolbar__text">
              <strong>{{ currentConversation?.title || '新对话' }}</strong>
              <span>{{ currentConversation?.conversation_no ? `NO.${currentConversation.conversation_no}` : '准备开始' }}</span>
            </div>
          </div>

          <a-popconfirm content="是否删除该对话？" @ok="deleteCurrentConversation">
            <a-button :disabled="!currentConversationId" type="text" shape="circle" status="danger">
              <template #icon><icon-delete /></template>
            </a-button>
          </a-popconfirm>
        </div>

        <div ref="messageContainer" class="message-list">
          <div v-if="!currentConversationId" class="empty-state">
            <a-avatar :size="64" class="empty-state__avatar">
              <img src="@/assets/img/ai.png" alt="小妍助理" />
            </a-avatar>
            <div class="empty-state__title">开启一段新对话</div>
          </div>

          <template v-else>
            <div v-if="messagesLoading" class="message-loading">
              <a-spin />
            </div>

            <div v-if="!messagesLoading && !messages.length" class="welcome-card">
              <a-avatar :size="52" class="welcome-card__avatar">
                <img src="@/assets/img/ai.png" alt="小妍助理" />
              </a-avatar>
              <div>
                <div class="welcome-card__title">我是小妍助理</div>
                <div class="welcome-card__text">可以开始输入问题。</div>
              </div>
            </div>

            <div
              v-for="message in messages"
              :key="message.id"
              class="message-row"
              :class="`message-row--${message.role}`"
            >
              <a-avatar :size="36" class="message-avatar">
                <img v-if="message.role === 'assistant'" src="@/assets/img/ai.png" alt="小妍助理" />
                <icon-user v-else-if="message.role === 'user'" />
                <icon-info-circle v-else />
              </a-avatar>

              <div class="message-stack">
                <div class="message-meta">
                  <span>{{ roleLabel(message.role) }}</span>
                  <span>{{ formatFullTime(message.create_time) }}</span>
                  <a-tag v-if="message.status === 'error'" size="small" color="red">异常</a-tag>
                </div>

                <div class="message-bubble">
                  <div v-if="message.content" class="message-content" v-html="renderMarkdown(message.content)"></div>
                  <div v-if="message.images?.length" class="message-images">
                    <a-image
                      v-for="url in message.images"
                      :key="url"
                      :src="url"
                      width="118"
                      height="118"
                      fit="cover"
                    />
                  </div>
                  <div v-if="message.error_msg" class="message-error">{{ message.error_msg }}</div>
                </div>
              </div>
            </div>
          </template>
        </div>

        <div v-if="uploadingImages.length" class="image-preview-bar">
          <div v-for="item in uploadingImages" :key="item.id" class="image-preview">
            <a-image :src="item.url" width="62" height="62" fit="cover" />
            <a-button size="mini" shape="circle" @click="removeImage(item.id)">
              <template #icon><icon-close /></template>
            </a-button>
          </div>
        </div>

        <div class="composer-wrap">
          <div class="composer">
            <input ref="fileInput" type="file" accept="image/png,image/jpeg,image/jpg,image/gif" multiple hidden @change="handleFileInput" />
            <a-tooltip content="添加图片">
              <a-button :loading="uploading" shape="circle" class="composer__tool" @click="fileInput?.click()">
                <template #icon><icon-image /></template>
              </a-button>
            </a-tooltip>
            <a-textarea
              v-model="input"
              placeholder="输入消息"
              :max-length="1000"
              :auto-size="{ minRows: 1, maxRows: 5 }"
              allow-clear
              @keydown.enter.exact.prevent="sendMessage"
            />
            <a-button type="primary" shape="circle" :loading="sending" :disabled="!canSend" class="composer__send" @click="sendMessage">
              <template #icon><icon-send /></template>
            </a-button>
          </div>
        </div>
      </main>
    </div>
  </a-drawer>
</template>

<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { Message, Notification } from '@arco-design/web-vue'
import MarkdownIt from 'markdown-it'
import storage from 'store'
import { useUserStore } from '@/store/modules/user'
import { uploadImg } from '@/api/upload'
import {
  createAIChatConversation,
  deleteAIChatConversation,
  listAIChatConversations,
  listAIChatMessages,
  sendAIChatMessage
} from '@/api/aiChat'

const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(['close', 'unread-change'])

const md = new MarkdownIt({ html: false, linkify: true, breaks: true })
const userStore = useUserStore()
const isMobile = ref(window.innerWidth <= 768)
const showConversationPanel = ref(false)
const conversations = ref([])
const messages = ref([])
const currentConversationId = ref(null)
const input = ref('')
const uploadingImages = ref([])
const messagesLoading = ref(false)
const sending = ref(false)
const uploading = ref(false)
const dragging = ref(false)
const messageContainer = ref(null)
const fileInput = ref(null)
const unreadMap = ref({})
let conversationTimer = null
let messageTimer = null

const visible = computed(() => props.visible)
const drawerWidth = computed(() => (isMobile.value ? '100%' : '940px'))
const currentConversation = computed(() => conversations.value.find(item => item.id === currentConversationId.value))
const canSend = computed(() => currentConversationId.value && (input.value.trim() || uploadingImages.value.length > 0))
const unreadTotal = computed(() => Object.values(unreadMap.value).reduce((sum, value) => sum + Number(value || 0), 0))
const seenKey = computed(() => `aiChatSeen:${userStore.uuid || 'guest'}`)

const roleLabel = (role) => ({ user: '我', assistant: '小妍助理', system: '系统' }[role] || role)
const renderMarkdown = (text) => md.render(text || '')
const formatFullTime = (time) => time ? new Date(Number(time)).toLocaleString('zh-CN', { hour12: false }) : ''
const formatShortTime = (time) => {
  if (!time) return ''
  return new Date(Number(time)).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false })
}

const loadSeen = () => storage.get(seenKey.value) || {}
const saveSeen = (seen) => storage.set(seenKey.value, seen)

const updateUnreadByConversations = (list) => {
  const oldTotal = unreadTotal.value
  const seen = loadSeen()
  const next = {}
  list.forEach((item) => {
    if (item.id === currentConversationId.value && visible.value) return
    if (Number(item.last_message_time || 0) > Number(seen[item.id] || 0)) next[item.id] = 1
  })
  unreadMap.value = next
  emit('unread-change', unreadTotal.value)
  if (!visible.value && unreadTotal.value > oldTotal) {
    Notification.info({ title: '小妍助理有新消息', content: '点击右下角助手查看回复' })
  }
}

const markCurrentSeen = () => {
  if (!currentConversationId.value) return
  const seen = loadSeen()
  const last = messages.value[messages.value.length - 1]
  const conv = currentConversation.value
  seen[currentConversationId.value] = Math.max(Number(last?.create_time || 0), Number(conv?.last_message_time || 0), Date.now())
  saveSeen(seen)
  delete unreadMap.value[currentConversationId.value]
  unreadMap.value = { ...unreadMap.value }
  emit('unread-change', unreadTotal.value)
}

const scrollToBottom = () => {
  nextTick(() => {
    if (messageContainer.value) messageContainer.value.scrollTop = messageContainer.value.scrollHeight
  })
}

const loadConversations = async () => {
  const res = await listAIChatConversations({ current: 1, pagesize: 30 })
  if (!res || res.code !== 0) return
  conversations.value = res.data || []
  updateUnreadByConversations(conversations.value)
  if (visible.value && !currentConversationId.value && conversations.value.length) {
    await openConversation(conversations.value[0].id)
  }
}

const loadMessages = async () => {
  if (!currentConversationId.value) return
  messagesLoading.value = true
  try {
    const res = await listAIChatMessages({ conversation_id: currentConversationId.value, current: 1, pagesize: 80 })
    if (!res || res.code !== 0) return Message.error(res?.msg || '获取消息失败')
    messages.value = res.data || []
    markCurrentSeen()
    scrollToBottom()
  } finally {
    messagesLoading.value = false
  }
}

const pollNewMessages = async () => {
  if (!currentConversationId.value || !visible.value) return
  const lastId = messages.value[messages.value.length - 1]?.id || 0
  const res = await listAIChatMessages({ conversation_id: currentConversationId.value, after_id: lastId })
  if (!res || res.code !== 0) return
  const incoming = res.data || []
  if (!incoming.length) return
  messages.value.push(...incoming)
  const hasAssistant = incoming.some(item => item.role === 'assistant' || item.role === 'system')
  if (hasAssistant) Notification.info({ title: '小妍助理有新回复', content: incoming[incoming.length - 1]?.content || '收到新消息' })
  markCurrentSeen()
  scrollToBottom()
  await loadConversations()
}

const openConversation = async (id) => {
  currentConversationId.value = id
  showConversationPanel.value = false
  await loadMessages()
}

const createConversationAndOpen = async () => {
  const blank = conversations.value.find(item => Number(item.last_message_time || 0) === 0)
  if (blank) {
    await openConversation(blank.id)
    return
  }

  const res = await createAIChatConversation({ title: '小妍助理对话' })
  if (!res || res.code !== 0) return Message.error(res?.msg || '创建会话失败')
  currentConversationId.value = res.data.id
  messages.value = []
  await loadConversations()
  scrollToBottom()
}

const deleteCurrentConversation = async () => {
  if (!currentConversationId.value) return
  const res = await deleteAIChatConversation({ id: currentConversationId.value })
  if (!res || res.code !== 0) return Message.error(res?.msg || '删除失败')
  currentConversationId.value = null
  messages.value = []
  await loadConversations()
}

const uploadFiles = async (files) => {
  const imageFiles = Array.from(files || []).filter(file => file.type?.startsWith('image/')).slice(0, 6 - uploadingImages.value.length)
  if (!imageFiles.length) return
  uploading.value = true
  try {
    for (const file of imageFiles) {
      const formData = new FormData()
      formData.append('uuid', userStore.uuid)
      formData.append('session', userStore.session)
      formData.append('upload', file)
      const res = await uploadImg(formData)
      if (!res || res.code !== 0) {
        Message.error(res?.msg || '图片上传失败')
        continue
      }
      const url = res.data?.picturePath
      if (url) uploadingImages.value.push({ id: `${Date.now()}-${Math.random()}`, url })
    }
  } finally {
    uploading.value = false
    if (fileInput.value) fileInput.value.value = ''
  }
}

const handleFileInput = (event) => uploadFiles(event.target.files)
const handlePaste = (event) => {
  const files = Array.from(event.clipboardData?.files || [])
  if (files.length) uploadFiles(files)
}
const handleDrop = (event) => {
  dragging.value = false
  uploadFiles(event.dataTransfer?.files)
}
const removeImage = (id) => {
  uploadingImages.value = uploadingImages.value.filter(item => item.id !== id)
}

const sendMessage = async () => {
  if (!canSend.value || sending.value) return
  const content = input.value.trim()
  const images = uploadingImages.value.map(item => item.url)
  input.value = ''
  uploadingImages.value = []
  sending.value = true
  try {
    const res = await sendAIChatMessage({ conversation_id: currentConversationId.value, content, images })
    if (!res || res.code !== 0) {
      Message.error(res?.msg || '发送失败')
      input.value = content
      uploadingImages.value = images.map(url => ({ id: `${Date.now()}-${Math.random()}`, url }))
      return
    }
    await loadMessages()
    await loadConversations()
  } finally {
    sending.value = false
  }
}

const close = () => emit('close')
const syncMobile = () => { isMobile.value = window.innerWidth <= 768 }

const startPolling = () => {
  if (!conversationTimer) conversationTimer = setInterval(loadConversations, 8000)
  if (!messageTimer) messageTimer = setInterval(pollNewMessages, 3000)
}
const stopPolling = () => {
  clearInterval(conversationTimer)
  clearInterval(messageTimer)
  conversationTimer = null
  messageTimer = null
}

watch(() => props.visible, async (value) => {
  if (value) {
    await loadConversations()
    if (!currentConversationId.value) await createConversationAndOpen()
    markCurrentSeen()
    scrollToBottom()
  }
})

watch(unreadTotal, value => emit('unread-change', value))

onMounted(async () => {
  await userStore.getInfo()
  window.addEventListener('resize', syncMobile)
  await loadConversations()
  startPolling()
})

onUnmounted(() => {
  window.removeEventListener('resize', syncMobile)
  stopPolling()
})
</script>

<style lang="less" scoped>
.ai-chat-title {
  display: flex;
  align-items: center;
  gap: 12px;

  &__avatar {
    background: linear-gradient(135deg, #eaf2ff, #f7ecff);
    box-shadow: 0 8px 20px rgba(48, 91, 189, 0.16);
  }

  &__copy {
    display: grid;
    gap: 3px;
  }

  &__name {
    color: #1d2129;
    font-size: 16px;
    font-weight: 700;
    line-height: 1.2;
  }

  &__sub {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: #4e5969;
    font-size: 12px;
  }
}

.status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #16b364;
  box-shadow: 0 0 0 4px rgba(22, 179, 100, 0.12);
}

.ai-chat-shell {
  display: grid;
  grid-template-columns: 270px minmax(0, 1fr);
  height: calc(100vh - 92px);
  min-height: 0;
  margin: -12px -8px -16px;
  background:
    radial-gradient(circle at 18% 6%, rgba(36, 99, 235, 0.08), transparent 30%),
    linear-gradient(135deg, #f7faff 0%, #ffffff 46%, #f8fbf8 100%);
  border-top: 1px solid rgba(29, 33, 41, 0.08);
}

.conversation-panel {
  min-width: 0;
  border-right: 1px solid rgba(29, 33, 41, 0.08);
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(18px);
}

.conversation-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 16px 12px;
}

.conversation-panel__label {
  color: #1d2129;
  font-size: 16px;
  font-weight: 720;
}

.conversation-panel__count {
  margin-top: 2px;
  color: #86909c;
  font-size: 12px;
}

.conversation-list {
  height: calc(100% - 76px);
  overflow-y: auto;
  padding: 0 12px 18px;
}

.conversation-item {
  position: relative;
  display: grid;
  width: 100%;
  gap: 7px;
  margin-bottom: 10px;
  padding: 13px 14px;
  border: 1px solid rgba(29, 33, 41, 0.07);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.58);
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.04);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease, background 0.18s ease;

  &:hover,
  &--active {
    border-color: rgba(37, 99, 235, 0.36);
    background: #ffffff;
    box-shadow: 0 12px 28px rgba(37, 99, 235, 0.12);
    transform: translateY(-1px);
  }

  &__top,
  &__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
  }

  &__title,
  &__preview {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  &__title {
    min-width: 0;
    color: #1d2129;
    font-weight: 650;
  }

  &__preview {
    color: #4e5969;
    font-size: 13px;
  }

  &__foot {
    color: #86909c;
    font-size: 11px;
  }

  &__dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #f53f3f;
    box-shadow: 0 0 0 4px rgba(245, 63, 63, 0.12);
  }
}

.conversation-empty {
  display: grid;
  place-items: center;
  gap: 10px;
  padding: 40px 12px;
  color: #86909c;
  font-size: 13px;

  &__avatar {
    background: #eef4ff;
  }
}

.chat-main {
  position: relative;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  min-width: 0;

  &--dragging::after {
    content: '释放上传图片';
    position: absolute;
    inset: 16px;
    z-index: 5;
    display: grid;
    place-items: center;
    border: 2px dashed #2563eb;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.88);
    color: #1d4ed8;
    font-size: 15px;
    font-weight: 700;
    backdrop-filter: blur(6px);
  }
}

.chat-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 68px;
  padding: 14px 18px;
  border-bottom: 1px solid rgba(29, 33, 41, 0.08);
  background: rgba(255, 255, 255, 0.62);
  backdrop-filter: blur(16px);

  &__identity {
    display: flex;
    align-items: center;
    gap: 11px;
    flex: 1;
    min-width: 0;
  }

  &__avatar {
    flex: 0 0 auto;
    background: #eef4ff;
  }

  &__text {
    display: grid;
    flex: 1;
    min-width: 0;
    gap: 3px;

    strong,
    span {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    strong {
      color: #1d2129;
      font-size: 15px;
      font-weight: 700;
    }

    span {
      color: #86909c;
      font-size: 12px;
    }
  }
}

.message-list {
  overflow-y: auto;
  padding: 22px 22px 18px;
}

.message-loading {
  display: flex;
  justify-content: center;
  padding: 18px;
}

.empty-state,
.welcome-card {
  display: grid;
  place-items: center;
  gap: 10px;
  height: 100%;
  color: #86909c;
}

.empty-state__avatar,
.welcome-card__avatar {
  background: linear-gradient(135deg, #eaf2ff, #f7ecff);
}

.empty-state__title,
.welcome-card__title {
  color: #1d2129;
  font-size: 16px;
  font-weight: 700;
}

.welcome-card {
  justify-content: center;
  align-content: center;
  height: auto;
  min-height: 220px;
  text-align: center;
}

.welcome-card__text {
  margin-top: 4px;
  color: #86909c;
  font-size: 13px;
}

.message-row {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  margin-bottom: 18px;

  &--user {
    flex-direction: row-reverse;

    .message-stack {
      align-items: flex-end;
    }

    .message-meta {
      flex-direction: row-reverse;
    }

    .message-bubble {
      color: #ffffff;
      background: linear-gradient(135deg, #2563eb, #0f766e);
      box-shadow: 0 12px 28px rgba(37, 99, 235, 0.2);
    }

    .message-content :deep(a) {
      color: #ffffff;
    }
  }

  &--system {
    .message-avatar {
      background: #fff7e8;
      color: #d46b08;
    }

    .message-bubble {
      background: #fffaf0;
      border-color: rgba(245, 158, 11, 0.22);
    }
  }
}

.message-avatar {
  flex: 0 0 36px;
  background: #eef4ff;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.08);
}

.message-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: min(78%, 640px);
  min-width: 0;
}

.message-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
  color: #86909c;
  font-size: 12px;
}

.message-bubble {
  max-width: 100%;
  padding: 12px 14px;
  border: 1px solid rgba(29, 33, 41, 0.07);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.86);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.06);
  line-height: 1.72;
  word-break: break-word;
}

.message-content {
  :deep(p) {
    margin: 0 0 7px;
  }

  :deep(p:last-child) {
    margin-bottom: 0;
  }

  :deep(ul),
  :deep(ol) {
    margin: 6px 0;
    padding-left: 20px;
  }

  :deep(code) {
    border-radius: 4px;
    padding: 2px 5px;
    background: rgba(15, 23, 42, 0.08);
    font-size: 12px;
  }
}

.message-images {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 9px;

  :deep(.arco-image-img) {
    border-radius: 8px;
  }
}

.message-error {
  margin-top: 7px;
  color: #f53f3f;
  font-size: 12px;
}

.image-preview-bar {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding: 10px 18px 0;
}

.image-preview {
  position: relative;
  flex: 0 0 auto;
  border-radius: 8px;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.1);

  :deep(.arco-image-img) {
    border-radius: 8px;
  }

  :deep(.arco-btn) {
    position: absolute;
    top: -8px;
    right: -8px;
    background: #ffffff;
  }
}

.composer-wrap {
  padding: 12px 18px 18px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.9) 32%);
}

.composer {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: end;
  gap: 10px;
  padding: 10px;
  border: 1px solid rgba(29, 33, 41, 0.08);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 16px 36px rgba(15, 23, 42, 0.1);

  :deep(.arco-textarea-wrapper) {
    border: 0;
    background: transparent;
    box-shadow: none;
  }

  :deep(textarea) {
    font-size: 14px;
    line-height: 1.65;
  }

  &__tool {
    background: #f2f3f5;
  }

  &__send {
    background: linear-gradient(135deg, #2563eb, #0f766e);
    border: 0;
  }
}

@media (max-width: 768px) {
  .ai-chat-shell {
    grid-template-columns: 1fr;
    height: calc(100vh - 64px);
    margin: -12px -8px -16px;
  }

  .conversation-panel {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 10;
    width: min(86vw, 310px);
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: 12px 0 32px rgba(15, 23, 42, 0.16);

    &--open {
      transform: translateX(0);
    }
  }

  .chat-toolbar {
    min-height: 62px;
    padding: 12px;
  }

  .message-list {
    padding: 16px 12px 12px;
  }

  .message-stack {
    max-width: calc(100% - 52px);
  }

  .message-bubble {
    padding: 11px 12px;
  }

  .image-preview-bar {
    padding: 8px 12px 0;
  }

  .composer-wrap {
    padding: 10px 12px max(12px, env(safe-area-inset-bottom));
  }

  .composer {
    gap: 8px;
    padding: 8px;
  }
}
</style>
