data-table-component
the brief, redacted

Design a dense data table with sorting affordances and a selected row state. Tests whether a model can make information density feel calm rather than cramped.

559 chars · 82 words · fingerprint 3b4a4ef0b3ee

raw output — byte exact

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Deployments</title>
<style>
  :root {
    --bg: #e8eaed;
    --surface: #ffffff;
    --border: #d7dade;
    --border-strong: #c3c7cc;
    --text: #1f2328;
    --text-dim: #626c76;
    --accent: #2456c4;
    --accent-soft: #eaf0fc;
    --hover: #f4f6f8;
    --ok: #1a7f37;
    --fail: #c0392b;
    --warn: #9a6700;
    --run: #2456c4;
    font-size: 16px;
  }

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

  html, body {
    background: var(--bg);
    font-family: "Segoe UI", -apple-system, "Helvetica Neue", Arial, sans-serif;
    color: var(--text);
    -webkit-font-smoothing: antialiased;
  }

  body {
    display: flex;
    justify-content: center;
    padding: 56px 40px;
  }

  .panel {
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    box-shadow: 0 1px 2px rgba(20,25,32,0.06), 0 4px 14px rgba(20,25,32,0.05);
    overflow: hidden;
    width: 940px;
    max-width: 100%;
  }

  .panel-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 14px 18px 12px;
    border-bottom: 1px solid var(--border);
  }

  .panel-head h1 {
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.01em;
  }

  .panel-head .meta {
    font-size: 11.5px;
    color: var(--text-dim);
  }

  table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12.5px;
    table-layout: fixed;
  }

  col.c-status  { width: 118px; }
  col.c-service { width: auto; }
  col.c-region  { width: 122px; }
  col.c-deploy  { width: 138px; }
  col.c-dur     { width: 84px; }
  col.c-time    { width: 172px; }

  thead th {
    text-align: left;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-dim);
    background: #fafbfc;
    border-bottom: 1px solid var(--border-strong);
    padding: 0;
    user-select: none;
  }

  thead th .th-inner {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 9px 12px;
    cursor: pointer;
    white-space: nowrap;
  }

  thead th .th-inner:hover { color: var(--text); }

  thead th.num .th-inner { justify-content: flex-end; }

  /* active sort column */
  thead th.sorted {
    color: var(--text);
    background: #f1f3f6;
    box-shadow: inset 0 -2px 0 var(--accent);
  }
  thead th.sorted .th-inner { color: var(--text); }

  .sort-arrow {
    font-size: 9px;
    line-height: 1;
    color: var(--accent);
  }
  .sort-arrow.idle {
    color: #b6bcc4;
    visibility: hidden;
  }
  thead th .th-inner:hover .sort-arrow.idle { visibility: visible; }

  tbody td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
  }

  tbody tr:last-child td { border-bottom: none; }

  tbody tr:hover { background: var(--hover); }

  /* statically demonstrated hover state */
  tr.is-hover { background: var(--hover); }

  /* selected row */
  tr.is-selected {
    background: var(--accent-soft);
  }
  tr.is-selected td:first-child {
    box-shadow: inset 3px 0 0 var(--accent);
  }
  tr.is-selected:hover { background: #e0e9fa; }

  .mono {
    font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
    font-size: 11.5px;
  }

  .svc {
    font-weight: 600;
    color: var(--text);
  }
  .svc .ver {
    font-weight: 400;
    color: var(--text-dim);
    font-family: Consolas, Menlo, monospace;
    font-size: 11px;
    margin-left: 6px;
  }

  .num { text-align: right; }
  .dim { color: var(--text-dim); }

  /* status badges: icon glyph + label, never colour alone */
  .status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    font-size: 11.5px;
  }
  .status .glyph {
    display: inline-flex;
    width: 14px;
    height: 14px;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 9px;
    font-weight: 700;
    line-height: 1;
    flex: none;
  }
  .st-ok      { color: var(--ok); }
  .st-ok .glyph      { background: #dcf0e2; color: var(--ok); }
  .st-fail    { color: var(--fail); }
  .st-fail .glyph    { background: #fbe3e0; color: var(--fail); }
  .st-run     { color: var(--run); }
  .st-run .glyph     { background: #e2eafb; color: var(--run); }
  .st-roll    { color: var(--warn); }
  .st-roll .glyph    { background: #f8ecd2; color: var(--warn); }

  .user {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
  }
  .avatar {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #dfe3e8;
    color: #4a5563;
    font-size: 8.5px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    letter-spacing: 0.02em;
  }

  .panel-foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 9px 18px;
    border-top: 1px solid var(--border);
    font-size: 11.5px;
    color: var(--text-dim);
    background: #fafbfc;
  }
</style>
</head>
<body>

<div class="panel">
  <div class="panel-head">
    <h1>Server Deployments</h1>
    <span class="meta">8 records &middot; last refreshed 09:42 UTC</span>
  </div>

  <table aria-label="Server deployment records">
    <colgroup>
      <col class="c-status"><col class="c-service"><col class="c-region">
      <col class="c-deploy"><col class="c-dur"><col class="c-time">
    </colgroup>
    <thead>
      <tr>
        <th scope="col"><span class="th-inner">Status <span class="sort-arrow idle">&#9650;</span></span></th>
        <th scope="col"><span class="th-inner">Service <span class="sort-arrow idle">&#9650;</span></span></th>
        <th scope="col"><span class="th-inner">Region <span class="sort-arrow idle">&#9650;</span></span></th>
        <th scope="col"><span class="th-inner">Deployed by <span class="sort-arrow idle">&#9650;</span></span></th>
        <th scope="col" class="num"><span class="th-inner">Duration <span class="sort-arrow idle">&#9650;</span></span></th>
        <th scope="col" class="sorted" aria-sort="descending">
          <span class="th-inner">Timestamp <span class="sort-arrow">&#9660;</span></span>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><span class="status st-run"><span class="glyph">&#9654;</span>Running</span></td>
        <td class="svc">billing-api <span class="ver">v3.9.1</span></td>
        <td class="mono">eu-west-1</td>
        <td><span class="user"><span class="avatar">RK</span>r.kaur</span></td>
        <td class="num mono dim">1m 12s</td>
        <td class="mono dim">2024-05-14 09:41:07</td>
      </tr>
      <tr class="is-selected" aria-selected="true">
        <td><span class="status st-ok"><span class="glyph">&#10003;</span>Success</span></td>
        <td class="svc">auth-gateway <span class="ver">v2.4.0</span></td>
        <td class="mono">us-east-1</td>
        <td><span class="user"><span class="avatar">MO</span>m.okafor</span></td>
        <td class="num mono dim">2m 48s</td>
        <td class="mono dim">2024-05-14 09:18:33</td>
      </tr>
      <tr class="is-hover">
        <td><span class="status st-fail"><span class="glyph">&#10005;</span>Failed</span></td>
        <td class="svc">search-indexer <span class="ver">v1.17.4</span></td>
        <td class="mono">ap-south-1</td>
        <td><span class="user"><span class="avatar">JT</span>j.tanaka</span></td>
        <td class="num mono dim">0m 54s</td>
        <td class="mono dim">2024-05-14 08:52:19</td>
      </tr>
      <tr>
        <td><span class="status st-ok"><span class="glyph">&#10003;</span>Success</span></td>
        <td class="svc">notifications <span class="ver">v5.2.7</span></td>
        <td class="mono">eu-central-1</td>
        <td><span class="user"><span class="avatar">AL</span>a.lindgren</span></td>
        <td class="num mono dim">3m 05s</td>
        <td class="mono dim">2024-05-14 07:36:48</td>
      </tr>
      <tr>
        <td><span class="status st-roll"><span class="glyph">&#8634;</span>Rolled&nbsp;back</span></td>
        <td class="svc">payments-worker <span class="ver">v4.0.0</span></td>
        <td class="mono">us-west-2</td>
        <td><span class="user"><span class="avatar">MO</span>m.okafor</span></td>
        <td class="num mono dim">6m 31s</td>
        <td class="mono dim">2024-05-14 06:04:12</td>
      </tr>
      <tr>
        <td><span class="status st-ok"><span class="glyph">&#10003;</span>Success</span></td>
        <td class="svc">media-transcoder <span class="ver">v0.9.12</span></td>
        <td class="mono">sa-east-1</td>
        <td><span class="user"><span class="avatar">CD</span>c.duarte</span></td>
        <td class="num mono dim">4m 22s</td>
        <td class="mono dim">2024-05-13 22:47:55</td>
      </tr>
      <tr>
        <td><span class="status st-fail"><span class="glyph">&#10005;</span>Failed</span></td>
        <td class="svc">edge-router <span class="ver">v7.1.3</span></td>
        <td class="mono">us-east-2</td>
        <td><span class="user"><span class="avatar">RK</span>r.kaur</span></td>
        <td class="num mono dim">1m 47s</td>
        <td class="mono dim">2024-05-13 20:15:02</td>
      </tr>
      <tr>
        <td><span class="status st-ok"><span class="glyph">&#10003;</span>Success</span></td>
        <td class="svc">analytics-etl <span class="ver">v2.11.0</span></td>
        <td class="mono">ap-northeast-1</td>
        <td><span class="user"><span class="avatar">JT</span>j.tanaka</span></td>
        <td class="num mono dim">8m 16s</td>
        <td class="mono dim">2024-05-13 18:29:40</td>
      </tr>
    </tbody>
  </table>

  <div class="panel-foot">
    <span>1 row selected</span>
    <span>Sorted by timestamp &middot; newest first</span>
  </div>
</div>

<script>
  // Minimal interactive affordance: clicking a header toggles the sorted state indicator.
  document.querySelectorAll('thead th').forEach(function (th) {
    th.querySelector('.th-inner').addEventListener('click', function () {
      var current = document.querySelector('thead th.sorted');
      if (current === th) {
        var arrow = th.querySelector('.sort-arrow');
        arrow.innerHTML = arrow.innerHTML.trim() === '\u25B2' ? '&#9660;' : '&#9650;';
        th.setAttribute('aria-sort', arrow.innerHTML.trim() === '\u25B2' ? 'ascending' : 'descending');
        return;
      }
      if (current) {
        current.classList.remove('sorted');
        current.removeAttribute('aria-sort');
        current.querySelector('.sort-arrow').className = 'sort-arrow idle';
        current.querySelector('.sort-arrow').innerHTML = '&#9650;';
      }
      th.classList.add('sorted');
      th.setAttribute('aria-sort', 'ascending');
      var a = th.querySelector('.sort-arrow');
      a.className = 'sort-arrow';
      a.innerHTML = '&#9650;';
    });
  });

  // Row selection on click.
  document.querySelectorAll('tbody tr').forEach(function (tr) {
    tr.addEventListener('click', function () {
      var sel = document.querySelector('tbody tr.is-selected');
      if (sel) { sel.classList.remove('is-selected'); sel.removeAttribute('aria-selected'); }
      tr.classList.add('is-selected');
      tr.setAttribute('aria-selected', 'true');
    });
  });
</script>

</body>
</html>

request envelope — prompt redacted

{
  "model": "anthropic/claude-fable-5",
  "system": "Respond with a single complete, self-contained HTML document rendering the component and nothing else. No markdown fences, no explanation. Inline all CSS and JavaScript, reference no external resource. Render the component at its natural size on a neutral background, with enough surrounding space that it can be photographed.",
  "messages": [
    {
      "role": "user",
      "content": "«REDACTED — 87 words, 559 chars»"
    }
  ],
  "maxOutputTokens": 32000,
  "gatewayStringId": "edf0793e-2e8b-4fa7-9a2c-3f5896800c71"
}