/* global React */
/* ============================================================
   Insights — index + article template
   ============================================================ */

const { useEffect: iEffect, useState: iState, useMemo: iMemo } = React;

const INSIGHTS = [
  {
    slug: 'leaders-who-never-explain',
    date: '2026 · Nov',
    category: 'Composure',
    kind: 'Field note',
    title: 'The leaders who never explain themselves into a room.',
    excerpt: 'They state the position once. They do not extend the case. The room does the work of catching up to them.',
    mins: 6,
    tone: 'warm',
  },
  {
    slug: 'composure-compounds',
    date: '2026 · Oct',
    category: 'Identity',
    kind: 'On record',
    title: 'Why composure compounds. And what corrodes it.',
    excerpt: 'Composure is the only leadership behaviour with returns to scale. The cost is that it is also the most expensive to repair once lost.',
    mins: 8,
    tone: 'cool',
  },
  {
    slug: 'authority-not-borrowed',
    date: '2026 · Sep',
    category: 'Authority',
    kind: 'Essay',
    title: 'Authority not borrowed, but embodied. A working theory.',
    excerpt: 'External authority can hide internal fragmentation for years, until a moment of real consequence asks it to hold. Often, it does not.',
    mins: 11,
    tone: 'warm',
  },
  {
    slug: 'the-second-clause',
    date: '2026 · Aug',
    category: 'Composure',
    kind: 'Field note',
    title: 'The second clause is the leak.',
    excerpt: 'A clean answer ends. A frayed answer adds. The frequency of your second clauses is the most accurate reading of where the pressure sits.',
    mins: 4,
    tone: 'cool',
  },
  {
    slug: 'rooms-that-do-not-give',
    date: '2026 · Jul',
    category: 'Pressure',
    kind: 'Essay',
    title: 'On rooms that do not give.',
    excerpt: 'A room that does not give is not hostile. It is honest. Most leaders learn how to read hostile rooms. Few learn how to read honest ones.',
    mins: 9,
    tone: 'warm',
  },
  {
    slug: 'private-cost-of-public-composure',
    date: '2026 · Jun',
    category: 'Recovery',
    kind: 'On record',
    title: 'The private cost of public composure.',
    excerpt: 'If nothing slips in the room, the question worth holding is what slips after. Composure without recovery is the longest, quietest tax in senior leadership.',
    mins: 7,
    tone: 'cool',
  },
];

function getInsight(slug) {
  return INSIGHTS.find((i) => i.slug === slug);
}

/* ============================================================
   INSIGHTS INDEX
   ============================================================ */
function InsightsIndexPage() {
  const router = useRouter();
  const [filter, setFilter] = iState('All');
  const cats = ['All', ...Array.from(new Set(INSIGHTS.map(i => i.category)))];
  const items = filter === 'All' ? INSIGHTS : INSIGHTS.filter(i => i.category === filter);
  const featured = items[0];
  const rest = items.slice(1);

  return (
    <div className="page-fade">
      {/* Header */}
      <section style={{ position: 'relative', overflow: 'hidden', paddingTop: 160, paddingBottom: 60 }}>
        <Beam intensity={0.35} from="-8%" width="60%" sweep />
        <div className="container" style={{ position: 'relative', zIndex: 2 }}>
          <div style={{
            display: 'grid',
            gridTemplateColumns: '1.4fr 1fr',
            gap: 80,
            alignItems: 'center',
          }} data-asym="">
            <Reveal>
              <Eyebrow>Field notes · Essays · On record</Eyebrow>
              <h1 style={{
                fontSize: 'clamp(40px, 5.4vw, 88px)',
                fontWeight: 600,
                lineHeight: 0.98,
                letterSpacing: '-0.035em',
                color: '#fff',
                margin: '28px 0 28px',
                textWrap: 'balance',
                maxWidth: '14ch',
              }}>
                Notes from the room.
              </h1>
              <p style={{
                fontSize: 19,
                color: 'var(--c-steel-300)',
                lineHeight: 1.55,
                fontWeight: 300,
                maxWidth: '52ch',
                margin: 0,
              }}>
                Short, deliberate writing on identity, authority, and what the room actually reads. Published infrequently. Sent privately to a small list.
              </p>
            </Reveal>

            <Reveal delay={140} style={{ alignSelf: 'center' }}>
              <ImageSlot label="from the room" tone="cool" ratio="3 / 4" src="assets/images/field-notes-daniel.jpg" showLabel={false} />
            </Reveal>
          </div>
        </div>
      </section>

      {/* Filter rail */}
      <section className="section-tight">
        <div className="container">
          <div style={{
            display: 'flex',
            gap: 24,
            paddingBottom: 24,
            borderBottom: '1px solid var(--line)',
            flexWrap: 'wrap',
            alignItems: 'center',
          }}>
            <Eyebrow>Filter</Eyebrow>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {cats.map(c => (
                <button key={c} onClick={() => setFilter(c)}
                  style={{
                    padding: '8px 16px',
                    border: '1px solid ' + (filter === c ? 'var(--accent)' : 'var(--line-strong)'),
                    background: filter === c ? 'rgba(212,169,66,0.06)' : 'transparent',
                    color: filter === c ? 'var(--c-glow-200)' : 'var(--c-steel-300)',
                    fontSize: 11,
                    letterSpacing: '0.18em',
                    textTransform: 'uppercase',
                    fontWeight: 500,
                    cursor: 'pointer',
                    transition: 'all 220ms var(--ease-out)',
                    borderRadius: 2,
                  }}>
                  {c}
                </button>
              ))}
            </div>
          </div>
        </div>
      </section>

      {/* Featured + grid */}
      <section style={{ paddingBottom: 'calc(120px * var(--tdp-density))' }}>
        <div className="container">
          {featured && (
            <Reveal>
              <a href={'/insights/' + featured.slug} onClick={(e) => { e.preventDefault(); router.go('/insights/' + featured.slug); }}
                 style={{ textDecoration: 'none', display: 'block', marginBottom: 96 }}>
                <div style={{
                  display: 'grid',
                  gridTemplateColumns: '1.3fr 1fr',
                  gap: 64,
                  alignItems: 'end',
                }} data-asym="">
                  <div>
                    <div style={{ display: 'flex', gap: 20, alignItems: 'baseline', marginBottom: 22 }}>
                      <Eyebrow>Featured · {featured.kind}</Eyebrow>
                      <span style={{ fontSize: 11, color: 'var(--c-slate-ocean)', letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 500 }}>{featured.date}</span>
                    </div>
                    <h2 style={{
                      fontSize: 'clamp(34px, 4.4vw, 64px)',
                      fontWeight: 500,
                      letterSpacing: '-0.028em',
                      color: '#fff',
                      lineHeight: 1.04,
                      margin: '0 0 28px',
                      textWrap: 'balance',
                      maxWidth: '20ch',
                    }}>
                      {featured.title}
                    </h2>
                    <p style={{
                      fontSize: 18,
                      color: 'var(--c-steel-300)',
                      lineHeight: 1.55,
                      fontWeight: 300,
                      margin: '0 0 32px',
                      maxWidth: '54ch',
                    }}>
                      {featured.excerpt}
                    </p>
                    <span style={{
                      color: 'var(--c-glow-500)',
                      fontSize: 11,
                      letterSpacing: '0.22em',
                      textTransform: 'uppercase',
                      fontWeight: 500,
                      display: 'inline-flex',
                      alignItems: 'center',
                      gap: 8,
                    }}>
                      Read · {featured.mins} min <i data-lucide="arrow-right" style={{ width: 13, height: 13 }} />
                    </span>
                  </div>
                  <ImageSlot label="warm-cool · low light" tone={featured.tone} ratio="4 / 5" src="assets/images/field-notes-daniel.jpg" showLabel={false} />
                </div>
              </a>
            </Reveal>
          )}

          <div style={{
            display: 'grid',
            gridTemplateColumns: 'repeat(3, 1fr)',
            gap: 0,
            borderTop: '1px solid var(--line)',
            borderLeft: '1px solid var(--line)',
          }} data-asym="">
            {rest.map((n, i) => (
              <Reveal key={n.slug} delay={i * 60}>
                <InsightTile n={n} onClick={() => router.go('/insights/' + n.slug)} />
              </Reveal>
            ))}
          </div>
        </div>
      </section>

      <section style={{ background: 'var(--c-nightfall)', padding: 'calc(100px * var(--tdp-density)) 0' }}>
        <div className="container">
          <NewsletterRail />
        </div>
      </section>
    </div>
  );
}

function InsightTile({ n, onClick }) {
  const [hover, setHover] = iState(false);
  return (
    <a href={'/insights/' + n.slug} onClick={(e) => { e.preventDefault(); onClick(); }}
       onMouseEnter={() => setHover(true)}
       onMouseLeave={() => setHover(false)}
       style={{
         display: 'flex',
         flexDirection: 'column',
         padding: '36px 32px 40px',
         borderRight: '1px solid var(--line)',
         borderBottom: '1px solid var(--line)',
         textDecoration: 'none',
         color: 'inherit',
         position: 'relative',
         minHeight: 320,
         gap: 22,
         transition: 'background 280ms var(--ease-out)',
         background: hover ? 'rgba(255,255,255,0.012)' : 'transparent',
       }}>
      <div style={{
        position: 'absolute', top: 0, left: 0,
        width: hover ? '60%' : 0, height: 2,
        background: 'var(--accent)',
        transition: 'width 480ms var(--ease-out)',
      }} />
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <span style={{ fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 500 }}>{n.category}</span>
        <span style={{ fontSize: 10, letterSpacing: '0.18em', textTransform: 'uppercase', color: 'var(--c-slate-ocean)', fontWeight: 500 }}>{n.date}</span>
      </div>
      <div style={{
        fontSize: 22,
        fontWeight: 500,
        color: '#fff',
        letterSpacing: '-0.014em',
        lineHeight: 1.22,
        textWrap: 'balance',
      }}>{n.title}</div>
      <p style={{
        fontSize: 14,
        color: 'var(--c-steel-300)',
        lineHeight: 1.6,
        fontWeight: 300,
        margin: 0,
        flex: 1,
      }}>{n.excerpt}</p>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        paddingTop: 16, borderTop: '1px solid var(--line)',
        fontSize: 11,
        letterSpacing: '0.18em',
        textTransform: 'uppercase',
        fontWeight: 500,
      }}>
        <span style={{ color: 'var(--c-steel-300)' }}>{n.kind} · {n.mins} min</span>
        <span style={{ color: hover ? 'var(--c-glow-200)' : 'var(--c-glow-500)' }}>
          Read <i data-lucide="arrow-right" style={{ width: 12, height: 12, marginLeft: 3 }}></i>
        </span>
      </div>
    </a>
  );
}

function NewsletterRail() {
  const [submitted, setSubmitted] = iState(false);
  const [email, setEmail] = iState('');
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: '1fr 1fr',
      gap: 80,
      alignItems: 'center',
    }} data-asym="">
      <div>
        <Eyebrow>The private list</Eyebrow>
        <h2 style={{
          fontSize: 'clamp(28px, 3vw, 44px)',
          fontWeight: 500,
          letterSpacing: '-0.025em',
          color: '#fff',
          lineHeight: 1.1,
          margin: '18px 0 16px',
          textWrap: 'balance',
          maxWidth: '22ch',
        }}>
          A short note. Sent infrequently. No funnel.
        </h2>
        <p style={{ fontSize: 15, color: 'var(--c-steel-300)', lineHeight: 1.65, fontWeight: 300, margin: 0, maxWidth: '48ch' }}>
          New field notes, sent the morning they are published. One read. No promotion. No automated sequence.
        </p>
      </div>
      <div>
        {!submitted ? (
          <form onSubmit={(e) => { e.preventDefault(); setSubmitted(true); }}
            style={{ display: 'flex', gap: 16, alignItems: 'flex-end' }}>
            <FormField label="Email">
              <input className="input" type="email" required value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@firm.com" />
            </FormField>
            <Button variant="primary" type="submit">Subscribe</Button>
          </form>
        ) : (
          <div style={{ padding: '24px 0', borderTop: '1px solid var(--accent)' }}>
            <Eyebrow>Subscribed</Eyebrow>
            <p style={{ fontSize: 17, color: '#fff', fontWeight: 300, marginTop: 12 }}>You will hear from Daniel when the next note is published.</p>
          </div>
        )}
      </div>
    </div>
  );
}

/* ============================================================
   ARTICLE TEMPLATE
   ============================================================ */

// Article bodies — sample-faithful prose. Each is keyed by slug.
const ARTICLE_BODIES = {
  'leaders-who-never-explain': [
    'Some leaders state a position once. They do not extend the case. They do not stack reasons. They put the position down on the table and they leave it there.',
    'The first time you watch it, it reads as confidence. The second time, you realise it is something else. It is the absence of need.',
    { type: 'h2', text: 'The room catches up.' },
    'Most senior leaders are trained, often unconsciously, to bring the room along. They explain. They contextualise. They pre-empt the question. The instinct is generous. It is also expensive.',
    'A position that arrives with five reasons reads as five reasons. A position that arrives once, and stops, reads as a position.',
    'The room does the work of catching up. The room actually likes doing that work. The room dislikes being pulled along.',
    { type: 'h2', text: 'What this is not.' },
    'It is not refusal to explain. It is not theatre. It is not silence as strategy. Each of those is performance, and the room can tell.',
    'It is the calibrated trust that what you said was sufficient. That you do not need to add to it. That the absence of the second clause is the message.',
    { type: 'pull', text: 'The frequency of your second clauses is the most accurate reading of where the pressure sits.' },
    { type: 'h2', text: 'A small practice.' },
    'In your next senior conversation, count your second clauses. Not your sentences. Your second clauses. The "and also." The "what I mean is." The "to be clear."',
    'Most leaders are surprised by the count. The count is the leak.',
  ],
  'composure-compounds': [
    'Composure is the only leadership behaviour with returns to scale. Strategy ages. Vision ages. Knowledge ages. Composure compounds.',
    'Every senior decision is made twice. Once in the meeting, where the room is reading you, and once in the room\u2019s memory afterward, where the meeting is recalled by what you looked like more than by what you said.',
    { type: 'h2', text: 'The compounding.' },
    'A leader who is composed in three rooms is read as composed by three rooms. The next room they enter has already inherited that reading. The pressure they walk into is structurally lower.',
    'It is not optics. It is acoustics. Composure changes how loud the room has to be to be heard, which changes how loud the leader has to be to respond.',
    { type: 'h2', text: 'The corrosion.' },
    'Composure is corroded in two directions. The first is acceleration. Tempo, pitch, breath. A composure that frays through pace.',
    'The second is delay. Holding the room perfectly, paying the cost in the night. A composure that frays through privacy.',
    'Both are common. Both are usually invisible to the leader, and increasingly visible to the room over time.',
    { type: 'pull', text: 'Composure without recovery is the longest, quietest tax in senior leadership.' },
  ],
  'authority-not-borrowed': [
    'External authority can hide internal fragmentation for years, until a moment of real consequence asks it to hold. Often, it does not.',
    'This is the central observation underneath everything I work on. The room can read certainty in a leader who has not yet read it in themselves. The mismatch is invisible. Until it is not.',
    { type: 'h2', text: 'The two kinds of authority.' },
    'Borrowed authority comes from role, from history, from the org chart, from the brand of the firm. It works. It works well. It works until the moment it is asked to do something it cannot.',
    'Embodied authority comes from a structural alignment between the leader and the seat they occupy. The two are not the same person performing two parts. They are one person.',
    { type: 'h2', text: 'Why the difference shows up late.' },
    'Most rooms do not test authority. Most rooms ratify it. The leader walks in, the room receives, the meeting proceeds. The structure underneath the authority is never stressed.',
    'A moment of consequence stresses it. A board push-back. A founder revisiting a decision. A regulator. An IPO road show. A press conference that runs long.',
    'Under stress, borrowed authority leaks. Embodied authority does not. The leak is the diagnostic.',
    { type: 'pull', text: 'A lighthouse does not chase ships. It does not move with the storm. It remains structurally aligned within itself.' },
    { type: 'h2', text: 'The work.' },
    'The work is structural, not performative. It is not new language. It is not a new posture. It is the slow, deliberate alignment between identity and seat, until the two stop being distinguishable.',
    'When that happens, authority stops being borrowed. The room reads it differently because it is different.',
  ],
  'the-second-clause': [
    'A clean answer ends. A frayed answer adds. The frequency of your second clauses is the most accurate reading of where the pressure sits.',
    { type: 'h2', text: 'Watch the next clause.' },
    'When a senior leader is asked a hard question, listen for the comma. The comma is where the decision is made: end the answer, or extend it.',
    'A leader who is settled ends. A leader under pressure extends. The pressure is rarely about the question. The pressure is about the leader\u2019s relationship to having spoken.',
    { type: 'pull', text: 'The frequency of your second clauses is the most accurate reading of where the pressure sits.' },
  ],
  'rooms-that-do-not-give': [
    'A room that does not give is not hostile. It is honest. Most leaders learn how to read hostile rooms. Few learn how to read honest ones.',
    { type: 'h2', text: 'The difference.' },
    'A hostile room is performing scepticism. It has decided in advance. It is testing whether you will hold under pressure that is not actually being applied.',
    'An honest room is not performing anything. It is reading you. It is making a decision based on what it sees. It does not telegraph its decision because it has not made it yet.',
    { type: 'h2', text: 'What rooms that do not give actually need.' },
    'They do not need your case. They have read your case. They need the structural answer to a question they have not asked.',
    'The question is: are you the one who will hold this when it gets harder than it is right now.',
  ],
  'private-cost-of-public-composure': [
    'If nothing slips in the room, the question worth holding is what slips after. Composure without recovery is the longest, quietest tax in senior leadership.',
    { type: 'h2', text: 'The pattern.' },
    'The leader holds. The leader holds beautifully. The meeting ends. The leader walks out and the cost begins.',
    'It shows up in sleep. It shows up in the first conversation of the next day, which inherits the unfinished business of the previous one. It shows up in the body, slowly, across years.',
    { type: 'h2', text: 'Why this is hard to see.' },
    'Peers cannot see it. The room cannot see it. The leader themselves often cannot see it, because the cost is paid in a register that is not part of the meeting.',
    'The people closest to the leader can see it. They rarely have the language for it. They name it after they leave.',
    { type: 'pull', text: 'The room is over when the room is over. Reclaim the night.' },
  ],
};

function InsightArticlePage({ slug }) {
  const router = useRouter();
  const insight = getInsight(slug);
  const body = ARTICLE_BODIES[slug];

  if (!insight) {
    return (
      <div className="page-fade">
        <section style={{ paddingTop: 200, minHeight: '80vh' }}>
          <div className="container-narrow" style={{ textAlign: 'center' }}>
            <Eyebrow>Not found</Eyebrow>
            <h1 style={{ fontSize: 'clamp(32px, 4vw, 56px)', color: '#fff', fontWeight: 500, margin: '24px 0', letterSpacing: '-0.028em' }}>This note has been retired.</h1>
            <Button variant="primary" href="/insights">All writing</Button>
          </div>
        </section>
      </div>
    );
  }

  // related = same category, different slug, max 2
  const related = INSIGHTS.filter(i => i.category === insight.category && i.slug !== slug).slice(0, 2);

  return (
    <div className="page-fade">
      <ArticleParagraphStyle />

      {/* Article header */}
      <section style={{ position: 'relative', overflow: 'hidden', paddingTop: 160, paddingBottom: 60 }}>
        <Beam intensity={0.3} from="-6%" width="50%" sweep />
        <div className="container-narrow" style={{ position: 'relative', zIndex: 2 }}>
          <Reveal>
            <div style={{ display: 'flex', gap: 18, alignItems: 'baseline', marginBottom: 24 }}>
              <Eyebrow>{insight.kind}</Eyebrow>
              <span style={{ fontSize: 11, color: 'var(--c-slate-ocean)', letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 500 }}>{insight.date}</span>
              <span style={{ fontSize: 11, color: 'var(--accent)', letterSpacing: '0.22em', textTransform: 'uppercase', fontWeight: 500 }}>{insight.category}</span>
            </div>
            <h1 style={{
              fontSize: 'clamp(36px, 5vw, 76px)',
              fontWeight: 600,
              lineHeight: 1.02,
              letterSpacing: '-0.034em',
              color: '#fff',
              margin: '0 0 28px',
              textWrap: 'balance',
            }}>
              {insight.title}
            </h1>
            <p style={{
              fontSize: 21,
              color: 'var(--c-glow-200)',
              fontWeight: 300,
              fontStyle: 'italic',
              lineHeight: 1.4,
              margin: 0,
              maxWidth: '46ch',
              textWrap: 'balance',
            }}>
              {insight.excerpt}
            </p>
            <div style={{ marginTop: 40, display: 'flex', gap: 24, alignItems: 'center' }}>
              <div style={{ width: 36, height: 36, borderRadius: 999, background: 'linear-gradient(160deg, #2a3f5a, #0a1939)', boxShadow: '0 0 0 1px var(--accent)' }} />
              <div>
                <div style={{ fontSize: 14, color: '#fff', fontWeight: 500 }}>Daniel Pledger</div>
                <div style={{ fontSize: 11, letterSpacing: '0.18em', textTransform: 'uppercase', color: 'var(--c-slate-ocean)', fontWeight: 500, marginTop: 4 }}>{insight.mins} min read</div>
              </div>
            </div>
          </Reveal>
        </div>
      </section>

      {/* Article body */}
      <section style={{ paddingBottom: 'calc(100px * var(--tdp-density))' }}>
        <div className="container-narrow" style={{ position: 'relative' }}>
          <Reveal>
            <div className="article-body" style={{ paddingTop: 56, borderTop: '1px solid var(--line)' }}>
              {body && body.map((b, i) => {
                if (typeof b === 'string') return <p key={i}>{b}</p>;
                if (b.type === 'h2') return (
                  <h2 key={i} style={{
                    fontSize: 'clamp(22px, 2vw, 30px)',
                    fontWeight: 500,
                    color: '#fff',
                    letterSpacing: '-0.022em',
                    lineHeight: 1.2,
                    margin: '48px 0 22px',
                    textWrap: 'balance',
                  }}>{b.text}</h2>
                );
                if (b.type === 'pull') return (
                  <div key={i} style={{ margin: '56px 0 56px' }}>
                    <PullQuote>{b.text}</PullQuote>
                  </div>
                );
                return null;
              })}

              {/* Sign-off */}
              <div style={{ marginTop: 64, paddingTop: 32, borderTop: '1px solid var(--line)' }}>
                <Eyebrow>Continue</Eyebrow>
                <p style={{ fontSize: 17, color: 'var(--c-steel-300)', fontWeight: 300, lineHeight: 1.6, marginTop: 16, maxWidth: '48ch' }}>
                  If the pattern in this note recognises something, the audit will read it.
                </p>
                <div style={{ marginTop: 28, display: 'flex', gap: 18, flexWrap: 'wrap' }}>
                  <Button variant="primary" href="/audit">Take the audit</Button>
                  <Button variant="ghost" href="/insights">All writing</Button>
                </div>
              </div>
            </div>
          </Reveal>
        </div>
      </section>

      {/* Related */}
      {related.length > 0 && (
        <section style={{ background: 'var(--c-nightfall)', padding: 'calc(100px * var(--tdp-density)) 0' }}>
          <div className="container">
            <Reveal>
              <Eyebrow>Adjacent</Eyebrow>
              <h2 className="t-h2" style={{ marginTop: 18, marginBottom: 48, maxWidth: '20ch' }}>
                More from this territory.
              </h2>
            </Reveal>
            <div style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(2, 1fr)',
              borderTop: '1px solid var(--line)',
              borderLeft: '1px solid var(--line)',
            }} data-asym="">
              {related.map((r, i) => (
                <Reveal key={r.slug} delay={i * 80}>
                  <InsightTile n={r} onClick={() => router.go('/insights/' + r.slug)} />
                </Reveal>
              ))}
            </div>
          </div>
        </section>
      )}
    </div>
  );
}

Object.assign(window, { InsightsIndexPage, InsightArticlePage, INSIGHTS, getInsight });
