<section>
  {% set step_index = 1 %}{% set step_total = 5 %}
  <h3>Step 1: Choose a Commander</h3>
  {% include "build/_stage_navigator.html" %}

  <form id="cmdr-search-form" hx-post="/build/step1" hx-target="#wizard" hx-swap="innerHTML" aria-label="Commander search form" role="search">
    <label for="cmdr-search">Search by name</label>
  <span class="input-wrap">
    <input id="cmdr-search" type="text" name="query" value="{{ query or '' }}" autocomplete="off" aria-describedby="cmdr-help" aria-controls="candidate-grid" placeholder="Type a commander name…" />
    <button id="cmdr-clear" type="button" class="clear-btn" title="Clear search" aria-label="Clear search" hidden>×</button>
  </span>
    <input id="active-name" type="hidden" name="active" value="{{ active or '' }}" />
    <button type="submit">Search</button>
    <label style="margin-left:.5rem; font-weight:normal;">
      <input type="checkbox" name="auto" value="1" {% if auto %}checked{% endif %} /> Auto-select top match (very confident)
    </label>
  <span id="search-spinner" class="spinner" aria-hidden="true" hidden style="display:none;"></span>
  </form>
  <div id="cmdr-help" class="muted" style="margin:.35rem 0 .5rem 0; font-size:.9rem;">
    Tip: Press Enter to select the highlighted result, or use arrow keys to navigate. If your query is a full first word (e.g., "vivi"), exact first-word matches are prioritized.
  </div>
  <div id="selection-live" class="sr-only" aria-live="polite" role="status"></div>
  <div id="results-live" class="sr-only" aria-live="polite" role="status"></div>
  <div id="kbd-hint" class="hint" hidden>
    <span class="hint-text">Use 
      <span class="keys"><kbd>↑</kbd><kbd>↓</kbd></span> to navigate, <kbd>Enter</kbd> to select
    </span>
    <button type="button" class="hint-close" title="Dismiss keyboard hint" aria-label="Dismiss">×</button>
  </div>

  {% if candidates %}
  <h4 style="display:flex; align-items:center; gap:.5rem;">
    Top matches
    <small class="muted" aria-live="polite">{% if count is defined %}{{ count }} result{% if count != 1 %}s{% endif %}{% else %}{{ (candidates|length) if candidates else 0 }} results{% endif %}</small>
  </h4>
  <div class="candidate-grid" id="candidate-grid" role="list">
    {% for name, score, colors in candidates %}
      <div class="candidate-tile{% if active and active == name %} active{% endif %}" data-card-name="{{ name }}" role="listitem" aria-selected="{% if active and active == name %}true{% else %}false{% endif %}">
        <form hx-post="/build/step1/confirm" hx-target="#wizard" hx-swap="innerHTML">
          <input type="hidden" name="name" value="{{ name }}" />
          <button class="img-btn" type="submit" title="Select {{ name }} (score {{ score }})">
            <img src="https://api.scryfall.com/cards/named?fuzzy={{ name|urlencode }}&format=image&version=normal" data-card-name="{{ name }}"
                 alt="{{ name }}" loading="lazy" decoding="async" />
          </button>
        </form>
        <div class="meta">
          <div class="name"><span class="name-text">{{ name }}</span></div>
          <div class="score">
            match {{ score }}%
            {% if colors %}
              <span class="colors" style="margin-left:.25rem;">
                {% for c in colors %}
                  <span class="chip chip-{{ c|lower }}" title="{{ c }}">{{ c }}</span>
                {% endfor %}
              </span>
            {% endif %}
          </div>
          <form hx-post="/build/step1/inspect" hx-target="#wizard" hx-swap="innerHTML" style="margin-top:.25rem;">
            <input type="hidden" name="name" value="{{ name }}" />
            <button type="submit">Inspect</button>
          </form>
        </div>
      </div>
    {% endfor %}
  </div>
  {% endif %}

  {% if (query is defined and query and (not candidates or (candidates|length == 0))) and not inspect %}
    <div id="candidate-grid" class="muted" style="margin-top:.5rem;" aria-live="polite">
      No results for “{{ query }}”. Try a shorter name or a different spelling.
    </div>
  {% endif %}

  {% if inspect and inspect.ok %}
  <div class="two-col two-col-left-rail">
  <aside class="card-preview card-sm" data-card-name="{{ selected }}">
    {# Strip synergy annotation for Scryfall search and image fuzzy param #}
    {% set sel_base = (selected.split(' - Synergy (')[0] if ' - Synergy (' in selected else selected) %}
    <a href="https://scryfall.com/search?q={{ sel_base|urlencode }}" target="_blank" rel="noopener">
  <img src="https://api.scryfall.com/cards/named?fuzzy={{ sel_base|urlencode }}&format=image&version=normal" alt="{{ selected }} card image" data-card-name="{{ sel_base }}" />
      </a>
    </aside>
    <div class="grow">
      <h4>Theme Tags</h4>
      {% if tags and tags|length > 0 %}
        <ul>
          {% for t in tags %}
            <li>{{ t }}</li>
          {% endfor %}
        </ul>
      {% else %}
        <p class="muted">No theme tags found for this commander.</p>
      {% endif %}
      <div style="margin-top:.75rem;">
        <form style="display:inline" hx-post="/build/step1/confirm" hx-target="#wizard" hx-swap="innerHTML">
          <input type="hidden" name="name" value="{{ selected }}" />
          <button class="btn-continue" data-action="continue">Use this commander</button>
        </form>
        <form style="display:inline" hx-post="/build/step1" hx-target="#wizard" hx-swap="innerHTML">
          <input type="hidden" name="query" value="" />
          <button class="btn-back" data-action="back">Back to search</button>
        </form>
        <form action="/build" method="get" style="display:inline; margin-left:.5rem;">
          <button type="submit">Start over</button>
        </form>
      </div>
  <div hx-get="/build/banner?step=Choose%20Commander&i=1&n=5" hx-trigger="load"></div>
    </div>
  </div>
  {% elif inspect and not inspect.ok %}
    <div style="color:#a00">{{ inspect.error }}</div>
  {% endif %}

  {% if error %}
  <div style="color:#a00">{{ error }}</div>
  {% endif %}
</section>
<script>
(function(){
  var input = document.getElementById('cmdr-search');
  var form = document.getElementById('cmdr-search-form');
  var grid = document.getElementById('candidate-grid');
  var spinner = document.getElementById('search-spinner');
  var activeField = document.getElementById('active-name');
  var selLive = document.getElementById('selection-live');
  var resultsLive = document.getElementById('results-live');
  var hint = document.getElementById('kbd-hint');
  var defaultPlaceholder = (input && input.placeholder) ? input.placeholder : 'Type a commander name…';
  var clearBtn = document.getElementById('cmdr-clear');
  var initialDescribedBy = (input && input.getAttribute('aria-describedby')) || '';
  // Persist auto-select preference
  try {
    var autoCb = document.querySelector('input[name="auto"][type="checkbox"]');
    if (autoCb) {
      var saved = localStorage.getItem('step1-auto');
      if (saved === '1' || saved === '0') autoCb.checked = (saved === '1');
      autoCb.addEventListener('change', function(){ localStorage.setItem('step1-auto', autoCb.checked ? '1' : '0'); });
    }
  } catch(_){ }
  if (!input || !form) return;
  // Show keyboard hint only when candidates exist and user hasn't dismissed it
  function showHintIfNeeded() {
    try {
      if (!hint) return;
      var dismissed = localStorage.getItem('step1-hint-dismissed') === '1';
      var hasTiles = !!(document.getElementById('candidate-grid') && document.getElementById('candidate-grid').querySelector('.candidate-tile'));
      var shouldShow = !(dismissed || !hasTiles);
      hint.hidden = !shouldShow;
      // Link hint to input a11y description only when visible
      if (input) {
        var base = initialDescribedBy.trim();
        var parts = base ? base.split(/\s+/) : [];
        var idx = parts.indexOf('kbd-hint');
        if (shouldShow) {
          if (idx === -1) parts.push('kbd-hint');
        } else {
          if (idx !== -1) parts.splice(idx, 1);
        }
        if (parts.length) input.setAttribute('aria-describedby', parts.join(' '));
        else input.removeAttribute('aria-describedby');
      }
    } catch(_) { /* noop */ }
  }
  showHintIfNeeded();
  // Close button for hint
  try {
    var closeBtn = hint ? hint.querySelector('.hint-close') : null;
    if (closeBtn) {
      closeBtn.addEventListener('click', function(){
        try { localStorage.setItem('step1-hint-dismissed', '1'); } catch(_){}
        if (hint) hint.hidden = true;
      });
    }
  } catch(_){ }
  // Debounce live search
  var t = null;
  function submit(){
    if (!form) return;
    // Trigger the HTMX post without clicking submit
    if (window.htmx) { window.htmx.trigger(form, 'submit'); }
    else { form.submit(); }
  }
  input.addEventListener('input', function(){
    if (t) clearTimeout(t);
    t = setTimeout(submit, 250);
    try { if (clearBtn) clearBtn.hidden = !(input && input.value && input.value.length); } catch(_){ }
  });
  // Initialize clear visibility
  try { if (clearBtn) clearBtn.hidden = !(input && input.value && input.value.length); } catch(_){ }
  if (clearBtn) clearBtn.addEventListener('click', function(){
    if (!input) return;
    input.value = '';
    try { clearBtn.hidden = true; } catch(_){ }
    if (t) clearTimeout(t);
    t = setTimeout(submit, 0);
    try { input.focus(); } catch(_){}
  });
  // Focus the search box on load if nothing else is focused
  try {
    var ae = document.activeElement;
    if (input && (!ae || ae === document.body)) { input.focus(); input.select && input.select(); }
  } catch(_){}
  // Quick focus: press "/" to focus the search input (unless already typing)
  document.addEventListener('keydown', function(e){
    if (e.key !== '/') return;
    var tag = (e.target && e.target.tagName) ? e.target.tagName.toLowerCase() : '';
    var isEditable = (tag === 'input' || tag === 'textarea' || tag === 'select' || (e.target && e.target.isContentEditable));
    if (isEditable) return;
    if (e.ctrlKey || e.altKey || e.metaKey) return;
    e.preventDefault();
    if (input) { input.focus(); try { input.select(); } catch(_){} }
  });
  // Keyboard navigation: up/down to move selection, Enter to choose/inspect
  document.addEventListener('keydown', function(e){
    // Dismiss hint on first keyboard navigation
    if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'ArrowLeft' || e.key === 'ArrowRight' || e.key === 'Enter') {
      try { localStorage.setItem('step1-hint-dismissed', '1'); } catch(_){}
      if (hint) hint.hidden = true;
    }
    if (!grid || !grid.children || grid.children.length === 0) return;
    var tiles = Array.prototype.slice.call(grid.querySelectorAll('.candidate-tile'));
    // Ensure something is selected by default
    var idx = tiles.findIndex(function(el){ return el.classList.contains('active'); });
    if (idx < 0 && tiles.length > 0) {
      tiles[0].classList.add('active');
      try { if (activeField) activeField.value = tiles[0].dataset.cardName || ''; } catch(_){}
  try { if (selLive) selLive.textContent = 'Selected ' + (tiles[0].dataset.cardName || ''); } catch(_){}
      idx = 0;
    }

    // Determine columns via first row's offsetTop count
    var cols = 1;
    if (tiles.length > 1) {
      var firstTop = tiles[0].offsetTop;
      cols = tiles.findIndex(function(el, i){ return i>0 && el.offsetTop !== firstTop; });
      if (cols === -1 || cols === 0) cols = tiles.length; // single row fallback
    }

    function setActive(newIdx) {
      // Clamp to bounds; wrapping handled by callers
      newIdx = Math.max(0, Math.min(tiles.length - 1, newIdx));
      tiles.forEach(function(el){ el.classList.remove('active'); el.setAttribute('aria-selected', 'false'); });
  tiles[newIdx].classList.add('active');
  tiles[newIdx].setAttribute('aria-selected', 'true');
  try { if (activeField) activeField.value = tiles[newIdx].dataset.cardName || ''; } catch(_){}
  try { if (selLive) selLive.textContent = 'Selected ' + (tiles[newIdx].dataset.cardName || ''); } catch(_){}
      tiles[newIdx].scrollIntoView({ block: 'nearest', inline: 'nearest' });
      return newIdx;
    }

    if (e.key === 'ArrowDown') {
      e.preventDefault();
      var total = tiles.length;
      var rows = Math.ceil(total / cols);
      var row = Math.floor(idx / cols);
      var col = idx % cols;
      var newRow = row + 1;
      if (newRow >= rows) newRow = 0; // wrap to first row
      var newIdx = newRow * cols + col;
      if (newIdx >= total) newIdx = total - 1; // clamp to last tile if last row shorter
      idx = setActive(newIdx);
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      var totalU = tiles.length;
      var rowsU = Math.ceil(totalU / cols);
      var rowU = Math.floor(idx / cols);
      var colU = idx % cols;
      var newRowU = rowU - 1;
      if (newRowU < 0) newRowU = rowsU - 1; // wrap to last row
      var newIdxU = newRowU * cols + colU;
      if (newIdxU >= totalU) newIdxU = totalU - 1;
      idx = setActive(newIdxU);
    } else if (e.key === 'ArrowRight') {
      e.preventDefault();
      var totalR = tiles.length;
      idx = setActive((idx + 1) % totalR);
    } else if (e.key === 'ArrowLeft') {
      e.preventDefault();
      var totalL = tiles.length;
      idx = setActive((idx - 1 + totalL) % totalL);
    } else if (e.key === 'Enter') {
      e.preventDefault();
      var active = tiles[idx];
      if (!active) return;
      var formSel = active.querySelector('form[hx-post="/build/step1/confirm"]');
      if (formSel) {
        if (window.htmx) { window.htmx.trigger(formSel, 'submit'); }
        else if (formSel.submit) { formSel.submit(); }
        else {
          var btn = active.querySelector('button');
          if (btn) btn.click();
        }
      }
    } else if (e.key === 'Escape') {
      // ESC clears the search field and triggers a refresh
      if (input && input.value) {
        input.value = '';
        if (t) clearTimeout(t);
        t = setTimeout(submit, 0);
      }
    }
  });
  // Persist current active on click selection movement too
  if (grid) {
    grid.addEventListener('click', function(e){
  // Dismiss hint on interaction
  try { localStorage.setItem('step1-hint-dismissed', '1'); } catch(_){}
  if (hint) hint.hidden = true;
      var tile = e.target.closest('.candidate-tile');
      if (!tile) return;
  grid.querySelectorAll('.candidate-tile').forEach(function(el){ el.classList.remove('active'); el.setAttribute('aria-selected', 'false'); });
  tile.classList.add('active');
  tile.setAttribute('aria-selected', 'true');
      try { if (activeField) activeField.value = tile.dataset.cardName || ''; } catch(_){}
  try { if (selLive) selLive.textContent = 'Selected ' + (tile.dataset.cardName || ''); } catch(_){}
    });
  }
  // Highlight matched text
  try {
    var q = (input.value || '').trim().toLowerCase();
    if (q && grid) {
      grid.querySelectorAll('.name-text').forEach(function(el){
        var txt = el.textContent || '';
        var low = txt.toLowerCase();
        var i = low.indexOf(q);
        if (i >= 0) {
          el.innerHTML = txt.substring(0, i) + '<mark>' + txt.substring(i, i+q.length) + '</mark>' + txt.substring(i+q.length);
        }
      });
    }
  } catch(_){}
  // HTMX spinner binding for this form — only show if no results are currently displayed
  if (window.htmx && form) {
    form.addEventListener('htmx:beforeRequest', function(){
      var hasTiles = false;
      try { hasTiles = !!(grid && grid.querySelector('.candidate-tile')); } catch(_){}
      if (spinner) spinner.hidden = hasTiles ? true : false;
      if (!hasTiles && input) input.placeholder = 'Searching…';
      try { form.setAttribute('aria-busy', 'true'); } catch(_){ }
      if (resultsLive) resultsLive.textContent = 'Searching…';
    });
    form.addEventListener('htmx:afterSwap', function(){
      if (spinner) spinner.hidden = true; if (input) input.placeholder = defaultPlaceholder;
      // After swap, if there are no candidate tiles, clear active selection and live text
      try {
        var grid2 = document.getElementById('candidate-grid');
        var hasAny = !!(grid2 && grid2.querySelector('.candidate-tile'));
        if (!hasAny) {
          if (activeField) activeField.value = '';
          if (selLive) selLive.textContent = '';
        }
  // Re-evaluate hint visibility post-swap
  showHintIfNeeded();
        // Announce results count
        try {
          var qNow = (input && input.value) ? input.value.trim() : '';
          var cnt = 0;
          if (grid2) cnt = grid2.querySelectorAll('.candidate-tile').length;
          if (resultsLive) {
            if (cnt > 0) resultsLive.textContent = cnt + (cnt === 1 ? ' result' : ' results');
            else if (qNow) resultsLive.textContent = 'No results for "' + qNow + '"';
            else resultsLive.textContent = '';
          }
        } catch(_){ }
        try { form.removeAttribute('aria-busy'); } catch(_){ }
      } catch(_){ }
    });
    form.addEventListener('htmx:responseError', function(){ if (spinner) spinner.hidden = true; if (input) input.placeholder = defaultPlaceholder; });
  }
})();
</script>
<style>
.candidate-grid { display:grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap:.75rem; }
.candidate-tile { border:1px solid var(--border); border-radius:8px; background:#0f1115; padding:.5rem; }
.candidate-tile.active { outline:2px solid #3b82f6; }
.img-btn { display:block; width:100%; background:transparent; border:0; padding:0; cursor:pointer; }
.img-btn img { width:100%; height:auto; border-radius:6px; }
.chip { display:inline-block; padding:0 .35rem; border-radius:999px; font-size:.75rem; line-height:1.4; border:1px solid var(--border); background:#151821; margin-left:.15rem; }
.chip-w { background:#fdf4d6; color:#6b4f00; border-color:#e9d8a6; }
.chip-u { background:#dbeafe; color:#1e40af; border-color:#93c5fd; }
.chip-b { background:#e5e7eb; color:#111827; border-color:#9ca3af; }
.chip-g { background:#dcfce7; color:#065f46; border-color:#86efac; }
.chip-r { background:#fee2e2; color:#991b1b; border-color:#fecaca; }
.chip-c { background:#f3f4f6; color:#111827; border-color:#e5e7eb; }
mark { background: rgba(251, 191, 36, .35); color: inherit; padding:0 .1rem; border-radius:2px; }
.candidate-tile { cursor: pointer; }
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
 .spinner { display:inline-block; width:16px; height:16px; border:2px solid #93c5fd; border-top-color: transparent; border-radius:50%; animation: spin 0.8s linear infinite; vertical-align:middle; margin-left:.4rem; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Ensure hidden attribute always hides spinner within this fragment */
.spinner[hidden] { display: none !important; }
.hint { display:flex; align-items:center; gap:.5rem; background:#0b1220; border:1px solid var(--border); color:#cbd5e1; padding:.4rem .6rem; border-radius:8px; margin:.4rem 0 .6rem; }
.hint .hint-close { background:transparent; border:0; color:#9aa4b2; font-size:1rem; line-height:1; cursor:pointer; }
.hint .keys kbd { background:#1f2937; color:#e5e7eb; padding:.1rem .3rem; border-radius:4px; margin:0 .1rem; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; font-size:.85em; }
 .input-wrap { position: relative; display:inline-flex; align-items:center; }
 .clear-btn { position:absolute; right:.35rem; background:transparent; color:#9aa4b2; border:0; cursor:pointer; font-size:1.1rem; line-height:1; padding:.1rem .2rem; }
 .clear-btn:hover { color:#cbd5e1; }
</style>
