<script setup>
import { computed, onMounted, reactive, ref } from 'vue'
import { accountApi } from '@/api/accountApi'
import IconBtn from '@/components/ui/IconBtn.vue'

const now = new Date()
const year = ref(now.getFullYear())
const month = ref(now.getMonth() + 1)
const unit = ref('MONTH') // DAY / WEEK / MONTH / YEAR
const tableYear = ref(now.getFullYear()) // 월별 총액 표 전용 연도
const currentYear = now.getFullYear()

const loading = ref(false)
const error = ref(null)

const budgetTotal = ref(0)
const spentTotal = ref(0)
const monthIncome = ref(0)
const monthExpense = ref(0)
const barData = ref([]) // [{bucket, budget, expense}]
const monthlyStats = ref([]) // MONTH unit of year (income/expense)
const catType = ref('EXPENSE') // 분류별 파이차트 구분
const catData = ref([]) // [{category, total}]
const trendData = ref([]) // [{month, netWorth}]

const periodLabel = computed(() => `${year.value}년 ${String(month.value).padStart(2, '0')}월`)

function won(n) {
  return (n ?? 0).toLocaleString('ko-KR')
}
function daysInMonth(y, m) {
  return new Date(y, m, 0).getDate()
}
function range(a, b) {
  const r = []
  for (let i = a; i <= b; i++) r.push(i)
  return r
}

/* ===== 예산 대비 지출 도넛 ===== */
const R = 52
const C = 2 * Math.PI * R
const budgetRatio = computed(() => (budgetTotal.value > 0 ? Math.min(spentTotal.value / budgetTotal.value, 1) : 0))
const budgetPct = computed(() => (budgetTotal.value > 0 ? Math.round((spentTotal.value / budgetTotal.value) * 100) : 0))
const donutDash = computed(() => `${budgetRatio.value * C} ${C}`)
const donutColor = computed(() => {
  const r = budgetTotal.value > 0 ? spentTotal.value / budgetTotal.value : 0
  return r >= 1 ? '#c0392b' : r >= 0.8 ? '#e67e22' : '#2e7d32'
})

/* ===== 수입/지출 비율 ===== */
const ieTotal = computed(() => monthIncome.value + monthExpense.value)
const incomePct = computed(() => (ieTotal.value > 0 ? (monthIncome.value / ieTotal.value) * 100 : 0))

/* ===== 막대 차트 (기간별 예산 대비 지출) ===== */
const bars = computed(() => {
  const map = {}
  barData.value.forEach((d) => (map[d.bucket] = d))
  let buckets
  if (unit.value === 'DAY') buckets = range(1, daysInMonth(year.value, month.value)).map(String)
  else if (unit.value === 'WEEK') buckets = range(1, Math.ceil(daysInMonth(year.value, month.value) / 7)).map(String)
  else if (unit.value === 'MONTH') buckets = range(1, 12).map(String)
  else buckets = barData.value.map((d) => d.bucket) // YEAR: 존재하는 연도
  return buckets.map((b) => ({
    label: unit.value === 'WEEK' ? `${b}주` : b,
    budget: map[b]?.budget || 0,
    expense: map[b]?.expense || 0,
  }))
})
const barMax = computed(() => Math.max(1, ...bars.value.flatMap((b) => [b.budget, b.expense])))

/* ===== 막대 차트 툴팁 (지출/예산 비율) ===== */
const chartRef = ref(null)
const tip = reactive({ show: false, x: 0, y: 0, label: '', budget: 0, expense: 0, ratio: 0 })
function showTip(b) {
  tip.label = b.label
  tip.budget = b.budget
  tip.expense = b.expense
  tip.ratio = b.budget > 0 ? Math.round((b.expense / b.budget) * 100) : 0
  tip.show = true
}
function moveTip(e) {
  const r = chartRef.value?.getBoundingClientRect()
  if (!r) return
  tip.x = e.clientX - r.left
  tip.y = e.clientY - r.top
}
function hideTip() {
  tip.show = false
}

/* ===== 분류별 파이차트 ===== */
const PIE_R = 46 // viewBox 120 기준, 선두께 20(hover 24) 포함해도 잘리지 않도록 (46+12=58 ≤ 60)
const PIE_C = 2 * Math.PI * PIE_R
const PIE_COLORS = ['#3b82a6', '#e67e22', '#2e7d32', '#9b59b6', '#c0392b', '#16a085', '#f39c12', '#8e44ad', '#27ae60', '#d35400', '#2980b9', '#7f8c8d']
const catTotal = computed(() => catData.value.reduce((s, d) => s + d.total, 0))
const pieSegments = computed(() => {
  const total = catTotal.value
  if (total <= 0) return []
  let acc = 0
  return catData.value.map((d, i) => {
    const len = (d.total / total) * PIE_C
    const seg = {
      category: d.category,
      total: d.total,
      pct: Math.round((d.total / total) * 100),
      color: PIE_COLORS[i % PIE_COLORS.length],
      len,
      offset: -acc,
    }
    acc += len
    return seg
  })
})
const catHover = ref(-1)

/* ===== 순자산 추이 ===== */
const trendView = computed(() => {
  const data = trendData.value
  if (!data.length) return { pts: [], line: '', area: '', zeroY: null, min: 0, max: 0 }
  const vals = data.map((d) => d.netWorth)
  const min = Math.min(...vals, 0)
  const max = Math.max(...vals, 0)
  const span = max - min || 1
  const n = data.length
  const pts = data.map((d, i) => ({
    x: n === 1 ? 50 : (i / (n - 1)) * 100,
    y: 100 - ((d.netWorth - min) / span) * 100,
    month: d.month,
    netWorth: d.netWorth,
    label: d.month.slice(5), // MM
  }))
  const line = pts.map((p) => `${p.x.toFixed(2)},${p.y.toFixed(2)}`).join(' ')
  const area = `${pts[0].x.toFixed(2)},100 ` + line + ` ${pts[n - 1].x.toFixed(2)},100`
  const zeroY = min < 0 && max > 0 ? 100 - ((0 - min) / span) * 100 : null
  return { pts, line, area, zeroY, min, max }
})
const trendTip = reactive({ show: false, x: 0, y: 0, month: '', netWorth: 0 })
function showTrendTip(p) {
  trendTip.month = p.month
  trendTip.netWorth = p.netWorth
  trendTip.x = p.x
  trendTip.y = p.y
  trendTip.show = true
}
function hideTrendTip() {
  trendTip.show = false
}

async function loadCat() {
  try {
    catData.value = await accountApi.categoryStats({ type: catType.value, year: year.value, month: month.value })
  } catch {
    catData.value = []
  }
}
function setCatType(t) {
  catType.value = t
  loadCat()
}
async function loadTrend() {
  try {
    trendData.value = await accountApi.netWorthTrend({ months: 12 })
  } catch {
    trendData.value = []
  }
}

/* ===== 월별 총액 목록 ===== */
const monthlyRows = computed(() => {
  const map = {}
  monthlyStats.value.forEach((d) => (map[d.bucket] = d))
  return range(1, 12).map((m) => {
    const d = map[String(m)] || { income: 0, expense: 0 }
    return { month: m, income: d.income, expense: d.expense, net: d.income - d.expense }
  })
})

async function loadBar() {
  try {
    barData.value = await accountApi.budgetPeriod({ unit: unit.value, year: year.value, month: month.value })
  } catch {
    barData.value = []
  }
}

async function load() {
  loading.value = true
  error.value = null
  try {
    const [status, summary] = await Promise.all([
      accountApi.budgetStatus({ year: year.value, month: month.value }),
      accountApi.summary({ year: year.value, month: month.value }),
      loadBar(),
      loadCat(),
    ])
    budgetTotal.value = status.reduce((s, x) => s + x.monthlyBudget, 0)
    spentTotal.value = status.reduce((s, x) => s + x.spent, 0)
    monthIncome.value = summary.totalIncome
    monthExpense.value = summary.totalExpense
  } catch (e) {
    error.value = e.response?.data?.message || '불러오지 못했습니다.'
  } finally {
    loading.value = false
  }
}

function setUnit(u) {
  unit.value = u
  loadBar()
}
function prevMonth() {
  if (month.value === 1) {
    month.value = 12
    year.value -= 1
  } else month.value -= 1
  load()
}
function nextMonth() {
  if (month.value === 12) {
    month.value = 1
    year.value += 1
  } else month.value += 1
  load()
}

// 월별 총액 표: 전용 연도
async function loadMonthly() {
  try {
    monthlyStats.value = await accountApi.stats({ unit: 'MONTH', year: tableYear.value })
  } catch {
    monthlyStats.value = []
  }
}
function prevTableYear() {
  tableYear.value -= 1
  loadMonthly()
}
function nextTableYear() {
  if (tableYear.value >= currentYear) return
  tableYear.value += 1
  loadMonthly()
}

onMounted(async () => {
  // 진입 시 밀린 정기 거래를 먼저 반영 (중복 없이)
  try {
    await accountApi.runRecurrings()
  } catch {
    // 정기 거래 반영 실패는 대시보드 조회를 막지 않는다
  }
  load()
  loadMonthly()
  loadTrend()
})
</script>

<template>
  <section class="dash">
    <header class="head">
      <h1>통계</h1>
    </header>

    <div class="month-nav">
      <IconBtn icon="chevronLeft" title="이전 달" size="sm" @click="prevMonth" />
      <span class="period">{{ periodLabel }}</span>
      <IconBtn icon="chevronRight" title="다음 달" size="sm" @click="nextMonth" />
    </div>

    <p v-if="error" class="msg error">{{ error }}</p>
    <p v-if="loading" class="msg">불러오는 중...</p>

    <template v-else>
      <!-- 상단: 예산 대비 지출(도넛) + 수입 대비 지출 -->
      <div class="top-grid">
        <div class="panel donut-panel">
          <h2>예산 대비 지출</h2>
          <div v-if="budgetTotal > 0" class="donut-wrap">
            <svg viewBox="0 0 120 120" class="donut">
              <circle cx="60" cy="60" :r="R" fill="none" stroke="var(--color-background-mute)" stroke-width="14" />
              <circle
                cx="60" cy="60" :r="R" fill="none" :stroke="donutColor" stroke-width="14"
                :stroke-dasharray="donutDash" stroke-linecap="round" transform="rotate(-90 60 60)"
              />
              <text x="60" y="56" text-anchor="middle" class="donut-pct">{{ budgetPct }}%</text>
              <text x="60" y="74" text-anchor="middle" class="donut-sub">지출/예산</text>
            </svg>
            <div class="donut-legend">
              <div>지출 <b>{{ won(spentTotal) }}</b></div>
              <div>예산 <b>{{ won(budgetTotal) }}</b></div>
              <div :class="budgetTotal - spentTotal < 0 ? 'neg' : ''">
                {{ budgetTotal - spentTotal >= 0 ? '잔여' : '초과' }} <b>{{ won(Math.abs(budgetTotal - spentTotal)) }}</b>
              </div>
            </div>
          </div>
          <p v-else class="empty">설정된 예산이 없습니다.</p>
        </div>

        <div class="panel">
          <h2>수입 대비 지출</h2>
          <div class="ie">
            <div class="ie-row"><span>수입</span><b class="income">{{ won(monthIncome) }}</b></div>
            <div class="ie-row"><span>지출</span><b class="expense">{{ won(monthExpense) }}</b></div>
            <div class="ie-bar">
              <div class="ie-fill income" :style="{ width: incomePct + '%' }"></div>
            </div>
            <div class="ie-row net"><span>수지</span><b :class="monthIncome - monthExpense < 0 ? 'expense' : 'income'">{{ won(monthIncome - monthExpense) }}</b></div>
          </div>
        </div>
      </div>

      <!-- 분류별 파이차트 -->
      <div class="panel">
        <div class="panel-head">
          <h2>분류별 {{ catType === 'EXPENSE' ? '지출' : '수입' }}</h2>
          <div class="unit-tabs">
            <button type="button" :class="{ active: catType === 'EXPENSE' }" @click="setCatType('EXPENSE')">지출</button>
            <button type="button" :class="{ active: catType === 'INCOME' }" @click="setCatType('INCOME')">수입</button>
          </div>
        </div>
        <div v-if="pieSegments.length" class="pie-wrap">
          <svg viewBox="0 0 120 120" class="pie">
            <circle cx="60" cy="60" :r="PIE_R" fill="none" stroke="var(--color-background-mute)" stroke-width="20" />
            <circle
              v-for="(s, i) in pieSegments" :key="i"
              cx="60" cy="60" :r="PIE_R" fill="none" :stroke="s.color"
              :stroke-width="catHover === i ? 24 : 20"
              :stroke-dasharray="`${s.len} ${PIE_C - s.len}`" :stroke-dashoffset="s.offset"
              transform="rotate(-90 60 60)" class="pie-seg"
              @mouseenter="catHover = i" @mouseleave="catHover = -1"
            />
            <text x="60" y="57" text-anchor="middle" class="pie-center">{{ won(catTotal) }}</text>
            <text x="60" y="72" text-anchor="middle" class="pie-center-sub">총 {{ catType === 'EXPENSE' ? '지출' : '수입' }}</text>
          </svg>
          <ul class="pie-legend">
            <li v-for="(s, i) in pieSegments" :key="i" :class="{ hover: catHover === i }"
                @mouseenter="catHover = i" @mouseleave="catHover = -1">
              <span class="sw" :style="{ background: s.color }"></span>
              <span class="cat">{{ s.category }}</span>
              <span class="pct">{{ s.pct }}%</span>
              <span class="amt">{{ won(s.total) }}</span>
            </li>
          </ul>
        </div>
        <p v-else class="empty">{{ catType === 'EXPENSE' ? '지출' : '수입' }} 내역이 없습니다.</p>
      </div>

      <!-- 기간별 예산 대비 지출 막대 차트 -->
      <div class="panel">
        <div class="panel-head">
          <h2>기간별 예산 대비 지출</h2>
          <div class="unit-tabs">
            <button type="button" :class="{ active: unit === 'MONTH' }" @click="setUnit('MONTH')">월별</button>
            <button type="button" :class="{ active: unit === 'YEAR' }" @click="setUnit('YEAR')">년별</button>
          </div>
        </div>
        <div class="legend-inline">
          <span class="dot budget"></span>예산 <span class="dot expense"></span>지출
        </div>
        <div v-if="bars.length" ref="chartRef" class="chart-wrap" @mousemove="moveTip" @mouseleave="hideTip">
          <div class="bar-chart">
            <div v-for="(b, i) in bars" :key="i" class="bar-col" @mouseenter="showTip(b)">
              <div class="bars">
                <div class="bar budget" :style="{ height: (b.budget / barMax) * 100 + '%' }"></div>
                <div class="bar expense" :style="{ height: (b.expense / barMax) * 100 + '%' }"></div>
              </div>
              <span class="bar-label">{{ b.label }}</span>
            </div>
          </div>
          <div v-if="tip.show" class="tooltip" :style="{ left: tip.x + 'px', top: tip.y + 'px' }">
            <div class="t-label">{{ tip.label }}{{ unit === 'YEAR' ? '년' : unit === 'MONTH' ? '월' : '' }}</div>
            <div><span class="dot budget"></span>예산 {{ won(tip.budget) }}</div>
            <div><span class="dot expense"></span>지출 {{ won(tip.expense) }}</div>
            <div class="t-ratio" :class="tip.ratio >= 100 ? 'over' : ''">예산 대비 {{ tip.ratio }}%</div>
          </div>
        </div>
        <p v-else class="empty">데이터가 없습니다.</p>
      </div>

      <!-- 순자산 추이 (최근 12개월) -->
      <div class="panel">
        <h2>순자산 추이 <span class="sub-note">최근 12개월</span></h2>
        <div v-if="trendView.pts.length" class="trend-wrap" @mouseleave="hideTrendTip">
          <svg viewBox="0 0 100 100" preserveAspectRatio="none" class="trend-svg">
            <line v-if="trendView.zeroY !== null" x1="0" :y1="trendView.zeroY" x2="100" :y2="trendView.zeroY"
                  class="zero-line" vector-effect="non-scaling-stroke" />
            <polygon :points="trendView.area" class="trend-area" />
            <polyline :points="trendView.line" class="trend-line" vector-effect="non-scaling-stroke" />
          </svg>
          <!-- 점/호버 마커 (HTML 오버레이) -->
          <div
            v-for="(p, i) in trendView.pts" :key="i" class="trend-dot"
            :style="{ left: p.x + '%', top: p.y + '%' }"
            @mouseenter="showTrendTip(p)"
          ></div>
          <div class="trend-labels">
            <span v-for="(p, i) in trendView.pts" :key="i" class="t-axis" :style="{ left: p.x + '%' }">{{ p.label }}</span>
          </div>
          <div v-if="trendTip.show" class="tooltip trend-tip" :style="{ left: trendTip.x + '%', top: trendTip.y + '%' }">
            <div class="t-label">{{ trendTip.month }}</div>
            <div :class="trendTip.netWorth < 0 ? 'neg' : ''">순자산 {{ won(trendTip.netWorth) }}</div>
          </div>
        </div>
        <p v-else class="empty">데이터가 없습니다.</p>
      </div>

      <!-- 월별 수입/지출 총액 목록 -->
      <div class="panel">
        <div class="panel-head">
          <h2>월별 총액</h2>
          <div class="year-nav">
            <IconBtn icon="chevronLeft" title="이전 연도" size="sm" @click="prevTableYear" />
            <span class="year-label">{{ tableYear }}년</span>
            <IconBtn icon="chevronRight" title="다음 연도" size="sm" :disabled="tableYear >= currentYear" @click="nextTableYear" />
          </div>
        </div>
        <table class="monthly">
          <thead>
            <tr><th>월</th><th class="num">수입</th><th class="num">지출</th><th class="num">수지</th></tr>
          </thead>
          <tbody>
            <tr v-for="r in monthlyRows" :key="r.month">
              <td>{{ r.month }}월</td>
              <td class="num income">{{ won(r.income) }}</td>
              <td class="num expense">{{ won(r.expense) }}</td>
              <td class="num" :class="r.net < 0 ? 'expense' : 'income'">{{ won(r.net) }}</td>
            </tr>
          </tbody>
        </table>
      </div>
    </template>
  </section>
</template>

<style scoped>
.dash {
  max-width: 760px;
  margin: 0 auto;
}
.head {
  margin-bottom: 0.75rem;
}
h1 {
  font-size: 1.5rem;
}
h2 {
  font-size: 1rem;
  margin-bottom: 0.75rem;
}
.month-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-bottom: 1.25rem;
}
.month-nav button {
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-background-soft);
  color: var(--color-text);
  cursor: pointer;
}
.period {
  font-size: 1.1rem;
  font-weight: 600;
  min-width: 8rem;
  text-align: center;
}
.panel {
  border: 1px solid var(--color-border);
  border-radius: 8px;
  padding: 1rem 1.1rem;
  margin-bottom: 1rem;
}
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.top-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
.top-grid .panel {
  margin-bottom: 1rem;
}
.donut-wrap {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.donut {
  width: 120px;
  height: 120px;
  flex-shrink: 0;
  overflow: visible;
}
.donut-pct {
  font-size: 20px;
  font-weight: 700;
  fill: var(--color-heading);
}
.donut-sub {
  font-size: 9px;
  fill: var(--color-text);
  opacity: 0.6;
}
.donut-legend {
  font-size: 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.donut-legend .neg b {
  color: #c0392b;
}
.ie-row {
  display: flex;
  justify-content: space-between;
  padding: 0.2rem 0;
  font-size: 0.9rem;
}
.ie-row.net {
  border-top: 1px solid var(--color-border);
  margin-top: 0.3rem;
  padding-top: 0.4rem;
}
.income {
  color: #2e7d32;
}
.expense {
  color: #c0392b;
}
.ie-bar {
  height: 8px;
  background: #c0392b;
  border-radius: 999px;
  overflow: hidden;
  margin: 0.4rem 0;
}
.ie-fill.income {
  height: 100%;
  background: #2e7d32;
}
.unit-tabs {
  display: flex;
  gap: 0.2rem;
}
.unit-tabs button {
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-background-soft);
  color: var(--color-text);
  font-size: 0.8rem;
  cursor: pointer;
}
.unit-tabs button.active {
  border-color: hsla(160, 100%, 37%, 1);
  color: hsla(160, 100%, 37%, 1);
  font-weight: 600;
}
.legend-inline {
  font-size: 0.78rem;
  opacity: 0.75;
  margin: 0.5rem 0;
  display: flex;
  align-items: center;
  gap: 0.3rem;
}
.dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  margin-left: 0.5rem;
}
.dot.income {
  background: #2e7d32;
}
.dot.expense {
  background: #c0392b;
}
.dot.budget {
  background: #3b82a6;
}
.chart-wrap {
  position: relative;
}
.bar-chart {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 160px;
  overflow-x: auto;
  padding-top: 0.5rem;
}
.bar-col {
  flex: 1;
  min-width: 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
}
.bars {
  flex: 1;
  display: flex;
  align-items: flex-end;
  gap: 1px;
  width: 100%;
  justify-content: center;
}
.bar {
  width: 45%;
  min-height: 1px;
  border-radius: 2px 2px 0 0;
}
.bar.income {
  background: #2e7d32;
}
.bar.budget {
  background: #3b82a6;
}
.bar.expense {
  background: #c0392b;
}
.tooltip {
  position: absolute;
  transform: translate(-50%, calc(-100% - 12px));
  pointer-events: none;
  background: #1e1e1e;
  color: #fff;
  border-radius: 6px;
  padding: 0.5rem 0.65rem;
  font-size: 0.78rem;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
  z-index: 5;
  line-height: 1.5;
}
.tooltip .t-label {
  font-weight: 700;
  margin-bottom: 0.2rem;
}
.tooltip .dot {
  margin-left: 0;
  margin-right: 0.3rem;
}
.tooltip .t-ratio {
  margin-top: 0.25rem;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  padding-top: 0.25rem;
  font-weight: 700;
}
.tooltip .t-ratio.over {
  color: #ff6b6b;
}
.bar-label {
  font-size: 0.65rem;
  opacity: 0.7;
  margin-top: 0.2rem;
  white-space: nowrap;
}
/* 분류별 파이차트 */
.pie-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.pie {
  width: 100%;
  max-width: 170px;
  height: auto;
  aspect-ratio: 1 / 1;
  flex-shrink: 0;
  overflow: visible;
}
.pie-seg {
  cursor: pointer;
  transition: stroke-width 0.12s ease;
}
.pie-center {
  font-size: 13px;
  font-weight: 700;
  fill: var(--color-heading);
}
.pie-center-sub {
  font-size: 8px;
  fill: var(--color-text);
  opacity: 0.6;
}
.pie-legend {
  list-style: none;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 0.1rem 1rem;
  font-size: 0.85rem;
}
.pie-legend li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.3rem;
  border-radius: 4px;
}
.pie-legend li.hover {
  background: var(--color-background-mute);
}
.pie-legend .sw {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  flex-shrink: 0;
}
.pie-legend .cat {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pie-legend .pct {
  opacity: 0.65;
  min-width: 2.5rem;
  text-align: right;
}
.pie-legend .amt {
  font-weight: 600;
  min-width: 5rem;
  text-align: right;
}

/* 순자산 추이 */
.sub-note {
  font-size: 0.75rem;
  font-weight: 400;
  opacity: 0.6;
}
.trend-wrap {
  position: relative;
  height: 170px;
  padding-bottom: 1.1rem;
}
.trend-svg {
  width: 100%;
  height: 150px;
  overflow: visible;
}
.trend-area {
  fill: hsla(160, 100%, 37%, 0.12);
}
.trend-line {
  fill: none;
  stroke: hsla(160, 100%, 37%, 1);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.zero-line {
  stroke: var(--color-border);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}
.trend-dot {
  position: absolute;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: var(--color-background);
  border: 2px solid hsla(160, 100%, 37%, 1);
  cursor: pointer;
}
.trend-dot:hover {
  transform: scale(1.3);
}
.trend-labels {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1rem;
}
.t-axis {
  position: absolute;
  transform: translateX(-50%);
  font-size: 0.62rem;
  opacity: 0.6;
  white-space: nowrap;
}
.trend-tip {
  position: absolute;
}
.trend-tip .neg {
  color: #ff6b6b;
}

.year-nav {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.year-nav button {
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-background-soft);
  color: var(--color-text);
  cursor: pointer;
}
.year-nav button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.year-label {
  font-weight: 600;
  min-width: 4rem;
  text-align: center;
}
.monthly {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.monthly th,
.monthly td {
  padding: 0.4rem 0.5rem;
  border-bottom: 1px solid var(--color-border);
  text-align: left;
}
.monthly .num {
  text-align: right;
}
.empty {
  font-size: 0.85rem;
  opacity: 0.6;
  padding: 1rem 0;
}
.msg {
  margin: 1rem 0;
}
.msg.error {
  color: #c0392b;
}
@media (max-width: 768px) {
  .dash {
    max-width: 100%;
  }
  .top-grid {
    grid-template-columns: 1fr;
  }
  .monthly th,
  .monthly td {
    padding: 0.4rem 0.3rem;
  }
}
</style>
