<template>
  <PageShell>
    <ClientOnly>
    <!-- Unauthenticated -->
    <div v-if="!memberData" class="loading">
      <p>Please sign in to access your account settings.</p>
      <button
        class="btn btn-primary"
        @click="openLoginModal({ title: 'Sign in to manage your account' })"
      >
        Sign In
      </button>
    </div>

    <template v-else>
      <!-- PAGE HEADER -->
      <PageHeader
        title="Account Settings"
        subtitle="Manage your membership and billing"
      />

      <!-- CONTENT AREA WITH EVENTS SIDEBAR -->
      <ColumnsLayout cols="events-sidebar">
        <ColumnsLayout cols="2">
          <!-- LEFT COLUMN: Membership Status & Email -->
          <template #left>
            <PageSection>
              <div class="section-label">Current Membership</div>

              <div class="membership-card">
                <div class="membership-row">
                  <span class="membership-k">Status</span>
                  <span class="membership-v status-v">
                    <span
                      class="status-dot"
                      :class="memberData.status || 'active'"
                    />
                    <span>{{
                      formatStatus(memberData.status || "active")
                    }}</span>
                  </span>
                </div>
                <div class="membership-row">
                  <span class="membership-k">Circle</span>
                  <span
                    class="membership-v"
                    :style="{
                      color: `var(--c-${memberData.circle || 'community'})`,
                    }"
                  >
                    {{
                      memberData.circle
                        ? capitalise(memberData.circle)
                        : "Community"
                    }}
                  </span>
                </div>
                <div class="membership-row">
                  <span class="membership-k">Contribution</span>
                  <span class="membership-v">{{ currentContributionLabel }}</span>
                </div>
                <div v-if="nextPaymentDate" class="membership-row">
                  <span class="membership-k">Next payment</span>
                  <span class="membership-v">{{ formatNextPaymentDate(nextPaymentDate) }}</span>
                </div>
                <div class="membership-row">
                  <span class="membership-k">Member since</span>
                  <span class="membership-v">{{
                    formatMemberSince(memberData.createdAt)
                  }}</span>
                </div>
              </div>
            </PageSection>

            <!-- PAYMENT HISTORY (shown when a paid plan is active OR past payments exist) -->
            <PageSection
              v-if="memberData.helcimCustomerId && ((memberData.contributionAmount || 0) > 0 || paymentHistory.length > 0)"
              divider="top"
            >
              <div class="section-label">Payment history</div>

              <div v-if="nextPaymentDate" class="next-charge">
                <span class="next-charge-label">Next charge</span>
                <span class="next-charge-value">${{ nextChargeAmount }} on {{ formatNextPaymentDate(nextPaymentDate) }}</span>
              </div>

              <div v-if="paymentHistoryLoading" class="history-card">
                <div class="history-row history-state">Loading…</div>
              </div>

              <div
                v-else-if="paymentHistoryError"
                class="history-card"
              >
                <div class="history-row history-state">
                  Payment history temporarily unavailable. Try again in a few minutes.
                </div>
              </div>

              <div
                v-else-if="paymentHistory.length === 0"
                class="history-card"
              >
                <div class="history-row history-state">
                  No payments yet. Your first charge will appear here after your next billing cycle.
                </div>
              </div>

              <div v-else class="history-card">
                <div
                  v-for="txn in paymentHistory"
                  :key="txn.id"
                  class="history-row"
                >
                  <span class="history-date">{{ formatTxnDate(txn.date) }}</span>
                  <span class="history-amount">{{ formatTxnAmount(txn.amount, txn.currency) }}</span>
                  <span
                    class="history-status"
                    :class="`status-${txn.status}`"
                  >{{ formatTxnStatus(txn.status) }}</span>
                </div>
              </div>
            </PageSection>

            <!-- CHANGE CARD (only for active subscriptions) -->
            <PageSection
              v-if="canChangeCard"
              divider="top"
            >
              <div class="section-label">Change card</div>
              <p class="change-card-hint">
                Replace the card on file. Future charges will use the new card.
              </p>
              <button
                class="btn btn-primary btn-section"
                :disabled="isChangingCard"
                @click="handleChangeCard"
              >
                {{ changeCardButtonLabel }}
              </button>
            </PageSection>

            <!-- ADVANCED BILLING LINK (escape hatch) -->
            <PageSection
              v-if="helcimPortalUrl && memberData.helcimCustomerId"
              divider="top"
            >
              <a
                :href="helcimPortalUrl"
                target="_blank"
                rel="noopener"
                class="billing-link"
              >
                Advanced billing in Helcim &rarr;
              </a>
            </PageSection>

            <PageSection divider="top">
              <div class="section-label">Email</div>

              <div v-if="!showEmailEdit" class="email-display">
                <span class="email-value">{{ memberData.email }}</span>
                <button class="btn btn-inline" @click="showEmailEdit = true">
                  Change
                </button>
              </div>

              <div v-else class="email-edit">
                <div class="field">
                  <label>New email address</label>
                  <input
                    v-model="newEmail"
                    type="email"
                    placeholder="you@example.com"
                    autofocus
                    @keydown.enter="handleUpdateEmail"
                    @keydown.escape="cancelEmailEdit"
                  >
                </div>
                <div class="email-edit-actions">
                  <button
                    class="btn btn-primary"
                    :disabled="isUpdatingEmail || !newEmail.trim()"
                    @click="handleUpdateEmail"
                  >
                    {{ isUpdatingEmail ? "Saving…" : "Save" }}
                  </button>
                  <button
                    class="btn"
                    :disabled="isUpdatingEmail"
                    @click="cancelEmailEdit"
                  >
                    Cancel
                  </button>
                </div>
              </div>

              <div class="email-hint">
                Used for login magic links and notifications
              </div>
            </PageSection>

            <PageSection divider="top" class="danger-section">
              <div class="section-label danger">Danger Zone</div>
              <div class="danger-zone">
                <p>
                  Cancelling closes your account and ends access to member-only
                  spaces, including Slack.<template v-if="(memberData.contributionAmount || 0) > 0"> If you're cancelling because of a
                  money issue, the
                  <NuxtLink to="/community-guidelines">Solidarity Fund</NuxtLink>
                  and the $0 tier are always available — reach out before you
                  go.</template>
                </p>
                <div v-if="showCancelConfirm" class="cancel-confirm">
                  <p class="cancel-confirm-prompt">
                    Are you sure? This cannot be easily undone.
                  </p>
                  <div class="cancel-confirm-actions">
                    <button
                      class="btn btn-danger"
                      :disabled="isCancelling"
                      @click="confirmCancelMembership"
                    >
                      {{ isCancelling ? "Cancelling…" : "Yes, Cancel" }}
                    </button>
                    <button class="btn" @click="showCancelConfirm = false">
                      Nevermind
                    </button>
                  </div>
                </div>
                <button
                  v-else
                  class="btn btn-danger"
                  :disabled="isCancelling"
                  @click="handleCancelMembership"
                >
                  Cancel Membership
                </button>
              </div>
            </PageSection>
          </template>

          <!-- RIGHT COLUMN: Change Contribution & Circle -->
          <template #right>
            <PageSection>
              <div class="section-label">Change Contribution</div>

              <div class="form-group">
                <label class="form-label" for="account-contribution">
                  Monthly Contribution
                </label>
                <div class="contribution-input-row">
                  <span class="contribution-currency">$</span>
                  <input
                    id="account-contribution"
                    v-model.number="form.contributionAmount"
                    type="number"
                    min="0"
                    step="1"
                    inputmode="numeric"
                    class="contribution-input"
                  >
                </div>
                <div class="contribution-presets" role="group" aria-label="Suggested amounts">
                  <button
                    v-for="preset in CONTRIBUTION_PRESETS"
                    :key="preset.amount"
                    type="button"
                    class="contribution-preset-chip"
                    @click="form.contributionAmount = preset.amount"
                  >
                    ${{ preset.amount }}
                  </button>
                </div>
                <p v-if="guidanceLabel" class="contribution-guidance">{{ guidanceLabel }}</p>
              </div>
              <div v-if="contributionChangeHint" class="tier-hint">
                {{ contributionChangeHint }}
              </div>
              <button
                class="btn btn-primary btn-section"
                :disabled="
                  form.contributionAmount === Number(memberData.contributionAmount || 0) ||
                  isUpdating
                "
                @click="handleUpdateTier"
              >
                {{ isUpdating ? "Updating…" : "Update Contribution" }}
              </button>
            </PageSection>

            <PageSection divider="top">
              <div class="section-label">Change Circle</div>

              <CirclePicker
                v-model="selectedCircle"
                :saved-value="memberData.circle"
                :circles="circleOptions"
              />
              <button
                class="btn btn-primary btn-section"
                :disabled="selectedCircle === memberData.circle || isUpdating"
                @click="handleUpdateCircle"
              >
                {{ isUpdating ? "Updating…" : "Update Circle" }}
              </button>
            </PageSection>
          </template>
        </ColumnsLayout>
      </ColumnsLayout>
    </template>
    </ClientOnly>
  </PageShell>
</template>

<script setup>
import { CONTRIBUTION_PRESETS, getGuidanceLabel, requiresPayment } from '~/config/contributions';

definePageMeta({
  middleware: "auth",
});

const { memberData, checkMemberStatus } = useAuth();
const { openLoginModal } = useLoginModal();
const { initializeHelcimPay, verifyPayment, cleanup: cleanupHelcimPay } = useHelcimPay();
const toast = useToast();
const helcimPortalUrl = useRuntimeConfig().public.helcimPortalUrl || '';

const form = reactive({ contributionAmount: 0 });
const selectedCircle = ref("");
const isUpdating = ref(false);
const isCancelling = ref(false);

// Email edit state
const showEmailEdit = ref(false);
const newEmail = ref("");
const isUpdatingEmail = ref(false);

// Payment history state
const paymentHistory = ref([]);
const paymentHistoryLoading = ref(false);
const paymentHistoryError = ref(false);
const paymentHistoryLoaded = ref(false);

// Next payment (refreshed lazily from Helcim when cached date is stale)
const refreshedNextBillingDate = ref(null);
const nextBillingRefreshed = ref(false);

const nextPaymentDate = computed(() => {
  const m = memberData.value;
  if (!m) return null;
  if (m.status !== 'active') return null;
  if (!Number(m.contributionAmount)) return null;
  return refreshedNextBillingDate.value || m.nextBillingDate || null;
});

// Change-card state
const isChangingCard = ref(false);
const changeCardButtonLabel = ref("Change card");

const canChangeCard = computed(() => {
  const m = memberData.value;
  if (!m) return false;
  if (!m.helcimCustomerId) return false;
  if (!["active", "pending_payment"].includes(m.status)) return false;
  // $0 tier has no subscription to attach a card to
  if (!requiresPayment(Number(m.contributionAmount || 0))) return false;
  return true;
});

const cadence = computed(() => memberData.value?.billingCadence || 'monthly');

const guidanceLabel = computed(() => getGuidanceLabel(form.contributionAmount));

const contributionChangeHint = computed(() => {
  const current = Number(memberData.value?.contributionAmount || 0);
  const next = Number(form.contributionAmount || 0);
  if (current === next) return "";
  if (current === 0 && next > 0) {
    const firstCharge = cadence.value === "annual" ? next * 12 : next;
    return `You'll be charged $${firstCharge} today to start your subscription.`;
  }
  if (current > 0 && next === 0) {
    return "Your paid subscription will be cancelled.";
  }
  return "Changes apply on your next billing cycle.";
});

const currentContributionLabel = computed(() => {
  const amount = Number(memberData.value?.contributionAmount || 0);
  if (!amount) return '$0';
  const displayAmount = cadence.value === 'annual' ? amount * 12 : amount;
  return cadence.value === 'annual' ? `$${displayAmount} / year` : `$${displayAmount} / month`;
});

const nextChargeAmount = computed(() => {
  const amount = Number(memberData.value?.contributionAmount || 0);
  if (!amount) return null;
  return cadence.value === 'annual' ? amount * 12 : amount;
});

const circleOptions = [
  {
    value: "community",
    label: "Community",
    description: "Exploring cooperative ideas",
  },
  {
    value: "founder",
    label: "Founder",
    description: "Building a cooperative studio",
  },
  {
    value: "practitioner",
    label: "Practitioner",
    description: "Experienced in cooperative practice",
  },
];

const STATUS_LABELS = {
  active: "Active",
  pending_payment: "Setting up payment",
  suspended: "Paused",
  cancelled: "Closed",
};

const formatStatus = (s) => STATUS_LABELS[s] || s;

const capitalise = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);

// Initialize from member data
watchEffect(() => {
  if (memberData.value) {
    form.contributionAmount = Number(memberData.value.contributionAmount || 0);
    selectedCircle.value = memberData.value.circle || "community";
  }
});

const formatMemberSince = (dateStr) => {
  if (!dateStr) return "";
  return new Date(dateStr).toLocaleDateString("en-US", {
    month: "long",
    year: "numeric",
  });
};

const formatNextPaymentDate = (dateStr) => {
  if (!dateStr) return "";
  const d = new Date(dateStr);
  if (Number.isNaN(d.getTime())) return "";
  return d.toLocaleDateString("en-US", {
    month: "long",
    day: "numeric",
    year: "numeric",
  });
};

const STALE_WINDOW_MS = 24 * 60 * 60 * 1000;

const isNextBillingStale = (dateStr) => {
  if (!dateStr) return true;
  const d = new Date(dateStr);
  if (Number.isNaN(d.getTime())) return true;
  return d.getTime() - Date.now() < STALE_WINDOW_MS;
};

const refreshNextBillingIfStale = async () => {
  if (nextBillingRefreshed.value) return;
  const m = memberData.value;
  if (!m) return;
  if (m.status !== 'active') return;
  if (!Number(m.contributionAmount)) return;
  if (!isNextBillingStale(m.nextBillingDate)) return;

  nextBillingRefreshed.value = true;
  try {
    const response = await $fetch("/api/helcim/subscription");
    const fresh = response?.subscription?.nextBillingDate;
    if (fresh) refreshedNextBillingDate.value = fresh;
  } catch (err) {
    // Silent — fall back to cached value (if any)
  }
};

const handleUpdateTier = async () => {
  isUpdating.value = true;
  try {
    await $fetch("/api/members/update-contribution", {
      method: "POST",
      body: {
        contributionAmount: form.contributionAmount,
        cadence: cadence.value,
      },
    });
    await checkMemberStatus();
    toast.add({ title: "Contribution updated", color: "success" });
  } catch (err) {
    // Paid upgrade without a saved card — route to payment setup instead of erroring.
    if (err.data?.data?.requiresPaymentSetup) {
      await navigateTo(
        `/member/payment-setup?tier=${form.contributionAmount}&circle=${
          selectedCircle.value || memberData.value?.circle || 'community'
        }`,
      );
      return;
    }
    form.contributionAmount = Number(memberData.value?.contributionAmount || 0);
    toast.add({
      title: "Update failed",
      description: err.data?.statusMessage || "Please try again.",
      color: "error",
    });
  } finally {
    isUpdating.value = false;
  }
};

const handleUpdateCircle = async () => {
  isUpdating.value = true;
  try {
    await $fetch("/api/members/update-circle", {
      method: "POST",
      body: { circle: selectedCircle.value },
    });
    await checkMemberStatus();
    toast.add({ title: "Circle updated", color: "success" });
  } catch (err) {
    selectedCircle.value = memberData.value?.circle || "community";
    toast.add({
      title: "Update failed",
      description: err.data?.statusMessage || "Please try again.",
      color: "error",
    });
  } finally {
    isUpdating.value = false;
  }
};

const cancelEmailEdit = () => {
  showEmailEdit.value = false;
  newEmail.value = "";
};

const handleUpdateEmail = async () => {
  const trimmed = newEmail.value.trim();
  if (!trimmed) return;
  isUpdatingEmail.value = true;
  try {
    await $fetch("/api/members/update-email", {
      method: "POST",
      body: { email: trimmed },
    });
    await checkMemberStatus();
    cancelEmailEdit();
    toast.add({ title: "Email updated", color: "success" });
  } catch (err) {
    toast.add({
      title: "Update failed",
      description: err.data?.statusMessage || "Please try again.",
      color: "error",
    });
  } finally {
    isUpdatingEmail.value = false;
  }
};

// Payment history
const loadPaymentHistory = async () => {
  if (paymentHistoryLoaded.value) return;
  if (!memberData.value?.helcimCustomerId) return;
  paymentHistoryLoading.value = true;
  paymentHistoryError.value = false;
  try {
    const response = await $fetch("/api/helcim/payment-history");
    if (response?.error === "unavailable") {
      paymentHistoryError.value = true;
      paymentHistory.value = [];
    } else {
      paymentHistory.value = Array.isArray(response?.transactions)
        ? response.transactions
        : [];
    }
  } catch (err) {
    paymentHistoryError.value = true;
    paymentHistory.value = [];
  } finally {
    paymentHistoryLoading.value = false;
    paymentHistoryLoaded.value = true;
  }
};

onMounted(() => {
  if (memberData.value?.helcimCustomerId) {
    loadPaymentHistory();
  }
  refreshNextBillingIfStale();
});

watch(
  () => memberData.value?.helcimCustomerId,
  (id) => {
    if (id && !paymentHistoryLoaded.value) {
      loadPaymentHistory();
    }
  },
);

watch(
  () => memberData.value?.status,
  () => {
    refreshNextBillingIfStale();
  },
);

const formatTxnDate = (iso) => {
  if (!iso) return "—";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "—";
  return d.toLocaleDateString("en-US", {
    month: "short",
    day: "2-digit",
    year: "numeric",
  });
};

const formatTxnAmount = (amount, currency) => {
  const num = Number(amount) || 0;
  const cur = currency ? ` ${currency}` : "";
  return `$${num.toFixed(2)}${cur}`;
};

const STATUS_BADGE = {
  paid: "Paid",
  refunded: "Refunded",
  failed: "Failed",
  other: "—",
};

const formatTxnStatus = (s) => STATUS_BADGE[s] || "—";

// Change card
const handleChangeCard = async () => {
  if (isChangingCard.value) return;
  if (!canChangeCard.value) return;

  isChangingCard.value = true;
  changeCardButtonLabel.value = "Opening…";

  try {
    // Fetch current customer id + code
    const customerResponse = await $fetch("/api/helcim/customer-code");
    const customerId = customerResponse?.customerId;
    const customerCode = customerResponse?.customerCode;
    if (!customerId || !customerCode) {
      throw new Error("Could not locate customer record");
    }

    await initializeHelcimPay(customerId, customerCode, 0);

    let paymentResult;
    try {
      paymentResult = await verifyPayment();
    } catch (cancelOrFailure) {
      // User cancelled or iframe failed — no server call
      return;
    }

    if (!paymentResult?.success || !paymentResult?.cardToken) {
      return;
    }

    changeCardButtonLabel.value = "Updating…";

    try {
      await $fetch("/api/helcim/update-card", {
        method: "POST",
        body: { cardToken: paymentResult.cardToken },
      });
      toast.add({
        title: "Card updated",
        description: "Future charges will use your new card.",
        color: "success",
      });
    } catch (err) {
      console.error("[change-card] update failed", err);
      toast.add({
        title: "Could not update card",
        description: "Please try again.",
        color: "error",
        actions: [
          {
            label: "Retry",
            onClick: () => handleChangeCard(),
          },
        ],
      });
    }
  } catch (err) {
    console.error("[change-card] flow failed", err);
    toast.add({
      title: "Could not update card",
      description: "Please try again.",
      color: "error",
    });
  } finally {
    cleanupHelcimPay();
    isChangingCard.value = false;
    changeCardButtonLabel.value = "Change card";
  }
};

const showCancelConfirm = ref(false);

const handleCancelMembership = () => {
  showCancelConfirm.value = true;
};

const confirmCancelMembership = async () => {
  showCancelConfirm.value = false;
  isCancelling.value = true;
  try {
    const result = await $fetch("/api/members/cancel-subscription", {
      method: "POST",
    });
    await checkMemberStatus();
    if (result.message === "No active subscription to cancel") {
      toast.add({
        title: "No active subscription",
        description: "You are on the free tier — nothing to cancel.",
        color: "neutral",
      });
    } else {
      toast.add({ title: "Membership cancelled", color: "warning" });
    }
  } catch (err) {
    toast.add({
      title: "Cancellation failed",
      description: err.data?.statusMessage || "Please try again.",
      color: "error",
    });
  } finally {
    isCancelling.value = false;
  }
};
</script>

<style scoped>
.loading {
  padding: 48px 32px;
  color: var(--text-dim);
}

/* ---- MEMBERSHIP CARD ---- */
.membership-card {
  border: 1px dashed var(--border);
  padding: 0;
  margin-bottom: 12px;
}
.membership-row {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 0 12px;
  align-items: center;
  padding: 10px 20px;
  font-size: 12px;
  border-bottom: 1px dashed var(--border);
}
.membership-row:last-child {
  border-bottom: none;
}
.membership-k {
  color: var(--text-faint);
}
.membership-v {
  color: var(--text);
}

/* Status dot — flex row so gap is exact, no whitespace-node gap */
.status-v {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.status-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}
.status-dot.active {
  background: var(--green);
}
.status-dot.suspended {
  background: var(--ember);
}
.status-dot.cancelled {
  background: var(--text-faint);
}
.status-dot.pending_payment {
  background: var(--candle);
}

/* ---- EMAIL ---- */
.email-display {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 13px;
  margin-bottom: 6px;
}
.email-value {
  color: var(--text);
}
.btn-inline {
  font-size: 10px;
  letter-spacing: 0.06em;
  padding: 2px 8px;
  border-style: dashed;
  line-height: 1.6;
}
.email-edit {
  margin-bottom: 6px;
}
.email-edit .field {
  margin-bottom: 8px;
}
.email-edit .field label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 3px;
  display: block;
}
.email-edit .field input {
  width: 100%;
  padding: 5px 8px;
  font-family: "Commit Mono", monospace;
  font-size: 13px;
  background: var(--input-bg);
  border: 1px solid var(--border);
  color: var(--text);
  outline: none;
}
.email-edit .field input:focus {
  border-color: var(--candle);
}
.email-edit-actions {
  display: flex;
  gap: 8px;
}
.email-hint {
  font-size: 11px;
  color: var(--text-faint);
}

/* ---- DANGER ZONE ---- */
.danger-section {
  background: var(--ember-bg);
}

.danger-section .section-label.danger {
  color: var(--ember);
}
.danger-section .danger-zone p {
  color: var(--text-dim);
  font-size: 12px;
  line-height: 1.7;
  margin-bottom: 12px;
  max-width: 400px;
}

/* ---- CANCEL CONFIRM ---- */
.cancel-confirm {
  border: 1px dashed var(--ember);
  padding: 14px 16px;
  margin-bottom: 0;
}
.cancel-confirm-prompt {
  font-size: 12px;
  color: var(--ember);
  margin-bottom: 10px;
}
.cancel-confirm-actions {
  display: flex;
  gap: 8px;
}

/* ---- TIER HINT ---- */
.tier-hint {
  font-size: 11px;
  color: var(--text-faint);
  margin-bottom: 12px;
}

/* ---- CONTRIBUTION AMOUNT INPUT + CHIPS ---- */
.contribution-input-row {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.contribution-currency {
  font-weight: 600;
}
.contribution-input {
  flex: 1;
  padding: 0.5rem 0.75rem;
  background: var(--input-bg);
  border: 1px solid var(--parch);
  font-family: 'Commit Mono', monospace;
  font-size: 1rem;
}
.contribution-input:focus {
  outline: none;
  border-color: var(--candle);
}
.contribution-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.5rem;
}
.contribution-preset-chip {
  padding: 0.25rem 0.75rem;
  background: transparent;
  border: 1px dashed var(--parch);
  font-family: 'Commit Mono', monospace;
  font-size: 0.875rem;
  cursor: pointer;
}
.contribution-preset-chip:hover {
  border-style: solid;
  border-color: var(--candle);
}
.contribution-guidance {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  font-style: italic;
  color: var(--ink-soft, currentColor);
}

.btn-section {
  width: 100%;
  text-align: center;
}

.billing-link {
  display: inline-block;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  text-decoration: none;
}

.billing-link:hover {
  color: var(--candle);
  text-decoration: underline;
}

/* ---- NEXT CHARGE ---- */
.next-charge {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 0 12px;
  align-items: center;
  padding: 10px 20px;
  font-size: 12px;
  border: 1px dashed var(--candle);
  margin-bottom: 12px;
}
.next-charge-label {
  color: var(--text-faint);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 11px;
}
.next-charge-value {
  color: var(--text);
}

/* ---- PAYMENT HISTORY ---- */
.history-card {
  border: 1px dashed var(--border);
  padding: 0;
  margin-bottom: 12px;
}
.history-row {
  display: grid;
  grid-template-columns: 120px 1fr auto;
  gap: 0 12px;
  align-items: center;
  padding: 10px 20px;
  font-size: 12px;
  border-bottom: 1px dashed var(--border);
}
.history-row:last-child {
  border-bottom: none;
}
.history-date {
  color: var(--text-faint);
}
.history-amount {
  color: var(--text);
}
.history-status {
  color: var(--text-faint);
  font-size: 11px;
  letter-spacing: 0.04em;
}
.history-status.status-failed {
  color: var(--ember);
}
.history-state {
  color: var(--text-faint);
  font-style: italic;
  display: block;
  grid-template-columns: 1fr;
}

/* ---- CHANGE CARD ---- */
.change-card-hint {
  font-size: 11px;
  color: var(--text-faint);
  margin-bottom: 12px;
  line-height: 1.6;
}

</style>
