Models 44

Gemini 3.8 Flash

by GoogleReasoning1 console error
Open in new window

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

How it went

Total time
1 min 23 s
Cost
$0.048
Output tokens
12,566
Spent thinking
2,183 tokens
Speed
156.5 tok/s
Console errors
1
First token after
2.3 s
First visible text after
22.5 s
Prompt tokens
507
Code size
29.8 KB
Finish reason
stop
Served by
Google
Model id
google/gemini-3.8-flash
Reasoning sent
model default
Max output
65,536 tokens
Generated
Nov 12, 2026

Console errors

Caught in the first 3 seconds after load, in a sandboxed iframe like the one above.

Blocked autofocusing on a <input> element in a cross-origin subframe.

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 · 1048 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kanban Flow</title>
  <style>
    :root {
      --bg-page: #f4f5f8;
      --bg-column: #ebedf2;
      --bg-card: #ffffff;
      --bg-modal: #ffffff;
      --bg-overlay: rgba(15, 23, 42, 0.45);
      --text-main: #1e293b;
      --text-muted: #64748b;
      --text-placeholder: #94a3b8;
      --border-subtle: #e2e8f0;
      --border-card: #e2e8f0;
      --card-shadow: 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.03);
      --card-shadow-hover: 0 8px 16px -4px rgba(0, 0, 0, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.04);
      --primary: #4f46e5;
      --primary-hover: #4338ca;
      --primary-light: #eef2ff;
      --drop-indicator: #4f46e5;

      /* Priorities */
      --pri-high-bg: #fef2f2;
      --pri-high-text: #b91c1c;
      --pri-high-dot: #ef4444;
      --pri-med-bg: #fffbeb;
      --pri-med-text: #b45309;
      --pri-med-dot: #f59e0b;
      --pri-low-bg: #f0fdf4;
      --pri-low-text: #15803d;
      --pri-low-dot: #22c55e;
    }

    [data-theme="dark"] {
      --bg-page: #0b0f19;
      --bg-column: #151c2c;
      --bg-card: #1e293b;
      --bg-modal: #1e293b;
      --bg-overlay: rgba(0, 0, 0, 0.7);
      --text-main: #f8fafc;
      --text-muted: #94a3b8;
      --text-placeholder: #64748b;
      --border-subtle: #26334a;
      --border-card: #2a374f;
      --card-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
      --card-shadow-hover: 0 8px 20px -2px rgba(0, 0, 0, 0.45);
      --primary: #6366f1;
      --primary-hover: #4f46e5;
      --primary-light: #1e1b4b;
      --drop-indicator: #818cf8;

      --pri-high-bg: rgba(239, 68, 68, 0.15);
      --pri-high-text: #fca5a5;
      --pri-high-dot: #ef4444;
      --pri-med-bg: rgba(245, 158, 11, 0.15);
      --pri-med-text: #fcd34d;
      --pri-med-dot: #f59e0b;
      --pri-low-bg: rgba(34, 197, 94, 0.15);
      --pri-low-text: #86efac;
      --pri-low-dot: #22c55e;
    }

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
      background-color: var(--bg-page);
      color: var(--text-main);
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      transition: background-color 0.2s ease, color 0.2s ease;
      overflow-x: hidden;
    }

    /* Top Bar */
    header {
      background: var(--bg-card);
      border-bottom: 1px solid var(--border-subtle);
      padding: 14px 28px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 16px;
      position: sticky;
      top: 0;
      z-index: 20;
    }

    .brand {
      display: flex;
      align-items: center;
      gap: 10px;
      font-weight: 700;
      font-size: 1.15rem;
      letter-spacing: -0.02em;
    }

    .brand-icon {
      width: 28px;
      height: 28px;
      background: linear-gradient(135deg, var(--primary), #818cf8);
      border-radius: 7px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #fff;
    }

    .header-actions {
      display: flex;
      align-items: center;
      gap: 12px;
      flex: 1;
      max-width: 600px;
      justify-content: flex-end;
    }

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

    .search-wrapper svg {
      position: absolute;
      left: 10px;
      top: 50%;
      transform: translateY(-50%);
      width: 15px;
      height: 15px;
      fill: none;
      stroke: var(--text-muted);
      stroke-width: 2;
      stroke-linecap: round;
      stroke-linejoin: round;
      pointer-events: none;
    }

    .search-input {
      width: 100%;
      padding: 7px 12px 7px 34px;
      font-size: 0.88rem;
      border: 1px solid var(--border-subtle);
      border-radius: 8px;
      background: var(--bg-page);
      color: var(--text-main);
      outline: none;
      transition: all 0.15s ease;
    }

    .search-input:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 2px var(--primary-light);
    }

    /* Buttons */
    .btn {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-size: 0.88rem;
      font-weight: 600;
      padding: 7px 14px;
      border-radius: 8px;
      border: none;
      cursor: pointer;
      transition: all 0.15s ease;
    }

    .btn-primary {
      background: var(--primary);
      color: #ffffff;
    }

    .btn-primary:hover {
      background: var(--primary-hover);
    }

    .btn-icon {
      background: var(--bg-page);
      color: var(--text-main);
      border: 1px solid var(--border-subtle);
      padding: 7px 10px;
      border-radius: 8px;
    }

    .btn-icon:hover {
      background: var(--border-subtle);
    }

    /* Board Container */
    .board-container {
      flex: 1;
      padding: 24px 28px;
      display: grid;
      grid-template-columns: repeat(3, minmax(290px, 1fr));
      gap: 20px;
      align-items: flex-start;
      overflow-x: auto;
    }

    /* Column */
    .kanban-col {
      background: var(--bg-column);
      border-radius: 12px;
      padding: 14px;
      display: flex;
      flex-direction: column;
      max-height: calc(100vh - 110px);
      min-height: 240px;
      transition: outline 0.15s ease;
    }

    .col-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 4px 6px 12px 6px;
    }

    .col-title-group {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .col-dot {
      width: 9px;
      height: 9px;
      border-radius: 50%;
    }

    .col-todo .col-dot { background-color: #64748b; }
    .col-inprogress .col-dot { background-color: #3b82f6; }
    .col-done .col-dot { background-color: #10b981; }

    .col-title {
      font-size: 0.94rem;
      font-weight: 700;
      letter-spacing: -0.01em;
    }

    .col-count {
      font-size: 0.75rem;
      font-weight: 600;
      background: rgba(100, 116, 139, 0.18);
      color: var(--text-muted);
      padding: 2px 7px;
      border-radius: 10px;
    }

    .cards-list {
      flex: 1;
      overflow-y: auto;
      display: flex;
      flex-direction: column;
      gap: 10px;
      padding: 2px 2px 10px 2px;
      min-height: 60px;
    }

    /* Card Item */
    .kanban-card {
      background: var(--bg-card);
      border: 1px solid var(--border-card);
      border-radius: 10px;
      padding: 12px 14px;
      box-shadow: var(--card-shadow);
      cursor: grab;
      user-select: none;
      display: flex;
      flex-direction: column;
      gap: 10px;
      transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.15s ease, border-color 0.15s ease;
      position: relative;
    }

    .kanban-card:hover {
      box-shadow: var(--card-shadow-hover);
      border-color: var(--border-subtle);
    }

    .kanban-card:active {
      cursor: grabbing;
    }

    .kanban-card.dragging {
      opacity: 0.35;
      transform: scale(0.97);
    }

    .card-top {
      display: flex;
      justify-content: space-between;
      align-items: flex-start;
      gap: 8px;
    }

    .card-title {
      font-size: 0.92rem;
      font-weight: 600;
      line-height: 1.35;
      word-break: break-word;
      color: var(--text-main);
    }

    .btn-delete-card {
      background: transparent;
      border: none;
      color: var(--text-placeholder);
      padding: 2px 4px;
      border-radius: 5px;
      cursor: pointer;
      opacity: 0.6;
      transition: all 0.15s ease;
      flex-shrink: 0;
    }

    .kanban-card:hover .btn-delete-card {
      opacity: 1;
    }

    .btn-delete-card:hover {
      color: #ef4444;
      background: rgba(239, 68, 68, 0.12);
    }

    .card-bottom {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 6px;
      margin-top: 2px;
    }

    /* Badges */
    .badge-priority {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      padding: 3px 8px;
      border-radius: 6px;
      font-size: 0.72rem;
      font-weight: 700;
      text-transform: capitalize;
      letter-spacing: 0.02em;
    }

    .badge-priority .pri-dot {
      width: 6px;
      height: 6px;
      border-radius: 50%;
    }

    .pri-high {
      background-color: var(--pri-high-bg);
      color: var(--pri-high-text);
    }
    .pri-high .pri-dot { background-color: var(--pri-high-dot); }

    .pri-medium {
      background-color: var(--pri-med-bg);
      color: var(--pri-med-text);
    }
    .pri-medium .pri-dot { background-color: var(--pri-med-dot); }

    .pri-low {
      background-color: var(--pri-low-bg);
      color: var(--pri-low-text);
    }
    .pri-low .pri-dot { background-color: var(--pri-low-dot); }

    .card-id {
      font-size: 0.72rem;
      font-weight: 600;
      color: var(--text-muted);
    }

    /* Drop Indicator placeholder */
    .drop-indicator {
      height: 48px;
      border: 2px dashed var(--drop-indicator);
      background: rgba(99, 102, 241, 0.08);
      border-radius: 10px;
      margin: 2px 0;
      pointer-events: none;
      transition: all 0.12s ease;
    }

    /* Empty state */
    .col-empty {
      border: 2px dashed var(--border-subtle);
      border-radius: 10px;
      padding: 24px 12px;
      text-align: center;
      color: var(--text-muted);
      font-size: 0.83rem;
      margin-top: 4px;
      user-select: none;
    }

    /* Quick column add card button */
    .btn-col-add {
      background: transparent;
      border: none;
      color: var(--text-muted);
      display: flex;
      align-items: center;
      gap: 6px;
      font-size: 0.83rem;
      font-weight: 600;
      padding: 8px 10px;
      border-radius: 8px;
      cursor: pointer;
      margin-top: 4px;
      transition: all 0.15s ease;
    }

    .btn-col-add:hover {
      background: rgba(100, 116, 139, 0.12);
      color: var(--text-main);
    }

    /* Modal */
    .modal-overlay {
      position: fixed;
      inset: 0;
      background: var(--bg-overlay);
      backdrop-filter: blur(4px);
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 100;
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.2s ease;
      padding: 16px;
    }

    .modal-overlay.active {
      opacity: 1;
      pointer-events: auto;
    }

    .modal-dialog {
      background: var(--bg-modal);
      border: 1px solid var(--border-subtle);
      box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.2), 0 10px 10px -5px rgba(0, 0, 0, 0.1);
      border-radius: 14px;
      width: 100%;
      max-width: 440px;
      transform: scale(0.95);
      transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
      overflow: hidden;
    }

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

    .modal-header {
      padding: 18px 22px 14px 22px;
      border-bottom: 1px solid var(--border-subtle);
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .modal-title {
      font-size: 1.05rem;
      font-weight: 700;
      letter-spacing: -0.01em;
    }

    .btn-close-modal {
      background: transparent;
      border: none;
      color: var(--text-muted);
      cursor: pointer;
      padding: 4px;
      border-radius: 6px;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .btn-close-modal:hover {
      background: var(--border-subtle);
      color: var(--text-main);
    }

    .modal-body {
      padding: 20px 22px;
      display: flex;
      flex-direction: column;
      gap: 16px;
    }

    .form-group {
      display: flex;
      flex-direction: column;
      gap: 6px;
    }

    .form-label {
      font-size: 0.8rem;
      font-weight: 600;
      color: var(--text-muted);
      text-transform: uppercase;
      letter-spacing: 0.04em;
    }

    .form-input, .form-select {
      background: var(--bg-page);
      border: 1px solid var(--border-subtle);
      border-radius: 8px;
      padding: 9px 12px;
      font-size: 0.92rem;
      color: var(--text-main);
      outline: none;
      font-family: inherit;
      transition: border-color 0.15s ease, box-shadow 0.15s ease;
    }

    .form-input:focus, .form-select:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 2px var(--primary-light);
    }

    .priority-selector {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 8px;
    }

    .pri-radio-label {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      padding: 8px;
      border: 1px solid var(--border-subtle);
      border-radius: 8px;
      font-size: 0.85rem;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.15s ease;
      background: var(--bg-page);
    }

    .pri-radio-label input {
      position: absolute;
      opacity: 0;
      pointer-events: none;
    }

    .pri-radio-label:has(input:checked) {
      border-color: var(--primary);
      background: var(--primary-light);
      color: var(--primary);
    }

    .modal-footer {
      padding: 14px 22px 18px 22px;
      background: var(--bg-column);
      display: flex;
      justify-content: flex-end;
      gap: 10px;
    }

    .btn-secondary {
      background: var(--bg-card);
      border: 1px solid var(--border-subtle);
      color: var(--text-main);
    }

    .btn-secondary:hover {
      background: var(--border-subtle);
    }

    /* Responsive */
    @media (max-width: 860px) {
      .board-container {
        grid-template-columns: 1fr;
        padding: 16px;
      }
      .kanban-col {
        max-height: none;
      }
      header {
        padding: 12px 16px;
      }
    }
  </style>
</head>
<body data-theme="light">

  <header>
    <div class="brand">
      <div class="brand-icon">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
          <rect x="3" y="3" width="7" height="9" rx="1"></rect>
          <rect x="14" y="3" width="7" height="5" rx="1"></rect>
          <rect x="14" y="12" width="7" height="9" rx="1"></rect>
          <rect x="3" y="16" width="7" height="5" rx="1"></rect>
        </svg>
      </div>
      <span>KanbanFlow</span>
    </div>

    <div class="header-actions">
      <div class="search-wrapper">
        <svg viewBox="0 0 24 24">
          <circle cx="11" cy="11" r="8"></circle>
          <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
        </svg>
        <input type="text" id="searchInput" class="search-input" placeholder="Search cards..." autocomplete="off">
      </div>

      <button id="themeToggleBtn" class="btn btn-icon" title="Toggle Theme" aria-label="Toggle Theme">
        <svg id="themeIcon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
        </svg>
      </button>

      <button id="openModalBtn" class="btn btn-primary">
        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
          <line x1="12" y1="5" x2="12" y2="19"></line>
          <line x1="5" y1="12" x2="19" y2="12"></line>
        </svg>
        <span>Add Task</span>
      </button>
    </div>
  </header>

  <main class="board-container" id="boardContainer">
    <!-- To do Column -->
    <div class="kanban-col col-todo" data-col="todo">
      <div class="col-header">
        <div class="col-title-group">
          <span class="col-dot"></span>
          <span class="col-title">To do</span>
        </div>
        <span class="col-count" id="count-todo">0</span>
      </div>
      <div class="cards-list" id="list-todo"></div>
      <button class="btn-col-add" data-add-to="todo">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
        <span>New task</span>
      </button>
    </div>

    <!-- In progress Column -->
    <div class="kanban-col col-inprogress" data-col="inprogress">
      <div class="col-header">
        <div class="col-title-group">
          <span class="col-dot"></span>
          <span class="col-title">In progress</span>
        </div>
        <span class="col-count" id="count-inprogress">0</span>
      </div>
      <div class="cards-list" id="list-inprogress"></div>
      <button class="btn-col-add" data-add-to="inprogress">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
        <span>New task</span>
      </button>
    </div>

    <!-- Done Column -->
    <div class="kanban-col col-done" data-col="done">
      <div class="col-header">
        <div class="col-title-group">
          <span class="col-dot"></span>
          <span class="col-title">Done</span>
        </div>
        <span class="col-count" id="count-done">0</span>
      </div>
      <div class="cards-list" id="list-done"></div>
      <button class="btn-col-add" data-add-to="done">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
        <span>New task</span>
      </button>
    </div>
  </main>

  <!-- Add Card Modal -->
  <div class="modal-overlay" id="cardModal">
    <div class="modal-dialog">
      <div class="modal-header">
        <h3 class="modal-title">Create New Task</h3>
        <button class="btn-close-modal" id="closeModalBtn" aria-label="Close modal">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <line x1="18" y1="6" x2="6" y2="18"></line>
            <line x1="6" y1="6" x2="18" y2="18"></line>
          </svg>
        </button>
      </div>
      <form id="addCardForm">
        <div class="modal-body">
          <div class="form-group">
            <label class="form-label" for="taskTitle">Task Title *</label>
            <input type="text" id="taskTitle" class="form-input" placeholder="e.g. Audit authentication middleware" required autofocus>
          </div>

          <div class="form-group">
            <label class="form-label">Priority</label>
            <div class="priority-selector">
              <label class="pri-radio-label">
                <input type="radio" name="priority" value="low">
                <span>Low</span>
              </label>
              <label class="pri-radio-label">
                <input type="radio" name="priority" value="medium" checked>
                <span>Medium</span>
              </label>
              <label class="pri-radio-label">
                <input type="radio" name="priority" value="high">
                <span>High</span>
              </label>
            </div>
          </div>

          <div class="form-group">
            <label class="form-label" for="taskColumn">Column</label>
            <select id="taskColumn" class="form-select">
              <option value="todo">To do</option>
              <option value="inprogress">In progress</option>
              <option value="done">Done</option>
            </select>
          </div>
        </div>

        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" id="cancelModalBtn">Cancel</button>
          <button type="submit" class="btn btn-primary">Create Task</button>
        </div>
      </form>
    </div>
  </div>

  <script>
    // State lives in-memory
    let cards = [
      { id: 'TASK-101', title: 'Audit OAuth2 authentication flow for session vulnerabilities', priority: 'high', column: 'todo' },
      { id: 'TASK-102', title: 'Design onboarding empty states and illustration assets', priority: 'medium', column: 'todo' },
      { id: 'TASK-103', title: 'Migrate PostgreSQL database read replica to AWS Aurora', priority: 'high', column: 'inprogress' },
      { id: 'TASK-104', title: 'Implement real-time WebSocket connection heartbeat', priority: 'medium', column: 'inprogress' },
      { id: 'TASK-105', title: 'Optimize sidebar gesture handling on mobile web', priority: 'low', column: 'done' },
      { id: 'TASK-106', title: 'Run baseline performance benchmarks with k6 load test', priority: 'low', column: 'done' }
    ];

    let nextTaskId = 107;
    let searchQuery = '';
    let isDarkTheme = false;

    // Drag tracking
    let draggedCardId = null;
    let dropIndicator = null;

    // DOM Elements
    const lists = {
      todo: document.getElementById('list-todo'),
      inprogress: document.getElementById('list-inprogress'),
      done: document.getElementById('list-done')
    };

    const counts = {
      todo: document.getElementById('count-todo'),
      inprogress: document.getElementById('count-inprogress'),
      done: document.getElementById('count-done')
    };

    const searchInput = document.getElementById('searchInput');
    const themeToggleBtn = document.getElementById('themeToggleBtn');
    const themeIcon = document.getElementById('themeIcon');
    const openModalBtn = document.getElementById('openModalBtn');
    const closeModalBtn = document.getElementById('closeModalBtn');
    const cancelModalBtn = document.getElementById('cancelModalBtn');
    const cardModal = document.getElementById('cardModal');
    const addCardForm = document.getElementById('addCardForm');
    const taskTitleInput = document.getElementById('taskTitle');
    const taskColumnSelect = document.getElementById('taskColumn');

    // Create drop indicator element
    function createDropIndicator() {
      const el = document.createElement('div');
      el.className = 'drop-indicator';
      return el;
    }
    dropIndicator = createDropIndicator();

    // Render Cards
    function renderBoard() {
      const filtered = cards.filter(card => 
        card.title.toLowerCase().includes(searchQuery.toLowerCase())
      );

      // Render for each column
      ['todo', 'inprogress', 'done'].forEach(col => {
        const listEl = lists[col];
        const colCards = filtered.filter(c => c.column === col);
        const totalInCol = cards.filter(c => c.column === col).length;

        counts[col].textContent = searchQuery ? `${colCards.length} / ${totalInCol}` : totalInCol;
        listEl.innerHTML = '';

        if (colCards.length === 0) {
          const empty = document.createElement('div');
          empty.className = 'col-empty';
          empty.textContent = searchQuery ? 'No matching cards' : 'Drop cards here';
          listEl.appendChild(empty);
          return;
        }

        colCards.forEach(card => {
          const cardEl = document.createElement('div');
          cardEl.className = 'kanban-card';
          cardEl.setAttribute('draggable', 'true');
          cardEl.dataset.id = card.id;

          cardEl.innerHTML = `
            <div class="card-top">
              <span class="card-title">${escapeHTML(card.title)}</span>
              <button class="btn-delete-card" title="Delete card" aria-label="Delete card" data-delete-id="${card.id}">
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <polyline points="3 6 5 6 21 6"></polyline>
                  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
                </svg>
              </button>
            </div>
            <div class="card-bottom">
              <span class="badge-priority pri-${card.priority}">
                <span class="pri-dot"></span>
                ${card.priority}
              </span>
              <span class="card-id">${card.id}</span>
            </div>
          `;

          // Card Drag Events
          cardEl.addEventListener('dragstart', (e) => {
            draggedCardId = card.id;
            cardEl.classList.add('dragging');
            e.dataTransfer.effectAllowed = 'move';
            e.dataTransfer.setData('text/plain', card.id);
          });

          cardEl.addEventListener('dragend', () => {
            draggedCardId = null;
            cardEl.classList.remove('dragging');
            if (dropIndicator.parentNode) {
              dropIndicator.parentNode.removeChild(dropIndicator);
            }
          });

          listEl.appendChild(cardEl);
        });
      });
    }

    // Helper for HTML escaping
    function escapeHTML(str) {
      return str.replace(/[&<>'"]/g, 
        tag => ({
          '&': '&amp;',
          '<': '&lt;',
          '>': '&gt;',
          "'": '&#39;',
          '"': '&quot;'
        }[tag] || tag)
      );
    }

    // Setup Drag and Drop on Columns
    ['todo', 'inprogress', 'done'].forEach(col => {
      const listEl = lists[col];

      listEl.addEventListener('dragover', (e) => {
        e.preventDefault();
        e.dataTransfer.dropEffect = 'move';

        const afterElement = getDragAfterElement(listEl, e.clientY);
        if (afterElement == null) {
          listEl.appendChild(dropIndicator);
        } else {
          listEl.insertBefore(dropIndicator, afterElement);
        }
      });

      listEl.addEventListener('drop', (e) => {
        e.preventDefault();
        if (!draggedCardId) return;

        const cardIndex = cards.findIndex(c => c.id === draggedCardId);
        if (cardIndex === -1) return;

        const [movedCard] = cards.splice(cardIndex, 1);
        movedCard.column = col;

        // Calculate insertion index
        const afterElement = getDragAfterElement(listEl, e.clientY);
        if (afterElement == null) {
          cards.push(movedCard);
        } else {
          const targetId = afterElement.dataset.id;
          const targetIndex = cards.findIndex(c => c.id === targetId);
          if (targetIndex !== -1) {
            cards.splice(targetIndex, 0, movedCard);
          } else {
            cards.push(movedCard);
          }
        }

        if (dropIndicator.parentNode) {
          dropIndicator.parentNode.removeChild(dropIndicator);
        }

        renderBoard();
      });
    });

    // Helper to determine position in list based on mouse Y
    function getDragAfterElement(container, y) {
      const draggableElements = [...container.querySelectorAll('.kanban-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;
    }

    // Event Delegation: Delete card
    document.getElementById('boardContainer').addEventListener('click', (e) => {
      const deleteBtn = e.target.closest('[data-delete-id]');
      if (deleteBtn) {
        const idToDelete = deleteBtn.getAttribute('data-delete-id');
        cards = cards.filter(c => c.id !== idToDelete);
        renderBoard();
        return;
      }

      const quickAddBtn = e.target.closest('[data-add-to]');
      if (quickAddBtn) {
        const targetCol = quickAddBtn.getAttribute('data-add-to');
        taskColumnSelect.value = targetCol;
        openModal();
      }
    });

    // Search filter
    searchInput.addEventListener('input', (e) => {
      searchQuery = e.target.value.trim();
      renderBoard();
    });

    // Modal controls
    function openModal() {
      cardModal.classList.add('active');
      taskTitleInput.value = '';
      setTimeout(() => taskTitleInput.focus(), 100);
    }

    function closeModal() {
      cardModal.classList.remove('active');
      addCardForm.reset();
    }

    openModalBtn.addEventListener('click', () => {
      taskColumnSelect.value = 'todo';
      openModal();
    });

    closeModalBtn.addEventListener('click', closeModal);
    cancelModalBtn.addEventListener('click', closeModal);

    cardModal.addEventListener('click', (e) => {
      if (e.target === cardModal) closeModal();
    });

    window.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && cardModal.classList.contains('active')) {
        closeModal();
      }
    });

    // Add Card Form Submission
    addCardForm.addEventListener('submit', (e) => {
      e.preventDefault();
      const title = taskTitleInput.value.trim();
      if (!title) return;

      const priority = document.querySelector('input[name="priority"]:checked').value;
      const column = taskColumnSelect.value;

      const newCard = {
        id: `TASK-${nextTaskId++}`,
        title,
        priority,
        column
      };

      cards.unshift(newCard);
      closeModal();
      renderBoard();
    });

    // Theme toggle
    themeToggleBtn.addEventListener('click', () => {
      isDarkTheme = !isDarkTheme;
      document.body.setAttribute('data-theme', isDarkTheme ? 'dark' : 'light');
      
      if (isDarkTheme) {
        themeIcon.innerHTML = `
          <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>
        `;
      } else {
        themeIcon.innerHTML = `<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>`;
      }
    });

    // Initial render
    renderBoard();
  </script>
</body>
</html>
Reasoning trace (2,183 tokens)
**Building Interactive Kanban**

I'm currently focusing on structuring the HTML for the Kanban board, including creating the three distinct columns with their respective titles and placeholder areas for cards. My next step is to implement the visual styling using CSS to ensure a clean and responsive layout, followed by populating the initial data.

**Designing Kanban Card Elements**

I'm now concentrating on the specific components within each Kanban card. My current focus is on integrating the title, a priority badge with distinct color coding for high, medium, and low, and a delete button. This is being followed by the development of the modal for adding new cards.

**Visualizing Drop Targets**

I'm focusing on the visual cues for drag and drop functionality. My current task involves developing the distinct placeholder element, likely a line or box, that will clearly indicate where a card will be placed when dropped. This will be followed by refining the overall header elements and column styling.

**Adding Drop Functionality**

I'm focusing on enabling drag and drop for the Kanban cards. I've implemented the necessary event handlers on both the cards and the columns, and I'm now refining the logic to accurately determine the drop target and insert a dynamic placeholder to visualize the drop location.

**Implementing Card Reordering**

I'm working on updating the data structure when cards are dropped. My current focus is on accurately identifying the source column, the target column, and the precise position within the target column's array to correctly reorder the cards, then I will focus on filtering and modals.

**Designing Theme Toggles**

I'm currently focused on the user interface for theme switching. My primary task is developing a toggle button with sun and moon SVG icons, allowing for a seamless transition between light and dark modes, and I will then implement the smooth animation for this change.

**Refining Dragging Mechanics**

I'm currently focused on the finer points of drag and drop, specifically ensuring smooth transitions when dropping cards. This involves implementing precise logic to handle edge cases like dropping into empty columns or between existing cards, and refining the visual feedback for drop targets.

**Optimizing Card Insertion**

I'm solidifying the card insertion algorithm, dynamically creating and inserting a `.drop-indicator` element at the precise `afterElement`. Upon dropping, I'll accurately identify the destination column and target position to reorder the `cards` array and then re-render the board.