/* ============================================================
   Chrome for the dev build — nav, footer, theme, routing.
   Self-contained on purpose: production src/chrome.jsx is not
   loaded here, so the two page sets can diverge without either
   breaking the other. Design tokens are the shared part.
   ============================================================ */
const { useState: cState, useEffect: cEffect } = React;

function useTheme2() {
  const read = () => (document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light');
  const [theme, setTheme] = cState(read);
  cEffect(() => {
    const onChange = () => setTheme(read());
    window.addEventListener('gd-theme-change', onChange);
    return () => window.removeEventListener('gd-theme-change', onChange);
  }, []);
  const toggle = () => {
    const next = theme === 'dark' ? 'light' : 'dark';
    if (next === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
    else document.documentElement.removeAttribute('data-theme');
    try { localStorage.setItem('gd-theme-v2', next); } catch (e) {}
    window.dispatchEvent(new Event('gd-theme-change'));
  };
  return [theme, toggle];
}

function ThemeToggle2() {
  const [theme, toggle] = useTheme2();
  const dark = theme === 'dark';
  return (
    <button type="button" onClick={toggle} className="theme-toggle"
      aria-label={dark ? 'Switch to light mode' : 'Switch to dark mode'} aria-pressed={dark}>
      {dark ? (
        <svg viewBox="0 0 24 24" width="16" height="16" fill="none" aria-hidden="true">
          <circle cx="12" cy="12" r="4" stroke="currentColor" strokeWidth="1.6"/>
          <path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4L7 17M17 7l1.4-1.4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
        </svg>
      ) : (
        <svg viewBox="0 0 24 24" width="16" height="16" fill="none" aria-hidden="true">
          <path d="M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round"/>
        </svg>
      )}
    </button>
  );
}

function useRoute2() {
  const [route, setRoute] = cState(() => window.location.hash.replace(/^#/, '') || '/');
  cEffect(() => {
    const onHash = () => setRoute(window.location.hash.replace(/^#/, '') || '/');
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  return route;
}

/* The same files serve the dev build (dev.html) and, once released, the
   site itself (index.html). Everything that marks a screenshot as "not
   the live site" keys off the file name, so a release changes no code. */
const IS_DEV_BUILD = /dev\.html$/i.test(window.location.pathname);

/* Ribbon so a dev screenshot can never be mistaken for the live site. */
function DevRibbon() {
  return (
    <div className="w-full" style={{ background: 'rgb(var(--c-ink))', color: 'rgb(var(--c-paper))' }}>
      <div className="mx-auto max-w-[1440px] px-8 lg:px-16 py-1.5 flex items-center justify-between gap-4">
        <span className="mono text-[9.5px]">DEV BUILD · NOT PUBLISHED · NOINDEX</span>
        <span className="mono text-[9.5px] opacity-60 hidden sm:inline">PRODUCT COMMUNICATION REBUILD · 03 SEP 2026</span>
      </div>
    </div>
  );
}

/* One page, four anchors. Hash routing owns "#/…", so in-page jumps run
   through a scroll handler instead of an href — otherwise the router
   would read "#approach" as a route and answer with a 404. */
const SECTIONS = [
  { id: 'home',      label: 'Home' },
  { id: 'what',      label: 'What we do' },
  { id: 'how',       label: 'How it works' },
  { id: 'cases',     label: 'Case Studies' },
  { id: 'team',      label: 'Team' },
]

function scrollToId(id) {
  const el = document.getElementById(id);
  if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

/* Section links live on the landing page. From a deep page (a case study,
   /verify, /limits) the section does not exist yet, so the click has to
   route home first and scroll once the landing page has rendered —
   otherwise the nav looks dead and the reader is stuck. */
function goToSection(id) {
  const onLanding = (window.location.hash.replace(/^#/, '') || '/') === '/';
  if (onLanding) {
    scrollToId(id);
    return;
  }
  window.location.hash = '/';
  window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
    if (id === 'home') window.scrollTo({ top: 0 });
    else scrollToId(id);
  }));
}

/* Scroll-spy: the nav marks the section the reader is actually in. */
function useActiveSection() {
  const route = useRoute2();
  const [active, setActive] = cState('home');
  /* A deep page belongs to the menu entry that leads there — otherwise
     the bar claims you are on "Home" while you are reading a case. */
  const deep = route !== '/';
  cEffect(() => {
    if (deep || !('IntersectionObserver' in window)) return;
    const obs = new IntersectionObserver(
      entries => {
        const visible = entries.filter(e => e.isIntersecting)
          .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
        if (visible) setActive(visible.target.id);
      },
      { rootMargin: '-45% 0px -45% 0px', threshold: [0, 0.25, 0.5, 1] }
    );
    SECTIONS.forEach(s => {
      const el = document.getElementById(s.id);
      if (el) obs.observe(el);
    });
    return () => obs.disconnect();
  }, [deep]);
  return deep ? (route.startsWith('/case') ? 'cases' : '') : active;
}

function Nav2() {
  const active = useActiveSection();
  const { CONTACT } = window.GD;
  return (
    <header className="sticky top-0 z-30 bg-paper/85 backdrop-blur-xl hair-b">
      <div className="mx-auto max-w-[1440px] px-8 lg:px-16 h-16 flex items-center justify-between gap-4">
        <button type="button" onClick={() => goToSection('home')} className="flex items-center shrink-0">
          <Logo size={28}/>
        </button>

        <nav className="hidden md:flex items-center gap-1">
          {SECTIONS.map(s => (
            <button key={s.id} type="button" onClick={() => goToSection(s.id)}
              className={`px-3.5 py-1.5 text-[13.5px] rounded-full transition-colors ${
                active === s.id ? 'text-ink bg-off' : 'text-mute hover:text-ink'}`}>
              {s.label}
            </button>
          ))}
        </nav>

        <div className="flex items-center gap-2 shrink-0">
          <ThemeToggle2/>
          <a href={CONTACT}
            className="rounded-full bg-ink text-paper hover:bg-ink/90 px-4 py-1.5 text-[13px] font-medium transition-colors">
            Get in touch
          </a>
        </div>
      </div>

      <div className="md:hidden border-t border-line overflow-x-auto no-scrollbar">
        <div className="flex items-center gap-1 px-6 py-2">
          {SECTIONS.map(s => (
            <button key={s.id} type="button" onClick={() => goToSection(s.id)}
              className={`whitespace-nowrap px-3 py-1.5 text-[12.5px] rounded-full ${
                active === s.id ? 'text-ink bg-off' : 'text-mute'}`}>
              {s.label}
            </button>
          ))}
        </div>
      </div>
    </header>
  );
}

/* ---------------------------------------------------------------
   Source — the 0/1 rule made visible. Any number on a page can be
   unfolded down to the artifact it came from. Collapsed by default
   so the page stays readable; present on every claim so nobody has
   to take one on trust.                                            */
/* Internal references — file paths, run outputs, chapter numbers of our
   own documents — never reach a page (Mo, 17.09.). Public sources may.
   This is the last line of defence; the register itself is not served. */
const INTERNAL_REF = /\.(md|json|parquet|py|csv|jsx|txt)\b|(^|[\s(—·,])(out|docs|mece|src|devsrc|configs|preprocessing|premium_oem|_massnahmen|_experiments)\/|Heftchen|Kap\.\s*\d|[A-Za-z]:\\/;
function Source({ children }) {
  const [open, setOpen] = cState(false);
  const text = React.Children.toArray(children).map(c => (typeof c === 'string' ? c : '')).join(' ');
  if (!text.trim() || INTERNAL_REF.test(text)) return null;
  return (
    <span className="inline-block">
      <button type="button" onClick={() => setOpen(o => !o)}
        className="mono text-[9px] text-mute hover:text-ink border border-line hover:border-ink/40 rounded-full px-2 py-0.5 transition-colors"
        aria-expanded={open}>
        {open ? 'HIDE SOURCE' : 'SOURCE'}
      </button>
      {open && (
        <span className="block mt-2 text-[11.5px] text-mute leading-relaxed font-mono break-words"
          style={{ fontFamily: "'JetBrains Mono', ui-monospace, Menlo" }}>
          {children}
        </span>
      )}
    </span>
  );
}

/* Status chip — the only place colour carries meaning, and it never
   travels alone: every chip is followed by words. */
function Chip({ tone = 'grey', children }) {
  const tones = {
    green: { bg: 'rgba(34,197,94,0.12)',  fg: '#16A34A', bd: 'rgba(34,197,94,0.35)' },
    amber: { bg: 'rgba(245,158,11,0.14)', fg: '#B45309', bd: 'rgba(245,158,11,0.38)' },
    grey:  { bg: 'rgb(var(--c-off))',     fg: 'rgb(var(--c-mute))', bd: 'rgb(var(--c-line))' },
    cyan:  { bg: 'rgba(34,211,238,0.12)', fg: '#0891B2', bd: 'rgba(34,211,238,0.4)' },
  };
  const t = tones[tone] || tones.grey;
  return (
    <span className="mono text-[9.5px] rounded-full px-2.5 py-1 border inline-flex items-center gap-1.5"
      style={{ background: t.bg, color: t.fg, borderColor: t.bd }}>
      <span className="h-1.5 w-1.5 rounded-full" style={{ background: 'currentColor' }}/>
      {children}
    </span>
  );
}

function Eyebrow({ children }) {
  return <div className="mono text-[10px] text-mute">{children}</div>;
}

function Section({ id, tone = 'paper', children, className = '' }) {
  return (
    <section id={id} className={`border-t border-line ${tone === 'off' ? 'bg-off' : ''} ${className}`}>
      <div className="mx-auto max-w-[1440px] px-8 lg:px-16 py-24 sm:py-28">{children}</div>
    </section>
  );
}


/* ---------------------------------------------------------------
   Figure — a diagram is not body text, so it does not look like
   body text (Mo, 15.09.): its own surface, a hairline frame, a faint
   grid, and a mono caption that says what it is. Sections that carry
   a figure run on the off tone, so the paper panel always lifts off
   the page.                                                        */
function Figure({ label, note, children }) {
  return (
    <figure className="relative rounded-[26px] overflow-hidden"
      style={{ background: 'rgb(var(--c-paper))', boxShadow: 'inset 0 0 0 1px rgb(var(--c-line))' }}>
      <div aria-hidden className="absolute inset-0 dot-grid" style={{ opacity: 0.5 }}/>
      <figcaption className="relative flex items-center justify-between gap-4 px-6 sm:px-8 pt-5">
        <span className="mono text-[9.5px] text-mute">{label}</span>
        {note && <span className="mono text-[9.5px] text-mute text-right">{note}</span>}
      </figcaption>
      <div className="relative px-5 sm:px-10 pb-10 pt-8">{children}</div>
    </figure>
  );
}

function Footer2() {
  return (
    <footer className="border-t border-line">
      <div className="mx-auto max-w-[1440px] px-8 lg:px-16 py-12 grid grid-cols-1 md:grid-cols-12 gap-10">
        <div className="md:col-span-5">
          <Logo size={26}/>
          <p className="mt-4 text-[13px] text-mute max-w-sm leading-relaxed">
            Cause by cause, we bring what millions of customer voices already show — each with
            its own grade. Which measures work against it, we find out together with you.
          </p>
        </div>
        <div className="md:col-span-7 grid grid-cols-2 gap-8">
          <div>
            <Eyebrow>ON THIS PAGE</Eyebrow>
            <ul className="mt-3 space-y-2 text-[13px]">
              {SECTIONS.map(sec => (
                <li key={sec.id}>
                  <button type="button" onClick={() => goToSection(sec.id)}
                    className="text-ink hover:text-mute">{sec.label}</button>
                </li>
              ))}
            </ul>
          </div>
          <div>
            <Eyebrow>COMPANY</Eyebrow>
            <ul className="mt-3 space-y-2 text-[13px]">
              <li><a href="#/contact" className="text-ink hover:text-mute">Contact</a></li>
              <li><a href="#/impressum" className="text-ink hover:text-mute">Imprint</a></li>
              <li><a href="#/datenschutz" className="text-ink hover:text-mute">Privacy</a></li>
            </ul>
          </div>
        </div>
      </div>
      <div className="mx-auto max-w-[1440px] px-8 lg:px-16 py-5 border-t border-line flex flex-col sm:flex-row items-center justify-between gap-3">
        <span className="mono text-[10px] text-mute">© 2026 GENDATA UG (HAFTUNGSBESCHRÄNKT)</span>
        <span className="mono text-[10px] text-mute">
          {IS_DEV_BUILD ? 'DEV BUILD · NOT FOR DISTRIBUTION' : 'CAUSAL AI FOR BUSINESS STEERING'}
        </span>
      </div>
    </footer>
  );
}

/* Page. `fill` is for the pages that must not scroll at all (Mo, 16.09.:
   the case study has to sit on one laptop screen): the shell takes exactly
   the viewport height, main becomes the only flexible row, and the footer
   stays off — a footer below the fold would reintroduce the scrollbar. */
function Page({ children, fill = false }) {
  return (
    <div className={(fill ? 'xl:h-[100dvh] xl:overflow-hidden ' : '') + 'min-h-screen flex flex-col bg-paper'}>
      {IS_DEV_BUILD && <DevRibbon/>}
      <Nav2/>
      <main className="flex-1 min-h-0">{children}</main>
      {!fill && <Footer2/>}
    </div>
  );
}

/* The Impressum and the Datenschutzerklärung are the production files
   under src/ — one legal text, kept in one place. Those pages ask for the
   production chrome by name; here the names resolve to ours. */
function PublicNav() {
  return <>{IS_DEV_BUILD && <DevRibbon/>}<Nav2/></>;
}
function Footer() { return <Footer2/>; }

window.useRoute2 = useRoute2;
window.Page = Page;
window.Section = Section;
window.Eyebrow = Eyebrow;
window.Chip = Chip;
window.Source = Source;
window.Figure = Figure;
