<template>
  <div class="admin-members">
    <!-- Page Header -->
    <div class="page-header">
      <div class="header-row">
        <div>
          <h1>Members</h1>
          <p>Manage members, contributions, and access</p>
        </div>
        <div class="header-actions">
          <button class="btn" @click="showImportModal = true">
            Import CSV
          </button>
          <button
            class="btn"
            :disabled="selectedMemberIds.length === 0"
            @click="openInviteModal"
          >
            Send Invites ({{ selectedMemberIds.length }})
          </button>
          <button class="btn btn-primary" @click="showCreateModal = true">
            Add Member
          </button>
        </div>
      </div>
    </div>

    <!-- Search / Filter -->
    <div class="filter-bar">
      <div class="field" style="margin-bottom: 0; flex: 1">
        <input v-model="searchQuery" placeholder="Search members..." />
      </div>
      <div class="field" style="margin-bottom: 0">
        <select v-model="circleFilter" aria-label="Filter by circle">
          <option value="">All Circles</option>
          <option value="community">Community</option>
          <option value="founder">Founder</option>
          <option value="practitioner">Practitioner</option>
        </select>
      </div>
    </div>

    <!-- Members Table -->
    <div class="table-wrap">
      <div v-if="pending" class="loading-state">
        <div class="spinner" />
        <span>Loading members...</span>
      </div>

      <div v-else-if="error" class="error-state">
        Error loading members: {{ error }}
      </div>

      <table v-else-if="filteredMembers.length">
        <thead>
          <tr>
            <th class="col-check">
              <UCheckbox
                label="Select all members"
                :ui="{ label: 'sr-only' }"
                :model-value="
                  allVisibleSelected
                    ? true
                    : someVisibleSelected
                      ? 'indeterminate'
                      : false
                "
                @update:model-value="toggleSelectAll"
              />
            </th>
            <th>Name</th>
            <th>Email</th>
            <th>Circle</th>
            <th>Tier</th>
            <th>Invite</th>
            <th>Slack</th>
            <th>Joined</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="member in filteredMembers" :key="member._id">
            <td class="col-check">
              <UCheckbox
                :label="`Select ${member.name}`"
                :ui="{ label: 'sr-only' }"
                :model-value="selectedMemberIds.includes(member._id)"
                @update:model-value="toggleSelect(member._id)"
              />
            </td>
            <td class="col-name">{{ member.name }}</td>
            <td class="col-email">{{ member.email }}</td>
            <td>
              <span class="badge" :class="member.circle">{{
                member.circle
              }}</span>
            </td>
            <td class="col-mono">${{ member.contributionTier }}/mo</td>
            <td>
              <span
                :class="member.inviteEmailSent ? 'status-ok' : 'status-dim'"
              >
                {{ member.inviteEmailSent ? "Sent" : "Not sent" }}
              </span>
            </td>
            <td>
              <span :class="member.slackInvited ? 'status-ok' : 'status-dim'">
                {{ member.slackInvited ? "Invited" : "Pending" }}
              </span>
            </td>
            <td class="col-mono col-date">
              {{ formatDate(member.createdAt) }}
            </td>
            <td class="col-actions">
              <NuxtLink :to="`/admin/members/${member._id}`" class="link-btn"
                >View</NuxtLink
              >
              <button @click="sendSlackInvite(member)" class="link-btn">
                Slack
              </button>
              <button @click="editMember(member)" class="link-btn">Edit</button>
            </td>
          </tr>
        </tbody>
      </table>

      <div v-else class="empty-state">
        No members found matching your criteria
      </div>
    </div>

    <!-- Create Member Modal -->
    <div
      v-if="showCreateModal"
      class="modal-overlay"
      @click.self="showCreateModal = false"
    >
      <div class="modal">
        <div class="modal-header">
          <h2>Add New Member</h2>
          <button class="modal-close" @click="showCreateModal = false">
            &times;
          </button>
        </div>

        <form @submit.prevent="createMember" class="modal-body">
          <div class="field">
            <label>Name</label>
            <input v-model="newMember.name" placeholder="Full name" required />
          </div>
          <div class="field">
            <label>Email</label>
            <input
              v-model="newMember.email"
              type="email"
              placeholder="email@example.com"
              required
            />
          </div>
          <div class="field">
            <label>Circle</label>
            <select v-model="newMember.circle">
              <option value="community">Community</option>
              <option value="founder">Founder</option>
              <option value="practitioner">Practitioner</option>
            </select>
          </div>
          <div class="field">
            <label>Contribution Tier</label>
            <select v-model="newMember.contributionTier">
              <option value="0">$0/month</option>
              <option value="5">$5/month</option>
              <option value="15">$15/month</option>
              <option value="30">$30/month</option>
              <option value="50">$50/month</option>
            </select>
          </div>
          <div class="modal-actions">
            <button type="button" class="btn" @click="showCreateModal = false">
              Cancel
            </button>
            <button type="submit" class="btn btn-primary" :disabled="creating">
              {{ creating ? "Creating..." : "Create Member" }}
            </button>
          </div>
        </form>
      </div>
    </div>

    <!-- CSV Import Modal -->
    <div
      v-if="showImportModal"
      class="modal-overlay"
      @click.self="closeImportModal"
    >
      <div class="modal modal-wide">
        <div class="modal-header">
          <h2>Import Members from CSV</h2>
          <button class="modal-close" @click="closeImportModal">&times;</button>
        </div>

        <div class="modal-body">
          <div v-if="!csvRows.length">
            <p class="help-text">
              Upload a CSV with columns:
              <code>name,email,circle,contributionTier</code>
            </p>
            <p class="help-text" style="margin-bottom: 12px">
              Valid circles: community, founder, practitioner. Valid tiers: 0,
              5, 15, 30, 50.
            </p>
            <input
              ref="csvFileInput"
              type="file"
              accept=".csv"
              @change="handleCsvFile"
              class="file-input"
            />
          </div>

          <div v-if="csvParseError" class="error-box">
            {{ csvParseError }}
          </div>

          <div v-if="csvRows.length">
            <div class="csv-summary">
              <span
                >{{ csvRows.length }} row{{
                  csvRows.length !== 1 ? "s" : ""
                }}
                parsed.</span
              >
              <span
                v-if="csvValidRows.length !== csvRows.length"
                class="csv-errors"
              >
                {{ csvRows.length - csvValidRows.length }} with errors.
              </span>
              <button @click="resetCsvImport" class="link-btn">
                Choose different file
              </button>
            </div>

            <div class="csv-table-wrap">
              <table class="csv-table">
                <thead>
                  <tr>
                    <th>Status</th>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Circle</th>
                    <th>Tier</th>
                  </tr>
                </thead>
                <tbody>
                  <tr
                    v-for="(row, i) in csvRows"
                    :key="i"
                    :class="{ 'row-error': row.error }"
                  >
                    <td>
                      <span v-if="row.error" class="status-error">{{
                        row.error
                      }}</span>
                      <span v-else class="status-ok">OK</span>
                    </td>
                    <td>{{ row.name }}</td>
                    <td class="col-email">{{ row.email }}</td>
                    <td>{{ row.circle }}</td>
                    <td>${{ row.contributionTier }}/mo</td>
                  </tr>
                </tbody>
              </table>
            </div>

            <div v-if="importResults" class="results-box">
              <strong>Import complete</strong>
              <p class="status-ok">{{ importResults.created }} created</p>
              <p v-if="importResults.failed" class="status-error">
                {{ importResults.failed }} failed
              </p>
              <div v-if="importResults.results?.some((r) => !r.success)">
                <p
                  v-for="fail in importResults.results.filter(
                    (r) => !r.success,
                  )"
                  :key="fail.email"
                  class="status-error"
                  style="font-size: 11px"
                >
                  {{ fail.email }}: {{ fail.error }}
                </p>
              </div>
            </div>
          </div>
        </div>

        <div class="modal-actions">
          <button @click="closeImportModal" class="btn">
            {{ importResults ? "Done" : "Cancel" }}
          </button>
          <button
            v-if="csvValidRows.length && !importResults"
            :disabled="importing"
            @click="submitImport"
            class="btn btn-primary"
          >
            {{
              importing
                ? "Importing..."
                : `Import ${csvValidRows.length} member${csvValidRows.length !== 1 ? "s" : ""}`
            }}
          </button>
        </div>
      </div>
    </div>

    <!-- Edit Member Modal -->
    <div
      v-if="showEditModal"
      class="modal-overlay"
      @click.self="showEditModal = false"
    >
      <div class="modal">
        <div class="modal-header">
          <h2>Edit Member</h2>
          <button class="modal-close" @click="showEditModal = false">
            &times;
          </button>
        </div>

        <form @submit.prevent="submitEditMember" class="modal-body">
          <div class="field">
            <label>Name</label>
            <input v-model="editingMember.name" required />
          </div>
          <div class="field">
            <label>Email</label>
            <input v-model="editingMember.email" type="email" required />
          </div>
          <div class="field">
            <label>Circle</label>
            <select v-model="editingMember.circle">
              <option value="community">Community</option>
              <option value="founder">Founder</option>
              <option value="practitioner">Practitioner</option>
            </select>
          </div>
          <div class="field">
            <label>Contribution Tier</label>
            <select v-model="editingMember.contributionTier">
              <option value="0">$0/month</option>
              <option value="5">$5/month</option>
              <option value="15">$15/month</option>
              <option value="30">$30/month</option>
              <option value="50">$50/month</option>
            </select>
          </div>
          <div class="field">
            <label>Status</label>
            <select v-model="editingMember.status">
              <option value="pending_payment">Pending Payment</option>
              <option value="active">Active</option>
              <option value="suspended">Suspended</option>
              <option value="cancelled">Cancelled</option>
            </select>
          </div>
          <div class="modal-actions">
            <button type="button" class="btn" @click="showEditModal = false">
              Cancel
            </button>
            <button type="submit" class="btn btn-primary" :disabled="saving">
              {{ saving ? "Saving..." : "Save Changes" }}
            </button>
          </div>
        </form>
      </div>
    </div>

    <!-- Send Invites Modal -->
    <div
      v-if="showInviteModal"
      class="modal-overlay"
      @click.self="showInviteModal = false"
    >
      <div class="modal modal-wide">
        <div class="modal-header">
          <h2>Send Invite Emails</h2>
          <button class="modal-close" @click="showInviteModal = false">
            &times;
          </button>
        </div>

        <div class="modal-body">
          <p class="help-text">
            Sending to <strong>{{ selectedMemberIds.length }}</strong> member{{
              selectedMemberIds.length !== 1 ? "s" : ""
            }}. Each receives a unique magic login link valid for 48 hours.
          </p>

          <div class="field">
            <label>Email Template</label>
            <textarea v-model="inviteTemplate" rows="12"></textarea>
            <p class="help-text" style="margin-top: 4px">
              Tokens: <code>{name}</code>, <code>{loginLink}</code>,
              <code>{circle}</code>
            </p>
          </div>

          <div v-if="invitePreviewMember" class="field">
            <label>Preview ({{ invitePreviewMember.name }})</label>
            <pre class="preview-box">{{ invitePreviewText }}</pre>
          </div>

          <div v-if="inviteResults" class="results-box">
            <strong>Invites sent</strong>
            <p class="status-ok">{{ inviteResults.sent }} sent</p>
            <p v-if="inviteResults.failed" class="status-error">
              {{ inviteResults.failed }} failed
            </p>
            <div v-if="inviteResults.results?.some((r) => !r.success)">
              <p
                v-for="fail in inviteResults.results.filter((r) => !r.success)"
                :key="fail.email"
                class="status-error"
                style="font-size: 11px"
              >
                {{ fail.email }}: {{ fail.error }}
              </p>
            </div>
          </div>
        </div>

        <div class="modal-actions">
          <button @click="showInviteModal = false" class="btn">
            {{ inviteResults ? "Done" : "Cancel" }}
          </button>
          <button
            v-if="!inviteResults"
            :disabled="sendingInvites"
            @click="submitInvites"
            class="btn btn-primary"
          >
            {{
              sendingInvites
                ? "Sending..."
                : `Send ${selectedMemberIds.length} invite${selectedMemberIds.length !== 1 ? "s" : ""}`
            }}
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
definePageMeta({
  layout: "admin",
  middleware: "admin",
});

const toast = useToast();

const {
  data: members,
  pending,
  error,
  refresh,
} = await useFetch("/api/admin/members");

const searchQuery = ref("");
const circleFilter = ref("");
const showCreateModal = ref(false);
const creating = ref(false);

// Selection
const selectedMemberIds = ref([]);

// CSV import
const showImportModal = ref(false);
const csvFileInput = ref(null);
const csvRows = ref([]);
const csvParseError = ref("");
const importing = ref(false);
const importResults = ref(null);

// Invite
const showInviteModal = ref(false);
const sendingInvites = ref(false);
const inviteResults = ref(null);

const DEFAULT_INVITE_TEMPLATE = `Hi {name},

You've been invited to Ghost Guild as a member of the {circle} circle.

Sign in here to get started:
{loginLink}

This link expires in 48 hours. After that, you can always request a new login link at https://ghostguild.org/login.

See you inside.`;

const inviteTemplate = ref(DEFAULT_INVITE_TEMPLATE);

const newMember = reactive({
  name: "",
  email: "",
  circle: "community",
  contributionTier: "0",
});

const filteredMembers = computed(() => {
  if (!members.value) return [];

  return members.value.filter((member) => {
    const matchesSearch =
      !searchQuery.value ||
      member.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
      member.email.toLowerCase().includes(searchQuery.value.toLowerCase());

    const matchesCircle =
      !circleFilter.value || member.circle === circleFilter.value;

    return matchesSearch && matchesCircle;
  });
});

// Selection helpers
const allVisibleSelected = computed(() => {
  if (!filteredMembers.value.length) return false;
  return filteredMembers.value.every((m) =>
    selectedMemberIds.value.includes(m._id),
  );
});

const someVisibleSelected = computed(() => {
  return filteredMembers.value.some((m) =>
    selectedMemberIds.value.includes(m._id),
  );
});

const toggleSelectAll = () => {
  if (allVisibleSelected.value) {
    const visibleIds = new Set(filteredMembers.value.map((m) => m._id));
    selectedMemberIds.value = selectedMemberIds.value.filter(
      (id) => !visibleIds.has(id),
    );
  } else {
    const currentSet = new Set(selectedMemberIds.value);
    for (const m of filteredMembers.value) {
      currentSet.add(m._id);
    }
    selectedMemberIds.value = [...currentSet];
  }
};

const toggleSelect = (id) => {
  const idx = selectedMemberIds.value.indexOf(id);
  if (idx >= 0) {
    selectedMemberIds.value.splice(idx, 1);
  } else {
    selectedMemberIds.value.push(id);
  }
};

// Invite preview
const invitePreviewMember = computed(() => {
  if (!selectedMemberIds.value.length || !members.value) return null;
  return members.value.find((m) => m._id === selectedMemberIds.value[0]);
});

const invitePreviewText = computed(() => {
  if (!invitePreviewMember.value) return "";
  return inviteTemplate.value
    .replace(/\{name\}/g, invitePreviewMember.value.name)
    .replace(
      /\{loginLink\}/g,
      "https://ghostguild.org/api/auth/verify?token=...",
    )
    .replace(/\{circle\}/g, invitePreviewMember.value.circle);
});

const formatDate = (dateString) => {
  return new Date(dateString).toLocaleDateString();
};

// --- Create Member ---
const createMember = async () => {
  creating.value = true;
  try {
    await $fetch("/api/admin/members", {
      method: "POST",
      body: newMember,
    });

    showCreateModal.value = false;
    Object.assign(newMember, {
      name: "",
      email: "",
      circle: "community",
      contributionTier: "0",
    });

    await refresh();
    toast.add({ title: "Member created", color: "green" });
  } catch (err) {
    console.error("Failed to create member:", err);
    toast.add({
      title: "Failed to create member",
      description: err.data?.statusMessage || err.message,
      color: "red",
    });
  } finally {
    creating.value = false;
  }
};

// --- CSV Import ---
const VALID_CIRCLES = ["community", "founder", "practitioner"];
const VALID_TIERS = ["0", "5", "15", "30", "50"];

const handleCsvFile = (event) => {
  const file = event.target.files[0];
  if (!file) return;

  csvParseError.value = "";
  csvRows.value = [];

  const reader = new FileReader();
  reader.onload = (e) => {
    const text = e.target.result;
    parseCsv(text);
  };
  reader.readAsText(file);
};

const parseCsv = (text) => {
  const lines = text.split(/\r?\n/).filter((l) => l.trim());
  if (lines.length < 2) {
    csvParseError.value =
      "CSV must have a header row and at least one data row.";
    return;
  }

  const header = lines[0].split(",").map((h) => h.trim().toLowerCase());
  const nameIdx = header.indexOf("name");
  const emailIdx = header.indexOf("email");
  const circleIdx = header.indexOf("circle");
  const tierIdx = header.indexOf("contributiontier");

  if (nameIdx === -1 || emailIdx === -1 || circleIdx === -1 || tierIdx === -1) {
    csvParseError.value = `Missing required columns. Found: ${header.join(", ")}. Need: name, email, circle, contributionTier`;
    return;
  }

  const seenEmails = new Set();
  const rows = [];

  for (let i = 1; i < lines.length; i++) {
    const cols = lines[i].split(",").map((c) => c.trim());
    const name = cols[nameIdx] || "";
    const email = (cols[emailIdx] || "").toLowerCase();
    const circle = (cols[circleIdx] || "").toLowerCase();
    const contributionTier = cols[tierIdx] || "";

    let error = null;
    if (!name) error = "Missing name";
    else if (!email || !email.includes("@")) error = "Invalid email";
    else if (!VALID_CIRCLES.includes(circle))
      error = `Invalid circle: ${circle}`;
    else if (!VALID_TIERS.includes(contributionTier))
      error = `Invalid tier: ${contributionTier}`;
    else if (seenEmails.has(email)) error = "Duplicate email in CSV";

    if (!error) seenEmails.add(email);

    rows.push({ name, email, circle, contributionTier, error });
  }

  csvRows.value = rows;
};

const csvValidRows = computed(() => csvRows.value.filter((r) => !r.error));

const resetCsvImport = () => {
  csvRows.value = [];
  csvParseError.value = "";
  importResults.value = null;
  if (csvFileInput.value) csvFileInput.value.value = "";
};

const closeImportModal = () => {
  showImportModal.value = false;
  if (importResults.value) {
    resetCsvImport();
    refresh();
  }
};

const submitImport = async () => {
  importing.value = true;
  try {
    const payload = csvValidRows.value.map(
      ({ name, email, circle, contributionTier }) => ({
        name,
        email,
        circle,
        contributionTier,
      }),
    );

    const result = await $fetch("/api/admin/members/import", {
      method: "POST",
      body: { members: payload },
    });

    importResults.value = result;
    toast.add({
      title: `Imported ${result.created} member${result.created !== 1 ? "s" : ""}`,
      description: result.failed ? `${result.failed} failed` : undefined,
      color: result.failed ? "orange" : "green",
    });
  } catch (err) {
    console.error("Import failed:", err);
    toast.add({
      title: "Import failed",
      description: err.data?.statusMessage || err.message,
      color: "red",
    });
  } finally {
    importing.value = false;
  }
};

// --- Send Invites ---
const openInviteModal = () => {
  inviteResults.value = null;
  inviteTemplate.value = DEFAULT_INVITE_TEMPLATE;
  showInviteModal.value = true;
};

const submitInvites = async () => {
  sendingInvites.value = true;
  try {
    const result = await $fetch("/api/admin/members/invite", {
      method: "POST",
      body: {
        memberIds: selectedMemberIds.value,
        emailTemplate: inviteTemplate.value,
      },
    });

    inviteResults.value = result;
    await refresh();
    selectedMemberIds.value = [];

    toast.add({
      title: `Sent ${result.sent} invite${result.sent !== 1 ? "s" : ""}`,
      description: result.failed ? `${result.failed} failed` : undefined,
      color: result.failed ? "orange" : "green",
    });
  } catch (err) {
    console.error("Failed to send invites:", err);
    toast.add({
      title: "Failed to send invites",
      description: err.data?.statusMessage || err.message,
      color: "red",
    });
  } finally {
    sendingInvites.value = false;
  }
};

// --- Existing actions ---
const sendSlackInvite = (member) => {
  console.log("Send Slack invite to:", member.email);
};

// --- Edit Member ---
const showEditModal = ref(false);
const saving = ref(false);
const editingMemberId = ref(null);
const editingMember = reactive({
  name: "",
  email: "",
  circle: "community",
  contributionTier: "0",
  status: "pending_payment",
});

const editMember = (member) => {
  editingMemberId.value = member._id;
  Object.assign(editingMember, {
    name: member.name,
    email: member.email,
    circle: member.circle,
    contributionTier: String(member.contributionTier),
    status: member.status || "pending_payment",
  });
  showEditModal.value = true;
};

const submitEditMember = async () => {
  saving.value = true;
  try {
    await $fetch(`/api/admin/members/${editingMemberId.value}`, {
      method: "PUT",
      body: {
        name: editingMember.name,
        email: editingMember.email,
        circle: editingMember.circle,
        contributionTier: editingMember.contributionTier,
        status: editingMember.status,
      },
    });
    showEditModal.value = false;
    await refresh();
    toast.add({ title: "Member updated", color: "green" });
  } catch (err) {
    toast.add({
      title: "Failed to update member",
      description: err.data?.statusMessage || err.message,
      color: "red",
    });
  } finally {
    saving.value = false;
  }
};
</script>

<style scoped>
.admin-members {
  max-width: 1100px;
  margin: 0 auto;
}

/* ---- PAGE HEADER ---- */
.page-header {
  padding: 28px 28px 20px;
  border-bottom: 1px dashed var(--border);
}

.header-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  flex-wrap: wrap;
}

.page-header h1 {
  font-family: "Brygada 1918", serif;
  font-size: 24px;
  font-weight: 500;
  color: var(--text-bright);
  line-height: 1.2;
  margin-bottom: 4px;
}

.page-header p {
  font-size: 12px;
  color: var(--text-dim);
}

.header-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

/* ---- FILTER BAR ---- */
.filter-bar {
  display: flex;
  gap: 12px;
  padding: 16px 28px;
  border-bottom: 1px dashed var(--border);
}

/* ---- TABLE ---- */
.table-wrap {
  padding: 0 28px 28px;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

thead th {
  text-align: left;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 14px 10px 10px;
  border-bottom: 1px dashed var(--border-d);
  font-weight: normal;
}

tbody tr {
  border-bottom: 1px dashed var(--border);
  transition: background 0.1s;
}

tbody tr:hover {
  background: var(--surface);
}

tbody td {
  padding: 10px;
  color: var(--text);
  vertical-align: middle;
}

.col-check {
  width: 32px;
  padding-left: 0;
  padding-right: 4px;
}

.col-name {
  font-weight: 500;
  color: var(--text-bright);
}

.col-email {
  color: var(--text-dim);
  font-size: 11px;
}

.col-mono {
  font-variant-numeric: tabular-nums;
}

.col-date {
  font-size: 11px;
  color: var(--text-faint);
}

.col-actions {
  white-space: nowrap;
}

/* ---- LINK BUTTON ---- */
.link-btn {
  background: none;
  border: none;
  color: var(--candle);
  cursor: pointer;
  font-family: "Commit Mono", monospace;
  font-size: 11px;
  padding: 2px 6px;
}

.link-btn:hover {
  text-decoration: underline;
}

/* ---- STATUS INDICATORS ---- */
.status-ok {
  color: var(--green);
  font-size: 11px;
}

.status-dim {
  color: var(--text-faint);
  font-size: 11px;
}

.status-error {
  color: var(--ember);
  font-size: 11px;
}

/* ---- MODALS ---- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
}

.modal {
  background: var(--bg);
  border: 1px dashed var(--border);
  max-width: 440px;
  width: 100%;
  margin: 16px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
}

.modal-wide {
  max-width: 640px;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 24px 16px;
  border-bottom: 1px dashed var(--border);
}

.modal-header h2 {
  font-family: "Brygada 1918", serif;
  font-size: 18px;
  font-weight: 500;
  color: var(--text-bright);
}

.modal-close {
  background: none;
  border: none;
  color: var(--text-faint);
  font-size: 20px;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
}

.modal-close:hover {
  color: var(--text);
}

.modal-body {
  padding: 20px 24px;
  overflow-y: auto;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 16px 24px;
  border-top: 1px dashed var(--border);
}

/* ---- HELP TEXT ---- */
.help-text {
  font-size: 11px;
  color: var(--text-dim);
  line-height: 1.5;
}

.help-text code {
  color: var(--text-bright);
  font-size: 11px;
}

/* ---- FILE INPUT ---- */
.file-input {
  font-size: 12px;
  color: var(--text-dim);
}

/* ---- ERROR / RESULTS BOXES ---- */
.error-box {
  padding: 12px 16px;
  border: 1px dashed var(--ember);
  color: var(--ember);
  font-size: 12px;
  margin-bottom: 12px;
}

.results-box {
  padding: 16px 20px;
  border: 1px dashed var(--border);
  margin-top: 16px;
}

.results-box strong {
  color: var(--text-bright);
  font-size: 13px;
  display: block;
  margin-bottom: 4px;
}

/* ---- CSV TABLE ---- */
.csv-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 12px;
}

.csv-errors {
  color: var(--ember);
}

.csv-table-wrap {
  max-height: 250px;
  overflow: auto;
  border: 1px dashed var(--border);
}

.csv-table {
  font-size: 11px;
}

.csv-table thead th {
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 1;
}

.row-error {
  background: rgba(138, 68, 32, 0.04);
}

/* ---- PREVIEW BOX ---- */
.preview-box {
  font-family: "Commit Mono", monospace;
  font-size: 11px;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px dashed var(--border);
  padding: 16px;
  white-space: pre-wrap;
  overflow: auto;
  max-height: 200px;
  line-height: 1.5;
}

/* ---- STATES ---- */
.loading-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--text-faint);
  font-size: 12px;
}

.error-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--ember);
  font-size: 12px;
}

.empty-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--text-faint);
  font-size: 12px;
}

.spinner {
  width: 24px;
  height: 24px;
  border: 2px dashed var(--candle);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin: 0 auto 12px;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ---- RESPONSIVE ---- */
@media (max-width: 768px) {
  .page-header {
    padding: 24px 20px 16px;
  }

  .header-row {
    flex-direction: column;
  }

  .header-actions {
    flex-wrap: wrap;
  }

  .filter-bar {
    flex-direction: column;
    padding: 12px 20px;
  }

  .table-wrap {
    padding: 0 12px 20px;
    overflow-x: auto;
  }

  table {
    min-width: 700px;
  }
}
</style>
