<template>
  <section class="service-dashboard">
    <div class="dashboard-header">
      <div>
        <h1 class="dashboard-title">{{ dashboardTitle }}</h1>
        <div class="site-label">
          <v-icon icon="mdi-map-marker" size="16" />
          <span>{{ currentSiteName || "Selected site" }}</span>
        </div>
      </div>

      <div class="header-actions">
        <v-btn
          variant="outlined"
          color="default"
          density="comfortable"
          class="text-none action-button"
          prepend-icon="mdi-tune-variant"
          @click="openCustomizeDialog"
        >
          Customize Dashboard
        </v-btn>

        <v-menu>
          <template #activator="{ props: menuProps }">
            <v-btn
              v-bind="menuProps"
              variant="outlined"
              color="default"
              density="comfortable"
              class="text-none action-button"
              append-icon="mdi-chevron-down"
            >
              Export
            </v-btn>
          </template>

          <v-list class="export-menu" density="compact" border>
            <v-list-item title="PDF" @click="notifyExport('PDF')" />
            <v-list-item title="Word" @click="notifyExport('Word')" />
          </v-list>
        </v-menu>

        <v-btn-toggle
          v-model="selectedRange"
          mandatory
          density="comfortable"
          class="range-toggle"
          divided
        >
          <v-btn
            v-for="range in rangeOptions"
            :key="range.value"
            :value="range.value"
            class="text-none"
            size="small"
          >
            {{ range.label }}
          </v-btn>
        </v-btn-toggle>
      </div>
    </div>

    <v-progress-linear v-if="loading" indeterminate color="primary" class="mb-4" />

    <v-row class="kpi-grid" dense>
      <v-col
        v-for="card in visibleKpiCards"
        :key="card.key"
        cols="12"
        md="6"
      >
        <v-card :class="['dashboard-card', 'kpi-card', `kpi-card-${card.key}`]" flat border>
          <div class="kpi-topline">
            <div :class="['kpi-icon', `kpi-icon-${card.key}`]" :style="{ backgroundColor: card.tint }">
              <v-icon :icon="card.icon" :color="card.color" size="15" />
            </div>

            <v-menu v-if="card.filter" v-model="filterMenus[card.key]">
              <template #activator="{ props: menuProps }">
                <v-btn
                  v-bind="menuProps"
                  variant="outlined"
                  density="compact"
                  class="text-none mini-filter"
                  append-icon="mdi-chevron-down"
                >
                  {{ card.filter.model }}
                </v-btn>
              </template>

              <v-list class="filter-menu" density="compact" border>
                <v-list-item
                  v-for="option in card.filter.options"
                  :key="option"
                  :active="card.filter.model === option"
                  :title="option"
                  @click="card.filter.set(option)"
                >
                  <template #prepend>
                    <v-icon
                      :icon="card.filter.model === option ? 'mdi-check' : 'mdi-blank'"
                      size="16"
                    />
                  </template>
                </v-list-item>
              </v-list>
            </v-menu>
          </div>

          <div class="kpi-content">
            <p class="kpi-label">{{ card.title }}</p>
            <div class="kpi-value-row">
              <strong>{{ card.value }}</strong>
            </div>
            <div class="kpi-meta-row">
              <p v-if="card.meta" class="kpi-meta">{{ card.meta }}</p>
              <v-chip
                :color="card.percentage >= 0 ? 'success' : 'error'"
                size="x-small"
                variant="flat"
                class="font-weight-bold"
              >
                <v-icon
                  :icon="card.percentage >= 0 ? 'mdi-arrow-up-right' : 'mdi-arrow-down-right'"
                  size="13"
                  start
                />
                {{ Math.abs(card.percentage) }}%
              </v-chip>
            </div>
          </div>
        </v-card>
      </v-col>
    </v-row>

    <v-card v-if="isWidgetVisible('activity')" class="dashboard-card activity-card" flat border>
      <div class="section-header">
        <h2>{{ activityTitle }}</h2>
      </div>

      <div v-if="hasChartData" class="chart-wrap">
        <svg viewBox="0 0 920 260" preserveAspectRatio="none" class="activity-chart">
          <line
            v-for="tick in chartTicks"
            :key="tick"
            x1="48"
            :y1="tick"
            x2="900"
            :y2="tick"
            class="chart-grid"
          />

          <polyline :points="primaryPoints" class="primary-line" />
          <polyline :points="secondaryPoints" class="secondary-line" />

          <circle
            v-for="point in primaryDots"
            :key="`primary-${point.x}-${point.y}`"
            :cx="point.x"
            :cy="point.y"
            r="4"
            class="primary-dot"
          />
          <circle
            v-for="point in secondaryDots"
            :key="`secondary-${point.x}-${point.y}`"
            :cx="point.x"
            :cy="point.y"
            r="4"
            class="secondary-dot"
          />

          <text
            v-for="label in chartAxisLabels"
            :key="`${label.text}-${label.x}`"
            :x="label.x"
            y="246"
            class="chart-label"
            text-anchor="middle"
          >
            {{ label.text }}
          </text>
        </svg>

        <div class="chart-legend">
          <span><i class="legend-dot primary" />{{ primaryLegendLabel }}</span>
          <span><i class="legend-dot secondary" />{{ secondaryLegendLabel }}</span>
        </div>
      </div>

      <EmptyDashboardState v-else />
    </v-card>

    <v-row class="dashboard-section-grid" dense>
      <v-col v-if="isWidgetVisible('taskSchedule')" cols="12" lg="7">
        <DashboardPanel :title="primaryListConfig.title" action-label="View All" @action="goToDashboardRoute(primaryListConfig.route)">
          <div v-if="taskScheduleItems.length" class="task-list">
            <div v-for="item in taskScheduleItems" :key="item.id" class="task-row">
              <div class="task-summary">
                <strong>{{ item.title }}</strong>
                <p>{{ item.subtitle }}</p>
              </div>

              <div class="person-cell">
                <span class="avatar">{{ getInitials(item.person) }}</span>
                <span>{{ item.person }}</span>
              </div>

              <span :class="['status-pill', `status-pill-${getStatusTone(item.status)}`]">
                {{ item.status }}
              </span>

              <button class="row-action row-action-right" type="button" @click="goToListItem(item, primaryListConfig.route)">View</button>
            </div>
          </div>
          <EmptyDashboardState v-else />
        </DashboardPanel>
      </v-col>

      <v-col v-if="isWidgetVisible('staffStatus')" cols="12" lg="5">
        <DashboardPanel title="Staff Status" action-label="View All" @action="goToDashboardRoute(staffStatusRoute)">
          <div v-if="staffStatusItems.length" class="staff-list">
            <div v-for="item in staffStatusItems" :key="item.id" class="staff-row">
              <span class="avatar">{{ getInitials(item.name) }}</span>
              <div class="staff-main">
                <strong>{{ item.name }}</strong>
                <p>{{ item.role }}</p>
              </div>
              <span :class="['status-pill', `status-pill-${getStaffTone(item.status)}`]">
                {{ item.status }}
              </span>
            </div>
          </div>
          <EmptyDashboardState v-else />
        </DashboardPanel>
      </v-col>

      <v-col v-if="isWidgetVisible('feedbacks')" cols="12">
        <DashboardPanel title="Feedbacks" action-label="View All" @action="goToDashboardRoute('feedbacks')">
          <div v-if="feedbackItems.length" class="feedback-list">
            <div v-for="item in feedbackItems" :key="item.id" class="feedback-row">
              <div class="feedback-summary">
                <strong>{{ item.title }}</strong>
                <p>{{ item.subtitle }}</p>
              </div>

              <div class="person-cell">
                <span class="avatar">{{ getInitials(item.person) }}</span>
                <span>{{ item.person }}</span>
              </div>

              <span :class="['status-pill', `status-pill-${getStatusTone(item.status)}`]">
                {{ item.status }}
              </span>

              <button class="row-action row-action-right" type="button" @click="goToListItem(item, 'feedbacks')">View</button>
            </div>
          </div>
          <EmptyDashboardState v-else />
        </DashboardPanel>
      </v-col>

      <v-col v-if="isWidgetVisible('recentActivity')" cols="12">
        <DashboardPanel title="Recent Activity" action-label="View All" variant="recent" @action="goToDashboardRoute('workOrders')">
          <DashboardList :items="recentActivities" empty-icon="mdi-history" align-time />
        </DashboardPanel>
      </v-col>
    </v-row>

    <v-dialog v-model="customizeDialog" max-width="720" persistent scrollable>
      <v-card class="customize-dialog" rounded="lg">
        <div class="customize-dialog-header">
          <div>
            <h2>Customize Dashboard</h2>
            <p>Select which widgets to display on your dashboard</p>
          </div>
          <v-btn
            icon="mdi-close"
            variant="text"
            density="comfortable"
            aria-label="Close customize dashboard"
            @click="cancelCustomize"
          />
        </div>

        <v-card-text class="customize-dialog-body">
          <v-text-field
            v-model="widgetSearch"
            placeholder="Search widgets..."
            prepend-inner-icon="mdi-magnify"
            variant="outlined"
            density="compact"
            hide-details
            class="widget-search"
          />

          <div class="reset-row">
            <v-btn
              variant="text"
              color="#0b2f47"
              size="small"
              class="text-none font-weight-bold"
              prepend-icon="mdi-refresh"
              @click="resetCustomizeDraft"
            >
              Reset to default
            </v-btn>
          </div>

          <div class="widget-list">
            <div
              v-for="widget in filteredCustomizeWidgets"
              :key="widget.key"
              class="widget-row"
            >
              <div>
                <strong>{{ widget.title }}</strong>
                <p>{{ widget.description }}</p>
              </div>
              <v-switch
                v-model="draftVisibleWidgetKeys"
                :value="widget.key"
                color="#0b2f47"
                inset
                hide-details
                density="compact"
                aria-label="Toggle dashboard widget"
              />
            </div>

            <EmptyDashboardState v-if="!filteredCustomizeWidgets.length" compact />
          </div>
        </v-card-text>

        <v-card-actions class="customize-dialog-actions">
          <v-btn
            variant="text"
            class="text-none cancel-button"
            @click="cancelCustomize"
          >
            Cancel
          </v-btn>
          <v-btn
            variant="flat"
            class="text-none submit-button"
            @click="submitCustomize"
          >
            Submit
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <v-snackbar v-model="snackbar.visible" :timeout="2200" color="primary">
      {{ snackbar.text }}
    </v-snackbar>
  </section>
</template>

<script setup lang="ts">
import { defineComponent, h } from "vue";

type DashboardMetric = {
  count?: number;
  percentage?: number;
  overdue?: number;
  inProgress?: number;
  pending?: number;
  highSeverity?: number;
  currentlyOnSite?: number;
  lowStock?: number;
  outOfStock?: number;
  completed?: number;
  total?: number;
};

type DashboardListItem = {
  id: string;
  title: string;
  subtitle?: string;
  time?: string;
  icon?: string;
  tone?: string;
  raw?: Record<string, any>;
};

type TaskItem = {
  id: string;
  title: string;
  subtitle: string;
  person: string;
  status: string;
  raw?: Record<string, any>;
};

type StaffItem = {
  id: string;
  name: string;
  role: string;
  status: string;
  raw?: Record<string, any>;
};

type FeedbackItem = {
  id: string;
  title: string;
  subtitle: string;
  person: string;
  status: string;
  raw?: Record<string, any>;
};

const props = defineProps({
  orgId: {
    type: String,
    default: "",
  },
  site: {
    type: String,
    default: "",
  },
  dashboardData: {
    type: Object as () => Record<string, any>,
    default: () => ({}),
  },
  loading: {
    type: Boolean,
    default: false,
  },
  cardPeriods: {
    type: Object as () => Record<string, TDashboardValues>,
    required: true,
  },
  currentSiteName: {
    type: String,
    default: "",
  },
  cardValues: {
    type: Array as () => TDashboardCardValue[],
    required: true,
  },
  title: {
    type: String,
    default: "",
  },
});

const emit = defineEmits<{
  updatePeriod: [payload: { key: string; period: string }];
}>();

const router = useRouter();
const runtimeConfig = useRuntimeConfig();
const customizeDialog = ref(false);
const widgetSearch = ref("");
const selectedRange = ref("Today");
const visitorType = ref("All");
const visibleWidgetKeys = ref<string[]>([]);
const draftVisibleWidgetKeys = ref<string[]>([]);
const filterMenus = reactive<Record<string, boolean>>({});
const snackbar = reactive({
  visible: false,
  text: "",
});

const rangeOptions = [
  { label: "Today", value: "Today" },
  { label: "7d", value: "This Week" },
  { label: "30d", value: "This Month" },
];
const defaultVisitorOptions = ["All", "Drive-In", "Walk-In", "Pick-up", "Drop-Off", "Delivery", "Contractor"];

const dashboardTitle = computed(() => {
  if (props.title) return props.title;
  const appName = String(runtimeConfig.public.APP_NAME || runtimeConfig.public.APP || "");
  return `${getServiceDisplayName(appName)} - Dashboard`;
});
const appKey = computed(() => String(runtimeConfig.public.APP || runtimeConfig.public.APP_NAME || "").toLowerCase());
const isSecurityDashboard = computed(() => appKey.value.includes("security"));
const primaryListConfig = computed(() => isSecurityDashboard.value
  ? {
    title: "Active Patrol",
    route: "virtualPatrol",
    keys: ["activePatrolItems", "patrolItems"],
  }
  : {
    title: "Today's Task Schedule",
    route: "scheduleTask",
    keys: ["taskScheduleItems", "scheduleTaskItems", "scheduledTaskItems", "cleaningScheduleItems", "tasks"],
  });
const staffStatusRoute = computed(() => isSecurityDashboard.value ? "manpower" : "attendance");

const defaultVisibleWidgetKeys = computed(() => [
  ...props.cardValues.map((card) => card.key),
  "activity",
  "taskSchedule",
  "staffStatus",
  "feedbacks",
  "recentActivity",
]);

watch(
  defaultVisibleWidgetKeys,
  (keys) => {
    const nextKeys = [...keys];
    if (!visibleWidgetKeys.value.length) {
      visibleWidgetKeys.value = nextKeys;
      draftVisibleWidgetKeys.value = nextKeys;
      return;
    }

    visibleWidgetKeys.value = visibleWidgetKeys.value.filter((key) => nextKeys.includes(key));
    draftVisibleWidgetKeys.value = draftVisibleWidgetKeys.value.filter((key) => nextKeys.includes(key));
  },
  { immediate: true },
);

watch(selectedRange, (period) => {
  emit("updatePeriod", { key: "__all__", period });
});

const customizeWidgets = computed(() => [
  ...props.cardValues.map((card) => ({
    key: card.key,
    title: card.title,
    description: `Show ${card.title} metrics for the selected period.`,
  })),
  {
    key: "activity",
    title: "Activity Chart",
    description: "Compare activity trends over time.",
  },
  {
    key: "taskSchedule",
    title: primaryListConfig.value.title,
    description: "Show current tasks and their latest status.",
  },
  {
    key: "staffStatus",
    title: "Staff Status",
    description: "See who is on duty, on break, or absent.",
  },
  {
    key: "feedbacks",
    title: "Feedbacks",
    description: "Show recent feedback and resolution state.",
  },
  {
    key: "recentActivity",
    title: "Recent Activity",
    description: "Latest updates across the service.",
  },
]);

const filteredCustomizeWidgets = computed(() => {
  const search = widgetSearch.value.trim().toLowerCase();
  if (!search) return customizeWidgets.value;

  return customizeWidgets.value.filter((widget) => (
    widget.title.toLowerCase().includes(search) ||
    widget.description.toLowerCase().includes(search)
  ));
});
const visitorItems = computed(() => getDashboardArray(["visitorItems", "visitorsList", "visitorTransactionsList"]));
const visitorOptions = computed(() => buildFilterOptions(defaultVisitorOptions, visitorItems.value, getVisitorFilterValue));

const kpiCards = computed(() => props.cardValues.map((mapping, index) => {
  const metric = mapping.key === "visitors" && isSecurityDashboard.value
    ? getFilteredVisitorMetric()
    : getMetric([mapping.key]);
  const value = getMetricValue(metric, mapping.key);

  return {
    key: mapping.key,
    title: mapping.title,
    icon: mapping.icon,
    tint: getCardTint(mapping.color, index),
    color: mapping.color || getCardColor(index),
    value: typeof value === "string" ? value : formatNumber(value),
    percentage: toNumber(metric.percentage),
    meta: getMetricMeta(metric),
    filter: mapping.key === "visitors" && isSecurityDashboard.value
      ? {
        model: visitorType.value,
        options: visitorOptions.value,
        set: (option: string) => {
          visitorType.value = option;
          filterMenus.visitors = false;
        },
      }
      : undefined,
  };
}));

const visibleKpiCards = computed(() => kpiCards.value.filter((card) => isWidgetVisible(card.key)));

const activityTitle = computed(() => {
  if (selectedRange.value === "Today") return "Today's Activity";
  if (selectedRange.value === "This Month") return "This Month Activity";
  return "This Week Activity";
});

const activityChart = computed(() => normalizeActivityChart(getActivityChartSource()));
const chartLabels = computed<string[]>(() => {
  const labels = activityChart.value.labels;
  if (labels.length) return labels;

  if (selectedRange.value === "Today") return ["12 AM", "4 AM", "8 AM", "12 PM", "4 PM", "8 PM"];
  if (selectedRange.value === "This Month") return ["Week 1", "Week 2", "Week 3", "Week 4"];
  return ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
});
const primarySeries = computed(() => normalizeSeries(activityChart.value.primary, chartLabels.value.length));
const secondarySeries = computed(() => normalizeSeries(activityChart.value.secondary, chartLabels.value.length));
const primaryLegendLabel = computed(() => activityChart.value.primaryLabel || "Work Order");
const secondaryLegendLabel = computed(() => activityChart.value.secondaryLabel || "Feedback");
const chartMax = computed(() => Math.max(1, ...primarySeries.value, ...secondarySeries.value));
const hasChartData = computed(() => primarySeries.value.some(Boolean) || secondarySeries.value.some(Boolean));
const chartTicks = [28, 76, 124, 172, 220];
const primaryDots = computed(() => buildChartDots(primarySeries.value));
const secondaryDots = computed(() => buildChartDots(secondarySeries.value));
const primaryPoints = computed(() => primaryDots.value.map((point) => `${point.x},${point.y}`).join(" "));
const secondaryPoints = computed(() => secondaryDots.value.map((point) => `${point.x},${point.y}`).join(" "));
const chartAxisLabels = computed(() => {
  const labels = chartLabels.value;
  const count = Math.max(1, labels.length - 1);

  return labels.map((label, index) => ({
    text: label,
    x: 54 + ((846 / count) * index),
  }));
});

const taskScheduleItems = computed<TaskItem[]>(() => getDashboardArray([
  ...primaryListConfig.value.keys,
]).map(normalizeTaskItem).slice(0, 4));
const staffStatusItems = computed<StaffItem[]>(() => getDashboardArray([
  "staffStatusItems",
  "attendanceItems",
  "staffItems",
]).map(normalizeStaffItem).slice(0, 4));
const feedbackItems = computed<FeedbackItem[]>(() => getDashboardArray([
  "feedbackItems",
  "feedbacksList",
  "feedbacks",
]).map(normalizeFeedbackItem).slice(0, 4));
const recentActivities = computed<DashboardListItem[]>(() => getDashboardArray([
  "recentActivities",
  "activityItems",
]).map(normalizeActivityItem).slice(0, 3));

const EmptyDashboardState = defineComponent({
  name: "EmptyDashboardState",
  props: {
    compact: Boolean,
  },
  setup(componentProps) {
    return () => h("div", { class: ["empty-state", componentProps.compact ? "empty-state-compact" : ""] }, [
      h("i", { class: "mdi mdi-database-search-outline" }),
      h("span", "No data to display"),
    ]);
  },
});

const DashboardPanel = defineComponent({
  name: "DashboardPanel",
  props: {
    title: {
      type: String,
      required: true,
    },
    actionLabel: {
      type: String,
      default: "",
    },
    variant: {
      type: String,
      default: "",
    },
  },
  emits: ["action"],
  setup(componentProps, { slots, emit: componentEmit }) {
    return () => h("div", {
      class: [
        "dashboard-card",
        "dashboard-panel",
        componentProps.variant ? `dashboard-panel-${componentProps.variant}` : "",
      ],
    }, [
      h("div", {
        class: "panel-header",
        style: {
          alignItems: "center",
          display: "flex",
          flexDirection: "row",
          justifyContent: "space-between",
          width: "100%",
        },
      }, [
        h("h2", {
          style: {
            color: "#132b43",
            fontSize: componentProps.variant === "recent" ? "15px" : "15px",
            fontWeight: "800",
            letterSpacing: "0",
            lineHeight: "1.2",
            margin: "0",
            textTransform: componentProps.variant === "recent" ? "uppercase" : "none",
          },
        }, componentProps.title),
        componentProps.actionLabel
          ? h("button", {
            class: "panel-action",
            style: {
              appearance: "none",
              background: "transparent",
              border: "0",
              color: "#2196f3",
              cursor: "pointer",
              fontSize: "12px",
              fontWeight: "800",
              lineHeight: "1.2",
              marginLeft: "auto",
              padding: "0",
            },
            type: "button",
            onClick: () => componentEmit("action"),
          }, componentProps.actionLabel)
          : null,
      ]),
      h("div", { class: "panel-body" }, slots.default?.()),
    ]);
  },
});

const DashboardList = defineComponent({
  name: "DashboardList",
  props: {
    items: {
      type: Array as () => DashboardListItem[],
      default: () => [],
    },
    emptyIcon: {
      type: String,
      default: "mdi-database-search-outline",
    },
    alignTime: Boolean,
  },
  setup(componentProps) {
    return () => componentProps.items.length
      ? h("div", {
        class: "simple-list",
        style: {
          display: "grid",
          width: "100%",
        },
      }, componentProps.items.map((item) => {
        const tone = getActivityToneStyle(item.tone || "neutral");

        return h("div", {
          class: "simple-list-row",
          key: item.id,
          style: {
            alignItems: "center",
            background: "#fff",
            borderBottom: "1px solid #e0e0e0",
            display: "grid",
            gap: "14px",
            gridTemplateColumns: componentProps.alignTime ? "34px minmax(0, 1fr) 96px" : "34px minmax(0, 1fr)",
            minHeight: "58px",
            padding: "10px 0",
          },
        }, [
        h("span", {
          class: ["list-icon", `list-icon-${item.tone || "neutral"}`],
          style: {
            alignItems: "center",
            background: tone.background,
            borderRadius: "6px",
            color: tone.color,
            display: "inline-flex",
            fontSize: "13px",
            height: "25px",
            justifyContent: "center",
            width: "25px",
          },
        }, [
          h("i", { class: `mdi ${item.icon || componentProps.emptyIcon}` }),
        ]),
        h("div", {
          class: "list-main",
          style: {
            minWidth: "0",
          },
        }, [
          h("strong", {
            style: {
              color: "#132b43",
              display: "block",
              fontSize: "13px",
              fontWeight: "700",
              lineHeight: "1.3",
              overflow: "hidden",
              textOverflow: "ellipsis",
              whiteSpace: "nowrap",
            },
          }, item.title),
          item.subtitle ? h("p", {
            style: {
              color: "#888",
              fontSize: "12px",
              fontWeight: "500",
              lineHeight: "1.35",
              margin: "5px 0 0",
              overflow: "hidden",
              textOverflow: "ellipsis",
              whiteSpace: "nowrap",
            },
          }, item.subtitle) : null,
        ]),
        componentProps.alignTime
          ? h("span", {
            class: "list-action",
            style: {
              color: "#888",
              fontSize: "12px",
              fontWeight: "500",
              justifySelf: "end",
              textAlign: "right",
              whiteSpace: "nowrap",
            },
          }, item.time || "")
          : null,
      ]);
      }))
      : h(EmptyDashboardState);
  },
});

function getServiceDisplayName(value: string) {
  const normalized = value.toLowerCase();
  const titleMap: Record<string, string> = {
    security_agency: "Security",
    cleaning_services: "Hygiene",
    hygiene: "Hygiene",
    mechanical_electrical: "Mechanical & Electrical",
    mechanical_electrical_services: "Mechanical & Electrical",
    pest_control_services: "Pest Control",
    pool_maintenance_services: "Pool Maintenance",
    landscaping_services: "Landscaping",
    property_management_agency: "Property Management",
  };

  if (titleMap[normalized]) return titleMap[normalized];

  const cleaned = normalized
    .replace(/_services|_agency/g, "")
    .replace(/[_-]+/g, " ")
    .trim();

  return cleaned
    ? cleaned.replace(/\b\w/g, (char) => char.toUpperCase())
    : "Service";
}

function getMetric(keys: string[]): DashboardMetric {
  const data = props.dashboardData || {};
  for (const key of keys) {
    const value = data[key];
    if (value && typeof value === "object" && !Array.isArray(value)) {
      return value as DashboardMetric;
    }
  }
  return {};
}

function getMetricValue(metric: DashboardMetric, key?: string) {
  if (key === "patrolCompliance") {
    return `${formatNumber(toNumber(metric.count))}%`;
  }

  const completed = toNumber(metric.completed);
  const total = toNumber(metric.total);

  if (total > 0 && typeof metric.completed !== "undefined") {
    return `${formatNumber(completed)}/${formatNumber(total)}`;
  }

  return toNumber(metric.count);
}

function getMetricMeta(metric: DashboardMetric) {
  const parts: string[] = [];

  if (typeof metric.overdue !== "undefined") parts.push(`${formatNumber(toNumber(metric.overdue))} overdue`);
  if (typeof metric.inProgress !== "undefined") parts.push(`${formatNumber(toNumber(metric.inProgress))} in progress`);
  if (typeof metric.pending !== "undefined") parts.push(`${formatNumber(toNumber(metric.pending))} pending`);
  if (typeof metric.highSeverity !== "undefined") parts.push(`${formatNumber(toNumber(metric.highSeverity))} high severity`);
  if (typeof metric.currentlyOnSite !== "undefined") parts.push(`${formatNumber(toNumber(metric.currentlyOnSite))} currently on site`);
  if (typeof (metric as Record<string, any>).missedCheckpoints !== "undefined" || typeof (metric as Record<string, any>).missed !== "undefined") {
    parts.push(`${formatNumber(toNumber((metric as Record<string, any>).missedCheckpoints ?? (metric as Record<string, any>).missed))} checkpoint missed`);
  }
  if (typeof metric.lowStock !== "undefined") parts.push(`${formatNumber(toNumber(metric.lowStock))} low stock`);
  if (typeof metric.outOfStock !== "undefined") parts.push(`${formatNumber(toNumber(metric.outOfStock))} out of stock`);
  if (typeof metric.completed !== "undefined" && typeof metric.total !== "undefined") {
    parts.push(`${formatNumber(toNumber(metric.completed))} completed`);
  }

  return parts.join(" - ");
}

function getCardColor(index: number) {
  return ["#155178", "#9f2f29", "#1f8a56", "#b96d17"][index % 4];
}

function getCardTint(color: string, index: number) {
  const tints = ["#dbeeff", "#f8c6c3", "#d8f5e5", "#ffe7c2"];
  if (!color) return tints[index % tints.length];

  const normalized = color.toLowerCase();
  if (normalized.includes("f44336") || normalized.includes("d32f2f")) return "#f8c6c3";
  if (normalized.includes("4caf50") || normalized.includes("43a047")) return "#d8f5e5";
  if (normalized.includes("ff9800") || normalized.includes("ffa726")) return "#ffe7c2";
  return "#dbeeff";
}

function getActivityChartSource() {
  const data = props.dashboardData || {};
  return data.activityChart ||
    data.statistic?.activityChart ||
    data.statistics?.activityChart ||
    data.statisticChart ||
    data.statisticsChart ||
    data.activityStatistics ||
    data.activityStatistic ||
    {};
}

function normalizeActivityChart(source: any) {
  const labels = Array.isArray(source?.labels)
    ? source.labels.map((label: any) => String(label))
    : [];
  const primary = extractChartSeries(source, ["workOrders", "workOrder", "work_orders"]);
  const secondaryCandidate = getSecondaryChartSeries(source);

  return {
    labels,
    primary,
    secondary: secondaryCandidate.series,
    primaryLabel: "Work Order",
    secondaryLabel: secondaryCandidate.label,
  };
}

function getSecondaryChartSeries(source: any) {
  const candidates = [
    { label: "Task Completed", keys: ["taskCompleted", "completedTasks", "completed"] },
    { label: "Incident", keys: ["incidents", "incident", "incidentReports"] },
    { label: "Feedback", keys: ["feedbacks", "feedback", "feedbackTickets"] },
  ];

  for (const candidate of candidates) {
    const series = extractChartSeries(source, candidate.keys);
    if (series.length) return { label: candidate.label, series };
  }

  return { label: "Feedback", series: [] as number[] };
}

function extractChartSeries(source: any, keys: string[]) {
  for (const key of keys) {
    const value = source?.[key];
    if (Array.isArray(value)) return value.map(toNumber);
  }

  if (Array.isArray(source?.datasets)) {
    const dataset = source.datasets.find((item: any) => {
      const keyText = String(item?.key || item?.label || item?.name || "").toLowerCase();
      return keys.some((key) => keyText.includes(key.toLowerCase()));
    });
    if (Array.isArray(dataset?.data)) return dataset.data.map(toNumber);
  }

  return [];
}

function normalizeSeries(value: any, targetLength: number) {
  const source = Array.isArray(value) ? value : [];
  return Array.from({ length: targetLength }, (_, index) => toNumber(source[index]));
}

function buildChartDots(series: number[]) {
  const count = Math.max(1, series.length - 1);

  return series.map((value, index) => ({
    x: 54 + ((846 / count) * index),
    y: 220 - ((toNumber(value) / chartMax.value) * 184),
  }));
}

function getDashboardArray(keys: string[]) {
  const data = props.dashboardData || {};

  for (const key of keys) {
    const value = data[key];
    if (Array.isArray(value)) return value;
    if (Array.isArray(value?.items)) return value.items;
    if (Array.isArray(value?.docs)) return value.docs;
    if (Array.isArray(value?.data)) return value.data;
  }

  return [];
}

function getFilteredVisitorMetric(): DashboardMetric {
  const metric = getMetric(["visitors", "visitor"]);
  const selected = visitorType.value;
  const items = visitorItems.value;

  if (selected === "All") {
    return {
      ...metric,
      count: toNumber(metric.count ?? items.length),
      currentlyOnSite: toNumber(metric.currentlyOnSite ?? items.filter((item) => !isClosedStatus(item.status) && !item.checkOut).length),
    };
  }

  const filtered = items.filter((item) => getVisitorFilterValue(item) === selected);

  return {
    ...metric,
    count: filtered.length,
    currentlyOnSite: filtered.filter((item) => !isClosedStatus(item.status) && !item.checkOut).length,
  };
}

function buildFilterOptions(
  defaults: string[],
  items: Record<string, any>[],
  getValue: (item: Record<string, any>) => string,
) {
  const options = new Set(defaults);
  items.forEach((item) => {
    const value = getValue(item);
    if (value) options.add(value);
  });

  return Array.from(options);
}

function getVisitorFilterValue(item: Record<string, any>) {
  const raw = String(item.type || item.visitorType || item.category || "").toLowerCase();
  if (raw.includes("contractor")) return "Contractor";
  if (raw.includes("walk")) return "Walk-In";
  if (raw.includes("delivery")) return "Delivery";
  if (raw.includes("pick")) return "Pick-up";
  if (raw.includes("drop")) return "Drop-Off";
  if (raw.includes("guest") || raw.includes("drive")) return "Drive-In";
  return "All";
}

function normalizeTaskItem(item: Record<string, any>, index: number): TaskItem {
  const title = item.title || item.subject || item.name || item.taskName || item.description || "Task";
  const subtitle = item.subtitle || item.area || item.location || item.asset || item.category || "";
  const person = item.person || item.assigneeName || item.assignedTo?.name || item.staff?.name || item.createdBy?.name || "Unassigned";

  return {
    id: String(item.id || item._id || `${title}-${index}`),
    title,
    subtitle,
    person,
    status: normalizeStatus(item.status || item.state || item.taskStatus || "To-Do"),
    raw: item,
  };
}

function normalizeStaffItem(item: Record<string, any>, index: number): StaffItem {
  const name = item.name || item.employeeName || item.user?.name || item.staff?.name || item.createdByName || "Unassigned";
  const role = item.role || item.jobTitle || item.designation || item.position || "Officer";

  return {
    id: String(item.id || item._id || `${name}-${index}`),
    name,
    role,
    status: normalizeStatus(item.statusLabel || item.status || item.currentStatus || item.attendanceStatus || "Off duty"),
    raw: item,
  };
}

function normalizeFeedbackItem(item: Record<string, any>, index: number): FeedbackItem {
  const title = item.title || item.subject || item.description || "Feedback";
  const subject = item.category || item.type || item.service || "Subject";
  const app = item.app || item.source || item.channel || "";
  const person = item.person || item.createdByName || item.submittedBy || item.createdBy?.name || item.user?.name || "Unassigned";

  return {
    id: String(item.id || item._id || `${title}-${index}`),
    title,
    subtitle: [subject, app].filter(Boolean).join(" - "),
    person,
    status: normalizeStatus(item.status || item.state || "To-Do"),
    raw: item,
  };
}

function normalizeActivityItem(item: Record<string, any>, index: number): DashboardListItem {
  const title = item.title || item.subject || item.description || item.message || "Activity";
  const subtitle = item.subtitle || item.type || item.category || item.status || "";

  return {
    id: String(item.id || item._id || `${title}-${index}`),
    title,
    subtitle,
    time: formatActivityTime(item),
    icon: item.icon || "mdi-history",
    tone: item.tone || getStatusTone(item.status || item.type),
    raw: item,
  };
}

function formatActivityTime(item: Record<string, any>) {
  if (item.displayTime) return String(item.displayTime);

  const rawTime = item.time || getItemTime(item);
  const rawText = String(rawTime || "");

  if (!rawText) return "";
  if (/\b(ago|now|today|yesterday|min|mins|hr|hrs|hour|hours|day|days)\b/i.test(rawText)) {
    return rawText;
  }

  return formatRelativeTime(rawTime);
}

function getActivityToneStyle(tone: string) {
  const toneMap: Record<string, { background: string; color: string }> = {
    info: {
      background: "#d8ecff",
      color: "#17496f",
    },
    danger: {
      background: "#ffd9d6",
      color: "#bd413c",
    },
    success: {
      background: "#d8f4e3",
      color: "#2b9160",
    },
    warning: {
      background: "#ffe0ad",
      color: "#d88717",
    },
    neutral: {
      background: "#edf2f6",
      color: "#607386",
    },
  };

  return toneMap[tone] || toneMap.neutral;
}

function getItemTime(item: Record<string, any>) {
  return item.createdAt || item.updatedAt || item.date || item.time || item.created_on || item.updated_on;
}

function normalizeStatus(value: any) {
  const text = String(value || "").trim();
  if (!text) return "To-Do";

  return text
    .replace(/[_-]+/g, " ")
    .replace(/\b\w/g, (char) => char.toUpperCase());
}

function getStatusTone(status: any) {
  const normalized = String(status || "").toLowerCase();
  if (normalized.includes("complete") || normalized.includes("done") || normalized.includes("resolved") || normalized.includes("closed")) return "success";
  if (normalized.includes("progress") || normalized.includes("active") || normalized.includes("ongoing")) return "info";
  if (normalized.includes("overdue") || normalized.includes("urgent") || normalized.includes("high")) return "danger";
  return "neutral";
}

function getStaffTone(status: any) {
  const normalized = String(status || "").toLowerCase();
  if (normalized.includes("duty") || normalized.includes("present") || normalized.includes("active")) return "success";
  if (normalized.includes("break")) return "warning";
  if (normalized.includes("absent") || normalized.includes("off")) return "danger";
  return "neutral";
}

function isClosedStatus(status: any) {
  const normalized = String(status || "").toLowerCase();
  return normalized.includes("complete") ||
    normalized.includes("cancel") ||
    normalized.includes("reject") ||
    normalized.includes("closed") ||
    normalized.includes("deleted") ||
    normalized.includes("check-out") ||
    normalized.includes("checkout");
}

function isWidgetVisible(key: string) {
  return visibleWidgetKeys.value.includes(key);
}

function openCustomizeDialog() {
  draftVisibleWidgetKeys.value = [...visibleWidgetKeys.value];
  customizeDialog.value = true;
}

function cancelCustomize() {
  draftVisibleWidgetKeys.value = [...visibleWidgetKeys.value];
  widgetSearch.value = "";
  customizeDialog.value = false;
}

function resetCustomizeDraft() {
  draftVisibleWidgetKeys.value = [...defaultVisibleWidgetKeys.value];
}

function submitCustomize() {
  visibleWidgetKeys.value = [...draftVisibleWidgetKeys.value];
  widgetSearch.value = "";
  customizeDialog.value = false;
}

function notifyExport(format: string) {
  snackbar.text = `${format} export is being prepared.`;
  snackbar.visible = true;
}

function goToDashboardRoute(routeKey: string) {
  if (!props.orgId || !props.site) return;

  const pathMap: Record<string, string> = {
    attendance: "attendance",
    feedbacks: "feedbacks",
    scheduleTask: "schedule-task",
    virtualPatrol: "virtual-patrol/logs",
    manpower: "manpower-monitoring/attendance",
    incidentReports: "incident-reports",
    visitorManagement: "visitor-management",
    workOrders: "work-orders",
  };
  const path = pathMap[routeKey] || routeKey;
  router.push(`/${props.orgId}/${props.site}/${path}`);
}

function goToListItem(item: TaskItem | FeedbackItem, routeKey: string) {
  if (routeKey === "virtualPatrol") {
    goToDashboardRoute(routeKey);
    return;
  }

  const id = item.raw?._id || item.raw?.id || item.id;
  if (!id || String(id).includes("-")) {
    goToDashboardRoute(routeKey);
    return;
  }

  const pathMap: Record<string, string> = {
    feedbacks: "feedbacks",
    scheduleTask: "schedule-task",
  };
  const path = pathMap[routeKey] || routeKey;
  router.push(`/${props.orgId}/${props.site}/${path}/${id}`);
}

function getInitials(name: string) {
  const parts = String(name || "")
    .trim()
    .split(/\s+/)
    .filter(Boolean);
  if (!parts.length) return "?";
  return parts.slice(0, 2).map((part) => part[0]).join("").toUpperCase();
}

function formatNumber(value: number) {
  return new Intl.NumberFormat("en-US").format(toNumber(value));
}

function toNumber(value: any) {
  const numberValue = Number(value ?? 0);
  return Number.isFinite(numberValue) ? numberValue : 0;
}

function formatRelativeTime(value: any) {
  if (!value) return "";

  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "";

  const diffMs = Date.now() - date.getTime();
  const diffMinutes = Math.max(0, Math.round(diffMs / 60000));
  if (diffMinutes < 60) {
    const minutes = diffMinutes || 1;
    return `${minutes} min${minutes === 1 ? "" : "s"} ago`;
  }

  const diffHours = Math.round(diffMinutes / 60);
  if (diffHours < 24) return `${diffHours} hr${diffHours === 1 ? "" : "s"} ago`;

  const diffDays = Math.round(diffHours / 24);
  return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
}
</script>

<style scoped>
.service-dashboard {
  color: #132b43;
  padding-bottom: 32px;
}

.dashboard-header {
  align-items: flex-start;
  display: flex;
  gap: 20px;
  justify-content: space-between;
  margin-bottom: 24px;
}

.dashboard-title {
  color: #0b2f47;
  font-size: 28px;
  font-weight: 800;
  letter-spacing: 0;
  line-height: 1.2;
  margin: 0;
}

.site-label {
  align-items: center;
  color: #6d7d8b;
  display: flex;
  font-size: 13px;
  gap: 6px;
  margin-top: 8px;
}

.header-actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: flex-end;
}

.action-button {
  border-color: #d9e1e8;
  border-radius: 6px;
  color: #102b40;
  height: 36px;
  font-weight: 700;
  letter-spacing: 0.04em;
  min-height: 36px;
  padding: 0 16px;
}

.action-button :deep(.v-btn__content) {
  font-size: 15px;
  line-height: 1;
}

.action-button :deep(.v-btn__prepend) {
  margin-inline: 0 8px;
}

.action-button :deep(.v-btn__append) {
  margin-inline: 8px 0;
}

.range-toggle {
  border: 1px solid #d9e1e8;
  border-radius: 6px;
  height: 36px;
  min-height: 36px;
  overflow: hidden;
}

.range-toggle :deep(.v-btn) {
  border-radius: 0;
  color: #102b40;
  font-size: 14px;
  font-weight: 500;
  height: 34px;
  letter-spacing: 0.04em;
  min-height: 34px;
  min-width: 62px;
  padding: 0 20px;
}

.range-toggle :deep(.v-btn--active) {
  background: #e0e0e0;
}

.range-toggle :deep(.v-btn__overlay) {
  opacity: 0;
}

.export-menu,
.filter-menu {
  border-color: #d9e1e8;
  border-radius: 7px;
  box-shadow: 0 12px 30px rgba(16, 35, 54, 0.12);
}

.kpi-grid {
  margin-bottom: 14px;
}

.dashboard-card {
  background: #fff;
  border: 1px solid #d9e0e7;
  border-radius: 8px;
  box-shadow: 0 1px 2px rgba(15, 35, 54, 0.04);
}

.kpi-card {
  display: flex;
  flex-direction: column;
  min-height: 158px;
  padding: 16px 18px 18px;
}

.kpi-topline {
  align-items: flex-start;
  display: flex;
  justify-content: space-between;
}

.kpi-icon {
  align-items: center;
  border-radius: 8px;
  display: inline-flex;
  height: 28px;
  justify-content: center;
  width: 28px;
}

.kpi-icon :deep(.v-icon) {
  font-size: 15px;
  height: 15px;
  width: 15px;
}

.mini-filter {
  border-color: #d9e1e8;
  font-size: 12px;
  height: 26px;
  min-width: 50px;
  padding-inline: 10px 6px;
}

.mini-filter :deep(.v-btn__append) {
  margin-inline-start: 4px;
}

.kpi-content {
  display: flex;
  flex-direction: column;
  margin-top: 26px;
  min-width: 0;
}

.kpi-label {
  color: #2a465a;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0;
  line-height: 1.2;
  margin: 0 0 13px;
  text-transform: uppercase;
}

.kpi-value-row {
  align-items: center;
  display: flex;
  min-height: 31px;
}

.kpi-value-row strong {
  color: #092f49;
  font-size: 30px;
  font-weight: 800;
  letter-spacing: 0;
  line-height: 1;
}

.kpi-meta-row {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
  min-height: 22px;
}

.kpi-meta-row :deep(.v-chip) {
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  height: 20px;
  padding-inline: 8px;
}

.kpi-meta-row :deep(.v-chip__prepend) {
  margin-inline-end: 3px;
}

.kpi-meta {
  color: #4f6576;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.35;
  margin: 0;
}

.activity-card {
  padding: 18px 20px 14px;
}

.section-header,
.panel-header {
  align-items: center;
  display: flex;
  justify-content: space-between;
}

.section-header h2,
.panel-header h2 {
  color: #132b43;
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0;
  line-height: 1.2;
  margin: 0;
}

.chart-wrap {
  margin-top: 18px;
}

.activity-chart {
  display: block;
  height: 260px;
  width: 100%;
}

.chart-grid {
  stroke: #e9eef2;
  stroke-width: 1;
}

.primary-line,
.secondary-line {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 3;
}

.primary-line {
  stroke: #2196f3;
}

.secondary-line {
  stroke: #1eca6b;
}

.primary-dot,
.secondary-dot {
  stroke: #fff;
  stroke-width: 2;
}

.primary-dot {
  fill: #2196f3;
}

.secondary-dot {
  fill: #1eca6b;
}

.chart-label {
  fill: #7e8b96;
  font-size: 12px;
  font-weight: 600;
}

.chart-legend {
  align-items: center;
  display: flex;
  gap: 18px;
  justify-content: center;
  margin-top: 10px;
}

.chart-legend span {
  align-items: center;
  color: #6d7c88;
  display: inline-flex;
  font-size: 12px;
  font-weight: 700;
  gap: 7px;
}

.legend-dot {
  border-radius: 50%;
  display: inline-flex;
  height: 8px;
  width: 8px;
}

.legend-dot.primary {
  background: #2196f3;
}

.legend-dot.secondary {
  background: #1eca6b;
}

.dashboard-section-grid {
  align-items: stretch;
  margin-top: 14px;
}

.dashboard-section-grid > .v-col {
  display: flex;
}

.dashboard-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 24px;
  width: 100%;
}

.dashboard-panel-recent {
  min-height: 224px;
  padding: 26px 30px 16px;
}

.panel-body {
  flex: 1;
  margin-top: 20px;
  max-height: 380px;
  overflow-y: auto;
}

.panel-action,
.row-action {
  appearance: none;
  background: transparent;
  border: 0;
  color: #2196f3;
  cursor: pointer;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0;
  line-height: 1.2;
  padding: 0;
}

.panel-action {
  margin-right: -10px;
  padding: 0 10px;
}

.task-list,
.feedback-list,
.staff-list {
  display: grid;
  gap: 10px;
}

.task-row,
.feedback-row {
  align-items: center;
  background: #fff;
  border: 1px solid #e0e5ea;
  border-radius: 8px;
  display: grid;
  gap: 16px;
  min-height: 76px;
  padding: 15px 15px 15px 10px;
}

.task-row {
  grid-template-columns: minmax(220px, 280px) minmax(130px, 170px) minmax(82px, 120px) minmax(44px, 1fr);
}

.feedback-row {
  grid-template-columns: minmax(220px, 280px) minmax(130px, 170px) minmax(82px, 120px) minmax(44px, 1fr);
}

.task-row:hover,
.feedback-row:hover,
.staff-row:hover,
.simple-list-row:hover {
  border-color: #d8e3ec;
  box-shadow: 0 6px 14px rgba(15, 44, 69, 0.04);
}

.task-summary,
.feedback-summary,
.staff-main,
.list-main {
  min-width: 0;
}

.task-summary,
.feedback-summary {
  padding: 0 10px;
}

.task-summary strong,
.feedback-summary strong,
.staff-main strong,
.list-main strong {
  color: #132b43;
  display: block;
  font-size: 13px;
  font-weight: 800;
  line-height: 1.3;
  white-space: normal;
}

.task-summary p,
.feedback-summary p,
.staff-main p,
.list-main p {
  color: #888;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.35;
  margin: 5px 0 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.person-cell {
  align-items: center;
  color: #888;
  display: inline-flex;
  font-size: 12px;
  font-weight: 600;
  gap: 7px;
  min-width: 0;
}

.person-cell span:last-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.avatar {
  align-items: center;
  background: #e0e0e0;
  border-radius: 999px;
  color: #fff;
  display: inline-flex;
  flex: 0 0 34px;
  font-size: 11px;
  font-weight: 800;
  height: 34px;
  justify-content: center;
  letter-spacing: 0;
  width: 34px;
}

.status-pill {
  align-items: center;
  border-radius: 999px;
  display: inline-flex;
  font-size: 12px;
  font-weight: 600;
  justify-content: center;
  line-height: 1;
  min-height: 26px;
  padding: 6px 10px;
  white-space: nowrap;
  width: fit-content;
}

.status-pill-success {
  background: rgba(30, 202, 107, 0.5);
  color: #015b29;
}

.status-pill-info {
  background: #d8ecff;
  color: #14557d;
}

.status-pill-warning {
  background: #ffe9c7;
  color: #9c5e0e;
}

.status-pill-danger {
  background: #ffd9d6;
  color: #9f2f29;
}

.status-pill-neutral {
  background: #e0e0e0;
  color: #616065;
}

.row-action-right {
  justify-self: end;
}

.task-row .row-action-right {
  align-items: center;
  background: #fff;
  border: 1px solid #b9ddfb;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(33, 150, 243, 0.1);
  color: #0b8ff1;
  display: inline-flex;
  height: 32px;
  justify-content: center;
  min-width: 54px;
  padding: 0 12px;
}

.task-row .row-action-right:hover {
  background: #f2f9ff;
  border-color: #80c3f7;
  color: #0878d3;
}

.feedback-row .row-action-right {
  padding-right: 8px;
}

.staff-row {
  align-items: center;
  background: #fff;
  border: 1px solid #e0e5ea;
  border-radius: 8px;
  display: grid;
  gap: 10px;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  min-height: 68px;
  padding: 12px 14px;
}

.simple-list {
  display: grid;
}

.simple-list-row {
  align-items: center;
  background: #fff;
  border-bottom: 1px solid #e8edf1;
  display: grid;
  gap: 14px;
  grid-template-columns: 30px minmax(0, 1fr) 82px;
  min-height: 58px;
  padding: 9px 0;
}

.simple-list-row:last-child {
  border-bottom: 0;
}

.simple-list-row:hover {
  box-shadow: none;
}

.list-icon {
  align-items: center;
  border-radius: 6px;
  display: inline-flex;
  flex: 0 0 auto;
  font-size: 13px;
  height: 25px;
  justify-content: center;
  width: 25px;
}

.list-action {
  color: #768493;
  font-size: 12px;
  font-weight: 700;
  justify-self: end;
  text-align: right;
  white-space: nowrap;
}

.list-icon-info {
  background: #d8ecff;
  color: #17496f;
}

.list-icon-danger {
  background: #ffd9d6;
  color: #bd413c;
}

.list-icon-success {
  background: #d8f4e3;
  color: #2b9160;
}

.list-icon-warning {
  background: #ffe9c7;
  color: #be7418;
}

.list-icon-neutral {
  background: #edf2f6;
  color: #607386;
}

.empty-state {
  align-items: center;
  color: #8a98a5;
  display: flex;
  flex-direction: column;
  font-size: 13px;
  font-weight: 700;
  gap: 8px;
  justify-content: center;
  min-height: 140px;
  text-align: center;
}

.empty-state i {
  font-size: 28px;
}

.empty-state-compact {
  min-height: 72px;
}

.customize-dialog {
  background: #fff;
}

.customize-dialog-header {
  align-items: flex-start;
  border-bottom: 1px solid #eef2f5;
  display: flex;
  justify-content: space-between;
  padding: 24px 26px 18px;
}

.customize-dialog-header h2 {
  color: #0b2f47;
  font-size: 20px;
  font-weight: 800;
  line-height: 1.2;
  margin: 0;
}

.customize-dialog-header p {
  color: #71808d;
  font-size: 13px;
  margin: 6px 0 0;
}

.customize-dialog-body {
  padding: 20px 26px 8px;
}

.reset-row {
  display: flex;
  justify-content: flex-end;
  margin: 12px 0;
}

.widget-list {
  display: grid;
  gap: 10px;
}

.widget-row {
  align-items: center;
  border: 1px solid #e2e8ee;
  border-radius: 8px;
  display: flex;
  gap: 16px;
  justify-content: space-between;
  padding: 14px 16px;
}

.widget-row strong {
  color: #132b43;
  display: block;
  font-size: 14px;
  font-weight: 800;
}

.widget-row p {
  color: #71808d;
  font-size: 12px;
  margin: 4px 0 0;
}

.customize-dialog-actions {
  border-top: 1px solid #eef2f5;
  gap: 10px;
  justify-content: flex-end;
  padding: 16px 26px 22px;
}

.cancel-button {
  color: #607386;
  font-weight: 800;
}

.submit-button {
  background: #0b2f47;
  color: #fff;
  font-weight: 800;
  min-width: 110px;
}

@media (max-width: 960px) {
  .dashboard-header {
    align-items: stretch;
    flex-direction: column;
  }

  .header-actions {
    justify-content: flex-start;
  }

  .task-row,
  .feedback-row {
    grid-template-columns: 1fr;
  }

  .row-action-right {
    justify-self: start;
  }

  .status-pill {
    margin-left: 0;
  }
}

@media (max-width: 640px) {
  .dashboard-title {
    font-size: 24px;
  }

  .header-actions,
  .action-button,
  .range-toggle {
    width: 100%;
  }

  .range-toggle :deep(.v-btn) {
    flex: 1 1 0;
  }

  .kpi-card,
  .activity-card,
  .dashboard-panel {
    padding: 16px;
  }

  .kpi-card {
    min-height: 154px;
  }

  .kpi-content {
    margin-left: 0;
    margin-top: 22px;
  }

  .kpi-value-row strong {
    font-size: 26px;
  }

  .staff-row {
    grid-template-columns: 30px minmax(0, 1fr);
  }

  .staff-row .status-pill {
    grid-column: 2;
  }

  .simple-list-row {
    grid-template-columns: 30px minmax(0, 1fr);
  }

  .list-action {
    grid-column: 2;
    justify-self: start;
  }
}
</style>
