// Direction C — OBSERVATORY
// Echoes the source mark: dark plate, fine grid, blue gradient bleed,
// concentric "S" radial diagram repeated as scaffolding.
// Cards float on the grid. Each is a "station" with a coordinate.

const Observatory = (() => {
  const { useState, useEffect, useRef, useMemo } = React;

  const tokens = (dark) => ({
    bg:       dark ? '#06080d' : '#eef0f5',
    bgDeep:   dark ? '#03050a' : '#e2e6ee',
    plate:    dark ? 'rgba(255,255,255,0.04)' : 'rgba(10,18,40,0.04)',
    plateHi:  dark ? 'rgba(255,255,255,0.08)' : 'rgba(10,18,40,0.08)',
    grid:     dark ? 'rgba(120,160,220,0.10)' : 'rgba(10,40,90,0.10)',
    gridStr:  dark ? 'rgba(160,200,255,0.18)' : 'rgba(10,40,90,0.18)',
    ink:      dark ? '#f0f3fb' : '#0a1530',
    inkSoft:  dark ? 'rgba(240,243,251,0.62)' : 'rgba(10,21,48,0.6)',
    rule:     dark ? 'rgba(240,243,251,0.16)' : 'rgba(10,21,48,0.16)',
    ruleSoft: dark ? 'rgba(240,243,251,0.08)' : 'rgba(10,21,48,0.08)',
    blue:     dark ? '#5fa8ff' : '#1f5bd8',
    blueGlow: dark ? 'rgba(60,130,255,0.55)' : 'rgba(31,91,216,0.35)',
  });

  const FONTS = {
    serif: '"Cormorant Garamond", "EB Garamond", Georgia, serif',
    mono:  '"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace',
    sans:  '"Inter Tight", "Helvetica Neue", Arial, sans-serif',
  };

  // Stable pseudo-coordinates so each card has a deterministic "station coord"
  function coord(url) {
    let h = 0; for (let i = 0; i < url.length; i++) h = (h * 131 + url.charCodeAt(i)) >>> 0;
    const lat = (h % 9000) / 100 - 45;       // -45..+45
    const lon = ((h >>> 8) % 36000) / 100 - 180; // -180..+180
    return `${lat.toFixed(2)}° ${lat >= 0 ? 'N' : 'S'} · ${lon.toFixed(2)}° ${lon >= 0 ? 'E' : 'W'}`;
  }

  // ─── Concentric S diagram ─────────────────────────────────
  function ConcentricMark({ size = 220, dark = true, animate = true }) {
    const t = tokens(dark);
    const ringStroke = t.gridStr;
    return (
      <svg viewBox="0 0 200 200" width={size} height={size} style={{ display:'block' }}>
        <defs>
          <radialGradient id="cm-glow" cx="50%" cy="55%" r="55%">
            <stop offset="0%" stopColor={t.blueGlow} />
            <stop offset="100%" stopColor="transparent" />
          </radialGradient>
        </defs>
        <circle cx="100" cy="100" r="95" fill="url(#cm-glow)" />
        {/* outer ticks */}
        {Array.from({ length: 48 }).map((_, i) => {
          const a = (i / 48) * Math.PI * 2;
          const x1 = 100 + Math.cos(a) * 92, y1 = 100 + Math.sin(a) * 92;
          const x2 = 100 + Math.cos(a) * 96, y2 = 100 + Math.sin(a) * 96;
          return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke={ringStroke} strokeWidth="0.7" />;
        })}
        {/* concentric arcs */}
        {[60, 48, 36, 24].map((r, i) => (
          <g key={r} style={animate ? { transformOrigin:'100px 100px', animation: `obs-spin ${24 + i*6}s linear infinite ${i % 2 ? 'reverse' : 'normal'}` } : {}}>
            <path d={`M ${100 - r} 100 A ${r} ${r} 0 0 1 ${100 + r} 100`} stroke="#f5f7ff" strokeWidth="6" fill="none" strokeLinecap="round" />
          </g>
        ))}
        {[60, 48, 36, 24].map((r, i) => (
          <g key={'b'+r} style={animate ? { transformOrigin:'100px 100px', animation: `obs-spin ${30 + i*5}s linear infinite ${i % 2 ? 'normal' : 'reverse'}` } : {}}>
            <path d={`M ${100 + r} 100 A ${r} ${r} 0 0 1 ${100 - r} 100`} stroke="#f5f7ff" strokeWidth="6" fill="none" strokeLinecap="round" transform={`rotate(180 100 100)`} />
          </g>
        ))}
        {/* center dot */}
        <circle cx="100" cy="100" r="3" fill={t.blue} />
      </svg>
    );
  }

  // ─── Boot ─────────────────────────────────────────────────
  function Boot({ done, dark }) {
    const t = tokens(dark);
    const [phase, setPhase] = useState(0);
    useEffect(() => {
      const a = setTimeout(() => setPhase(1), 280);
      const b = setTimeout(() => setPhase(2), 1000);
      const c = setTimeout(() => setPhase(3), 1900);
      const d = setTimeout(() => done(), 2600);
      return () => [a,b,c,d].forEach(clearTimeout);
    }, []);
    return (
      <div style={{
        position:'absolute', inset:0, zIndex: 50, background: t.bg,
        display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center',
        transition:'opacity .55s', opacity: phase >= 3 ? 0 : 1, pointerEvents: phase >= 3 ? 'none' : 'auto',
      }}>
        {/* grid */}
        <div style={{
          position:'absolute', inset:0,
          backgroundImage:
            `linear-gradient(${t.grid} 1px, transparent 1px),
             linear-gradient(90deg, ${t.grid} 1px, transparent 1px)`,
          backgroundSize: '40px 40px',
          maskImage: 'radial-gradient(circle at 50% 50%, black 30%, transparent 75%)',
        }} />
        <div style={{
          transform: `scale(${phase >= 1 ? 1 : .8})`, opacity: phase >= 1 ? 1 : 0,
          transition:'transform .7s cubic-bezier(.2,.7,.3,1), opacity .5s',
        }}>
          <ConcentricMark size={180} dark={dark} animate={phase >= 1} />
        </div>
        <div style={{
          fontFamily: FONTS.serif, fontSize: 28, color: t.ink, marginTop: 28, letterSpacing:'-0.01em',
          opacity: phase >= 2 ? 1 : 0, transform: `translateY(${phase >= 2 ? 0 : 6}px)`, transition:'opacity .5s, transform .5s',
        }}>
          <span style={{ fontStyle:'italic' }}>Suede Labs</span> <span style={{ color: t.inkSoft }}>·</span> Operations Observatory
        </div>
        <div style={{
          fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.22em', color: t.inkSoft, marginTop: 14,
          opacity: phase >= 2 ? 1 : 0, transition:'opacity .5s .15s',
        }}>
          AQUIRING STATIONS · 60 SURFACES · 3 CHAINS · 1 PUBLIC INDEX
        </div>
      </div>
    );
  }

  function hostOf(u) { try { return new URL(u).host; } catch (e) { return u; } }

  // ─── Card ─────────────────────────────────────────────────
  function Card({ item, secIdx, itemIdx, sectionTitle, dark, accent }) {
    const t = tokens(dark);
    const [hover, setHover] = useState(false);
    return (
      <a href={item.url} target="_blank" rel="noreferrer"
        onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
        style={{
          display:'block', position:'relative', textDecoration:'none', color: t.ink,
          background: hover ? t.plateHi : t.plate,
          border: `1px solid ${hover ? t.rule : t.ruleSoft}`,
          padding: '16px 18px 18px',
          minHeight: 154,
          transition: 'background .15s, border-color .15s, transform .15s',
          transform: hover ? 'translateY(-2px)' : 'none',
        }}>
        {/* coord + station number */}
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom: 12 }}>
          <span style={{ fontFamily: FONTS.mono, fontSize: 9, letterSpacing:'0.22em', color: t.inkSoft }}>
            STN {String(secIdx + 1).padStart(2,'0')}·{String(itemIdx + 1).padStart(2,'0')}
          </span>
          <span style={{ display:'flex', alignItems:'center', gap: 6, fontFamily: FONTS.mono, fontSize: 9, letterSpacing:'0.18em', color: accent }}>
            <span style={{
              position:'relative', display:'inline-block', width: 6, height: 6, borderRadius:'50%',
              background: accent, boxShadow: `0 0 0 0 ${accent}`,
              animation: hover ? 'obs-pulse 1.2s ease-out infinite' : 'none',
            }} />
            LIVE
          </span>
        </div>
        <div style={{ fontFamily: FONTS.serif, fontSize: 26, lineHeight: 1.05, fontStyle: hover ? 'italic' : 'normal', letterSpacing:'-0.015em', marginBottom: 8, transition:'font-style .2s' }}>
          {item.label}
        </div>
        <div style={{ fontFamily: FONTS.serif, fontStyle:'italic', fontSize: 13, color: t.inkSoft, lineHeight: 1.45, marginBottom: 14 }}>
          {item.desc}
        </div>
        <div style={{
          position:'absolute', left: 18, right: 18, bottom: 14,
          display:'flex', justifyContent:'space-between', alignItems:'center',
          fontFamily: FONTS.mono, fontSize: 9, letterSpacing:'0.14em', color: t.inkSoft,
          borderTop: `1px solid ${t.ruleSoft}`, paddingTop: 10,
        }}>
          <span style={{ overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', maxWidth: '70%' }}>{hostOf(item.url)}</span>
          <span style={{ color: hover ? accent : t.inkSoft, transition:'color .15s' }}>→</span>
        </div>
        {/* hover overlay — thin coord readout */}
        <div style={{
          position:'absolute', top: 0, right: 0, padding: '4px 8px',
          fontFamily: FONTS.mono, fontSize: 8, letterSpacing:'0.18em', color: accent,
          opacity: hover ? 1 : 0, transition:'opacity .2s',
          background: t.bg, borderLeft: `1px solid ${t.ruleSoft}`, borderBottom: `1px solid ${t.ruleSoft}`,
        }}>
          {coord(item.url)}
        </div>
      </a>
    );
  }

  function SectionBlock({ section, secIdx, query, dark }) {
    const t = tokens(dark);
    const accent = t.blue;
    const visible = useMemo(() => {
      if (!query) return section.items;
      const q = query.toLowerCase();
      return section.items.filter(it =>
        it.label.toLowerCase().includes(q) ||
        (it.desc||'').toLowerCase().includes(q) ||
        it.url.toLowerCase().includes(q) ||
        section.title.toLowerCase().includes(q)
      );
    }, [query, section]);
    if (visible.length === 0) return null;
    return (
      <section id={`obs-sec-${section.id}`} style={{ padding: '36px 36px 8px' }}>
        <div style={{
          display:'grid', gridTemplateColumns: 'auto 1fr auto', gap: 24, alignItems:'baseline', marginBottom: 18,
          paddingBottom: 12, borderBottom: `1px solid ${t.rule}`,
        }}>
          <div style={{ display:'flex', alignItems:'baseline', gap: 12 }}>
            <span style={{ fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.24em', color: t.inkSoft }}>{section.latin.toUpperCase().replace('.','')}</span>
            <span style={{ fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.18em', color: accent }}>· {section.id.toUpperCase()}</span>
          </div>
          <div>
            <span style={{ fontFamily: FONTS.serif, fontSize: 30, fontStyle:'italic', color: t.ink, letterSpacing:'-0.015em' }}>{section.title}</span>
            <span style={{ fontFamily: FONTS.serif, fontSize: 15, fontStyle:'italic', color: t.inkSoft, marginLeft: 14 }}>{section.sub}</span>
          </div>
          <span style={{ fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.18em', color: t.inkSoft }}>
            {visible.length}/{section.items.length} STATIONS
          </span>
        </div>
        <div style={{
          display:'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))', gap: 14,
        }}>
          {visible.map((it, i) => (
            <Card key={it.url + i} item={it} secIdx={secIdx} itemIdx={section.items.indexOf(it)} sectionTitle={section.title} dark={dark} accent={accent} />
          ))}
        </div>
      </section>
    );
  }

  function SuedeObservatory({ dark = true, onToggleDark }) {
    const [query, setQuery] = useState('');
    const [booted, setBooted] = useState(false);
    const t = tokens(dark);
    const data = window.SUEDE_DATA;
    const totalCount = data.sections.reduce((a, s) => a + s.items.length, 0);
    const filteredCount = useMemo(() => {
      if (!query) return totalCount;
      const q = query.toLowerCase();
      return data.sections.reduce((a,s) => a + s.items.filter(it =>
        it.label.toLowerCase().includes(q) ||
        (it.desc||'').toLowerCase().includes(q) ||
        it.url.toLowerCase().includes(q) ||
        s.title.toLowerCase().includes(q)
      ).length, 0);
    }, [query, data, totalCount]);

    // inject keyframes once
    useEffect(() => {
      if (document.getElementById('obs-kf')) return;
      const s = document.createElement('style');
      s.id = 'obs-kf';
      s.textContent = `
        @keyframes obs-spin { to { transform: rotate(360deg); } }
        @keyframes obs-pulse {
          0%   { box-shadow: 0 0 0 0 currentColor; }
          70%  { box-shadow: 0 0 0 10px transparent; }
          100% { box-shadow: 0 0 0 0 transparent; }
        }
        @keyframes obs-sweep {
          from { transform: rotate(0deg); }
          to   { transform: rotate(360deg); }
        }
      `;
      document.head.appendChild(s);
    }, []);

    return (
      <div style={{
        position:'relative', width:'100%', height:'100%', overflow:'auto',
        background: t.bg, color: t.ink, fontFamily: FONTS.sans,
      }}>
        {!booted && <Boot dark={dark} done={() => setBooted(true)} />}

        {/* persistent grid backdrop */}
        <div style={{
          position:'absolute', inset:0, pointerEvents:'none',
          backgroundImage:
            `linear-gradient(${t.grid} 1px, transparent 1px),
             linear-gradient(90deg, ${t.grid} 1px, transparent 1px)`,
          backgroundSize: '40px 40px',
        }} />
        {/* blue bottom glow */}
        <div style={{
          position:'absolute', left: 0, right: 0, bottom: 0, height: '40vh', pointerEvents:'none',
          background: `radial-gradient(ellipse at 50% 100%, ${t.blueGlow} 0%, transparent 65%)`,
        }} />

        {/* Topbar */}
        <div style={{ position:'sticky', top: 0, zIndex: 20, background: dark ? 'rgba(6,8,13,0.85)' : 'rgba(238,240,245,0.85)', backdropFilter:'blur(10px)', borderBottom: `1px solid ${t.rule}` }}>
          <div style={{ display:'grid', gridTemplateColumns:'auto 1fr auto', alignItems:'center', gap: 24, padding: '14px 28px' }}>
            <a href="https://suedeai.ai" target="_blank" rel="noreferrer" style={{ display:'flex', alignItems:'center', gap: 14, textDecoration:'none', color:'inherit' }}>
              <img src="assets/suede-mark.jpeg" alt="Suede Labs" style={{ width: 32, height: 32, objectFit:'cover', borderRadius: 4 }} />
              <div>
                <div style={{ fontFamily: FONTS.mono, fontSize: 9, letterSpacing:'0.24em', color: t.inkSoft }}>SUEDE LABS · OBSERVATORY</div>
                <div style={{ fontFamily: FONTS.serif, fontSize: 17, fontStyle:'italic', color: t.ink, lineHeight: 1.1 }}>Operations across <span style={{ color: accent(t) }}>60 stations</span></div>
              </div>
            </a>
            <div style={{ display:'flex', justifyContent:'center' }}>
              <div style={{
                display:'flex', alignItems:'center', gap: 8, border: `1px solid ${t.rule}`, padding: '8px 14px', borderRadius: 999,
                background: t.plate, minWidth: 360,
              }}>
                <svg width="12" height="12" viewBox="0 0 16 16" style={{ color: t.inkSoft }}><circle cx="7" cy="7" r="5" stroke="currentColor" fill="none"/><line x1="11" y1="11" x2="14" y2="14" stroke="currentColor"/></svg>
                <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="locate a station…"
                  style={{ flex:1, background:'transparent', border:0, outline:'none', color: t.ink, fontFamily: FONTS.serif, fontStyle:'italic', fontSize: 14 }} />
                <span style={{ fontFamily: FONTS.mono, fontSize: 10, color: t.inkSoft }}>{query ? `${filteredCount}/${totalCount}` : totalCount}</span>
              </div>
            </div>
            <button onClick={onToggleDark} style={{
              background: t.plate, color: t.ink, border:`1px solid ${t.rule}`, padding:'8px 14px',
              fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.18em', cursor:'pointer', borderRadius: 999,
            }}>
              {dark ? '☼ DAY' : '☾ NIGHT'}
            </button>
          </div>
          {/* section nav */}
          <div style={{ padding: '8px 28px 12px', display:'flex', gap: 20, overflowX:'auto' }}>
            {data.sections.map((s, i) => (
              <a key={s.id} href={`#obs-sec-${s.id}`} style={{
                fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.18em', color: t.inkSoft, textDecoration:'none', whiteSpace:'nowrap',
              }}
                onMouseEnter={(e) => e.currentTarget.style.color = accent(t)}
                onMouseLeave={(e) => e.currentTarget.style.color = t.inkSoft}
              >
                <span style={{ color: t.ink }}>{String(i+1).padStart(2,'0')}</span> · {s.title.toUpperCase()}
              </a>
            ))}
          </div>
        </div>

        {/* Hero */}
        <header style={{ position:'relative', padding: '60px 36px 40px', borderBottom: `1px solid ${t.rule}` }}>
          <div style={{ display:'grid', gridTemplateColumns: '1.4fr 1fr', gap: 48, alignItems:'center' }}>
            <div>
              <div style={{ fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.28em', color: t.inkSoft, marginBottom: 22 }}>
                EST. MMXXIV · PUBLIC OBSERVATORY · {data.sections.length} FASCICLES
              </div>
              <h1 style={{ fontFamily: FONTS.serif, fontSize: 88, lineHeight: 0.94, margin: 0, letterSpacing:'-0.025em', color: t.ink, fontWeight: 400 }}>
                <span style={{ fontStyle:'italic' }}>Suede Labs</span>
                <br />
                <span style={{ color: t.inkSoft }}>Operations</span> Observatory
              </h1>
              <div style={{ fontFamily: FONTS.serif, fontSize: 18, fontStyle:'italic', color: t.inkSoft, marginTop: 22, maxWidth: 600, lineHeight: 1.5 }}>
                Every console, registry, vault, agent and editorial surface, plotted as
                stations across a single observatory. Hover any station to read its
                coordinates and follow its signal.
              </div>
              <div style={{ display:'flex', gap: 16, marginTop: 28 }}>
                <a href="#obs-sec-creative" style={{
                  fontFamily: FONTS.mono, fontSize: 11, letterSpacing:'0.18em', color: t.ink, background: accent(t),
                  padding: '12px 18px', textDecoration:'none', borderRadius: 2,
                }}>ENTER OBSERVATORY →</a>
                <a href="#obs-sec-investor" style={{
                  fontFamily: FONTS.mono, fontSize: 11, letterSpacing:'0.18em', color: t.ink, border: `1px solid ${t.rule}`,
                  padding: '12px 18px', textDecoration:'none', borderRadius: 2, background: t.plate,
                }}>READ THE THESIS</a>
              </div>
            </div>
            <div style={{ position:'relative', display:'flex', justifyContent:'center' }}>
              <ConcentricMark size={300} dark={dark} animate />
              <div style={{
                position:'absolute', inset:0, display:'flex', alignItems:'center', justifyContent:'center', pointerEvents:'none',
              }}>
                <div style={{
                  width: 380, height: 380, border: `1px dashed ${t.rule}`, borderRadius: '50%',
                }} />
              </div>
            </div>
          </div>
        </header>

        {/* Sections */}
        <div style={{ position:'relative' }}>
          {data.sections.map((s, i) => (
            <SectionBlock key={s.id} section={s} secIdx={i} query={query} dark={dark} />
          ))}
        </div>

        {/* Footer */}
        <footer style={{
          position:'relative', padding: '32px 36px 40px', borderTop: `1px solid ${t.rule}`, marginTop: 36,
          display:'flex', alignItems:'center', justifyContent:'space-between',
        }}>
          <a href="https://suedeai.ai" target="_blank" rel="noreferrer" style={{ display:'flex', alignItems:'center', gap: 14, textDecoration:'none', color:'inherit' }}>
            <img src="assets/suede-mark.jpeg" alt="Suede Labs" style={{ width: 22, height: 22, borderRadius: 2, objectFit:'cover' }} />
            <span style={{ fontFamily: FONTS.serif, fontStyle:'italic', fontSize: 14, color: t.ink }}>
              Suede Labs — Operations Observatory
            </span>
          </a>
          <div style={{ fontFamily: FONTS.mono, fontSize: 10, letterSpacing:'0.2em', color: t.inkSoft }}>
            {totalCount} STATIONS · 3 CHAINS · OPEN · {new Date().getUTCFullYear()}
          </div>
        </footer>
      </div>
    );
  }

  function accent(t) { return t.blue; }

  return SuedeObservatory;
})();

window.SuedeObservatory = Observatory;
