Models 44

GPT-6 Luna

by OpenAIReasoningClean
Open in new window

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

How it went

Total time
3 min 8 s
Cost
$0.0079
Output tokens
15,766
Spent thinking
5,853 tokens
Speed
86.2 tok/s
Console errors
0
First token after
5.1 s
First visible text after
1 min 33 s
Prompt tokens
493
Code size
33.7 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6-luna
Reasoning sent
{"effort":"xhigh"}
Max output
64,000 tokens
Generated
Nov 10, 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 · 1077 lines

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Product sprint — Kanban board</title>
  <style>
    :root {
      color-scheme: light;
      --page: #f7f8fb;
      --topbar: rgba(255, 255, 255, 0.94);
      --surface: #ffffff;
      --column: #f0f2f6;
      --text: #202431;
      --muted: #788092;
      --subtle: #a1a8b5;
      --border: #e6e8ee;
      --accent: #5b63df;
      --accent-hover: #4d55cf;
      --accent-soft: #eef0ff;
      --drop-surface: #f0f1ff;
      --shadow: 0 5px 16px rgba(32, 39, 66, 0.045);
      --modal-shadow: 0 24px 80px rgba(16, 20, 40, 0.24);
    }

    body[data-theme="dark"] {
      color-scheme: dark;
      --page: #13151c;
      --topbar: rgba(25, 27, 36, 0.96);
      --surface: #20232e;
      --column: #1a1d26;
      --text: #eef0f6;
      --muted: #a5aabb;
      --subtle: #7f8495;
      --border: #303441;
      --accent: #9098ff;
      --accent-hover: #aab0ff;
      --accent-soft: #30334c;
      --drop-surface: #282b41;
      --shadow: 0 5px 16px rgba(0, 0, 0, 0.16);
      --modal-shadow: 0 24px 80px rgba(0, 0, 0, 0.48);
    }

    * { box-sizing: border-box; }

    body {
      min-width: 320px;
      min-height: 100vh;
      margin: 0;
      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-color 180ms ease, color 180ms ease;
    }

    button, input, select { font: inherit; }
    button { color: inherit; }
    [hidden] { display: none !important; }

    .topbar {
      height: 66px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 max(28px, calc((100vw - 1220px) / 2));
      background: var(--topbar);
      border-bottom: 1px solid var(--border);
    }

    .brand {
      display: flex;
      align-items: center;
      gap: 11px;
      min-width: 0;
    }

    .brand-mark {
      width: 30px;
      height: 30px;
      border-radius: 9px;
      display: grid;
      place-items: center;
      color: #fff;
      background: linear-gradient(145deg, #7379f4, #4b53ca);
      box-shadow: 0 3px 8px rgba(91, 99, 223, 0.24);
      flex: none;
    }

    .brand-mark svg { width: 18px; height: 18px; }
    .brand-name { font-size: 15px; font-weight: 750; letter-spacing: -0.35px; }
    .brand-divider { width: 1px; height: 23px; margin: 0 4px; background: var(--border); }
    .workspace-name {
      color: var(--muted);
      font-size: 13px;
      font-weight: 550;
      white-space: nowrap;
    }

    .topbar-note {
      display: flex;
      align-items: center;
      gap: 8px;
      color: var(--muted);
      font-size: 12px;
    }

    .online-dot {
      width: 7px;
      height: 7px;
      border-radius: 50%;
      background: #53bd8a;
      box-shadow: 0 0 0 3px rgba(83, 189, 138, 0.12);
    }

    .page {
      width: min(1220px, 100%);
      margin: 0 auto;
      padding: 30px 28px 56px;
    }

    .breadcrumbs {
      display: flex;
      align-items: center;
      gap: 8px;
      color: var(--subtle);
      font-size: 12px;
      line-height: 18px;
    }

    .breadcrumbs .current { color: var(--muted); font-weight: 600; }
    .crumb-separator { color: var(--subtle); }

    .heading-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 20px;
      margin-top: 11px;
    }

    .title-block { min-width: 0; }
    .title-line { display: flex; align-items: center; flex-wrap: wrap; gap: 11px; }
    h1 {
      margin: 0;
      font-size: 30px;
      line-height: 1.2;
      letter-spacing: -1.05px;
      font-weight: 740;
    }

    .sprint-pill {
      padding: 5px 9px;
      border-radius: 7px;
      color: var(--accent);
      background: var(--accent-soft);
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 0.02em;
    }

    .page-subtitle {
      margin: 5px 0 0;
      color: var(--muted);
      font-size: 13px;
      line-height: 1.5;
    }

    .primary-button {
      height: 40px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      padding: 0 14px;
      border: 0;
      border-radius: 9px;
      color: #fff;
      background: var(--accent);
      box-shadow: 0 3px 7px rgba(91, 99, 223, 0.18);
      font-size: 13px;
      font-weight: 650;
      cursor: pointer;
      white-space: nowrap;
      transition: background 140ms ease, transform 140ms ease, box-shadow 140ms ease;
    }

    .primary-button:hover {
      background: var(--accent-hover);
      box-shadow: 0 5px 12px rgba(91, 99, 223, 0.23);
      transform: translateY(-1px);
    }

    .primary-button svg { width: 16px; height: 16px; }

    .toolbar {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-top: 22px;
    }

    .search-box {
      width: min(310px, 42vw);
      height: 40px;
      display: flex;
      align-items: center;
      gap: 9px;
      padding: 0 11px;
      border: 1px solid var(--border);
      border-radius: 9px;
      background: var(--surface);
      color: var(--muted);
      transition: border-color 150ms ease, box-shadow 150ms ease;
    }

    .search-box:focus-within {
      border-color: var(--accent);
      box-shadow: 0 0 0 3px rgba(91, 99, 223, 0.12);
    }

    .search-box svg { width: 16px; height: 16px; flex: none; }
    .search-box input {
      min-width: 0;
      width: 100%;
      border: 0;
      outline: 0;
      background: transparent;
      color: var(--text);
      font-size: 13px;
    }

    .search-box input::placeholder { color: var(--subtle); }
    .toolbar-spacer { flex: 1; }
    .task-summary { color: var(--muted); font-size: 12px; white-space: nowrap; }
    .task-summary strong { color: var(--text); font-weight: 700; }

    .theme-button {
      height: 38px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      padding: 0 11px;
      border: 1px solid var(--border);
      border-radius: 9px;
      background: var(--surface);
      color: var(--muted);
      font-size: 12px;
      font-weight: 600;
      cursor: pointer;
      transition: background 140ms ease, border-color 140ms ease;
    }

    .theme-button:hover { background: var(--column); border-color: var(--subtle); }
    .theme-button svg { width: 16px; height: 16px; color: var(--text); }

    .board-grid {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      align-items: start;
      gap: 17px;
      margin-top: 18px;
    }

    .kanban-column {
      min-width: 0;
      position: relative;
      padding: 13px;
      border: 1px solid var(--border);
      border-radius: 13px;
      background: var(--column);
      transition: background-color 150ms ease, outline-color 150ms ease;
    }

    .column-heading {
      min-height: 29px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      padding: 0 2px 1px;
    }

    .column-name { display: flex; align-items: center; gap: 9px; min-width: 0; }
    .column-name h2 {
      margin: 0;
      font-size: 13px;
      font-weight: 700;
      letter-spacing: -0.1px;
    }

    .status-mark {
      width: 9px;
      height: 9px;
      border-radius: 3px;
      flex: none;
    }

    .mark-todo { background: #9ba2b1; }
    .mark-progress { background: #e4a44f; }
    .mark-done { background: #50b88a; }

    .column-count {
      min-width: 22px;
      height: 22px;
      display: grid;
      place-items: center;
      padding: 0 6px;
      border: 1px solid var(--border);
      border-radius: 7px;
      background: var(--surface);
      color: var(--muted);
      font-size: 11px;
      font-weight: 650;
      line-height: 1;
    }

    .card-list {
      display: grid;
      gap: 11px;
      min-height: 90px;
      margin-top: 12px;
      border-radius: 9px;
    }

    .task-card {
      min-width: 0;
      padding: 13px 13px 12px;
      border: 1px solid var(--border);
      border-radius: 10px;
      background: var(--surface);
      box-shadow: var(--shadow);
      cursor: grab;
      transition: transform 130ms ease, box-shadow 130ms ease, opacity 130ms ease, border-color 130ms ease;
    }

    .task-card:hover {
      border-color: #d4d7e3;
      box-shadow: 0 7px 18px rgba(32, 39, 66, 0.08);
      transform: translateY(-1px);
    }

    body[data-theme="dark"] .task-card:hover { border-color: #4a4e5d; }
    .task-card:active { cursor: grabbing; }
    .task-card.is-dragging { opacity: 0.42; transform: scale(0.985); }

    .card-top {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 22px;
    }

    .priority {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      padding: 4px 7px;
      border-radius: 5px;
      font-size: 9px;
      line-height: 1;
      letter-spacing: 0.055em;
      font-weight: 750;
      text-transform: uppercase;
      white-space: nowrap;
    }

    .priority::before {
      content: "";
      width: 5px;
      height: 5px;
      border-radius: 50%;
      background: currentColor;
    }

    .priority-high { color: #c9515b; background: #fff0f0; }
    .priority-medium { color: #b47b24; background: #fff5e5; }
    .priority-low { color: #328669; background: #e9f7f0; }
    body[data-theme="dark"] .priority-high { color: #ff9299; background: #48272e; }
    body[data-theme="dark"] .priority-medium { color: #f3c16d; background: #44351f; }
    body[data-theme="dark"] .priority-low { color: #80d6b2; background: #203d34; }

    .delete-button {
      width: 25px;
      height: 25px;
      display: grid;
      place-items: center;
      padding: 0;
      border: 0;
      border-radius: 6px;
      background: transparent;
      color: var(--subtle);
      cursor: pointer;
      opacity: 0;
      transition: background 130ms ease, color 130ms ease, opacity 130ms ease;
    }

    .task-card:hover .delete-button,
    .delete-button:focus-visible { opacity: 1; }
    .delete-button:hover { color: #cf4d58; background: #fff0f0; }
    body[data-theme="dark"] .delete-button:hover { color: #ff9299; background: #48272e; }
    .delete-button svg { width: 15px; height: 15px; }

    .task-card h3 {
      margin: 8px 0 0;
      color: var(--text);
      font-size: 14px;
      line-height: 1.4;
      letter-spacing: -0.16px;
      font-weight: 680;
    }

    .task-description {
      margin: 5px 0 0;
      color: var(--muted);
      font-size: 11.5px;
      line-height: 1.5;
    }

    .card-footer {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      margin-top: 13px;
      min-width: 0;
    }

    .category-tag {
      max-width: 40%;
      overflow: hidden;
      padding: 4px 7px;
      border-radius: 5px;
      background: var(--column);
      color: var(--muted);
      font-size: 10px;
      line-height: 1.15;
      font-weight: 600;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .card-tail {
      display: flex;
      align-items: center;
      gap: 8px;
      min-width: 0;
    }

    .card-date {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      overflow: hidden;
      color: var(--muted);
      font-size: 10px;
      white-space: nowrap;
      text-overflow: ellipsis;
    }

    .card-date svg { width: 12px; height: 12px; flex: none; color: var(--subtle); }
    .owner-avatar {
      width: 22px;
      height: 22px;
      display: grid;
      place-items: center;
      flex: none;
      border: 2px solid var(--surface);
      border-radius: 50%;
      background: #e8eaff;
      color: #555dc3;
      font-size: 8px;
      font-weight: 750;
    }

    .owner-2 { background: #f8e9dc; color: #a36a37; }
    .owner-3 { background: #e1f2eb; color: #398665; }
    .owner-4 { background: #f1e6f5; color: #8756a1; }
    body[data-theme="dark"] .owner-avatar { border-color: var(--surface); }

    .empty-state {
      min-height: 82px;
      display: grid;
      place-items: center;
      padding: 15px;
      border: 1px dashed var(--border);
      border-radius: 9px;
      color: var(--subtle);
      font-size: 12px;
      text-align: center;
    }

    .kanban-column.is-drop-target {
      background: var(--drop-surface);
      outline: 2px dashed var(--accent);
      outline-offset: 2px;
    }

    .kanban-column.is-drop-target .card-list {
      outline: 1px dashed var(--accent);
      outline-offset: 3px;
      background: rgba(91, 99, 223, 0.045);
    }

    body[data-theme="dark"] .kanban-column.is-drop-target .card-list {
      background: rgba(144, 152, 255, 0.07);
    }

    .kanban-column.is-drop-target .card-list::after {
      content: "Drop card here";
      display: block;
      padding: 9px;
      border-radius: 7px;
      color: var(--accent);
      font-size: 11px;
      font-weight: 650;
      text-align: center;
    }

    .modal-backdrop {
      position: fixed;
      z-index: 10;
      inset: 0;
      display: grid;
      place-items: center;
      padding: 18px;
      background: rgba(17, 20, 32, 0.48);
      backdrop-filter: blur(3px);
    }

    .modal {
      width: min(430px, 100%);
      padding: 23px;
      border: 1px solid var(--border);
      border-radius: 15px;
      background: var(--surface);
      box-shadow: var(--modal-shadow);
      animation: modal-in 150ms ease-out;
    }

    @keyframes modal-in {
      from { opacity: 0; transform: translateY(7px) scale(0.99); }
      to { opacity: 1; transform: translateY(0) scale(1); }
    }

    .modal-heading {
      display: flex;
      justify-content: space-between;
      align-items: flex-start;
      gap: 12px;
      margin-bottom: 19px;
    }

    .modal-heading h2 { margin: 0; font-size: 19px; letter-spacing: -0.4px; }
    .modal-heading p { margin: 5px 0 0; color: var(--muted); font-size: 12px; }

    .modal-close {
      width: 30px;
      height: 30px;
      display: grid;
      place-items: center;
      border: 0;
      border-radius: 7px;
      background: transparent;
      color: var(--muted);
      cursor: pointer;
    }

    .modal-close:hover { background: var(--column); color: var(--text); }
    .modal-close svg { width: 16px; height: 16px; }
    .form-field { display: grid; gap: 7px; margin-top: 14px; }
    .form-field label { color: var(--text); font-size: 12px; font-weight: 650; }
    .form-field input, .form-field select {
      width: 100%;
      height: 40px;
      padding: 0 11px;
      border: 1px solid var(--border);
      border-radius: 8px;
      outline: 0;
      background: var(--surface);
      color: var(--text);
      font-size: 13px;
    }

    .form-field input:focus, .form-field select:focus {
      border-color: var(--accent);
      box-shadow: 0 0 0 3px rgba(91, 99, 223, 0.12);
    }

    .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
    .modal-actions {
      display: flex;
      justify-content: flex-end;
      gap: 9px;
      margin-top: 22px;
    }

    .secondary-button {
      height: 38px;
      padding: 0 13px;
      border: 1px solid var(--border);
      border-radius: 8px;
      background: var(--surface);
      color: var(--muted);
      font-size: 12px;
      font-weight: 600;
      cursor: pointer;
    }

    .secondary-button:hover { background: var(--column); color: var(--text); }
    .modal-actions .primary-button { height: 38px; }

    button:focus-visible, .task-card:focus-visible {
      outline: 3px solid rgba(91, 99, 223, 0.4);
      outline-offset: 2px;
    }

    @media (max-width: 820px) {
      .topbar { padding: 0 22px; }
      .page { padding-right: 22px; padding-left: 22px; }
      .board-grid { gap: 12px; }
      .kanban-column { padding: 10px; }
      .task-card { padding: 12px 11px; }
      .card-tail { gap: 5px; }
    }

    @media (max-width: 700px) {
      .topbar { height: 60px; padding: 0 17px; }
      .topbar-note { display: none; }
      .page { padding: 24px 17px 40px; }
      .heading-row { align-items: flex-start; gap: 12px; }
      h1 { font-size: 27px; }
      .page-subtitle { max-width: 400px; }
      .board-grid { grid-template-columns: minmax(0, 1fr); gap: 13px; }
      .kanban-column { padding: 12px; }
      .task-card { padding: 13px; }
      .card-tail { gap: 8px; }
      .delete-button { opacity: 1; }
    }

    @media (max-width: 440px) {
      .topbar { padding: 0 15px; }
      .brand-divider, .workspace-name { display: none; }
      .page { padding: 20px 14px 34px; }
      h1 { font-size: 25px; }
      .title-line { gap: 8px; }
      .sprint-pill { padding: 4px 7px; }
      .heading-row { gap: 8px; }
      .primary-button { height: 38px; padding: 0 10px; font-size: 12px; gap: 5px; }
      .toolbar { gap: 8px; margin-top: 17px; }
      .search-box { width: auto; flex: 1; height: 39px; }
      .task-summary { display: none; }
      .theme-button { width: 40px; height: 39px; padding: 0; flex: none; }
      .theme-label { display: none; }
      .form-row { gap: 9px; }
      .modal { padding: 20px; }
    }

    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after { scroll-behavior: auto !important; animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
    }
  </style>
</head>
<body>
  <header class="topbar">
    <div class="brand" aria-label="Taskflow workspace">
      <span class="brand-mark" aria-hidden="true">
        <svg viewBox="0 0 20 20" fill="none">
          <rect x="2.5" y="2.5" width="6" height="6" rx="1.5" fill="currentColor"/>
          <rect x="11.5" y="2.5" width="6" height="6" rx="1.5" fill="currentColor" opacity=".72"/>
          <rect x="2.5" y="11.5" width="6" height="6" rx="1.5" fill="currentColor" opacity=".72"/>
          <rect x="11.5" y="11.5" width="6" height="6" rx="1.5" fill="currentColor"/>
        </svg>
      </span>
      <span class="brand-name">Taskflow</span>
      <span class="brand-divider" aria-hidden="true"></span>
      <span class="workspace-name">Product workspace</span>
    </div>
    <div class="topbar-note"><span class="online-dot" aria-hidden="true"></span> All changes are up to date</div>
  </header>

  <main class="page">
    <nav class="breadcrumbs" aria-label="Breadcrumb">
      <span>Workspace</span><span class="crumb-separator">/</span>
      <span>Product</span><span class="crumb-separator">/</span>
      <span class="current">Board</span>
    </nav>

    <section class="heading-row" aria-labelledby="board-title">
      <div class="title-block">
        <div class="title-line">
          <h1 id="board-title">Product launch</h1>
          <span class="sprint-pill">SPRINT 08</span>
        </div>
        <p class="page-subtitle">A focused view of the work moving your next release forward.</p>
      </div>
      <button class="primary-button" id="open-modal" type="button">
        <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
          <path d="M10 4v12M4 10h12" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
        </svg>
        Add task
      </button>
    </section>

    <div class="toolbar">
      <label class="search-box">
        <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
          <circle cx="8.8" cy="8.8" r="5.7" stroke="currentColor" stroke-width="1.6"/>
          <path d="m13 13 4 4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
        </svg>
        <input id="search" type="search" placeholder="Search tasks..." aria-label="Search tasks by title">
      </label>
      <span class="task-summary" id="task-summary" aria-live="polite"><strong>6</strong> tasks across 3 columns</span>
      <span class="toolbar-spacer"></span>
      <button class="theme-button" id="theme-toggle" type="button" aria-label="Switch to dark theme">
        <svg id="theme-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true">
          <path d="M16.1 12.3A6.8 6.8 0 0 1 7.7 3.9a6.8 6.8 0 1 0 8.4 8.4Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>
        </svg>
        <span class="theme-label" id="theme-label">Dark mode</span>
      </button>
    </div>

    <section class="board-grid" aria-label="Kanban board">
      <section class="kanban-column" data-status="todo" aria-labelledby="heading-todo">
        <div class="column-heading">
          <div class="column-name"><span class="status-mark mark-todo" aria-hidden="true"></span><h2 id="heading-todo">To do</h2></div>
          <span class="column-count" id="count-todo" aria-label="Tasks in To do">0</span>
        </div>
        <div class="card-list" id="list-todo" role="list" aria-label="To do tasks"></div>
      </section>

      <section class="kanban-column" data-status="progress" aria-labelledby="heading-progress">
        <div class="column-heading">
          <div class="column-name"><span class="status-mark mark-progress" aria-hidden="true"></span><h2 id="heading-progress">In progress</h2></div>
          <span class="column-count" id="count-progress" aria-label="Tasks in progress">0</span>
        </div>
        <div class="card-list" id="list-progress" role="list" aria-label="Tasks in progress"></div>
      </section>

      <section class="kanban-column" data-status="done" aria-labelledby="heading-done">
        <div class="column-heading">
          <div class="column-name"><span class="status-mark mark-done" aria-hidden="true"></span><h2 id="heading-done">Done</h2></div>
          <span class="column-count" id="count-done" aria-label="Done tasks">0</span>
        </div>
        <div class="card-list" id="list-done" role="list" aria-label="Completed tasks"></div>
      </section>
    </section>
  </main>

  <div class="modal-backdrop" id="modal-backdrop" hidden>
    <section class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title" aria-describedby="modal-description">
      <div class="modal-heading">
        <div>
          <h2 id="modal-title">Add a task</h2>
          <p id="modal-description">Give your next piece of work a clear name.</p>
        </div>
        <button class="modal-close" id="close-modal" type="button" aria-label="Close dialog">
          <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
            <path d="m5 5 10 10M15 5 5 15" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/>
          </svg>
        </button>
      </div>
      <form id="task-form">
        <div class="form-field">
          <label for="task-title">Task title <span aria-hidden="true">*</span></label>
          <input id="task-title" name="title" type="text" maxlength="90" placeholder="e.g. Review launch checklist" required>
        </div>
        <div class="form-row">
          <div class="form-field">
            <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-field">
            <label for="task-status">Add to</label>
            <select id="task-status" name="status">
              <option value="todo" selected>To do</option>
              <option value="progress">In progress</option>
              <option value="done">Done</option>
            </select>
          </div>
        </div>
        <div class="modal-actions">
          <button class="secondary-button" id="cancel-modal" type="button">Cancel</button>
          <button class="primary-button" type="submit">Create task</button>
        </div>
      </form>
    </section>
  </div>

  <script>
    const tasks = [
      {
        id: 1, status: "todo", priority: "high",
        title: "Map onboarding friction points",
        description: "Review session notes and flag the biggest drop-off moments.",
        category: "Research", date: "Due Mar 21", owner: "ML", ownerClass: ""
      },
      {
        id: 2, status: "todo", priority: "medium",
        title: "Draft empty-state copy",
        description: "Write the first-run messaging for a more helpful dashboard.",
        category: "Content", date: "Due Mar 22", owner: "AK", ownerClass: "owner-2"
      },
      {
        id: 3, status: "progress", priority: "high",
        title: "Ship billing settings refresh",
        description: "Polish the responsive layout and connect the new payment flow.",
        category: "Engineering", date: "Due Mar 20", owner: "JR", ownerClass: "owner-3"
      },
      {
        id: 4, status: "progress", priority: "medium",
        title: "Audit keyboard navigation",
        description: "Check focus order, shortcuts, and screen-reader labels.",
        category: "Quality", date: "Due Mar 22", owner: "ST", ownerClass: "owner-4"
      },
      {
        id: 5, status: "done", priority: "low",
        title: "Agree on activation metric",
        description: "Align product and analytics on the north-star event.",
        category: "Analytics", date: "Done Mar 18", owner: "ML", ownerClass: ""
      },
      {
        id: 6, status: "done", priority: "medium",
        title: "Create launch checklist",
        description: "Bring QA, communications, and release steps into one place.",
        category: "Planning", date: "Done Mar 17", owner: "AK", ownerClass: "owner-2"
      }
    ];

    const statuses = ["todo", "progress", "done"];
    let nextId = 7;
    let draggedId = null;

    const searchInput = document.getElementById("search");
    const taskSummary = document.getElementById("task-summary");
    const backdrop = document.getElementById("modal-backdrop");
    const form = document.getElementById("task-form");
    const titleInput = document.getElementById("task-title");
    const openModalButton = document.getElementById("open-modal");

    const calendarIcon = `
      <svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
        <rect x="2.3" y="3.5" width="11.4" height="10" rx="1.8" stroke="currentColor" stroke-width="1.3"/>
        <path d="M5.2 2.3v2.4M10.8 2.3v2.4M2.5 6.4h11" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/>
      </svg>`;

    function makeTaskCard(task) {
      const card = document.createElement("article");
      card.className = "task-card";
      card.draggable = true;
      card.dataset.id = String(task.id);
      card.setAttribute("role", "listitem");
      card.setAttribute("aria-roledescription", "draggable task");

      const top = document.createElement("div");
      top.className = "card-top";

      const priority = document.createElement("span");
      priority.className = `priority priority-${task.priority}`;
      priority.textContent = task.priority;

      const deleteButton = document.createElement("button");
      deleteButton.type = "button";
      deleteButton.className = "delete-button";
      deleteButton.setAttribute("aria-label", `Delete ${task.title}`);
      deleteButton.title = "Delete task";
      deleteButton.innerHTML = `
        <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
          <path d="M4.5 6h11M8 6V4.5h4V6m-6 0 .7 9h6.6l.7-9M8.3 8.5v4.4m3.4-4.4v4.4" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
        </svg>`;
      deleteButton.addEventListener("click", () => {
        const index = tasks.findIndex(item => item.id === task.id);
        if (index !== -1) tasks.splice(index, 1);
        renderBoard();
      });

      top.append(priority, deleteButton);

      const title = document.createElement("h3");
      title.textContent = task.title;

      card.append(top, title);

      if (task.description) {
        const description = document.createElement("p");
        description.className = "task-description";
        description.textContent = task.description;
        card.append(description);
      }

      const footer = document.createElement("div");
      footer.className = "card-footer";

      const category = document.createElement("span");
      category.className = "category-tag";
      category.textContent = task.category || "Inbox";

      const tail = document.createElement("div");
      tail.className = "card-tail";

      const date = document.createElement("span");
      date.className = "card-date";
      date.innerHTML = calendarIcon;
      const dateText = document.createElement("span");
      dateText.textContent = task.date || "Just added";
      date.append(dateText);

      const avatar = document.createElement("span");
      avatar.className = `owner-avatar ${task.ownerClass || ""}`;
      avatar.textContent = task.owner || "YO";
      avatar.setAttribute("aria-label", `Assigned to ${task.owner || "you"}`);

      tail.append(date, avatar);
      footer.append(category, tail);
      card.append(footer);

      card.addEventListener("dragstart", event => {
        draggedId = task.id;
        event.dataTransfer.effectAllowed = "move";
        event.dataTransfer.setData("text/plain", String(task.id));
        card.classList.add("is-dragging");
      });

      card.addEventListener("dragend", () => {
        draggedId = null;
        clearDropTargets();
        document.querySelectorAll(".task-card.is-dragging").forEach(item => item.classList.remove("is-dragging"));
      });

      return card;
    }

    function renderBoard() {
      const query = searchInput.value.trim().toLocaleLowerCase();
      const matchingTasks = tasks.filter(task => task.title.toLocaleLowerCase().includes(query));

      statuses.forEach(status => {
        const list = document.getElementById(`list-${status}`);
        const count = document.getElementById(`count-${status}`);
        const columnTasks = matchingTasks.filter(task => task.status === status);

        count.textContent = String(columnTasks.length);
        count.setAttribute("aria-label", `${columnTasks.length} ${columnTasks.length === 1 ? "task" : "tasks"}`);

        list.replaceChildren();

        if (columnTasks.length === 0) {
          const empty = document.createElement("div");
          empty.className = "empty-state";
          empty.textContent = query ? "No matching tasks" : "Nothing here yet — drop a task in";
          list.append(empty);
        } else {
          columnTasks.forEach(task => list.append(makeTaskCard(task)));
        }
      });

      taskSummary.innerHTML = `<strong>${matchingTasks.length}</strong> ${matchingTasks.length === 1 ? "task" : "tasks"} across 3 columns`;
    }

    function clearDropTargets() {
      document.querySelectorAll(".kanban-column.is-drop-target").forEach(column => {
        column.classList.remove("is-drop-target");
      });
    }

    document.querySelectorAll(".kanban-column").forEach(column => {
      column.addEventListener("dragenter", event => {
        event.preventDefault();
        column.classList.add("is-drop-target");
      });

      column.addEventListener("dragover", event => {
        event.preventDefault();
        event.dataTransfer.dropEffect = "move";
        column.classList.add("is-drop-target");
      });

      column.addEventListener("dragleave", event => {
        if (!event.relatedTarget || !column.contains(event.relatedTarget)) {
          column.classList.remove("is-drop-target");
        }
      });

      column.addEventListener("drop", event => {
        event.preventDefault();
        const id = Number(event.dataTransfer.getData("text/plain")) || draggedId;
        const task = tasks.find(item => item.id === id);
        if (task) task.status = column.dataset.status;
        clearDropTargets();
        draggedId = null;
        renderBoard();
      });
    });

    searchInput.addEventListener("input", renderBoard);

    const themeButton = document.getElementById("theme-toggle");
    const themeIcon = document.getElementById("theme-icon");
    const themeLabel = document.getElementById("theme-label");

    themeButton.addEventListener("click", () => {
      const isDark = document.body.dataset.theme !== "dark";
      document.body.dataset.theme = isDark ? "dark" : "light";
      themeButton.setAttribute("aria-label", `Switch to ${isDark ? "light" : "dark"} theme`);
      themeLabel.textContent = isDark ? "Light mode" : "Dark mode";
      themeIcon.innerHTML = isDark
        ? `<circle cx="10" cy="10" r="3.1" stroke="currentColor" stroke-width="1.5"/>
           <path d="M10 2.2v1.6M10 16.2v1.6M17.8 10h-1.6M3.8 10H2.2m13.3-5.5-1.1 1.1M5.6 14.4l-1.1 1.1m11 0-1.1-1.1M5.6 5.6 4.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>`
        : `<path d="M16.1 12.3A6.8 6.8 0 0 1 7.7 3.9a6.8 6.8 0 1 0 8.4 8.4Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>`;
    });

    function openModal() {
      backdrop.hidden = false;
      requestAnimationFrame(() => titleInput.focus());
    }

    function closeModal() {
      backdrop.hidden = true;
      form.reset();
      openModalButton.focus();
    }

    openModalButton.addEventListener("click", openModal);
    document.getElementById("close-modal").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.hidden) closeModal();
    });

    form.addEventListener("submit", event => {
      event.preventDefault();
      const title = titleInput.value.trim();
      if (!title) {
        titleInput.setCustomValidity("Please enter a task title.");
        titleInput.reportValidity();
        return;
      }
      titleInput.setCustomValidity("");

      const priority = document.getElementById("task-priority").value;
      const status = document.getElementById("task-status").value;
      tasks.push({
        id: nextId++,
        status,
        priority,
        title,
        description: "",
        category: "Inbox",
        date: "Just added",
        owner: "YO",
        ownerClass: ""
      });

      searchInput.value = "";
      renderBoard();
      backdrop.hidden = true;
      form.reset();
      openModalButton.focus();
    });

    titleInput.addEventListener("input", () => titleInput.setCustomValidity(""));

    renderBoard();
  </script>
</body>
</html>
Reasoning trace (5,853 tokens)
**Planning UI Design**

I need to generate a polished HTML UI with a responsive design, focusing on the first paint. I'm considering a Kanban board layout for a desktop size of 1280x800, which should include stylish elements like a workspace header and a sidebar. The main board should feel dynamic with a light gray background and a white top header featuring a logo. I'll incorporate a main heading and a toggle for easy navigation across three equal columns with well-designed task cards.**Creating Drag and Drop Functionality**

I need to implement a drag-and-drop feature with a clear drop indicator. This involves making cards draggable using native HTML5 features and handling pointer events. Each column will serve as a drop target, changing the card's opacity on drag start and applying a dashed border when hovered over. I’ll ensure the drag-and-drop process works smoothly, updating the status and rendering accordingly, while allowing for live search filters that reflect card counts per column after filtering.**Clarifying Card Count and Modal Dialog**

I need to decide if the card count in each column should reflect visible cards or total cards. It might make sense to show actual counts based on filtered lists, so I’ll consider showing counts directly in the columns, especially if search results yield zero matches. For the modal dialog, I want it to be accessible and simple, with fields for task title, priority, and column selection, using either the native `<dialog>` or a custom overlay for a small modal format.**Designing a Kanban Board**

I'm diving into details around designing a Kanban board. I need to focus on adding card IDs within a modal form. It should validate and ensure there’s no local storage involved. I'll implement a theme toggle for light and dark modes, adapting the button labels accordingly. My layout has to be responsive, avoiding horizontal scrollbars. The board should stack columns vertically on mobile, consolidating to a single column at a width of 375 pixels. It's a lot to consider!**Structuring the Sprint Board**

I'm laying out the top section with a margin of 38 pixels. The breadcrumbs should say "Workspace / Product," while the board heading will read "Sprint Board" with a badge for "Sprint 08." I envision member avatars on the right and a "Share" option. The controls row will have a search function on the left and possibly a static "Recently Updated" sort. I'll keep unnecessary controls to a minimum. Each column should be equal in size, with subtle backgrounds, and I need to ensure card details remain concise. It's all about fitting it together!**Designing Card Structure**

Each card will have a priority badge at the top and a delete button, which must be included. I’m thinking of placing the trash icon as a button in the top right corner alongside the priority badge. The card's heading will feature a title and a description, which will help set the card's height. I also want to include a small footer with due dates and avatar initials. The visual details need to be clear and compact, but still effective. Let's structure it precisely!**Designing the interface**

I’m working on a header that includes the app logo and "NORTHSTAR" alongside "Workspace," with a separator and a Board section. Quick avatars? Maybe not necessary. I’ll add a theme toggle too. 

In the main area, I need a small breadcrumb for the top line, a title that reads "Product Launch" with a "Sprint 08" badge saying "Updated just now," and an "Add Task" button. The toolbar will include a search area, a status text showing "6 tasks · 3 columns," and another theme toggle on the right. I’ll create a balanced screenshot layout!**Considering UI Layout**

I'm thinking about the brand system and layout. I want to set the main padding and design the header with a simple icon and label for the theme button. Should I add the task and top header simultaneously? The "Add task" button might be a nice touch. For mobile, I’m curious about the search bar's width and whether it should be flexible. Ultimately, I want a good card layout that adapts as the screen size changes. I’ll consider stacking columns for mobile views too!**Designing Layout Breakpoints**

I’m working on layout breakpoints. At 640 pixels, I want to stack elements, while at 768 pixels, I'm considering three columns with a width of about 220 pixels for the cards. That seems reasonable! I think I should set a breakpoint at 680 pixels. However, at 375 pixels, everything should be arranged vertically. It’s essential to create a smooth and functional user experience across different screen sizes!**Designing responsive CSS**

I need to set up a color scheme for the CSS and make it responsive for screens 640 pixels wide and smaller. For the top bar, I'll add padding and adjust the main content as well. Breadcrumbs should be small, and I'll align headings flexibly. I wonder if a button of 38 pixels is appropriate. The toolbar needs adjustments for search and a theme toggle, with specific styles at varying widths. I’ll also include features for the grid and overall layout. Great!**Evaluating layout options**

I'm considering the layout options for a push design during a drag event. A dashed border around the list could provide a clear visual separation, which might enhance usability. Also, keeping the list background low in contrast would help maintain focus. I wonder if these elements together would create a good user experience. It's essential to think about how they’ll work together in practice!