// Blog index — filterable by tag, reverse chronological
const Writing = ({ onNav }) => {
  const [filter, setFilter] = React.useState('all');
  const posts = [
    ['2026-04-18', 'the agentic loop, explained by its failure modes', 'A loop isn\'t clever until it can admit defeat.', ['agents', 'patterns'], true, '14 min'],
    ['2026-04-11', 'hybrid search in three lines — and a thousand tradeoffs', 'BM25 and vectors are easy to combine. Knowing which to trust when they disagree is the entire job.', ['rag'], true, '11 min'],
    ['2026-04-02', 'langfuse in production: what i actually use it for', 'After a year of observability, the surprising answer isn\'t traces.', ['infra'], false, '8 min'],
    ['2026-03-25', 'structured output is a contract, not a format', 'Why JSON mode is an interface, not a feature.', ['fundamentals'], true, '9 min'],
    ['2026-03-18', 'ollama on a laptop: granite-4b vs llama-3.2-3b, measured', 'Tokens per second, memory, and the thing no one benchmarks.', ['oss'], true, '16 min'],
    ['2026-03-10', 'why i stopped writing eval code by hand', 'Ragas, a small harness, and the tests that actually catch drift.', ['rag'], false, '7 min'],
    ['2026-02-28', 'tool calling is a state machine with bad documentation', 'Every agent framework is hiding the same shape.', ['agents'], true, '12 min'],
    ['2026-02-19', 'streaming is easy. backpressure is the hard part', 'What happens when the model is faster than your UI.', ['fundamentals'], false, '6 min'],
    ['2026-02-11', 'mcp in anger: a week of migrating tools', 'The protocol is small. The ergonomics matter more than the spec.', ['agents', 'infra'], true, '10 min'],
    ['2026-02-03', 'docker for AI: the four images you actually need', 'Model server, vector db, reranker, gateway.', ['infra'], false, '9 min'],
    ['2026-01-24', 'chunking strategies, ranked by how often i change my mind', 'Recursive, semantic, token, sliding — and when each wins.', ['rag'], true, '13 min'],
    ['2026-01-15', 'the cost of an agent is not the model call', 'Observability bills, vector storage, reranker latency.', ['infra'], false, '8 min'],
  ];
  const tags = ['all', 'agents', 'rag', 'infra', 'fundamentals', 'oss', 'patterns'];
  const filtered = filter === 'all' ? posts : posts.filter(p => p[3].includes(filter));

  return (
    <PageShell topPath="~/writing" topCurrent="./ls -la" nav="writing" onNav={onNav}>
      <section style={{ padding: '44px 0 20px' }}>
        <div style={{ fontFamily: 'var(--mono)', fontSize: 11, color: 'var(--brass)', marginBottom: 12 }}>~/writing/index.md</div>
        <h1 style={{ fontFamily: 'var(--mono)', fontSize: 28, fontWeight: 700, letterSpacing: '-0.03em', margin: 0, color: 'var(--fg)', textTransform: 'uppercase' }}>
          # Writing
        </h1>
        <div style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--fg-dim)', marginTop: 12, maxWidth: 560, lineHeight: 1.7 }}>
          Deep dives, quick notes, and retrospectives. {posts.length} entries. Posts with
          a <span style={{ color: 'var(--brass)' }}>◉ lab</span> badge ship with a working companion repo.
        </div>
      </section>

      <div style={{ padding: '0 0 20px', display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--fg-dimmer)', marginRight: 8, textTransform: 'uppercase', letterSpacing: '0.08em' }}>grep tag:</span>
        {tags.map(t => (
          <button key={t} onClick={() => setFilter(t)} style={{
            fontFamily: 'var(--mono)', fontSize: 11,
            color: filter === t ? 'var(--brass)' : 'var(--fg-dim)',
            border: filter === t ? '1px solid var(--brass)' : '1px solid var(--rule)',
            background: 'transparent', padding: '3px 10px', cursor: 'pointer',
          }}>{t === 'all' ? 'all' : `#${t}`}</button>
        ))}
        <span style={{ flex: 1 }} />
        <span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--fg-dimmer)' }}>
          sort: date desc · {filtered.length} / {posts.length}
        </span>
      </div>

      <section style={{ padding: '0 0 40px', borderTop: '1px solid var(--rule)' }}>
        {filtered.map(([d, title, dek, tgs, lab, rt]) => (
          <a key={title} onClick={() => onNav('article')} style={{
            display: 'grid', gridTemplateColumns: '120px 1fr auto', gap: 24, padding: '22px 0',
            borderBottom: '1px dashed var(--rule)', alignItems: 'baseline', cursor: 'pointer', textDecoration: 'none',
          }}>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 11, color: 'var(--fg-dimmer)', fontVariantNumeric: 'tabular-nums' }}>{d}</div>
            <div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 15, color: 'var(--fg)', fontWeight: 500, marginBottom: 6 }}>{title}</div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--fg-dim)', lineHeight: 1.6, marginBottom: 10, maxWidth: 560 }}>{dek}</div>
              <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
                {tgs.map(tg => <Tag key={tg}>#{tg}</Tag>)}
                {lab && <LabBadge />}
              </div>
            </div>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--fg-dimmer)', whiteSpace: 'nowrap' }}>{rt} →</div>
          </a>
        ))}
      </section>
    </PageShell>
  );
};

window.Writing = Writing;
