<script setup lang="ts">
import { onMounted } from "vue";
import meQuery from "./graphql/operations/me.graphql?raw";
import chatMessagesQuery from "./graphql/operations/chat-messages.graphql?raw";
import dashboardQuery from "./graphql/operations/dashboard.graphql?raw";
import loginMutation from "./graphql/operations/login.graphql?raw";
import logoutMutation from "./graphql/operations/logout.graphql?raw";
import sendPilotMessageMutation from "./graphql/operations/send-pilot-message.graphql?raw";
import logPilotNoteMutation from "./graphql/operations/log-pilot-note.graphql?raw";
import createCalendarEventMutation from "./graphql/operations/create-calendar-event.graphql?raw";
import createCommunicationMutation from "./graphql/operations/create-communication.graphql?raw";
import updateFeedDecisionMutation from "./graphql/operations/update-feed-decision.graphql?raw";
import chatConversationsQuery from "./graphql/operations/chat-conversations.graphql?raw";
import createChatConversationMutation from "./graphql/operations/create-chat-conversation.graphql?raw";
import selectChatConversationMutation from "./graphql/operations/select-chat-conversation.graphql?raw";
import confirmLatestChangeSetMutation from "./graphql/operations/confirm-latest-change-set.graphql?raw";
import rollbackLatestChangeSetMutation from "./graphql/operations/rollback-latest-change-set.graphql?raw";
type TabId = "communications" | "documents";
type CalendarView = "day" | "week" | "month" | "year" | "agenda";
type SortMode = "name" | "lastContact";
type PeopleLeftMode = "contacts" | "calendar";
type PeopleSortMode = "name" | "lastContact" | "company" | "country";

type FeedCard = {
  id: string;
  at: string;
  contact: string;
  text: string;
  proposal: {
    title: string;
    details: string[];
    key: "create_followup" | "open_comm" | "call" | "draft_message" | "run_summary" | "prepare_question";
  };
  decision: "pending" | "accepted" | "rejected";
  decisionNote?: string;
};

type Contact = {
  id: string;
  name: string;
  avatar: string;
  company: string;
  country: string;
  location: string;
  channels: string[];
  lastContactAt: string;
  description: string;
};

type CalendarEvent = {
  id: string;
  title: string;
  start: string;
  end: string;
  contact: string;
  note: string;
};

type CommItem = {
  id: string;
  at: string;
  contact: string;
  channel: "Telegram" | "WhatsApp" | "Instagram" | "Phone" | "Email";
  kind: "message" | "call";
  direction: "in" | "out";
  text: string;
  duration?: string;
  transcript?: string[];
};

type CommPin = {
  id: string;
  contact: string;
  text: string;
};

type Deal = {
  id: string;
  contact: string;
  title: string;
  company: string;
  stage: string;
  amount: string;
  nextStep: string;
  summary: string;
};

type WorkspaceDocument = {
  id: string;
  title: string;
  type: "Regulation" | "Playbook" | "Policy" | "Template";
  owner: string;
  scope: string;
  updatedAt: string;
  summary: string;
  body: string;
};

const tabs: { id: TabId; label: string }[] = [
  { id: "communications", label: "Workspace" },
  { id: "documents", label: "Documents" },
];

const selectedTab = ref<TabId>("communications");
const pilotSettingsOpen = ref(false);

function dayKey(date: Date) {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, "0");
  const d = String(date.getDate()).padStart(2, "0");
  return `${y}-${m}-${d}`;
}

function formatDay(iso: string) {
  return new Intl.DateTimeFormat("en-GB", {
    day: "2-digit",
    month: "short",
    year: "numeric",
  }).format(new Date(iso));
}

function formatTime(iso: string) {
  return new Intl.DateTimeFormat("en-GB", {
    hour: "2-digit",
    minute: "2-digit",
  }).format(new Date(iso));
}

function formatThreadTime(iso: string) {
  return new Intl.DateTimeFormat("en-GB", {
    hour: "2-digit",
    minute: "2-digit",
    hour12: false,
  })
    .format(new Date(iso))
    .replace(":", ".");
}

function formatStamp(iso: string) {
  return new Intl.DateTimeFormat("en-GB", {
    day: "2-digit",
    month: "short",
    hour: "2-digit",
    minute: "2-digit",
  }).format(new Date(iso));
}

function atOffset(days: number, hour: number, minute: number) {
  const d = new Date();
  d.setDate(d.getDate() + days);
  d.setHours(hour, minute, 0, 0);
  return d.toISOString();
}

function inMinutes(minutes: number) {
  const d = new Date();
  d.setMinutes(d.getMinutes() + minutes, 0, 0);
  return d.toISOString();
}

function endAfter(startIso: string, minutes: number) {
  const d = new Date(startIso);
  d.setMinutes(d.getMinutes() + minutes);
  return d.toISOString();
}

const feedCards = ref<FeedCard[]>([]);

const contacts = ref<Contact[]>([]);

const calendarEvents = ref<CalendarEvent[]>([]);

const commItems = ref<CommItem[]>([]);

const commPins = ref<CommPin[]>([]);

const deals = ref<Deal[]>([]);

const documents = ref<WorkspaceDocument[]>([]);

type PilotMessage = {
  id: string;
  role: "user" | "assistant" | "system";
  text: string;
  plan?: string[] | null;
  thinking?: string[] | null;
  tools?: string[] | null;
  toolRuns?: Array<{
    name: string;
    status: "ok" | "error";
    input: string;
    output: string;
    at: string;
  }> | null;
  changeSetId?: string | null;
  changeStatus?: "pending" | "confirmed" | "rolled_back" | null;
  changeSummary?: string | null;
  changeItems?: Array<{
    entity: string;
    action: string;
    title: string;
    before: string;
    after: string;
  }> | null;
  createdAt?: string;
};

type ChatConversation = {
  id: string;
  title: string;
  createdAt: string;
  updatedAt: string;
  lastMessageAt?: string | null;
  lastMessageText?: string | null;
};

const pilotMessages = ref<PilotMessage[]>([]);
const pilotInput = ref("");
const pilotSending = ref(false);
const authMe = ref<{
  user: { id: string; phone: string; name: string };
  team: { id: string; name: string };
  conversation: { id: string; title: string };
} | null>(
  null,
);
const chatConversations = ref<ChatConversation[]>([]);
const chatThreadsLoading = ref(false);
const chatSwitching = ref(false);
const chatCreating = ref(false);
const selectedChatId = ref("");
const loginPhone = ref("");
const loginPassword = ref("");
const loginError = ref<string | null>(null);
const loginBusy = ref(false);

watch(
  () => authMe.value?.conversation.id,
  (id) => {
    if (id) selectedChatId.value = id;
  },
  { immediate: true },
);

function pilotRoleName(role: PilotMessage["role"]) {
  if (role === "user") return authMe.value?.user.name ?? "You";
  if (role === "system") return "System";
  return "Pilot";
}

function pilotRoleBadge(role: PilotMessage["role"]) {
  if (role === "user") return "You";
  if (role === "system") return "SYS";
  return "AI";
}

function formatPilotStamp(iso?: string) {
  if (!iso) return "";
  return new Intl.DateTimeFormat("en-GB", {
    day: "2-digit",
    month: "short",
    hour: "2-digit",
    minute: "2-digit",
  }).format(new Date(iso));
}

async function gqlFetch<TData>(query: string, variables?: Record<string, unknown>) {
  const result = await $fetch<{ data?: TData; errors?: Array<{ message: string }> }>("/api/graphql", {
    method: "POST",
    body: { query, variables },
  });

  if (result.errors?.length) {
    throw new Error(result.errors[0].message || "GraphQL request failed");
  }

  if (!result.data) {
    throw new Error("GraphQL returned empty payload");
  }

  return result.data;
}

async function loadPilotMessages() {
  const data = await gqlFetch<{ chatMessages: PilotMessage[] }>(chatMessagesQuery);
  pilotMessages.value = data.chatMessages ?? [];
}

async function loadChatConversations() {
  chatThreadsLoading.value = true;
  try {
    const data = await gqlFetch<{ chatConversations: ChatConversation[] }>(chatConversationsQuery);
    chatConversations.value = data.chatConversations ?? [];
  } finally {
    chatThreadsLoading.value = false;
  }
}

async function loadMe() {
  const data = await gqlFetch<{
    me: {
      user: { id: string; phone: string; name: string };
      team: { id: string; name: string };
      conversation: { id: string; title: string };
    };
  }>(
    meQuery,
  );
  authMe.value = data.me;
}

async function createNewChatConversation() {
  if (chatCreating.value) return;
  chatCreating.value = true;
  try {
    await gqlFetch<{ createChatConversation: ChatConversation }>(createChatConversationMutation);
    await Promise.all([loadMe(), loadPilotMessages(), loadChatConversations()]);
  } finally {
    chatCreating.value = false;
  }
}

async function switchChatConversation(id: string) {
  if (!id || chatSwitching.value || authMe.value?.conversation.id === id) return;
  chatSwitching.value = true;
  try {
    await gqlFetch<{ selectChatConversation: { ok: boolean } }>(selectChatConversationMutation, { id });
    await Promise.all([loadMe(), loadPilotMessages(), loadChatConversations()]);
  } finally {
    chatSwitching.value = false;
  }
}

async function login() {
  loginError.value = null;
  loginBusy.value = true;
  try {
    await gqlFetch<{ login: { ok: boolean } }>(loginMutation, {
      phone: loginPhone.value,
      password: loginPassword.value,
    });
    await loadMe();
    await Promise.all([loadPilotMessages(), loadChatConversations(), refreshCrmData()]);
  } catch (e: any) {
    loginError.value = e?.data?.message || e?.message || "Login failed";
  } finally {
    loginBusy.value = false;
  }
}

async function logout() {
  await gqlFetch<{ logout: { ok: boolean } }>(logoutMutation);
  authMe.value = null;
  pilotMessages.value = [];
  chatConversations.value = [];
}

async function refreshCrmData() {
  const data = await gqlFetch<{
    dashboard: {
      contacts: Contact[];
      communications: CommItem[];
      calendar: CalendarEvent[];
      deals: Deal[];
      feed: FeedCard[];
      pins: CommPin[];
      documents: WorkspaceDocument[];
    };
  }>(dashboardQuery);

  contacts.value = data.dashboard.contacts ?? [];
  commItems.value = data.dashboard.communications ?? [];
  calendarEvents.value = data.dashboard.calendar ?? [];
  deals.value = data.dashboard.deals ?? [];
  feedCards.value = data.dashboard.feed ?? [];
  commPins.value = data.dashboard.pins ?? [];
  documents.value = data.dashboard.documents ?? [];

  // Derive channels per contact from communication items.
  const byName = new Map<string, Set<string>>();
  for (const item of commItems.value) {
    if (!byName.has(item.contact)) byName.set(item.contact, new Set());
    byName.get(item.contact)?.add(item.channel);
  }
  contacts.value = contacts.value.map((c) => ({
    ...c,
    channels: Array.from(byName.get(c.name) ?? []),
  }));
}

async function sendPilotMessage() {
  const text = pilotInput.value.trim();
  if (!text || pilotSending.value) return;

  pilotSending.value = true;
  pilotInput.value = "";
  await loadPilotMessages().catch(() => {});
  const pollId = setInterval(() => {
    loadPilotMessages().catch(() => {});
  }, 450);
  try {
    await gqlFetch<{ sendPilotMessage: { ok: boolean } }>(sendPilotMessageMutation, { text });
    await Promise.all([loadPilotMessages(), loadChatConversations(), refreshCrmData()]);
  } catch {
    pilotInput.value = text;
  } finally {
    clearInterval(pollId);
    pilotSending.value = false;
  }
}

const changePanelOpen = ref(true);
const changeActionBusy = ref(false);

const latestChangeMessage = computed(() => {
  return (
    [...pilotMessages.value]
      .reverse()
      .find((m) => m.role === "assistant" && m.changeSetId && m.changeStatus !== "rolled_back") ?? null
  );
});

async function confirmLatestChangeSet() {
  if (changeActionBusy.value || !latestChangeMessage.value?.changeSetId) return;
  changeActionBusy.value = true;
  try {
    await gqlFetch<{ confirmLatestChangeSet: { ok: boolean } }>(confirmLatestChangeSetMutation);
    await loadPilotMessages();
  } finally {
    changeActionBusy.value = false;
  }
}

async function rollbackLatestChangeSet() {
  if (changeActionBusy.value || !latestChangeMessage.value?.changeSetId) return;
  changeActionBusy.value = true;
  try {
    await gqlFetch<{ rollbackLatestChangeSet: { ok: boolean } }>(rollbackLatestChangeSetMutation);
    await Promise.all([loadPilotMessages(), refreshCrmData()]);
  } finally {
    changeActionBusy.value = false;
  }
}

onMounted(() => {
  loadMe()
    .then(() => Promise.all([loadPilotMessages(), loadChatConversations(), refreshCrmData()]))
    .catch(() => {});
});

const calendarView = ref<CalendarView>("month");
const calendarCursor = ref(new Date(new Date().getFullYear(), new Date().getMonth(), 1));
const selectedDateKey = ref(dayKey(new Date()));

const sortedEvents = computed(() => [...calendarEvents.value].sort((a, b) => a.start.localeCompare(b.start)));

const eventsByDate = computed(() => {
  const map = new Map<string, CalendarEvent[]>();

  for (const event of sortedEvents.value) {
    const key = event.start.slice(0, 10);
    if (!map.has(key)) {
      map.set(key, []);
    }
    map.get(key)?.push(event);
  }

  return map;
});

function getEventsByDate(key: string) {
  return eventsByDate.value.get(key) ?? [];
}

const monthLabel = computed(() =>
  new Intl.DateTimeFormat("en-US", { month: "long", year: "numeric" }).format(calendarCursor.value),
);

const calendarViewOptions: { value: CalendarView; label: string }[] = [
  { value: "day", label: "Day" },
  { value: "week", label: "Week" },
  { value: "month", label: "Month" },
  { value: "year", label: "Year" },
  { value: "agenda", label: "Agenda" },
];

const monthCells = computed(() => {
  const year = calendarCursor.value.getFullYear();
  const month = calendarCursor.value.getMonth();
  const first = new Date(year, month, 1);
  const start = new Date(year, month, 1 - first.getDay());

  return Array.from({ length: 42 }, (_, index) => {
    const d = new Date(start);
    d.setDate(start.getDate() + index);
    const key = dayKey(d);

    return {
      key,
      day: d.getDate(),
      inMonth: d.getMonth() === month,
      events: getEventsByDate(key),
    };
  });
});

const weekDays = computed(() => {
  const base = new Date(`${selectedDateKey.value}T00:00:00`);
  const mondayOffset = (base.getDay() + 6) % 7;
  const monday = new Date(base);
  monday.setDate(base.getDate() - mondayOffset);

  return Array.from({ length: 7 }, (_, index) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + index);
    const key = dayKey(d);

    return {
      key,
      label: new Intl.DateTimeFormat("en-US", { weekday: "short" }).format(d),
      day: d.getDate(),
      events: getEventsByDate(key),
    };
  });
});

const calendarPeriodLabel = computed(() => {
  if (calendarView.value === "month") {
    return monthLabel.value;
  }

  if (calendarView.value === "year") {
    return String(calendarCursor.value.getFullYear());
  }

  if (calendarView.value === "week") {
    const first = weekDays.value[0];
    const last = weekDays.value[weekDays.value.length - 1];
    if (!first || !last) return "";
    return `${formatDay(`${first.key}T00:00:00`)} - ${formatDay(`${last.key}T00:00:00`)}`;
  }

  if (calendarView.value === "day") {
    return formatDay(`${selectedDateKey.value}T00:00:00`);
  }

  return `Agenda · ${monthLabel.value}`;
});

const yearMonths = computed(() => {
  const year = calendarCursor.value.getFullYear();
  return Array.from({ length: 12 }, (_, monthIndex) => {
    const monthStart = new Date(year, monthIndex, 1);
    const monthEnd = new Date(year, monthIndex + 1, 1);
    const items = sortedEvents.value.filter((event) => {
      const d = new Date(event.start);
      return d >= monthStart && d < monthEnd;
    });

    return {
      monthIndex,
      label: new Intl.DateTimeFormat("en-US", { month: "long" }).format(monthStart),
      count: items.length,
      first: items[0],
    };
  });
});

const selectedDayEvents = computed(() => getEventsByDate(selectedDateKey.value));

function shiftCalendar(step: number) {
  if (calendarView.value === "year") {
    const next = new Date(calendarCursor.value);
    next.setFullYear(next.getFullYear() + step);
    calendarCursor.value = new Date(next.getFullYear(), next.getMonth(), 1);
    const selected = new Date(`${selectedDateKey.value}T00:00:00`);
    selected.setFullYear(selected.getFullYear() + step);
    selectedDateKey.value = dayKey(selected);
    return;
  }

  if (calendarView.value === "month" || calendarView.value === "agenda") {
    const next = new Date(calendarCursor.value);
    next.setMonth(next.getMonth() + step);
    calendarCursor.value = new Date(next.getFullYear(), next.getMonth(), 1);
    return;
  }

  const current = new Date(`${selectedDateKey.value}T00:00:00`);
  const days = calendarView.value === "week" ? 7 : 1;
  current.setDate(current.getDate() + days * step);

  selectedDateKey.value = dayKey(current);
  calendarCursor.value = new Date(current.getFullYear(), current.getMonth(), 1);
}

function setToday() {
  const now = new Date();
  selectedDateKey.value = dayKey(now);
  calendarCursor.value = new Date(now.getFullYear(), now.getMonth(), 1);
}

function pickDate(key: string) {
  selectedDateKey.value = key;
  const d = new Date(`${key}T00:00:00`);
  calendarCursor.value = new Date(d.getFullYear(), d.getMonth(), 1);
}

function openYearMonth(monthIndex: number) {
  const year = calendarCursor.value.getFullYear();
  calendarCursor.value = new Date(year, monthIndex, 1);
  selectedDateKey.value = dayKey(new Date(year, monthIndex, 1));
  calendarView.value = "month";
}

const contactSearch = ref("");
const selectedCountry = ref("All");
const selectedLocation = ref("All");
const selectedCompany = ref("All");
const selectedChannel = ref("All");
const sortMode = ref<SortMode>("name");

const countries = computed(() => ["All", ...new Set(contacts.value.map((c) => c.country))].sort());

const locationScopeContacts = computed(() =>
  selectedCountry.value === "All"
    ? contacts.value
    : contacts.value.filter((contact) => contact.country === selectedCountry.value),
);

const locations = computed(() => ["All", ...new Set(locationScopeContacts.value.map((c) => c.location))].sort());

const companyScopeContacts = computed(() =>
  selectedLocation.value === "All"
    ? locationScopeContacts.value
    : locationScopeContacts.value.filter((contact) => contact.location === selectedLocation.value),
);

const companies = computed(() => ["All", ...new Set(companyScopeContacts.value.map((c) => c.company))].sort());
const channels = computed(() => ["All", ...new Set(contacts.value.flatMap((c) => c.channels))].sort());

watch(selectedCountry, () => {
  selectedLocation.value = "All";
  selectedCompany.value = "All";
});

watch(selectedLocation, () => {
  selectedCompany.value = "All";
});

function resetContactFilters() {
  contactSearch.value = "";
  selectedCountry.value = "All";
  selectedLocation.value = "All";
  selectedCompany.value = "All";
  selectedChannel.value = "All";
  sortMode.value = "name";
}

const filteredContacts = computed(() => {
  const query = contactSearch.value.trim().toLowerCase();
  const data = contacts.value.filter((contact) => {
    if (selectedCountry.value !== "All" && contact.country !== selectedCountry.value) return false;
    if (selectedLocation.value !== "All" && contact.location !== selectedLocation.value) return false;
    if (selectedCompany.value !== "All" && contact.company !== selectedCompany.value) return false;
    if (selectedChannel.value !== "All" && !contact.channels.includes(selectedChannel.value)) return false;
    if (query) {
      const haystack = [contact.name, contact.company, contact.country, contact.location, contact.description, contact.channels.join(" ")]
        .join(" ")
        .toLowerCase();
      if (!haystack.includes(query)) return false;
    }
    return true;
  });

  return data.sort((a, b) => {
    if (sortMode.value === "lastContact") {
      return b.lastContactAt.localeCompare(a.lastContactAt);
    }
    return a.name.localeCompare(b.name);
  });
});

const groupedContacts = computed(() => {
  if (sortMode.value === "lastContact") {
    return [["Recent", filteredContacts.value]] as [string, Contact[]][];
  }

  const map = new Map<string, Contact[]>();

  for (const contact of filteredContacts.value) {
    const key = contact.name[0].toUpperCase();
    if (!map.has(key)) {
      map.set(key, []);
    }
    map.get(key)?.push(contact);
  }

  return [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]));
});

const selectedContactId = ref(contacts.value[0]?.id ?? "");

watchEffect(() => {
  if (!filteredContacts.value.length) {
    selectedContactId.value = "";
    return;
  }
  if (!filteredContacts.value.some((item) => item.id === selectedContactId.value)) {
    selectedContactId.value = filteredContacts.value[0].id;
  }
});

const selectedContact = computed(() => contacts.value.find((item) => item.id === selectedContactId.value));
const selectedContactEvents = computed(() => {
  if (!selectedContact.value) return [];
  const nowIso = new Date().toISOString();
  const events = sortedEvents.value.filter((event) => event.contact === selectedContact.value?.name);
  const upcoming = events.filter((event) => event.end >= nowIso);
  const past = events.filter((event) => event.end < nowIso).reverse();

  return [...upcoming, ...past].slice(0, 8);
});

const selectedContactRecentMessages = computed(() => {
  if (!selectedContact.value) return [];
  return commItems.value
    .filter((item) => item.contact === selectedContact.value?.name && item.kind === "message")
    .sort((a, b) => b.at.localeCompare(a.at))
    .slice(0, 8);
});

const documentSearch = ref("");
const selectedDocumentType = ref<"All" | WorkspaceDocument["type"]>("All");

const documentTypes = computed(() =>
  ["All", ...new Set(documents.value.map((item) => item.type))] as ("All" | WorkspaceDocument["type"])[],
);

const filteredDocuments = computed(() => {
  const query = documentSearch.value.trim().toLowerCase();

  return documents.value
    .filter((item) => {
      if (selectedDocumentType.value !== "All" && item.type !== selectedDocumentType.value) return false;
      if (!query) return true;
      const haystack = [item.title, item.summary, item.owner, item.scope, item.body].join(" ").toLowerCase();
      return haystack.includes(query);
    })
    .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
});

const selectedDocumentId = ref(documents.value[0]?.id ?? "");

watchEffect(() => {
  if (!filteredDocuments.value.length) {
    selectedDocumentId.value = "";
    return;
  }

  if (!filteredDocuments.value.some((item) => item.id === selectedDocumentId.value)) {
    selectedDocumentId.value = filteredDocuments.value[0].id;
  }
});

const selectedDocument = computed(() => documents.value.find((item) => item.id === selectedDocumentId.value));

function openPilotDocument(docId: string) {
  if (!docId) return;
  selectedTab.value = "documents";
  selectedDocumentId.value = docId;
  pilotSettingsOpen.value = false;
}

const peopleLeftMode = ref<PeopleLeftMode>("contacts");
const peopleListMode = ref<"contacts" | "deals">("contacts");
const peopleSearch = ref("");
const peopleSortMode = ref<PeopleSortMode>("lastContact");
const peopleSortOptions: Array<{ value: PeopleSortMode; label: string }> = [
  { value: "lastContact", label: "Last contact" },
  { value: "name", label: "Name" },
  { value: "company", label: "Company" },
  { value: "country", label: "Country" },
];
const selectedDealId = ref(deals.value[0]?.id ?? "");

const commThreads = computed(() => {
  const sorted = [...commItems.value].sort((a, b) => a.at.localeCompare(b.at));
  const map = new Map<string, CommItem[]>();

  for (const item of sorted) {
    if (!map.has(item.contact)) {
      map.set(item.contact, []);
    }
    map.get(item.contact)?.push(item);
  }

  return contacts.value
    .map((contact) => {
      const items = map.get(contact.name) ?? [];
      const last = items[items.length - 1];
      const channels = [...new Set([...contact.channels, ...items.map((item) => item.channel)])] as CommItem["channel"][];

      return {
        id: contact.id,
        contact: contact.name,
        avatar: contact.avatar,
        company: contact.company,
        country: contact.country,
        location: contact.location,
        channels,
        lastAt: last?.at ?? contact.lastContactAt,
        lastText: last?.text ?? "No messages yet",
        items,
      };
    })
    .sort((a, b) => b.lastAt.localeCompare(a.lastAt));
});

const peopleContactList = computed(() => {
  const query = peopleSearch.value.trim().toLowerCase();
  const list = commThreads.value.filter((item) => {
    if (!query) return true;
    const haystack = [item.contact, item.company, item.country, item.location].join(" ").toLowerCase();
    return haystack.includes(query);
  });

  return list.sort((a, b) => {
    if (peopleSortMode.value === "name") return a.contact.localeCompare(b.contact);
    if (peopleSortMode.value === "company") return a.company.localeCompare(b.company);
    if (peopleSortMode.value === "country") return a.country.localeCompare(b.country);
    return b.lastAt.localeCompare(a.lastAt);
  });
});

const peopleDealList = computed(() => {
  const query = peopleSearch.value.trim().toLowerCase();
  const list = deals.value.filter((deal) => {
    if (!query) return true;
    const haystack = [deal.title, deal.company, deal.stage, deal.amount, deal.nextStep, deal.summary, deal.contact]
      .join(" ")
      .toLowerCase();
    return haystack.includes(query);
  });

  return list.sort((a, b) => a.title.localeCompare(b.title));
});

const selectedCommThreadId = ref("");

watchEffect(() => {
  if (!commThreads.value.length) {
    selectedCommThreadId.value = "";
    return;
  }

  if (!commThreads.value.some((thread) => thread.id === selectedCommThreadId.value)) {
    selectedCommThreadId.value = commThreads.value[0].id;
  }
});

const selectedCommThread = computed(() =>
  commThreads.value.find((thread) => thread.id === selectedCommThreadId.value),
);

const selectedCommChannel = ref<"All" | CommItem["channel"]>("All");
const rightSidebarMode = ref<"summary" | "pinned">("summary");
const commDraft = ref("");
const commSending = ref(false);

watch(selectedCommThreadId, () => {
  selectedCommChannel.value = "All";
  rightSidebarMode.value = "summary";
  commDraft.value = "";
});

const commChannelTabs = computed(() => {
  if (!selectedCommThread.value) return ["All"] as ("All" | CommItem["channel"])[];
  return ["All", ...selectedCommThread.value.channels] as ("All" | CommItem["channel"])[];
});

const visibleThreadItems = computed(() => {
  if (!selectedCommThread.value) return [];
  if (selectedCommChannel.value === "All") return selectedCommThread.value.items;
  return selectedCommThread.value.items.filter((item) => item.channel === selectedCommChannel.value);
});

const selectedThreadRecommendation = computed(() => {
  if (!selectedCommThread.value) return null;
  const cards = feedCards.value
    .filter((card) => card.contact === selectedCommThread.value?.contact)
    .sort((a, b) => a.at.localeCompare(b.at));
  return cards[cards.length - 1] ?? null;
});

const threadStreamItems = computed(() => {
  const messageRows = visibleThreadItems.value.map((item) => ({
    id: `comm-${item.id}`,
    at: item.at,
    kind: item.kind,
    item,
  })).sort((a, b) => a.at.localeCompare(b.at));

  if (selectedCommChannel.value !== "All") {
    return messageRows;
  }

  const centeredRows: Array<
    | {
      id: string;
      at: string;
      kind: "eventAlert";
      event: CalendarEvent;
    }
    | {
      id: string;
      at: string;
      kind: "recommendation";
      card: FeedCard;
    }
  > = [];

  if (selectedCommUrgentEvent.value) {
    centeredRows.push({
      id: `event-alert-${selectedCommUrgentEvent.value.id}`,
      at: selectedCommUrgentEvent.value.start,
      kind: "eventAlert",
      event: selectedCommUrgentEvent.value,
    });
  }

  if (selectedThreadRecommendation.value) {
    centeredRows.push({
      id: `rec-${selectedThreadRecommendation.value.id}`,
      at: selectedThreadRecommendation.value.at,
      kind: "recommendation",
      card: selectedThreadRecommendation.value,
    });
  }

  return [...messageRows, ...centeredRows];
});

const selectedCommPins = computed(() => {
  if (!selectedCommThread.value) return [];
  return commPins.value.filter((item) => item.contact === selectedCommThread.value?.contact);
});

const selectedCommEvents = computed(() => {
  if (!selectedCommThread.value) return [];
  const now = new Date();

  return sortedEvents.value
    .filter((event) => event.contact === selectedCommThread.value?.contact)
    .filter((event) => new Date(event.end) >= now)
    .slice(0, 6);
});

const selectedCommUrgentEvent = computed(() => {
  if (!selectedCommThread.value) return null;
  const now = Date.now();
  const inFifteenMinutes = now + 15 * 60 * 1000;

  const event = sortedEvents.value
    .filter((item) => item.contact === selectedCommThread.value?.contact)
    .filter((item) => {
      const start = new Date(item.start).getTime();
      return start >= now && start <= inFifteenMinutes;
    })
    .sort((a, b) => a.start.localeCompare(b.start))[0];

  return event ?? null;
});

const selectedCommPinnedStream = computed(() => {
  const pins = selectedCommPins.value.map((pin) => ({
    id: `pin-${pin.id}`,
    kind: "pin" as const,
    text: pin.text,
  }));

  const events = selectedCommEvents.value.map((event) => ({
    id: `event-${event.id}`,
    kind: "event" as const,
    event,
  }));

  return [...pins, ...events];
});

const latestPinnedItem = computed(() => selectedCommPinnedStream.value[0] ?? null);

const latestPinnedLabel = computed(() => {
  if (!latestPinnedItem.value) return "No pinned items yet";
  if (latestPinnedItem.value.kind === "pin") return latestPinnedItem.value.text;
  return `${latestPinnedItem.value.event.title} · ${formatDay(latestPinnedItem.value.event.start)}`;
});

const selectedWorkspaceContact = computed(() => {
  if (selectedContact.value) return selectedContact.value;
  if (!selectedCommThread.value) return null;
  return contacts.value.find((contact) => contact.name === selectedCommThread.value?.contact) ?? null;
});

const selectedWorkspaceDeal = computed(() => {
  if (selectedWorkspaceContact.value) {
    const linked = deals.value.find((deal) => deal.contact === selectedWorkspaceContact.value?.name);
    if (linked) return linked;
  }

  return deals.value.find((deal) => deal.id === selectedDealId.value) ?? null;
});

const openCallTranscripts = ref<Record<string, boolean>>({});

function toggleCallTranscript(itemId: string) {
  openCallTranscripts.value[itemId] = !openCallTranscripts.value[itemId];
}

function isCallTranscriptOpen(itemId: string) {
  return Boolean(openCallTranscripts.value[itemId]);
}

function threadTone(thread: { contact: string; items: CommItem[] }) {
  const now = Date.now();
  const oneDay = 24 * 60 * 60 * 1000;
  const hasEvent = sortedEvents.value.some((event) => {
    if (event.contact !== thread.contact) return false;
    const start = new Date(event.start).getTime();
    const end = new Date(event.end).getTime();
    return end <= now || start - now <= oneDay;
  });
  if (hasEvent) return "event";

  const hasRecommendation = feedCards.value.some((card) => card.contact === thread.contact && card.decision === "pending");
  if (hasRecommendation) return "recommendation";

  const last = thread.items[thread.items.length - 1];
  if (!last) return "neutral";
  if (last.direction === "in") return "message";
  return "neutral";
}

function openEventFromCommunication(event: CalendarEvent) {
  selectedTab.value = "communications";
  peopleLeftMode.value = "calendar";
  pickDate(event.start.slice(0, 10));
}

function channelIcon(channel: "All" | CommItem["channel"]) {
  if (channel === "All") return "all";
  if (channel === "Telegram") return "telegram";
  if (channel === "WhatsApp") return "whatsapp";
  if (channel === "Instagram") return "instagram";
  if (channel === "Email") return "email";
  return "phone";
}

function makeId(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
}

function pushPilotNote(text: string) {
  // Fire-and-forget: log assistant note to the same conversation.
  gqlFetch<{ logPilotNote: { ok: boolean } }>(logPilotNoteMutation, { text })
    .then(() => Promise.all([loadPilotMessages(), loadChatConversations()]))
    .catch(() => {});
}

function openCommunicationThread(contact: string) {
  selectedTab.value = "communications";
  peopleLeftMode.value = "contacts";
  const linkedContact = contacts.value.find((item) => item.name === contact);
  if (linkedContact) {
    selectedContactId.value = linkedContact.id;
  }
  const linkedDeal = deals.value.find((deal) => deal.contact === contact);
  if (linkedDeal) {
    selectedDealId.value = linkedDeal.id;
  }
  const thread = commThreads.value.find((item) => item.contact === contact);
  if (thread) {
    selectedCommThreadId.value = thread.id;
  }
}

function openDealThread(deal: Deal) {
  selectedDealId.value = deal.id;
  openCommunicationThread(deal.contact);
}

function openThreadFromCalendarItem(event: CalendarEvent) {
  if (!event.contact?.trim()) {
    selectedTab.value = "communications";
    peopleLeftMode.value = "calendar";
    pickDate(event.start.slice(0, 10));
    return;
  }
  openCommunicationThread(event.contact);
  selectedCommChannel.value = "All";
}

function openEventFromContact(event: CalendarEvent) {
  selectedTab.value = "communications";
  peopleLeftMode.value = "calendar";
  pickDate(event.start.slice(0, 10));
}

function openMessageFromContact(channel: CommItem["channel"]) {
  if (!selectedContact.value) return;
  openCommunicationThread(selectedContact.value.name);
  selectedCommChannel.value = channel;
}

async function sendCommMessage() {
  const text = commDraft.value.trim();
  if (!text || commSending.value || !selectedCommThread.value) return;

  commSending.value = true;
  try {
    const fallback =
      selectedCommThread.value.channels.find((channel) => channel !== "Phone") ??
      "Telegram";
    const channel = selectedCommChannel.value === "All" ? fallback : selectedCommChannel.value;

    await gqlFetch<{ createCommunication: { ok: boolean; id: string } }>(createCommunicationMutation, {
      input: {
        contact: selectedCommThread.value.contact,
        channel,
        kind: "message",
        direction: "out",
        text,
      },
    });

    commDraft.value = "";
    await refreshCrmData();
    openCommunicationThread(selectedCommThread.value.contact);
  } finally {
    commSending.value = false;
  }
}

async function executeFeedAction(card: FeedCard) {
  const key = card.proposal.key;
  if (key === "create_followup") {
    const start = new Date();
    start.setMinutes(start.getMinutes() + 30);
    start.setSeconds(0, 0);
    const end = new Date(start);
    end.setMinutes(end.getMinutes() + 30);

    const res = await gqlFetch<{ createCalendarEvent: CalendarEvent }>(createCalendarEventMutation, {
      input: {
        title: `Follow-up: ${card.contact.split(" ")[0] ?? "Contact"}`,
        start: start.toISOString(),
        end: end.toISOString(),
        contact: card.contact,
        note: "Created from feed action.",
        status: "planned",
      },
    });
    calendarEvents.value = [res.createCalendarEvent, ...calendarEvents.value];

    selectedDateKey.value = dayKey(start);
    calendarCursor.value = new Date(start.getFullYear(), start.getMonth(), 1);
    selectedTab.value = "communications";
    peopleLeftMode.value = "calendar";
    return `Event created: Follow-up · ${formatDay(start.toISOString())} ${formatTime(start.toISOString())} · ${card.contact}`;
  }

  if (key === "open_comm") {
    openCommunicationThread(card.contact);
    return `Opened ${card.contact} communication thread.`;
  }

  if (key === "call") {
    await gqlFetch<{ createCommunication: { ok: boolean; id: string } }>(createCommunicationMutation, {
      input: {
        contact: card.contact,
        channel: "Phone",
        kind: "call",
        direction: "out",
        text: "Call started from feed",
        durationSec: 0,
      },
    });
    await refreshCrmData();
    openCommunicationThread(card.contact);
    return `Call event created and ${card.contact} chat opened.`;
  }

  if (key === "draft_message") {
    await gqlFetch<{ createCommunication: { ok: boolean; id: string } }>(createCommunicationMutation, {
      input: {
        contact: card.contact,
        channel: "Email",
        kind: "message",
        direction: "out",
        text: "Draft: onboarding plan + two slots for tomorrow.",
      },
    });
    await refreshCrmData();
    openCommunicationThread(card.contact);
    return `Draft message added to ${card.contact} communications.`;
  }

  if (key === "run_summary") {
    return "Call summary prepared: 5 next steps sent to Pilot.";
  }

  if (key === "prepare_question") {
    await gqlFetch<{ createCommunication: { ok: boolean; id: string } }>(createCommunicationMutation, {
      input: {
        contact: card.contact,
        channel: "Telegram",
        kind: "message",
        direction: "out",
        text: "Draft: can you confirm your decision date for this cycle?",
      },
    });
    await refreshCrmData();
    openCommunicationThread(card.contact);
    return `Question about decision date added to ${card.contact} chat.`;
  }

  return "Action completed.";
}

async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected") {
  card.decision = decision;

  if (decision === "rejected") {
    const note = "Rejected. Nothing created.";
    card.decisionNote = note;
    await gqlFetch<{ updateFeedDecision: { ok: boolean; id: string } }>(updateFeedDecisionMutation, {
      id: card.id,
      decision: "rejected",
      decisionNote: note,
    });
    pushPilotNote(`[${card.contact}] recommendation rejected: ${card.proposal.title}`);
    return;
  }

  const result = await executeFeedAction(card);
  card.decisionNote = result;
  await gqlFetch<{ updateFeedDecision: { ok: boolean; id: string } }>(updateFeedDecisionMutation, {
    id: card.id,
    decision: "accepted",
    decisionNote: result,
  });
  pushPilotNote(`[${card.contact}] ${result}`);
}

</script>

<template>
  <div class="h-[100dvh] overflow-hidden bg-base-200/35">
    <div v-if="!authMe" class="flex h-full items-center justify-center px-3">
      <div class="card w-full max-w-sm border border-base-300 bg-base-100 shadow-sm">
        <div class="card-body p-5">
          <h1 class="text-lg font-semibold">Login</h1>
          <p class="mt-1 text-xs text-base-content/65">Sign in with phone and password.</p>
          <div class="mt-4 space-y-2">
            <input
              v-model="loginPhone"
              type="tel"
              class="input input-bordered w-full"
              placeholder="+1 555 000 0001"
              @keyup.enter="login"
            >
            <input
              v-model="loginPassword"
              type="password"
              class="input input-bordered w-full"
              placeholder="Password"
              @keyup.enter="login"
            >
            <p v-if="loginError" class="text-xs text-error">{{ loginError }}</p>
            <button class="btn w-full" :disabled="loginBusy" @click="login">
              {{ loginBusy ? "Logging in..." : "Login" }}
            </button>
          </div>
        </div>
      </div>
    </div>

    <template v-else>
      <div class="grid h-full min-h-0 grid-cols-1 gap-0 lg:grid-cols-[320px_minmax(0,1fr)]">
        <aside class="pilot-shell min-h-0 border-r border-base-300">
          <div class="flex h-full min-h-0 flex-col p-0">
            <div class="pilot-header">
              <div>
                <h2 class="text-sm font-semibold uppercase tracking-wide text-white/75">Pilot Chat</h2>
              </div>
              <button
                class="btn btn-ghost btn-xs btn-square text-white/80 hover:bg-white/10"
                title="Pilot settings"
                @click="pilotSettingsOpen = !pilotSettingsOpen"
              >
                <svg viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                  <path d="M19.14 12.94a7.43 7.43 0 0 0 .05-.94 7.43 7.43 0 0 0-.05-.94l2.03-1.58a.5.5 0 0 0 .12-.64l-1.92-3.32a.5.5 0 0 0-.6-.22l-2.39.96a7.28 7.28 0 0 0-1.62-.94l-.36-2.54A.5.5 0 0 0 14.9 2h-3.8a.5.5 0 0 0-.49.42l-.36 2.54c-.58.22-1.12.53-1.62.94l-2.39-.96a.5.5 0 0 0-.6.22L3.72 8.84a.5.5 0 0 0 .12.64l2.03 1.58c-.03.31-.05.63-.05.94s.02.63.05.94l-2.03 1.58a.5.5 0 0 0-.12.64l1.92 3.32c.13.23.4.32.64.22l2.39-.96c.5.41 1.04.72 1.62.94l.36 2.54c.04.24.25.42.49.42h3.8c.24 0 .45-.18.49-.42l.36-2.54c.58-.22 1.12-.53 1.62-.94l2.39.96c.24.1.51.01.64-.22l1.92-3.32a.5.5 0 0 0-.12-.64zM13 15.5A3.5 3.5 0 1 1 13 8.5a3.5 3.5 0 0 1 0 7z" />
                </svg>
              </button>
            </div>
            <div v-if="pilotSettingsOpen" class="pilot-settings-panel">
              <p class="text-[11px] font-semibold uppercase tracking-wide text-white/65">Pilot Settings</p>
              <p class="mt-1 text-xs text-white/70">Prompt sources from workspace documents.</p>
              <div class="mt-2 max-h-44 space-y-1 overflow-y-auto pr-1">
                <button
                  v-for="doc in documents.slice(0, 10)"
                  :key="`pilot-doc-${doc.id}`"
                  class="w-full rounded-lg border border-white/10 bg-white/5 px-2 py-1.5 text-left text-xs text-white/85 transition hover:bg-white/10"
                  @click="openPilotDocument(doc.id)"
                >
                  <p class="truncate font-medium">{{ doc.title }}</p>
                  <p class="truncate text-[11px] text-white/55">{{ doc.type }} · {{ doc.owner }}</p>
                </button>
                <p v-if="documents.length === 0" class="text-xs text-white/55">No documents yet.</p>
              </div>
            </div>

            <div class="pilot-threads">
              <div class="pilot-threads-head">
                <span class="text-[11px] uppercase tracking-wide text-white/60">Thread</span>
                <button class="btn btn-xs border-0 bg-[#5865f2] text-white hover:bg-[#4752c4]" :disabled="chatCreating" @click="createNewChatConversation">
                  {{ chatCreating ? "..." : "New chat" }}
                </button>
              </div>
              <div class="mt-2">
                <select
                  v-model="selectedChatId"
                  class="select select-sm w-full border-white/15 bg-[#1e2230] text-white"
                  :disabled="chatSwitching || chatThreadsLoading || chatConversations.length === 0"
                  @change="switchChatConversation(selectedChatId)"
                >
                  <option v-for="thread in chatConversations" :key="`thread-option-${thread.id}`" :value="thread.id">
                    {{ thread.title }}
                  </option>
                </select>
              </div>
            </div>

            <div class="pilot-timeline min-h-0 flex-1 overflow-y-auto">
              <div
                v-for="message in pilotMessages"
                :key="message.id"
                class="pilot-row"
              >
                <div class="pilot-avatar" :class="message.role === 'user' ? 'pilot-avatar-user' : ''">
                  {{ pilotRoleBadge(message.role) }}
                </div>

                <div class="pilot-body">
                  <div class="pilot-meta">
                    <span class="pilot-author">{{ pilotRoleName(message.role) }}</span>
                    <span class="pilot-time">{{ formatPilotStamp(message.createdAt) }}</span>
                  </div>

                  <div class="pilot-message-text">
                    {{ message.text }}
                  </div>

                  <div
                    v-if="message.role !== 'user' && ((message.plan && message.plan.length) || (message.thinking && message.thinking.length) || (message.toolRuns && message.toolRuns.length) || (message.tools && message.tools.length))"
                    class="pilot-debug mt-2"
                  >
                    <div v-if="message.plan && message.plan.length" class="pilot-debug-block">
                      <p class="pilot-debug-title">Plan</p>
                      <ol class="pilot-debug-list">
                        <li v-for="(step, idx) in message.plan" :key="`plan-${message.id}-${idx}`">{{ step }}</li>
                      </ol>
                    </div>

                    <div v-if="message.thinking && message.thinking.length" class="pilot-debug-block">
                      <p class="pilot-debug-title">Trace</p>
                      <ol class="pilot-debug-list">
                        <li v-for="(step, idx) in message.thinking" :key="`thinking-${message.id}-${idx}`">{{ step }}</li>
                      </ol>
                    </div>

                    <div v-if="message.toolRuns && message.toolRuns.length" class="pilot-debug-block">
                      <p class="pilot-debug-title">Tool Runs</p>
                      <ul class="pilot-tool-list">
                        <li v-for="(run, idx) in message.toolRuns" :key="`toolrun-${message.id}-${idx}`" class="pilot-tool-row">
                          <div class="pilot-tool-head">
                            <code>{{ run.name }}</code>
                            <span :class="run.status === 'error' ? 'pilot-tool-status-error' : 'pilot-tool-status-ok'">{{ run.status }}</span>
                          </div>
                          <p class="pilot-tool-io"><strong>Input:</strong> {{ run.input }}</p>
                          <p class="pilot-tool-io"><strong>Output:</strong> {{ run.output }}</p>
                        </li>
                      </ul>
                    </div>

                    <div v-else-if="message.tools && message.tools.length" class="pilot-debug-block">
                      <p class="pilot-debug-title">Tools</p>
                      <ul class="pilot-debug-list">
                        <li v-for="(tool, idx) in message.tools" :key="`tools-${message.id}-${idx}`">{{ tool }}</li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>

            </div>

            <div
              v-if="latestChangeMessage && latestChangeMessage.changeItems && latestChangeMessage.changeItems.length"
              class="mb-2 rounded-xl border border-amber-300/40 bg-amber-500/10 p-2"
            >
              <div class="flex items-center justify-between gap-2">
                <div>
                  <p class="text-xs font-semibold text-amber-100">Detected changes</p>
                  <p class="text-[11px] text-amber-100/80">
                    {{ latestChangeMessage.changeSummary || `Changed: ${latestChangeMessage.changeItems.length}` }}
                    · status: {{ latestChangeMessage.changeStatus || "pending" }}
                  </p>
                </div>
                <div class="flex items-center gap-1">
                  <button class="btn btn-xs btn-ghost" @click="changePanelOpen = !changePanelOpen">
                    {{ changePanelOpen ? "Hide" : "Show" }}
                  </button>
                  <button
                    class="btn btn-xs"
                    :disabled="changeActionBusy || latestChangeMessage.changeStatus === 'confirmed'"
                    @click="confirmLatestChangeSet"
                  >
                    Keep
                  </button>
                  <button
                    class="btn btn-xs btn-outline"
                    :disabled="changeActionBusy || latestChangeMessage.changeStatus === 'rolled_back'"
                    @click="rollbackLatestChangeSet"
                  >
                    Rollback
                  </button>
                </div>
              </div>
              <div v-if="changePanelOpen" class="mt-2 max-h-44 space-y-2 overflow-y-auto pr-1">
                <div
                  v-for="(item, idx) in latestChangeMessage.changeItems"
                  :key="`change-item-${idx}`"
                  class="rounded-lg border border-amber-200/30 bg-[#1e2230] p-2"
                >
                  <p class="text-[11px] font-semibold text-white/90">{{ item.title }}</p>
                  <p class="text-[11px] text-white/60">{{ item.entity }} · {{ item.action }}</p>
                  <p v-if="item.before" class="mt-1 text-[11px] text-red-300/80">- {{ item.before }}</p>
                  <p v-if="item.after" class="text-[11px] text-emerald-300/80">+ {{ item.after }}</p>
                </div>
              </div>
            </div>

            <div class="pilot-input-wrap">
              <input
                v-model="pilotInput"
                type="text"
                class="input input-sm w-full border-white/15 bg-[#1e2230] text-white placeholder:text-white/40"
                placeholder="Type a message for Pilot..."
                @keyup.enter="sendPilotMessage"
              >
              <button class="btn btn-sm border-0 bg-[#5865f2] text-white hover:bg-[#4752c4]" :disabled="pilotSending" @click="sendPilotMessage">
                <svg viewBox="0 0 24 24" class="h-4 w-4 fill-current" :class="pilotSending ? 'opacity-50' : ''">
                  <path d="M4.5 19.5 21 12 4.5 4.5l.02 5.84L15 12l-10.48 1.66z" />
                </svg>
              </button>
            </div>
          </div>
        </aside>

        <main class="min-h-0 bg-base-100">
        <div class="flex h-full min-h-0 flex-col pb-20 md:pb-24">
          <div class="workspace-topbar border-b border-base-300 px-3 py-2 md:px-4">
            <div class="ml-auto flex items-center gap-2">
              <button class="btn btn-sm btn-outline" @click="logout">Logout</button>
            </div>
          </div>
          <div class="min-h-0 flex-1 p-3 md:p-4">
            <section v-if="selectedTab === 'communications' && peopleLeftMode === 'calendar'" class="flex h-full min-h-0 flex-col gap-3">
            <div class="mb-1 flex justify-end">
              <div class="join">
                <button class="btn btn-sm join-item btn-ghost" @click="peopleLeftMode = 'contacts'">Contacts</button>
                <button class="btn btn-sm join-item btn-primary" @click="peopleLeftMode = 'calendar'">Calendar</button>
              </div>
            </div>
            <div class="grid grid-cols-[auto_1fr_auto] items-center gap-2">
              <div class="flex items-center gap-1">
                <button class="btn btn-xs" @click="setToday">Today</button>
                <button class="btn btn-xs btn-ghost" @click="shiftCalendar(-1)">←</button>
                <button class="btn btn-xs btn-ghost" @click="shiftCalendar(1)">→</button>
              </div>

              <div class="text-center text-sm font-medium">
                {{ calendarPeriodLabel }}
              </div>

              <div class="justify-self-end">
                <select v-model="calendarView" class="select select-bordered select-xs w-36">
                  <option
                    v-for="option in calendarViewOptions"
                    :key="`calendar-view-${option.value}`"
                    :value="option.value"
                  >
                    {{ option.label }}
                  </option>
                </select>
              </div>
            </div>

            <div class="min-h-0 flex-1 overflow-y-auto pr-1">
            <div v-if="calendarView === 'month'" class="space-y-1">
              <div class="grid grid-cols-7 gap-1 text-center text-xs font-semibold text-base-content/60">
                <span>Sun</span>
                <span>Mon</span>
                <span>Tue</span>
                <span>Wed</span>
                <span>Thu</span>
                <span>Fri</span>
                <span>Sat</span>
              </div>

              <div class="grid grid-cols-7 gap-1">
                <button
                  v-for="cell in monthCells"
                  :key="cell.key"
                  class="min-h-24 rounded-lg border p-1 text-left"
                  :class="[
                    cell.inMonth ? 'border-base-300 bg-base-100' : 'border-base-200 bg-base-200/40 text-base-content/40',
                    selectedDateKey === cell.key ? 'border-primary bg-primary/5' : '',
                  ]"
                  @click="pickDate(cell.key)"
                >
                  <p class="mb-1 text-xs font-semibold">{{ cell.day }}</p>
                  <button
                    v-for="event in cell.events.slice(0, 2)"
                    :key="event.id"
                    class="block w-full truncate text-left text-[10px] text-base-content/70 hover:underline"
                    @click.stop="openThreadFromCalendarItem(event)"
                  >
                    {{ formatTime(event.start) }} {{ event.title }}
                  </button>
                </button>
              </div>
            </div>

            <div v-else-if="calendarView === 'week'" class="space-y-2">
              <article
                v-for="day in weekDays"
                :key="day.key"
                class="rounded-xl border border-base-300 p-3"
                :class="selectedDateKey === day.key ? 'border-primary bg-primary/5' : ''"
                @click="pickDate(day.key)"
              >
                <p class="mb-2 text-sm font-semibold">{{ day.label }} {{ day.day }}</p>
                <div class="space-y-1">
                  <button
                    v-for="event in day.events"
                    :key="event.id"
                    class="block w-full rounded bg-base-200 px-2 py-1 text-left text-xs hover:bg-base-300/80"
                    @click.stop="openThreadFromCalendarItem(event)"
                  >
                    {{ formatTime(event.start) }} - {{ event.title }} ({{ event.contact }})
                  </button>
                  <p v-if="day.events.length === 0" class="text-xs text-base-content/50">No events</p>
                </div>
              </article>
            </div>

            <div v-else-if="calendarView === 'day'" class="space-y-2">
              <button
                v-for="event in selectedDayEvents"
                :key="event.id"
                class="block w-full rounded-xl border border-base-300 p-3 text-left transition hover:bg-base-200/60"
                @click="openThreadFromCalendarItem(event)"
              >
                <p class="font-medium">{{ event.title }}</p>
                <p class="text-xs text-base-content/60">{{ event.contact }}</p>
                <p class="text-xs text-base-content/60">{{ formatTime(event.start) }} - {{ formatTime(event.end) }}</p>
                <p class="mt-1 text-sm text-base-content/80">{{ event.note }}</p>
              </button>
              <p v-if="selectedDayEvents.length === 0" class="text-sm text-base-content/60">No events on this day.</p>
            </div>

            <div v-else-if="calendarView === 'year'" class="grid gap-2 sm:grid-cols-2 xl:grid-cols-3">
              <button
                v-for="item in yearMonths"
                :key="`year-month-${item.monthIndex}`"
                class="rounded-xl border border-base-300 p-3 text-left transition hover:border-primary/50 hover:bg-primary/5"
                @click="openYearMonth(item.monthIndex)"
              >
                <p class="font-medium">{{ item.label }}</p>
                <p class="text-xs text-base-content/60">{{ item.count }} events</p>
                <button
                  v-if="item.first"
                  class="mt-1 block w-full text-left text-xs text-base-content/70 hover:underline"
                  @click.stop="openThreadFromCalendarItem(item.first)"
                >
                  {{ formatDay(item.first.start) }} · {{ item.first.title }}
                </button>
              </button>
            </div>

            <div v-else class="space-y-2">
              <button
                v-for="event in sortedEvents"
                :key="event.id"
                class="block w-full rounded-xl border border-base-300 p-3 text-left transition hover:bg-base-200/60"
                @click="openThreadFromCalendarItem(event)"
              >
                <p class="font-medium">{{ event.title }}</p>
                <p class="text-xs text-base-content/60">{{ event.contact }}</p>
                <p class="text-xs text-base-content/60">{{ formatDay(event.start) }} · {{ formatTime(event.start) }} - {{ formatTime(event.end) }}</p>
                <p class="mt-1 text-sm text-base-content/80">{{ event.note }}</p>
              </button>
            </div>
            </div>
            </section>

            <section v-else-if="selectedTab === 'communications' && false" class="space-y-3">
            <div class="mb-1 flex justify-end">
              <div class="join">
                <button class="btn btn-sm join-item btn-primary" @click="peopleLeftMode = 'contacts'">Contacts</button>
                <button class="btn btn-sm join-item btn-ghost" @click="peopleLeftMode = 'calendar'">Calendar</button>
              </div>
            </div>
            <div class="rounded-xl border border-base-300 p-3">
              <div class="flex flex-wrap items-center gap-2">
                <input
                  v-model="contactSearch"
                  type="text"
                  class="input input-bordered input-md w-full flex-1"
                  placeholder="Search contacts..."
                >

                <select v-model="sortMode" class="select select-bordered select-sm w-40">
                  <option value="name">Sort: Name</option>
                  <option value="lastContact">Sort: Last contact</option>
                </select>

                <div class="dropdown dropdown-end">
                  <button tabindex="0" class="btn btn-sm btn-ghost btn-square" title="Filters">
                    <svg viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                      <path d="M3 5h18v2H3zm4 6h10v2H7zm3 6h4v2h-4z" />
                    </svg>
                  </button>
                  <div tabindex="0" class="dropdown-content z-20 mt-2 w-72 rounded-xl border border-base-300 bg-base-100 p-3 shadow-lg">
                    <div class="grid gap-2">
                      <label class="form-control">
                        <span class="label-text text-xs uppercase tracking-wide text-base-content/60">Country</span>
                        <select v-model="selectedCountry" class="select select-bordered select-sm">
                          <option v-for="country in countries" :key="`country-${country}`" :value="country">{{ country }}</option>
                        </select>
                      </label>

                      <label class="form-control">
                        <span class="label-text text-xs uppercase tracking-wide text-base-content/60">Location</span>
                        <select v-model="selectedLocation" class="select select-bordered select-sm">
                          <option v-for="location in locations" :key="`location-${location}`" :value="location">{{ location }}</option>
                        </select>
                      </label>

                      <label class="form-control">
                        <span class="label-text text-xs uppercase tracking-wide text-base-content/60">Company</span>
                        <select v-model="selectedCompany" class="select select-bordered select-sm">
                          <option v-for="company in companies" :key="`company-${company}`" :value="company">{{ company }}</option>
                        </select>
                      </label>

                      <label class="form-control">
                        <span class="label-text text-xs uppercase tracking-wide text-base-content/60">Channel</span>
                        <select v-model="selectedChannel" class="select select-bordered select-sm">
                          <option v-for="channel in channels" :key="`channel-${channel}`" :value="channel">{{ channel }}</option>
                        </select>
                      </label>
                    </div>

                    <div class="mt-3 flex justify-end">
                      <button class="btn btn-ghost btn-sm" @click="resetContactFilters">Reset filters</button>
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <div class="grid gap-3 md:grid-cols-12">
              <aside class="min-h-0 rounded-xl border border-base-300 md:col-span-4">
                <div class="min-h-0 space-y-3 overflow-y-auto p-2">
                  <article v-for="group in groupedContacts" :key="group[0]" class="space-y-2">
                    <div class="sticky top-0 z-10 rounded-lg bg-base-200 px-3 py-1 text-sm font-semibold">{{ group[0] }}</div>

                    <button
                      v-for="contact in group[1]"
                      :key="contact.id"
                      class="w-full rounded-xl border border-base-300 p-3 text-left transition hover:bg-base-200/60"
                      :class="selectedContactId === contact.id ? 'border-primary bg-primary/5' : ''"
                      @click="selectedContactId = contact.id"
                    >
                      <p class="font-medium">{{ contact.name }}</p>
                      <p class="text-xs text-base-content/60">{{ contact.company }} · {{ contact.location }}, {{ contact.country }}</p>
                      <p class="mt-1 text-[11px] text-base-content/55">Last contact · {{ formatStamp(contact.lastContactAt) }}</p>
                    </button>
                  </article>
                </div>
              </aside>

              <article class="min-h-0 rounded-xl border border-base-300 md:col-span-8">
                <div v-if="selectedContact" class="p-3 md:p-4">
                  <div class="border-b border-base-300 pb-2">
                    <p class="font-medium">{{ selectedContact.name }}</p>
                    <p class="text-xs text-base-content/60">
                      {{ selectedContact.company }} · {{ selectedContact.location }}, {{ selectedContact.country }}
                    </p>
                    <p class="mt-1 text-xs text-base-content/55">Last contact · {{ formatStamp(selectedContact.lastContactAt) }}</p>
                  </div>

                  <div class="mt-3">
                    <ContactCollaborativeEditor
                      :key="`contact-editor-${selectedContact.id}`"
                      v-model="selectedContact.description"
                      :room="`crm-contact-${selectedContact.id}`"
                      placeholder="Describe contact context and next steps..."
                    />
                  </div>

                  <div class="mt-4 grid gap-3 xl:grid-cols-2">
                    <section class="rounded-xl border border-base-300 p-3">
                      <div class="mb-2 flex items-center justify-between gap-2">
                        <p class="text-sm font-semibold">Upcoming events</p>
                      </div>
                      <div class="space-y-2">
                        <button
                          v-for="event in selectedContactEvents"
                          :key="`contact-event-${event.id}`"
                          class="w-full rounded-lg border border-base-300 px-3 py-2 text-left transition hover:bg-base-200/50"
                          @click="openEventFromContact(event)"
                        >
                          <p class="text-sm font-medium">{{ event.title }}</p>
                          <p class="text-xs text-base-content/65">
                            {{ formatDay(event.start) }} · {{ formatTime(event.start) }} - {{ formatTime(event.end) }}
                          </p>
                          <p class="mt-1 text-xs text-base-content/80">{{ event.note }}</p>
                        </button>
                        <p v-if="selectedContactEvents.length === 0" class="text-xs text-base-content/55">
                          No linked events yet.
                        </p>
                      </div>
                    </section>

                    <section class="rounded-xl border border-base-300 p-3">
                      <div class="mb-2 flex items-center justify-between gap-2">
                        <p class="text-sm font-semibold">Recent messages</p>
                        <button class="btn btn-ghost btn-xs" @click="openCommunicationThread(selectedContact.name)">Open chat</button>
                      </div>
                      <div class="space-y-2">
                        <button
                          v-for="item in selectedContactRecentMessages"
                          :key="`contact-message-${item.id}`"
                          class="w-full rounded-lg border border-base-300 px-3 py-2 text-left transition hover:bg-base-200/50"
                          @click="openMessageFromContact(item.channel)"
                        >
                          <p class="text-sm text-base-content/90">{{ item.text }}</p>
                          <p class="mt-1 text-xs text-base-content/60">
                            <span class="mr-1 inline-flex h-4 w-4 items-center justify-center align-middle">
                              <svg v-if="channelIcon(item.channel) === 'telegram'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M9.04 15.51 8.7 20.27c.49 0 .7-.21.96-.46l2.3-2.2 4.77 3.49c.88.49 1.5.23 1.74-.81l3.15-14.77.01-.01c.29-1.35-.49-1.88-1.35-1.56L1.74 11.08c-1.28.5-1.26 1.22-.22 1.54l4.74 1.48L17.3 7.03c.52-.34 1-.15.61.19" />
                              </svg>
                              <svg v-else-if="channelIcon(item.channel) === 'whatsapp'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M20 3.99A9.94 9.94 0 0 0 12.01 1C6.49 1 2 5.49 2 11c0 1.76.46 3.49 1.33 5.03L2 23l7.17-1.88A9.95 9.95 0 0 0 12 21h.01c5.51 0 9.99-4.49 9.99-10.01 0-2.67-1.04-5.18-2.99-7m-7.99 15.32h-.01a8.3 8.3 0 0 1-4.23-1.16l-.3-.18-4.26 1.12 1.14-4.15-.2-.32a8.28 8.28 0 0 1-1.27-4.4c0-4.58 3.73-8.31 8.32-8.31a8.27 8.27 0 0 1 5.88 2.44 8.25 8.25 0 0 1 2.43 5.87c0 4.59-3.73 8.32-8.31 8.32m4.56-6.23c-.25-.12-1.49-.74-1.73-.82-.23-.09-.4-.12-.57.12s-.66.82-.81.99-.3.18-.55.06a6.7 6.7 0 0 1-1.97-1.21 7.43 7.43 0 0 1-1.38-1.71c-.14-.24-.01-.37.1-.49.11-.11.24-.3.36-.45.12-.14.16-.24.25-.39.08-.18.05-.3-.02-.42-.07-.12-.56-1.35-.77-1.85-.2-.48-.41-.41-.57-.42h-.48c-.16 0-.42.06-.64.3-.22.24-.84.82-.84 2s.86 2.31.98 2.48c.12.16 1.69 2.57 4.09 3.6.57.24 1.01.38 1.36.48.58.18 1.11.15 1.52.09.46-.06 1.49-.61 1.7-1.19.21-.58.21-1.09.15-1.19-.06-.11-.23-.17-.48-.3" />
                              </svg>
                              <svg v-else-if="channelIcon(item.channel) === 'instagram'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M7 2h10a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H7a5 5 0 0 1-5-5V7a5 5 0 0 1 5-5m10 2H7a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3m-5 3.5A4.5 4.5 0 1 1 7.5 12 4.5 4.5 0 0 1 12 7.5m0 2A2.5 2.5 0 1 0 14.5 12 2.5 2.5 0 0 0 12 9.5m4.8-3.2a1.2 1.2 0 1 1-1.2 1.2 1.2 1.2 0 0 1 1.2-1.2" />
                              </svg>
                              <svg v-else-if="channelIcon(item.channel) === 'email'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M20 4H4a2 2 0 0 0-2 2v.4l10 5.6 10-5.6V6a2 2 0 0 0-2-2m0 4.2-7.4 4.14a1.25 1.25 0 0 1-1.2 0L4 8.2V18a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2z" />
                              </svg>
                              <svg v-else viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M6.62 10.79a15.47 15.47 0 0 0 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1C10.07 21 3 13.93 3 5c0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.24.2 2.45.57 3.57.11.35.03.74-.25 1.02z" />
                              </svg>
                            </span>
                            <span>{{ formatStamp(item.at) }}</span>
                          </p>
                        </button>
                        <p v-if="selectedContactRecentMessages.length === 0" class="text-xs text-base-content/55">
                          No messages yet.
                        </p>
                      </div>
                    </section>
                  </div>
                </div>

                <div v-else class="flex h-full items-center justify-center text-sm text-base-content/60">
                  No contact selected.
                </div>
              </article>
            </div>
            </section>

            <section v-else-if="selectedTab === 'communications' && peopleLeftMode === 'contacts'" class="flex h-full min-h-0 flex-col gap-3">
            <div class="mb-1 flex justify-end">
              <div class="join">
                <button class="btn btn-sm join-item btn-primary" @click="peopleLeftMode = 'contacts'">Contacts</button>
                <button class="btn btn-sm join-item btn-ghost" @click="peopleLeftMode = 'calendar'">Calendar</button>
              </div>
            </div>
            <div class="grid h-full min-h-0 flex-1 gap-0 md:grid-cols-[220px_minmax(0,1fr)_320px]">
              <aside class="h-full min-h-0 border-r border-base-300 flex flex-col">
                <div class="sticky top-0 z-20 border-b border-base-300 bg-base-100 p-2">
                  <div class="mb-2 flex items-center gap-1">
                    <button
                      class="btn btn-xs flex-1"
                      :class="peopleListMode === 'contacts' ? 'btn-primary' : 'btn-ghost'"
                      @click="peopleListMode = 'contacts'"
                    >
                      Contacts
                    </button>
                    <button
                      class="btn btn-xs flex-1"
                      :class="peopleListMode === 'deals' ? 'btn-primary' : 'btn-ghost'"
                      @click="peopleListMode = 'deals'"
                    >
                      Deals
                    </button>
                  </div>
                  <div class="flex items-center gap-1">
                    <input
                      v-model="peopleSearch"
                      type="text"
                      class="input input-bordered input-sm w-full"
                      :placeholder="peopleListMode === 'contacts' ? 'Search contacts' : 'Search deals'"
                    >

                    <div class="dropdown dropdown-end">
                      <button
                        tabindex="0"
                        class="btn btn-ghost btn-sm btn-square"
                        :title="peopleListMode === 'contacts' ? 'Sort contacts' : 'Sort deals'"
                      >
                        <svg viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                          <path d="M3 5h18v2H3zm3 6h12v2H6zm4 6h4v2h-4z" />
                        </svg>
                      </button>

                      <div tabindex="0" class="dropdown-content z-20 mt-2 w-52 rounded-xl border border-base-300 bg-base-100 p-2 shadow-lg">
                        <template v-if="peopleListMode === 'contacts'">
                          <p class="px-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-base-content/55">Sort contacts</p>
                          <button
                            v-for="option in peopleSortOptions"
                            :key="`people-sort-${option.value}`"
                            class="btn btn-ghost btn-sm w-full justify-between"
                            @click="peopleSortMode = option.value"
                          >
                            <span>{{ option.label }}</span>
                            <span v-if="peopleSortMode === option.value">✓</span>
                          </button>
                        </template>
                        <p v-else class="px-2 py-1 text-xs text-base-content/60">Deals are sorted by title.</p>
                      </div>
                    </div>
                  </div>
                </div>

                <div class="min-h-0 flex-1 space-y-1.5 overflow-y-auto p-2">
                  <button
                    v-if="peopleListMode === 'contacts'"
                    v-for="thread in peopleContactList"
                    :key="thread.id"
                    class="w-full rounded-xl border border-base-300 px-2 py-2 text-left transition hover:bg-base-200/60"
                    :class="selectedCommThreadId === thread.id ? 'border-primary bg-primary/5' : ''"
                    @click="openCommunicationThread(thread.contact)"
                  >
                    <div class="flex items-start gap-2">
                      <div class="avatar shrink-0">
                        <div class="h-8 w-8 rounded-full ring-1 ring-base-300/70">
                          <img :src="thread.avatar" :alt="thread.contact">
                        </div>
                      </div>

                      <div class="min-w-0 flex-1">
                        <div class="flex items-start justify-between gap-2">
                          <p class="truncate text-xs font-semibold">{{ thread.contact }}</p>
                          <span class="shrink-0 text-[10px] text-base-content/55">{{ formatThreadTime(thread.lastAt) }}</span>
                        </div>
                        <div class="mt-0.5 flex items-center gap-2">
                          <p class="min-w-0 flex-1 truncate text-[11px] text-base-content/75">{{ thread.lastText }}</p>
                          <span
                            class="inline-block h-2 w-2 rounded-full"
                            :class="
                              threadTone(thread) === 'event'
                                ? 'bg-red-500'
                                : threadTone(thread) === 'recommendation'
                                  ? 'bg-violet-500'
                                  : threadTone(thread) === 'message'
                                    ? 'bg-blue-500'
                                    : 'bg-base-300'
                            "
                          />
                        </div>
                      </div>
                    </div>
                  </button>

                  <button
                    v-if="peopleListMode === 'deals'"
                    v-for="deal in peopleDealList"
                    :key="deal.id"
                    class="w-full rounded-xl border border-base-300 px-2 py-2 text-left transition hover:bg-base-200/60"
                    :class="selectedDealId === deal.id ? 'border-primary bg-primary/5' : ''"
                    @click="openDealThread(deal)"
                  >
                    <div class="flex items-start justify-between gap-2">
                      <p class="truncate text-xs font-semibold">{{ deal.title }}</p>
                      <span class="shrink-0 text-[10px] text-base-content/55">{{ deal.amount }}</span>
                    </div>
                    <p class="mt-0.5 truncate text-[11px] text-base-content/75">{{ deal.company }} · {{ deal.stage }}</p>
                    <p class="mt-0.5 truncate text-[11px] text-base-content/60">{{ deal.nextStep }}</p>
                  </button>

                  <p v-if="peopleListMode === 'contacts' && peopleContactList.length === 0" class="px-1 py-2 text-xs text-base-content/55">
                    No contacts found.
                  </p>
                  <p v-if="peopleListMode === 'deals' && peopleDealList.length === 0" class="px-1 py-2 text-xs text-base-content/55">
                    No deals found.
                  </p>
                </div>
              </aside>

              <article class="h-full min-h-0 border-r border-base-300 flex flex-col">
                <div v-if="false" class="p-3">
                  <div class="grid grid-cols-[auto_1fr_auto] items-center gap-2">
                    <div class="flex items-center gap-1">
                      <button class="btn btn-xs" @click="setToday">Today</button>
                      <button class="btn btn-xs btn-ghost" @click="shiftCalendar(-1)">←</button>
                      <button class="btn btn-xs btn-ghost" @click="shiftCalendar(1)">→</button>
                    </div>

                    <div class="text-center text-sm font-medium">
                      {{ calendarPeriodLabel }}
                    </div>

                    <div class="justify-self-end">
                      <select v-model="calendarView" class="select select-bordered select-xs w-36">
                        <option
                          v-for="option in calendarViewOptions"
                          :key="`workspace-right-calendar-view-${option.value}`"
                          :value="option.value"
                        >
                          {{ option.label }}
                        </option>
                      </select>
                    </div>
                  </div>

                  <div v-if="calendarView === 'month'" class="mt-3 space-y-1">
                    <div class="grid grid-cols-7 gap-1 text-center text-xs font-semibold text-base-content/60">
                      <span>Sun</span>
                      <span>Mon</span>
                      <span>Tue</span>
                      <span>Wed</span>
                      <span>Thu</span>
                      <span>Fri</span>
                      <span>Sat</span>
                    </div>

                    <div class="grid grid-cols-7 gap-1">
                      <button
                        v-for="cell in monthCells"
                        :key="`workspace-right-month-${cell.key}`"
                        class="min-h-24 rounded-lg border p-1 text-left"
                        :class="[
                          cell.inMonth ? 'border-base-300 bg-base-100' : 'border-base-200 bg-base-200/40 text-base-content/40',
                          selectedDateKey === cell.key ? 'border-primary bg-primary/5' : '',
                        ]"
                        @click="pickDate(cell.key)"
                      >
                        <p class="mb-1 text-xs font-semibold">{{ cell.day }}</p>
                        <button
                          v-for="event in cell.events.slice(0, 2)"
                          :key="`workspace-right-month-event-${event.id}`"
                          class="block w-full truncate text-left text-[10px] text-base-content/70 hover:underline"
                          @click.stop="openThreadFromCalendarItem(event)"
                        >
                          {{ formatTime(event.start) }} {{ event.title }}
                        </button>
                      </button>
                    </div>
                  </div>

                  <div v-else-if="calendarView === 'week'" class="mt-3 space-y-2">
                    <article
                      v-for="day in weekDays"
                      :key="`workspace-right-week-${day.key}`"
                      class="rounded-xl border border-base-300 p-3"
                      :class="selectedDateKey === day.key ? 'border-primary bg-primary/5' : ''"
                      @click="pickDate(day.key)"
                    >
                      <p class="mb-2 text-sm font-semibold">{{ day.label }} {{ day.day }}</p>
                      <div class="space-y-1">
                        <button
                          v-for="event in day.events"
                          :key="`workspace-right-week-event-${event.id}`"
                          class="block w-full rounded bg-base-200 px-2 py-1 text-left text-xs hover:bg-base-300/80"
                          @click.stop="openThreadFromCalendarItem(event)"
                        >
                          {{ formatTime(event.start) }} - {{ event.title }} ({{ event.contact }})
                        </button>
                        <p v-if="day.events.length === 0" class="text-xs text-base-content/50">No events</p>
                      </div>
                    </article>
                  </div>

                  <div v-else-if="calendarView === 'day'" class="mt-3 space-y-2">
                    <button
                      v-for="event in selectedDayEvents"
                      :key="`workspace-right-day-event-${event.id}`"
                      class="block w-full rounded-xl border border-base-300 p-3 text-left hover:bg-base-200/60"
                      @click="openThreadFromCalendarItem(event)"
                    >
                      <p class="font-medium">{{ event.title }}</p>
                      <p class="text-xs text-base-content/60">{{ event.contact }}</p>
                      <p class="text-xs text-base-content/60">{{ formatTime(event.start) }} - {{ formatTime(event.end) }}</p>
                      <p class="mt-1 text-sm text-base-content/80">{{ event.note }}</p>
                    </button>
                    <p v-if="selectedDayEvents.length === 0" class="text-sm text-base-content/60">No events on this day.</p>
                  </div>

                  <div v-else-if="calendarView === 'year'" class="mt-3 grid gap-2 sm:grid-cols-2 xl:grid-cols-3">
                    <button
                      v-for="item in yearMonths"
                      :key="`workspace-right-year-${item.monthIndex}`"
                      class="rounded-xl border border-base-300 p-3 text-left transition hover:border-primary/50 hover:bg-primary/5"
                      @click="openYearMonth(item.monthIndex)"
                    >
                      <p class="font-medium">{{ item.label }}</p>
                      <p class="text-xs text-base-content/60">{{ item.count }} events</p>
                      <p v-if="item.first" class="mt-1 text-xs text-base-content/70">
                        {{ formatDay(item.first.start) }} · {{ item.first.title }}
                      </p>
                    </button>
                  </div>

                  <div v-else class="mt-3 space-y-2">
                    <button
                      v-for="event in sortedEvents"
                      :key="`workspace-right-agenda-${event.id}`"
                      class="block w-full rounded-xl border border-base-300 p-3 text-left hover:bg-base-200/60"
                      @click="openThreadFromCalendarItem(event)"
                    >
                      <p class="font-medium">{{ event.title }}</p>
                      <p class="text-xs text-base-content/60">{{ event.contact }}</p>
                      <p class="text-xs text-base-content/60">{{ formatDay(event.start) }} · {{ formatTime(event.start) }} - {{ formatTime(event.end) }}</p>
                      <p class="mt-1 text-sm text-base-content/80">{{ event.note }}</p>
                    </button>
                  </div>
                </div>

                <div v-else-if="selectedCommThread" class="relative flex h-full min-h-0 flex-col p-3">
                  <div class="mb-3 flex items-start justify-between gap-2 border-b border-base-300 pb-2">
                    <div>
                      <p class="font-medium">{{ selectedCommThread.contact }}</p>
                    </div>
                  </div>

                  <div class="mb-3 flex items-center justify-between gap-2">
                    <div class="flex flex-wrap gap-2">
                      <button
                        v-for="channel in commChannelTabs"
                        :key="`comm-tab-${channel}`"
                        class="btn btn-xs btn-square"
                        :class="selectedCommChannel === channel ? 'btn-primary' : 'btn-ghost'"
                        :title="channel"
                        @click="selectedCommChannel = channel"
                      >
                        <svg v-if="channelIcon(channel) === 'all'" viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                          <circle cx="7" cy="7" r="2.2" />
                          <circle cx="17" cy="7" r="2.2" />
                          <circle cx="7" cy="17" r="2.2" />
                          <circle cx="17" cy="17" r="2.2" />
                        </svg>
                        <svg v-else-if="channelIcon(channel) === 'telegram'" viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                          <path d="M9.04 15.51 8.7 20.27c.49 0 .7-.21.96-.46l2.3-2.2 4.77 3.49c.88.49 1.5.23 1.74-.81l3.15-14.77.01-.01c.29-1.35-.49-1.88-1.35-1.56L1.74 11.08c-1.28.5-1.26 1.22-.22 1.54l4.74 1.48L17.3 7.03c.52-.34 1-.15.61.19" />
                        </svg>
                        <svg v-else-if="channelIcon(channel) === 'whatsapp'" viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                          <path d="M20 3.99A9.94 9.94 0 0 0 12.01 1C6.49 1 2 5.49 2 11c0 1.76.46 3.49 1.33 5.03L2 23l7.17-1.88A9.95 9.95 0 0 0 12 21h.01c5.51 0 9.99-4.49 9.99-10.01 0-2.67-1.04-5.18-2.99-7m-7.99 15.32h-.01a8.3 8.3 0 0 1-4.23-1.16l-.3-.18-4.26 1.12 1.14-4.15-.2-.32a8.28 8.28 0 0 1-1.27-4.4c0-4.58 3.73-8.31 8.32-8.31a8.27 8.27 0 0 1 5.88 2.44 8.25 8.25 0 0 1 2.43 5.87c0 4.59-3.73 8.32-8.31 8.32m4.56-6.23c-.25-.12-1.49-.74-1.73-.82-.23-.09-.4-.12-.57.12s-.66.82-.81.99-.3.18-.55.06a6.7 6.7 0 0 1-1.97-1.21 7.43 7.43 0 0 1-1.38-1.71c-.14-.24-.01-.37.1-.49.11-.11.24-.3.36-.45.12-.14.16-.24.25-.39.08-.18.05-.3-.02-.42-.07-.12-.56-1.35-.77-1.85-.2-.48-.41-.41-.57-.42h-.48c-.16 0-.42.06-.64.3-.22.24-.84.82-.84 2s.86 2.31.98 2.48c.12.16 1.69 2.57 4.09 3.6.57.24 1.01.38 1.36.48.58.18 1.11.15 1.52.09.46-.06 1.49-.61 1.7-1.19.21-.58.21-1.09.15-1.19-.06-.11-.23-.17-.48-.3" />
                        </svg>
                        <svg v-else-if="channelIcon(channel) === 'instagram'" viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                          <path d="M7 2h10a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H7a5 5 0 0 1-5-5V7a5 5 0 0 1 5-5m10 2H7a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3m-5 3.5A4.5 4.5 0 1 1 7.5 12 4.5 4.5 0 0 1 12 7.5m0 2A2.5 2.5 0 1 0 14.5 12 2.5 2.5 0 0 0 12 9.5m4.8-3.2a1.2 1.2 0 1 1-1.2 1.2 1.2 1.2 0 0 1 1.2-1.2" />
                        </svg>
                        <svg v-else-if="channelIcon(channel) === 'email'" viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                          <path d="M20 4H4a2 2 0 0 0-2 2v.4l10 5.6 10-5.6V6a2 2 0 0 0-2-2m0 4.2-7.4 4.14a1.25 1.25 0 0 1-1.2 0L4 8.2V18a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2z" />
                        </svg>
                        <svg v-else viewBox="0 0 24 24" class="h-4 w-4 fill-current">
                          <path d="M6.62 10.79a15.47 15.47 0 0 0 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1C10.07 21 3 13.93 3 5c0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.24.2 2.45.57 3.57.11.35.03.74-.25 1.02z" />
                        </svg>
                      </button>
                    </div>

                    <button
                      class="btn btn-ghost btn-sm max-w-[320px] justify-start rounded-lg border border-base-300"
                      @click="rightSidebarMode = 'pinned'"
                    >
                      <span class="shrink-0 text-xs font-semibold">Pinned {{ selectedCommPinnedStream.length }}</span>
                      <span class="truncate text-xs text-base-content/70">{{ latestPinnedLabel }}</span>
                    </button>
                  </div>

                  <div class="min-h-0 flex-1 space-y-2 overflow-y-auto pr-1 pb-3">
                    <div v-for="entry in threadStreamItems" :key="entry.id">
                      <div v-if="entry.kind === 'call'" class="flex justify-center">
                        <div class="call-wave-card w-full max-w-[460px] rounded-2xl border border-base-300 px-4 py-3 text-center">
                          <div class="mb-2 flex items-center justify-center gap-2">
                            <button class="btn btn-xs btn-outline" @click="toggleCallTranscript(entry.item.id)">
                              <svg viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M8 5v14l11-7z" />
                              </svg>
                            </button>
                            <span class="text-xs text-base-content/70">Transcript</span>
                          </div>
                          <div class="wave-bars mb-2">
                            <span v-for="n in 12" :key="`wave-${entry.item.id}-${n}`" :style="{ animationDelay: `${n * 0.08}s` }" />
                          </div>
                          <p class="mt-1 text-xs text-base-content/60">
                            <span>{{ entry.item.direction === "out" ? "↗" : "↙" }}</span>
                            <span class="mx-1">·</span>
                            <span>{{ formatStamp(entry.item.at) }}</span>
                            <span v-if="entry.item.duration"> · {{ entry.item.duration }}</span>
                          </p>
                          <div v-if="isCallTranscriptOpen(entry.item.id)" class="mt-2 rounded-xl border border-base-300 bg-base-100/70 p-2 text-left">
                            <p
                              v-for="(line, idx) in (entry.item.transcript ?? [entry.item.text])"
                              :key="`transcript-${entry.item.id}-${idx}`"
                              class="text-xs leading-relaxed text-base-content/80"
                            >
                              {{ line }}
                            </p>
                          </div>
                        </div>
                      </div>

                      <div v-else-if="entry.kind === 'eventAlert'" class="flex justify-center">
                        <article class="w-full max-w-[460px] rounded-xl border border-error/45 bg-error/10 p-3 text-center">
                          <p class="text-[11px] font-semibold uppercase tracking-wide text-error/80">Event in 15 minutes</p>
                          <p class="mt-1 text-sm font-semibold text-base-content">{{ entry.event.title }}</p>
                          <p class="mt-1 text-xs text-base-content/75">{{ formatTime(entry.event.start) }} · {{ entry.event.contact }}</p>
                          <button class="btn btn-xs btn-outline mt-2" @click="openEventFromCommunication(entry.event)">Open calendar</button>
                        </article>
                      </div>

                      <div v-else-if="entry.kind === 'recommendation'" class="flex justify-center">
                        <article class="w-full max-w-[460px] rounded-xl border border-base-300 bg-base-100 p-3">
                          <p class="text-sm">{{ entry.card.text }}</p>

                          <div class="mt-2 rounded-lg border border-base-300 bg-base-200/30 p-2">
                            <p class="text-xs font-semibold uppercase tracking-wide text-base-content/70">{{ entry.card.proposal.title }}</p>
                            <p
                              v-for="line in entry.card.proposal.details"
                              :key="`${entry.card.id}-${line}`"
                              class="mt-1 text-xs text-base-content/80"
                            >
                              {{ line }}
                            </p>
                          </div>

                          <div v-if="entry.card.decision === 'pending'" class="mt-2 flex gap-2">
                            <button class="btn btn-xs flex-1" @click="decideFeedCard(entry.card, 'accepted')">Yes</button>
                            <button class="btn btn-xs btn-outline flex-1" @click="decideFeedCard(entry.card, 'rejected')">No</button>
                          </div>
                          <p v-else class="mt-2 text-xs text-base-content/70">{{ entry.card.decisionNote }}</p>
                        </article>
                      </div>

                      <div
                        v-else
                        class="flex"
                        :class="entry.item.direction === 'out' ? 'justify-end' : 'justify-start'"
                      >
                        <div class="max-w-[88%] rounded-xl border border-base-300 p-3" :class="entry.item.direction === 'out' ? 'bg-base-200' : 'bg-base-100'">
                          <p class="text-sm">{{ entry.item.text }}</p>
                          <p class="mt-1 text-xs text-base-content/60">
                            <span class="mr-1 inline-flex h-4 w-4 items-center justify-center align-middle">
                              <svg v-if="channelIcon(entry.item.channel) === 'telegram'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M9.04 15.51 8.7 20.27c.49 0 .7-.21.96-.46l2.3-2.2 4.77 3.49c.88.49 1.5.23 1.74-.81l3.15-14.77.01-.01c.29-1.35-.49-1.88-1.35-1.56L1.74 11.08c-1.28.5-1.26 1.22-.22 1.54l4.74 1.48L17.3 7.03c.52-.34 1-.15.61.19" />
                              </svg>
                              <svg v-else-if="channelIcon(entry.item.channel) === 'whatsapp'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M20 3.99A9.94 9.94 0 0 0 12.01 1C6.49 1 2 5.49 2 11c0 1.76.46 3.49 1.33 5.03L2 23l7.17-1.88A9.95 9.95 0 0 0 12 21h.01c5.51 0 9.99-4.49 9.99-10.01 0-2.67-1.04-5.18-2.99-7m-7.99 15.32h-.01a8.3 8.3 0 0 1-4.23-1.16l-.3-.18-4.26 1.12 1.14-4.15-.2-.32a8.28 8.28 0 0 1-1.27-4.4c0-4.58 3.73-8.31 8.32-8.31a8.27 8.27 0 0 1 5.88 2.44 8.25 8.25 0 0 1 2.43 5.87c0 4.59-3.73 8.32-8.31 8.32m4.56-6.23c-.25-.12-1.49-.74-1.73-.82-.23-.09-.4-.12-.57.12s-.66.82-.81.99-.3.18-.55.06a6.7 6.7 0 0 1-1.97-1.21 7.43 7.43 0 0 1-1.38-1.71c-.14-.24-.01-.37.1-.49.11-.11.24-.3.36-.45.12-.14.16-.24.25-.39.08-.18.05-.3-.02-.42-.07-.12-.56-1.35-.77-1.85-.2-.48-.41-.41-.57-.42h-.48c-.16 0-.42.06-.64.3-.22.24-.84.82-.84 2s.86 2.31.98 2.48c.12.16 1.69 2.57 4.09 3.6.57.24 1.01.38 1.36.48.58.18 1.11.15 1.52.09.46-.06 1.49-.61 1.7-1.19.21-.58.21-1.09.15-1.19-.06-.11-.23-.17-.48-.3" />
                              </svg>
                              <svg v-else-if="channelIcon(entry.item.channel) === 'instagram'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M7 2h10a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H7a5 5 0 0 1-5-5V7a5 5 0 0 1 5-5m10 2H7a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3m-5 3.5A4.5 4.5 0 1 1 7.5 12 4.5 4.5 0 0 1 12 7.5m0 2A2.5 2.5 0 1 0 14.5 12 2.5 2.5 0 0 0 12 9.5m4.8-3.2a1.2 1.2 0 1 1-1.2 1.2 1.2 1.2 0 0 1 1.2-1.2" />
                              </svg>
                              <svg v-else-if="channelIcon(entry.item.channel) === 'email'" viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M20 4H4a2 2 0 0 0-2 2v.4l10 5.6 10-5.6V6a2 2 0 0 0-2-2m0 4.2-7.4 4.14a1.25 1.25 0 0 1-1.2 0L4 8.2V18a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2z" />
                              </svg>
                              <svg v-else viewBox="0 0 24 24" class="h-3.5 w-3.5 fill-current">
                                <path d="M6.62 10.79a15.47 15.47 0 0 0 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1C10.07 21 3 13.93 3 5c0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.24.2 2.45.57 3.57.11.35.03.74-.25 1.02z" />
                              </svg>
                            </span>
                            <span>{{ formatStamp(entry.item.at) }}</span>
                          </p>
                        </div>
                      </div>
                    </div>
                  </div>

                  <div class="sticky bottom-0 z-10 mt-3 border-t border-base-300 bg-base-100/95 pt-2 backdrop-blur">
                    <div class="flex items-center gap-2">
                      <input
                        v-model="commDraft"
                        type="text"
                        class="input input-bordered input-sm w-full"
                        placeholder="Type a message..."
                        :disabled="commSending"
                        @keyup.enter="sendCommMessage"
                      >
                      <button class="btn btn-sm btn-primary" :disabled="commSending || !commDraft.trim()" @click="sendCommMessage">
                        {{ commSending ? "..." : "Send" }}
                      </button>
                    </div>
                  </div>
                </div>

                <div v-else class="flex h-full items-center justify-center text-sm text-base-content/60">
                  No communication history.
                </div>
              </article>

              <aside class="h-full min-h-0">
                <div v-if="selectedWorkspaceContact" class="flex h-full min-h-0 flex-col p-3">
                  <div class="mb-3 flex items-start justify-between gap-2 border-b border-base-300 pb-2">
                    <div>
                      <p class="font-medium">{{ selectedWorkspaceContact.name }}</p>
                      <p class="text-xs text-base-content/60">
                        {{ selectedWorkspaceContact.company }} · {{ selectedWorkspaceContact.location }}, {{ selectedWorkspaceContact.country }}
                      </p>
                      <p v-if="rightSidebarMode === 'pinned'" class="mt-1 text-xs text-base-content/55">
                        Pinned {{ selectedCommPinnedStream.length }}
                      </p>
                    </div>
                    <button
                      v-if="rightSidebarMode === 'pinned'"
                      class="btn btn-ghost btn-xs btn-square"
                      title="Close pinned"
                      @click="rightSidebarMode = 'summary'"
                    >
                      ×
                    </button>
                  </div>

                  <div class="min-h-0 flex-1 overflow-y-auto pr-1">
                  <div v-if="rightSidebarMode === 'pinned'" class="space-y-2">
                    <article
                      v-for="item in selectedCommPinnedStream"
                      :key="item.id"
                      class="rounded-lg border border-base-300 px-3 py-2"
                    >
                      <template v-if="item.kind === 'pin'">
                        <p class="text-[11px] uppercase tracking-wide text-base-content/55">Note</p>
                        <p class="mt-1 text-xs leading-relaxed text-base-content/85">{{ item.text }}</p>
                      </template>
                      <template v-else>
                        <p class="text-[11px] uppercase tracking-wide text-base-content/55">Event</p>
                        <button class="mt-1 w-full text-left" @click="openEventFromCommunication(item.event)">
                          <p class="text-sm font-medium">{{ item.event.title }}</p>
                          <p class="text-xs text-base-content/65">
                            {{ formatDay(item.event.start) }} · {{ formatTime(item.event.start) }}
                          </p>
                        </button>
                      </template>
                    </article>

                    <p v-if="selectedCommPinnedStream.length === 0" class="text-xs text-base-content/55">
                      No pinned notes or events.
                    </p>
                  </div>

                  <template v-else>
                    <div v-if="selectedWorkspaceDeal" class="mt-3 rounded-xl border border-base-300 bg-base-200/30 p-2.5">
                      <p class="text-[10px] font-semibold uppercase tracking-wide text-base-content/55">Deal</p>
                      <p class="mt-1 text-sm font-medium">{{ selectedWorkspaceDeal.title }}</p>
                      <p class="mt-1 text-[11px] text-base-content/65">{{ selectedWorkspaceDeal.company }} · {{ selectedWorkspaceDeal.stage }}</p>
                      <p class="mt-1 text-[11px] text-base-content/80">{{ selectedWorkspaceDeal.nextStep }}</p>
                    </div>

                    <div class="mt-3">
                      <p class="mb-2 text-xs font-semibold uppercase tracking-wide text-base-content/60">Summary</p>
                      <ContactCollaborativeEditor
                        :key="`contact-summary-${selectedWorkspaceContact.id}`"
                        v-model="selectedWorkspaceContact.description"
                        :room="`crm-contact-${selectedWorkspaceContact.id}`"
                        placeholder="Contact summary..."
                      />
                    </div>
                  </template>
                  </div>
                </div>

                <div v-else class="flex h-full items-center justify-center text-sm text-base-content/60">
                  No contact selected.
                </div>
              </aside>
            </div>
            </section>

            <section v-else-if="selectedTab === 'documents'" class="flex h-full min-h-0 flex-col gap-3">
            <div class="rounded-xl border border-base-300 p-3">
              <div class="grid gap-2 md:grid-cols-[1fr_220px]">
                <label class="form-control">
                  <span class="label-text text-xs uppercase tracking-wide text-base-content/60">Search docs</span>
                  <input
                    v-model="documentSearch"
                    type="text"
                    class="input input-bordered input-sm"
                    placeholder="Title, owner, scope, content"
                  >
                </label>

                <label class="form-control">
                  <span class="label-text text-xs uppercase tracking-wide text-base-content/60">Type</span>
                  <select v-model="selectedDocumentType" class="select select-bordered select-sm">
                    <option v-for="item in documentTypes" :key="`doc-type-${item}`" :value="item">{{ item }}</option>
                  </select>
                </label>
              </div>
            </div>

            <div class="grid min-h-0 flex-1 gap-0 md:grid-cols-12">
              <aside class="min-h-0 border-r border-base-300 md:col-span-4 flex flex-col">
                <div class="min-h-0 flex-1 space-y-2 overflow-y-auto p-2">
                  <button
                    v-for="doc in filteredDocuments"
                    :key="doc.id"
                    class="w-full rounded-xl border border-base-300 p-3 text-left transition hover:bg-base-200/60"
                    :class="selectedDocumentId === doc.id ? 'border-primary bg-primary/5' : ''"
                    @click="selectedDocumentId = doc.id"
                  >
                    <p class="font-medium">{{ doc.title }}</p>
                    <p class="mt-1 text-xs text-base-content/60">{{ doc.type }} · {{ doc.owner }}</p>
                    <p class="mt-1 line-clamp-2 text-xs text-base-content/75">{{ doc.summary }}</p>
                    <p class="mt-1 text-xs text-base-content/55">Updated {{ formatStamp(doc.updatedAt) }}</p>
                  </button>
                </div>
              </aside>

              <article class="min-h-0 md:col-span-8 flex flex-col">
                <div v-if="selectedDocument" class="flex h-full min-h-0 flex-col p-3 md:p-4">
                  <div class="border-b border-base-300 pb-2">
                    <p class="font-medium">{{ selectedDocument.title }}</p>
                    <p class="text-xs text-base-content/60">
                      {{ selectedDocument.type }} · {{ selectedDocument.scope }} · {{ selectedDocument.owner }}
                    </p>
                    <p class="mt-1 text-sm text-base-content/80">{{ selectedDocument.summary }}</p>
                  </div>

                  <div class="mt-3 min-h-0 flex-1 overflow-y-auto">
                    <ContactCollaborativeEditor
                      :key="`doc-editor-${selectedDocument.id}`"
                      v-model="selectedDocument.body"
                      :room="`crm-doc-${selectedDocument.id}`"
                      placeholder="Describe policy, steps, rules, and exceptions..."
                    />
                  </div>
                </div>

                <div v-else class="flex h-full items-center justify-center text-sm text-base-content/60">
                  No document selected.
                </div>
              </article>
            </div>
            </section>

          </div>

        </div>
      </main>
    </div>

    <nav class="dock-fixed pointer-events-none fixed left-1/2 z-40 -translate-x-1/2">
      <div class="dock-nav pointer-events-auto inline-flex items-center gap-1 rounded-2xl border border-base-300 px-2 py-1.5">
        <button
          v-for="tab in tabs"
          :key="`dock-${tab.id}`"
          class="btn btn-ghost btn-sm btn-square"
          :class="selectedTab === tab.id ? 'btn-primary' : ''"
          :title="tab.label"
          @click="selectedTab = tab.id"
        >
          <svg v-if="tab.id === 'communications'" viewBox="0 0 24 24" class="h-4 w-4 fill-current">
            <path d="M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2" />
          </svg>
          <svg v-else-if="tab.id === 'documents'" viewBox="0 0 24 24" class="h-4 w-4 fill-current">
            <path d="M6 2h9l5 5v15a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2m8 1.5V8h4.5z" />
          </svg>
          <svg v-else viewBox="0 0 24 24" class="h-4 w-4 fill-current">
            <path d="M3 3h18v4H3zm0 7h12v4H3zm0 7h18v4H3z" />
          </svg>
        </button>
      </div>
    </nav>
    </template>
  </div>
</template>

<style scoped>
.pilot-shell {
  background:
    radial-gradient(circle at 10% -10%, rgba(124, 144, 255, 0.25), transparent 40%),
    radial-gradient(circle at 85% 110%, rgba(88, 101, 242, 0.2), transparent 45%),
    #151821;
  color: #f5f7ff;
}

.pilot-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  padding: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(8, 10, 16, 0.2);
}

.pilot-settings-panel {
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(8, 10, 16, 0.34);
  padding: 10px;
}

.pilot-threads {
  padding: 10px 10px 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.pilot-threads-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.pilot-timeline {
  padding: 10px 8px;
}

.pilot-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 8px 6px;
  border-radius: 10px;
}

.pilot-row:hover {
  background: rgba(255, 255, 255, 0.04);
}

.pilot-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: #e6ebff;
  background: linear-gradient(135deg, #5865f2, #7c90ff);
}

.pilot-avatar-user {
  background: linear-gradient(135deg, #2a9d8f, #38b2a7);
}

.pilot-body {
  min-width: 0;
  width: 100%;
}

.pilot-meta {
  display: flex;
  align-items: center;
  gap: 8px;
}

.pilot-author {
  font-size: 13px;
  font-weight: 700;
  color: #f8f9ff;
}

.pilot-time {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.45);
}

.pilot-message-text {
  margin-top: 2px;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  color: rgba(255, 255, 255, 0.92);
}

.pilot-debug {
  display: grid;
  gap: 8px;
}

.pilot-debug-block {
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(9, 11, 19, 0.52);
  padding: 8px;
}

.pilot-debug-title {
  margin: 0 0 6px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(172, 187, 255, 0.95);
}

.pilot-debug-list {
  margin: 0;
  padding-left: 18px;
  display: grid;
  gap: 4px;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.82);
}

.pilot-tool-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 8px;
}

.pilot-tool-row {
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.06);
  padding: 7px;
}

.pilot-tool-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
  font-size: 11px;
}

.pilot-tool-head code {
  color: #cfd7ff;
}

.pilot-tool-status-ok {
  color: #6be2a1;
  font-weight: 700;
}

.pilot-tool-status-error {
  color: #ff8f8f;
  font-weight: 700;
}

.pilot-tool-io {
  margin: 0;
  font-size: 11px;
  line-height: 1.35;
  color: rgba(255, 255, 255, 0.74);
}

.pilot-input-wrap {
  display: flex;
  gap: 8px;
  padding: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(11, 13, 21, 0.65);
}

.feed-chart-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  background:
    radial-gradient(circle at 20% 20%, rgba(30, 107, 255, 0.12), transparent 45%),
    radial-gradient(circle at 80% 80%, rgba(30, 107, 255, 0.08), transparent 45%),
    #f6f9ff;
  border-bottom: 1px solid rgba(30, 107, 255, 0.15);
}

.dock-nav {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(255, 255, 255, 0.86));
  backdrop-filter: blur(8px);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.1);
}

.dock-fixed {
  bottom: calc(0.75rem + env(safe-area-inset-bottom));
}

.feed-chart-bars {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  width: 100%;
  max-width: 280px;
  height: 100%;
}

.feed-chart-bars span {
  flex: 1 1 0;
  border-radius: 999px 999px 6px 6px;
  background: linear-gradient(180deg, rgba(30, 107, 255, 0.9), rgba(30, 107, 255, 0.35));
}

.feed-chart-pie {
  width: min(140px, 70%);
  aspect-ratio: 1;
  border-radius: 999px;
  background: conic-gradient(
    rgba(30, 107, 255, 0.92) 0 42%,
    rgba(30, 107, 255, 0.55) 42% 73%,
    rgba(30, 107, 255, 0.25) 73% 100%
  );
  box-shadow: 0 8px 24px rgba(30, 107, 255, 0.2);
}

.call-wave-card {
  background:
    radial-gradient(circle at 50% 0%, rgba(59, 130, 246, 0.14), transparent 50%),
    linear-gradient(180deg, rgba(59, 130, 246, 0.05), transparent);
}

.wave-bars {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 4px;
  height: 30px;
}

.wave-bars span {
  width: 4px;
  height: 18%;
  border-radius: 999px;
  background: rgba(30, 107, 255, 0.75);
  animation: wave-pulse 1.2s ease-in-out infinite;
}

@keyframes wave-pulse {
  0%, 100% {
    height: 20%;
    opacity: 0.45;
  }
  50% {
    height: 100%;
    opacity: 1;
  }
}
</style>
