// Artlito web shell — the Ocula-derived chrome shared across every surface.
//
// Header (slim, hide-on-scroll): LEFT = three-line menu + wordmark · CENTER =
// search bar · RIGHT = messages chat-bubble + notifications bell + profile
// cluster. The primary nav lives in a full-screen overlay opened by the menu
// button. FOOTER = dark grey (#252525) panel, white text, our current columns.
const { Logo, RoleDot } = window.ArtlitoDesignSystem_f3b428;

/* ─────────────────────────── icons ───────────────────────────────────────── */
function SearchIcon({ size = 17 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.6" aria-hidden>
      <circle cx="8" cy="8" r="6" /><line x1="12.5" y1="12.5" x2="17" y2="17" />
    </svg>
  );
}
function BellIcon({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden>
      <path d="M4 7a5 5 0 0 1 10 0c0 4 1.4 5 1.4 5H2.6S4 11 4 7Z" /><path d="M7.2 15a1.8 1.8 0 0 0 3.6 0" />
    </svg>
  );
}
function ChatIcon({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden>
      <path d="M2.5 8.5a5.5 5.5 0 0 1 5.5-5.5h1a5.5 5.5 0 0 1 0 11H5l-2.5 2.2V8.5Z" />
    </svg>
  );
}
function CloseIcon({ size = 22 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 22 22" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden>
      <path d="M5 5l12 12M17 5L5 17" />
    </svg>
  );
}
function ArrowRight({ size = 16 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden>
      <path d="M3 9h12M10 4l5 5-5 5" />
    </svg>
  );
}

// Search-band styles copied from the parked Ocula header (GordonGreyman/Artlito
// design_parked/kaan-2026-06 — ocula.css): icy dark frost over a hero that
// DEEPENS on hover/focus; flat light-grey panel that CLEARS on hover/focus once
// Search-band placeholder colours (the one thing inline styles can't set). The
// band's fill/ink are driven by React state on the SearchField component below;
// only ::placeholder is keyed here, by a state class. Behaviour mirrors the
// parked Ocula header (design_parked/kaan-2026-06): icy dark frost over the
// hero, light-grey panel when solid, and — the new bit — the highlight green on
// hover/focus.
(function () {
  if (document.getElementById('al-search-css')) return;
  const s = document.createElement('style');
  s.id = 'al-search-css';
  s.textContent = `
.al-search input::placeholder { color: hsla(0,0%,100%,0.7); }
.al-search.is-light input::placeholder { color: rgba(0,0,0,0.7); }
.al-search.is-green input::placeholder { color: rgba(0,0,0,0.55); }
.al-search input:focus::placeholder { opacity: 0; }
`;
  document.head.appendChild(s);
})();

const NAV = [
  { key: 'discover', label: 'discover' },
  { key: 'archive', label: 'archive' },
  { key: 'library', label: 'library' },
  { key: 'events', label: 'events' },
  { key: 'spotlights', label: 'in focus' },
];

/* ─────────────────────────── header ──────────────────────────────────────── */
// Centre search band. Fill + ink are React state (so hover/focus is reliable and
// inspectable); only ::placeholder lives in CSS. Three resting fills: icy dark
// frost over the hero, light-grey panel when solid, and the highlight GREEN on
// hover/focus — full header height, touching the bar's top and bottom edges.
function SearchField({ light, onSubmit }) {
  const [hover, setHover] = React.useState(false);
  const [focus, setFocus] = React.useState(false);
  const green = hover || focus;
  const stateClass = green ? 'is-green' : light ? 'is-dark' : 'is-light';
  const fill = green ? 'var(--role-artist)' : light ? 'rgba(0,0,0,0.1)' : 'hsla(0,0%,87%,0.8)';
  const ink = green ? '#0a0a0a' : light ? '#ffffff' : '#000000';
  const blur = green ? 'none' : 'blur(100px)';
  return (
    <form role="search" className={`al-search ${stateClass}`} onSubmit={onSubmit}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ flex: 1, maxWidth: 620, margin: '0 auto', minWidth: 0,
        position: 'relative', display: 'flex', alignItems: 'center', height: '100%',
        background: fill, WebkitBackdropFilter: blur, backdropFilter: blur,
        transition: 'background-color 0.25s var(--ease)' }}>
      <span className="al-search-icon" aria-hidden
        style={{ position: 'absolute', left: 22, display: 'flex', color: ink, pointerEvents: 'none', transition: 'color 0.25s var(--ease)' }}>
        <SearchIcon size={13} />
      </span>
      <input type="search" name="search" autoComplete="off" placeholder="search artlito" aria-label="search artlito"
        onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
        style={{ width: '100%', height: '100%', padding: '0 15px 0 46px', background: 'transparent', border: 'none', outline: 'none',
          fontFamily: 'var(--font-sans)', fontSize: '0.9375rem', color: ink, transition: 'color 0.25s var(--ease)' }} />
    </form>
  );
}

function IconButton({ label, onClick, badge, ink = 'var(--text-primary)', hoverBg = 'var(--plate)', size = 40, children }) {
  const [h, setH] = React.useState(false);
  const off = Math.round(size * 0.22);
  return (
    <button onClick={onClick} aria-label={label} title={label}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ position: 'relative', width: size, height: size, borderRadius: 'var(--radius-sm)', border: 'none',
        background: h ? hoverBg : 'transparent', color: ink, cursor: 'pointer',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', transition: 'background var(--dur) var(--ease), color var(--dur) var(--ease)' }}>
      {children}
      {badge ? <span style={{ position: 'absolute', top: off, right: off, width: 7, height: 7, borderRadius: 999, background: 'var(--signal-new)' }} /> : null}
    </button>
  );
}

// artlito three-line menu icon: three 22px rules. (The production header uses a
// two-line mark; artlito's is three.) Lines tint with the header ink state and
// pick up the hover wash.
function MenuButton({ ink, hoverBg, onClick, expanded }) {
  const [h, setH] = React.useState(false);
  return (
    <button onClick={onClick} aria-label="open menu" aria-expanded={expanded} aria-haspopup="dialog"
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ width: 48, height: 48, borderRadius: 'var(--radius-sm)', border: 'none', background: h ? hoverBg : 'transparent', cursor: 'pointer',
        display: 'inline-flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 5,
        transition: 'background var(--dur) var(--ease)' }}>
      {[0, 1, 2].map((i) => (
        <span key={i} style={{ width: 22, height: 1.5, background: ink, transition: 'background 0.25s var(--ease)' }} />
      ))}
    </button>
  );
}

// ── Logo from the official Lottie, stopped on its settled 2×2 frame ──────────
// Three cached datasets: `natural` (black wordmark + role-colour dots),
// `white` (whole mark whitened — used over the photographic hero), and
// `wordmark` (the WORDMARK ONLY, dots layers stripped + text whitened) which we
// pair with a guaranteed-correct static dot cluster on dark panels (footer,
// menu) so the four brand bubbles always read as black·purple·green·gray and
// never inherit the Lottie's whitened/scrambled dots.
let _lottieNatural = null, _lottieWhite = null, _lottieWordmark = null, _lottiePromise = null;
function loadLottieData() {
  if (_lottiePromise) return _lottiePromise;
  _lottiePromise = fetch('/artlito/assets/artlito-logo-animation.json')
    .then((r) => r.json())
    .then((j) => {
      _lottieNatural = j;
      const whitenWalk = (o) => {
        if (Array.isArray(o)) { o.forEach(whitenWalk); return; }
        if (o && typeof o === 'object') {
          if ((o.ty === 'fl' || o.ty === 'st') && o.c && o.c.a === 0 && Array.isArray(o.c.k)) {
            const k = o.c.k;
            if (k[0] < 0.18 && k[1] < 0.18 && k[2] < 0.18) o.c.k = [1, 1, 1, k[3] == null ? 1 : k[3]];
          }
          Object.keys(o).forEach((key) => whitenWalk(o[key]));
        }
      };
      const clone = JSON.parse(JSON.stringify(j));
      whitenWalk(clone);
      _lottieWhite = clone;

      // wordmark-only: drop every dot layer (keep the typo), whiten the text.
      const wm = JSON.parse(JSON.stringify(j));
      wm.layers = (wm.layers || []).filter((L) => !/rond|Calque/i.test(L.nm || ''));
      whitenWalk(wm);
      _lottieWordmark = wm;
      return true;
    });
  return _lottiePromise;
}

const LOGO_ASPECT = 1050 / 230;

function LottieLogo({ height = 30, variant = 'natural', whiten = false }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    let anim, cancelled = false;
    loadLottieData().then(() => {
      if (cancelled || !ref.current || !window.lottie) return;
      const data = variant === 'white' ? _lottieWhite : variant === 'wordmark' ? _lottieWordmark : _lottieNatural;
      anim = window.lottie.loadAnimation({ container: ref.current, renderer: 'svg', loop: false, autoplay: false, animationData: data });
      anim.addEventListener('DOMLoaded', () => { try { anim.goToAndStop(anim.totalFrames - 1, true); } catch (e) {} });
    }).catch(() => {});
    return () => { cancelled = true; if (anim) anim.destroy(); };
  }, [variant]);
  return <span ref={ref} aria-hidden style={{ display: 'block', width: Math.round(height * LOGO_ASPECT), height, filter: whiten ? 'brightness(0) invert(1)' : 'none', transition: 'filter 0.25s var(--ease)' }} />;
}

// Brand lockup for DARK surfaces (footer, menu): the whitened wordmark with the
// correct 2×2 brand cluster overlaid exactly where the Lottie's own dots sit
// (region measured from the animation's dot geometry, as a % of the 1050×230
// canvas), so the bubbles are always black·purple·green·gray, touching, with a
// faint ring on the black dot so it reads on black. onClick optional.
function BrandLockup({ height = 26, onClick }) {
  // dot region within the canvas: x 0.45%→15.44%, y 29.62%→98.08%.
  const box = { left: '0.45%', top: '29.6%', width: '15.0%', height: '68.5%' };
  const cols = ['#000000', '#9b66ff', '#5ef05c', '#b1b1b1']; // TL black · TR purple · BL green · BR gray
  const cluster = (
    <span style={{ position: 'absolute', ...box, display: 'grid', gridTemplateColumns: '1fr 1fr', gridTemplateRows: '1fr 1fr' }}>
      {cols.map((c, i) => (
        <span key={i} style={{ width: '100%', height: '100%', borderRadius: 999, background: c, boxShadow: c === '#000000' ? 'inset 0 0 0 1px rgba(255,255,255,0.32)' : 'none' }} />
      ))}
    </span>
  );
  const inner = (
    <span style={{ position: 'relative', display: 'inline-block', width: Math.round(height * LOGO_ASPECT), height }}>
      <LottieLogo height={height} variant="wordmark" />
      {cluster}
    </span>
  );
  if (!onClick) return inner;
  return (
    <button onClick={onClick} aria-label="artlito — home"
      style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 0, display: 'inline-flex', alignItems: 'center' }}>
      {inner}
    </button>
  );
}

function HeaderLogo({ height = 28, light = false, onClick }) {
  return (
    <button onClick={onClick} aria-label="artlito — home"
      style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '0 6px', display: 'inline-flex', alignItems: 'center' }}>
      <LottieLogo height={height} variant="natural" whiten={light} />
    </button>
  );
}

// Tight 2×2 brand-dot cluster — Lottie-faithful: in the mark the dots TOUCH
// (centre distance equals the dot diameter), and the settled frame reads
// black TL · purple TR · green BL · gray BR.
function ProfileDots({ size = 30, light = false }) {
  const d = Math.round(size / 2);
  const cols = ['#000000', '#9b66ff', '#5ef05c', '#b1b1b1'];
  return (
    <span style={{ display: 'inline-grid', gridTemplateColumns: `repeat(2, ${d}px)`, filter: light ? 'brightness(0) invert(1)' : 'none', transition: 'filter 0.3s var(--ease)' }}>
      {cols.map((c, i) => (
        <span key={i} style={{ width: d, height: d, borderRadius: 999, background: c }} />
      ))}
    </span>
  );
}

// Signed-in account identity (the kit is signed in as the artist profile).
const ACCOUNT = { name: 'mira okafor', initials: 'mo', headline: 'artist · photography · lagos', handle: '@mira', roleColor: '#5ef05c' };

function AccountAvatar({ size = 48 }) {
  const badge = Math.round(size * 0.3);
  return (
    <span style={{ position: 'relative', width: size, height: size, flex: 'none', display: 'inline-block' }}>
      <span style={{ width: size, height: size, borderRadius: 999, background: 'var(--plate)', border: '1px solid var(--line)',
        display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-sans)', fontSize: Math.round(size * 0.36), color: 'var(--text-primary)', textTransform: 'lowercase' }}>
        {ACCOUNT.initials}
      </span>
      <span style={{ position: 'absolute', right: -1, bottom: -1, width: badge, height: badge, borderRadius: 999, background: ACCOUNT.roleColor, border: '2px solid var(--white)' }} />
    </span>
  );
}

// Account dropdown — opened by the header account mark (instead of jumping
// straight to the profile). A scrollable popover: signed-in identity, profile +
// verification actions, grouped account links, sign out. Popovers/menus are one
// of the few artlito surfaces allowed a soft shadow.
function AccountMenu({ onNav, onClose, minimal = false }) {
  const groups = [
    { h: 'your work', items: [
      { label: 'new entry', k: 'new-entry' },
      { label: 'my archive', k: 'archive' },
      { label: 'library', k: 'library' },
      { label: 'saved', k: 'saved' },
      { label: 'drafts', k: 'drafts' },
    ] },
    { h: 'account', items: [
      { label: 'settings', k: 'settings' },
      { label: 'verification', k: 'verification' },
      { label: 'help & guidelines', k: 'help' },
    ] },
  ];
  const go = (k) => { onClose(); onNav && onNav(k); };
  const item = (label, k) => (
    <button key={k} role="menuitem" onClick={() => go(k)}
      style={{ width: '100%', textAlign: 'left', background: 'none', border: 'none', cursor: 'pointer', padding: '9px 12px', borderRadius: 'var(--radius-sm)',
        fontFamily: 'var(--font-sans)', fontSize: 15, color: 'var(--text-primary)', textTransform: 'lowercase', transition: 'background var(--dur) var(--ease)' }}
      onMouseEnter={(e) => (e.currentTarget.style.background = 'var(--plate)')} onMouseLeave={(e) => (e.currentTarget.style.background = 'none')}>
      {label}
    </button>
  );
  const groupLabel = (t) => (
    <div style={{ padding: '4px 12px 8px', fontFamily: 'var(--font-meta)', fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--brand-body)' }}>{t}</div>
  );
  // minimal (focused-screen) menu — fewer options, like a settings-mode dropdown
  if (minimal) {
    return (
      <div role="menu" style={{ position: 'absolute', top: 'calc(100% + 12px)', right: 0, zIndex: 200, width: 268,
        background: 'var(--white)', border: '1px solid var(--line)', borderRadius: 'var(--radius-md)', boxShadow: '0 12px 32px rgba(0,0,0,0.12)' }}>
        <div style={{ padding: '18px 18px 14px', display: 'flex', gap: 14, alignItems: 'flex-start' }}>
          <AccountAvatar size={44} />
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 17, color: 'var(--text-primary)', textTransform: 'lowercase', lineHeight: 1.15, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{ACCOUNT.name}</div>
            <div style={{ marginTop: 3, fontFamily: 'var(--font-meta)', fontSize: 13, color: 'var(--brand-gray)' }}>{ACCOUNT.handle}</div>
          </div>
        </div>
        <div style={{ padding: '0 18px 16px' }}>
          <button onClick={() => go('profile')}
            style={{ width: '100%', height: 38, borderRadius: 'var(--radius-sm)', border: '1px solid var(--brand-gray)', background: 'transparent', cursor: 'pointer',
              fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--text-primary)', textTransform: 'lowercase' }}>view profile</button>
        </div>
        <div style={{ borderTop: '1px solid var(--line)', padding: '8px' }}>
          {item('back to artlito', 'discover')}
          {item('help & guidelines', 'help')}
        </div>
        <div style={{ borderTop: '1px solid var(--line)', padding: '8px' }}>
          {item('sign out', 'signout')}
        </div>
      </div>
    );
  }
  return (
    <div role="menu" style={{ position: 'absolute', top: 'calc(100% + 12px)', right: 0, zIndex: 200, width: 300,
      background: 'var(--white)', border: '1px solid var(--line)', borderRadius: 'var(--radius-md)', boxShadow: '0 12px 32px rgba(0,0,0,0.12)',
      maxHeight: 'calc(100vh - var(--header-h) - 40px)', overflowY: 'auto' }}>
      <div style={{ padding: '18px 18px 14px', display: 'flex', gap: 14, alignItems: 'flex-start' }}>
        <AccountAvatar size={48} />
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 18, color: 'var(--text-primary)', textTransform: 'lowercase', lineHeight: 1.15 }}>{ACCOUNT.name}</div>
          <div style={{ marginTop: 4, fontSize: 13, color: 'var(--brand-body)', textWrap: 'pretty' }}>{ACCOUNT.headline}</div>
          <div style={{ marginTop: 2, fontFamily: 'var(--font-meta)', fontSize: 13, color: 'var(--brand-gray)' }}>{ACCOUNT.handle}</div>
        </div>
      </div>
      <div style={{ padding: '0 18px 16px', display: 'flex', gap: 10 }}>
        <button onClick={() => go('profile')}
          style={{ flex: 1, height: 38, borderRadius: 'var(--radius-sm)', border: '1px solid var(--brand-gray)', background: 'transparent', cursor: 'pointer',
            fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--text-primary)', textTransform: 'lowercase' }}>view profile</button>
        <button onClick={() => go('verification')}
          style={{ flex: 1, height: 38, borderRadius: 'var(--radius-sm)', border: '1px solid var(--black)', background: 'var(--black)', cursor: 'pointer',
            fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--white)', textTransform: 'lowercase' }}>get verified</button>
      </div>
      {groups.map((g) => (
        <div key={g.h} style={{ borderTop: '1px solid var(--line)', padding: '12px 8px' }}>
          {groupLabel(g.h)}
          {g.items.map((it) => item(it.label, it.k))}
        </div>
      ))}
      <div style={{ borderTop: '1px solid var(--line)', padding: '8px' }}>
        {item('sign out', 'signout')}
      </div>
    </div>
  );
}

// Signed-out header actions — log in (quiet) + sign up (filled). Both adapt to
// the light/dark header state so they read over the hero and on white.
function AuthActions({ light, onNav }) {
  const [hLogin, setHLogin] = React.useState(false);
  const signUpBg = light ? 'var(--white)' : 'var(--black)';
  const signUpInk = light ? '#0a0a0a' : 'var(--white)';
  const loginInk = light ? '#ffffff' : 'var(--text-primary)';
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
      <button onClick={() => onNav('login')}
        onMouseEnter={() => setHLogin(true)} onMouseLeave={() => setHLogin(false)}
        style={{ height: 38, padding: '0 16px', borderRadius: 'var(--radius-sm)', border: 'none', cursor: 'pointer',
          background: hLogin ? (light ? 'rgba(255,255,255,0.14)' : 'var(--plate)') : 'transparent', color: loginInk,
          fontFamily: 'var(--font-sans)', fontSize: 15, textTransform: 'lowercase', whiteSpace: 'nowrap',
          transition: 'background var(--dur) var(--ease)' }}>log in</button>
      <button onClick={() => onNav('signup')}
        style={{ height: 38, padding: '0 18px', borderRadius: 'var(--radius-sm)', border: 'none', cursor: 'pointer',
          background: signUpBg, color: signUpInk,
          fontFamily: 'var(--font-sans)', fontSize: 15, textTransform: 'lowercase', whiteSpace: 'nowrap',
          transition: 'opacity var(--dur) var(--ease)' }}
        onMouseEnter={(e) => (e.currentTarget.style.opacity = '0.85')} onMouseLeave={(e) => (e.currentTarget.style.opacity = '1')}>sign up</button>
    </div>
  );
}

function SiteHeader({ active, onNav, unread = 2, msgUnread = 3, heroDark = false, signedIn = true, minimal = false }) {
  const [menuOpen, setMenuOpen] = React.useState(false);
  const [accountOpen, setAccountOpen] = React.useState(false);
  const accountRef = React.useRef(null);
  const [scrolled, setScrolled] = React.useState(false);
  const [hidden, setHidden] = React.useState(false);
  const lastY = React.useRef(0);
  const menuRef = React.useRef(false);
  const headerRef = React.useRef(null);

  React.useEffect(() => {
    menuRef.current = menuOpen;
    if (menuOpen) setHidden(false);
  }, [menuOpen]);

  // Hide-on-scroll — the standard contract, no polling loop:
  //   • within the first bar-height of the page the bar is always shown;
  //   • scrolling DOWN past it hides the bar (translateY(-100%));
  //   • ANY upward scroll reveals it again;
  //   • the open menu pins it visible.
  // A 2px delta dead-zone absorbs rubber-band / sub-pixel jitter.
  React.useEffect(() => {
    let ticking = false;
    const update = () => {
      ticking = false;
      const y = Math.max(0, window.scrollY || document.documentElement.scrollTop || 0);
      const H = headerRef.current ? headerRef.current.offsetHeight : 76;
      setScrolled(y > H - 2);
      const dy = y - lastY.current;
      if (menuRef.current || y <= H) setHidden(false);
      else if (dy > 2) setHidden(true);
      else if (dy < -2) setHidden(false);
      lastY.current = y;
    };
    const onScroll = () => { if (!ticking) { ticking = true; window.requestAnimationFrame(update); } };
    update();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll, { passive: true });
    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
    };
  }, []);

  React.useEffect(() => {
    if (!menuOpen) return;
    const onKey = (e) => { if (e.key === 'Escape') setMenuOpen(false); };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [menuOpen]);

  const go = (key) => { setMenuOpen(false); setAccountOpen(false); onNav && onNav(key); };

  // close the account dropdown on outside-click / Escape, and whenever the bar
  // hides on scroll or the full menu opens.
  React.useEffect(() => {
    if (!accountOpen) return;
    const onDown = (e) => { if (accountRef.current && !accountRef.current.contains(e.target)) setAccountOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setAccountOpen(false); };
    document.addEventListener('mousedown', onDown);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onDown); document.removeEventListener('keydown', onKey); };
  }, [accountOpen]);
  React.useEffect(() => { if (hidden || menuOpen) setAccountOpen(false); }, [hidden, menuOpen]);

  // Colour is decided by scroll POSITION only (blended exclusively at the very
  // top), so once you scroll the bar is solid and never changes colour while it
  // hides/reveals. Over a dark hero the at-top state goes light.
  const solid = scrolled;
  const light = heroDark && !solid;
  const ink = light ? '#ffffff' : 'var(--text-primary)';
  const hoverBg = light ? 'rgba(255,255,255,0.14)' : 'var(--plate)';

  return (
    <React.Fragment>
      <header ref={headerRef} style={{
        position: 'fixed', top: 0, left: 0, right: 0, zIndex: 112, height: 'var(--header-h)',
        display: 'flex', alignItems: 'center',
        transform: hidden ? 'translateY(-100%)' : 'translateY(0)',
        transition: 'transform 0.32s var(--ease), background 0.3s var(--ease), border-color 0.3s var(--ease)',
        background: solid ? 'var(--white)' : 'transparent',
        WebkitBackdropFilter: 'none', backdropFilter: 'none',
        borderBottom: `1px solid ${solid ? 'var(--line)' : 'transparent'}`,
      }}>
        <div style={{ width: '100%', height: 'var(--header-h)', padding: '0 15px', display: 'flex', alignItems: 'stretch', gap: 14 }}>

          {/* LEFT — Ocula two-line menu + wordmark, flush to the edge */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 4, flex: 'none', marginLeft: -10 }}>
            {!minimal && <MenuButton ink={ink} hoverBg={hoverBg} expanded={menuOpen} onClick={() => setMenuOpen(true)} />}
            <HeaderLogo height={28} light={light} onClick={() => go('landing')} />
          </div>

          {/* CENTER — search band (SearchField): full header height, touching the
              bar's top and bottom; icy frost over the hero / light-grey when
              solid, and the highlight green on hover/focus. Enter opens search. */}
          {minimal ? <div style={{ flex: 1 }} /> : <SearchField light={light} onSubmit={(e) => { e.preventDefault(); go('search'); }} />}

          {/* RIGHT — signed-in: messages + bell + profile. signed-out: log in +
              sign up. Both flush to the edge. */}
          {signedIn ? (
          <div style={{ display: 'flex', alignItems: 'center', gap: 2, flex: 'none', marginRight: -8 }}>
            {!minimal && <IconButton size={44} label="messages" onClick={() => go('messages')} badge={msgUnread > 0} ink={ink} hoverBg={hoverBg}><ChatIcon size={23} /></IconButton>}
            {!minimal && <IconButton size={44} label="notifications" onClick={() => go('notifications')} badge={unread > 0} ink={ink} hoverBg={hoverBg}><BellIcon size={23} /></IconButton>}
            <div ref={accountRef} style={{ position: 'relative', display: 'flex' }}>
              <button onClick={() => setAccountOpen((v) => !v)} aria-label="your account" aria-haspopup="menu" aria-expanded={accountOpen}
                style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '0 4px 0 10px', display: 'flex' }}>
                <ProfileDots size={30} light={light} />
              </button>
              {accountOpen && <AccountMenu onNav={go} onClose={() => setAccountOpen(false)} minimal={minimal} />}
            </div>
          </div>
          ) : (
          <div style={{ display: 'flex', alignItems: 'center', flex: 'none', marginRight: 2 }}>
            <AuthActions light={light} onNav={go} />
          </div>
          )}
        </div>
      </header>

      {/* Non-hero pages need a spacer so the fixed bar doesn't overlap content.
          Hero pages (heroDark) let the hero sit UNDER the blended bar. */}
      {!heroDark && <div aria-hidden style={{ height: 'var(--header-h)' }} data-header-spacer></div>}

      {/* MENU OVERLAY */}
      <MenuOverlay open={menuOpen} active={active} onClose={() => setMenuOpen(false)} onNav={go} signedIn={signedIn} />
    </React.Fragment>
  );
}

function MenuOverlay({ open, active, onClose, onNav, signedIn = true }) {
  const main = NAV.concat(signedIn ? [{ key: 'profile', label: 'me' }] : []);
  const account = [
    { key: 'archive', label: 'my archive' },
    { key: 'library', label: 'library' },
    { key: 'settings', label: 'settings' },
    { key: 'help', label: 'help & guidelines' },
  ];
  return (
    <div role="dialog" aria-label="menu" aria-hidden={!open}
      style={{ position: 'fixed', inset: 0, zIndex: 200,
        opacity: open ? 1 : 0, visibility: open ? 'visible' : 'hidden',
        transition: 'opacity 0.3s var(--ease), visibility 0.3s var(--ease)' }}>
      {/* dim empty space — click anywhere here to close */}
      <button aria-label="close menu" onClick={onClose} tabIndex={-1}
        style={{ position: 'absolute', inset: 0, border: 'none', cursor: 'pointer', background: 'rgba(0,0,0,0.4)' }} />
      {/* panel — left side, leaving empty space to the right */}
      <div style={{ position: 'absolute', top: 0, left: 0, bottom: 0, width: 'min(620px, 70%)',
        background: 'var(--black)', color: 'var(--white)',
        transform: open ? 'translateX(0)' : 'translateX(-24px)', transition: 'transform 0.32s var(--ease)',
        display: 'flex', flexDirection: 'column', boxShadow: '0 0 60px rgba(0,0,0,0.4)' }}>
        {/* top bar inside overlay */}
        <div style={{ height: 'var(--header-h)', flex: 'none', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px' }}>
          <button onClick={() => onNav('landing')} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '0 6px', display: 'flex', alignItems: 'center' }} aria-label="artlito — home">
            <BrandLockup height={24} />
          </button>
          <button onClick={onClose} aria-label="close menu"
            style={{ width: 44, height: 44, borderRadius: 'var(--radius-sm)', border: 'none', background: 'transparent', color: 'var(--white)', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
            <CloseIcon />
          </button>
        </div>

        {/* body — single column, vertically centred */}
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '0 44px 40px' }}>
          <nav aria-label="primary" style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
            {main.map((n) => {
              const on = active === n.key;
              return (
                <button key={n.key} onClick={() => onNav(n.key)}
                  style={{ background: 'none', border: 'none', cursor: 'pointer', textAlign: 'left', padding: '5px 0',
                    display: 'inline-flex', alignItems: 'center', gap: 16,
                    fontFamily: 'var(--font-sans)', fontSize: 'clamp(30px, 3.4vw, 46px)', lineHeight: 1.12, letterSpacing: '-0.02em',
                    textTransform: 'lowercase', color: on ? 'var(--white)' : 'rgba(255,255,255,0.62)',
                    transition: 'color var(--dur) var(--ease)' }}
                  onMouseEnter={(e) => e.currentTarget.style.color = 'var(--white)'}
                  onMouseLeave={(e) => e.currentTarget.style.color = on ? 'var(--white)' : 'rgba(255,255,255,0.62)'}>
                  {on && <span style={{ width: 9, height: 9, borderRadius: 999, background: 'var(--signal-new)', flex: 'none' }} />}
                  {n.label}
                </button>
              );
            })}
          </nav>

          <div style={{ display: 'flex', flexDirection: 'column', gap: 2, marginTop: 40, paddingTop: 28, borderTop: '1px solid rgba(255,255,255,0.14)' }}>
            {signedIn ? (
            <React.Fragment>
            <span style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.45)', marginBottom: 12 }}>account</span>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px 28px' }}>
              {account.map((a) => (
                <button key={a.label} onClick={() => onNav(a.key)}
                  style={{ background: 'none', border: 'none', cursor: 'pointer', textAlign: 'left', padding: '6px 0', whiteSpace: 'nowrap',
                    fontFamily: 'var(--font-sans)', fontSize: 16, textTransform: 'lowercase', color: 'rgba(255,255,255,0.8)' }}
                  onMouseEnter={(e) => e.currentTarget.style.color = 'var(--white)'}
                  onMouseLeave={(e) => e.currentTarget.style.color = 'rgba(255,255,255,0.8)'}>
                  {a.label}
                </button>
              ))}
            </div>
            </React.Fragment>
            ) : (
            <React.Fragment>
            <span style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.45)', marginBottom: 14 }}>join artlito</span>
            <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
              <button onClick={() => onNav('signup')}
                style={{ height: 46, padding: '0 26px', borderRadius: 'var(--radius-sm)', border: 'none', cursor: 'pointer',
                  background: 'var(--white)', color: '#0a0a0a', fontFamily: 'var(--font-sans)', fontSize: 16, textTransform: 'lowercase' }}>sign up</button>
              <button onClick={() => onNav('login')}
                style={{ height: 46, padding: '0 26px', borderRadius: 'var(--radius-sm)', border: '1px solid rgba(255,255,255,0.5)', cursor: 'pointer',
                  background: 'transparent', color: 'var(--white)', fontFamily: 'var(--font-sans)', fontSize: 16, textTransform: 'lowercase' }}>log in</button>
            </div>
            </React.Fragment>
            )}
            {/* brand cluster — Lottie layout: 2×2, dots touching, black TL ·
                purple TR · green BL · gray BR (faint ring keeps black on black) */}
            <div style={{ display: 'inline-grid', gridTemplateColumns: 'repeat(2, 13px)', marginTop: 26, justifySelf: 'start', width: 'max-content' }}>
              {['#000000', '#9b66ff', '#5ef05c', '#b1b1b1'].map((c, i) => (
                <span key={i} style={{ width: 13, height: 13, borderRadius: 999, background: c, boxShadow: c === '#000000' ? 'inset 0 0 0 1px rgba(255,255,255,0.3)' : 'none' }} />
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─────────────────────────── footer (dark grey #252525) ──────────────────── */
function SiteFooter({ onNav }) {
  // keys route into the app; entries without a key are intentionally inert
  // (in focus, spotlights — editorial surfaces not in the kit).
  const go = (k) => (e) => { e.preventDefault(); if (!k) return; if (onNav) onNav(k); else window.location.href = '/discover#' + k; };
  const cols = [
    { h: 'browse', links: [{ l: 'discover', k: 'discover' }, { l: 'search', k: 'search' }, { l: 'events', k: 'events' }, { l: 'in focus' }] },
    { h: 'your work', links: [{ l: 'my archive', k: 'archive' }, { l: 'library', k: 'library' }, { l: 'collections', k: 'library' }, { l: 'spotlights' }] },
    { h: 'artlito', links: [{ l: 'about', k: 'about' }, { l: 'guidelines', k: 'guidelines' }, { l: 'help', k: 'help' }, { l: 'contact', k: 'contact' }] },
  ];
  return (
    <footer style={{ background: 'var(--footer-grey)', color: 'var(--white)', marginTop: 'var(--section-gap)' }}>
      <div style={{ maxWidth: 'var(--page-max)', margin: '0 auto', padding: '64px var(--gutter-desktop) 44px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', gap: 48, flexWrap: 'wrap' }}>
          <div style={{ maxWidth: 280 }}>
            <BrandLockup height={24} />
            <p style={{ marginTop: 16, fontSize: 15, lineHeight: 1.5, color: 'rgba(255,255,255,0.62)' }}>
              a quiet space to archive your work, connect with the ecosystem, and let your practice grow.
            </p>
          </div>
          <div style={{ display: 'flex', gap: 64, flexWrap: 'wrap' }}>
            {cols.map((c) => (
              <div key={c.h} style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                <span style={{ fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.45)' }}>{c.h}</span>
                {c.links.map((l) => (
                  <a key={l.l} href="#" onClick={go(l.k)} style={{ fontSize: 15, color: 'rgba(255,255,255,0.85)', textTransform: 'lowercase' }}
                    onMouseEnter={(e) => e.currentTarget.style.color = '#fff'}
                    onMouseLeave={(e) => e.currentTarget.style.color = 'rgba(255,255,255,0.85)'}>{l.l}</a>
                ))}
              </div>
            ))}
          </div>
        </div>
        <div style={{ marginTop: 48, paddingTop: 24, borderTop: '1px solid rgba(255,255,255,0.18)', display: 'flex', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 12, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.55)' }}>© 2026 artlito</span>
          <span style={{ display: 'flex', gap: 24 }}>
            {[{ l: 'terms', k: 'terms' }, { l: 'privacy', k: 'privacy-policy' }, { l: 'accessibility', k: 'accessibility' }].map((x) => (
              <a key={x.l} href="#" onClick={go(x.k)} style={{ fontSize: 12, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.55)' }}>{x.l}</a>
            ))}
          </span>
        </div>
      </div>
    </footer>
  );
}

Object.assign(window, { SiteHeader, SiteFooter, SearchIcon, BellIcon, ChatIcon });
