Models 44

Muse Ember

Open in new window

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

How it went

Total time
29.0 s
Cost
$0.0091
Output tokens
18,077
Spent thinking
9,179 tokens
Speed
675 tok/s
Console errors
0
First token after
2.2 s
First visible text after
20.6 s
Prompt tokens
511
Code size
29.3 KB
Finish reason
stop
Served by
Meta
Model id
meta/muse-ember
Reasoning sent
model default
Max output
943,718 tokens
Generated
Nov 12, 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 · 591 lines

<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flowboard — Kanban Board</title>
<style>
  *{box-sizing:border-box;margin:0;padding:0}
  :root{
    --bg:#f4f5f8; --surface:#ffffff; --surface2:#eef0f4; --surface3:#f8f9fb;
    --border:#e2e5ec; --border2:#d4d9e3; --text:#161a22; --muted:#6b7280; --muted2:#9aa1af;
    --accent:#6366f1; --accent2:#8b5cf6; --accent-soft:rgba(99,102,241,.10);
    --shadow:0 1px 2px rgba(15,17,23,.05),0 4px 14px rgba(15,17,23,.05);
    --shadow-lg:0 18px 50px rgba(15,17,23,.22);
  }
  [data-theme="dark"]{
    --bg:#0d0f13; --surface:#171a21; --surface2:#12141a; --surface3:#1c2029;
    --border:#262b36; --border2:#323a49; --text:#f2f4f8; --muted:#9aa3b2; --muted2:#6e7889;
    --accent:#818cf8; --accent2:#a78bfa; --accent-soft:rgba(129,140,248,.14);
    --shadow:0 1px 2px rgba(0,0,0,.35),0 4px 14px rgba(0,0,0,.25);
    --shadow-lg:0 18px 50px rgba(0,0,0,.6);
  }
  html,body{height:100%}
  body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--text);overflow-x:hidden;-webkit-font-smoothing:antialiased}
  button,input{font:inherit}
  button{cursor:pointer}
  :focus-visible{outline:2px solid var(--accent);outline-offset:2px}

  /* Header */
  .topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;padding:16px 28px;background:var(--surface);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:30}
  .brand{display:flex;align-items:center;gap:12px;min-width:0}
  .logo{width:44px;height:44px;border-radius:13px;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:grid;place-items:center;flex:0 0 auto;box-shadow:0 6px 16px rgba(99,102,241,.35)}
  .brand h1{font-size:21px;line-height:1;letter-spacing:-.02em}
  .brand p{font-size:12.5px;color:var(--muted);margin-top:4px;white-space:nowrap}
  .controls{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  .search-wrap{position:relative;flex:1 1 260px;min-width:220px;max-width:420px}
  .search-wrap svg{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--muted2);pointer-events:none}
  .search-wrap input{width:100%;padding:11px 38px 11px 40px;border:1px solid var(--border);background:var(--surface2);color:var(--text);border-radius:999px;font-size:14px;outline:none;transition:border-color .15s,background .15s,box-shadow .15s}
  .search-wrap input::placeholder{color:var(--muted2)}
  .search-wrap input:focus{border-color:var(--accent);background:var(--surface);box-shadow:0 0 0 3px var(--accent-soft)}
  .clear-search{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:26px;height:26px;border:none;border-radius:50%;background:var(--surface3);color:var(--muted);font-size:18px;line-height:1;display:grid;place-items:center}
  .clear-search:hover{background:var(--border);color:var(--text)}
  .icon-btn{width:42px;height:42px;border-radius:50%;border:1px solid var(--border);background:var(--surface);color:var(--text);display:grid;place-items:center;flex:0 0 auto;transition:background .15s,border-color .15s,transform .15s}
  .icon-btn:hover{background:var(--surface2);border-color:var(--border2);transform:translateY(-1px)}
  .icon-btn.small{width:34px;height:34px;font-size:22px;border:none;background:var(--surface2)}
  [data-theme="light"] .icon-sun{display:none}
  [data-theme="dark"] .icon-moon{display:none}
  .btn-primary{border:none;background:linear-gradient(135deg,#6366f1,#7c5cf6);color:#fff;font-weight:700;font-size:14px;padding:11px 19px;border-radius:999px;box-shadow:0 6px 16px rgba(99,102,241,.35);transition:transform .15s,box-shadow .15s,filter .15s;white-space:nowrap}
  .btn-primary:hover{transform:translateY(-1px);filter:brightness(1.06);box-shadow:0 9px 22px rgba(99,102,241,.42)}
  .btn-primary:active{transform:translateY(0)}
  .btn-ghost{border:1px solid var(--border);background:var(--surface);color:var(--text);font-weight:600;font-size:14px;padding:11px 18px;border-radius:999px}
  .btn-ghost:hover{background:var(--surface2)}

  /* Board meta */
  .board-meta{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding:18px 28px 2px}
  .meta-left{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
  .meta-title{font-size:17px;font-weight:800;letter-spacing:-.02em}
  .meta-sub{font-size:13px;color:var(--muted)}
  .progress-track{flex:1 1 160px;min-width:140px;height:9px;background:var(--surface2);border:1px solid var(--border);border-radius:999px;overflow:hidden}
  .progress-fill{height:100%;width:0%;background:linear-gradient(90deg,#22c55e,#4ade80);border-radius:999px;transition:width .5s ease}
  .meta-hint{font-size:12.5px;color:var(--muted2);white-space:nowrap}

  /* Board */
  .board{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;padding:16px 28px 6px;align-items:start}
  .column{background:var(--surface2);border:1px solid var(--border);border-radius:18px;padding:14px;min-height:380px;display:flex;flex-direction:column;transition:border-color .15s,box-shadow .15s}
  .column:has(.drag-over){border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
  .col-header{display:flex;align-items:center;gap:9px;padding:2px 2px 13px}
  .col-dot{width:10px;height:10px;border-radius:50%;flex:0 0 auto}
  .dot-todo{background:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.18)}
  .dot-progress{background:#f59e0b;box-shadow:0 0 0 3px rgba(245,158,11,.18)}
  .dot-done{background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,.18)}
  .col-header h2{font-size:15px;font-weight:800;letter-spacing:-.01em}
  .count{margin-left:2px;background:var(--surface);border:1px solid var(--border);color:var(--muted);font-size:12px;font-weight:800;min-width:26px;height:24px;padding:0 7px;border-radius:999px;display:grid;place-items:center}
  .col-add{margin-left:auto;width:30px;height:30px;border-radius:9px;border:1px solid var(--border);background:var(--surface);color:var(--muted);font-size:19px;line-height:1;display:grid;place-items:center;transition:all .15s}
  .col-add:hover{background:var(--accent);border-color:var(--accent);color:#fff}

  .cards{display:flex;flex-direction:column;gap:12px;flex:1;border-radius:14px;padding:2px;min-height:120px;transition:background .15s}
  .cards.drag-over{background:var(--accent-soft)}

  /* Card */
  .card{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:14px;box-shadow:var(--shadow);cursor:grab;user-select:none;transition:transform .16s ease,box-shadow .16s ease,border-color .16s ease,opacity .16s ease;animation:popIn .28s ease both}
  .card:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(15,17,23,.10);border-color:var(--border2)}
  .card:active{cursor:grabbing}
  .card.dragging{opacity:.45;transform:rotate(2deg) scale(.98);box-shadow:var(--shadow-lg);cursor:grabbing}
  .card.removing{opacity:0;transform:scale(.94) translateX(12px)}
  .card.flash{animation:flash 1.4s ease both}
  @keyframes popIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
  @keyframes flash{0%{box-shadow:0 0 0 0 rgba(99,102,241,.55)}35%{box-shadow:0 0 0 6px rgba(99,102,241,.18)}100%{box-shadow:var(--shadow)}}
  .card-top{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:9px}
  .badge{font-size:11px;letter-spacing:.07em;text-transform:uppercase;font-weight:800;padding:4px 9px;border-radius:999px;display:inline-flex;align-items:center;gap:6px}
  .badge::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
  .badge-low{background:#dcfce7;color:#166534}
  .badge-medium{background:#fef3c7;color:#92400e}
  .badge-high{background:#fee2e2;color:#991b1b}
  [data-theme="dark"] .badge-low{background:rgba(34,197,94,.18);color:#4ade80}
  [data-theme="dark"] .badge-medium{background:rgba(245,158,11,.18);color:#fbbf24}
  [data-theme="dark"] .badge-high{background:rgba(239,68,68,.18);color:#f87171}
  .delete-btn{width:28px;height:28px;border:none;border-radius:8px;background:transparent;color:var(--muted2);font-size:20px;line-height:1;display:grid;place-items:center;transition:all .15s;flex:0 0 auto}
  .delete-btn:hover{background:#fee2e2;color:#dc2626;transform:scale(1.06)}
  [data-theme="dark"] .delete-btn:hover{background:rgba(239,68,68,.18);color:#f87171}
  .card-title{font-size:15px;line-height:1.35;font-weight:700;letter-spacing:-.01em}
  .card-desc{font-size:13px;line-height:1.5;color:var(--muted);margin-top:6px}
  .card-meta{display:flex;align-items:center;gap:8px;margin-top:13px;padding-top:11px;border-top:1px solid var(--border)}
  .avatar{width:27px;height:27px;border-radius:50%;background:linear-gradient(135deg,#6366f1,#ec4899);color:#fff;font-size:11px;font-weight:800;display:grid;place-items:center;flex:0 0 auto}
  .meta-name{font-size:12.5px;color:var(--muted);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .drag-hint{margin-left:auto;font-size:11.5px;color:var(--muted2);white-space:nowrap}
  .empty-state{border:1.5px dashed var(--border2);border-radius:12px;padding:20px 14px;text-align:center;color:var(--muted2);font-size:13px;line-height:1.5}
  .drop-indicator{height:74px;min-height:74px;border:2px dashed var(--accent);background:var(--accent-soft);border-radius:14px;flex:0 0 auto}

  .foot-note{text-align:center;color:var(--muted2);font-size:12.5px;padding:16px 20px 22px}

  /* Modal */
  .modal-overlay{position:fixed;inset:0;background:rgba(13,15,20,.58);backdrop-filter:blur(6px);display:grid;place-items:center;padding:20px;opacity:0;pointer-events:none;transition:opacity .2s ease;z-index:50}
  .modal-overlay.show{opacity:1;pointer-events:auto}
  .modal{width:100%;max-width:470px;background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:22px;box-shadow:var(--shadow-lg);transform:translateY(10px) scale(.98);transition:transform .22s ease}
  .modal-overlay.show .modal{transform:translateY(0) scale(1)}
  .modal-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:18px}
  .modal-header h3{font-size:18px;letter-spacing:-.02em}
  .field{display:block;margin-bottom:16px}
  .field>span{display:block;font-size:13px;font-weight:700;margin-bottom:8px}
  .field>span em{color:#dc2626;font-style:normal}
  .field input[type="text"]{width:100%;padding:12px 13px;border:1px solid var(--border);border-radius:12px;background:var(--surface2);color:var(--text);font-size:14px;outline:none;transition:border-color .15s,box-shadow .15s,background .15s}
  .field input[type="text"]:focus{border-color:var(--accent);background:var(--surface);box-shadow:0 0 0 3px var(--accent-soft)}
  .field input.invalid{border-color:#dc2626;box-shadow:0 0 0 3px rgba(220,38,38,.12)}
  .error{display:none;color:#dc2626;font-size:12.5px;margin:-8px 0 14px}
  .error.show{display:block}
  .segmented{display:flex;gap:8px;flex-wrap:wrap}
  .seg-btn{flex:1 1 0;min-width:0;padding:10px 8px;border:1px solid var(--border);border-radius:12px;background:var(--surface2);color:var(--muted);font-weight:700;font-size:13px;display:flex;align-items:center;justify-content:center;gap:7px;transition:all .15s}
  .seg-btn:hover{border-color:var(--border2);color:var(--text)}
  .seg-btn.active{border-color:var(--accent);background:var(--accent-soft);color:var(--text)}
  .p-dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto}
  .p-low{background:#22c55e}.p-medium{background:#f59e0b}.p-high{background:#ef4444}
  .c-dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto}
  .modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:22px}

  @media (max-width:900px){
    .board{grid-template-columns:1fr;padding:14px 18px 6px}
    .topbar{padding:14px 18px}
    .board-meta{padding:16px 18px 2px}
    .column{min-height:0}
    .meta-hint{display:none}
  }
  @media (max-width:560px){
    .topbar{align-items:stretch}
    .controls{width:100%}
    .search-wrap{flex:1 1 100%;max-width:none;order:3}
    .brand p{display:none}
    #addCardBtn{flex:1}
    .board{padding:12px 14px 6px}
    .board-meta{padding:14px 14px 2px}
    .seg-btn{flex:1 1 100%}
  }
</style>
</head>
<body>

<header class="topbar">
  <div class="brand">
    <div class="logo" aria-hidden="true">
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round"><rect x="3" y="3" width="5" height="13" rx="1.5"/><rect x="10" y="3" width="5" height="9" rx="1.5"/><rect x="17" y="3" width="4" height="16" rx="1.5"/></svg>
    </div>
    <div>
      <h1>Flowboard</h1>
      <p>Product Launch &bull; Sprint 12</p>
    </div>
  </div>
  <div class="controls">
    <div class="search-wrap">
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>
      <input id="searchInput" type="text" placeholder="Search cards by title..." autocomplete="off" aria-label="Search cards by title">
      <button id="clearSearch" class="clear-search" type="button" hidden aria-label="Clear search">&times;</button>
    </div>
    <button id="themeToggle" class="icon-btn" type="button" aria-label="Toggle light / dark theme" title="Toggle theme">
      <svg class="icon-moon" width="19" height="19" 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"/></svg>
      <svg class="icon-sun" width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
    </button>
    <button id="addCardBtn" class="btn-primary" type="button">+ Add card</button>
  </div>
</header>

<div class="board-meta">
  <div class="meta-left">
    <span class="meta-title">Sprint board</span>
    <span class="meta-sub" id="progressText">2 of 6 done</span>
  </div>
  <div class="progress-track" aria-hidden="true"><div class="progress-fill" id="progressFill"></div></div>
  <span class="meta-hint">&#8596; Drag cards between columns</span>
</div>

<main class="board" id="board">
  <section class="column" aria-label="To do column">
    <header class="col-header">
      <span class="col-dot dot-todo"></span><h2>To do</h2><span class="count" id="count-todo">0</span>
      <button class="col-add" type="button" data-add="todo" aria-label="Add card to To do">+</button>
    </header>
    <div class="cards" data-column="todo" id="list-todo"></div>
  </section>

  <section class="column" aria-label="In progress column">
    <header class="col-header">
      <span class="col-dot dot-progress"></span><h2>In progress</h2><span class="count" id="count-progress">0</span>
      <button class="col-add" type="button" data-add="progress" aria-label="Add card to In progress">+</button>
    </header>
    <div class="cards" data-column="progress" id="list-progress"></div>
  </section>

  <section class="column" aria-label="Done column">
    <header class="col-header">
      <span class="col-dot dot-done"></span><h2>Done</h2><span class="count" id="count-done">0</span>
      <button class="col-add" type="button" data-add="done" aria-label="Add card to Done">+</button>
    </header>
    <div class="cards" data-column="done" id="list-done"></div>
  </section>
</main>

<p class="foot-note">Search filters live by title &bull; Click &times; on a card to delete it &bull; State lives in memory only</p>

<div class="modal-overlay" id="modalOverlay" aria-hidden="true">
  <div class="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
    <div class="modal-header">
      <h3 id="modalTitle">Add a new card</h3>
      <button class="icon-btn small" id="closeModal" type="button" aria-label="Close dialog">&times;</button>
    </div>
    <form id="addForm" novalidate>
      <label class="field">
        <span>Title <em>*</em></span>
        <input id="titleInput" type="text" placeholder="e.g. Design new landing page" maxlength="120" autocomplete="off">
      </label>
      <p class="error" id="titleError">Please enter a title for the card.</p>

      <div class="field">
        <span>Priority</span>
        <div class="segmented" id="priorityOptions">
          <button type="button" class="seg-btn" data-priority="low"><span class="p-dot p-low"></span>Low</button>
          <button type="button" class="seg-btn active" data-priority="medium"><span class="p-dot p-medium"></span>Medium</button>
          <button type="button" class="seg-btn" data-priority="high"><span class="p-dot p-high"></span>High</button>
        </div>
      </div>

      <div class="field">
        <span>Column</span>
        <div class="segmented" id="columnOptions">
          <button type="button" class="seg-btn active" data-column-val="todo"><span class="c-dot" style="background:#3b82f6"></span>To do</button>
          <button type="button" class="seg-btn" data-column-val="progress"><span class="c-dot" style="background:#f59e0b"></span>In progress</button>
          <button type="button" class="seg-btn" data-column-val="done"><span class="c-dot" style="background:#22c55e"></span>Done</button>
        </div>
      </div>

      <div class="modal-actions">
        <button type="button" class="btn-ghost" id="cancelBtn">Cancel</button>
        <button type="submit" class="btn-primary">Add card</button>
      </div>
    </form>
  </div>
</div>

<script>
(function(){
  "use strict";

  var searchInput = document.getElementById('searchInput');
  var clearSearch = document.getElementById('clearSearch');
  var themeToggle = document.getElementById('themeToggle');
  var addCardBtn = document.getElementById('addCardBtn');
  var board = document.getElementById('board');
  var progressFill = document.getElementById('progressFill');
  var progressText = document.getElementById('progressText');
  var modalOverlay = document.getElementById('modalOverlay');
  var addForm = document.getElementById('addForm');
  var titleInput = document.getElementById('titleInput');
  var titleError = document.getElementById('titleError');
  var priorityOptions = document.getElementById('priorityOptions');
  var columnOptions = document.getElementById('columnOptions');

  var cards = [
    {id:'c1', title:'Design new onboarding flow', priority:'high', column:'todo', desc:'Create wireframes and an interactive prototype for the 3-step signup.', assignee:'AK', name:'Ava Kim'},
    {id:'c2', title:'Write API documentation', priority:'medium', column:'todo', desc:'Document auth endpoints, error codes and rate limits for v2.', assignee:'JM', name:'James Miller'},
    {id:'c3', title:'Fix checkout payment bug', priority:'high', column:'progress', desc:'Stripe webhook fails on Safari — investigate the retry logic.', assignee:'SR', name:'Sara Rossi'},
    {id:'c4', title:'Build search autocomplete', priority:'medium', column:'progress', desc:'Debounced suggestions with full keyboard navigation support.', assignee:'LT', name:'Leo Turner'},
    {id:'c5', title:'Ship v2.1 release notes', priority:'low', column:'done', desc:'Changelog, blog post and in-app announcement for the release.', assignee:'AK', name:'Ava Kim'},
    {id:'c6', title:'Refactor auth middleware', priority:'medium', column:'done', desc:'Split into token, session and permissions modules with tests.', assignee:'JM', name:'James Miller'}
  ];

  var filter = '';
  var dragId = null;
  var selectedPriority = 'medium';
  var selectedColumn = 'todo';

  var placeholder = document.createElement('div');
  placeholder.className = 'drop-indicator';
  placeholder.setAttribute('aria-hidden','true');

  function createCardElement(card){
    var el = document.createElement('article');
    el.className = 'card';
    el.draggable = true;
    el.dataset.id = card.id;
    el.dataset.column = card.column;

    var top = document.createElement('div');
    top.className = 'card-top';

    var badge = document.createElement('span');
    badge.className = 'badge badge-' + card.priority;
    badge.textContent = card.priority;

    var del = document.createElement('button');
    del.className = 'delete-btn';
    del.type = 'button';
    del.title = 'Delete card';
    del.setAttribute('aria-label','Delete ' + card.title);
    del.dataset.id = card.id;
    del.textContent = '\u00D7';

    top.appendChild(badge);
    top.appendChild(del);

    var title = document.createElement('h3');
    title.className = 'card-title';
    title.textContent = card.title;

    el.appendChild(top);
    el.appendChild(title);

    if(card.desc){
      var desc = document.createElement('p');
      desc.className = 'card-desc';
      desc.textContent = card.desc;
      el.appendChild(desc);
    }

    var meta = document.createElement('div');
    meta.className = 'card-meta';
    var avatar = document.createElement('span');
    avatar.className = 'avatar';
    avatar.textContent = card.assignee || 'YO';
    avatar.title = card.name || 'You';
    var name = document.createElement('span');
    name.className = 'meta-name';
    name.textContent = card.name || 'You';
    var hint = document.createElement('span');
    hint.className = 'drag-hint';
    hint.textContent = '\u2807 Drag';
    meta.appendChild(avatar);
    meta.appendChild(name);
    meta.appendChild(hint);
    el.appendChild(meta);

    return el;
  }

  function render(){
    var cols = ['todo','progress','done'];
    cols.forEach(function(col){
      var list = document.getElementById('list-' + col);
      var countEl = document.getElementById('count-' + col);
      var all = cards.filter(function(c){ return c.column === col; });
      countEl.textContent = String(all.length);
      list.innerHTML = '';
      var visible = all.filter(function(c){
        return !filter || c.title.toLowerCase().indexOf(filter) !== -1;
      });
      if(visible.length === 0){
        var empty = document.createElement('div');
        empty.className = 'empty-state';
        empty.textContent = filter
          ? 'No cards match "' + searchInput.value + '"'
          : 'No cards here — drag one in or add a new card.';
        list.appendChild(empty);
      } else {
        visible.forEach(function(card){ list.appendChild(createCardElement(card)); });
      }
    });
    var total = cards.length;
    var done = cards.filter(function(c){ return c.column === 'done'; }).length;
    var pct = total ? Math.round(done / total * 100) : 0;
    progressFill.style.width = pct + '%';
    progressText.textContent = total ? (done + ' of ' + total + ' done \u2022 ' + pct + '% complete') : 'No cards yet';
  }

  /* ---- Search (live by title) ---- */
  searchInput.addEventListener('input', function(){
    filter = searchInput.value.trim().toLowerCase();
    clearSearch.hidden = !searchInput.value;
    render();
  });
  clearSearch.addEventListener('click', function(){
    searchInput.value = '';
    filter = '';
    clearSearch.hidden = true;
    render();
    searchInput.focus();
  });

  /* ---- Theme toggle (memory only) ---- */
  themeToggle.addEventListener('click', function(){
    var html = document.documentElement;
    html.dataset.theme = html.dataset.theme === 'dark' ? 'light' : 'dark';
  });

  /* ---- Delete (delegated) ---- */
  board.addEventListener('click', function(e){
    var btn = e.target.closest('.delete-btn');
    if(!btn) return;
    var id = btn.dataset.id;
    var cardEl = btn.closest('.card');
    if(cardEl){
      cardEl.classList.add('removing');
      setTimeout(function(){
        cards = cards.filter(function(c){ return c.id !== id; });
        render();
      }, 180);
    } else {
      cards = cards.filter(function(c){ return c.id !== id; });
      render();
    }
  });

  /* ---- Add buttons in column headers ---- */
  document.querySelectorAll('[data-add]').forEach(function(btn){
    btn.addEventListener('click', function(){ openModal(btn.dataset.add); });
  });

  /* ---- Drag & drop ---- */
  function getDragAfterElement(list, y){
    var els = Array.prototype.slice.call(list.querySelectorAll('.card:not(.dragging)'));
    for(var i=0;i<els.length;i++){
      var r = els[i].getBoundingClientRect();
      if(y < r.top + r.height / 2) return els[i];
    }
    return null;
  }

  board.addEventListener('dragstart', function(e){
    var cardEl = e.target.closest('.card');
    if(!cardEl) return;
    dragId = cardEl.dataset.id;
    cardEl.classList.add('dragging');
    e.dataTransfer.effectAllowed = 'move';
    try{ e.dataTransfer.setData('text/plain', dragId); }catch(err){}
  });

  board.addEventListener('dragend', function(e){
    var cardEl = e.target.closest('.card');
    if(cardEl) cardEl.classList.remove('dragging');
    dragId = null;
    if(placeholder.parentNode) placeholder.remove();
    document.querySelectorAll('.drag-over').forEach(function(el){ el.classList.remove('drag-over'); });
  });

  document.querySelectorAll('.cards').forEach(function(list){
    list.addEventListener('dragover', function(e){
      if(!dragId) return;
      e.preventDefault();
      e.dataTransfer.dropEffect = 'move';
      list.classList.add('drag-over');
      var after = getDragAfterElement(list, e.clientY);
      if(after === null){ list.appendChild(placeholder); }
      else { list.insertBefore(placeholder, after); }
    });
    list.addEventListener('dragleave', function(e){
      if(!list.contains(e.relatedTarget)){
        list.classList.remove('drag-over');
        if(placeholder.parentNode === list) placeholder.remove();
      }
    });
    list.addEventListener('drop', function(e){
      e.preventDefault();
      list.classList.remove('drag-over');
      var targetColumn = list.dataset.column;
      if(!dragId){ if(placeholder.parentNode) placeholder.remove(); return; }

      var insertIndex = Array.prototype.slice.call(list.querySelectorAll('.card:not(.dragging)')).length;
      if(placeholder.parentNode === list){
        var count = 0;
        for(var i=0;i<list.children.length;i++){
          if(list.children[i] === placeholder) break;
          if(list.children[i].classList && list.children[i].classList.contains('card')) count++;
        }
        insertIndex = count;
      }
      if(placeholder.parentNode) placeholder.remove();

      var idx = cards.findIndex(function(c){ return c.id === dragId; });
      if(idx === -1){ dragId = null; return; }
      var moved = cards.splice(idx,1)[0];
      moved.column = targetColumn;

      var colCards = cards.filter(function(c){ return c.column === targetColumn; });
      if(insertIndex >= colCards.length){
        if(colCards.length === 0){ cards.push(moved); }
        else {
          var lastIdx = cards.findIndex(function(c){ return c.id === colCards[colCards.length-1].id; });
          cards.splice(lastIdx + 1, 0, moved);
        }
      } else {
        var beforeIdx = cards.findIndex(function(c){ return c.id === colCards[insertIndex].id; });
        cards.splice(beforeIdx, 0, moved);
      }
      dragId = null;
      render();
    });
  });

  /* ---- Modal ---- */
  function syncSegUI(){
    priorityOptions.querySelectorAll('.seg-btn').forEach(function(b){
      b.classList.toggle('active', b.dataset.priority === selectedPriority);
    });
    columnOptions.querySelectorAll('.seg-btn').forEach(function(b){
      b.classList.toggle('active', b.dataset.columnVal === selectedColumn);
    });
  }
  priorityOptions.addEventListener('click', function(e){
    var btn = e.target.closest('.seg-btn');
    if(!btn) return;
    selectedPriority = btn.dataset.priority;
    syncSegUI();
  });
  columnOptions.addEventListener('click', function(e){
    var btn = e.target.closest('.seg-btn');
    if(!btn) return;
    selectedColumn = btn.dataset.columnVal;
    syncSegUI();
  });

  function openModal(col){
    selectedColumn = col || 'todo';
    syncSegUI();
    titleInput.value = '';
    titleError.classList.remove('show');
    titleInput.classList.remove('invalid');
    modalOverlay.classList.add('show');
    modalOverlay.setAttribute('aria-hidden','false');
    setTimeout(function(){ titleInput.focus(); }, 60);
  }
  function closeModal(){
    modalOverlay.classList.remove('show');
    modalOverlay.setAttribute('aria-hidden','true');
  }

  addCardBtn.addEventListener('click', function(){ openModal('todo'); });
  document.getElementById('closeModal').addEventListener('click', closeModal);
  document.getElementById('cancelBtn').addEventListener('click', closeModal);
  modalOverlay.addEventListener('click', function(e){ if(e.target === modalOverlay) closeModal(); });
  document.addEventListener('keydown', function(e){
    if(e.key === 'Escape' && modalOverlay.classList.contains('show')) closeModal();
  });
  titleInput.addEventListener('input', function(){
    titleError.classList.remove('show');
    titleInput.classList.remove('invalid');
  });

  addForm.addEventListener('submit', function(e){
    e.preventDefault();
    var title = titleInput.value.trim();
    if(!title){
      titleError.classList.add('show');
      titleInput.classList.add('invalid');
      titleInput.focus();
      return;
    }
    var newCard = {
      id: 'c' + Date.now().toString(36) + Math.floor(Math.random()*999),
      title: title,
      priority: selectedPriority,
      column: selectedColumn,
      desc: '',
      assignee: 'YO',
      name: 'You'
    };
    cards.push(newCard);
    if(filter){
      searchInput.value = '';
      filter = '';
      clearSearch.hidden = true;
    }
    closeModal();
    render();
    var el = document.querySelector('.card[data-id="' + newCard.id + '"]');
    if(el){
      el.classList.add('flash');
      el.scrollIntoView({behavior:'smooth', block:'center'});
    }
  });

  render();
})();
</script>
</body>
</html>
Reasoning trace (9,179 tokens)
Implementing a single-file HTML kanban board with drag-and-drop, filtering, theming, and responsive layout using system fonts and in-memory state.Adding UI layout, modal form, drag-and-drop handling, search filtering, theming, and delete actions with counts and empty states.Extending the UI with theme colors, responsive grid, drag-and-drop ordering, and modal form validation.Adding CSS variables, responsive layout, drag-and-drop styling, and modal form details.Defining color tokens, badge styles, card markup, and initial data with DOM rendering and event delegation.Adding drag-and-drop handlers with placeholder insertion and modal form validation for card creation.Extending UI with progress bar, theme toggle, accessibility labels, and delete animations.Implementing segmented button styling, drag-and-drop handlers, and card rendering with validation and theme logic.Adding document-level add-button listeners, drag-over handling, modal open/close logic, and theme and search event bindings.Defining modal, segmented control, badge, avatar, empty state, and responsive CSS with theme overrides and focus styles.