{#
  Form Macros
  ===========
  Reusable form input components.

  Usage:
    {% from 'shared/macros/forms.html' import form_input, form_select, form_textarea, form_checkbox, password_input, input_with_icon %}
    {{ form_input('Email', 'email', 'formData.email', type='email', required=true) }}
    {{ form_select('Status', 'formData.status', [{'value': 'active', 'label': 'Active'}]) }}
    {{ form_textarea('Description', 'formData.description', rows=4) }}
    {{ password_input('Password', 'formData.password', required=true) }}
    {{ input_with_icon('Search', 'query', 'search', icon='search', icon_position='left') }}
#}


{#
  Form Input
  ==========
  A text input field with label, validation, and error handling.

  Parameters:
    - label: Field label
    - name: Input name attribute
    - x_model: Alpine.js x-model binding
    - type: Input type (default: 'text')
    - placeholder: Placeholder text
    - required: Whether the field is required (default: false)
    - disabled: Alpine.js expression for disabled state
    - error: Alpine.js expression for error message
    - help: Help text shown below the input
    - maxlength: Maximum length
    - min: Minimum value (for number inputs)
    - max: Maximum value (for number inputs)
    - step: Step value (for number inputs)
    - autocomplete: Autocomplete attribute
    - class_extra: Additional CSS classes for the input
#}
{% macro form_input(label, name, x_model, type='text', placeholder='', required=false, disabled=none, error=none, help=none, maxlength=none, min=none, max=none, step=none, autocomplete=none, class_extra='') %}
<label class="block mb-4 text-sm">
    <span class="text-gray-700 dark:text-gray-400">
        {{ label }}{% if required %} <span class="text-red-600">*</span>{% endif %}
    </span>
    <input
        type="{{ type }}"
        name="{{ name }}"
        x-model="{{ x_model }}"
        {% if placeholder %}placeholder="{{ placeholder }}"{% endif %}
        {% if required %}required{% endif %}
        {% if maxlength %}maxlength="{{ maxlength }}"{% endif %}
        {% if min is not none %}min="{{ min }}"{% endif %}
        {% if max is not none %}max="{{ max }}"{% endif %}
        {% if step %}step="{{ step }}"{% endif %}
        {% if autocomplete %}autocomplete="{{ autocomplete }}"{% endif %}
        {% if disabled %}:disabled="{{ disabled }}"{% endif %}
        class="block w-full mt-1 text-sm dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray form-input {{ class_extra }}"
        {% if error %}:class="{ 'border-red-600 focus:border-red-400 focus:shadow-outline-red': {{ error }} }"{% endif %}
    >
    {% if error %}
    <span x-show="{{ error }}" class="text-xs text-red-600 dark:text-red-400 mt-1" x-text="{{ error }}"></span>
    {% endif %}
    {% if help %}
    <span class="text-xs text-gray-500 dark:text-gray-400 mt-1">{{ help }}</span>
    {% endif %}
</label>
{% endmacro %}


{#
  Form Select
  ===========
  A select dropdown with label and error handling.

  Parameters:
    - label: Field label
    - x_model: Alpine.js x-model binding
    - options: List of options [{'value': '', 'label': ''}] or Alpine.js expression
    - name: Input name attribute
    - required: Whether the field is required (default: false)
    - disabled: Alpine.js expression for disabled state
    - error: Alpine.js expression for error message
    - placeholder: First empty option text (default: 'Select...')
    - on_change: Alpine.js @change handler
#}
{% macro form_select(label, x_model, options=[], name='', required=false, disabled=none, error=none, placeholder='Select...', on_change=none) %}
<label class="block mb-4 text-sm">
    <span class="text-gray-700 dark:text-gray-400">
        {{ label }}{% if required %} <span class="text-red-600">*</span>{% endif %}
    </span>
    <select
        {% if name %}name="{{ name }}"{% endif %}
        x-model="{{ x_model }}"
        {% if required %}required{% endif %}
        {% if disabled %}:disabled="{{ disabled }}"{% endif %}
        {% if on_change %}@change="{{ on_change }}"{% endif %}
        class="block w-full mt-1 text-sm dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray form-select"
        {% if error %}:class="{ 'border-red-600 focus:border-red-400 focus:shadow-outline-red': {{ error }} }"{% endif %}
    >
        {% if placeholder %}
        <option value="">{{ placeholder }}</option>
        {% endif %}
        {% for option in options %}
        <option value="{{ option.value }}">{{ option.label }}</option>
        {% endfor %}
    </select>
    {% if error %}
    <span x-show="{{ error }}" class="text-xs text-red-600 dark:text-red-400 mt-1" x-text="{{ error }}"></span>
    {% endif %}
</label>
{% endmacro %}


{#
  Form Select (Dynamic Options)
  =============================
  A select dropdown with options from Alpine.js.

  Parameters:
    - label: Field label
    - x_model: Alpine.js x-model binding
    - options_var: Alpine.js variable containing options array
    - value_key: Key for option value (default: 'value')
    - label_key: Key for option label (default: 'label')
    - ... (other params same as form_select)
#}
{% macro form_select_dynamic(label, x_model, options_var, value_key='value', label_key='label', name='', required=false, disabled=none, error=none, placeholder='Select...', on_change=none) %}
<label class="block mb-4 text-sm">
    <span class="text-gray-700 dark:text-gray-400">
        {{ label }}{% if required %} <span class="text-red-600">*</span>{% endif %}
    </span>
    <select
        {% if name %}name="{{ name }}"{% endif %}
        x-model="{{ x_model }}"
        {% if required %}required{% endif %}
        {% if disabled %}:disabled="{{ disabled }}"{% endif %}
        {% if on_change %}@change="{{ on_change }}"{% endif %}
        class="block w-full mt-1 text-sm dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray form-select"
        {% if error %}:class="{ 'border-red-600 focus:border-red-400 focus:shadow-outline-red': {{ error }} }"{% endif %}
    >
        {% if placeholder %}
        <option value="">{{ placeholder }}</option>
        {% endif %}
        <template x-for="option in {{ options_var }}" :key="option.{{ value_key }}">
            <option :value="option.{{ value_key }}" x-text="option.{{ label_key }}"></option>
        </template>
    </select>
    {% if error %}
    <span x-show="{{ error }}" class="text-xs text-red-600 dark:text-red-400 mt-1" x-text="{{ error }}"></span>
    {% endif %}
</label>
{% endmacro %}


{#
  Form Textarea
  =============
  A textarea field with label and error handling.

  Parameters:
    - label: Field label
    - x_model: Alpine.js x-model binding
    - name: Input name attribute
    - rows: Number of rows (default: 3)
    - placeholder: Placeholder text
    - required: Whether the field is required (default: false)
    - disabled: Alpine.js expression for disabled state
    - error: Alpine.js expression for error message
    - maxlength: Maximum length
#}
{% macro form_textarea(label, x_model, name='', rows=3, placeholder='', required=false, disabled=none, error=none, maxlength=none) %}
<label class="block mb-4 text-sm">
    <span class="text-gray-700 dark:text-gray-400">
        {{ label }}{% if required %} <span class="text-red-600">*</span>{% endif %}
    </span>
    <textarea
        {% if name %}name="{{ name }}"{% endif %}
        x-model="{{ x_model }}"
        rows="{{ rows }}"
        {% if placeholder %}placeholder="{{ placeholder }}"{% endif %}
        {% if required %}required{% endif %}
        {% if maxlength %}maxlength="{{ maxlength }}"{% endif %}
        {% if disabled %}:disabled="{{ disabled }}"{% endif %}
        class="block w-full mt-1 text-sm dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray form-textarea"
        {% if error %}:class="{ 'border-red-600 focus:border-red-400 focus:shadow-outline-red': {{ error }} }"{% endif %}
    ></textarea>
    {% if error %}
    <span x-show="{{ error }}" class="text-xs text-red-600 dark:text-red-400 mt-1" x-text="{{ error }}"></span>
    {% endif %}
</label>
{% endmacro %}


{#
  Form Checkbox
  =============
  A checkbox input with label.

  Parameters:
    - label: Checkbox label
    - x_model: Alpine.js x-model binding
    - name: Input name attribute
    - disabled: Alpine.js expression for disabled state
    - help: Help text shown below
#}
{% macro form_checkbox(label, x_model, name='', disabled=none, help=none) %}
<label class="flex items-center mb-4 text-sm">
    <input
        type="checkbox"
        {% if name %}name="{{ name }}"{% endif %}
        x-model="{{ x_model }}"
        {% if disabled %}:disabled="{{ disabled }}"{% endif %}
        class="form-checkbox h-4 w-4 text-purple-600 dark:bg-gray-700 dark:border-gray-600 focus:ring-purple-500 dark:focus:ring-purple-600"
    >
    <span class="ml-2 text-gray-700 dark:text-gray-400">{{ label }}</span>
</label>
{% if help %}
<span class="text-xs text-gray-500 dark:text-gray-400 -mt-2 mb-4 block ml-6">{{ help }}</span>
{% endif %}
{% endmacro %}


{#
  Form Toggle Switch
  ==================
  A toggle switch (styled checkbox).

  Parameters:
    - label: Toggle label
    - x_model: Alpine.js x-model binding
    - disabled: Alpine.js expression for disabled state
#}
{% macro form_toggle(label, x_model, disabled=none) %}
<div class="flex items-center mb-4">
    <button
        type="button"
        @click="{{ x_model }} = !{{ x_model }}"
        {% if disabled %}:disabled="{{ disabled }}"{% endif %}
        class="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
        :class="{{ x_model }} ? 'bg-purple-600' : 'bg-gray-200 dark:bg-gray-700'"
        role="switch"
        :aria-checked="{{ x_model }}"
    >
        <span
            class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
            :class="{{ x_model }} ? 'translate-x-5' : 'translate-x-0'"
        ></span>
    </button>
    <span class="ml-3 text-sm text-gray-700 dark:text-gray-400">{{ label }}</span>
</div>
{% endmacro %}


{#
  Form Radio Group
  ================
  A group of radio buttons.

  Parameters:
    - label: Group label
    - name: Radio group name
    - x_model: Alpine.js x-model binding
    - options: List of options [{'value': '', 'label': ''}]
    - inline: Whether to display inline (default: false)
#}
{% macro form_radio_group(label, name, x_model, options=[], inline=false) %}
<div class="mb-4">
    <span class="block text-sm text-gray-700 dark:text-gray-400 mb-2">{{ label }}</span>
    <div class="{{ 'flex flex-wrap gap-4' if inline else 'space-y-2' }}">
        {% for option in options %}
        <label class="flex items-center text-sm">
            <input
                type="radio"
                name="{{ name }}"
                value="{{ option.value }}"
                x-model="{{ x_model }}"
                class="form-radio h-4 w-4 text-purple-600 dark:bg-gray-700 dark:border-gray-600 focus:ring-purple-500"
            >
            <span class="ml-2 text-gray-700 dark:text-gray-400">{{ option.label }}</span>
        </label>
        {% endfor %}
    </div>
</div>
{% endmacro %}


{#
  Search Input
  ============
  A search input with icon.

  Parameters:
    - x_model: Alpine.js x-model binding
    - placeholder: Placeholder text (default: 'Search...')
    - on_input: Alpine.js @input handler (e.g., 'debouncedSearch()')
    - class_extra: Additional CSS classes
#}
{% macro search_input(x_model, placeholder='Search...', on_input=none, class_extra='') %}
<div class="relative {{ class_extra }}">
    <span class="absolute inset-y-0 left-0 flex items-center pl-3">
        <span x-html="$icon('search', 'w-5 h-5 text-gray-400')"></span>
    </span>
    <input
        type="text"
        x-model="{{ x_model }}"
        {% if on_input %}@input="{{ on_input }}"{% endif %}
        placeholder="{{ placeholder }}"
        class="w-full pl-10 pr-4 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg focus:border-purple-400 focus:outline-none dark:bg-gray-700 dark:text-gray-300"
    >
</div>
{% endmacro %}


{#
  Filter Select
  =============
  A compact select for filtering (no label, inline style).

  Parameters:
    - x_model: Alpine.js x-model binding
    - options: List of options [{'value': '', 'label': ''}]
    - on_change: Alpine.js @change handler
    - placeholder: First option text (default: 'All')
#}
{% macro filter_select(x_model, options=[], on_change=none, placeholder='All') %}
<select
    x-model="{{ x_model }}"
    {% if on_change %}@change="{{ on_change }}"{% endif %}
    class="px-4 py-2 text-sm text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg focus:border-purple-400 focus:outline-none"
>
    <option value="">{{ placeholder }}</option>
    {% for option in options %}
    <option value="{{ option.value }}">{{ option.label }}</option>
    {% endfor %}
</select>
{% endmacro %}


{#
  Password Input
  ==============
  A password input with show/hide toggle.

  Parameters:
    - label: Field label
    - x_model: Alpine.js x-model binding
    - name: Input name attribute
    - placeholder: Placeholder text (default: 'Enter password')
    - required: Whether the field is required (default: false)
    - disabled: Alpine.js expression for disabled state
    - error: Alpine.js expression for error message
    - help: Help text shown below the input
    - minlength: Minimum password length
    - autocomplete: Autocomplete attribute (default: 'current-password')
    - show_strength: Whether to show password strength indicator (default: false)
#}
{% macro password_input(label, x_model, name='password', placeholder='Enter password', required=false, disabled=none, error=none, help=none, minlength=none, autocomplete='current-password', show_strength=false) %}
<div x-data="{ showPassword: false }" class="mb-4">
    <label class="block text-sm">
        <span class="text-gray-700 dark:text-gray-400">
            {{ label }}{% if required %} <span class="text-red-600">*</span>{% endif %}
        </span>
        <div class="relative mt-1">
            <input
                :type="showPassword ? 'text' : 'password'"
                name="{{ name }}"
                x-model="{{ x_model }}"
                placeholder="{{ placeholder }}"
                {% if required %}required{% endif %}
                {% if minlength %}minlength="{{ minlength }}"{% endif %}
                autocomplete="{{ autocomplete }}"
                {% if disabled %}:disabled="{{ disabled }}"{% endif %}
                class="block w-full pr-10 text-sm dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray form-input"
                {% if error %}:class="{ 'border-red-600 focus:border-red-400 focus:shadow-outline-red': {{ error }} }"{% endif %}
            >
            <button
                type="button"
                @click="showPassword = !showPassword"
                class="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 focus:outline-none"
            >
                <template x-if="!showPassword">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
                    </svg>
                </template>
                <template x-if="showPassword">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"/>
                    </svg>
                </template>
            </button>
        </div>
        {% if error %}
        <span x-show="{{ error }}" class="text-xs text-red-600 dark:text-red-400 mt-1" x-text="{{ error }}"></span>
        {% endif %}
        {% if help %}
        <span class="text-xs text-gray-500 dark:text-gray-400 mt-1">{{ help }}</span>
        {% endif %}
    </label>
    {% if show_strength %}
    <div class="mt-2">
        <div class="flex gap-1">
            <div class="h-1 flex-1 rounded-full bg-gray-200 dark:bg-gray-700"
                 :class="{
                     'bg-red-500': {{ x_model }}.length > 0 && {{ x_model }}.length < 6,
                     'bg-yellow-500': {{ x_model }}.length >= 6 && {{ x_model }}.length < 10,
                     'bg-green-500': {{ x_model }}.length >= 10
                 }"></div>
            <div class="h-1 flex-1 rounded-full bg-gray-200 dark:bg-gray-700"
                 :class="{
                     'bg-yellow-500': {{ x_model }}.length >= 6 && {{ x_model }}.length < 10,
                     'bg-green-500': {{ x_model }}.length >= 10
                 }"></div>
            <div class="h-1 flex-1 rounded-full bg-gray-200 dark:bg-gray-700"
                 :class="{ 'bg-green-500': {{ x_model }}.length >= 10 }"></div>
        </div>
        <p class="text-xs text-gray-500 dark:text-gray-400 mt-1"
           x-text="{{ x_model }}.length < 6 ? 'Weak' : ({{ x_model }}.length < 10 ? 'Medium' : 'Strong')"></p>
    </div>
    {% endif %}
</div>
{% endmacro %}


{#
  Input with Icon
  ===============
  A text input with an icon on the left or right.

  Parameters:
    - label: Field label
    - x_model: Alpine.js x-model binding
    - name: Input name attribute
    - icon: Icon name (uses $icon helper)
    - icon_position: 'left' | 'right' (default: 'left')
    - type: Input type (default: 'text')
    - placeholder: Placeholder text
    - required: Whether the field is required
    - disabled: Alpine.js expression for disabled state
    - error: Alpine.js expression for error message
    - on_click_icon: Alpine.js handler when icon is clicked (makes icon a button)
#}
{% macro input_with_icon(label, x_model, name, icon, icon_position='left', type='text', placeholder='', required=false, disabled=none, error=none, on_click_icon=none) %}
<label class="block mb-4 text-sm">
    <span class="text-gray-700 dark:text-gray-400">
        {{ label }}{% if required %} <span class="text-red-600">*</span>{% endif %}
    </span>
    <div class="relative mt-1">
        {% if icon_position == 'left' %}
        {% if on_click_icon %}
        <button
            type="button"
            @click="{{ on_click_icon }}"
            class="absolute inset-y-0 left-0 flex items-center pl-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 focus:outline-none"
        >
            <span x-html="$icon('{{ icon }}', 'w-5 h-5')"></span>
        </button>
        {% else %}
        <span class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
            <span x-html="$icon('{{ icon }}', 'w-5 h-5 text-gray-400')"></span>
        </span>
        {% endif %}
        {% endif %}
        <input
            type="{{ type }}"
            name="{{ name }}"
            x-model="{{ x_model }}"
            {% if placeholder %}placeholder="{{ placeholder }}"{% endif %}
            {% if required %}required{% endif %}
            {% if disabled %}:disabled="{{ disabled }}"{% endif %}
            class="block w-full text-sm dark:text-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray form-input {{ 'pl-10' if icon_position == 'left' else 'pr-10' }}"
            {% if error %}:class="{ 'border-red-600 focus:border-red-400 focus:shadow-outline-red': {{ error }} }"{% endif %}
        >
        {% if icon_position == 'right' %}
        {% if on_click_icon %}
        <button
            type="button"
            @click="{{ on_click_icon }}"
            class="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 focus:outline-none"
        >
            <span x-html="$icon('{{ icon }}', 'w-5 h-5')"></span>
        </button>
        {% else %}
        <span class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
            <span x-html="$icon('{{ icon }}', 'w-5 h-5 text-gray-400')"></span>
        </span>
        {% endif %}
        {% endif %}
    </div>
    {% if error %}
    <span x-show="{{ error }}" class="text-xs text-red-600 dark:text-red-400 mt-1" x-text="{{ error }}"></span>
    {% endif %}
</label>
{% endmacro %}


{#
  File Input
  ==========
  A styled file input with drag and drop support.

  Parameters:
    - label: Field label
    - name: Input name attribute
    - accept: Accepted file types (e.g., 'image/*', '.pdf,.doc')
    - multiple: Allow multiple files (default: false)
    - max_size: Maximum file size in MB (for display only)
    - on_change: Alpine.js handler when files are selected
    - help: Help text
#}
{% macro file_input(label, name, accept='*', multiple=false, max_size=none, on_change=none, help=none) %}
<div class="mb-4">
    <label class="block text-sm font-medium text-gray-700 dark:text-gray-400 mb-1.5">
        {{ label }}
    </label>
    <div
        x-data="{ isDragging: false, files: [] }"
        @dragover.prevent="isDragging = true"
        @dragleave.prevent="isDragging = false"
        @drop.prevent="isDragging = false; files = $event.dataTransfer.files; {% if on_change %}{{ on_change }}{% endif %}"
        class="relative border-2 border-dashed rounded-lg p-6 text-center transition-colors"
        :class="isDragging ? 'border-purple-500 bg-purple-50 dark:bg-purple-900/10' : 'border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500'"
    >
        <input
            type="file"
            name="{{ name }}"
            accept="{{ accept }}"
            {% if multiple %}multiple{% endif %}
            @change="files = $event.target.files; {% if on_change %}{{ on_change }}{% endif %}"
            class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
        >
        <div class="space-y-2">
            <svg class="mx-auto w-10 h-10 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
            </svg>
            <p class="text-sm text-gray-600 dark:text-gray-400">
                <span class="font-medium text-purple-600 dark:text-purple-400">Click to upload</span> or drag and drop
            </p>
            {% if help %}
            <p class="text-xs text-gray-500 dark:text-gray-400">{{ help }}</p>
            {% elif max_size %}
            <p class="text-xs text-gray-500 dark:text-gray-400">Max file size: {{ max_size }}MB</p>
            {% endif %}
        </div>
    </div>
</div>
{% endmacro %}


{#
  Searchable Select
  =================
  A select dropdown with search/filter functionality.

  Parameters:
    - label: Field label
    - x_model: Alpine.js x-model binding for selected value
    - options_var: Alpine.js variable containing options array
    - value_key: Key for option value (default: 'value')
    - label_key: Key for option label (default: 'label')
    - search_var: Alpine.js variable for search query (default: 'searchQuery')
    - open_var: Alpine.js variable for dropdown open state (default: 'isOpen')
    - placeholder: Placeholder text (default: 'Select...')
    - search_placeholder: Search input placeholder (default: 'Search...')
    - required: Whether the field is required
    - disabled: Alpine.js expression for disabled state
    - no_results_text: Text shown when no results (default: 'No results found')

  Usage:
    <div x-data="{
        selected: '',
        selectedLabel: '',
        searchQuery: '',
        isOpen: false,
        options: [
            { id: '1', name: 'Option 1' },
            { id: '2', name: 'Option 2' }
        ],
        get filteredOptions() {
            if (!this.searchQuery) return this.options;
            return this.options.filter(o => o.name.toLowerCase().includes(this.searchQuery.toLowerCase()));
        },
        selectOption(option) {
            this.selected = option.id;
            this.selectedLabel = option.name;
            this.isOpen = false;
            this.searchQuery = '';
        }
    }">
        {{ searchable_select('Category', 'selected', 'filteredOptions', value_key='id', label_key='name') }}
    </div>
#}
{% macro searchable_select(label, x_model, options_var, value_key='value', label_key='label', search_var='searchQuery', open_var='isOpen', placeholder='Select...', search_placeholder='Search...', required=false, disabled=none, no_results_text='No results found') %}
<div class="mb-4">
    <label class="block text-sm">
        <span class="text-gray-700 dark:text-gray-400">
            {{ label }}{% if required %} <span class="text-red-600">*</span>{% endif %}
        </span>
        <div class="relative mt-1">
            {# Selected value display / trigger button #}
            <button
                type="button"
                @click="{{ open_var }} = !{{ open_var }}"
                @click.outside="{{ open_var }} = false"
                {% if disabled %}:disabled="{{ disabled }}"{% endif %}
                class="flex items-center justify-between w-full px-4 py-2 text-sm text-left bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg hover:border-gray-400 dark:hover:border-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                :class="{ 'ring-2 ring-purple-500 border-transparent': {{ open_var }} }"
            >
                <span
                    :class="!{{ x_model }} ? 'text-gray-400' : 'text-gray-700 dark:text-gray-300'"
                    x-text="selectedLabel || '{{ placeholder }}'"
                >{{ placeholder }}</span>
                <svg
                    class="w-4 h-4 ml-2 text-gray-400 transition-transform"
                    :class="{ 'rotate-180': {{ open_var }} }"
                    fill="none" stroke="currentColor" viewBox="0 0 24 24"
                >
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
                </svg>
            </button>

            {# Dropdown panel #}
            <div
                x-show="{{ open_var }}"
                x-transition:enter="transition ease-out duration-100"
                x-transition:enter-start="transform opacity-0 scale-95"
                x-transition:enter-end="transform opacity-100 scale-100"
                x-transition:leave="transition ease-in duration-75"
                x-transition:leave-start="transform opacity-100 scale-100"
                x-transition:leave-end="transform opacity-0 scale-95"
                class="absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 overflow-hidden"
            >
                {# Search input #}
                <div class="p-2 border-b border-gray-200 dark:border-gray-700">
                    <div class="relative">
                        <span class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
                            <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
                            </svg>
                        </span>
                        <input
                            type="text"
                            x-model="{{ search_var }}"
                            @click.stop
                            placeholder="{{ search_placeholder }}"
                            class="w-full pl-9 pr-4 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-md focus:border-purple-500 focus:ring-1 focus:ring-purple-500 dark:bg-gray-700 dark:text-gray-300"
                        >
                    </div>
                </div>

                {# Options list #}
                <ul class="max-h-60 overflow-y-auto py-1">
                    <template x-for="option in {{ options_var }}" :key="option.{{ value_key }}">
                        <li>
                            <button
                                type="button"
                                @click="selectOption(option)"
                                class="flex items-center justify-between w-full px-4 py-2 text-sm text-left transition-colors"
                                :class="{{ x_model }} === option.{{ value_key }}
                                    ? 'bg-purple-50 dark:bg-purple-900/20 text-purple-700 dark:text-purple-300'
                                    : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'"
                            >
                                <span x-text="option.{{ label_key }}"></span>
                                <svg
                                    x-show="{{ x_model }} === option.{{ value_key }}"
                                    class="w-4 h-4 text-purple-600"
                                    fill="none" stroke="currentColor" viewBox="0 0 24 24"
                                >
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
                                </svg>
                            </button>
                        </li>
                    </template>
                    <li x-show="{{ options_var }}.length === 0" class="px-4 py-3 text-sm text-center text-gray-500 dark:text-gray-400">
                        {{ no_results_text }}
                    </li>
                </ul>
            </div>
        </div>
    </label>
</div>
{% endmacro %}


{#
  Multi-Select with Tags
  ======================
  A multi-select dropdown that shows selected items as tags.

  Parameters:
    - label: Field label
    - selected_var: Alpine.js variable for selected values array
    - options_var: Alpine.js variable containing options array
    - value_key: Key for option value (default: 'value')
    - label_key: Key for option label (default: 'label')
    - placeholder: Placeholder text (default: 'Select items...')
    - max_items: Maximum number of items (optional)

  Required Alpine.js methods:
    toggleOption(option) - Add/remove option from selection
    removeOption(value) - Remove option by value
    isSelected(value) - Check if option is selected
    getLabel(value) - Get label for a value
#}
{% macro multi_select(label, selected_var, options_var, value_key='value', label_key='label', placeholder='Select items...', max_items=none) %}
<div x-data="{ isOpen: false }" class="mb-4">
    <label class="block text-sm">
        <span class="text-gray-700 dark:text-gray-400">{{ label }}</span>
        <div class="relative mt-1">
            {# Selected tags display / trigger #}
            <div
                @click="isOpen = !isOpen"
                @click.outside="isOpen = false"
                class="min-h-[42px] px-3 py-2 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg cursor-pointer hover:border-gray-400 dark:hover:border-gray-500 focus:outline-none"
                :class="{ 'ring-2 ring-purple-500 border-transparent': isOpen }"
            >
                <div class="flex flex-wrap gap-1">
                    <template x-for="value in {{ selected_var }}" :key="value">
                        <span class="inline-flex items-center px-2 py-1 text-xs font-medium text-purple-700 bg-purple-100 rounded-full dark:bg-purple-900/30 dark:text-purple-300">
                            <span x-text="getLabel(value)"></span>
                            <button
                                type="button"
                                @click.stop="removeOption(value)"
                                class="ml-1 hover:text-purple-900 dark:hover:text-purple-100"
                            >
                                <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                                </svg>
                            </button>
                        </span>
                    </template>
                    <span x-show="{{ selected_var }}.length === 0" class="text-gray-400 text-sm py-0.5">{{ placeholder }}</span>
                </div>
            </div>

            {# Dropdown #}
            <div
                x-show="isOpen"
                x-transition
                class="absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-h-60 overflow-y-auto"
            >
                <template x-for="option in {{ options_var }}" :key="option.{{ value_key }}">
                    <button
                        type="button"
                        @click="toggleOption(option)"
                        {% if max_items %}:disabled="{{ selected_var }}.length >= {{ max_items }} && !isSelected(option.{{ value_key }})"{% endif %}
                        class="flex items-center justify-between w-full px-4 py-2 text-sm text-left transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                        :class="isSelected(option.{{ value_key }})
                            ? 'bg-purple-50 dark:bg-purple-900/20 text-purple-700 dark:text-purple-300'
                            : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'"
                    >
                        <span x-text="option.{{ label_key }}"></span>
                        <svg
                            x-show="isSelected(option.{{ value_key }})"
                            class="w-4 h-4 text-purple-600"
                            fill="none" stroke="currentColor" viewBox="0 0 24 24"
                        >
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
                        </svg>
                    </button>
                </template>
            </div>
        </div>
    </label>
    {% if max_items %}
    <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
        <span x-text="{{ selected_var }}.length"></span> / {{ max_items }} selected
    </p>
    {% endif %}
</div>
{% endmacro %}
