Models 44

GPT-6 Luna Pro

by OpenAIreasoning defaultClean
Open in new window

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

How it went

Total time
1 min 44 s
Cost
$0.014
Output tokens
23,038
Spent thinking
4,203 tokens
Speed
8484.5 tok/s
Console errors
0
First token after
1 min 41 s
First visible text after
1 min 43 s
Prompt tokens
23,904
Code size
30.2 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6-luna-pro
Reasoning sent
model default
Max output
128,000 tokens
Generated
Nov 13, 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 · 660 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Orbit — Product launch board</title>
<style>
  :root {
    color-scheme: light;
    --page: #f5f6fa;
    --surface: #ffffff;
    --surface-2: #f8f9fc;
    --text: #202336;
    --muted: #83889b;
    --line: #e9eaf0;
    --accent: #6558df;
    --accent-soft: #f0efff;
    --shadow: 0 2px 8px rgba(34, 39, 68, .045), 0 12px 30px rgba(34, 39, 68, .025);
  }

  * { box-sizing: border-box; }
  body {
    margin: 0;
    min-width: 320px;
    background: var(--page);
    color: var(--text);
    font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    font-size: 14px;
    transition: background .2s, color .2s;
  }
  body.dark {
    color-scheme: dark;
    --page: #171923;
    --surface: #20222f;
    --surface-2: #252735;
    --text: #eef0fa;
    --muted: #a1a5b8;
    --line: #343746;
    --accent: #9b90ff;
    --accent-soft: #302d4c;
    --shadow: 0 3px 12px rgba(0, 0, 0, .15);
  }
  button, input, select { font: inherit; }
  button { color: inherit; }
  .topbar {
    height: 68px;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    padding: 0 max(28px, calc((100vw - 1190px) / 2));
    gap: 34px;
  }
  .brand {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 17px;
    font-weight: 750;
    letter-spacing: -.5px;
    white-space: nowrap;
  }
  .brand-mark {
    width: 29px;
    height: 29px;
    border-radius: 9px;
    display: grid;
    place-items: center;
    color: white;
    background: linear-gradient(145deg, #8275fa, #5b4bd4);
    box-shadow: 0 4px 10px rgba(101, 88, 223, .24);
  }
  .brand-mark svg { width: 17px; height: 17px; }
  .top-nav { display: flex; align-items: center; gap: 28px; height: 100%; }
  .top-nav a {
    height: 100%;
    display: flex;
    align-items: center;
    position: relative;
    text-decoration: none;
    color: var(--muted);
    font-weight: 550;
  }
  .top-nav a.active { color: var(--text); }
  .top-nav a.active::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: -1px;
    height: 2px;
    background: var(--accent);
    border-radius: 2px 2px 0 0;
  }
  .top-right { margin-left: auto; display: flex; align-items: center; gap: 14px; }
  .team-avatars { display: flex; padding-left: 4px; }
  .avatar {
    width: 29px;
    height: 29px;
    margin-left: -5px;
    display: inline-grid;
    place-items: center;
    border-radius: 50%;
    border: 2px solid var(--surface);
    color: #fff;
    font-size: 9px;
    font-weight: 750;
    letter-spacing: .15px;
  }
  .av-lilac { background: #8a79df; }
  .av-coral { background: #e28472; }
  .av-teal { background: #51a99c; }
  .av-blue { background: #5486c8; }
  .avatar.more { background: var(--surface-2); color: var(--muted); border-color: var(--surface); font-size: 9px; }
  .top-divider { height: 24px; width: 1px; background: var(--line); }
  .icon-btn {
    width: 35px; height: 35px;
    display: grid; place-items: center;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    cursor: pointer;
    transition: background .15s, border .15s, transform .15s;
  }
  .icon-btn:hover { background: var(--surface-2); border-color: #d9d9e8; }
  .icon-btn:active { transform: scale(.96); }
  .icon-btn svg { width: 17px; height: 17px; color: var(--muted); }

  main { max-width: 1190px; margin: 0 auto; padding: 30px 24px 44px; }
  .crumbs {
    display: flex; align-items: center; gap: 9px;
    color: var(--muted); font-size: 12px; font-weight: 550;
    margin-bottom: 17px;
  }
  .crumb-dot { width: 7px; height: 7px; border-radius: 2px; background: #e9a655; }
  .crumb-sep { color: #c2c4d0; font-size: 16px; font-weight: 400; }
  .project-heading {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
    margin-bottom: 23px;
  }
  h1 { margin: 0; font-size: 27px; line-height: 1.22; letter-spacing: -.8px; font-weight: 730; }
  .subtitle { color: var(--muted); margin-top: 7px; font-size: 13px; }
  .heading-actions { display: flex; align-items: center; gap: 9px; padding-top: 3px; }
  .button {
    height: 37px;
    border-radius: 9px;
    padding: 0 13px;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    font-size: 12px; font-weight: 650;
    cursor: pointer;
    transition: transform .15s, box-shadow .15s, background .15s;
  }
  .button:active { transform: translateY(1px); }
  .button svg { width: 15px; height: 15px; }
  .button.secondary { border: 1px solid var(--line); background: var(--surface); color: var(--text); }
  .button.secondary:hover { background: var(--surface-2); }
  .button.primary {
    border: 1px solid var(--accent);
    color: white;
    background: #6558df;
    box-shadow: 0 3px 7px rgba(101, 88, 223, .18);
  }
  .button.primary:hover { background: #584bcf; box-shadow: 0 5px 12px rgba(101, 88, 223, .25); }
  body.dark .button.primary { background: #6b60d8; border-color: #6b60d8; }

  .board-toolbar {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    margin-bottom: 17px;
  }
  .board-tabs { display: flex; align-items: center; gap: 22px; height: 35px; }
  .board-tab {
    border: 0; background: none; padding: 0;
    color: var(--muted); font-size: 12px; font-weight: 600;
    cursor: pointer; height: 100%; position: relative;
  }
  .board-tab.selected { color: var(--accent); }
  .board-tab.selected::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
    height: 2px; border-radius: 2px; background: var(--accent);
  }
  .toolbar-tools { display: flex; align-items: center; gap: 9px; }
  .search-wrap {
    width: 218px; height: 35px; display: flex; align-items: center; gap: 8px;
    padding: 0 10px; background: var(--surface);
    border: 1px solid var(--line); border-radius: 9px;
  }
  .search-wrap svg { width: 15px; height: 15px; color: #9a9daf; flex: 0 0 auto; }
  .search-wrap input {
    width: 100%; min-width: 0; background: transparent; border: 0; outline: 0;
    color: var(--text); font-size: 12px;
  }
  .search-wrap input::placeholder { color: #a2a5b5; }
  .filter-button { height: 35px; padding: 0 10px; font-size: 12px; }
  .filter-button svg { width: 14px; height: 14px; }

  .board {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
  }
  .column {
    min-width: 0;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 13px 12px 12px;
    transition: background .15s, border-color .15s, box-shadow .15s;
  }
  .column.drag-over {
    border-color: var(--accent);
    background: var(--accent-soft);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 14%, transparent);
  }
  .column-head {
    height: 25px; display: flex; align-items: center; gap: 8px;
    padding: 0 1px; margin-bottom: 11px;
  }
  .status-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
  .todo-dot { background: #999eae; }
  .progress-dot { background: #edae4e; }
  .done-dot { background: #56b392; }
  .column-title { font-size: 12px; font-weight: 700; letter-spacing: .05px; }
  .count {
    display: inline-grid; place-items: center;
    min-width: 19px; height: 19px; padding: 0 5px;
    color: var(--muted); background: var(--surface);
    border: 1px solid var(--line); border-radius: 6px;
    font-size: 10px; font-weight: 650;
  }
  .column-add {
    margin-left: auto; width: 26px; height: 26px;
    border: 0; border-radius: 7px; background: transparent; color: #9a9daf;
    display: grid; place-items: center; cursor: pointer;
  }
  .column-add:hover { background: var(--surface); color: var(--accent); }
  .column-add svg { width: 16px; height: 16px; }
  .card-list { display: flex; flex-direction: column; gap: 10px; min-height: 105px; }
  .card {
    position: relative;
    padding: 13px 13px 11px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: var(--shadow);
    cursor: grab;
    transition: border-color .15s, box-shadow .15s, opacity .15s, transform .15s;
  }
  .card:hover { border-color: #d8d9e6; box-shadow: 0 4px 13px rgba(38, 40, 72, .075); }
  body.dark .card:hover { border-color: #4a4d60; }
  .card.dragging { opacity: .42; transform: rotate(-1deg); cursor: grabbing; }
  .card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 9px; }
  .category {
    color: #8a8da0; font-size: 9px; font-weight: 750; letter-spacing: .65px;
    text-transform: uppercase;
  }
  .priority {
    display: inline-flex; align-items: center; gap: 5px;
    border-radius: 5px; padding: 4px 7px;
    font-size: 9px; line-height: 1; font-weight: 700;
    text-transform: capitalize;
  }
  .priority::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
  .priority.high { color: #d76565; background: #fff0ef; }
  .priority.medium { color: #c88b2d; background: #fff6e6; }
  .priority.low { color: #579578; background: #eaf7f0; }
  body.dark .priority.high { background: #432b31; color: #f08a8a; }
  body.dark .priority.medium { background: #453823; color: #e7b45e; }
  body.dark .priority.low { background: #243e35; color: #75c7a0; }
  .card h3 { font-size: 13px; line-height: 1.42; letter-spacing: -.1px; margin: 0 0 6px; font-weight: 680; }
  .card-desc { color: var(--muted); font-size: 10.5px; line-height: 1.45; margin: 0 0 11px; }
  .card-bottom {
    border-top: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
    padding-top: 9px;
    display: flex; align-items: center; justify-content: space-between; gap: 6px;
  }
  .due { display: flex; align-items: center; gap: 5px; color: var(--muted); font-size: 10px; white-space: nowrap; }
  .due svg { width: 12px; height: 12px; color: #a3a6b4; }
  .card-people { display: flex; align-items: center; }
  .card-people .avatar { width: 22px; height: 22px; font-size: 8px; border-color: var(--surface); }
  .delete-card {
    position: absolute; right: 8px; top: 36px; width: 25px; height: 25px;
    display: grid; place-items: center; border: 0; border-radius: 6px;
    background: var(--surface); color: #a1a4b4; opacity: 0;
    cursor: pointer; transition: opacity .15s, color .15s, background .15s;
  }
  .card:hover .delete-card, .delete-card:focus-visible { opacity: 1; }
  .delete-card:hover { color: #d85d68; background: #fff0f0; }
  .delete-card svg { width: 14px; height: 14px; }
  .drop-marker {
    height: 5px; min-height: 5px; border-radius: 5px;
    background: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
    margin: 2px 2px;
  }
  .empty-state {
    color: var(--muted); font-size: 11px; text-align: center; padding: 18px 8px;
    border: 1px dashed var(--line); border-radius: 9px;
  }
  .board-foot {
    margin-top: 15px; color: var(--muted); font-size: 10px;
    display: flex; align-items: center; gap: 6px;
  }
  .board-foot svg { width: 13px; height: 13px; }

  .modal-backdrop {
    position: fixed; inset: 0; z-index: 10;
    display: none; align-items: center; justify-content: center;
    padding: 18px; background: rgba(22, 24, 40, .44);
    backdrop-filter: blur(3px);
  }
  .modal-backdrop.open { display: flex; }
  .modal {
    width: min(100%, 410px); background: var(--surface);
    border: 1px solid var(--line); border-radius: 15px;
    padding: 23px; box-shadow: 0 22px 70px rgba(18, 20, 42, .24);
    animation: modal-in .18s ease-out;
  }
  @keyframes modal-in { from { opacity: 0; transform: translateY(8px) scale(.985); } to { opacity: 1; transform: none; } }
  .modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 19px; }
  .modal h2 { font-size: 18px; margin: 0 0 5px; letter-spacing: -.35px; }
  .modal-copy { margin: 0; font-size: 12px; color: var(--muted); }
  .modal-close {
    border: 0; background: transparent; color: var(--muted); cursor: pointer;
    width: 28px; height: 28px; border-radius: 7px; display: grid; place-items: center;
  }
  .modal-close:hover { background: var(--surface-2); }
  .modal-close svg { width: 16px; height: 16px; }
  .form-group { margin-bottom: 15px; }
  .form-group label { display: block; font-size: 11px; font-weight: 650; margin-bottom: 7px; }
  .form-group input, .form-group select {
    width: 100%; height: 39px; border-radius: 8px;
    border: 1px solid var(--line); background: var(--surface);
    color: var(--text); padding: 0 11px; outline: 0; font-size: 12px;
  }
  .form-group input:focus, .form-group select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 13%, transparent); }
  .form-group input::placeholder { color: #a3a6b4; }
  .modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 21px; }
  .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

  @media (max-width: 760px) {
    .topbar { height: 60px; padding: 0 16px; gap: 22px; }
    .top-nav { gap: 18px; }
    .top-nav a { font-size: 12px; }
    .top-right { gap: 9px; }
    .team-avatars, .top-divider { display: none; }
    main { padding: 24px 16px 35px; }
    .board { grid-template-columns: 1fr; gap: 12px; }
    .column { padding: 12px; }
    .card-list { min-height: 0; }
    .delete-card { opacity: 1; }
    .board-toolbar { align-items: flex-end; }
    .search-wrap { width: 185px; }
  }
  @media (max-width: 480px) {
    .topbar { gap: 15px; }
    .brand { font-size: 15px; }
    .brand-mark { width: 27px; height: 27px; }
    .top-nav { gap: 13px; }
    .top-nav a { font-size: 11px; }
    .top-nav a:nth-child(n+2) { display: none; }
    .top-right { margin-left: auto; }
    main { padding: 20px 13px 32px; }
    .project-heading { margin-bottom: 19px; }
    h1 { font-size: 24px; }
    .heading-actions { gap: 7px; }
    .heading-actions .button.secondary { padding: 0 9px; }
    .heading-actions .button.primary { padding: 0 10px; }
    .board-toolbar { flex-direction: column; align-items: stretch; gap: 9px; margin-bottom: 13px; }
    .board-tabs { height: 30px; }
    .toolbar-tools { width: 100%; }
    .search-wrap { flex: 1; width: auto; }
    .filter-button { flex: 0 0 auto; }
  }
</style>
</head>
<body>
<header class="topbar">
  <div class="brand">
    <span class="brand-mark" aria-hidden="true">
      <svg viewBox="0 0 24 24" fill="none"><path d="M5 7.5 12 4l7 3.5v9L12 20l-7-3.5v-9Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="m5.5 7.8 6.5 3.4 6.5-3.4M12 11.3V19" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg>
    </span>
    orbit
  </div>
  <nav class="top-nav" aria-label="Main navigation">
    <a href="#" class="active">Workspace</a>
    <a href="#">Projects</a>
    <a href="#">Inbox</a>
  </nav>
  <div class="top-right">
    <div class="team-avatars" aria-label="Project team">
      <span class="avatar av-lilac">ML</span><span class="avatar av-coral">JR</span><span class="avatar av-teal">SK</span><span class="avatar more">+2</span>
    </div>
    <span class="top-divider"></span>
    <button class="icon-btn" id="theme-toggle" aria-label="Switch to dark theme" title="Toggle theme">
      <svg id="theme-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M20.2 15.1A8.5 8.5 0 0 1 8.9 3.8 8.5 8.5 0 1 0 20.2 15.1Z"/></svg>
    </button>
  </div>
</header>

<main>
  <div class="crumbs"><span class="crumb-dot"></span><span>Acme Studio</span><span class="crumb-sep">›</span><span>Projects</span><span class="crumb-sep">›</span><span>Product launch</span></div>
  <section class="project-heading">
    <div>
      <h1>Product launch</h1>
      <div class="subtitle">Plan, track, and ship something great together.</div>
    </div>
    <div class="heading-actions">
      <button class="button secondary" id="invite-btn" type="button">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M16 21v-2a4 4 0 0 0-4-4H7a4 4 0 0 0-4 4v2M9.5 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8ZM19 8v6M22 11h-6"/></svg>
        <span>Invite</span>
      </button>
      <button class="button primary" id="add-task" type="button">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>
        Add task
      </button>
    </div>
  </section>

  <div class="board-toolbar">
    <div class="board-tabs" aria-label="Project views">
      <button class="board-tab selected" type="button">Board</button>
      <button class="board-tab" type="button">List</button>
      <button class="board-tab" type="button">Calendar</button>
    </div>
    <div class="toolbar-tools">
      <label class="search-wrap">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-4-4"/></svg>
        <input id="search" type="search" placeholder="Search tasks…" aria-label="Search tasks by title">
      </label>
      <button class="button secondary filter-button" type="button" id="filter-btn" title="Priority filter">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h16M7 12h10m-7 6h4"/></svg>
        Filter
      </button>
    </div>
  </div>

  <section class="board" aria-label="Kanban board">
    <section class="column" data-column="todo" aria-label="To do">
      <header class="column-head">
        <span class="status-dot todo-dot"></span><span class="column-title">To do</span><span class="count" id="count-todo">0</span>
        <button class="column-add" data-add-column="todo" aria-label="Add task to To do"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg></button>
      </header>
      <div class="card-list" id="list-todo"></div>
    </section>
    <section class="column" data-column="progress" aria-label="In progress">
      <header class="column-head">
        <span class="status-dot progress-dot"></span><span class="column-title">In progress</span><span class="count" id="count-progress">0</span>
        <button class="column-add" data-add-column="progress" aria-label="Add task to In progress"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg></button>
      </header>
      <div class="card-list" id="list-progress"></div>
    </section>
    <section class="column" data-column="done" aria-label="Done">
      <header class="column-head">
        <span class="status-dot done-dot"></span><span class="column-title">Done</span><span class="count" id="count-done">0</span>
        <button class="column-add" data-add-column="done" aria-label="Add task to Done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg></button>
      </header>
      <div class="card-list" id="list-done"></div>
    </section>
  </section>
  <div class="board-foot">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8v4l2.5 2.5"/><circle cx="12" cy="12" r="9"/></svg>
    Last updated just now <span>·</span> Drag a card to move it between columns
  </div>
</main>

<div class="modal-backdrop" id="modal-backdrop" role="presentation">
  <section class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
    <div class="modal-head">
      <div><h2 id="modal-title">Add a task</h2><p class="modal-copy">Add a new card to your project board.</p></div>
      <button class="modal-close" id="modal-close" type="button" aria-label="Close dialog"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="m18 6-12 12M6 6l12 12"/></svg></button>
    </div>
    <form id="task-form">
      <div class="form-group">
        <label for="task-title">Task title <span aria-hidden="true" style="color:#d76565">*</span></label>
        <input id="task-title" name="title" type="text" maxlength="90" placeholder="e.g. Review launch checklist" required>
      </div>
      <div class="form-group">
        <label for="task-priority">Priority</label>
        <select id="task-priority" name="priority">
          <option value="low">Low</option><option value="medium" selected>Medium</option><option value="high">High</option>
        </select>
      </div>
      <div class="form-group">
        <label for="task-column">Add to column</label>
        <select id="task-column" name="column">
          <option value="todo">To do</option><option value="progress">In progress</option><option value="done">Done</option>
        </select>
      </div>
      <div class="modal-actions">
        <button class="button secondary" id="cancel-modal" type="button">Cancel</button>
        <button class="button primary" type="submit">Create task</button>
      </div>
    </form>
  </section>
</div>

<script>
(() => {
  let tasks = [
    { id: 1, title: "Review onboarding flow", priority: "high", column: "todo", category: "Design · UX", desc: "Walk through the first-run experience and flag any friction.", due: "Due today", initials: "ML", color: "lilac" },
    { id: 2, title: "Write release notes", priority: "medium", column: "todo", category: "Content · Docs", desc: "Summarize the customer-facing updates for v2.4.", due: "Mar 28", initials: "JR", color: "coral" },
    { id: 3, title: "Build billing settings page", priority: "high", column: "progress", category: "Product · Web", desc: "Finish the subscription and payment method screens.", due: "Due tomorrow", initials: "SK", color: "teal" },
    { id: 4, title: "QA mobile navigation", priority: "medium", column: "progress", category: "Engineering", desc: "Check menu states across the supported device sizes.", due: "Mar 29", initials: "AP", color: "blue" },
    { id: 5, title: "Ship analytics dashboard", priority: "low", column: "done", category: "Product · Data", desc: "Core usage metrics are ready for the launch review.", due: "Completed Mar 25", initials: "JR", color: "coral" },
    { id: 6, title: "Update component library", priority: "low", column: "done", category: "Design system", desc: "Buttons, inputs, and tokens are synced with the new UI.", due: "Completed Mar 24", initials: "ML", color: "lilac" }
  ];
  const labels = { todo: "To do", progress: "In progress", done: "Done" };
  const listIds = { todo: "list-todo", progress: "list-progress", done: "list-done" };
  const search = document.getElementById("search");
  const backdrop = document.getElementById("modal-backdrop");
  const form = document.getElementById("task-form");
  const titleInput = document.getElementById("task-title");
  let nextId = 7;
  let draggedId = null;
  let marker = null;

  const escapeHTML = value => String(value).replace(/[&<>"']/g, ch => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[ch]));

  function cardHTML(task) {
    return `<article class="card" draggable="true" data-id="${task.id}" aria-label="${escapeHTML(task.title)}">
      <div class="card-top"><span class="category">${escapeHTML(task.category || "General")}</span><span class="priority ${task.priority}">${task.priority}</span></div>
      <h3>${escapeHTML(task.title)}</h3>
      ${task.desc ? `<p class="card-desc">${escapeHTML(task.desc)}</p>` : ""}
      <div class="card-bottom">
        <span class="due"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="5" width="17" height="16" rx="2"/><path d="M7.5 3v4M16.5 3v4M3.5 10h17"/></svg>${escapeHTML(task.due || "No due date")}</span>
        <span class="card-people" aria-label="Assigned to ${escapeHTML(task.initials || "You")}"><span class="avatar av-${escapeHTML(task.color || "lilac")}">${escapeHTML(task.initials || "YO")}</span></span>
      </div>
      <button class="delete-card" type="button" aria-label="Delete ${escapeHTML(task.title)}" title="Delete task"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16M10 11v6m4-6v6M5.5 7l1 14h11l1-14M9 7V4h6v3"/></svg></button>
    </article>`;
  }

  function render() {
    const query = search.value.trim().toLowerCase();
    Object.keys(listIds).forEach(column => {
      const all = tasks.filter(task => task.column === column);
      const list = document.getElementById(listIds[column]);
      document.getElementById(`count-${column}`).textContent = all.length;
      const shown = all.filter(task => task.title.toLowerCase().includes(query));
      list.innerHTML = shown.length ? shown.map(cardHTML).join("") : (query ? '<div class="empty-state">No matching tasks</div>' : "");
    });
  }

  function openModal(column = "todo") {
    document.getElementById("task-column").value = column;
    backdrop.classList.add("open");
    titleInput.value = "";
    setTimeout(() => titleInput.focus(), 30);
  }
  function closeModal() { backdrop.classList.remove("open"); }

  document.getElementById("add-task").addEventListener("click", () => openModal());
  document.querySelectorAll("[data-add-column]").forEach(button => button.addEventListener("click", () => openModal(button.dataset.addColumn)));
  document.getElementById("modal-close").addEventListener("click", closeModal);
  document.getElementById("cancel-modal").addEventListener("click", closeModal);
  backdrop.addEventListener("click", event => { if (event.target === backdrop) closeModal(); });
  document.addEventListener("keydown", event => { if (event.key === "Escape" && backdrop.classList.contains("open")) closeModal(); });

  form.addEventListener("submit", event => {
    event.preventDefault();
    const title = titleInput.value.trim();
    if (!title) { titleInput.focus(); return; }
    tasks.push({
      id: nextId++, title, priority: document.getElementById("task-priority").value,
      column: document.getElementById("task-column").value,
      category: "New task", desc: "", due: "No due date", initials: "YO", color: "lilac"
    });
    render();
    closeModal();
  });

  document.getElementById("theme-toggle").addEventListener("click", () => {
    const isDark = document.body.classList.toggle("dark");
    document.getElementById("theme-toggle").setAttribute("aria-label", isDark ? "Switch to light theme" : "Switch to dark theme");
    document.getElementById("theme-icon").innerHTML = isDark
      ? '<circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M2 12h2m16 0h2M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/>'
      : '<path d="M20.2 15.1A8.5 8.5 0 0 1 8.9 3.8 8.5 8.5 0 1 0 20.2 15.1Z"/>';
  });

  search.addEventListener("input", render);

  document.getElementById("filter-btn").addEventListener("click", event => {
    const current = event.currentTarget.dataset.filter || "";
    const next = current === "" ? "high" : current === "high" ? "medium" : current === "medium" ? "low" : "";
    event.currentTarget.dataset.filter = next;
    event.currentTarget.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h16M7 12h10m-7 6h4"/></svg>${next ? ` ${next[0].toUpperCase()}${next.slice(1)} ×` : " Filter"}`;
    const query = search.value.trim().toLowerCase();
    Object.keys(listIds).forEach(column => {
      const list = document.getElementById(listIds[column]);
      const shown = tasks.filter(task => task.column === column && task.title.toLowerCase().includes(query) && (!next || task.priority === next));
      list.innerHTML = shown.length ? shown.map(cardHTML).join("") : ((query || next) ? '<div class="empty-state">No matching tasks</div>' : "");
    });
  });

  document.getElementById("invite-btn").addEventListener("click", event => {
    const button = event.currentTarget;
    const label = button.querySelector("span");
    label.textContent = label.textContent === "Invite" ? "Invited ✓" : "Invite";
  });

  document.addEventListener("click", event => {
    const deleteButton = event.target.closest(".delete-card");
    if (!deleteButton) return;
    const card = deleteButton.closest(".card");
    tasks = tasks.filter(task => task.id !== Number(card.dataset.id));
    render();
  });

  function removeMarker() {
    if (marker && marker.parentNode) marker.parentNode.removeChild(marker);
    marker = null;
    document.querySelectorAll(".column.drag-over").forEach(col => col.classList.remove("drag-over"));
  }

  document.addEventListener("dragstart", event => {
    const card = event.target.closest(".card");
    if (!card) return;
    draggedId = Number(card.dataset.id);
    card.classList.add("dragging");
    event.dataTransfer.effectAllowed = "move";
    event.dataTransfer.setData("text/plain", String(draggedId));
    marker = document.createElement("div");
    marker.className = "drop-marker";
  });
  document.addEventListener("dragend", event => {
    const card = event.target.closest(".card");
    if (card) card.classList.remove("dragging");
    removeMarker();
  });

  document.querySelectorAll(".column").forEach(column => {
    const list = column.querySelector(".card-list");
    column.addEventListener("dragover", event => {
      if (draggedId === null) return;
      event.preventDefault();
      column.classList.add("drag-over");
      const targetCard = event.target.closest(".card");
      if (targetCard && targetCard.dataset.id !== String(draggedId)) {
        const rect = targetCard.getBoundingClientRect();
        const after = event.clientY > rect.top + rect.height / 2;
        list.insertBefore(marker, after ? targetCard.nextSibling : targetCard);
      } else if (!targetCard) {
        list.appendChild(marker);
      }
    });
    column.addEventListener("dragleave", event => {
      if (!column.contains(event.relatedTarget)) column.classList.remove("drag-over");
    });
    column.addEventListener("drop", event => {
      event.preventDefault();
      if (draggedId === null) return;
      const task = tasks.find(item => item.id === draggedId);
      if (task) task.column = column.dataset.column;
      removeMarker();
      render();
    });
  });

  render();
})();
</script>
</body>
</html>
Reasoning trace (4,203 tokens)
**Implementing drag-and-drop features**

I'm thinking about adding a marker as an element within the .card-list. It needs a CSS height of 5px, a blue background, some margin, and rounded borders. When dragging, I need to target the closest card for marker insertion on dragover, and then replace the marker with the dragged card on drop. I'll also add a .dragging class and make sure to clean up the markers afterward. I wonder if I need to consider touch events, but mouse requirements should be enough.