<template>
  <q-page class="owner-dashboard-page">
    <DefaultHeaderPage />

    <div class="dashboard-shell">
      <q-banner
        v-if="!hasProperties"
        class="bg-surface text-text radius-8"
        rounded
      >
        Nenhum imóvel vinculado ao proprietário autenticado.
      </q-banner>

      <template v-else>
        <div class="dashboard-header">
          <div class="dashboard-title">Dashboard</div>

          <div class="dashboard-filters">
            <q-select
              v-model="selectedPropertyOption"
              class="dashboard-filter dashboard-filter--property"
              dense
              label="Imóveis"
              option-label="label"
              outlined
              :options="propertyOptions"
              @update:model-value="handlePropertyChange"
            />

            <q-select
              v-model="selectedMonth"
              class="dashboard-filter dashboard-filter--month"
              dense
              emit-value
              map-options
              label="Mês"
              option-label="label"
              option-value="value"
              outlined
              :options="monthOptions"
              @update:model-value="handleMonthChange"
            >
              <template #append>
                <q-icon name="event" />
              </template>
            </q-select>

            <q-select
              v-model="selectedYear"
              class="dashboard-filter dashboard-filter--year"
              dense
              emit-value
              label="Ano"
              map-options
              option-label="label"
              option-value="value"
              outlined
              :options="yearOptions"
              @update:model-value="handleYearChange"
            />

            <q-btn-dropdown
              class="dashboard-export-btn"
              color="primary"
              label="Exportar"
              no-caps
              unelevated
              :disable="loading || exporting || !canExportReport"
              :loading="exporting"
            >
              <q-list dense>
                <q-item v-close-popup clickable @click="exportDashboardReport('xlsx')">
                  <q-item-section>XLSX</q-item-section>
                </q-item>

                <q-item v-close-popup clickable @click="exportDashboardReport('pdf')">
                  <q-item-section>PDF</q-item-section>
                </q-item>
              </q-list>
            </q-btn-dropdown>
          </div>
        </div>

        <q-separator class="dashboard-separator" />

        <div class="metrics-grid">
          <DashboardMetricCard
            v-for="card in firstRowCards"
            :key="card.label"
            :caption="card.caption"
            :label="card.label"
            :value="card.value"
          />
        </div>

        <div class="metrics-grid">
          <DashboardMetricCard
            v-for="card in secondRowCards"
            :key="card.label"
            :caption="card.caption"
            :label="card.label"
            :value="card.value"
          />
        </div>

        <div class="dashboard-panels">
          <q-card flat class="panel-card panel-card--soft panel-card--channels">
            <div class="panel-title">Canais de Aquisição</div>

            <div class="channel-chart-wrap">
              <div class="channel-chart-box">
                <Doughnut
                  :data="channelChartData"
                  :options="channelChartOptions"
                />
              </div>
            </div>

            <div class="channel-legend">
              <div
                v-for="channel in channelLegendItems"
                :key="channel.key"
                class="channel-legend-item"
              >
                <span
                  class="channel-dot"
                  :style="{ backgroundColor: channel.color }"
                />

                <span class="channel-name">
                  {{ channel.label }}
                </span>

                <strong class="channel-total">
                  {{ formatInteger(channel.reservations_count) }}
                </strong>

                <span class="channel-caption">
                  {{ reservationsLabel(channel.reservations_count) }}
                </span>
              </div>
            </div>
          </q-card>

          <q-card flat class="panel-card">
            <div class="panel-title">Repasses por Unidade</div>

            <DashboardPayoutTable
              :rows="payoutRows"
              :total-reservations="Number(summary.reservations_count ?? 0)"
              :total-value="Number(summary.owner_payout_amount ?? 0)"
            />
          </q-card>

          <q-card flat class="panel-card panel-card--soft">
            <div class="panel-title">Disponibilidade do Período</div>

            <div class="availability-list">
              <div
                v-for="item in availabilityItems"
                :key="item.label"
                class="availability-item"
              >
                <div class="availability-track">
                  <div
                    class="availability-bar"
                    :style="{
                      width: `${item.percentage}%`,
                      backgroundColor: item.color,
                    }"
                  >
                    <div class="availability-bar-content">
                      <span class="availability-bar-label">{{ item.label }}</span>
                      <span class="availability-bar-value">{{ item.valueLabel }}</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <div class="availability-total">
              {{ isAllPropertiesSelected
                ? "Total: 100% do período consolidado"
                : `Total: ${formatInteger(totalCapacityDays)} dias no período` }}
            </div>
          </q-card>

          <q-card flat class="panel-card">
            <div class="panel-title">Evolução do Faturamento</div>

            <div class="line-chart-wrap">
              <Line
                :data="revenueChartData"
                :options="revenueChartOptions"
              />
            </div>
          </q-card>
        </div>
      </template>

      <q-inner-loading :showing="loading">
        <q-spinner color="primary" size="48px" />
      </q-inner-loading>
    </div>
  </q-page>
</template>

<script setup>
import {
  ArcElement,
  CategoryScale,
  Chart as ChartJS,
  Filler,
  Legend,
  LineElement,
  LinearScale,
  PointElement,
  Tooltip,
} from "chart.js";

import { computed, onMounted, ref } from "vue";
import { Doughnut, Line } from "vue-chartjs";
import { useQuasar } from "quasar";

import {
  downloadOwnerDashboardReport,
  getOwnerDashboard,
} from "src/api/ownerDashboard";

import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
import DashboardMetricCard from "./components/DashboardMetricCard.vue";
import DashboardPayoutTable from "./components/DashboardPayoutTable.vue";

ChartJS.register(
  ArcElement,
  CategoryScale,
  Filler,
  Legend,
  LineElement,
  LinearScale,
  PointElement,
  Tooltip,
);

const $q = useQuasar();

const dashboard = ref(null);
const loading = ref(false);
const exporting = ref(false);
const selectedPropertyOption = ref(null);
const selectedMonth = ref(null);
const selectedYear = ref(null);
const revenueSeries = ref([]);
const dashboardRequestId = ref(0);
const historyRequestId = ref(0);

const defaultSummary = Object.freeze({
  reserve_total: 0,
  total_forward_fee_all: 0,
  owner_payout_amount: 0,
  final_payout_amount: 0,
  total_expenses_amount: 0,
  occupied_nights_in_month: 0,
  occupancy_rate: 0,
  average_price_per_night: null,
  average_reservation_ticket: null,
  average_nights_per_reservation: 0,
  maintenance_days: 0,
  cleanings_count: 0,
  expenses: 0,
  reservations_count: 0,
  available_days: 0,
  days_in_month: 30,
  properties_count: 1,
});

const monthLabels = [
  "Janeiro",
  "Fevereiro",
  "Março",
  "Abril",
  "Maio",
  "Junho",
  "Julho",
  "Agosto",
  "Setembro",
  "Outubro",
  "Novembro",
  "Dezembro",
];

const availableReferences = computed(
  () => dashboard.value?.filters?.available_references ?? [],
);

const selectedFilters = computed(
  () => dashboard.value?.filters?.selected ?? {},
);

const channels = computed(() => dashboard.value?.channels ?? []);

//

const propertyOptions = computed(() => {
  const properties = dashboard.value?.filters?.properties ?? [];

  return [
    { id: null, label: "Todos os imóveis" },
    ...properties.map((property) => ({
      id: property.id,
      label: property.label,
    })),
  ];
});

const selectedPropertyId = computed(() => {
  return selectedPropertyOption.value?.id ?? null;
});

const hasProperties = computed(() => propertyOptions.value.length > 1);

const canExportReport = computed(
  () => hasProperties.value && dashboard.value !== null && selectedPropertyId.value !== null,
);

//

const isAllPropertiesSelected = computed(() => selectedPropertyId.value === null);

const payoutRows = computed(
  () => dashboard.value?.properties_breakdown ?? [],
);

const summary = computed(() => dashboard.value?.summary ?? defaultSummary);

const totalCapacityDays = computed(
  () => Math.max(1, Number(summary.value.days_in_month ?? 0) * Number(summary.value.properties_count ?? 1)),
);

//

const yearOptions = computed(() => {
  const years = [...new Set(availableReferences.value.map((reference) => reference.reference_year))];

  return years
    .sort((a, b) => b - a)
    .map((year) => ({
      label: String(year),
      value: year,
    }));
});

const monthOptions = computed(() => {
  if (!selectedYear.value) {
    return [];
  }

  const months = [...new Set(
    availableReferences.value
      .filter((reference) => reference.reference_year === selectedYear.value)
      .map((reference) => reference.reference_month),
  )];

  return months
    .sort((a, b) => a - b)
    .map((month) => ({
      label: monthLabels[month - 1] ?? String(month),
      value: month,
    }));
});

//

const buildMetricCards = () => [
  {
    label: "Faturamento Bruto",
    value: formatCurrency(summary.value.reserve_total),
    caption: "Valor pago pelo hóspede no período",
  },
  {
    label: "Faturamento Líquido",
    value: formatCurrency(summary.value.owner_payout_amount),
    caption: "Saldo líquido conforme a planilha",
  },
  {
    label: "Diária Média",
    value: formatCurrency(summary.value.average_price_per_night),
    caption: "Média por diária ocupada",
  },
  {
    label: "Ticket Médio/Reserva",
    value: formatCurrency(summary.value.average_reservation_ticket),
    caption: "Valor médio por reserva",
  },
  {
    label: "Repasse Total",
    value: formatCurrency(summary.value.owner_payout_amount),
    caption: "Repasse ao proprietário no período",
  },
  {
    label: "Ocupação",
    value: formatPercent(summary.value.occupancy_rate, 1),
    caption: `${formatInteger(summary.value.occupied_nights_in_month)} diárias ocupadas`,
  },
  {
    label: "Total de Reservas",
    value: formatInteger(summary.value.reservations_count),
    caption: "Reservas consolidadas no período",
  },
  {
    label: "Dias por Reserva",
    value: formatDecimal(summary.value.average_nights_per_reservation),
    caption: "Média de permanência",
  },
  {
    label: "Limpeza",
    value: formatInteger(summary.value.cleanings_count),
    caption: "Total de limpezas no período",
  },
  {
    label: "Despesas",
    value: formatCurrency(summary.value.expenses),
    caption: "Despesas cadastradas no dashboard",
  },
];

const allMetricCards = computed(buildMetricCards);
const firstRowCards  = computed(() => allMetricCards.value.slice(0, 5));
const secondRowCards = computed(() => allMetricCards.value.slice(5, 10));

const availabilityItems = computed(() => {
  const total = totalCapacityDays.value;
  const items = [
    {
      label: "Dias Ocupados",
      value: Number(summary.value.occupied_nights_in_month ?? 0),
      color: "#B7F35A",
    },
    {
      label: "Dias Disponíveis",
      value: Number(summary.value.available_days ?? 0),
      color: "#7AA7AA",
    },
    {
      label: "Dias de Manutenção",
      value: Number(summary.value.maintenance_days ?? 0),
      color: "#FFC86D",
    },
  ];

  return items.map((item) => ({
    ...item,
    valueLabel: isAllPropertiesSelected.value
      ? formatPercent(total > 0 ? (item.value * 100) / total : 0, 1)
      : `${formatInteger(item.value)} dias`,
    percentage: total > 0 ? Number(((item.value * 100) / total).toFixed(2)) : 0,
  }));
});

const channelLegendItems = computed(() => {
  const normalizedChannels = new Map(
    channels.value.map((channel) => [normalizeChannelKey(channel.channel), channel]),
  );

  const preferredChannels = [
    createChannelLegendItem("AirBnb", "#FF2D55", normalizedChannels.get("airbnb")),
    createChannelLegendItem("Kizzo", "#08514C", normalizedChannels.get("kizzo")),
    createChannelLegendItem("API Booking", "#399FE7", normalizedChannels.get("booking")),
  ];

  const extraChannels = channels.value
    .filter((channel) => !["airbnb", "kizzo", "booking"].includes(normalizeChannelKey(channel.channel)))
    .map((channel) => createChannelLegendItem(channel.channel, null, channel));

  return [...preferredChannels, ...extraChannels];
});

const channelChartData = computed(() => {
  const itemsWithValue = channelLegendItems.value.filter((item) => item.reservations_count > 0);

  if (!itemsWithValue.length) {
    return {
      labels: ["Sem reservas"],
      datasets: [
        {
          data: [1],
          backgroundColor: ["#D8E0E5"],
          borderWidth: 0,
        },
      ],
    };
  }

  return {
    labels: itemsWithValue.map((item) => item.label),
    datasets: [
      {
        data: itemsWithValue.map((item) => item.reservations_count),
        backgroundColor: itemsWithValue.map((item) => item.color),
        borderWidth: 0,
      },
    ],
  };
});

const channelChartOptions = {
  responsive: true,
  maintainAspectRatio: false,
  cutout: "0%",
  plugins: {
    legend: {
      display: false,
    },
    tooltip: {
      callbacks: {
        label: (context) => `${context.label}: ${formatInteger(context.raw)} reservas`,
      },
    },
  },
};

const revenueChartData = computed(() => {
  const series = revenueSeries.value.length
    ? revenueSeries.value
    : [
      {
        label: shortMonthLabel(selectedMonth.value, selectedYear.value),
        value: Number(summary.value.reserve_total ?? 0),
      },
    ];

  return {
    labels: series.map((item) => item.label),
    datasets: [
      {
        label: "Faturamento",
        data: series.map((item) => item.value),
        borderColor: "#399FE7",
        backgroundColor: "rgba(57, 159, 231, 0.14)",
        borderWidth: 2,
        fill: true,
        tension: 0.35,
        pointBackgroundColor: "#399FE7",
        pointBorderColor: "#399FE7",
        pointRadius: 3,
        pointHoverRadius: 4,
      },
    ],
  };
});

const revenueChartOptions = computed(() => ({
  responsive: true,
  maintainAspectRatio: false,
  plugins: {
    legend: {
      display: false,
    },
    tooltip: {
      displayColors: false,
      callbacks: {
        label: (context) => formatCurrency(context.raw),
      },
    },
  },
  scales: {
    x: {
      grid: {
        display: false,
      },
      ticks: {
        color: "#7B878C",
      },
    },
    y: {
      beginAtZero: true,
      grid: {
        color: "rgba(8, 81, 76, 0.08)",
      },
      ticks: {
        color: "#7B878C",
        callback: (value) => formatCurrencyCompact(value),
      },
    },
  },
}));

//

const formatCurrency = (value) => {
  return new Intl.NumberFormat("pt-BR", {
    style: "currency", currency: "BRL", minimumFractionDigits: 2,
  }).format(Number(value ?? 0));
}

const formatCurrencyCompact = (value) => {
  return new Intl.NumberFormat("pt-BR", {
    style:    "currency",
    currency: "BRL",
    notation: "compact",
    maximumFractionDigits: 1,
  }).format(Number(value ?? 0));
}

const formatInteger = (value) => {
  return Number(value ?? 0).toLocaleString("pt-BR");
}

const formatPercent = (value, digits = 2) => {
  return `${Number(value ?? 0).toFixed(digits).replace(".", ",")}%`;
}

const formatDecimal = (value) => {
  return Number(value ?? 0).toLocaleString("pt-BR", {
    minimumFractionDigits: 1,
    maximumFractionDigits: 1,
  });
}

//

const normalizeChannelKey = (channel) => {
  const normalized = String(channel ?? "")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase()
    .trim();

  if (!normalized || normalized === "sem canal") {
    return "kizzo";
  }

  if (normalized.includes("booking")) {
    return "booking";
  }

  if (normalized.includes("airbnb")) {
    return "airbnb";
  }

  if (normalized.includes("kizzo")) {
    return "kizzo";
  }

  return normalized || "kizzo";
}

const shortMonthLabel = (month, year) => {
  if (!month || !year) {
    return "-";
  }

  return new Intl.DateTimeFormat("pt-BR", {
    month: "short",
  })
    .format(new Date(year, month - 1, 1))
    .replace(".", "");
}

//

const buildDashboardParams = ({ year, month, propertyId, format } = {}) => {
  const params = {};

  if (year) {
    params.year = year;
  }

  if (month) {
    params.month = month;
  }

  if (propertyId !== null && propertyId !== undefined) {
    params.property_id = propertyId;
  }

  if (format) {
    params.format = format;
  }

  return params;
}

const buildFallbackReportFilename = (format) => {
  const year = String(selectedYear.value ?? "0000");

  const month = String(selectedMonth.value ?? "00").padStart(2, "0");

  const propertySegment = selectedPropertyId.value === null
    ? "all-properties"
    : `property_${selectedPropertyId.value}`;

  return `owner_dashboard_report_${year}${month}_${propertySegment}.${format}`;
}

const findPropertyOptionById = (propertyId) => {
  return propertyOptions.value.find((option) => option.id === propertyId) ?? propertyOptions.value[0] ?? null;
}

const createChannelLegendItem = (label, color, channelData) => {
  return {
    key: normalizeChannelKey(label),
    label,
    color: color ?? generateChannelColor(label),
    reservations_count: Number(channelData?.reservations_count ?? 0),
  };
}

const downloadBlob = (blob, filename) => {
  const url  = window.URL.createObjectURL(blob);
  const link = document.createElement("a");

  link.href     = url;
  link.download = filename;

  document.body.appendChild(link);

  link.click();

  document.body.removeChild(link);

  window.URL.revokeObjectURL(url);
}

const generateChannelColor = (seed) => {
  const input = String(seed ?? "canal");

  let hash = 0;

  for (let index = 0; index < input.length; index += 1) {
    hash = input.charCodeAt(index) + ((hash << 5) - hash);
  }

  const hue = Math.abs(hash) % 360;

  return `hsl(${hue} 62% 54%)`;
}

const reservationsLabel = (count) => {
  return Number(count ?? 0) === 1 ? "1 reserva" : `${formatInteger(count)} reservas`;
}

const resolveReportFilename = (response, format) => {
  const explicitHeader = response.headers["x-report-filename"];

  if (explicitHeader) {
    return explicitHeader;
  }

  const contentDisposition = response.headers["content-disposition"];
  const utf8Match = contentDisposition?.match(/filename\*=UTF-8''([^;]+)/i);

  if (utf8Match?.[1]) {
    return decodeURIComponent(utf8Match[1]);
  }

  const asciiMatch = contentDisposition?.match(/filename="?([^"]+)"?/i);

  if (asciiMatch?.[1]) {
    return asciiMatch[1];
  }

  return buildFallbackReportFilename(format);
}



const extractBlobErrorMessage = async (blob) => {
  if (!(blob instanceof Blob)) {
    return null;
  }

  try {
    const text   = await blob.text();
    const parsed = JSON.parse(text);

    return parsed?.message ?? null;
  } catch {
    return null;
  }
}

const exportDashboardReport = async (format) => {
  if (!canExportReport.value) {
    return;
  }

  exporting.value = true;

  try {
    const response = await downloadOwnerDashboardReport(buildDashboardParams({
      year:       selectedYear.value,
      month:      selectedMonth.value,
      propertyId: selectedPropertyId.value,
      format,
    }));

    downloadBlob(response.data, resolveReportFilename(response, format));
  } catch (error) {
    const blobMessage = await extractBlobErrorMessage(error?.response?.data);

    $q.notify({
      type: "negative", message: blobMessage ?? "Não foi possível exportar o relatório do dashboard.",
    });
  } finally {
    exporting.value = false;
  }
}

const fetchRevenueHistory = async (payload) => {
  const requestId = ++historyRequestId.value;

  const references = (payload?.filters?.available_references ?? [])
    .slice(0, 6)
    .reverse();

  if (!references.length) {
    revenueSeries.value = [];
    return;
  }

  try {
    const propertyId = payload?.filters?.selected?.property_id ?? null;

    const responses = await Promise.all(
      references.map(async (reference) => {
        const historyPayload = await getOwnerDashboard(
          buildDashboardParams({
            year:  reference.reference_year,
            month: reference.reference_month,
            propertyId,
          }),
        );

        return {
          label: shortMonthLabel(reference.reference_month, reference.reference_year),
          value: Number(historyPayload?.summary?.reserve_total ?? 0),
        };
      }),
    );

    if (requestId === historyRequestId.value) {
      revenueSeries.value = responses;
    }
  } catch {
    if (requestId === historyRequestId.value) {
      revenueSeries.value = [];
    }
  }
}

const fetchDashboard = async ({ year, month, propertyId } = {}) =>   {
  const requestId = ++dashboardRequestId.value;

  loading.value = true;

  try {
    const payload = await getOwnerDashboard(
      buildDashboardParams({ year, month, propertyId }),
    );

    if (requestId !== dashboardRequestId.value) {
      return;
    }

    dashboard.value = payload;

    selectedPropertyOption.value = findPropertyOptionById(payload.filters.selected?.property_id ?? null);
    selectedMonth.value = payload.filters.selected?.reference_month ?? null;
    selectedYear.value = payload.filters.selected?.reference_year ?? null;

    await fetchRevenueHistory(payload);
  } catch (error) {
    if (requestId !== dashboardRequestId.value) {
      return;
    }

    $q.notify({
      type: "negative",
      message: error?.response?.data?.message ?? "Não foi possível carregar o dashboard do proprietário.",
    });
  } finally {
    if (requestId === dashboardRequestId.value) {
      loading.value = false;
    }
  }
}

const handlePropertyChange = async (propertyOption) => {
  const nextPropertyId = propertyOption?.id ?? null;
  const currentPropertyId = selectedFilters.value.property_id ?? null;

  if (nextPropertyId === currentPropertyId) {
    return;
  }

  await fetchDashboard({
    year: selectedYear.value,
    month: selectedMonth.value,
    propertyId: nextPropertyId,
  });
}

const handleMonthChange = async (month) => {
  if (month === selectedFilters.value.reference_month) {
    return;
  }

  await fetchDashboard({
    year: selectedYear.value,
    month,
    propertyId: selectedPropertyId.value,
  });
}

const handleYearChange = async (year) => {
  const availableMonth = availableReferences.value
    .filter((reference) => reference.reference_year === year)
    .sort((a, b) => b.reference_month - a.reference_month)[0]?.reference_month ?? selectedMonth.value;

  if (
    year === selectedFilters.value.reference_year
    && availableMonth === selectedFilters.value.reference_month
  ) {
    return;
  }

  await fetchDashboard({
    year,
    month: availableMonth,
    propertyId: selectedPropertyId.value,
  });
}

onMounted(async () => {
  await fetchDashboard();
});
</script>

<style scoped lang="scss">
.owner-dashboard-page {
  position: relative;
}

.dashboard-shell {
  position:       relative;
  display:        flex;
  flex-direction: column;
  gap:            16px;
}

.dashboard-header {
  display:         flex;
  align-items:     center;
  justify-content: space-between;
  gap:             16px;
  flex-wrap:       wrap;
  vertical-align:  middle;
}

.dashboard-title {
  font-size:   28px;
  font-weight: 700;
  color:       #202427;
  line-height: 1.1;
}

.dashboard-filters {
  display:         flex;
  align-items:     center;
  justify-content: flex-end;
  gap:             12px;
  flex-wrap:       wrap;
  margin-left:     auto;
  vertical-align:  middle;
}

.dashboard-filter {
  min-width: 120px;
}

.dashboard-filter--property {
  min-width: 220px;
}

.dashboard-filter--month,
.dashboard-filter--year {
  min-width: 110px;
}

.dashboard-export-btn {
  height: 40px;
}

.dashboard-separator {
  margin-top: -4px;
  background: rgba(8, 81, 76, 0.12);
}

.metrics-grid {
  display: grid;

  grid-template-columns: repeat(5, minmax(0, 1fr));

  gap: 12px;
}

.dashboard-panels {
  display: grid;

  grid-template-columns: repeat(2, minmax(0, 1fr));

  gap:         16px;
  align-items: start;
}

.panel-card {
  padding:       18px;
  border-radius: 14px;
  background:    #ffffff;
  border:        1px solid #d9e3e7;
  min-height:    300px;
  vertical-align: middle;
}

.panel-card--soft {
  background: #f0f3f5;
}

.panel-card--channels {
  min-height: 0;
  align-self: start;
}

.panel-title {
  margin-bottom: 16px;
  font-size:     16px;
  font-weight:   700;
  color:         #08514c;
}

.channel-chart-wrap {
  display:         flex;
  justify-content: center;
  padding:         8px 0 16px;
}

.channel-chart-box {
  width:  min(240px, 100%);
  height: 240px;
}

.channel-legend {
  display: grid;

  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));

  gap:           14px;
  justify-items: center;
  text-align:    center;
}

.channel-legend-item {
  display:        flex;
  flex-direction: column;
  align-items:    center;
  gap:            4px;
  vertical-align: middle;
}

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

.channel-name {
  display:     inline-flex;
  align-items: center;
  gap:         8px;
  font-size:   13px;
  font-weight: 600;
  color:       #273136;
}

.channel-total {
  font-size: 14px;
  color:     #1d2327;
}

.channel-caption {
  font-size: 11px;
  color:     #7b878c;
}

.availability-list {
  display:        flex;
  flex-direction: column;
  gap:            16px;
}

.availability-item {
  display:        flex;
  flex-direction: column;
  gap:            10px;
}

.availability-track {
  width:      100%;
  height:     38px;
  overflow:   hidden;
  background: #dde5e8;
}

.availability-bar {
  height:    100%;
  min-width: fit-content;
}

.availability-bar-content {
  display:         flex;
  align-items:     center;
  justify-content: space-between;
  gap:             12px;
  min-width:       100%;
  height:          100%;
  padding:         0 12px;
  color:           #1d2327;
  font-size:       12px;
  font-weight:     600;
  white-space:     nowrap;
}

.availability-bar-value {
  margin-left: auto;
  text-align:  right;
}

.availability-total {
  margin-top: 18px;
  font-size:  12px;
  color:      #657177;
}

.availability-total {
  text-align: center;
}

.owner-dashboard-page :deep(.text-h6.text-bold) {
  display: none;
}

.line-chart-wrap {
  height: 235px;
}

@media (max-width: 1380px) {
  .metrics-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 1024px) {
  .dashboard-panels {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 900px) {
  .metrics-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .dashboard-filters {
    width:           100%;
    margin-left:     0;
    justify-content: stretch;
  }

  .dashboard-filter,
  .dashboard-filter--property,
  .dashboard-filter--month,
  .dashboard-filter--year {
    width:     100%;
    min-width: 100%;
  }

  .metrics-grid {
    grid-template-columns: 1fr;
  }

  .availability-bar {
    min-width: 0;
  }
}
</style>
