Models 44

Nemotron 3.5 Lightning (free)

by NVIDIAReasoningClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
1 min 35 s
Cost
$0
Output tokens
7,303
Spent thinking
0 tokens
Speed
77.1 tok/s
Console errors
0
First token after
267 ms
First visible text after
267 ms
Prompt tokens
513
Code size
24.6 KB
Finish reason
stop
Served by
Nvidia
Model id
nvidia/nemotron-3.5-lightning:free
Reasoning sent
{"effort":"none"}
Max output
32,000 tokens
Generated
Nov 9, 2026

What it was asked

The prompt
Build an interactive Kanban board in vanilla HTML, CSS and JavaScript (no framework, no library). Requirements: - Three columns: "To do", "In progress", "Done", each showing its card count. - Pre-populate the board with 6 realistic cards spread across the columns so the first screenshot looks alive. - Each card has a title and a priority (low / medium / high) shown as a colored badge. - Add a card through a small modal form (title required), and delete a card with a button on it. - Drag and drop cards between columns with the mouse, with a clear visual drop indicator. - A search field that filters cards live by title. - A light / dark theme toggle. - State lives in memory only (no storage APIs).
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 913 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kanban Board</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
  <style>
    :root {
      --bg-light: #f8f9fa;
      --bg-dark: #1e1e2f;
      --card-light: #ffffff;
      --card-dark: #2a2a3e;
      --text-light: #212529;
      --text-dark: #e8e8f0;
      --border-light: #dee2e6;
      --border-dark: #3a3a5a;
      --accent: #3b82f6;
      --accent-hover: #2563eb;
      --priority-low: #10b981;
      --priority-medium: #f59e0b;
      --priority-high: #ef4444;
      --shadow-light: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
      --shadow-dark: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.1);
    }

    * {
      box-sizing: border-box;
    }

    body {
      font-family: 'Inter', sans-serif;
      background: var(--bg-light);
      color: var(--text-light);
      margin: 0;
      min-height: 100vh;
      transition: background 0.3s, color 0.3s;
    }

    body.dark {
      background: var(--bg-dark);
      color: var(--text-dark);
    }

    /* Hide scrollbar but keep scrolling */
    body::-webkit-scrollbar {
      display: none;
    }
    body {
      -ms-overflow-style: none;
      scrollbar-width: none;
    }

    /* Toggle button */
    .theme-toggle {
      position: fixed;
      top: 1rem;
      right: 1rem;
      background: var(--card-light);
      border: 1px solid var(--border-light);
      color: var(--text-light);
      width: 44px;
      height: 44px;
      border-radius: 10px;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 100;
      transition: all 0.3s;
    }

    body.dark .theme-toggle {
      background: var(--card-dark);
      border-color: var(--border-dark);
      color: var(--text-dark);
    }

    .theme-toggle:hover {
      background: var(--accent);
      color: white;
    }

    /* Header */
    .header {
      max-width: 1280px;
      margin: 0 auto;
      padding: 1rem 1.5rem;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .title {
      font-size: 1.5rem;
      font-weight: 700;
      color: var(--text-light);
    }

    body.dark .title {
      color: var(--text-dark);
    }

    /* Search */
    .search-wrapper {
      position: relative;
      flex: 1;
      max-width: 400px;
    }

    .search-wrapper input {
      width: 100%;
      padding: 0.5rem 0.75rem 0.5rem 2.5rem;
      border: 1px solid var(--border-light);
      border-radius: 20px;
      font-size: 0.875rem;
      background: var(--card-light);
      color: var(--text-light);
      transition: border-color 0.2s, box-shadow 0.2s;
    }

    body.dark .search-wrapper input {
      background: var(--card-dark);
      border-color: var(--border-dark);
      color: var(--text-dark);
    }

    .search-wrapper input:focus {
      outline: none;
      border-color: var(--accent);
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
    }

    .search-wrapper svg {
      position: absolute;
      left: 0.75rem;
      top: 50%;
      transform: translateY(-50%);
      width: 16px;
      height: 16px;
      color: #666;
    }

    /* Cards counter */
    .stats {
      display: flex;
      gap: 1rem;
      font-size: 0.75rem;
      color: #666;
    }

    .stat {
      display: flex;
      align-items: center;
      gap: 0.25rem;
    }

    /* Columns */
    .columns {
      max-width: 1280px;
      margin: 2rem auto 0;
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
      gap: 1.5rem;
    }

    /* Column */
    .column {
      background: var(--card-light);
      border-radius: 16px;
      padding: 1rem;
      min-height: 200px;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      transition: box-shadow 0.3s;
    }

    body.dark .column {
      background: var(--card-dark);
    }

    .column:hover {
      box-shadow: var(--shadow-light);
    }

    body.dark .column:hover {
      box-shadow: var(--shadow-dark);
    }

    .column-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 0.75rem;
    }

    .column-title {
      font-size: 0.875rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.05em;
    }

    .column-count {
      font-size: 0.75rem;
      color: #666;
    }

    .column-count span {
      font-weight: 600;
      color: var(--text-light);
    }

    body.dark .column-count span {
      color: var(--text-dark);
    }

    .drop-indicator {
      border: 2px dashed var(--accent);
      border-radius: 8px;
      background: rgba(59, 130, 246, 0.1);
      height: 60px;
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 0.5rem 0;
      transition: background 0.2s;
    }

    .drop-indicator:hover {
      background: rgba(59, 130, 246, 0.2);
    }

    .drop-indicator.active {
      border-color: var(--accent-hover);
      background: rgba(37, 99, 235, 0.15);
    }

    .column-input {
      background: none;
      border: none;
      font: inherit;
      color: var(--text-light);
      flex: 1;
      font-size: 0.875rem;
    }

    body.dark .column-input {
      color: var(--text-dark);
    }

    .column-input:focus {
      outline: none;
    }

    /* Card */
    .card {
      background: var(--bg-light);
      border: 1px solid var(--border-light);
      border-radius: 12px;
      padding: 0.75rem 1rem;
      margin-bottom: 0.5rem;
      display: flex;
      align-items: center;
      justify-content: space-between;
      cursor: move;
      user-select: none;
      transition: background 0.2s, border-color 0.2s;
    }

    body.dark .card {
      background: var(--card-dark);
      border-color: var(--border-dark);
    }

    .card:hover {
      background: rgba(59, 130, 246, 0.05);
    }

    body.dark .card:hover {
      background: rgba(37, 99, 235, 0.1);
    }

    .card-title {
      font-size: 0.875rem;
      font-weight: 500;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 60%;
    }

    .priority-badge {
      display: inline-flex;
      align-items: center;
      padding: 0.25rem 0.5rem;
      border-radius: 10px;
      font-size: 0.65rem;
      font-weight: 600;
      text-transform: uppercase;
    }

    .priority-low { background: rgba(16, 185, 129, 0.2); color: var(--priority-low); }
    .priority-medium { background: rgba(245, 158, 11, 0.2); color: var(--priority-medium); }
    .priority-high { background: rgba(239, 68, 68, 0.2); color: var(--priority-high); }

    .card-actions {
      display: flex;
      gap: 0.5rem;
      opacity: 0;
      transition: opacity 0.2s;
    }

    .card:hover .card-actions {
      opacity: 1;
    }

    .btn-delete {
      background: none;
      border: none;
      color: #ef4444;
      font-size: 0.75rem;
      cursor: pointer;
      padding: 0.25rem;
      border-radius: 6px;
    }

    .btn-delete:hover {
      background: rgba(239, 68, 68, 0.1);
    }

    /* Modal */
    .modal-overlay {
      position: fixed;
      inset: 0;
      background: rgba(0, 0, 0, 0.5);
      backdrop-filter: blur(4px);
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 1000;
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.3s, visibility 0.3s;
    }

    .modal-overlay.active {
      opacity: 1;
      visibility: visible;
    }

    .modal {
      background: var(--card-light);
      padding: 1.5rem;
      border-radius: 16px;
      width: 90%;
      max-width: 400px;
      transform: scale(0.9) translateY(20px);
      transition: transform 0.3s;
    }

    body.dark .modal {
      background: var(--card-dark);
    }

    .modal-overlay.active .modal {
      transform: scale(1) translateY(0);
    }

    .modal h2 {
      margin: 0 0 1rem;
      font-size: 1.25rem;
    }

    .modal-input {
      width: 100%;
      padding: 0.5rem;
      margin-bottom: 1rem;
      border: 1px solid var(--border-light);
      border-radius: 8px;
      font: inherit;
      background: var(--bg-light);
      color: var(--text-light);
      transition: border-color 0.2s;
    }

    body.dark .modal-input {
      background: var(--card-dark);
      border-color: var(--border-dark);
      color: var(--text-dark);
    }

    .modal-input:focus {
      outline: none;
      border-color: var(--accent);
    }

    .modal-actions {
      display: flex;
      gap: 0.75rem;
      justify-content: flex-end;
    }

    .btn-cancel, .btn-save {
      padding: 0.5rem 1rem;
      border: none;
      border-radius: 8px;
      font: inherit;
      cursor: pointer;
      font-size: 0.875rem;
    }

    .btn-cancel {
      background: var(--border-light);
      color: var(--text-light);
    }

    body.dark .btn-cancel {
      background: var(--border-dark);
    }

    .btn-save {
      background: var(--accent);
      color: white;
    }

    /* Start message */
    .start-message {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: var(--bg-light);
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      z-index: 2000;
      transition: opacity 0.3s;
    }

    body.dark .start-message {
      background: var(--bg-dark);
    }

    .start-message.hidden {
      opacity: 0;
      visibility: hidden;
    }

    .start-text {
      font-size: 1.25rem;
      color: #666;
      margin-bottom: 2rem;
      text-align: center;
    }

    body.dark .start-text {
      color: #999;
    }

    /* Drag active */
    .card.dragging {
      opacity: 0.5;
      transform: scale(1.02);
    }

    /* Reduced motion */
    @media (prefers-reduced-motion: reduce) {
      * {
        transition: none !important;
        animation: none !important;
      }
    }
  </style>
</head>
<body>
  <!-- Start message -->
  <div class="start-message" id="startMessage">
    <div class="start-text">Click or press a key to start</div>
  </div>

  <!-- Header -->
  <header class="header">
    <h1 class="title">Kanban Board</h1>
    <div class="stats" id="stats">
      <!-- Dynamically populated -->
    </div>
    <button class="theme-toggle" id="themeToggle" aria-label="Toggle theme">
      <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" id="sunIcon">
        <circle cx="12" cy="12" r="5"></circle>
        <line x1="12" y1="1" x2="12" y2="3"></line>
        <line x1="12" y1="21" x2="12" y2="23"></line>
        <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
        <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
        <line x1="1" y1="12" x2="3" y2="12"></line>
        <line x1="21" y1="12" x2="23" y2="12"></line>
        <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
        <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
      </svg>
      <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" id="moonIcon" style="display:none;">
        <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
      </svg>
    </button>
  </header>

  <!-- Search -->
  <div class="search-wrapper">
    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6.3-6.3a.75.75 0 0 0-1.06 0L8.66 15H15v-2h-4.66l1.42-1.42a.75.75 0 0 0 0-1.06z"/><circle cx="12" cy="12" r="10"/></svg>
    <input type="text" id="searchInput" placeholder="Search cards...">
  </div>

  <!-- Columns -->
  <div class="columns" id="columns">
    <!-- Dynamically populated -->
  </div>

  <!-- Modal -->
  <div class="modal-overlay" id="modalOverlay">
    <div class="modal">
      <h2>Add Card</h2>
      <input type="text" class="modal-input" id="modalTitle" placeholder="Card title">
      <div class="modal-actions">
        <button class="btn-cancel" id="modalCancel">Cancel</button>
        <button class="btn-save" id="modalSave">Add</button>
      </div>
    </div>
  </div>

  <script>
    // ============ State ============
    const state = {
      columns: {
        'to-do': { id: 'to-do', title: 'To do', cards: [] },
        'in-progress': { id: 'in-progress', title: 'In progress', cards: [] },
        'done': { id: 'done', title: 'Done', cards: [] }
      },
      priorities: {
        'task-1': 'low',
        'task-2': 'medium',
        'task-3': 'high',
        'task-4': 'low',
        'task-5': 'medium',
        'task-6': 'high'
      },
      nextCardId: 7,
      isDragging: false,
      draggedCard: null,
      dragOverColumn: null
    };

    // ============ DOM Elements ============
    const columnsEl = document.getElementById('columns');
    const searchInput = document.getElementById('searchInput');
    const themeToggle = document.getElementById('themeToggle');
    const sunIcon = document.getElementById('sunIcon');
    const moonIcon = document.getElementById('moonIcon');
    const startMessage = document.getElementById('startMessage');
    const statsEl = document.getElementById('stats');

    // ============ Initial Cards ============
    function initCards() {
      state.columns['to-do'].cards = [
        { id: 'task-1', title: 'Design dashboard UI', priority: 'high' },
        { id: 'task-2', title: 'Write API documentation', priority: 'medium' },
        { id: 'task-3', title: 'Fix login bug on mobile', priority: 'high' }
      ];

      state.columns['in-progress'].cards = [
        { id: 'task-4', title: 'Implement dark mode toggle', priority: 'low' }
      ];

      state.columns['done'].cards = [
        { id: 'task-5', title: 'Review PR comments', priority: 'medium' },
        { id: 'task-6', title: 'Deploy staging environment', priority: 'high' }
      ];

      state.nextCardId = 7;
    }

    // ============ Render ============
    function render() {
      // Update stats
      const total = Object.values(state.columns).reduce((sum, col) => sum + col.cards.length, 0);
      statsEl.innerHTML = `
        <div class="stat">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="25" y="3" width="7" height="7"/></svg>
          <span>Total: ${total}</span>
        </div>
        <div class="stat">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
          <span>In progress: ${state.columns['in-progress'].cards.length}</span>
        </div>
      `;

      // Render columns
      columnsEl.innerHTML = '';

      const columnOrder = ['to-do', 'in-progress', 'done'];

      columnOrder.forEach(colId => {
        const col = state.columns[colId];
        const columnEl = document.createElement('div');
        columnEl.className = 'column';
        columnEl.setAttribute('data-column', colId);

        // Header
        const headerEl = document.createElement('div');
        headerEl.className = 'column-header';
        headerEl.innerHTML = `
          <span class="column-title">${col.title}</span>
          <span class="column-count">${col.cards.length} ${
            col.cards.length === 1 ? 'card' : 'cards'
          }</span>
        `;

        // Cards area
        const cardsEl = document.createElement('div');
        cardsEl.className = 'cards';
        cardsEl.style.flexGrow = '1';
        cardsEl.style.overflowY = 'auto';
        cardsEl.style.scrollbarDisplay = 'none';

        // Sort cards: high -> medium -> low, then by id
        const sortedCards = [...col.cards].sort((a, b) => {
          const priorityOrder = { high: 3, medium: 2, low: 1 };
          if (priorityOrder[a.priority] !== priorityOrder[b.priority]) {
            return priorityOrder[b.priority] - priorityOrder[a.priority];
          }
          return a.id.localeCompare(b.id);
        });

        sortedCards.forEach(card => {
          const cardEl = createCardElement(card);
          cardsEl.appendChild(cardEl);
        });

        // Drop indicator
        const dropIndicator = document.createElement('div');
        dropIndicator.className = 'drop-indicator' ;
        dropIndicator.setAttribute('role', 'button');
        dropIndicator.setAttribute('tabindex', '0');
        dropIndicator.setAttribute('aria-label', `Drop card here`);
        dropIndicator.innerHTML = `
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M12 12l4 4-4 4"/><path d="M7 18H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M16 14l2 2"/><path d="M8 14l-2 2"/></svg>
        `;

        columnEl.appendChild(headerEl);
        columnEl.appendChild(cardsEl);
        columnEl.appendChild(dropIndicator);
        columnsEl.appendChild(columnEl);
      });

      // Add drag listeners after render
      setupDragAndDrop();

      // Show start message if no columns have cards
      const anyCards = Object.values(state.columns).some(col => col.cards.length > 0);
      if (anyCards) {
        startMessage.classList.add('hidden');
      }
    }

    // ============ Create Card Element ============
    function createCardElement(card) {
      const cardEl = document.createElement('div');
      cardEl.className = 'card';
      cardEl.draggable = true;
      cardEl.id = card.id;
      cardEl.dataset.priority = card.priority;

      cardEl.innerHTML = `
        <span class="card-title">${card.title}</span>
        <span class="priority-badge priority-${card.priority}">${card.priority}</span>
        <div class="card-actions">
          <button class="btn-delete" aria-label="Delete card">×</button>
        </div>
      `;

      // Priority badge color
      const priorityBadge = cardEl.querySelector(`.priority-${card.priority}`);
      if (priorityBadge) {
        priorityBadge.style.background = card.priority === 'low'
          ? 'rgba(16, 185, 129, 0.2)'
          : card.priority === 'medium'
            ? 'rgba(245, 158, 11, 0.2)'
            : 'rgba(239, 68, 68, 0.2)';
      }

      // Delete button
      const deleteBtn = cardEl.querySelector('.btn-delete');
      deleteBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        deleteCard(card.id);
      });

      // Drag events
      cardEl.addEventListener('dragstart', handleDragStart);
      cardEl.addEventListener('dragend', handleDragEnd);

      return cardEl;
    }

    // ============ Drag and Drop ============
    function setupDragAndDrop() {
      const columns = document.querySelectorAll('.column');

      columns.forEach(column => {
        const cardsEl = column.querySelector('.cards');
        const dropIndicator = column.querySelector('.drop-indicator');

        // Column-level drag over
        column.addEventListener('dragover', (e) => {
          e.preventDefault();
          e.stopPropagation();
          
          if (state.isDragging && state.draggedCard) {
            state.dragOverColumn = column.getAttribute('data-column');
            dropIndicator.classList.add('active');
            
            // Place indicator after the last card or at top
            const afterElement = getDragAfterElement(cardsEl, e.clientY);
            const cards = cardsEl.querySelectorAll('.card:not(.dragging)');
            
            if (afterElement == null) {
              cardsEl.appendChild(state.draggedCard);
            } else {
              cardsEl.insertBefore(state.draggedCard, afterElement);
            }
          }
        });

        column.addEventListener('dragleave', (e) => {
          e.preventDefault();
          e.stopPropagation();
          dropIndicator.classList.remove('active');
        });

        column.addEventListener('dragend', (e) => {
          e.preventDefault();
          e.stopPropagation();
          dropIndicator.classList.remove('active');
          state.isDragging = false;
          state.draggedCard = null;
          state.dragOverColumn = null;
        });
      });
    }

    function getDragAfterElement(container, y) {
      const draggableElements = [...container.querySelectorAll('.card:not(.dragging)')];
      
      return draggableElements.reduce((closest, child) => {
        const box = child.getBoundingClientRect();
        const offset = y - box.top - box.height / 2;
        
        if (offset < 0 && offset > closest.offset) {
          return { offset: offset, element: child };
        } else {
          return closest;
        }
      }, { offset: Number.NEGATIVE_INFINITY }).element;
    }

    function handleDragStart(e) {
      const card = e.target.closest('.card');
      if (!card) return;

      state.isDragging = true;
      state.draggedCard = card;

      card.classList.add('dragging');

      // Move card to temp container so it doesn't leave a gap
      const cardsEl = card.parentElement;
      if (cardsEl) {
        cardsEl.removeChild(card);
      }

      e.dataTransfer.effectAllowed = 'move';
      e.dataTransfer.setData('text/plain', card.id);
    }

    function handleDragEnd(e) {
      const card = e.target.closest('.card');
      if (!card) return;

      card.classList.remove('dragging');
      state.isDragging = false;
      state.draggedCard = null;
      state.dragOverColumn = null;
    }

    // ============ Actions ============

    function deleteCard(cardId) {
      for (const colId of Object.keys(state.columns)) {
        const index = state.columns[colId].cards.findIndex(c => c.id === cardId);
        if (index !== -1) {
          state.columns[colId].cards.splice(index, 1);
          render();
          return;
        }
      }
    }

    function addCard(title, priority = 'medium') {
      const card = {
        id: `task-${state.nextCardId++}`,
        title,
        priority
      };

      // Add to first non-full column (or To Do as default)
      let added = false;
      const columnOrder = ['to-do', 'in-progress', 'done'];
      
      for (const colId of columnOrder) {
        if (state.columns[colId].cards.length < 4) {
          state.columns[colId].cards.push(card);
          added = true;
          break;
        }
      }

      if (!added) {
        // Fallback: add to To Do
        state.columns['to-do'].cards.push(card);
      }

      render();
    }

    // ============ Modal ============
    function openModal() {
      const modal = document.getElementById('modalOverlay');
      modal.classList.add('active');
      const input = document.getElementById('modalTitle');
      input.focus();
      input.select();
    }

    function closeModal() {
      const modal = document.getElementById('modalOverlay');
      modal.classList.remove('active');
      document.getElementById('modalTitle').value = '';
    }

    document.getElementById('modalSave').addEventListener('click', () => {
      const title = document.getElementById('modalTitle').value.trim();
      if (title) {
        addCard(title);
        closeModal();
      }
    });

    document.getElementById('modalCancel').addEventListener('click', closeModal);

    // Close modal on overlay click
    document.getElementById('modalOverlay').addEventListener('click', (e) => {
      if (e.target === e.currentTarget) {
        closeModal();
      }
    });

    // Close on Escape
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') {
        closeModal();
      }
    });

    // ============ Search ============
    searchInput.addEventListener('input', (e) => {
      const term = e.target.value.toLowerCase();
      const cards = document.querySelectorAll('.card');
      
      cards.forEach(card => {
        const title = card.querySelector('.card-title').textContent.toLowerCase();
        card.style.display = title.includes(term) ? '' : 'none';
      });
    });

    // ============ Theme Toggle ============
    themeToggle.addEventListener('click', () => {
      document.body.classList.toggle('dark');
      
      const isDark = document.body.classList.contains('dark');
      sunIcon.style.display = isDark ? 'none' : 'block';
      moonIcon.style.display = isDark ? 'block' : 'none';
      themeToggle.setAttribute('aria-label', isDark ? 'Toggle light theme' : 'Toggle dark theme');
    });

    // ============ Initialize ============
    initCards();
    render();

    // ============ Start Message ============
    // Hide start message after first interaction
    document.addEventListener('click', () => {
      startMessage.classList.add('hidden');
    });

    document.addEventListener('keydown', () => {
      startMessage.classList.add('hidden');
    });
  </script>
</body>
</html>