<script setup lang="ts">
import { ref, computed, onMounted, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { apiGet, apiPatch, apiDelete, apiPost } from "@/api/client";
import { useToastStore } from "@/stores/toast";

interface Milestone {
  id: number;
  title: string;
  status: string;
  order_index: number;
  pct: number;
  total: number;
  completed: number;
  status_counts: { todo: number; in_progress: number; done: number };
}

interface Project {
  id: number;
  title: string;
  description: string | null;
  goal: string | null;
  status: "active" | "completed" | "archived";
  color: string | null;
  created_at: string;
  updated_at: string;
  summary?: {
    task_counts: { todo: number; in_progress: number; done: number };
    note_count: number;
    last_activity: string | null;
    milestone_summary: Milestone[];
  };
}

interface NoteItem {
  id: number;
  title: string;
  type: "task" | "note";
  status?: string;
  priority?: string;
  due_date?: string | null;
  updated_at: string;
  milestone_id?: number | null;
}

const route = useRoute();
const router = useRouter();
const toast = useToastStore();

const project = ref<Project | null>(null);
const loading = ref(false);
const saving = ref(false);
const error = ref<string | null>(null);

const activeTab = ref<"tasks" | "notes">("tasks");

const tasks = ref<NoteItem[]>([]);
const notes = ref<NoteItem[]>([]);
const tasksLoading = ref(false);
const notesLoading = ref(false);

const milestones = ref<Milestone[]>([]);
const collapsedMilestones = ref<Set<number>>(new Set());
const showNewMilestone = ref(false);
const newMilestoneTitle = ref("");
const creatingMilestone = ref(false);

// Milestone edit/delete state
const renamingMilestoneId = ref<number | null>(null);
const renamingMilestoneTitle = ref("");
const deletingMilestone = ref<Milestone | null>(null);

// Edit state
const editTitle = ref("");
const editDescription = ref("");
const editGoal = ref("");
const editStatus = ref<Project["status"]>("active");
const editDirty = ref(false);

const projectId = computed(() => Number(route.params.id));

// Group tasks by milestone_id for the milestone view
interface MilestoneGroup {
  milestone: Milestone | null;
  tasks: NoteItem[];
}

const milestoneGroups = computed((): MilestoneGroup[] => {
  const groups: MilestoneGroup[] = [];
  // One group per milestone (ordered by order_index)
  for (const ms of milestones.value) {
    groups.push({
      milestone: ms,
      tasks: tasks.value.filter((t) => t.milestone_id === ms.id),
    });
  }
  // Unassigned tasks at the bottom
  const assignedIds = new Set(milestones.value.map((m) => m.id));
  const unassigned = tasks.value.filter(
    (t) => !t.milestone_id || !assignedIds.has(t.milestone_id)
  );
  if (unassigned.length > 0 || milestones.value.length === 0) {
    groups.push({ milestone: null, tasks: unassigned });
  }
  return groups;
});

function toggleMilestoneCollapse(id: number) {
  if (collapsedMilestones.value.has(id)) {
    collapsedMilestones.value.delete(id);
  } else {
    collapsedMilestones.value.add(id);
  }
}

async function loadProject() {
  loading.value = true;
  error.value = null;
  try {
    const data = await apiGet<Project>(`/api/projects/${projectId.value}`);
    project.value = data;
    editTitle.value = data.title;
    editDescription.value = data.description ?? "";
    editGoal.value = data.goal ?? "";
    editStatus.value = data.status;
    editDirty.value = false;
    milestones.value = data.summary?.milestone_summary ?? [];
  } catch {
    error.value = "Failed to load project.";
  } finally {
    loading.value = false;
  }
}

async function loadMilestones() {
  try {
    const data = await apiGet<{ milestones: Milestone[] }>(
      `/api/projects/${projectId.value}/milestones`
    );
    milestones.value = data.milestones;
  } catch {
    // silent
  }
}

async function createMilestone() {
  if (!newMilestoneTitle.value.trim() || creatingMilestone.value) return;
  creatingMilestone.value = true;
  try {
    await apiPost(`/api/projects/${projectId.value}/milestones`, {
      title: newMilestoneTitle.value.trim(),
    });
    newMilestoneTitle.value = "";
    showNewMilestone.value = false;
    await loadMilestones();
    toast.show("Milestone created");
  } catch {
    toast.show("Failed to create milestone", "error");
  } finally {
    creatingMilestone.value = false;
  }
}

function startRenameMilestone(ms: Milestone) {
  renamingMilestoneId.value = ms.id;
  renamingMilestoneTitle.value = ms.title;
}

async function commitRenameMilestone(ms: Milestone) {
  const newTitle = renamingMilestoneTitle.value.trim();
  renamingMilestoneId.value = null;
  if (!newTitle || newTitle === ms.title) return;
  try {
    await apiPatch(`/api/projects/${projectId.value}/milestones/${ms.id}`, { title: newTitle });
    await loadMilestones();
    toast.show("Milestone renamed");
  } catch {
    toast.show("Failed to rename milestone", "error");
  }
}

async function confirmDeleteMilestone() {
  const ms = deletingMilestone.value;
  if (!ms) return;
  deletingMilestone.value = null;
  try {
    await apiDelete(`/api/projects/${projectId.value}/milestones/${ms.id}`);
    await loadMilestones();
    await loadTasks();
    toast.show("Milestone deleted");
  } catch {
    toast.show("Failed to delete milestone", "error");
  }
}

async function loadTasks() {
  tasksLoading.value = true;
  try {
    const data = await apiGet<{ notes: NoteItem[]; total: number }>(
      `/api/projects/${projectId.value}/notes?type=task&limit=100`
    );
    tasks.value = data.notes;
  } catch {
    // Silently fail — tasks just won't show
  } finally {
    tasksLoading.value = false;
  }
}

async function loadNotes() {
  notesLoading.value = true;
  try {
    const data = await apiGet<{ notes: NoteItem[]; total: number }>(
      `/api/projects/${projectId.value}/notes?type=note&limit=100`
    );
    notes.value = data.notes;
  } catch {
    // Silently fail
  } finally {
    notesLoading.value = false;
  }
}

onMounted(async () => {
  await loadProject();
  loadTasks();
  loadNotes();
});

watch(projectId, async () => {
  await loadProject();
  loadTasks();
  loadNotes();
});

watch(
  () => [editTitle.value, editDescription.value, editGoal.value, editStatus.value],
  () => {
    if (!project.value) return;
    editDirty.value =
      editTitle.value !== project.value.title ||
      editDescription.value !== (project.value.description ?? "") ||
      editGoal.value !== (project.value.goal ?? "") ||
      editStatus.value !== project.value.status;
  }
);

async function saveProject() {
  if (!project.value || saving.value) return;
  saving.value = true;
  try {
    const updated = await apiPatch<Project>(`/api/projects/${project.value.id}`, {
      title: editTitle.value.trim(),
      description: editDescription.value.trim() || null,
      goal: editGoal.value.trim() || null,
      status: editStatus.value,
    });
    project.value = { ...project.value, ...updated };
    editDirty.value = false;
    toast.show("Project saved");
  } catch {
    toast.show("Failed to save project", "error");
  } finally {
    saving.value = false;
  }
}

const showDeleteConfirm = ref(false);

async function confirmDelete() {
  if (!project.value) return;
  showDeleteConfirm.value = false;
  try {
    await apiDelete(`/api/projects/${project.value.id}`);
    toast.show("Project deleted");
    router.push("/projects");
  } catch {
    toast.show("Failed to delete project", "error");
  }
}

function priorityClass(priority?: string): string {
  if (priority === "high") return "priority-high";
  if (priority === "medium") return "priority-medium";
  if (priority === "low") return "priority-low";
  return "";
}

function formatDate(dateStr?: string | null): string {
  if (!dateStr) return "";
  return new Date(dateStr).toLocaleDateString();
}
</script>

<template>
  <main class="project-view">
    <div class="page-header">
      <router-link to="/projects" class="btn-back">Back to Projects</router-link>
      <button
        v-if="project"
        class="btn-danger-outline"
        @click="showDeleteConfirm = true"
      >
        Delete Project
      </button>
    </div>

    <p v-if="loading" class="loading-msg">Loading...</p>
    <p v-else-if="error" class="error-msg">{{ error }}</p>

    <template v-else-if="project">
      <!-- Project header -->
      <div class="project-header">
        <div class="title-row">
          <input
            v-model="editTitle"
            type="text"
            class="title-input"
            placeholder="Project title"
          />
          <span :class="['status-badge', `status-${project.status}`]">
            {{ project.status.charAt(0).toUpperCase() + project.status.slice(1) }}
          </span>
        </div>
        <p v-if="project.goal && !editGoal" class="project-goal-display">{{ project.goal }}</p>
      </div>

      <!-- Summary bar -->
      <div v-if="project.summary" class="summary-bar">
        <span class="summary-item">
          <span class="summary-num">{{ project.summary.task_counts.todo }}</span> todo
        </span>
        <span class="summary-sep">·</span>
        <span class="summary-item">
          <span class="summary-num">{{ project.summary.task_counts.in_progress }}</span> in progress
        </span>
        <span class="summary-sep">·</span>
        <span class="summary-item">
          <span class="summary-num">{{ project.summary.task_counts.done }}</span> done
        </span>
        <span class="summary-sep">·</span>
        <span class="summary-item">
          <span class="summary-num">{{ project.summary.note_count }}</span> notes
        </span>
      </div>

      <div class="project-body">
        <!-- Edit panel -->
        <aside class="edit-panel">
          <h3>Details</h3>
          <div class="edit-field">
            <label>Goal</label>
            <input v-model="editGoal" type="text" class="edit-input" placeholder="What are you trying to achieve?" />
          </div>
          <div class="edit-field">
            <label>Description</label>
            <textarea v-model="editDescription" class="edit-textarea" rows="4" placeholder="Optional description..."></textarea>
          </div>
          <div class="edit-field">
            <label>Status</label>
            <select v-model="editStatus" class="edit-select">
              <option value="active">Active</option>
              <option value="completed">Completed</option>
              <option value="archived">Archived</option>
            </select>
          </div>
          <button
            class="btn-save"
            @click="saveProject"
            :disabled="!editDirty || saving"
          >
            {{ saving ? "Saving..." : "Save" }}
          </button>
        </aside>

        <!-- Main content area -->
        <div class="content-area">
          <!-- Tab bar -->
          <div class="tab-bar">
            <button
              :class="['tab-btn', { active: activeTab === 'tasks' }]"
              @click="activeTab = 'tasks'"
            >Tasks</button>
            <button
              :class="['tab-btn', { active: activeTab === 'notes' }]"
              @click="activeTab = 'notes'"
            >Notes</button>
          </div>

          <!-- Tasks tab — milestone-grouped -->
          <div v-if="activeTab === 'tasks'" class="tasks-view">
            <p v-if="tasksLoading" class="loading-msg">Loading tasks...</p>
            <template v-else>
              <!-- Add milestone button -->
              <div class="milestone-actions">
                <button v-if="!showNewMilestone" class="btn-add-milestone" @click="showNewMilestone = true">
                  + Add Milestone
                </button>
                <div v-else class="new-milestone-row">
                  <input
                    v-model="newMilestoneTitle"
                    class="milestone-title-input"
                    placeholder="Milestone title"
                    autofocus
                    @keydown.enter="createMilestone"
                    @keydown.escape="showNewMilestone = false; newMilestoneTitle = ''"
                  />
                  <button class="btn-ms-confirm" @click="createMilestone" :disabled="!newMilestoneTitle.trim() || creatingMilestone">
                    {{ creatingMilestone ? "..." : "Add" }}
                  </button>
                  <button class="btn-ms-cancel" @click="showNewMilestone = false; newMilestoneTitle = ''">Cancel</button>
                </div>
              </div>

              <!-- Milestone groups -->
              <div
                v-for="group in milestoneGroups"
                :key="group.milestone?.id ?? 'unassigned'"
                class="milestone-group"
              >
                <!-- Milestone header -->
                <div
                  class="milestone-header"
                  @click="group.milestone && renamingMilestoneId !== group.milestone.id && toggleMilestoneCollapse(group.milestone.id)"
                  :class="{ clickable: !!group.milestone && renamingMilestoneId !== group.milestone?.id }"
                >
                  <span class="ms-chevron" v-if="group.milestone">
                    {{ collapsedMilestones.has(group.milestone.id) ? '▶' : '▼' }}
                  </span>
                  <!-- Inline rename input -->
                  <template v-if="group.milestone && renamingMilestoneId === group.milestone.id">
                    <input
                      class="ms-rename-input"
                      v-model="renamingMilestoneTitle"
                      @click.stop
                      @keydown.enter.stop="commitRenameMilestone(group.milestone)"
                      @keydown.escape.stop="renamingMilestoneId = null"
                      @blur="commitRenameMilestone(group.milestone)"
                      autofocus
                    />
                  </template>
                  <span v-else class="ms-name">{{ group.milestone?.title ?? "No Milestone" }}</span>
                  <span class="ms-count">{{ group.tasks.length }}</span>
                  <template v-if="group.milestone">
                    <div class="ms-progress-track">
                      <div
                        class="ms-progress-fill"
                        :style="{ width: group.milestone.pct + '%' }"
                      ></div>
                    </div>
                    <span class="ms-pct">{{ group.milestone.pct }}%</span>
                    <!-- Edit / delete actions -->
                    <div class="ms-actions" @click.stop>
                      <button
                        class="ms-action-btn"
                        title="Rename milestone"
                        @click="startRenameMilestone(group.milestone)"
                      >✎</button>
                      <button
                        class="ms-action-btn ms-action-delete"
                        title="Delete milestone"
                        @click="deletingMilestone = group.milestone"
                      >✕</button>
                    </div>
                  </template>
                </div>

                <!-- Task list (collapsible) -->
                <div
                  v-if="!group.milestone || !collapsedMilestones.has(group.milestone.id)"
                  class="kanban"
                >
                  <div class="kanban-col">
                    <div class="kanban-col-header">
                      <span>Todo</span>
                      <span class="col-count">{{ group.tasks.filter(t => t.status === 'todo').length }}</span>
                      <router-link
                        :to="`/tasks/new?projectId=${projectId}${group.milestone ? '&milestoneId=' + group.milestone.id : ''}`"
                        class="col-add-btn"
                        title="Add task"
                      >+</router-link>
                    </div>
                    <div class="kanban-cards">
                      <router-link
                        v-for="task in group.tasks.filter(t => t.status === 'todo')"
                        :key="task.id"
                        :to="`/tasks/${task.id}`"
                        class="task-card"
                      >
                        <span class="task-title">{{ task.title || "Untitled" }}</span>
                        <div class="task-meta">
                          <span v-if="task.priority && task.priority !== 'none'" :class="['priority-badge', priorityClass(task.priority)]">{{ task.priority }}</span>
                          <span v-if="task.due_date" class="due-date">{{ formatDate(task.due_date) }}</span>
                        </div>
                      </router-link>
                      <p v-if="!group.tasks.filter(t => t.status === 'todo').length" class="col-empty">No tasks</p>
                    </div>
                  </div>
                  <div class="kanban-col">
                    <div class="kanban-col-header">
                      <span>In Progress</span>
                      <span class="col-count">{{ group.tasks.filter(t => t.status === 'in_progress').length }}</span>
                    </div>
                    <div class="kanban-cards">
                      <router-link
                        v-for="task in group.tasks.filter(t => t.status === 'in_progress')"
                        :key="task.id"
                        :to="`/tasks/${task.id}`"
                        class="task-card"
                      >
                        <span class="task-title">{{ task.title || "Untitled" }}</span>
                        <div class="task-meta">
                          <span v-if="task.priority && task.priority !== 'none'" :class="['priority-badge', priorityClass(task.priority)]">{{ task.priority }}</span>
                          <span v-if="task.due_date" class="due-date">{{ formatDate(task.due_date) }}</span>
                        </div>
                      </router-link>
                      <p v-if="!group.tasks.filter(t => t.status === 'in_progress').length" class="col-empty">No tasks</p>
                    </div>
                  </div>
                  <div class="kanban-col">
                    <div class="kanban-col-header">
                      <span>Done</span>
                      <span class="col-count">{{ group.tasks.filter(t => t.status === 'done').length }}</span>
                    </div>
                    <div class="kanban-cards">
                      <router-link
                        v-for="task in group.tasks.filter(t => t.status === 'done')"
                        :key="task.id"
                        :to="`/tasks/${task.id}`"
                        class="task-card task-card-done"
                      >
                        <span class="task-title">{{ task.title || "Untitled" }}</span>
                        <div class="task-meta">
                          <span v-if="task.due_date" class="due-date">{{ formatDate(task.due_date) }}</span>
                        </div>
                      </router-link>
                      <p v-if="!group.tasks.filter(t => t.status === 'done').length" class="col-empty">No tasks</p>
                    </div>
                  </div>
                </div>
              </div>

              <p v-if="tasks.length === 0" class="empty-msg">No tasks in this project yet.</p>
            </template>
          </div>

          <!-- Notes tab -->
          <div v-if="activeTab === 'notes'" class="notes-list">
            <p v-if="notesLoading" class="loading-msg">Loading notes...</p>
            <template v-else>
              <router-link
                v-for="note in notes"
                :key="note.id"
                :to="`/notes/${note.id}`"
                class="note-row"
              >
                <span class="note-title">{{ note.title || "Untitled" }}</span>
                <span class="note-date">{{ formatDate(note.updated_at) }}</span>
              </router-link>
              <p v-if="!notes.length" class="empty-msg">No notes in this project.</p>
            </template>
          </div>
        </div>
      </div>
    </template>

    <!-- Milestone delete confirmation modal -->
    <teleport to="body">
      <div v-if="deletingMilestone" class="modal-overlay" @click.self="deletingMilestone = null">
        <div class="modal-card">
          <h3 class="modal-title">Delete Milestone</h3>
          <p class="modal-message">
            Delete <strong>{{ deletingMilestone.title }}</strong>?
            Tasks will be unlinked from this milestone but not deleted.
          </p>
          <div class="modal-actions">
            <button class="modal-btn" @click="deletingMilestone = null">Cancel</button>
            <button class="modal-btn modal-btn-danger" @click="confirmDeleteMilestone">Delete</button>
          </div>
        </div>
      </div>
    </teleport>

    <!-- Project delete confirmation modal -->
    <teleport to="body">
      <div v-if="showDeleteConfirm" class="modal-overlay" @click.self="showDeleteConfirm = false">
        <div class="modal-card">
          <h3 class="modal-title">Delete Project</h3>
          <p class="modal-message">Are you sure you want to delete this project? This cannot be undone.</p>
          <div class="modal-actions">
            <button class="modal-btn" @click="showDeleteConfirm = false">Cancel</button>
            <button class="modal-btn modal-btn-danger" @click="confirmDelete">Delete</button>
          </div>
        </div>
      </div>
    </teleport>
  </main>
</template>

<style scoped>
.project-view {
  max-width: 1200px;
  margin: 2rem auto;
  padding: 0 1rem;
  overflow-x: clip;
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.25rem;
}

.btn-back {
  color: var(--color-primary);
  text-decoration: none;
  font-size: 0.875rem;
}
.btn-back:hover {
  text-decoration: underline;
}

.btn-danger-outline {
  padding: 0.35rem 0.8rem;
  background: none;
  border: 1px solid var(--color-danger, #e74c3c);
  color: var(--color-danger, #e74c3c);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.85rem;
  font-family: inherit;
}
.btn-danger-outline:hover {
  background: color-mix(in srgb, var(--color-danger, #e74c3c) 10%, transparent);
}

.loading-msg { color: var(--color-text-muted); font-size: 0.9rem; }
.error-msg { color: var(--color-danger); font-size: 0.9rem; }

.project-header {
  margin-bottom: 0.75rem;
}

.title-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}
.title-input {
  flex: 1;
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--color-text);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  outline: none;
  padding: 0.1rem 0;
  font-family: inherit;
  min-width: 0;
}
.title-input:focus {
  border-bottom-color: var(--color-primary);
}

.status-badge {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
  flex-shrink: 0;
}
.status-active   { background: color-mix(in srgb, var(--color-success) 15%, transparent); color: var(--color-success); }
.status-completed { background: color-mix(in srgb, var(--color-primary) 15%, transparent); color: var(--color-primary); }
.status-archived  { background: color-mix(in srgb, var(--color-text-muted) 15%, transparent); color: var(--color-text-muted); }

.project-goal-display {
  font-size: 0.9rem;
  color: var(--color-text-secondary);
  margin: 0;
  font-style: italic;
}

.summary-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
  font-size: 0.85rem;
  color: var(--color-text-secondary);
  flex-wrap: wrap;
}
.summary-num {
  font-weight: 700;
  color: var(--color-text);
}
.summary-sep {
  color: var(--color-text-muted);
}

.project-body {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 1.25rem;
  align-items: start;
}

/* Edit panel */
.edit-panel {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.edit-panel h3 {
  margin: 0 0 0.25rem;
  font-size: 0.875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}
.edit-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.edit-field label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-text-secondary);
}
.edit-input,
.edit-textarea,
.edit-select {
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
  font-size: 0.875rem;
  font-family: inherit;
  box-sizing: border-box;
  width: 100%;
}
.edit-input:focus,
.edit-textarea:focus,
.edit-select:focus {
  outline: none;
  border-color: var(--color-primary);
}
.edit-textarea {
  resize: vertical;
}
.btn-save {
  padding: 0.4rem 0.9rem;
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.875rem;
  font-family: inherit;
  width: 100%;
}
.btn-save:hover:not(:disabled) { opacity: 0.9; }
.btn-save:disabled { opacity: 0.5; cursor: default; }

/* Main content */
.content-area {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.tab-bar {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--color-border);
  padding-bottom: 0;
}
.tab-btn {
  padding: 0.4rem 0.85rem;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  font-family: inherit;
  margin-bottom: -1px;
}
.tab-btn:hover { color: var(--color-primary); }
.tab-btn.active {
  color: var(--color-primary);
  border-bottom-color: var(--color-primary);
  font-weight: 600;
}

/* Tasks view (wraps milestone groups) */
.tasks-view {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Milestone management */
.milestone-actions {
  display: flex;
  align-items: center;
}
.btn-add-milestone {
  background: none;
  border: 1px dashed var(--color-border);
  color: var(--color-text-secondary);
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8rem;
  font-family: inherit;
}
.btn-add-milestone:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.new-milestone-row {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex: 1;
}
.milestone-title-input {
  flex: 1;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
  font-size: 0.875rem;
  font-family: inherit;
}
.milestone-title-input:focus {
  outline: none;
  border-color: var(--color-primary);
}
.btn-ms-confirm {
  padding: 0.3rem 0.7rem;
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8rem;
  font-family: inherit;
}
.btn-ms-confirm:disabled { opacity: 0.5; cursor: default; }
.btn-ms-cancel {
  padding: 0.3rem 0.7rem;
  background: none;
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8rem;
  font-family: inherit;
}

/* Milestone group */
.milestone-group {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.milestone-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.8rem;
  background: var(--color-bg-secondary);
  font-size: 0.85rem;
  user-select: none;
}
.milestone-header.clickable {
  cursor: pointer;
}
.milestone-header.clickable:hover {
  background: var(--color-bg-card);
}
.ms-chevron {
  font-size: 0.65rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
}
.ms-name {
  font-weight: 600;
  color: var(--color-text);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ms-count {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.05rem 0.4rem;
  flex-shrink: 0;
}
.ms-progress-track {
  width: 80px;
  height: 5px;
  background: var(--color-border);
  border-radius: 999px;
  overflow: hidden;
  flex-shrink: 0;
}
.ms-progress-fill {
  height: 100%;
  background: var(--color-primary);
  border-radius: 999px;
  transition: width 0.3s ease;
}
.ms-pct {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
  min-width: 2.2rem;
  text-align: right;
}

/* Kanban */
.kanban {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  align-items: start;
  padding: 0.75rem;
  background: var(--color-bg);
}
.kanban-col {
  background: var(--color-bg-secondary);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.kanban-col-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-secondary);
  margin-bottom: 0.35rem;
}
.col-count {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  font-size: 0.7rem;
  color: var(--color-text-muted);
  font-weight: 600;
}
.col-add-btn {
  margin-left: auto;
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: 1rem;
  line-height: 1;
  padding: 0 0.15rem;
  border-radius: var(--radius-sm);
}
.col-add-btn:hover { color: var(--color-primary); }
.kanban-cards {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.task-card {
  display: block;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.6rem;
  text-decoration: none;
  color: var(--color-text);
  font-size: 0.875rem;
  transition: border-color 0.15s;
}
.task-card:hover {
  border-color: var(--color-primary);
}
.task-card-done .task-title {
  text-decoration: line-through;
  opacity: 0.6;
}
.task-title {
  display: block;
  font-weight: 500;
  margin-bottom: 0.25rem;
  line-height: 1.3;
  word-break: break-word;
}
.task-meta {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
}
.priority-badge {
  font-size: 0.67rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.1rem 0.3rem;
  border-radius: 3px;
}
.priority-high   { background: color-mix(in srgb, var(--color-danger, #e74c3c) 15%, transparent); color: var(--color-danger, #e74c3c); }
.priority-medium { background: rgba(201, 138, 0, 0.15); color: #c98a00; }
.priority-low    { background: color-mix(in srgb, var(--color-success) 12%, transparent); color: var(--color-success); }
.due-date {
  font-size: 0.72rem;
  color: var(--color-text-muted);
}
.col-empty {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  text-align: center;
  padding: 0.5rem 0;
  margin: 0;
}

/* Notes list */
.notes-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.note-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.6rem 0.9rem;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-text);
  font-size: 0.9rem;
  transition: border-color 0.15s;
}
.note-row:hover {
  border-color: var(--color-primary);
}
.note-title {
  font-weight: 500;
  min-width: 0;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.note-date {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
  margin-left: 0.75rem;
}
.empty-msg {
  color: var(--color-text-muted);
  font-size: 0.875rem;
  text-align: center;
  padding: 1rem;
}

/* Modal */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: var(--color-overlay, rgba(0,0,0,0.45));
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
}
.modal-card {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 1.5rem;
  width: 100%;
  max-width: 400px;
  box-shadow: 0 8px 32px var(--color-shadow);
}
.modal-title {
  margin: 0 0 0.75rem;
  font-size: 1.05rem;
}
.modal-message {
  font-size: 0.9rem;
  color: var(--color-text-secondary);
  margin: 0 0 1.25rem;
  line-height: 1.5;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}
.modal-btn {
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--color-border);
  background: var(--color-bg-secondary);
  color: var(--color-text);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.875rem;
  font-family: inherit;
}
.modal-btn:hover { background: var(--color-bg); }
.modal-btn-danger {
  background: var(--color-danger, #e74c3c);
  border-color: var(--color-danger, #e74c3c);
  color: #fff;
}
.modal-btn-danger:hover { opacity: 0.9; }

/* Milestone rename input */
.ms-rename-input {
  flex: 1;
  min-width: 0;
  padding: 0.1rem 0.35rem;
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
  font-size: 0.85rem;
  font-family: inherit;
  font-weight: 600;
}
.ms-rename-input:focus {
  outline: none;
}

/* Milestone action buttons */
.ms-actions {
  display: flex;
  gap: 0.15rem;
  margin-left: 0.25rem;
  opacity: 0;
  transition: opacity 0.15s;
}
.milestone-header:hover .ms-actions {
  opacity: 1;
}
.ms-action-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-text-muted);
  font-size: 0.8rem;
  padding: 0.15rem 0.3rem;
  border-radius: var(--radius-sm);
  line-height: 1;
  font-family: inherit;
}
.ms-action-btn:hover {
  background: var(--color-bg-card);
  color: var(--color-text);
}
.ms-action-delete:hover {
  color: var(--color-danger, #e74c3c);
}

@media (max-width: 900px) {
  .project-body {
    grid-template-columns: 1fr;
  }
  .kanban {
    grid-template-columns: 1fr;
  }
}

.empty-msg {
  color: var(--color-text-muted);
  font-size: 0.875rem;
  text-align: center;
  padding: 1rem;
}
</style>
