// Stromatic Labs — main app
// Single-file React build. All sections live here; tweaks panel is loaded
// separately from tweaks-panel.jsx.
//
// Color system:
//   --accent is a single CSS var that drives the whole page.
//   Each Pillar has its own brand hue. Hovering a pillar morphs --accent
//   for ~600ms so the page subtly takes on that project's identity.
//   (User asked for "themes that transition between projects".)

const { useState, useEffect, useCallback } = React;

function useThemeMeta(mode) {
  useEffect(() => {
    let meta = document.querySelector('meta[name="theme-color"][data-dynamic]');
    if (!meta) {
      meta = document.createElement("meta");
      meta.name = "theme-color";
      meta.setAttribute("data-dynamic", "true");
      document.head.appendChild(meta);
    }
    meta.content = mode === "dark" ? "#080808" : "#f4f4f1";
  }, [mode]);
}

function useReveal() {
  useEffect(() => {
    const nodes = document.querySelectorAll(".reveal");
    if (!nodes.length) return;
    if (!("IntersectionObserver" in window)) {
      nodes.forEach((n) => n.classList.add("is-visible"));
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            e.target.classList.add("is-visible");
            io.unobserve(e.target);
          }
        });
      },
      { threshold: 0.06, rootMargin: "0px 0px -32px 0px" }
    );
    nodes.forEach((n, i) => {
      n.style.transitionDelay = Math.min(i * 0.06, 0.24) + "s";
      io.observe(n);
    });
    return () => io.disconnect();
  });
}

// ── Tweakable defaults (EDITMODE block — host rewrites on persist) ────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "mode": "dark",
  "accent": "#6dffb0",
  "showSchematic": true,
  "marqueeSpeed": "regular",
  "morphOnHover": true
}/*EDITMODE-END*/;

// ── Static content ────────────────────────────────────────────────────
const PILLARS = [
  {
    id: "mentioned",
    no: "01",
    featured: true,
    kind: "Product · Primary focus",
    name: "Mentioned",
    domain: "mentioned.today",
    tag: "What retail is talking about before the news catches up. Aggregate ticker chatter, filtered for pump and noise — this is where the energy is right now.",
    status: "beta",
    color: "#6dffb0",
    chips: ["Stock Chatter", "Aggregate Trends", "Lite Web App", "Founding Waitlist", "Native · Q3"],
    meta: [
      ["status", "Live · v2"],
      ["focus", "Primary"],
      ["model", "$39/mo founding"],
    ],
    href: "https://mentioned.today",
  },
  {
    id: "media",
    no: "02",
    kind: "Agency · Maintained",
    name: "Stromatic Media",
    domain: "stromaticmedia.tech",
    tag: "Fixed-price brand and growth for founders — shipped, still live, on request. No longer the main bench.",
    status: "maintained",
    color: "#2563eb",
    chips: ["Brand Kits", "SEO Audits", "Logo Packs", "Stripe Checkout", "On request"],
    meta: [
      ["status", "Shipped"],
      ["model", "Fixed-price"],
      ["focus", "Maintained"],
    ],
    href: "https://stromaticmedia.tech",
  },
  {
    id: "labs",
    no: "03",
    kind: "Engine Room · R&D",
    name: "Stromatic Labs",
    domain: "stromaticlabs.tech",
    tag: "Automated SEO pipelines, AI workflows, motion-design tooling, and music released under the Stromatic alias.",
    status: "rnd",
    color: "#22d3ee",
    chips: ["AI Pipelines", "n8n Workflows", "Motion Design", "Music · Stromatic"],
    meta: [
      ["status", "Always-on"],
      ["focus", "Internal R&D"],
      ["since", "—"],
    ],
    href: null,
  },
];

const STACK = [
  "n8n", "OpenClaw", "Local LLMs", "Anthropic", "Stripe",
  "Adobe Premiere Pro", "After Effects", "Next.js", "GitHub Actions",
  "Cloudflare", "Postgres", "Figma",
];

const NOW = [
  { date: "Q3 · 26", what: <>Packaging native <em>iOS + Android</em> builds for Mentioned</>, meta: "in flight" },
  { date: "Q3 · 26", what: <>Growing <em>founding waitlist</em> — first 100 seats on mentioned.today</>, meta: "in flight" },
  { date: "Q3 · 26", what: <>Refining <em>chatter filters</em> — less pump, more signal</>, meta: "in flight" },
  { date: "Q4 · 26", what: <>Mentioned <em>Pro tier</em> — stocks + crypto chatter</>, meta: "queued" },
  { date: "—",       what: <>Stromatic Media <em>case studies</em> — backlog, on request</>, meta: "maintained" },
  { date: "—",       what: <>New <em>Stromatic</em> EP, mastered in the engine room</>, meta: "always" },
];

const EMAILS = [
  { addr: "mentioned@stromaticlabs.tech", label: "Mentioned · product" },
  { addr: "hello@stromaticlabs.tech", label: "General" },
  { addr: "press@stromaticlabs.tech", label: "Press · media" },
  { addr: "support@stromaticlabs.tech", label: "Product support" },
];

const SOCIAL_GROUPS = [
  {
    id: "broadcast",
    label: "// broadcast",
    links: [
      { name: "Instagram", handle: "@stromaticlabs", href: "https://instagram.com/stromaticlabs", icon: "instagram" },
      { name: "TikTok",    handle: "@stromaticlabs", href: "https://tiktok.com/@stromaticlabs", icon: "tiktok" },
      { name: "X",         handle: "@stromaticlabs", href: "https://x.com/stromaticlabs", icon: "x" },
      { name: "YouTube",   handle: "@stromaticlabs", href: "https://youtube.com/@stromaticlabs", icon: "youtube" },
      { name: "Snapchat",  handle: "@stromaticlabs", href: "https://snapchat.com/@stromaticlabs", icon: "snapchat" },
    ],
  },
  {
    id: "live",
    label: "// live",
    links: [
      { name: "Twitch", handle: "stromaticlabs", href: "https://twitch.tv/stromaticlabs", icon: "twitch" },
      { name: "Kick",   handle: "stromaticlabs", href: "https://kick.com/stromaticlabs", icon: "kick" },
    ],
  },
  {
    id: "community",
    label: "// community",
    links: [
      { name: "Discord", handle: "open invite", href: "https://discord.gg/Gfn9x4mtyz", icon: "discord" },
      { name: "Reddit",  handle: "u/stromaticlabs", href: "https://reddit.com/u/stromaticlabs", icon: "reddit" },
    ],
  },
];

// ── Tiny UI atoms ──────────────────────────────────────────────────────

const SunIcon = () => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
    <circle cx="12" cy="12" r="4" />
    <path strokeLinecap="round" d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4" />
  </svg>
);
const MoonIcon = () => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
    <path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5z" />
  </svg>
);
const ArrowUR = ({ size = 12 }) => (
  <svg width={size} height={size} viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.4">
    <path d="M3 9 9 3M4 3h5v5" strokeLinecap="round" strokeLinejoin="round" />
  </svg>
);

const BrandGlyph = () => (
  <svg className="brand-glyph-svg" viewBox="0 0 22 22" fill="none" aria-hidden="true">
    <rect x="0.5" y="0.5" width="21" height="21" stroke="currentColor" strokeWidth="1" />
    <path d="M6 16V6h5.2c2.4 0 3.8 1.1 3.8 2.9 0 1.2-.6 2.1-1.7 2.5l2.2 4.6h-2.4l-2-4.2H8.2V16H6zM8.2 9.4h2.8c1 0 1.6-.4 1.6-1.1s-.6-1.1-1.6-1.1H8.2v2.2z" fill="currentColor" />
  </svg>
);

const SocialIcon = ({ name }) => {
  const p = { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" };
  switch (name) {
    case "instagram":
      return <svg {...p}><rect x="2.5" y="2.5" width="11" height="11" rx="3" /><circle cx="8" cy="8" r="2.6" /><circle cx="11.6" cy="4.4" r="0.6" fill="currentColor" stroke="none" /></svg>;
    case "tiktok":
      return <svg {...p}><path d="M9.5 2.5v7.2a2.3 2.3 0 1 1-2.3-2.3" /><path d="M9.5 6.2c1.2.8 2.6 1.2 4 1.1V5.1a4.2 4.2 0 0 1-2.6-.9" /></svg>;
    case "x":
      return <svg {...p}><path d="M3.5 3.5 12.5 12.5M12.5 3.5 3.5 12.5" /></svg>;
    case "youtube":
      return <svg {...p}><rect x="2" y="4.5" width="12" height="7" rx="2" /><path d="M7 6.8v2.4l3.2-1.2L7 6.8z" fill="currentColor" stroke="none" /></svg>;
    case "snapchat":
      return <svg {...p}><path d="M4.5 4.2c1.8-1.2 5.2-1.2 7 0 .8.6 1.2 1.4 1.2 2.4-.1 1.6-.9 2.5-1.8 3.3.5.4 1.2.7 2.1.9-.3.8-.9 1.4-1.8 1.7-.6.2-1.3.2-2.1.2-.8 0-1.5-.1-2.1-.3-.9-.3-1.5-.9-1.8-1.7.9-.2 1.6-.5 2.1-.9-.9-.8-1.7-1.7-1.8-3.3 0-1 .4-1.8 1.2-2.4z" /></svg>;
    case "twitch":
      return <svg {...p}><path d="M3 3.5h2.5l1.5 3.5 1.5-3.5H11l-1 8.5H8.5L7 8.5 5.5 12H3V3.5z" /><path d="M11.5 5.5v2M13.5 5.5v2" /></svg>;
    case "kick":
      return <svg {...p}><path d="M4 4.5h2.5v7H4V4.5zM8 4.5h2l2.5 3.5L14 4.5h2v7h-2.5V8.5L11 12H9l-2.5-3.5V11.5H8V4.5z" /></svg>;
    case "discord":
      return <svg {...p}><path d="M4 5.5c2.2-1 4.8-1 7 0l1 3.2c-1.2.9-2.5 1.4-4 1.4s-2.8-.5-4-1.4L4 5.5z" /><circle cx="6.2" cy="8.2" r="0.7" fill="currentColor" stroke="none" /><circle cx="9.8" cy="8.2" r="0.7" fill="currentColor" stroke="none" /><path d="M5.5 11.5c.9.6 2 .9 3.5.9s2.6-.3 3.5-.9" /></svg>;
    case "reddit":
      return <svg {...p}><circle cx="8" cy="9" r="2.2" /><circle cx="5.6" cy="7.8" r="0.7" fill="currentColor" stroke="none" /><circle cx="10.4" cy="7.8" r="0.7" fill="currentColor" stroke="none" /><path d="M5.5 5.2c.4-.8 1.3-1.2 2.5-1.2M10.5 5.2c-.4-.8-1.3-1.2-2.5-1.2M3.5 9.5h1M11.5 9.5h1" /><path d="M6.2 11.8c.5.5 1.2.7 1.8.7s1.3-.2 1.8-.7" /></svg>;
    default:
      return <svg {...p}><circle cx="8" cy="8" r="4" /></svg>;
  }
};

// Status dot: pulses unless `idle`. Color follows --dot-color.
const Dot = ({ color, idle }) => (
  <span className={"dot" + (idle ? " idle" : "")} style={{ "--dot-color": color }} />
);

// ── Top bar ────────────────────────────────────────────────────────────

function TopBar({ mode, onToggleMode, accent }) {
  const [menuOpen, setMenuOpen] = useState(false);
  const closeMenu = () => setMenuOpen(false);

  useEffect(() => {
    document.body.classList.toggle("menu-open", menuOpen);
    return () => document.body.classList.remove("menu-open");
  }, [menuOpen]);

  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") closeMenu(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  return (
    <header className="topbar">
      <div className="frame topbar-inner">
        <div className="topbar-left">
          <a href="#top" className="brand-mark" onClick={closeMenu}>
            <BrandGlyph />
            <span className="brand-name">
              stromatic<span className="slash">/</span>labs
            </span>
          </a>
          <a
            href="https://mentioned.today"
            className="live-pill focus-pill desktop-only"
            target="_blank"
            rel="noopener noreferrer"
          >
            <Dot color={accent} />
            <span>mentioned.today</span>
          </a>
        </div>
        {menuOpen && (
          <button
            type="button"
            className="nav-backdrop"
            aria-label="Close menu"
            onClick={closeMenu}
          />
        )}
        <nav className={"nav-links" + (menuOpen ? " open" : "")} aria-label="Primary">
          <a
            href="https://mentioned.today"
            className="nav-mentioned"
            target="_blank"
            rel="noopener noreferrer"
            onClick={closeMenu}
          >
            mentioned.today
          </a>
          <a href="#projects" onClick={closeMenu}>Projects</a>
          <a href="#now" onClick={closeMenu}>Now</a>
          <a href="#about" onClick={closeMenu}>About</a>
          <a href="#contact" onClick={closeMenu}>Contact</a>
        </nav>
        <div className="topbar-right">
          <button
            className="icon-btn menu-btn"
            aria-label={menuOpen ? "Close menu" : "Open menu"}
            aria-expanded={menuOpen}
            onClick={() => setMenuOpen((o) => !o)}
          >
            <span className={"menu-bars" + (menuOpen ? " open" : "")} />
          </button>
          <button className="icon-btn" aria-label="Toggle theme" onClick={onToggleMode}>
            {mode === "dark" ? <SunIcon /> : <MoonIcon />}
          </button>
        </div>
      </div>
    </header>
  );
}

// ── Hero ───────────────────────────────────────────────────────────────

function Hero({ showSchematic }) {
  const now = new Date();
  const ymd = now.toISOString().slice(0, 10);
  const utc = now.toUTCString().slice(17, 22) + " UTC";
  return (
    <section className="hero" id="top" aria-label="Introduction">
      {showSchematic && <div className="schematic-bg" />}
      <div className="frame" style={{ position: "relative" }}>
        <div className="hero-meta">
          <div><span className="key">// log</span></div>
          <div className="val">stromatic labs &mdash; parent index &mdash; rev 02</div>
          <div><span className="key">// uplink</span></div>
          <div className="val">{ymd} · {utc}</div>
          <div><span className="key">// stance</span></div>
          <div className="val">heads-down on mentioned.today</div>
        </div>

        <h1 className="hero-title">
          Create, innovate&nbsp;&amp;
          <br />procrastinate.
          <em>
            The engine room behind Mentioned, Stromatic Media, and a small
            stack of tools. Right now the bench is mentioned.today — everything
            else ships when it needs to.
          </em>
        </h1>

        <a className="hero-cta" href="https://mentioned.today" target="_blank" rel="noopener noreferrer">
          <span>Open mentioned.today</span>
          <ArrowUR size={14} />
        </a>

        <div className="hero-strip">
          <div>
            <div className="k">Focus</div>
            <div className="v">mentioned.today</div>
          </div>
          <div>
            <div className="k">Stage</div>
            <div className="v">Beta · v2 live</div>
          </div>
          <div>
            <div className="k">Media</div>
            <div className="v">Shipped · maintained</div>
          </div>
          <div>
            <div className="k">Labs</div>
            <div className="v">R&amp;D · always-on</div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ── Pillars ────────────────────────────────────────────────────────────

function Pillar({ p, onEnter, onLeave }) {
  const statusLabel = {
    live: "Live",
    beta: "Beta",
    rnd: "Active R&D",
    maintained: "Maintained",
  }[p.status];
  const dotIdle = p.status === "maintained";
  const label = p.name + " — " + p.domain + " (" + statusLabel + ")";
  return (
    <a
      className={"pillar" + (p.featured ? " featured" : "")}
      style={{ "--p-color": p.color }}
      href={p.href || "#projects"}
      target={p.href ? "_blank" : undefined}
      rel={p.href ? "noopener noreferrer" : undefined}
      aria-label={p.href ? label + " — open site" : label}
      onMouseEnter={() => onEnter(p.color)}
      onMouseLeave={onLeave}
    >
      <div className="pillar-no">{p.no}</div>
      <div className="pillar-kind">
        <Dot color={p.color} idle={dotIdle} />
        <span>{p.kind}</span>
      </div>
      <div className="pillar-body">
        <h3 className="pillar-name">
          {p.name}
          <span className="domain">{p.domain}</span>
        </h3>
        <p className="pillar-tag">{p.tag}</p>
        <div className="pillar-chips">
          {p.chips.map((c) => <span key={c} className="chip">{c}</span>)}
        </div>
      </div>
      <div className="pillar-meta">
        {p.meta.map(([k, v]) => (
          <div key={k} className="row"><span className="k">{k}</span><span>{v}</span></div>
        ))}
        <div className="row" style={{ marginTop: 8 }}>
          <span className="k">status</span>
          <span style={{ color: p.color }}>● {statusLabel}</span>
        </div>
      </div>
      <div className="pillar-arrow"><ArrowUR size={16} /></div>
    </a>
  );
}

function Pillars({ onEnter, onLeave }) {
  return (
    <section className="sect reveal" id="projects" aria-labelledby="projects-title">
      <div className="frame">
        <div className="sect-head">
          <div className="sect-no"><span className="dot-inline" />02 &mdash; Index</div>
          <div>
            <h2 className="sect-title" id="projects-title">Mentioned first. Media shipped. Labs underneath.</h2>
            <p className="sect-sub">
              mentioned.today is the primary focus — native builds, founding seats,
              and a cleaner signal. Stromatic Media stays live on request. Hover to
              feel each project.
            </p>
          </div>
        </div>
        <div className="pillars">
          {PILLARS.map((p) => (
            <Pillar key={p.id} p={p} onEnter={onEnter} onLeave={onLeave} />
          ))}
        </div>
      </div>
    </section>
  );
}

// ── Marquee ────────────────────────────────────────────────────────────

function Marquee({ speed }) {
  const dur = speed === "fast" ? "22s" : speed === "slow" ? "60s" : "38s";
  const items = [...STACK, ...STACK];
  return (
    <div className="marquee" aria-label="Tech stack">
      <div className="marquee-track" style={{ animationDuration: dur }}>
        {items.map((s, i) => (
          <span key={i} className="marquee-item">{s}</span>
        ))}
      </div>
    </div>
  );
}

// ── Now ────────────────────────────────────────────────────────────────

function NowSection() {
  return (
    <section className="sect reveal" id="now" aria-labelledby="now-title">
      <div className="frame">
        <div className="now-grid">
          <div className="sect-no"><span className="dot-inline" />03 &mdash; Now</div>
          <div>
            <h2 className="sect-title" id="now-title" style={{ marginBottom: 8 }}>What's on the bench.</h2>
            <p className="sect-sub" style={{ marginBottom: 28 }}>
              What we're shipping, fielding or sketching. Updated quarterly.
            </p>
            <div className="now-list">
              {NOW.map((n, i) => (
                <div key={i} className="now-row">
                  <span className="date">{n.date}</span>
                  <span className="what">{n.what}</span>
                  <span className="meta">{n.meta}</span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ── About / Manifesto ──────────────────────────────────────────────────

function About() {
  return (
    <section className="sect reveal" id="about" aria-labelledby="about-title">
      <div className="frame">
        <div className="manifesto-grid">
          <div className="sect-no"><span className="dot-inline" />04 &mdash; About</div>
          <div>
            <h2 className="sr-only" id="about-title">About Stromatic Labs</h2>
            <p className="manifesto">
              We are the parent.<br />
              Mentioned is the focus. <span className="accent">// media shipped. labs underneath.</span>
            </p>
            <div className="about-cols">
              <div>
                <h4>Mentioned</h4>
                <p>
                  mentioned.today — retail chatter before the news. Live v2, founding waitlist,
                  native apps in flight. This is the main bench.
                </p>
              </div>
              <div>
                <h4>Stromatic Media</h4>
                <p>
                  Fixed-price brand and growth — shipped and maintained, still bookable on request.
                  Not the day job anymore.
                </p>
              </div>
              <div>
                <h4>The Engine Room</h4>
                <p>
                  Infrastructure, automated AI pipelines, motion-design tooling, and music
                  released under the Stromatic alias.
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ── Contact ────────────────────────────────────────────────────────────

function Contact() {
  return (
    <section className="sect reveal" id="contact" aria-labelledby="contact-title">
      <div className="frame">
        <div className="contact-grid">
          <div className="sect-no"><span className="dot-inline" />05 &mdash; Contact</div>
          <div>
            <h2 className="sect-title" id="contact-title" style={{ marginBottom: 24 }}>Open channels.</h2>
            <div className="contact-card">
              {EMAILS.map((e) => (
                <a key={e.addr} className="contact-cell" href={"mailto:" + e.addr}>
                  <span className="lbl">{e.label}</span>
                  <span className="val">{e.addr}</span>
                </a>
              ))}
            </div>
            <div className="social-groups">
              {SOCIAL_GROUPS.map((g) => (
                <div key={g.id} className="social-group">
                  <div className="channel-group-label">{g.label}</div>
                  <div className="social-list">
                    {g.links.map((s) => (
                      <a key={s.name} className="social-row" href={s.href} target="_blank" rel="noopener noreferrer">
                        <span className="social-icon"><SocialIcon name={s.icon} /></span>
                        <span className="social-text">
                          <span className="name">{s.name}</span>
                          <span className="handle">{s.handle}</span>
                        </span>
                        <span className="arrow"><ArrowUR /></span>
                      </a>
                    ))}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ── Footer ─────────────────────────────────────────────────────────────

function Footer() {
  const year = new Date().getFullYear();
  return (
    <footer className="footer">
      <div className="frame footer-grid">
        <div>© {year} stromatic labs · all signals routed</div>
        <div className="right">
          <span>stromaticlabs.tech</span>
          <span>·</span>
          <span>v 0.2 — public</span>
        </div>
      </div>
    </footer>
  );
}

// ── App ────────────────────────────────────────────────────────────────

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [hoverAccent, setHoverAccent] = useState(null);

  useThemeMeta(t.mode);
  useReveal();

  useEffect(() => {
    document.documentElement.setAttribute("data-mode", t.mode);
  }, [t.mode]);

  useEffect(() => {
    const active = hoverAccent && t.morphOnHover ? hoverAccent : t.accent;
    const soft = t.mode === "dark" ? 0.12 : 0.1;
    const glow = t.mode === "dark" ? 0.2 : 0.14;
    document.documentElement.style.setProperty("--accent", active);
    document.documentElement.style.setProperty("--accent-soft", hexToRgba(active, soft));
    document.documentElement.style.setProperty("--accent-glow", hexToRgba(active, glow));
  }, [t.accent, hoverAccent, t.morphOnHover, t.mode]);

  const onEnter = useCallback((c) => setHoverAccent(c), []);
  const onLeave = useCallback(() => setHoverAccent(null), []);
  const toggleMode = useCallback(
    () => setTweak("mode", t.mode === "dark" ? "light" : "dark"),
    [t.mode, setTweak]
  );

  return (
    <>
      <a className="skip-link" href="#main">
        Skip to content
      </a>
      <TopBar mode={t.mode} onToggleMode={toggleMode} accent={t.accent} />
      <main id="main">
        <Hero showSchematic={t.showSchematic} />
        <Marquee speed={t.marqueeSpeed} />
        <Pillars onEnter={onEnter} onLeave={onLeave} />
        <NowSection />
        <About />
        <Contact />
      </main>
      <Footer />

      <TweaksPanel title="Tweaks · stromatic labs">
        <TweakSection label="Theme" />
        <TweakRadio
          label="Mode"
          value={t.mode}
          options={["dark", "light"]}
          onChange={(v) => setTweak("mode", v)}
        />
        <TweakColor
          label="Accent"
          value={t.accent}
          options={["#6dffb0", "#22d3ee", "#2563eb", "#bb86fc", "#ff6d3a", "#fafafa"]}
          onChange={(v) => setTweak("accent", v)}
        />
        <TweakToggle
          label="Morph on hover"
          value={t.morphOnHover}
          onChange={(v) => setTweak("morphOnHover", v)}
        />

        <TweakSection label="Surface" />
        <TweakToggle
          label="Schematic grid"
          value={t.showSchematic}
          onChange={(v) => setTweak("showSchematic", v)}
        />
        <TweakRadio
          label="Marquee speed"
          value={t.marqueeSpeed}
          options={["slow", "regular", "fast"]}
          onChange={(v) => setTweak("marqueeSpeed", v)}
        />
      </TweaksPanel>
    </>
  );
}

// hex → rgba string, used to derive --accent-soft alpha from the picked hex.
function hexToRgba(hex, a) {
  const h = String(hex).replace("#", "");
  const x = h.length === 3 ? h.replace(/./g, (c) => c + c) : h.padEnd(6, "0");
  const n = parseInt(x.slice(0, 6), 16);
  const r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
  return `rgba(${r}, ${g}, ${b}, ${a})`;
}

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