<script lang="ts">
	import { goto } from '$app/navigation';
	import { page } from '$app/state';
	import { getApiBaseUrl } from '$lib/api/config';
	import { authenticatedFetch } from '$lib/auth';
	import Pagination from '$lib/components/molecules/Pagination/Pagination.svelte';
	import SearchInput from '$lib/components/molecules/SearchInput/SearchInput.svelte';
	import { untrack } from 'svelte';

	// Types
	interface Invitation {
		id: string;
		studentId: string;
		parentEmail: string;
		status: string;
		createdAt: string;
		expiresAt: string;
		sentAt: string | null;
		activatedAt: string | null;
		activatedUserId: string | null;
		studentFirstName: string | null;
		studentLastName: string | null;
	}

	interface StudentOption {
		id: string;
		firstName: string;
		lastName: string;
	}

	// Status options for filter
	const STATUS_OPTIONS = [
		{ value: 'pending', label: 'Non envoyée' },
		{ value: 'sent', label: 'Envoyée' },
		{ value: 'expired', label: 'Expirée' },
		{ value: 'activated', label: 'Activée' }
	];

	// State
	let invitations = $state<Invitation[]>([]);
	let isLoading = $state(true);
	let error = $state<string | null>(null);
	let successMessage = $state<string | null>(null);

	// Filters
	let filterStatus = $state<string>(page.url.searchParams.get('status') ?? '');

	// Pagination & Search
	let currentPage = $state(Number(page.url.searchParams.get('page')) || 1);
	let searchTerm = $state(page.url.searchParams.get('search') ?? '');
	let totalItems = $state(0);
	const itemsPerPage = 30;
	let totalPages = $derived(Math.ceil(totalItems / itemsPerPage));

	// Invite modal state
	let showInviteModal = $state(false);
	let inviteStudentId = $state('');
	let inviteEmail1 = $state('');
	let inviteEmail2 = $state('');
	let isSubmitting = $state(false);
	let isResending = $state<string | null>(null);

	// Students for the invite form
	let students = $state<StudentOption[]>([]);
	let isLoadingStudents = $state(false);

	// Load invitations on mount
	let loadAbortController: AbortController | null = null;

	$effect(() => {
		untrack(() => loadInvitations());
	});

	async function loadInvitations() {
		loadAbortController?.abort();
		const controller = new AbortController();
		loadAbortController = controller;

		try {
			isLoading = true;
			error = null;
			const apiUrl = getApiBaseUrl();
			const params = new URLSearchParams();
			params.set('page', String(currentPage));
			params.set('itemsPerPage', String(itemsPerPage));
			if (searchTerm) params.set('search', searchTerm);
			if (filterStatus) params.set('status', filterStatus);
			const url = `${apiUrl}/parent-invitations?${params.toString()}`;
			const response = await authenticatedFetch(url, { signal: controller.signal });

			if (controller.signal.aborted) return;

			if (!response.ok) {
				throw new Error('Erreur lors du chargement des invitations');
			}

			const data = await response.json();
			invitations = data['hydra:member'] ?? data['member'] ?? (Array.isArray(data) ? data : []);
			totalItems = data['hydra:totalItems'] ?? data['totalItems'] ?? invitations.length;
		} catch (e) {
			if (e instanceof DOMException && e.name === 'AbortError') return;
			error = e instanceof Error ? e.message : 'Erreur inconnue';
			invitations = [];
			totalItems = 0;
		} finally {
			if (!controller.signal.aborted) {
				isLoading = false;
			}
		}
	}

	function updateUrl() {
		const params = new URLSearchParams();
		if (currentPage > 1) params.set('page', String(currentPage));
		if (searchTerm) params.set('search', searchTerm);
		if (filterStatus) params.set('status', filterStatus);
		const query = params.toString();
		goto(`?${query}`, { replaceState: true, noScroll: true, keepFocus: true });
	}

	function handleSearch(value: string) {
		searchTerm = value;
		currentPage = 1;
		updateUrl();
		loadInvitations();
	}

	function handlePageChange(newPage: number) {
		currentPage = newPage;
		updateUrl();
		loadInvitations();
	}

	function applyFilters() {
		currentPage = 1;
		updateUrl();
		loadInvitations();
	}

	function resetFilters() {
		filterStatus = '';
		searchTerm = '';
		currentPage = 1;
		updateUrl();
		loadInvitations();
	}

	let studentsTruncated = $state(false);

	async function loadStudents() {
		try {
			isLoadingStudents = true;
			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(
				`${apiUrl}/students?itemsPerPage=500`
			);
			if (!response.ok) throw new Error('Erreur lors du chargement des élèves');
			const data = await response.json();
			const members = data['hydra:member'] ?? data['member'] ?? [];
			const totalStudents = data['hydra:totalItems'] ?? data['totalItems'] ?? members.length;
			studentsTruncated = totalStudents > members.length;
			students = members.map((s: Record<string, string>) => ({
				id: s['id'],
				firstName: s['firstName'],
				lastName: s['lastName']
			}));
		} catch {
			error = 'Erreur lors du chargement des élèves. Veuillez réessayer.';
			students = [];
		} finally {
			isLoadingStudents = false;
		}
	}

	function openInviteModal() {
		showInviteModal = true;
		inviteStudentId = '';
		inviteEmail1 = '';
		inviteEmail2 = '';
		error = null;
		if (students.length === 0) {
			loadStudents();
		}
	}

	function closeInviteModal() {
		showInviteModal = false;
	}

	let modalElement = $state<HTMLElement>();

	function trapFocus(event: KeyboardEvent) {
		if (event.key !== 'Tab' || !modalElement) return;
		const focusable = modalElement.querySelectorAll<HTMLElement>(
			'button:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
		);
		if (focusable.length === 0) return;
		const first = focusable.item(0);
		const last = focusable.item(focusable.length - 1);
		if (event.shiftKey && document.activeElement === first) {
			event.preventDefault();
			last.focus();
		} else if (!event.shiftKey && document.activeElement === last) {
			event.preventDefault();
			first.focus();
		}
	}

	async function handleSendInvitation() {
		if (!inviteStudentId || !inviteEmail1.trim()) return;

		try {
			isSubmitting = true;
			error = null;
			const apiUrl = getApiBaseUrl();

			// Send invitation for parent 1
			const response1 = await authenticatedFetch(`${apiUrl}/parent-invitations`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					studentId: inviteStudentId,
					parentEmail: inviteEmail1.trim().toLowerCase()
				})
			});

			if (!response1.ok) {
				const errorData = await response1.json().catch(() => ({}));
				throw new Error(
					errorData['hydra:description'] ??
						errorData.message ??
						errorData.detail ??
						`Erreur lors de l'envoi (${response1.status})`
				);
			}

			// Send invitation for parent 2 if provided
			if (inviteEmail2.trim()) {
				const response2 = await authenticatedFetch(`${apiUrl}/parent-invitations`, {
					method: 'POST',
					headers: { 'Content-Type': 'application/json' },
					body: JSON.stringify({
						studentId: inviteStudentId,
						parentEmail: inviteEmail2.trim().toLowerCase()
					})
				});

				if (!response2.ok) {
					const errorData = await response2.json().catch(() => ({}));
					throw new Error(
						errorData['hydra:description'] ??
							errorData.message ??
							errorData.detail ??
							`Erreur lors de l'envoi au parent 2 (${response2.status})`
					);
				}
			}

			const count = inviteEmail2.trim() ? 2 : 1;
			successMessage = `${count} invitation(s) envoyée(s) avec succès.`;
			await loadInvitations();
			closeInviteModal();
		} catch (e) {
			error = e instanceof Error ? e.message : "Erreur lors de l'envoi";
		} finally {
			isSubmitting = false;
		}
	}

	async function handleResend(invitationId: string) {
		try {
			isResending = invitationId;
			error = null;
			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(
				`${apiUrl}/parent-invitations/${invitationId}/resend`,
				{
					method: 'POST',
					headers: { 'Content-Type': 'application/json' },
					body: JSON.stringify({})
				}
			);

			if (!response.ok) {
				const errorData = await response.json().catch(() => ({}));
				throw new Error(
					errorData['hydra:description'] ??
						errorData.message ??
						errorData.detail ??
						`Erreur lors du renvoi (${response.status})`
				);
			}

			const updated = await response.json().catch(() => null);
			invitations = invitations.map((inv) =>
				inv.id === invitationId
					? {
							...inv,
							status: updated?.status ?? 'sent',
							sentAt: updated?.sentAt ?? new Date().toISOString(),
							expiresAt: updated?.expiresAt ?? inv.expiresAt
						}
					: inv
			);
			successMessage = "L'invitation a été renvoyée avec succès.";
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors du renvoi';
		} finally {
			isResending = null;
		}
	}

	async function handleExport() {
		try {
			const apiUrl = getApiBaseUrl();
			const params = new URLSearchParams();
			if (filterStatus) params.set('status', filterStatus);
			if (searchTerm) params.set('search', searchTerm);
			params.set('itemsPerPage', '10000');
			const url = `${apiUrl}/parent-invitations?${params.toString()}`;
			const response = await authenticatedFetch(url);

			if (!response.ok) throw new Error("Erreur lors de l'export");

			const data = await response.json();
			const items: Invitation[] =
				data['hydra:member'] ?? data['member'] ?? [];

			// Build CSV
			const headers = [
				'Élève',
				'Email parent',
				'Statut',
				'Date envoi',
				'Date activation'
			];
			const rows = items.map((inv) => [
				`${inv.studentFirstName ?? ''} ${inv.studentLastName ?? ''}`.trim(),
				inv.parentEmail,
				getStatusLabel(inv.status),
				formatDate(inv.sentAt),
				formatDate(inv.activatedAt)
			]);

			const csvContent = [headers, ...rows]
				.map((row) => row.map((cell) => `"${cell.replace(/"/g, '""')}"`).join(','))
				.join('\n');

			const blob = new Blob(['\uFEFF' + csvContent], { type: 'text/csv;charset=utf-8;' });
			const link = document.createElement('a');
			link.href = URL.createObjectURL(blob);
			link.download = `invitations-parents-${new Date().toISOString().slice(0, 10)}.csv`;
			link.click();
			URL.revokeObjectURL(link.href);
		} catch (e) {
			error = e instanceof Error ? e.message : "Erreur lors de l'export";
		}
	}

	function getStatusLabel(status: string): string {
		switch (status) {
			case 'pending':
				return 'Non envoyée';
			case 'sent':
				return 'Envoyée';
			case 'expired':
				return 'Expirée';
			case 'activated':
				return 'Activée';
			default:
				return status;
		}
	}

	function getStatusClass(status: string): string {
		switch (status) {
			case 'activated':
				return 'status-active';
			case 'sent':
				return 'status-pending';
			case 'expired':
				return 'status-expired';
			case 'pending':
				return 'status-draft';
			default:
				return '';
		}
	}

	function canResend(invitation: Invitation): boolean {
		return invitation.status === 'sent' || invitation.status === 'expired';
	}

	function formatDate(dateStr: string | null): string {
		if (!dateStr) return '-';
		return new Date(dateStr).toLocaleDateString('fr-FR', {
			day: '2-digit',
			month: '2-digit',
			year: 'numeric'
		});
	}
</script>

<svelte:window
	onkeydown={(e) => {
		if (e.key === 'Escape' && showInviteModal) closeInviteModal();
		if (showInviteModal) trapFocus(e);
	}}
/>

<svelte:head>
	<title>Invitations parents - Classeo</title>
</svelte:head>

<div class="invitations-page">
	<header class="page-header">
		<div class="header-content">
			<h1>Invitations parents</h1>
			<p class="subtitle">Gérez les invitations envoyées aux parents d'élèves</p>
		</div>
		<div class="header-actions">
			<button class="btn-secondary" onclick={handleExport}>
				Exporter CSV
			</button>
			<a href="/admin/import/parents" class="btn-secondary">
				Importer un fichier
			</a>
			<button class="btn-primary" onclick={openInviteModal}>
				<span class="btn-icon">+</span>
				Inviter les parents
			</button>
		</div>
	</header>

	{#if error}
		<div class="alert alert-error" role="alert">
			{error}
			<button class="alert-close" onclick={() => (error = null)} aria-label="Fermer l'erreur">x</button>
		</div>
	{/if}

	{#if successMessage}
		<div class="alert alert-success" role="alert">
			{successMessage}
			<button class="alert-close" onclick={() => (successMessage = null)} aria-label="Fermer le message">x</button>
		</div>
	{/if}

	<!-- Filters -->
	<div class="filters-bar">
		<div class="filter-group">
			<label for="filter-status">Statut</label>
			<select id="filter-status" bind:value={filterStatus}>
				<option value="">Tous les statuts</option>
				{#each STATUS_OPTIONS as opt}
					<option value={opt.value}>{opt.label}</option>
				{/each}
			</select>
		</div>
		<div class="filter-actions">
			<button class="btn-secondary btn-sm" onclick={applyFilters}>Filtrer</button>
			<button class="btn-text btn-sm" onclick={resetFilters}>Réinitialiser</button>
		</div>
	</div>

	<SearchInput
		value={searchTerm}
		onSearch={handleSearch}
		placeholder="Rechercher par nom d'élève, email parent..."
	/>

	{#if isLoading}
		<div class="loading-state" aria-live="polite" role="status">
			<div class="spinner"></div>
			<p>Chargement des invitations...</p>
		</div>
	{:else if invitations.length === 0}
		<div class="empty-state">
			<span class="empty-icon">&#x2709;</span>
			{#if searchTerm || filterStatus}
				<h2>Aucun résultat</h2>
				<p>Aucune invitation ne correspond à vos critères de recherche</p>
				<button class="btn-secondary" onclick={resetFilters}>Réinitialiser les filtres</button>
			{:else}
				<h2>Aucune invitation</h2>
				<p>Commencez par inviter les parents de vos élèves</p>
				<button class="btn-primary" onclick={openInviteModal}>Inviter les parents</button>
			{/if}
		</div>
	{:else}
		<div class="table-container">
			<table class="data-table">
				<thead>
					<tr>
						<th>Élève</th>
						<th>Email parent</th>
						<th>Statut</th>
						<th>Date d'envoi</th>
						<th>Date d'activation</th>
						<th>Actions</th>
					</tr>
				</thead>
				<tbody>
					{#each invitations as invitation (invitation.id)}
						<tr>
							<td data-label="Élève" class="name-cell">
								<span class="fullname">
									{invitation.studentFirstName ?? ''} {invitation.studentLastName ?? ''}
								</span>
							</td>
							<td data-label="Email" class="email-cell">{invitation.parentEmail}</td>
							<td data-label="Statut">
								<span class="status-badge {getStatusClass(invitation.status)}">
									{getStatusLabel(invitation.status)}
								</span>
							</td>
							<td data-label="Envoi" class="date-cell">{formatDate(invitation.sentAt)}</td>
							<td data-label="Activation" class="date-cell">
								{formatDate(invitation.activatedAt)}
							</td>
							<td data-label="Actions" class="actions-cell">
								{#if canResend(invitation)}
									<button
										class="btn-secondary btn-sm"
										onclick={() => handleResend(invitation.id)}
										disabled={isResending === invitation.id}
									>
										{#if isResending === invitation.id}
											Envoi...
										{:else}
											Renvoyer
										{/if}
									</button>
								{/if}
							</td>
						</tr>
					{/each}
				</tbody>
			</table>
		</div>
		<Pagination {currentPage} {totalPages} onPageChange={handlePageChange} />
	{/if}
</div>

<!-- Invite Parent Modal -->
{#if showInviteModal}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="modal-overlay" onclick={closeInviteModal} role="presentation">
		<div
			class="modal"
			bind:this={modalElement}
			role="dialog"
			aria-modal="true"
			aria-labelledby="invite-modal-title"
			onclick={(e) => e.stopPropagation()}
		>
			<header class="modal-header">
				<h2 id="invite-modal-title">Inviter les parents</h2>
				<button class="modal-close" onclick={closeInviteModal} aria-label="Fermer">x</button>
			</header>

			<form
				class="modal-body"
				onsubmit={(e) => {
					e.preventDefault();
					handleSendInvitation();
				}}
			>
				<div class="form-group">
					<label for="invite-student">Élève *</label>
					{#if isLoadingStudents}
						<p class="loading-hint">Chargement des élèves...</p>
					{:else}
						<select id="invite-student" bind:value={inviteStudentId} required>
							<option value="">Sélectionnez un élève</option>
							{#each students as student}
								<option value={student.id}>
									{student.lastName} {student.firstName}
								</option>
							{/each}
						</select>
						{#if studentsTruncated}
							<p class="field-warning">Seuls les 500 premiers élèves sont affichés. Utilisez l'import fichier pour un volume plus important.</p>
						{/if}
					{/if}
				</div>

				<div class="form-group">
					<label for="invite-email1">Email parent 1 *</label>
					<input
						type="email"
						id="invite-email1"
						bind:value={inviteEmail1}
						placeholder="ex: parent@email.com"
						required
					/>
				</div>

				<div class="form-group">
					<label for="invite-email2">Email parent 2 (optionnel)</label>
					<input
						type="email"
						id="invite-email2"
						bind:value={inviteEmail2}
						placeholder="ex: autre-parent@email.com"
					/>
				</div>

				<div class="form-hint-block">
					Un email d'invitation sera envoyé à chaque parent.
					L'invitation expire au bout de 7 jours.
				</div>

				<div class="modal-actions">
					<button
						type="button"
						class="btn-secondary"
						onclick={closeInviteModal}
						disabled={isSubmitting}
					>
						Annuler
					</button>
					<button
						type="submit"
						class="btn-primary"
						disabled={isSubmitting || !inviteStudentId || !inviteEmail1.trim()}
					>
						{#if isSubmitting}
							Envoi en cours...
						{:else}
							Envoyer l'invitation
						{/if}
					</button>
				</div>
			</form>
		</div>
	</div>
{/if}


<style>
	.invitations-page {
		padding: 1.5rem;
		max-width: 1200px;
		margin: 0 auto;
	}

	.page-header {
		display: flex;
		justify-content: space-between;
		align-items: flex-start;
		gap: 1rem;
		margin-bottom: 1.5rem;
		flex-wrap: wrap;
	}

	.header-content h1 {
		margin: 0;
		font-size: 1.5rem;
		font-weight: 700;
		color: #1f2937;
	}

	.subtitle {
		margin: 0.25rem 0 0;
		color: #6b7280;
		font-size: 0.875rem;
	}

	.header-actions {
		display: flex;
		gap: 0.75rem;
		align-items: center;
		flex-wrap: wrap;
	}

	/* Buttons */
	.btn-primary {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.75rem 1.25rem;
		background: var(--btn-primary-bg, #3b82f6);
		color: white;
		border: none;
		border-radius: 0.5rem;
		font-weight: 600;
		cursor: pointer;
		transition: background 0.2s;
	}

	.btn-primary:hover:not(:disabled) {
		background: var(--btn-primary-hover-bg, #2563eb);
	}

	.btn-primary:disabled {
		opacity: 0.6;
		cursor: not-allowed;
	}

	.btn-secondary {
		padding: 0.5rem 1rem;
		background: white;
		color: #374151;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-weight: 500;
		cursor: pointer;
		transition: all 0.2s;
	}

	.btn-secondary:hover:not(:disabled) {
		background: #f3f4f6;
	}

	.btn-secondary:disabled {
		opacity: 0.6;
		cursor: not-allowed;
	}

	.btn-text {
		padding: 0.5rem 1rem;
		background: none;
		color: #6b7280;
		border: none;
		border-radius: 0.375rem;
		font-weight: 500;
		cursor: pointer;
		transition: color 0.2s;
	}

	.btn-text:hover {
		color: #374151;
	}

	.btn-sm {
		padding: 0.375rem 0.75rem;
		font-size: 0.875rem;
	}

	.btn-icon {
		font-size: 1.25rem;
		line-height: 1;
	}

	/* Alerts */
	.alert {
		display: flex;
		align-items: center;
		gap: 0.75rem;
		padding: 1rem;
		border-radius: 0.5rem;
		margin-bottom: 1rem;
	}

	.alert-error {
		background: #fef2f2;
		border: 1px solid #fecaca;
		color: #dc2626;
	}

	.alert-success {
		background: #f0fdf4;
		border: 1px solid #bbf7d0;
		color: #16a34a;
	}

	.alert-close {
		margin-left: auto;
		padding: 0.25rem 0.5rem;
		background: none;
		border: none;
		font-size: 1.25rem;
		cursor: pointer;
		opacity: 0.6;
	}

	.alert-close:hover {
		opacity: 1;
	}

	/* Filters */
	.filters-bar {
		display: flex;
		flex-direction: column;
		align-items: stretch;
		gap: 1rem;
		margin-bottom: 1.5rem;
		padding: 1rem;
		background: white;
		border: 1px solid #e5e7eb;
		border-radius: 0.75rem;
		flex-wrap: wrap;
	}

	.filter-group {
		display: flex;
		flex-direction: column;
		gap: 0.25rem;
	}

	.filter-group label {
		font-size: 0.75rem;
		font-weight: 500;
		color: #6b7280;
		text-transform: uppercase;
		letter-spacing: 0.05em;
	}

	.filter-group select {
		padding: 0.5rem 0.75rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 0.875rem;
		min-width: auto;
		width: 100%;
		background: white;
	}

	.filter-group select:focus {
		outline: none;
		border-color: #3b82f6;
		box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
	}

	.filter-actions {
		display: flex;
		gap: 0.5rem;
		align-items: center;
	}

	/* Loading & Empty */
	.loading-state,
	.empty-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 3rem;
		text-align: center;
		background: white;
		border-radius: 0.75rem;
		border: 2px dashed #e5e7eb;
	}

	.spinner {
		width: 2rem;
		height: 2rem;
		border: 3px solid #e5e7eb;
		border-top-color: #3b82f6;
		border-radius: 50%;
		animation: spin 0.8s linear infinite;
	}

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

	.empty-icon {
		font-size: 3rem;
		margin-bottom: 1rem;
	}

	.empty-state h2 {
		margin: 0 0 0.5rem;
		font-size: 1.25rem;
		color: #1f2937;
	}

	.empty-state p {
		margin: 0 0 1.5rem;
		color: #6b7280;
	}

	/* Table */
	.table-container {
		background: white;
		border: 1px solid #e5e7eb;
		border-radius: 0.75rem;
		overflow-x: auto;
	}

	.data-table {
		width: 100%;
		border-collapse: collapse;
	}

	.data-table th {
		text-align: left;
		padding: 0.75rem 1rem;
		font-size: 0.75rem;
		font-weight: 600;
		color: #6b7280;
		text-transform: uppercase;
		letter-spacing: 0.05em;
		border-bottom: 1px solid #e5e7eb;
		background: #f9fafb;
	}

	.data-table td {
		padding: 0.75rem 1rem;
		font-size: 0.875rem;
		color: #374151;
		border-bottom: 1px solid #f3f4f6;
	}

	.data-table tr:last-child td {
		border-bottom: none;
	}

	.data-table tr:hover td {
		background: #f9fafb;
	}

	.name-cell {
		white-space: nowrap;
	}

	.fullname {
		font-weight: 500;
		color: #1f2937;
	}

	.email-cell {
		color: #6b7280;
	}

	.date-cell {
		white-space: nowrap;
		color: #6b7280;
	}

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

	/* Status Badges */
	.status-badge {
		display: inline-block;
		padding: 0.125rem 0.5rem;
		border-radius: 9999px;
		font-size: 0.75rem;
		font-weight: 500;
	}

	.status-active {
		background: #f0fdf4;
		color: #16a34a;
	}

	.status-pending {
		background: #fffbeb;
		color: #d97706;
	}

	.status-expired {
		background: #fef2f2;
		color: #dc2626;
	}

	.status-draft {
		background: #f3f4f6;
		color: #6b7280;
	}

	/* Modal */
	.modal-overlay {
		position: fixed;
		inset: 0;
		background: rgba(0, 0, 0, 0.5);
		display: flex;
		align-items: center;
		justify-content: center;
		padding: 1rem;
		z-index: 100;
	}

	.modal {
		background: white;
		border-radius: 0.75rem;
		width: 100%;
		max-width: 32rem;
		max-height: 90vh;
		overflow: auto;
		box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
	}

	.modal-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 1.25rem 1.5rem;
		border-bottom: 1px solid #e5e7eb;
	}

	.modal-header h2 {
		margin: 0;
		font-size: 1.125rem;
		font-weight: 600;
		color: #1f2937;
	}

	.modal-close {
		padding: 0.25rem 0.5rem;
		background: none;
		border: none;
		font-size: 1.5rem;
		line-height: 1;
		color: #6b7280;
		cursor: pointer;
	}

	.modal-close:hover {
		color: #1f2937;
	}

	.modal-body {
		padding: 1.5rem;
	}

	.form-group {
		margin-bottom: 1.25rem;
	}

	.form-group label {
		display: block;
		margin-bottom: 0.5rem;
		font-weight: 500;
		color: #374151;
	}

	.form-group input,
	.form-group select {
		width: 100%;
		padding: 0.75rem 1rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 1rem;
		transition: border-color 0.2s;
	}

	.form-group input:focus,
	.form-group select:focus {
		outline: none;
		border-color: #3b82f6;
		box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
	}

	.form-hint-block {
		padding: 0.75rem 1rem;
		background: #eff6ff;
		border-radius: 0.375rem;
		font-size: 0.875rem;
		color: #3b82f6;
		margin-bottom: 1.25rem;
	}

	.loading-hint {
		font-size: 0.875rem;
		color: #6b7280;
		font-style: italic;
	}

	.field-warning {
		font-size: 0.8125rem;
		color: #d97706;
		margin: 0.25rem 0 0;
	}

	.modal-actions {
		display: flex;
		justify-content: flex-end;
		gap: 0.75rem;
		padding-top: 1rem;
		border-top: 1px solid #e5e7eb;
	}

	@media (min-width: 768px) {
		.filters-bar {
			flex-direction: row;
			align-items: flex-end;
		}

		.filter-group select {
			min-width: 180px;
			width: auto;
		}
	}

	@media (max-width: 767px) {
		.table-container {
			background: transparent;
			border: none;
		}

		.data-table thead {
			display: none;
		}

		.data-table tbody tr {
			display: block;
			background: white;
			border: 1px solid #e5e7eb;
			border-radius: 0.75rem;
			margin-bottom: 0.75rem;
			padding: 0.25rem 0;
		}

		.data-table tr:hover td {
			background: transparent;
		}

		.data-table td {
			display: flex;
			justify-content: space-between;
			align-items: baseline;
			padding: 0.5rem 1rem;
			border-bottom: none;
			text-align: right;
		}

		.data-table td::before {
			content: attr(data-label);
			font-weight: 600;
			font-size: 0.75rem;
			color: #6b7280;
			text-transform: uppercase;
			letter-spacing: 0.05em;
			text-align: left;
			margin-right: 1rem;
			flex-shrink: 0;
		}

		.name-cell {
			white-space: normal;
		}

		.actions-cell {
			justify-content: flex-end;
			flex-wrap: wrap;
			padding-top: 0.75rem;
			border-top: 1px solid #f3f4f6;
		}
	}
</style>
