// JaneYouBradley.com — multi-page version with hash routing.
// Pages: /#/ (home: now building) · /#/agents · /#/blog · /#/quotes
// Stays a single-file React app but feels like a real multi-page site.

const { useState, useEffect, useRef } = React;

// ─── Tweaks defaults ────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "system",
  "accent": "mint",
  "typePair": "geist",
  "density": "comfortable",
  "cardStyle": "logomark",
  "avatar": "wordmark"
}/*EDITMODE-END*/;

const ACCENT_PALETTES = {
  mint:    { light: "#a3e4d7", dark: "#6dd9c3", soft_l: "#e8f8f5", soft_d: "#1a3a3a" },
  amber:   { light: "#e6c79c", dark: "#d4b07e", soft_l: "#faf3e8", soft_d: "#3a2f1a" },
  coral:   { light: "#f0b8a8", dark: "#e09b87", soft_l: "#fbece6", soft_d: "#3a241d" },
  lavender:{ light: "#c8b8e6", dark: "#a896d0", soft_l: "#f1ecf8", soft_d: "#2a233a" },
  slate:   { light: "#b8c5d1", dark: "#8fa0af", soft_l: "#eef2f6", soft_d: "#1f2730" },
};

const TYPE_PAIRS = {
  "geist":           { display: "'Geist', system-ui, sans-serif", body: "'Geist', system-ui, sans-serif", weightDisplay: 400, weightBody: 300 },
  "fraunces-inter":  { display: "'Fraunces', Georgia, serif", body: "'Inter Tight', system-ui, sans-serif", weightDisplay: 300, weightBody: 300 },
  "instrument-inter":{ display: "'Instrument Serif', Georgia, serif", body: "'Inter Tight', system-ui, sans-serif", weightDisplay: 400, weightBody: 300 },
  "roboto-roboto":   { display: "'Roboto', system-ui, sans-serif", body: "'Roboto', system-ui, sans-serif", weightDisplay: 300, weightBody: 300 },
};

function applyTheme(t) {
  const root = document.documentElement;
  const sysDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
  const dark = t.theme === "dark" || (t.theme === "system" && sysDark);
  root.classList.toggle("dark", dark);

  const pal = ACCENT_PALETTES[t.accent] || ACCENT_PALETTES.mint;
  root.style.setProperty("--accent-mint", dark ? pal.dark : pal.light);
  root.style.setProperty("--accent-mint-soft", dark ? pal.soft_d : pal.soft_l);

  const tp = TYPE_PAIRS[t.typePair] || TYPE_PAIRS["geist"];
  root.style.setProperty("--font-display", tp.display);
  root.style.setProperty("--font-body", tp.body);
  root.style.setProperty("--w-display", tp.weightDisplay);
  root.style.setProperty("--w-body", tp.weightBody);

  root.style.setProperty("--density-gap", t.density === "compact" ? "44px" : t.density === "spacious" ? "84px" : "64px");
  root.style.setProperty("--density-pad", t.density === "compact" ? "22px" : t.density === "spacious" ? "36px" : "30px");
}

// ─── Hash routing ───────────────────────────────────────────────────
const ROUTES = [
  { path: "/", title: "Projects" },
  { path: "/agents", title: "Agents" },
  { path: "/blog", title: "Blog" },
  { path: "/quotes", title: "Quotes" },
];

function useHashRoute() {
  const get = () => {
    const h = window.location.hash.replace(/^#/, "") || "/";
    return h.startsWith("/") ? h : "/" + h;
  };
  const [route, setRoute] = useState(get());
  useEffect(() => {
    const onHash = () => { setRoute(get()); window.scrollTo({ top: 0, behavior: "instant" }); };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);
  return route;
}

// ─── Components ────────────────────────────────────────────────────
function StatusDot({ status, muted }) {
  if (!status) return null;
  return <span className={"status-dot" + (muted ? " muted" : "")}><span className="dot" aria-hidden />{status}</span>;
}

function ProjectCard({ project, cardStyle, onBellClick, isSubscribed }) {
  const Logo = window.ProjectLogos[project.key];
  const href = project.url;
  const Wrapper = href ? "a" : "div";
  const wrapperProps = href ? { href, target: "_blank", rel: "noopener noreferrer" } : {};
  const shapeClass = project.shape ? ` card-shape-${project.shape}` : "";
  const showBell = project.status === "Building";
  return (
    <Wrapper {...wrapperProps} className={"card" + shapeClass}>
      <div className="card-mark">
        {cardStyle === "logomark" && Logo
          ? <Logo size={72} />
          : <span className="card-monogram">{project.title.charAt(0)}</span>}
      </div>
      <div className="card-body">
        {project.status && (
          <div className="card-status"><StatusDot status={project.status} muted={!href} /></div>
        )}
        <h3 className="card-title">{project.title}</h3>
        {project.subtitle && <p className="card-subtitle">{project.subtitle}</p>}
        <p className="card-desc">{project.description}</p>
        {project.tags && project.tags.length > 0 && (
          <p className="card-tags">{project.tags.join(" · ")}</p>
        )}
        {project.urlLabel && <p className="card-link">{project.urlLabel} →</p>}
        {showBell && (
          <button
            type="button"
            className={"card-bell" + (isSubscribed ? " subscribed" : "")}
            aria-label={isSubscribed ? "You're in the loop on " + project.title : "Keep me in the loop on " + project.title}
            onClick={(e) => { e.preventDefault(); e.stopPropagation(); onBellClick(project); }}
          >
            <BellIcon filled={isSubscribed} />
            <span className="card-bell-label">
              {isSubscribed ? "You're in the loop" : "Keep me in the loop"}
            </span>
          </button>
        )}
      </div>
    </Wrapper>
  );
}

function BellIcon({ filled }) {
  if (filled) {
    // Bell + checkmark: confirmed-subscribed state.
    return (
      <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
        <path d="M3.5 11 L11 11 Q10 10 10 8.5 L10 7 A3 3 0 0 0 4 7 L4 8.5 Q4 10 3.5 11 Z" fill="currentColor" />
        <path d="M5.8 12.4 Q7 13.4 8.2 12.4" />
        <circle cx="12" cy="12" r="3.2" fill="currentColor" stroke="none" />
        <path d="M10.6 12 L11.6 13 L13.4 11.1" stroke="var(--bg)" strokeWidth="1.4" />
      </svg>
    );
  }
  return (
    <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
      <path d="M3.5 12 L12.5 12 Q11.5 11 11.5 9.5 L11.5 7 A3.5 3.5 0 0 0 4.5 7 L4.5 9.5 Q4.5 11 3.5 12 Z" />
      <path d="M6.5 13.5 Q8 14.6 9.5 13.5" />
    </svg>
  );
}

// Notify modal — captures email once, then auto-subscribes future bells.
function NotifyModal({ project, existingEmail, onClose, onSubscribe }) {
  const [email, setEmail] = useState(existingEmail || "");
  const [done, setDone] = useState(false);
  const submit = (e) => {
    e.preventDefault();
    if (!/^\S+@\S+\.\S+$/.test(email)) return;
    onSubscribe(email, project.key);
    setDone(true);
    setTimeout(onClose, 1100);
  };
  // If user already has email saved AND they re-open a project they're already
  // subscribed to, show a "you're already in the loop" confirmation. Otherwise
  // show the form so they can confirm/cancel.
  if (!project) return null;
  return (
    <div className="notify-overlay" onClick={onClose}>
      <div className="notify-modal" onClick={(e) => e.stopPropagation()} role="dialog" aria-label={"Keep me in the loop on " + project.title}>
        <button className="notify-close" onClick={onClose} aria-label="Close">×</button>
        <p className="notify-eyebrow">In the loop</p>
        <h3 className="notify-h">Get a heads-up when {project.title} ships.</h3>
        <p className="notify-sub">One email when it's ready. No newsletter, no other use.</p>
        {!done ? (
          <form className="notify-form" onSubmit={submit}>
            <input
              type="email"
              required
              autoFocus
              placeholder="you@goodemail.com"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              aria-label="Email address"
            />
            <button type="submit">Keep me in the loop</button>
          </form>
        ) : (
          <div className="notify-thanks">
            <span className="thanks-dot" />
            You're on the list for {project.title}.
          </div>
        )}
        {existingEmail && !done && (
          <p className="notify-hint">Using {existingEmail} from your earlier signup.</p>
        )}
      </div>
    </div>
  );
}

function QuoteCard({ q }) {
  return (
    <figure className="quote">
      <blockquote><p>{q.quote}</p></blockquote>
      <figcaption>
        <span className="q-author">{q.author}</span>
        {q.book && <span className="q-book"> · <em>{q.book}</em></span>}
      </figcaption>
    </figure>
  );
}

function PostRow({ p }) {
  const date = new Date(p.date).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" });
  const href = p.slug ? "#/blog/" + p.slug : "#/blog";
  return (
    <a className="post" href={href}>
      <div className="post-meta"><span>{date}</span><span className="dotbreak">·</span><span>{p.readTime}</span></div>
      <h3 className="post-title">{p.title}</h3>
      <p className="post-excerpt">{p.excerpt}</p>
    </a>
  );
}

function SectionLabel({ children, intro }) {
  return (
    <div className="section-label-wrap">
      <span className="section-label">{children}</span>
      {intro && <p className="section-intro">{intro}</p>}
    </div>
  );
}

// ─── Newsletter waitlist ────────────────────────────────────────────
function Waitlist() {
  const [email, setEmail] = useState("");
  const [state, setState] = useState("idle"); // idle | submitted

  useEffect(() => {
    if (state !== "idle") return;
    try {
      const stored = localStorage.getItem("jyb_waitlist_email");
      if (stored) setState("submitted");
    } catch (e) {}
  }, [state]);

  const submit = (e) => {
    e.preventDefault();
    if (!email || !/^\S+@\S+\.\S+$/.test(email)) return;
    try {
      const list = JSON.parse(localStorage.getItem("jyb_waitlist") || "[]");
      list.push({ email, at: new Date().toISOString() });
      localStorage.setItem("jyb_waitlist", JSON.stringify(list));
      localStorage.setItem("jyb_waitlist_email", email);
    } catch (e) {}
    setState("submitted");
  };

  return (
    <section className="waitlist">
      <div className="waitlist-inner">
        <p className="waitlist-eyebrow">Keep up with me</p>
        <h2 className="waitlist-h">A weekly note on what I'm learning by doing.</h2>
        <p className="waitlist-sub">One short email weekly. Tag along as I try to catch up with the AI space, ship small projects, apply what I'm learning to tackle real life, and figure out what raising agents looks like in practice.</p>

        {state === "idle" ? (
          <form className="waitlist-form" onSubmit={submit}>
            <input
              type="email"
              required
              placeholder="you@goodemail.com"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              aria-label="Email address"
            />
            <button type="submit">Join the waitlist</button>
          </form>
        ) : (
          <div className="waitlist-thanks">
            <span className="thanks-dot" />
            You're on the list. Get in touch soon!
          </div>
        )}
      </div>
    </section>
  );
}

// ─── Sticky pill nav ────────────────────────────────────────────────
function StickyNav({ route }) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 360);
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  if (!scrolled) return null;
  return (
    <div className="sticky-nav">
      <div className="sticky-nav-inner">
        <a href="#/" className="sticky-mark"><span>JYB</span></a>
        <nav className="sticky-pills">
          {ROUTES.map((r) => (
            <a key={r.path} href={"#" + r.path}
               className={"pill" + (route === r.path ? " pill-active" : "")}>
              {r.title}
            </a>
          ))}
        </nav>
      </div>
    </div>
  );
}

// ─── Avatar (multiple modes) ────────────────────────────────────────
function Avatar({ mode }) {
  if (mode === "photo") {
    return (
      <div className="avatar avatar-photo">
        <div className="avatar-ring" aria-hidden />
        <div className="avatar-glyph">
          {/* Drop a square crop at images/avatar.jpg to show real photo */}
          <img src="images/avatar.jpg" alt="Jane You Bradley"
               onError={(e) => { e.currentTarget.style.display = 'none'; e.currentTarget.parentElement.classList.add('avatar-photo-missing'); }} />
          <span className="avatar-photo-fallback">photo</span>
        </div>
      </div>
    );
  }
  if (mode === "initial") {
    return (
      <div className="avatar">
        <div className="avatar-ring" aria-hidden />
        <div className="avatar-glyph"><span>J</span></div>
      </div>
    );
  }
  // wordmark — friendly "Hi!" greeting with waving hand
  return (
    <div className="avatar avatar-wordmark avatar-hi">
      <div className="avatar-ring" aria-hidden />
      <div className="avatar-glyph">
        <span className="wm">
          <span className="hi-text">Hi</span>
          <span className="hi-wave" aria-hidden>
            <svg width="22" height="22" viewBox="0 0 32 32" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M11 7 L11 17 M14 5 L14 17 M17 6 L17 17 M20 8 L20 18" />
              <path d="M11 17 C 9 17, 8 18, 8 20 C 8 25, 12 28, 16 28 C 21 28, 24 25, 24 19 L 24 11 C 24 9.5, 23 9, 22 9 C 21 9, 20 9.5, 20 11" />
              <path d="M22 5 L24 4 M25 7 L27 7 M24 10 L26 11" strokeWidth="1.2" />
            </svg>
          </span>
        </span>
      </div>
    </div>
  );
}

// ─── Theme toggle (sun / moon) ──────────────────────────────────────
function ThemeToggle({ theme, onChange }) {
  // resolve current effective dark state
  const sysDark = typeof window !== "undefined" && window.matchMedia
    ? window.matchMedia("(prefers-color-scheme: dark)").matches : false;
  const dark = theme === "dark" || (theme === "system" && sysDark);
  const next = dark ? "light" : "dark";
  return (
    <button className="theme-toggle" onClick={() => onChange(next)}
            aria-label={`Switch to ${next} mode`} title={`Switch to ${next} mode`}>
      {dark ? (
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
          <circle cx="12" cy="12" r="4" />
          <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" />
        </svg>
      ) : (
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
          <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
        </svg>
      )}
    </button>
  );
}

// ─── Hero ───────────────────────────────────────────────────────────
function Hero({ route, avatarMode, theme, setTheme }) {
  return (
    <header className="hero" id="top">
      <div className="hero-bridge" aria-hidden>
        <window.BridgeBackdrop />
      </div>
      <div className="hero-corner">
        <ThemeToggle theme={theme} onChange={(v) => setTheme(v)} />
      </div>
      <div className="hero-inner">
        <Avatar mode={avatarMode} />
        <h1 className="hero-name"><span className="hero-name-prefix">I'm</span> Jane You Bradley</h1>
        <p className="hero-role">PM &amp; builder</p>
        <p className="hero-now">
          <span className="hero-now-label">Currently</span>
          <span className="hero-now-line">Accelerating Agentic AI at Dropbox</span>
          <span className="hero-now-line">Building PMClaws, resource hub for the agentic PM</span>
          <span className="hero-now-line">Raising a wild 3-year-old, training my agent Raeya in parallel</span>
        </p>
        <nav className="hero-pills">
          {ROUTES.map((r) => (
            <a key={r.path} href={"#" + r.path}
               className={"pill" + (route === r.path ? " pill-active" : "")}>
              {r.title}
            </a>
          ))}
        </nav>
      </div>
    </header>
  );
}

// ─── Page header (compact, for non-home pages) ─────────────────────
function PageHeader({ route }) {
  const current = ROUTES.find((r) => r.path === route);
  return (
    <header className="page-header">
      <a href="#/" className="page-back">← Jane You Bradley</a>
      <h1 className="page-title">{current ? current.title : "Not found"}</h1>
      <nav className="page-nav">
        {ROUTES.filter((r) => r.path !== "/").map((r) => (
          <a key={r.path} href={"#" + r.path}
             className={"page-nav-item" + (route === r.path ? " active" : "")}>
            {r.title}
          </a>
        ))}
      </nav>
    </header>
  );
}

// ─── Footer ─────────────────────────────────────────────────────────
function Footer() {
  return (
    <footer className="footer">
      <div className="footer-inner">
        <p className="footer-h">Get in touch</p>
        <div className="footer-links">
          <a href="https://github.com/janeyou" target="_blank" rel="noopener noreferrer"><span>GitHub</span></a>
          <a href="https://www.linkedin.com/in/janeyou/" target="_blank" rel="noopener noreferrer"><span>LinkedIn</span></a>
          <a href="https://x.com/janeyoubradley" target="_blank" rel="noopener noreferrer"><span>X</span></a>
          <a href="mailto:hi@janeyoubradley.com"><span>Email</span></a>
        </div>
        <div className="footer-meta">
          <span>Jane You Bradley</span>
          <span className="dotbreak">·</span>
          <span>© {new Date().getFullYear()}</span>
          <span className="dotbreak">·</span>
          <a href="https://www.anthropic.com/claude-code" target="_blank" rel="noopener noreferrer">
            Built with Claude Code &amp; Claude Design
          </a>
        </div>
      </div>
    </footer>
  );
}

// ─── Notify (per-project launch notification) ──────────────────────
function useNotify() {
  const [email, setEmail] = useState(() => {
    try { return localStorage.getItem("jyb_notify_email") || ""; } catch (e) { return ""; }
  });
  const [subs, setSubs] = useState(() => {
    try { return JSON.parse(localStorage.getItem("jyb_notify_subs") || "{}"); } catch (e) { return {}; }
  });
  const [open, setOpen] = useState(null); // project being asked about

  const subscribe = (addr, projectKey) => {
    setEmail(addr);
    const next = { ...subs, [projectKey]: { email: addr, at: Date.now() } };
    setSubs(next);
    try {
      localStorage.setItem("jyb_notify_email", addr);
      localStorage.setItem("jyb_notify_subs", JSON.stringify(next));
    } catch (e) {}
  };

  const askFor = (project) => {
    // Always show the modal — subscription only happens on form submit
    // (or auto-confirmed click-through when we already have an email).
    setOpen(project);
  };

  return { email, subs, open, setOpen, subscribe, askFor };
}

// ─── Pages ─────────────────────────────────────────────────────────
function HomePage({ tweaks, notify }) {
  return (
    <main className="main">
      <section className="section first">
        <SectionLabel>Now building</SectionLabel>
        <div className="cards">
          {window.NOW_BUILDING.map((p) => (
            <ProjectCard key={p.key} project={p} cardStyle={tweaks.cardStyle}
              onBellClick={notify.askFor}
              isSubscribed={!!notify.subs[p.key]} />
          ))}
        </div>
      </section>

      <Waitlist />

      <section className="section">
        <SectionLabel intro="Recent writing.">Writing</SectionLabel>
        <div className="posts">
          {window.POSTS.slice(0, 2).map((p, i) => <PostRow key={i} p={p} />)}
        </div>
        <div className="more"><a href="#/blog">All posts →</a></div>
      </section>
    </main>
  );
}

function AgentsPage({ tweaks, notify }) {
  return (
    <main className="main">
      <section className="section first">
        <SectionLabel intro="The agents I hope will make mom-life a bit easier.">Agents</SectionLabel>
        <div className="cards">
          {window.AGENTS.map((p) => (
            <ProjectCard key={p.key} project={p} cardStyle={tweaks.cardStyle}
              onBellClick={notify.askFor}
              isSubscribed={!!notify.subs[p.key]} />
          ))}
        </div>
      </section>
    </main>
  );
}

function BlogPage() {
  return (
    <main className="main">
      <section className="section first">
        <SectionLabel intro="My thoughts and observations on how we evolve.">Writing</SectionLabel>
        <div className="posts">
          {window.POSTS.map((p, i) => <PostRow key={i} p={p} />)}
        </div>
      </section>
    </main>
  );
}

function PostPage({ slug }) {
  const post = window.POSTS.find((p) => p.slug === slug);
  if (!post) return <NotFoundPage />;
  const date = new Date(post.date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" });
  return (
    <main className="main">
      <article className="section first post-page">
        <a href="#/blog" className="post-back">← Writing</a>
        <h1 className="post-page-title">{post.title}</h1>
        <div className="post-page-meta">
          <time>{date}</time>
          <span className="dotbreak">·</span>
          <span>{post.readTime}</span>
          {post.tags && post.tags.length > 0 && (
            <><span className="dotbreak">·</span><span>{post.tags.join(" · ")}</span></>
          )}
        </div>
        <div className="post-page-body">
          <p className="post-page-lede">{post.excerpt}</p>
          <p className="post-page-note">
            Full essay lives in the repo. <a href="#/blog">← back to all writing</a>
          </p>
        </div>
      </article>
    </main>
  );
}

function QuotesPage() {
  return (
    <main className="main">
      <section className="section first">
        <SectionLabel intro="Lines I keep returning to.">Quotes</SectionLabel>
        <div className="quotes">
          {window.QUOTES.map((q, i) => <QuoteCard key={i} q={q} />)}
        </div>
      </section>
    </main>
  );
}

function NotFoundPage() {
  return (
    <main className="main">
      <section className="section first">
        <SectionLabel>Not found</SectionLabel>
        <p className="section-intro">Nothing here. <a href="#/">Back home →</a></p>
      </section>
    </main>
  );
}

// ─── App ────────────────────────────────────────────────────────────
function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const route = useHashRoute();
  const notify = useNotify();
  useEffect(() => { applyTheme(tweaks); }, [tweaks]);

  // re-apply when system color scheme changes (when in system mode)
  useEffect(() => {
    if (!window.matchMedia) return;
    const mq = window.matchMedia("(prefers-color-scheme: dark)");
    const handler = () => { if (tweaks.theme === "system") applyTheme(tweaks); };
    mq.addEventListener?.("change", handler);
    return () => mq.removeEventListener?.("change", handler);
  }, [tweaks.theme]);

  const isHome = route === "/";
  const page =
    route === "/"        ? <HomePage tweaks={tweaks} notify={notify} />
  : route === "/agents"  ? <AgentsPage tweaks={tweaks} notify={notify} />
  : route === "/blog"    ? <BlogPage />
  : route === "/quotes"  ? <QuotesPage />
  :                        <NotFoundPage />;

  return (
    <>
      <StickyNav route={route} />
      <Hero route={route} avatarMode={tweaks.avatar}
            theme={tweaks.theme} setTheme={(v) => setTweak("theme", v)} />
      {page}
      <Footer />
      {notify.open && (
        <NotifyModal
          project={notify.open}
          existingEmail={notify.email}
          onClose={() => notify.setOpen(null)}
          onSubscribe={notify.subscribe}
        />
      )}

      <TweaksPanel>
        <TweakSection label="Theme" />
        <TweakRadio label="Mode" value={tweaks.theme}
          options={["system", "light", "dark"]}
          onChange={(v) => setTweak("theme", v)} />
        <TweakSelect label="Accent" value={tweaks.accent}
          options={[
            { value: "mint", label: "Mint" },
            { value: "amber", label: "Amber" },
            { value: "coral", label: "Coral" },
            { value: "lavender", label: "Lavender" },
            { value: "slate", label: "Slate" },
          ]}
          onChange={(v) => setTweak("accent", v)} />

        <TweakSection label="Type" />
        <TweakSelect label="Pairing" value={tweaks.typePair}
          options={[
            { value: "geist", label: "Geist" },
            { value: "fraunces-inter", label: "Fraunces + Inter Tight" },
            { value: "instrument-inter", label: "Instrument + Inter Tight" },
            { value: "roboto-roboto", label: "Roboto" },
          ]}
          onChange={(v) => setTweak("typePair", v)} />

        <TweakSection label="Layout" />
        <TweakRadio label="Density" value={tweaks.density}
          options={["compact", "comfortable", "spacious"]}
          onChange={(v) => setTweak("density", v)} />
        <TweakRadio label="Card mark" value={tweaks.cardStyle}
          options={["logomark", "monogram"]}
          onChange={(v) => setTweak("cardStyle", v)} />

        <TweakSection label="Hero avatar" />
        <TweakRadio label="Style" value={tweaks.avatar}
          options={["wordmark", "initial", "photo"]}
          onChange={(v) => setTweak("avatar", v)} />
      </TweaksPanel>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
