<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import { apiGet, listEvents } from "@/api/client";
import { useBackgroundRefresh } from "@/composables/useBackgroundRefresh";
import { milestoneColor } from "@/utils/palette";
import { fmtRelativeDateTime } from "@/utils/dateFormat";
import type { Note } from "@/types/note";
import type { Task, TaskListResponse, TaskStatus } from "@/types/task";
import type { EventEntry } from "@/api/client";
import NoteCard from "@/components/NoteCard.vue";
import TaskCard from "@/components/TaskCard.vue";
import StatusBadge from "@/components/StatusBadge.vue";
import PriorityBadge from "@/components/PriorityBadge.vue";
import ChatPanel from "@/components/ChatPanel.vue";
import EventSlideOver from "@/components/EventSlideOver.vue";
import { useTasksStore } from "@/stores/tasks";
import { useChatStore } from "@/stores/chat";

// ─── Types ────────────────────────────────────────────────────────────────────

interface MilestoneSummary {
  id: number;
  title: string;
  status: string;
  pct: number;
  total: number;
  completed: number;
}

interface DashProject {
  id: number;
  title: string;
  status: string;
  updated_at: string;
  summary?: {
    task_counts: { todo?: number; in_progress?: number; done?: number };
    milestone_summary: MilestoneSummary[];
  };
}

// A recent item from the hero project (note or task — both come from /api/notes?all=true)
interface RecentItem {
  id: number;
  title: string;
  status: string | null;
  project_id: number | null;
  updated_at: string;
}

// ─── State ────────────────────────────────────────────────────────────────────

const loading = ref(true);
const tasksStore = useTasksStore();

// Hero project — most recently active project
const heroProject = ref<DashProject | null>(null);
const heroRecentItems = ref<RecentItem[]>([]);
const heroNextUp = ref<Task | null>(null);

// All other active projects (hero excluded)
const activeProjects = ref<DashProject[]>([]);

// Orphaned items (no project_id)
const orphanTasks = ref<Task[]>([]);
const orphanNotes = ref<Note[]>([]);
const inboxOpen = ref(true);

// Upcoming events (today + next 7 days)
const upcomingEvents = ref<EventEntry[]>([]);
const eventSlideOverOpen = ref(false);
const editingEvent = ref<EventEntry | null>(null);

// ─── Background refresh (no-flicker) ─────────────────────────────────────────
// Never touches `loading` so existing content stays on screen while fetching.

function _dateRange() {
  const today = new Date()
  const nextWeek = new Date(today)
  nextWeek.setDate(today.getDate() + 7)
  // Use full ISO strings so the server sees the correct UTC equivalent of
  // local midnight / end-of-day rather than a naive UTC-midnight guess.
  return {
    todayStr: today.toISOString(),
    nextWeekStr: nextWeek.toISOString(),
  }
}

function _backgroundRefresh() {
  if (document.hidden || loading.value) return
  const { todayStr, nextWeekStr } = _dateRange()
  Promise.allSettled([
    listEvents(todayStr, nextWeekStr),
    apiGet<TaskListResponse>('/api/tasks?no_project=true&sort=updated_at&order=desc&limit=8'),
    apiGet<{ notes: Note[] }>('/api/notes?type=note&no_project=true&sort=updated_at&order=desc&limit=6'),
  ]).then(([eventsRes, tasksRes, notesRes]) => {
    if (eventsRes.status === 'fulfilled') upcomingEvents.value = eventsRes.value
    if (tasksRes.status === 'fulfilled') orphanTasks.value = tasksRes.value.tasks
    if (notesRes.status === 'fulfilled') orphanNotes.value = notesRes.value.notes
  })
  if (heroProject.value) {
    apiGet<TaskListResponse>(
      `/api/tasks?project_id=${heroProject.value.id}&status=todo&sort=updated_at&order=desc&limit=1`
    )
      .then((r) => { heroNextUp.value = r.tasks[0] ?? null })
      .catch(() => {})
  }
}

// ─── Data loading ─────────────────────────────────────────────────────────────

onMounted(async () => {
  // Phase 1: projects list + cross-project recent items + orphaned items + events — all parallel
  const { todayStr, nextWeekStr } = _dateRange();

  const [projectsRes, recentRes, orphanTasksRes, orphanNotesRes, eventsRes] =
    await Promise.allSettled([
      apiGet<{ projects: DashProject[] }>("/api/projects?status=active"),
      apiGet<{ notes: RecentItem[] }>(
        "/api/notes?all=true&sort=updated_at&order=desc&limit=30"
      ),
      apiGet<TaskListResponse>(
        "/api/tasks?no_project=true&sort=updated_at&order=desc&limit=8"
      ),
      apiGet<{ notes: Note[] }>(
        "/api/notes?type=note&no_project=true&sort=updated_at&order=desc&limit=6"
      ),
      listEvents(todayStr, nextWeekStr),
    ]);

  // Determine hero project: the project whose item was most recently touched
  let heroId: number | null = null;
  if (recentRes.status === "fulfilled") {
    const withProject = recentRes.value.notes.find(
      (n) => n.project_id != null
    );
    heroId = withProject?.project_id ?? null;
  }

  if (projectsRes.status === "fulfilled") {
    const all = projectsRes.value.projects;
    const hero = all.find((p) => p.id === heroId) ?? all[0] ?? null;
    heroProject.value = hero;
    activeProjects.value = all.filter((p) => p.id !== hero?.id);
  }

  if (orphanTasksRes.status === "fulfilled")
    orphanTasks.value = orphanTasksRes.value.tasks;
  if (orphanNotesRes.status === "fulfilled")
    orphanNotes.value = orphanNotesRes.value.notes;
  if (eventsRes.status === "fulfilled")
    upcomingEvents.value = eventsRes.value;

  loading.value = false;

  // Focus chat input after data loads
  chatPanelRef.value?.focus();
  loadProjects();

});

useBackgroundRefresh(_backgroundRefresh, 90_000, () => !loading.value);

async function loadProjects() {
  if (!heroProject.value) return;
  const hid = heroProject.value.id;

  // Phase 2: hero details + all project summaries — parallel
  const [recentItemsRes, nextUpRes, heroSummaryRes] = await Promise.allSettled([
    apiGet<{ notes: RecentItem[] }>(
      `/api/notes?all=true&project_id=${hid}&sort=updated_at&order=desc&limit=5`
    ),
    apiGet<TaskListResponse>(
      `/api/tasks?project_id=${hid}&status=todo&sort=updated_at&order=desc&limit=1`
    ),
    apiGet<DashProject>(`/api/projects/${hid}`),
  ]);

  if (recentItemsRes.status === "fulfilled")
    heroRecentItems.value = recentItemsRes.value.notes;
  if (nextUpRes.status === "fulfilled")
    heroNextUp.value = nextUpRes.value.tasks[0] ?? null;
  if (heroSummaryRes.status === "fulfilled")
    heroProject.value = { ...heroProject.value!, ...heroSummaryRes.value };

  // Load summaries for remaining projects
  await Promise.allSettled(
    activeProjects.value.map(async (p) => {
      try {
        const full = await apiGet<DashProject>(`/api/projects/${p.id}`);
        const idx = activeProjects.value.findIndex((x) => x.id === p.id);
        if (idx !== -1)
          activeProjects.value[idx] = { ...activeProjects.value[idx], ...full };
      } catch {
        /* non-fatal */
      }
    })
  );
}

// ─── Status toggle (orphaned tasks) ──────────────────────────────────────────

function onStatusToggle(id: number, status: TaskStatus) {
  tasksStore.patchStatus(id, status).then((updated) => {
    if (updated.status === "done") {
      orphanTasks.value = orphanTasks.value.filter((t) => t.id !== id);
    } else {
      const idx = orphanTasks.value.findIndex((t) => t.id === id);
      if (idx !== -1) orphanTasks.value[idx] = updated;
    }
  });
}

// ─── Chat widget ──────────────────────────────────────────────────────────────

const chatPanelRef = ref<InstanceType<typeof ChatPanel> | null>(null);

function onFocusChatShortcut() {
  chatPanelRef.value?.focus();
}

onMounted(() => {
  document.addEventListener("shortcut:focus-chat", onFocusChatShortcut);
});
onUnmounted(() => {
  document.removeEventListener("shortcut:focus-chat", onFocusChatShortcut);
});

const chatStore = useChatStore();

chatStore.fetchStatus().then(() => {
  if (chatStore.defaultModel) chatStore.warmModel(chatStore.defaultModel);
});

const QUICK_ACTIONS = [
  "What's due today?",
  "Events this week?",
  "Any overdue tasks?",
  "My high priority tasks?",
];

async function onQuickAction(query: string) {
  await chatPanelRef.value?.send(query);
}

// ─── Upcoming events slide-over ───────────────────────────────────────────────

function openEvent(event: EventEntry) {
  editingEvent.value = event;
  eventSlideOverOpen.value = true;
}

function onEventUpdated(event: EventEntry) {
  const idx = upcomingEvents.value.findIndex((e) => e.id === event.id);
  if (idx !== -1) upcomingEvents.value[idx] = event;
  eventSlideOverOpen.value = false;
}

function onEventDeleted(id: number) {
  upcomingEvents.value = upcomingEvents.value.filter((e) => e.id !== id);
  eventSlideOverOpen.value = false;
}

function formatUpcomingTime(event: EventEntry): string {
  if (!event.start_dt) return "";
  return fmtRelativeDateTime(event.start_dt, event.all_day);
}
</script>

<template>
  <main class="home">

    <!-- ── Chat widget ─────────────────────────────────────────── -->
    <section class="chat-section">
      <div class="quick-actions">
        <button
          v-for="q in QUICK_ACTIONS"
          :key="q"
          class="quick-action-chip"
          :disabled="chatStore.streaming || !chatStore.chatReady"
          @click="onQuickAction(q)"
        >{{ q }}</button>
      </div>
      <ChatPanel ref="chatPanelRef" variant="widget" />
    </section>

    <!-- ── Upcoming events ────────────────────────────────────── -->
    <div v-if="!loading && upcomingEvents.length" class="upcoming-events-section">
      <div class="section-header">
        <h2>Upcoming</h2>
        <router-link to="/calendar" class="see-all">Calendar →</router-link>
      </div>
      <div class="upcoming-events-list">
        <button
          v-for="ev in upcomingEvents.slice(0, 6)"
          :key="ev.id"
          class="upcoming-event-card"
          @click="openEvent(ev)"
        >
          <span class="upcoming-event-dot" :style="ev.color ? { background: ev.color } : {}"></span>
          <span class="upcoming-event-body">
            <span class="upcoming-event-title">{{ ev.title }}</span>
            <span class="upcoming-event-time">{{ formatUpcomingTime(ev) }}</span>
            <span v-if="ev.location" class="upcoming-event-loc">{{ ev.location }}</span>
          </span>
        </button>
        <div v-if="upcomingEvents.length > 6" class="upcoming-events-more">
          +{{ upcomingEvents.length - 6 }} more —
          <router-link to="/calendar" class="see-all-inline">view all</router-link>
        </div>
      </div>
    </div>

    <!-- ── Skeleton while loading ─────────────────────────────── -->
    <template v-if="loading">
      <div class="skeleton-hero"></div>
      <div class="skeleton-grid">
        <div class="skeleton-card" v-for="i in 3" :key="i"></div>
      </div>
    </template>

    <template v-else>

      <!-- ── Hero: Last Active Project ──────────────────────── -->
      <div v-if="heroProject" class="hero-card">
        <div class="hero-top">
          <div class="hero-identity">
            <span class="hero-label">Last active</span>
            <router-link :to="`/projects/${heroProject.id}`" class="hero-title">
              {{ heroProject.title }}
            </router-link>
          </div>
          <router-link :to="`/workspace/${heroProject.id}`" class="btn-workspace-hero">
            ▶ Open Workspace
          </router-link>
        </div>

        <!-- Milestone bars -->
        <div
          v-if="heroProject.summary?.milestone_summary?.length"
          class="hero-milestones"
        >
          <div
            v-for="(ms, i) in heroProject.summary.milestone_summary
              .filter((m) => m.status !== 'archived')
              .slice(0, 3)"
            :key="ms.id"
            class="ms-row"
          >
            <span class="ms-label">{{ ms.title }}</span>
            <div class="ms-track">
              <div
                class="ms-fill"
                :style="{ width: ms.pct + '%', background: milestoneColor(i) }"
              ></div>
            </div>
            <span class="ms-pct">{{ Math.round(ms.pct) }}%</span>
          </div>
        </div>

        <!-- Recent items -->
        <div v-if="heroRecentItems.length" class="hero-recent">
          <span class="hero-section-label">Recent</span>
          <div class="hero-items">
            <router-link
              v-for="item in heroRecentItems"
              :key="item.id"
              :to="item.status != null ? `/tasks/${item.id}` : `/notes/${item.id}`"
              class="hero-item"
            >
              <span class="hero-item-icon">{{ item.status != null ? '◉' : '◈' }}</span>
              <span class="hero-item-title">{{ item.title || 'Untitled' }}</span>
              <StatusBadge
                v-if="item.status"
                :status="(item.status as TaskStatus)"
                class="hero-item-badge"
              />
            </router-link>
          </div>
        </div>

        <!-- Next up -->
        <div v-if="heroNextUp" class="hero-next-up">
          <span class="hero-section-label">Next up</span>
          <router-link :to="`/tasks/${heroNextUp.id}`" class="hero-next-link">
            <PriorityBadge :priority="heroNextUp.priority ?? 'none'" />
            {{ heroNextUp.title }}
          </router-link>
        </div>
      </div>

      <!-- ── Active Projects grid ────────────────────────────── -->
      <div v-if="activeProjects.length" class="projects-section">
        <div class="section-header">
          <h2>Projects</h2>
          <router-link to="/projects" class="see-all">See all →</router-link>
        </div>
        <div class="projects-grid">
          <div
            v-for="project in activeProjects"
            :key="project.id"
            class="project-card"
          >
            <div class="project-card-top">
              <router-link
                :to="`/projects/${project.id}`"
                class="project-card-title"
              >
                {{ project.title }}
              </router-link>
              <router-link
                :to="`/workspace/${project.id}`"
                class="btn-workspace-sm"
                title="Open Workspace"
              >▶</router-link>
            </div>

            <!-- Urgency badges -->
            <div class="project-urgency">
              <span
                v-if="(project.summary?.task_counts?.in_progress ?? 0) > 0"
                class="urgency-badge urgency-in-progress"
              >{{ project.summary!.task_counts.in_progress }} in progress</span>
              <span
                v-if="(project.summary?.task_counts?.todo ?? 0) > 0"
                class="urgency-badge urgency-todo"
              >{{ project.summary!.task_counts.todo }} todo</span>
              <span
                v-if="project.summary && !project.summary.task_counts.in_progress && !project.summary.task_counts.todo"
                class="urgency-badge urgency-clear"
              >All clear</span>
              <span v-if="!project.summary" class="urgency-badge urgency-loading">Loading…</span>
            </div>

            <!-- Milestone bars (up to 2) -->
            <template v-if="project.summary?.milestone_summary?.length">
              <div
                v-for="(ms, i) in project.summary.milestone_summary
                  .filter((m) => m.status !== 'archived')
                  .slice(0, 2)"
                :key="ms.id"
                class="ms-row"
              >
                <span class="ms-label">{{ ms.title }}</span>
                <div class="ms-track">
                  <div
                    class="ms-fill"
                    :style="{ width: ms.pct + '%', background: milestoneColor(i) }"
                  ></div>
                </div>
                <span class="ms-pct">{{ Math.round(ms.pct) }}%</span>
              </div>
            </template>
          </div>
        </div>
      </div>

      <!-- ── Inbox: orphaned items ───────────────────────────── -->
      <div
        v-if="orphanTasks.length || orphanNotes.length"
        class="inbox-section"
      >
        <button class="inbox-header" @click="inboxOpen = !inboxOpen">
          <span class="inbox-toggle">{{ inboxOpen ? '▼' : '▶' }}</span>
          <h2>
            Inbox
            <span class="inbox-count">{{ orphanTasks.length + orphanNotes.length }}</span>
          </h2>
          <span class="inbox-sub">Notes and tasks without a project</span>
        </button>
        <div v-if="inboxOpen" class="inbox-items">
          <TaskCard
            v-for="task in orphanTasks"
            :key="task.id"
            :task="task"
            compact
            @status-toggle="onStatusToggle"
          />
          <NoteCard
            v-for="note in orphanNotes"
            :key="note.id"
            :note="note"
          />
        </div>
      </div>

    </template>

  </main>

  <!-- Event slide-over -->
  <EventSlideOver
    v-if="eventSlideOverOpen"
    :event="editingEvent"
    initial-date=""
    @close="eventSlideOverOpen = false"
    @created="eventSlideOverOpen = false"
    @updated="onEventUpdated"
    @deleted="onEventDeleted"
  />
</template>

<style scoped>
.home {
  max-width: var(--page-max-width);
  margin: 2rem auto;
  padding: 0 var(--page-padding-x);
}

/* ─── Chat widget ────────────────────────────────────────────── */
.chat-section {
  max-width: 720px;
  margin: 0 auto 1.5rem;
}
.quick-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
}
.quick-action-chip {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-bg-secondary);
  color: var(--color-text);
  font-size: 0.8rem;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.quick-action-chip:hover:not(:disabled) {
  border-color: var(--color-primary);
  color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 8%, transparent);
}
.quick-action-chip:disabled { opacity: 0.4; cursor: default; }

/* ─── Skeleton loading ───────────────────────────────────────── */
.skeleton-hero {
  height: 180px;
  border-radius: var(--radius-lg);
  background: linear-gradient(90deg, var(--color-bg-secondary) 25%, var(--color-border) 50%, var(--color-bg-secondary) 75%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s ease infinite;
  margin-bottom: 1.75rem;
}
.skeleton-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.75rem;
}
.skeleton-card {
  height: 120px;
  border-radius: var(--radius-md);
  background: linear-gradient(90deg, var(--color-bg-secondary) 25%, var(--color-border) 50%, var(--color-bg-secondary) 75%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s ease infinite;
}
@keyframes skeleton-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ─── Hero card ──────────────────────────────────────────────── */
.hero-card {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.75rem;
  box-shadow: 0 2px 16px rgba(91, 74, 138, 0.08), 0 1px 4px rgba(0, 0, 0, 0.06);
}
.hero-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}
.hero-identity {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.hero-label {
  font-size: 0.7rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}
.hero-title {
  font-size: 1.4rem;
  font-weight: 500;
  color: var(--color-text);
  text-decoration: none;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
.hero-title:hover { color: var(--color-primary); }

.btn-workspace-hero {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 1.1rem;
  background: var(--gradient-cta);
  color: #fff;
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  white-space: nowrap;
  box-shadow: 0 1px 6px rgba(91, 74, 138, 0.3);
  transition: opacity 0.15s, box-shadow 0.15s;
  flex-shrink: 0;
}
.btn-workspace-hero:hover {
  opacity: 0.9;
  box-shadow: 0 3px 14px rgba(91, 74, 138, 0.45);
}

.hero-milestones { margin-bottom: 0.75rem; }

.hero-section-label {
  font-size: 0.68rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--color-text-muted);
  display: block;
  margin-bottom: 0.4rem;
}

.hero-recent { margin-bottom: 0.75rem; }
.hero-items {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.hero-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.5rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-text-secondary);
  font-size: 0.88rem;
  transition: background 0.12s, color 0.12s;
}
.hero-item:hover {
  background: color-mix(in srgb, var(--color-primary) 6%, transparent);
  color: var(--color-text);
}
.hero-item-icon { opacity: 0.45; font-size: 0.75rem; flex-shrink: 0; }
.hero-item-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hero-item-badge { flex-shrink: 0; }

.hero-next-up {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.hero-next-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--color-text);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
}
.hero-next-link:hover { color: var(--color-primary); }

/* ─── Projects grid ──────────────────────────────────────────── */
.projects-section { margin-bottom: 1.75rem; }
.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.75rem;
}
.section-header h2 { margin: 0; font-size: 1rem; font-weight: 500; }
.see-all { font-size: 0.85rem; color: var(--color-primary); text-decoration: none; }
.see-all:hover { text-decoration: underline; }

.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 0.75rem;
}
.project-card {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.85rem 1rem;
  transition: box-shadow 0.18s, border-color 0.15s, transform 0.18s;
}
.project-card:hover {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10);
  border-color: var(--color-primary);
  transform: translateY(-2px);
}
.project-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
  gap: 0.5rem;
}
.project-card-title {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--color-text);
  text-decoration: none;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.project-card-title:hover { color: var(--color-primary); }
.btn-workspace-sm {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
  color: var(--color-primary);
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-size: 0.75rem;
  flex-shrink: 0;
  transition: background 0.15s, color 0.15s;
}
.btn-workspace-sm:hover {
  background: var(--color-primary);
  color: #fff;
}

.project-urgency {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-bottom: 0.5rem;
}
.urgency-badge {
  font-size: 0.72rem;
  padding: 0.1rem 0.45rem;
  border-radius: var(--radius-pill);
  font-weight: 500;
}
.urgency-in-progress {
  background: color-mix(in srgb, #5B4A8A 15%, transparent);
  color: #5B4A8A;
}
.urgency-todo {
  background: color-mix(in srgb, var(--color-text-muted) 12%, transparent);
  color: var(--color-text-muted);
}
.urgency-clear {
  background: color-mix(in srgb, #22c55e 12%, transparent);
  color: #16a34a;
}
.urgency-loading { color: var(--color-text-muted); }

/* ─── Inbox ──────────────────────────────────────────────────── */
.inbox-section {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: 1.75rem;
}
.inbox-header {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.75rem 1rem;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  color: var(--color-text);
  transition: background 0.15s;
}
.inbox-header:hover { background: var(--color-bg-secondary); }
.inbox-toggle { font-size: 0.75rem; color: var(--color-text-muted); }
.inbox-header h2 {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.inbox-count {
  background: color-mix(in srgb, var(--color-text-muted) 15%, transparent);
  color: var(--color-text-muted);
  font-size: 0.75rem;
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius-pill);
}
.inbox-sub {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  margin-left: auto;
}
.inbox-items {
  padding: 0.5rem 0.75rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* ─── Shared: milestone bars ─────────────────────────────────── */
.ms-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.3rem;
}
.ms-label {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  width: 5rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex-shrink: 0;
}
.ms-track {
  flex: 1;
  height: 5px;
  background: var(--color-bg-secondary);
  border-radius: 999px;
  overflow: hidden;
}
.ms-fill {
  height: 100%;
  border-radius: 999px;
  transition: width 0.3s;
}
.ms-pct {
  font-size: 0.7rem;
  color: var(--color-text-muted);
  width: 2.2rem;
  text-align: right;
  flex-shrink: 0;
}

/* ─── Mobile ─────────────────────────────────────────────────── */
@media (max-width: 680px) {
  .home { padding: 0 var(--page-padding-x); margin: 1rem auto; }
  .hero-top { flex-direction: column; align-items: flex-start; }
  .btn-workspace-hero { width: 100%; justify-content: center; }
  .projects-grid { grid-template-columns: 1fr; }
  .inbox-sub { display: none; }
}

/* ─── Upcoming events ────────────────────────────────────────── */
.upcoming-events-section {
  margin-bottom: 1.75rem;
}
.upcoming-events-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.5rem;
}
.upcoming-event-card {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.55rem 0.75rem;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: border-color 0.15s, background 0.15s;
  width: 100%;
}
.upcoming-event-card:hover {
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 6%, var(--color-bg-card));
}
.upcoming-event-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-primary);
  flex-shrink: 0;
  margin-top: 4px;
}
.upcoming-event-body {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}
.upcoming-event-title {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.upcoming-event-time {
  font-size: 0.75rem;
  color: var(--color-text-muted);
}
.upcoming-event-loc {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.upcoming-events-more {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  padding: 0.25rem 0;
  grid-column: 1 / -1;
}
.see-all-inline {
  color: var(--color-primary);
  text-decoration: none;
}
.see-all-inline:hover { text-decoration: underline; }
</style>
